1
$\begingroup$

Sorry if the title is confusing, I wasn't sure how to best describe what I am trying to do.

Basically, I'm trying to create Bezier Curves that "grow" off of each other. For example, I would make one curve, deform it in whatever way, and then create a second curve that starts at a random point along the first curve, like this:

enter image description here

Obviously, I'm trying to do all of this programmatically in python.

I was able to pull the points of the first curve using the code suggested in this comment: Getting the list of points that describe a Curve without converting to mesh along with some of my own code.

However, the output of this seems to always be between -1 and 1 (though it goes a little over on both ends) no matter where in the scene I place it. This suggests to me that the exported points are in some relative space and not in the coordinate space used by the scene.

Does anyone know how to output the points of a curve in X, Y, Z coordinates of the scene? Or at least how to transform those points into the coordinates of the scene?

Thank you!

$\endgroup$
  • $\begingroup$ The curve data, like mesh data, is in local coordinates, whereas you want global coordinates, which can be obtained by multiplying by the curve objects matrix_world. blender.stackexchange.com/a/6156/15543 $\endgroup$ – batFINGER Jun 2 '16 at 17:19
1
$\begingroup$

Perhaps the following code gives you an explicit example of how to interpolate points on a Bezier curve. (I almost forgot the matrix_world that batFINGER has already explained is very important)

import bpy
from math import *

def interpBez3(bp0, t, bp3):
    # bp1, HR, HL, bp2

    return interpBez3_(bp0.co, bp0.handle_right, bp3.handle_left, bp3.co, t)
#    return interpBez3_(bp0.co, bp0.handle_left, bp3.handle_right, bp3.co, t)

def interpBez3_(p0, p1, p2, p3, t):
    r = 1-t
    return (r*r*r*p0 +
            3*r*r*t*p1 +
            3*r*t*t*p2 +
            t*t*t*p3)

def interpBlenderSpline(spline, i1, t2):

    bp1 = spline.bezier_points[i1]
    bp2 = spline.bezier_points[i1+1]
    return interpBez3(bp1, t2, bp2)

def mission1(obj, t):
    """ mathematically correct spline interpolation """

    i1 = floor(t)

    curve = obj.data

    bpy.context.scene.cursor_location = obj.matrix_world * interpBlenderSpline(curve.splines[0], i1, t-i1)


def mission2(obj, t):
    """ spline interpolation that matches the resolution_u setting inside blender """
    i1 = floor(t)
    t2 = t - i1
    spline = obj.data.splines[0]

    res = obj.data.render_resolution_u or obj.data.resolution_u
    t3 = t2*res
    t3i = floor(t3) / res
    t3f = t3 - floor(t3)

    p8 = interpBlenderSpline(spline, i1, t3i)
    p9 = interpBlenderSpline(spline, i1, t3i + 1/res)

    p = (1-t3f)*p8 + t3f*p9

    bpy.context.scene.cursor_location = obj.matrix_world * p


mission1(bpy.context.active_object, 0.7)

The mission2 function is if you want the point to match how blender chops up the spline into line segments instead of being on the mathematically precise bezier segment.

$\endgroup$
  • $\begingroup$ Thanks Mutant. How to change it to respect curve resolution ? $\endgroup$ – JuhaW Mar 26 '18 at 16:37
  • $\begingroup$ I'm going to need you to define what you mean by "respect curve resolution" . $\endgroup$ – Mutant Bob Apr 12 '18 at 14:36
  • $\begingroup$ For default curve object, default resolution is 12 and when you decrease/increase resolution, curve object changes. So interpolated points have to change also. $\endgroup$ – JuhaW Apr 12 '18 at 15:05

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.