3
$\begingroup$

I am trying to generate a bunch of points from a bezier curve. I am converting my curve to mesh then gather vertices then delete the mesh as discussed by helpful contributors in the past.

But the points I generated do not match the curve 3D location. Please see attached screenshot, blender file, and code.

To recreate my problem: 1. create a bezier curve 2. manually move bezier curve on all 3 axies 3. run the python script 4. see points generated do not correspond to the new 3D locations of the curve but rather match its original position only (when it was created at origin).

Thank you!

    #https://blender.stackexchange.com/questions/34145/calculate-points-on-a-nurbs-curve-without-converting-to-mesh
    import bpy
    obj = bpy.context.object
    scene = bpy.context.scene
    obj_mesh = obj.to_mesh(scene, True, 'PREVIEW')
    verts = [v.co for v in obj_mesh.vertices]
    print("total numbers of vertices generated = %d"%len(verts))
    for i in verts:
        bpy.ops.mesh.primitive_uv_sphere_add(size=0.05, location=i)
    bpy.data.meshes.remove(obj_mesh)

enter image description here

$\endgroup$
  • 1
    $\begingroup$ Try Apply Location/Rotation/Scale immediately before running the script. $\endgroup$ – Rich Sedman Nov 9 '17 at 16:20
  • $\begingroup$ Hi Rich, could you elaborate a little bit? I manually moved the bezier curve immediately before running the python script and that was the result. $\endgroup$ – John Nov 10 '17 at 2:40
  • 1
    $\begingroup$ There is a way to convert current mesh-space to world space. See link $\endgroup$ – tetii Nov 10 '17 at 2:58
6
+200
$\begingroup$

For global coordinates, multiply local coordinates by world matrix of object.

Data (obj.data) coordinates are in local space. The global scene coordinates have an origin at (0, 0, 0) with no rotation or scale. An object's origin is its local coordinate (0, 0, 0). An object's location is the location of its origin.

Latitude and longitude on earth could be considered a local coordinate system, with origin (0, 0) ... It's just some arbitrary point on the equator.. It tells us nothing about where we are in the universe, that the axis is tilted towards the sun...

Can calculate a global coordinate from any local coordinate by pre-multiplying the vector by the object's matrix world (obj.matrix_world) This accounts for any translation, rotation and scale on the object in global space.

When an object has no transformation, no rotation and unity scale, its world matrix is the Identity matrix. Multiplying by the identity matrix is the scalar equivalent of multiplying by one. In this case, and only this case, all global and local coordinates will be the same. Will find a number of answers on here that don't take this into account.

Applying location, rotation and scale has the effect of making an objects matrix world identity, by converting all local coordinates to their global equivalent.

import bpy
obj = bpy.context.object
mw = obj.matrix_world
scene = bpy.context.scene
obj_mesh = obj.to_mesh(scene, True, 'PREVIEW')
local_coords = [v.co for v in obj_mesh.vertices]
print("total numbers of vertices generated = %d" % len(local_coords))
for local_coord in local_coords:
    global_coord = mw * local_coord
    bpy.ops.mesh.primitive_uv_sphere_add(size=0.05,
            location=global_coord)
bpy.data.meshes.remove(obj_mesh)

In case you missed it, the link provided by @tet_li in comments provides a detailed explanation of coordinates in blender.

$\endgroup$
  • 1
    $\begingroup$ See pasteall.org/660404/python for only using add primitive operator once. Even for small number of spheres, there is an appreciable speed difference. $\endgroup$ – batFINGER Nov 11 '17 at 7:44
  • $\begingroup$ Nice answer @batFINGER (as usual! :-) ) Does multiplying by the ‘matrix world’ include the translation? I would expect it to just handle the scale and rotation. I’ve not tried it (yet) but my understanding of the maths (from many years gone) would imply you need to add in the translation separately. $\endgroup$ – Rich Sedman Nov 11 '17 at 22:30
  • $\begingroup$ @RichSedman all three. obj.matrix_world * Vector((0, 0, 0)) will give location of origin. $\endgroup$ – batFINGER Nov 12 '17 at 3:58

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.