1
$\begingroup$

i have defined a 3d NURBS curve and want many copies of an object to be laid on the the 3D curve, but without any deformation or rotation on the object.

I've tried using a curve + array modifier on the object, but that both rotates and deforms the object.

I've then tried using the above solution and manually adjusting the twist of each of the nodes of the curve, it works when the curve is not too tight, but requires tremendous work and is not a practical solution for the many 300+ control point curves that I am using.

Then I've identified a potential solution (available here) that uses dupliframes, and this works for blender 2.79 but not for 2.80 (beta, as of June/19)

What I am trying to replicate is exemplified on this picture - note that the boxes do not change orientation/rotation when places on the curve (copied from another question on SO)

enter image description here

I am now building python code to make this operation, but I am taping on this community to know if there is a faster/easier way for doing this.

$\endgroup$

bumped to the homepage by Community 21 hours ago

This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.

0
$\begingroup$

The code I wrote to do what I couldn't do through built-in functions is below:

import bpy

skull = bpy.data.objects["Skull"]
curve = bpy.data.objects["xobject_name"]

try:
    newCol = bpy.data.collections.new('Skulls')
    newCol = bpy.data.collections['Skulls']
    # link the newCol to the scene
    bpy.context.scene.collection.children.link(newCol)
except:
    print ("safely ignore")

skull_copy = []
for index, point in enumerate(curve.data.splines[0].points):
    if (index % 2 == 0):
        print (index, point.co)
        skull_copy.append(skull.copy())
        skull_copy[-1].data = skull.data.copy()
        #bpy.context.scene.collection.objects.link(skull_copy[-1])
        newCol.objects.link(skull_copy[-1])
        skull_copy[-1].location[0] = point.co[0] + skull.location[0]
        skull_copy[-1].location[1] = point.co[1] + skull.location[1]
        skull_copy[-1].location[2] = point.co[2] + skull.location[2]
$\endgroup$
  • $\begingroup$ Just some suggestions to improve your script. The collections.new will always create a new collection adding a numeric suffix if it exists, you can test if 'Skulls' in bpy.data.collections to see if it already exists. You do not need to duplicate the mesh data, for larger duplications this can increase the memory needed. Here is a variation of your script to have a look at. $\endgroup$ – sambler Jun 9 at 7:31
  • $\begingroup$ Thank you! It is indeed way faster and easier on memory. Too bad that this basic function was apparently removed from 2.79 $\endgroup$ – Oren Pinsky Jun 9 at 13:24
  • $\begingroup$ The collections are new in 2.80. If you remove collections and use bpy.context.scene.objects.link(new_skull) the rest works in 2.79. Adding them to a group in 2.79 would be the closest to using collections. $\endgroup$ – sambler Jun 9 at 19:24
  • $\begingroup$ Yes - the script works in 2.80 :-) , but there is no native function for this basic functionality in 2.80 (it existed in 2.79 but was apparently deprecated) $\endgroup$ – Oren Pinsky Jun 10 at 20:30
0
$\begingroup$

And here is a different approach, to maintain equidistant/even spacing between objects on the curve:

import bpy
import numpy as np

skull = bpy.data.objects["Skull"]
curve = bpy.data.objects["xobject_name"]
spline = curve.data.splines[0]

#create Skulls collection
if 'Skulls' not in bpy.data.collections:
    newCol = bpy.data.collections.new('Skulls')
    bpy.context.scene.collection.children.link(newCol)
skullCol = bpy.data.collections['Skulls']

#remove constraints from Skull
if skull.constraints:
    for c in skull.constraints:
        skull.constraints.remove(c)

s = 150
for i in range(0, 1*(s+1)):
    new_skull = skull.copy()
    new_skull.data = skull.data
    x = new_skull.constraints.new(type='FOLLOW_PATH')
    x.target = curve
    x.use_fixed_location = True
    x.offset_factor = i/s
    skullCol.objects.link(new_skull)
    #new_skull.location = skull.matrix_world.translation
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.