← Back to Blog

General

Create Custom Nodes with Python and Expressions in Mesh Morpher Studio

By Admin ·

Mesh Morpher Studio ships with a 260+ node graph, but the most powerful node in it is the one you write yourself. The Wrangle node is a small code editor inside the graph: type an expression or a Python script, press Run, and the node deforms meshes, paints weight maps or bakes attributes exactly the way you told it to. This video walks through building your own nodes with it, from a two-line deformer to a node with its own buttons.

▶ Watch the video on YouTube

You can download the node created in this video and load it straight into Mesh Morpher Studio:

Download Python Sculpt Lab.mmnode

28 KB · .mmnode

One node, any logic

A Wrangle expression runs over every vertex of the mesh wired into the node (or over triangles, or once for the whole mesh - that is the Run Over setting). You read and write the live channels directly: P for position, N for the normal, Cd for vertex colour, mask for whatever weight map is wired into the Mask pin. A complete masked inflate deformer, straight from the editor's Examples menu, is two lines:

float amount = 2.0 * mask;
P += normalize(N) * amount;

Paint the mask, turn the amount, and you have a sculpting tool that did not exist five minutes ago.

Parameters become pins

What makes a Wrangle node feel like a real custom node is its Parameters. Declare a Float, Mesh or Weight Map parameter and it appears as an actual pin and control on the node - your logic gets an interface for free. Reference them from the expression with ch() for values, wmap() for weight maps, and by pin name for meshes:

vector donorPos = pointpos("Reference", ptnum);
P = lerp(P, donorPos, ch("blend"));

That is a blend-shape node in three lines: wire any index-matched mesh into the Reference pin, drag the blend slider, and the mesh morphs toward it. The same idiom scales to donor meshes (surfattr("Donor", ...)), distance falloffs (neardist("Reference", P)) and weight-map outputs (wmap("Weights") = ...).

Real loops over real topology

The expression language is not a calculator - it has functions, conditionals and loops over the mesh itself. This is the Examples menu's iterative smooth: average each vertex toward its one-ring neighbours, then let the node's Iterations setting re-run the whole pass five times:

vector sum = vec3(0, 0, 0);
float count = 0;
foreach (nb in neighbours(ptnum)) { sum += pointpos(nb); count += 1; }
if (count > 0) { P = sum / count; }

Python in the same document

When an expression is not enough, add a #@python block to the same node. The script sees the mesh through the mm API (mm.P, mm.num_points, mm.set_detail...), can declare package requirements with #@requires, and hands values to the expression below through py() and pyv():

#@python
#@requires numpy
import numpy as np
p = np.frombuffer(mm.P, dtype=np.float64).reshape(-1, 3)
lo, hi = p.min(axis=0), p.max(axis=0)
mm.set_detail("centre", ((lo + hi) * 0.5).tolist())
mm.set_detail("longest", float((hi - lo).max()))
#@wrangle
vector c = pyv("centre");
float s = py("longest");
P += normalize(P - c) * (s * 0.02);

Python does the once-per-mesh math with NumPy; the expression applies it per vertex. And if you skip the #@wrangle section entirely, the script alone is the node - a Python-only node that can write real attributes:

p = mm.P
n = mm.num_points
def x_of(i):
    return float(p[i][0] if getattr(p, "ndim", 1) == 2 else p[i * 3])
buf = bytearray(n * 8)
view = memoryview(buf).cast('d')
cx = (sum(x_of(i) for i in range(n)) / n) if n else 0.0
for i in range(n):
    view[i] = abs(x_of(i) - cx)
mm.set_attrib("distFromCenterX", buf, "vertex", "float")
mm.note("Python-only: no expression needed")

Give the node its own buttons

Custom functionality goes beyond deformation. A script can declare UI on the node itself with mm.ui.button() and branch on mm.event - an ordinary Run press previews, pressing the button commits:

mm.ui.button("Bake", "Write the vertex count into @baked")
n = mm.num_points
if mm.event == "button:Bake":
    buf = bytearray(n * 8)
    view = memoryview(buf).cast('d')
    for i in range(n):
        view[i] = float(i)
    mm.set_attrib("baked", buf, "vertex", "float")

Interactive scripts can go further still and open their own window - a slider dialog, an Apply button - running on an isolated interpreter so the app stays responsive.

Start from the Examples menu

Every snippet above ships in the Wrangle editor's Examples menu, and the finished node from the video is available to download, and inserting one declares the parameters it needs automatically - wire a mesh, press Run, then start editing. Watch the video for the full walkthrough, and if you do not have the app yet, Mesh Morpher Studio is a self-contained Windows application - no Unreal Engine required. Also see the Studio release post for everything else in the app, or compare licenses on the pricing page.

#studio#python#wrangle#nodes#tutorial


Related posts

Looking for reference material? Read the Mesh Morpher documentation or see pricing & licenses.