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:
bpy.ops.mesh.vertex_color_add()
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:
bpy.ops.mesh.vertex_color_add()
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)