# Use Python to add multiple colors to a NURBS curve

I have a NURBS curve which has some thickness (since I set the Bevel Object to be a circle).

I have a list of RGB values specifying what color the curve should be at each point along the NURBS curve.

How can I achieve this with Python? It may have been easy if NURBS curves allowed vertex painting, but it appears that they don't.

I figured out a way to do it.

I created a script that first remembers all the locations of the control points of the NURBS curve (each of which has a color associated with it in a separate variable). Then I converted the curve to a mesh.

Next, for each vertex of the mesh, I loop through all the original NURBS control points, see which one is closest, and then color the vertex of the mesh with the corresponding color.

Here is the result:

It's not perfect, it would be better if the colors slowly blended into each other, but if you have many control points, it might be OK.

I'll include the script I used in case anyone finds it useful:

import bpy
from mathutils import Vector
import copy

def color_nurbs_curve(nurbs_obj, color_list):
"""Converts the NURBS curve which should already have a bevel object so it has some width.

color_list should be a list of colors each of which is a 3 element list with [R,G,B]."""

nurbs_coords = copy.deepcopy( [ nurbs_obj.data.splines[0].points[i].co for i in range(len(nurbs_obj.data.splines[0].points)) ] )

#Error checking
if len(nurbs_coords) != len(color_list):
raise RuntimeError('The color list must have a number of colors equal to the number of control points of your bezier curve')
if nurbs_obj.data.bevel_object == None:
raise RuntimeError('Your NURBS curve must have a bevel object')

scn = bpy.context.scene

#Convert to mesh
scn.objects.active = nurbs_obj
nurbs_obj.select = True
bpy.ops.object.convert( target='MESH' )
#sometimes this conversion results in a bunch of doubles, so I remove the doubles
remove_doubles(nurbs_obj)

mesh = nurbs_obj.data

if len(mesh.vertex_colors) == 0:

nurbs_obj.active_material = bpy.data.materials.new('material')
nurbs_obj.active_material.use_vertex_color_paint = True

print("test",nurbs_coords[1])

#loop through each vertex
num_verts = len(mesh.vertices)
for vert_i in range(num_verts):

#record shortest separation. -99 signals unset.
shortest_sep = -99

#loop through all the original bezier points to see
#which one is closest and then color it with the corresponding color
count=0
for b_point in nurbs_coords:

b_point.resize_3d()
temp_sep = (mesh.vertices[vert_i].co -  b_point).length

if temp_sep < shortest_sep or shortest_sep == -99:
shortest_sep = temp_sep
color = color_list[count]

count += 1

color_vertex( nurbs_obj, vert_i, color )
print( "Finished vertex: " + str(vert_i) + "/" + str(num_verts) )

def color_vertex(obj, vert, color=[1,0,0]):
"""
Paints a single vertex

"""
mesh = obj.data
scn = bpy.context.scene

#check if our mesh already has Vertex Colors, and if not add some... (first we need to make sure it's the active object)
scn.objects.active = obj
obj.select = True
if len(mesh.vertex_colors) == 0:

i=0
for poly in mesh.polygons:
for vert_side in poly.loop_indices:
global_vert_num = poly.vertices[vert_side-min(poly.loop_indices)]
if vert == global_vert_num:
mesh.vertex_colors[0].data[i].color = color

i += 1

def remove_doubles(obj):
""" Removes doubles using default settings"""
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='TOGGLE') #I believe objects are created with the vertices all not selected
bpy.ops.mesh.remove_doubles()
bpy.ops.object.mode_set(mode='OBJECT')

##Example Usage
##nurbs_obj = bpy.data.objects['NurbsCurve']
##color_list = [  [1.0, 0.0, 0.0], [1.0, 0.25, 0.0], [1.0, 0.5, 0.0], [0.5, 0.0, 0.0], [0.0, 0.75, 0.0], [0.0, 1.0, 0.0], [0.5, 0.5, 0.5], [0.75, 0.15, 0.9]   ]
##color_nurbs_curve(nurbs_obj, color_list)

• BTW, I'd be interested in hearing more ideas for solving this problem. Jan 10 '14 at 8:22

You could use a Colour Ramp to get a variation of colour along a curve but I don't see an easy way to match a point on a curve to a point in the ramp.

I think you may want to create a mesh cylinder and define the colours on it at the locations you want and then use a curve modifier to deform the mesh to the shape you want.

Also the python to create the material will vary depending on whether you are going to use blender internal or cycles.

• Good ideas, I wasn't able to get them working but it seems like they should work. I found another way, which I'll post. Jan 10 '14 at 4:58