I am developing a commandline tool to experiment with lofting a set of curves, and would appreciate any guidance.
blender_loft c0.txt c1.txt output.txt # simplest to start with
- c0.txt, c1.txt: two or more 3D curves represented as a text file each listing the ordered curve samples, one xyz coordinate triplet per line. These are usually just polylines finely sampling some curve fragments.
- A file storing a surface between these curves, tautly stretching over the curve fragments as best as possible.
- Speed is desirable but not a big deal since I just want to experiment first prior to writing optimal code.
- Easy to install for others to use. Ideally, just downloading blender should suffice.
What I have so far
- So far it seems BSurfaces's loft functionality is the most feature-rich out there, so I went with that. I want to target all its fancy controls and possibilities in the long run.
- A bpy script that reads the text files, creates bezier curves from the samples, and try to simulate what Bsurfaces does - for now it is limited to this:
Code I have so far
# Loft curves given by files into surface # # INPUT # p0.txt, p1.txt # # OUTPUT # loftsurf.ply # # USAGE # # Commandline # blender -b -nosound -P blender_loft.py # # Inside blender console # # filename = "PWD/blender_loft.py" # exec(compile(open(filename).read(), filename, 'exec')) # # AUTHOR # Ricardo Fabbri <email@example.com>, 3 Dec 2015 # import bpy import bpy_extras import numpy from mathutils import Matrix # Create a spline/bezier from a list of points def new_curve_from_points(p0,name_prefix): npts = len(p0) c0 = bpy.data.curves.new(name_prefix + 'CurveToLoft', 'CURVE') o0 = bpy.data.objects.new(name_prefix + 'CurveToLoft', c0) bpy.context.scene.objects.link(o0) c0.dimensions = "3D" spline = o0.data.splines.new('BEZIER') spline.bezier_points.add(npts - 1) # ^-- less one because one point is added when the spline is created. for p in range(0, npts): spline.bezier_points[p].co = p0[p] # spline.bezier_points[p].co = [p0[p], p0[p], p0[p]] return c0, o0, spline def read_files(): p0_fname = 'p0.txt' p1_fname = 'p1.txt' p0 = numpy.loadtxt(p0_fname) p0.tolist() p1 = numpy.loadtxt(p1_fname) p1.tolist() return p0, p1 # to be called inside console after testing def cleanup(): bpy.ops.object.mode_set(mode='OBJECT', toggle=True) bpy.ops.object.delete(use_global=False) def test(): print('hello') p0 =  p0.append([1, 0, 0]) p0.append([0, 0, 0]) p0.append([0, 1, 0]) p1 =  p1.append([1, 1, 0]) p1.append([0, 1, 0]) p1.append([0, 0, 1]) loft(p0,p1) def test1(): # cleanup() p0, p1 = read_files() loft(p0, p1) bpy.ops.export_mesh.ply(filepath='loftsurf.ply') def loft(p0, p1): c0, o0, s0 = new_curve_from_points(p0,'first') c1, o1, s1 = new_curve_from_points(p1,'second') # join curves into a group bpy.data.objects[o0.name].select = True bpy.data.objects[o1.name].select = True bpy.context.scene.objects.active = bpy.data.objects[o1.name] bpy.ops.object.join('INVOKE_REGION_WIN') # create a mesh to store the final surface me = bpy.data.meshes.new("outputLoft") ob = bpy.data.objects.new("outputLoft", me) scn = bpy.context.scene scn.objects.link(ob) scn.objects.active = ob ob.select = True # curves + object should be selected # call lofting bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='EDIT', toggle=True) bpy.ops.mesh.reveal() bpy.ops.gpencil.surfsk_add_surface('INVOKE_DEFAULT') if __name__ == "__main__": test1()
The current solution works from the GUI python console, but I'm still having a hard time calling it from commandline without the '-b' option.
- Cheating by calling without '-b' and calling bpy.ops.wm.quit_blender() in the end main works OK as prototype.
- This is basically a context problem
- Besides the current issue above, I would like to call the script directly from C or standalone python so that we don't have to set up blender entirely each time we're lofting between curves.
- I cannot use a lower-level API than bpy with this solution since BSurfaces is very intertwined with bpy to the basic level.
This discussion should be useful for anyone writing tools that seemlessly use blender in the background. I am not very experienced with blender. My main question is whether this all looks like a decent way to go, besides the above specific issue.
Note: After I initially wrote this question, partial solutions have been evolving and I have been updating this accordingly. Sorry if it seems like a multi-question question during this process. Feel free to post partial answers and evolve, this would already be useful, though I will accept the answer if it is thorough enough.