Sunday, July 19, 2009

How to draw a curve in Blender using Python - A Quick-N-Dirty Example

In a previous example, curves were generated using cylinder and spheres. This is computationally expensive and does not fully leverage Blender's capabilities. Rather than building curves using primitive meshes, the Blender.Curve objects can be used. This example demonstrates a simple script which creates a curve in 3D using Blender curves.

Code:
Download Code
#!BPY
__doc__ = """
curveTest_xxxx.py
Rev 1.0

The purpose of this script is to demonstrate the use of blender curves.

This script is executed at the command line by:
>blender -P curveTest_xxxx.py
"""
__author__ = "edt"
__version__ = "1.0 2009/07/19"
__url__="Website, dataOrigami.blogspot.com"


##############################################################
# load the modules used in the script
from Blender import Curve, Object, Scene
from Blender.Scene import Render 
from Blender import *

##############################################################
# Get rid of the cube from the default scene
scene = Scene.GetCurrent() 
for ob in scene.objects:
   if (cmp(ob.getName(),'Cube')==0):
     scene.objects.unlink(ob)
##############################################################
# misc setup

cu = Curve.New()             # create new  curve data
scn = Scene.GetCurrent()    # get current scene
ob = scn.objects.new(cu)     # make a new curve from the curve data

##############################################################

def bezList2Curve(bezier_vecs):
    '''
    Take a list or vector triples and converts them into a bezier curve object
    '''
    
    def bezFromVecs(vecs):
      '''
      Bezier triple from 3 vecs, shortcut functon
      '''
      bt= BezTriple.New(vecs[0].x, vecs[0].y, vecs[0].z,                        
     vecs[1].x, vecs[1].y, vecs[1].z,
     vecs[2].x, vecs[2].y, vecs[2].z)
      bt.handleTypes= (BezTriple.HandleTypes.FREE, BezTriple.HandleTypes.FREE)
      return bt
    
    # Create the curve data with one point
    cu= Curve.New()
    cu.appendNurb(bezFromVecs(bezier_vecs[0])) # We must add with a point to start with
    cu_nurb= cu[0] # Get the first curve just added in the CurveData
    i= 1 # skip first vec triple because it was used to init the curve
    while i<len(bezier_vecs):
      bt_vec_triple= bezier_vecs[i]
      bt= bezFromVecs(bt_vec_triple)
      cu_nurb.append(bt)
      i+=1
    
    # Add the Curve into the scene
    cu.setFlag(cu.getFlag() | 1)  # this fixes a visibility issue with curves in z axis
    scn= Scene.GetCurrent()
    ob = scn.objects.new(cu)
    return ob

##############################################################
# class to make it easier to pass info to the curve function
    
from Blender.Mathutils import *
class Point(object):
 def __init__(self,x,y,z):
  self.x = x
  self.y = y
  self.z = z

##############################################################
# create the curve of interest from Bezier knots and handles
 
# bezier points -> handle, knot, handle 
bezier_vecs = [ [Point(1,0,0),Point(-1.1,0,0),Point(1,0,0)],
    [Point(1,1,0),Point(1.1,1.1,0),Point(1,1,0)],
    [Point(0,1,0),Point(0,1.1,0),Point(0,1,0)],
    [Point(1,0,1),Point(1.1,1.1,1.1),Point(1,0,1)]]
ob = bezList2Curve(bezier_vecs)
mat = Material.New('curveMat') # create a new Material called 'newMat' 
mat.rgbCol = [1.0, 1.0, 0.0]      # change its color 
ob.getData(False,True).materials += [mat]
ob.getData(False,True).ext1 = 0.1

##############################################################
# draw axes for reference

bezier_vecs = [ [Point(-2,0,0),Point(-2,0,0),Point(-2,0,0)],
    [Point(2,0,0),Point(2,0,0),Point(2,0,0)]]
ob = bezList2Curve(bezier_vecs)
mat = Material.New('curveMat') # create a new Material called 'newMat' 
mat.rgbCol = [1.0, 1.0, 1.0]      # change its color 
ob.getData(False,True).materials += [mat]
ob.getData(False,True).ext1 = 0.1

bezier_vecs = [ [Point(0,-2,0),Point(0,-2,0),Point(0,-2,0)],
    [Point(0,2,0),Point(0,2,0),Point(0,2,0)]]
ob = bezList2Curve(bezier_vecs)
ob.getData(False,True).materials += [mat]
ob.getData(False,True).ext1 = 0.1

bezier_vecs = [ [Point(0,0,-2),Point(0,0,-2),Point(0,0,-2)],
    [Point(0,0,2),Point(0,0,2),Point(0,0,2)]]
ob = bezList2Curve(bezier_vecs)
ob.getData(False,True).materials += [mat]
ob.getData(False,True).ext1 = 0.1

#######################################
# add spheres to points in space to make the gridding understandable
# and make it easier to see what the curve is doing.

xList = range(-2,3,2)
yList = range(-2,3,2)
zList = range(-2,3,2)

for x in xList:
 for y in yList:
  for z in zList:
   markerMe = Mesh.Primitives.UVsphere(8,8,0.3/2.0)
   A = Matrix(
    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [x,y,z,1]) 
   markerMe.transform(A,True)
   if x==0 and y==0 and z==0:
    mat2 = Material.New('curveMat') # create a new Material called 'newMat' 
    mat2.rgbCol = [0.0, 0.0, 1.0] 
    markerMe.materials += [mat2]
   else:
    markerMe.materials += [mat]
   markerOb = scene.objects.new(markerMe,'marker')

#######################################
# render the image and save it
#
context = scn.getRenderingContext() 
# enable seperate window for rendering 
Render.EnableDispWin() 
context.imageType = Render.JPEG
# draw the image 
context.render() 
# save the image to disk 
# to the location specified by RenderPath 
# by default this will be a jpg file 
context.saveRenderedImage('CurveExample.jpg') 

Window.RedrawAll() 
#
########################################

To copy the code snippets easily, see:http://dataorigami.blogspot.com/2009/06/how-to-easily-copy-code-snippets-from.html

To execute the script in Blender, see:http://dataorigami.blogspot.com/2009/06/how-to-execute-script-from-command-line.html

To work with the script in a simple IDE, see:http://dataorigami.blogspot.com/2009/04/developing-scripts-for-blender.html

No comments:

Post a Comment