6
$\begingroup$

I'm writing a script to use with headless Blender but can't seem to figure out how to adjust the fall off curve of the Vertex Weight Edit modifier. Just want to move the upper point (1,1) down to something like (1,0.4). Picture for reference of desired outcome.

enter image description here

Thanks in advance for any help!

$\endgroup$

1 Answer 1

10
+250
$\begingroup$

As a one-liner :

bpy.context.active_object.modifiers["VertexWeightEdit"].map_curve.curves[0].points[1].location = (1, 0.4)

Let's see how we cracked this using the Console inside Blender :

obj = bpy.context.active_object
obj
>>> bpy.data.objects['Cube']

We selected the active object. Let's get a reference to the modifier.

mod = obj.modifiers["VertexWeightEdit"]
mod
>>> bpy.data.objects['Cube'].modifiers["VertexWeightEdit"]

Now let's print its attributes so we can see where to dig around.

dir(mod)
>>> ['__doc__', '__module__', '__slots__', 'add_threshold', 'bl_rna', 'default_weight', 'falloff_type', 'invert_falloff', 'invert_mask_vertex_group', 'is_active', 'map_curve', 'mask_constant', 'mask_tex_map_bone', 'mask_tex_map_object', 'mask_tex_mapping', 'mask_tex_use_channel', 'mask_tex_uv_layer', 'mask_texture', 'mask_vertex_group', 'name', 'normalize', 'remove_threshold', 'rna_type', 'show_expanded', 'show_in_editmode', 'show_on_cage', 'show_render', 'show_viewport', 'type', 'use_add', 'use_apply_on_spline', 'use_remove', 'vertex_group']

We've got some interesting things here. We're interested in map_curve.

curve_map = mod.map_curve
curve_map
>>> bpy.data.objects['Cube']...CurveMapping

dir(curve_map)
>>> ['__doc__', '__module__', '__slots__', 'bl_rna', 'black_level', 'clip_max_x', 'clip_max_y', 'clip_min_x', 'clip_min_y', 'curves', 'evaluate', 'extend', 'initialize', 'reset_view', 'rna_type', 'tone', 'update', 'use_clip', 'white_level']

type(curve_map)
>>> <class 'bpy.types.CurveMapping'>

curves = curve_map.curves
curves
>>> bpy.data.objects['Cube']...curves

type(curves)
>>> <class 'bpy_prop_collection'>

A Curve mapping object holds curves. Here we only have one but some curve mapping objects have more (eg RGB curves node in the shader editor). We can access the only curve by accessing the first element.

curve = curves[0]
curve
>>> bpy.data.objects['Cube']...CurveMap

type(curve)
>>> <class 'bpy.types.CurveMap'>

dir(curve)
>>> ['__doc__', '__module__', '__slots__', 'bl_rna', 'points', 'rna_type']

A Curve Map object holds points.

points = curve.points
points
>>> bpy.data.objects['Cube']...points

type(points)
>>> <class 'bpy_prop_collection'>

The Points object is a collection holding reference to points.

p1 = points[1] # We access the second point, which is index 1 with 0-based indexing
>>> p1
bpy.data.objects['Cube']...CurveMapPoint

type(p1)
>>> <class 'bpy.types.CurveMapPoint'>

dir(p1)
>>> ['__doc__', '__module__', '__slots__', 'bl_rna', 'handle_type', 'location', 'rna_type', 'select']

A Point object holds the point location. location is supposed to be a float array, so we can use a tuple.

Note that you want to be tweaking p1.handle_type to change the interpolation type.

p1.location = (1, 0.4)

If you just want to modify the y value (second index of the array) : p1.location[1] = 0.4

You'll notice when you run this and hover your cursor over the widget that the point moves, but not the actual curve. Digging in the docs shows an update method we can use.

curve_map.update()

If you're using this in a script and don't want to have to hover you cursor over the widget to force a UI redraw, you can tag all the areas to redraw on the next frame.

[a.tag_redraw() for a in bpy.context.screen.areas]


Demo code with some safety checks:

import bpy
from mathutils import Vector

obj = bpy.context.object
vertex_edit_modifier = None

# Get the modifier
for modifier in obj.modifiers:
    if modifier.type == 'VERTEX_WEIGHT_EDIT':
        if modifier.falloff_type == 'CURVE':
            vertex_edit_modifier = modifier

# If the modifier is present and its type is set to 'Custom Curve'
if vertex_edit_modifier:
    # Get the curve collection
    curve_map = vertex_edit_modifier.map_curve
    # Access the points of the curve (there is only one curve)
    for count, point in enumerate(curve_map.curves[0].points):
        # Compare the location
        if point.location == Vector((1.0, 1.0)):
            # Set the values
            point.location = Vector((1.0, 0.4))
            print("Point No {} set to custom location".format(count))
    # Update the Curve
    curve_map.update()
$\endgroup$
4
  • 2
    $\begingroup$ Very nice... 3 minutes to late, wrote a demo a demo script with a few checks: pasteall.org/cVfR What do you think about adding it to your answer? $\endgroup$
    – brockmann
    Nov 3, 2021 at 11:16
  • $\begingroup$ @brockmann yeah no problem go ahead :) $\endgroup$
    – Gorgious
    Nov 3, 2021 at 12:22
  • 2
    $\begingroup$ @brockmann and Gorgious - wow this is such an educational answer. Very helpful and I now know how to go about solving similar problems on my own! Thank you! $\endgroup$ Nov 3, 2021 at 12:41
  • 1
    $\begingroup$ y'all make a good teacher, Gorgious ! $\endgroup$
    – james_t
    Nov 6, 2021 at 16:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .