Python Tools - Session 2B

Objects on Curves and Mesh Vertices

January 2020

Session Navigation

Overview

Moving beyond the mosaic grid, this session explores placing objects along NURBS curves and on mesh vertices. You'll learn how to query curve parameters, evenly distribute duplicated objects along a path, and add randomized scaling for organic variation. These techniques are fundamental for environment art — think fences, railings, pillars, and foliage scatter.

Key Concepts

  • FOR loops with 3D components — iterating over vertices (mesh.verts) and curve CVs (curve.getCVs())
  • Vertex positions — querying world-space positions with vert.getPosition(space="world")
  • Curve parameterization — using getPointAtParam() to find positions along a NURBS curve
  • findParamFromLength() — converting curve arc length to parameter space for even spacing
  • Object duplication — using pm.duplicate() to create copies of a source object
  • Random variation — applying random.uniform() to scale for natural-looking distributions
  • Cleanup patterns — deleting previously generated objects by name before re-running the script

Distributing Objects Along a Curve

The core algorithm for evenly spacing objects along a curve:

  1. Get the total parameter length of the curve with findParamFromLength(length())
  2. Divide by the desired number of objects to get the step size
  3. Loop through, incrementing the parameter and querying the position at each step
  4. Duplicate and move the source object to each position

Code

This script distributes duplicated objects evenly along a NURBS curve, with random scale variation. It first cleans up any previous run, then creates the new distribution:

import pymel.core as pm
import random

OBJ_NAME = "Pillar"

# Delete the previous locators
for obj in pm.ls(type='mesh'):
    if OBJ_NAME in obj.name():
        pm.delete(obj.getTransform())


path = pm.PyNode('curve1')
object = pm.PyNode('pCylinder1')

print path.numCVs()
for point in path.getCVs():
    print point
print path.getPointAtParam(4.5)
print path.length()

# Now let's go along the curve

curve_length = path.findParamFromLength(path.length())

num_objects = 50
position = 0.0
for i in xrange(0, num_objects):
    print position

    position += (curve_length/num_objects)

    position = min(position, curve_length)


    # Duplicate the object and rename it so we can delete it
    dupe = pm.duplicate(object)[0]
    dupe.rename(OBJ_NAME)
    pm.move(dupe, path.getPointAtParam(position, space='world'))

    # Randomly uniformly scale each pillar
    random_scale = random.uniform(0.7, .8)
    dupe.sx.set(random_scale)
    dupe.sy.set(random_scale)
    dupe.sz.set(random_scale)
Scene Setup

Before running this script, you need two things in your Maya scene:

  • A NURBS curve named curve1 — this is the path objects will follow
  • A polygon object named pCylinder1 — this is the source object to duplicate
← Prev: Session 2A Next: Session 3A →