1
$\begingroup$

I'm working on a visualization problem.

I'm given a curve with a list of vertices. There is a color assigned to each vertex.

My question is "how do I generate the bevel curve by linearly interpolating the vertex colors?" Any ideas? It seems like I need to write some python scripts to achieve this.

Thanks!

$\endgroup$
  • 1
    $\begingroup$ As far as I know bezier curve objects can't hold vertex color information, you will likely need to convert to a mesh object eventually $\endgroup$ – Duarte Farrajota Ramos Sep 16 '18 at 1:23
0
$\begingroup$

With a Python script you can populate a Color Ramp in the material according to the color specification. With the curve's UV coordinates you can color the bevelled curve with the correct color.

final image

I start with a manually created Bezier curve with its bevel object set and the material assigned, as well as the node tree for the material. It's also possible to create the whole curve object in Python, just as I think it's possible to set up the node tree.

material node tree

In the Data tab of the bezier curve under Texture Space activate “Use UV for mapping”.

uv mapping setting

I supply the coordinates of the curve's points and their color values in a csv file called point_data.csv within Blender. If your files are stored in another format or in an external file, you'll have to modify the code accordingly. Perhaps you might also want to supply the handle positons instead of using auto-handles.

x, y, z, r, g, b, a
-1, -1, 0, 1, 0, 0, 1
-2, 0, 0, 0, 0, 1, 1
-1, 1, 0, 1, 0, 0, 1
2, 0, 0, 1, 0, 0, 0

This is the script that was used to generate the image above. The coordinate grid was added manually to check if the color positions are correct.

import bpy
import csv
from itertools import tee
from mathutils import Vector

material = bpy.data.materials['Material']
ramp = material.node_tree.nodes['ColorRamp'].color_ramp
# Clear the color ramp of all elements but the first
# which can't be removed
for e in reversed(ramp.elements[1:]):
    ramp.elements.remove(e)

# Modify an existing curve object instead of creating new one
curve = bpy.data.objects['BezierCurve']
curve.data.splines.remove(curve.data.splines[0])
spline = curve.data.splines.new('BEZIER')


# Read color info from internal csv file.
# Could also load from external file.
point_data = bpy.data.texts['point_data.csv']
lines = (line.body for line in point_data.lines)
reader = csv.DictReader(lines, skipinitialspace=True)
reader, line_counter = tee(reader)
line_count = sum(1 for line in line_counter)
for i, line in enumerate(reader):
    vals = {k:float(v) for k,v in line.items()}

    ramp_position = i / (line_count-1)

    if i==0:
        ramp_element = ramp.elements[0]
        ramp_element.position = 0
    else:
        ramp_element = ramp.elements.new(ramp_position)
        spline.bezier_points.add(1)

    ramp_element.color = [vals[c] for c in ['r', 'g', 'b', 'a']]

    spline_point = spline.bezier_points[i]
    spline_point.co = Vector(vals[c] for c in ['x', 'y', 'z'])
    spline_point.handle_left_type = 'AUTO'
    spline_point.handle_right_type = 'AUTO'
$\endgroup$
  • $\begingroup$ Fantastic! That's what I want! Thank you so much! $\endgroup$ – Rundong Zhao Sep 17 '18 at 22:17

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.