Skip to content

Point Operation Nodes

Point Operation nodes transform, compute, or reorganize point data without filtering. They may modify positions, rotations, scales, density, or metadata attributes of each point.

All nodes in this category share the amber/gold node color and belong to the Point Operations category.


Bounds Modifier

Description: Modifies the per-point bounding box (boundsMin / boundsMax). Three modes let you replace, scale, or expand the existing bounds. Bounds are used by spatial nodes such as Difference, Intersection, and Self Pruning.

Ports

NameDirectionTypeNotes
InInputPointPoints whose bounds are to be modified.
OutOutputPointPoints with updated bounds.

Settings

FieldTypeDefaultDescription
boundsModeModeSetSet: replaces bounds with boundsMin/boundsMax exactly. Scale: multiplies existing bounds by scaleFactor. Expand: adds boundsMin/boundsMax offsets to the existing bounds (expand with positive values, shrink with negative).
boundsMinVector3(-0.5, -0.5, -0.5)Minimum corner offset. Used in Set (absolute) and Expand (additive) modes.
boundsMaxVector3(0.5, 0.5, 0.5)Maximum corner offset. Used in Set (absolute) and Expand (additive) modes.
scaleFactorfloat1.0Uniform multiplier applied to existing boundsMin and boundsMax in Scale mode.

Notes

  • Bounds are stored in the point's local space (relative to the point transform, not world space).
  • Placing this node before Self Pruning lets you control the effective exclusion radius for overlap-based pruning.
  • Expand with equal negative values on min and max shrinks bounds toward zero.

Copy Points

Description: Stamps the Source point pattern onto every Target point, producing one copy of the source layout per target. The result is the Cartesian product of source and target points. Analogous to Houdini's "Copy to Points" node.

Ports

NameDirectionTypeNotes
SourceInputPointThe template point set that is copied.
TargetInputPointEach point in this set receives a full copy of Source.
OutOutputPointAll stamped copies combined in a single output.

Settings

FieldTypeDefaultDescription
rotationInheritanceInheritModeRelativeHow the final rotation is derived. Relative: targetRotation × sourceRotation (combined). Source: only source rotation. Target: only target rotation.
scaleInheritanceInheritModeRelativeHow the final scale is derived. Relative: targetScale × sourceScale (component-wise product). Source: only source scale. Target: only target scale.

Notes

  • Position is always computed in Relative mode: the source offset is transformed by the target rotation and scale, then added to the target position. This setting cannot be changed.
  • Output density is min(sourceDensity, targetDensity) per point.
  • Output metadata is cloned from the first Source input.
  • If either Source or Target is empty, the output is empty.

Distance

Description: Computes the 3D distance from each Source point to the nearest Target point. Writes the result to a metadata attribute and optionally maps it to density.

Ports

NameDirectionTypeNotes
SourceInputPointPoints to measure from.
TargetInputPointReference points to measure distance to.
OutOutputPointSource points with distance written as an attribute.

Provided Attributes

When outputSelector is set to a custom attribute, this node declares it as a Float attribute to downstream nodes.

AttributeTypeDescription
(custom name)FloatRaw distance in world units to the nearest target point.

Settings

FieldTypeDefaultDescription
outputSelectorPPGAttributeSelector (Write)"Distance"The metadata attribute (or built-in point property) to write the distance into.
setDensitybooltrueIf enabled, also sets density = 1 - saturate(distance / maxDistance). Points at or beyond maxDistance get density = 0; points at distance 0 get density = 1.
maxDistancefloat10.0Normalization distance used when setDensity is true. Clamped to a minimum of 0.0001 internally.

Notes

  • This node uses a Burst-compiled parallel job (O(N × M) brute-force nearest search).
  • If Target is empty, the output is empty.
  • Pair with Filter by Attribute or Filter by Density to select points within a proximity band.

Lloyd Relaxation

Description: Iteratively relaxes point positions toward uniform spacing using Lloyd's algorithm. On each iteration, each point moves a fraction of the way toward the centroid of its K=6 nearest neighbors.

Ports

NameDirectionTypeNotes
InInputPointPoints to relax.
OutOutputPointRelaxed points (positions updated, all other data preserved).

Settings

FieldTypeDefaultDescription
iterationsint [1..10]3Number of relaxation passes. More iterations produce more uniform spacing at increased cost.
constrainToBoundsbooltrueIf enabled, points are clamped to the axis-aligned bounding box of the original input after each iteration, preventing drift outside the original region.

Notes

  • The relaxation factor is 0.5 (each point moves half-way to the centroid), which is a fixed internal constant.
  • All inputs are flattened into a single point list before relaxation; the output is a single merged PPGPointData.
  • Uses a Burst-compiled parallel job per iteration. Each iteration is sequential; the job for iteration N must complete before N+1 begins.
  • If the input has 1 or fewer points, the output is returned unchanged.
  • This node is useful after random scatter to reduce clumping without fully regularizing to a grid.

Look At

Description: Rotates each point so that its forward axis (Z+) faces either a fixed world-space position or a direction vector.

Ports

NameDirectionTypeNotes
InInputPointPoints to rotate.
OutOutputPointPoints with updated rotation. Position and scale are preserved.

Settings

FieldTypeDefaultDescription
lookAtModeModePositionPosition: each point rotates to face the target world position. Direction: all points rotate to align their forward axis with the target vector.
targetVector3(0, 0, 0)Target world position (Position mode) or look direction (Direction mode).
keepUprightbooltrueIf true, uses (0, 1, 0) as the up vector for LookRotationSafe. If false, the point's existing up vector is preserved when computing the look rotation.

Notes

  • Points whose computed direction vector has length < 0.0001 (e.g. a point sitting exactly on the target position) are passed through without rotation change.
  • Scale is extracted from the existing transform and reapplied after the rotation is rebuilt.
  • In Direction mode, target is treated as a direction vector and does not need to be normalized — but a zero vector causes the point to be skipped.

Merge

Description: Combines all connected input point sets into a single output without any filtering or deduplication. The simplest way to concatenate point streams.

Ports

NameDirectionTypeNotes
InInputPointOne or more point sets. Accepts multiple connections.
OutOutputPointAll input points concatenated in connection order.

Settings

No configurable settings.

Notes

  • Output metadata is cloned from the first connected input.
  • Point order in the output matches the connection order of the In port.
  • If you need spatial deduplication, use Union instead.

Nearest Seed Assign

Description: Assigns each source point to its nearest seed point (Voronoi cell assignment). Writes the seed index and distance as metadata attributes, enabling downstream zone splitting with Filter by Attribute.

Ports

NameDirectionTypeNotes
SourceInputPointRequired. Points to assign.
SeedsInputPointRequired. The seed points that define the Voronoi cells.
OutOutputPointSource points with seed index and distance attributes written.

Provided Attributes

Both attributes are declared on the output so downstream selectors can discover them.

AttributeTypeDefault NameDescription
Index attributeInt"SeedIndex"Zero-based index of the nearest seed point.
Distance attributeFloat"SeedDistance"World-space distance to the nearest seed.

Settings

FieldTypeDefaultDescription
indexSelectorPPGAttributeSelector (Write)"SeedIndex"Attribute to write the nearest seed index into.
distanceSelectorPPGAttributeSelector (Write)"SeedDistance"Attribute to write the distance to the nearest seed into.
maxDistancefloat20.0Points farther than this from every seed are discarded from the output. Clamped to a minimum of 0.001 internally.
setDensityFromDistancebooltrueIf enabled, sets density = 1 - saturate(distance / maxDistance).

Notes

  • Search is a brute-force O(N × M) loop. For large point and seed counts, consider limiting scope with filter nodes first.
  • To split points by zone, connect Out to a Filter by Attribute node, set the attribute to SeedIndex, and use Equal / NotEqual comparisons for each zone index.
  • Output metadata starts empty; attribute columns are created fresh for each execution.

Project to Surface

Description: Projects each point onto a physical surface by casting a ray downward from above the point. Updates the Y position to the hit point and optionally aligns the point's rotation to the surface normal.

Ports

NameDirectionTypeNotes
InInputPointPoints to project.
SurfaceInputSurfaceOptional. If connected, raycasts only against these specific colliders. If disconnected, uses layerMask against all scene colliders.
OutOutputPointProjected points (misses removed by default).

Settings

FieldTypeDefaultDescription
rayOffsetfloat50.0Height (in world units) above each point from which the ray originates. Increase this if your terrain has high elevation variation.
maxRayDistancefloat100.0Maximum ray length. Rays that travel this distance without a hit are considered misses.
layerMaskLayerMaskEverything (~0)Physics layers to include when no Surface input is connected.
alignToNormalboolfalseIf true, re-orients the point so its Y-axis aligns with the surface normal, keeping the existing forward direction projected onto the surface plane.
removeMissesbooltrueIf true, points that do not hit any surface are removed from the output. If false, miss points are passed through at their original position.

Notes

  • All point positions are converted local → world for raycasting, then world → local for output. This is necessary because the graph operates in the component's local space.
  • In Edit Mode, Physics.SyncTransforms() is called automatically so colliders match their current GameObject transforms.
  • When alignToNormal is enabled, the existing forward direction is projected onto the hit-normal plane to avoid sudden spin artifacts. If the forward vector is nearly collinear with the normal, a fallback direction ((0,0,1) or (1,0,0)) is used.
  • steepness is automatically written to each projected point as 1 - dot(normal, up).

Random Choice

Description: Randomly routes each input point to either output A or output B using a seeded probability ratio.

Ports

NameDirectionTypeNotes
InInputPointPoints to split.
AOutputPointPoints selected with probability ratio.
BOutputPointPoints selected with probability 1 - ratio.

Settings

FieldTypeDefaultDescription
ratiofloat [0..1]0.5Probability that a given point goes to output A. Setting ratio = 0 sends everything to B; ratio = 1 sends everything to A.

Notes

  • Uses a seeded random value derived from both the node's seed and each point's individual seed field, so results are deterministic and stable even when the point set changes.
  • This node respects the graph's global seed (UseSeed = true). Changing the seed produces a different split.
  • Use this node to assign points to different prefab categories or to create two distinct populations from a single scatter.

Self Pruning

Description: Removes points that are too close to each other, using each point's bounds extent as a size proxy. Larger (or smaller) points win priority depending on the chosen mode.

Ports

NameDirectionTypeNotes
InInputPointPoints to prune.
OutOutputPointPruned point set with overlapping points removed.

Settings

FieldTypeDefaultDescription
modePruningModeLargeToSmallLargeToSmall: process points from largest to smallest bounds extent; larger points block smaller ones. SmallToLarge: process from smallest to largest; smaller points block larger ones. RemoveDuplicates: removes points within 0.001 units of each other regardless of size, using a spatial hash.
minDistancefloat1.0Minimum allowed world-space distance between any two kept points. Ignored in RemoveDuplicates mode (which uses a fixed threshold of 0.001).

Notes

  • All inputs are flattened into a single pool before pruning; the output is a single merged PPGPointData.
  • Bounds extent (size.x * size.y * size.z) is used as the sort key. Set bounds correctly with Bounds Modifier before this node.
  • Uses a Burst-compiled job for the distance/duplicate computation.
  • LargeToSmall is the typical mode for vegetation: large trees block placement of smaller shrubs in their vicinity.

Transform Points

Description: Applies random or fixed translation, rotation, and scale to each input point. All three transforms can be specified as min/max ranges; a seeded random value is sampled per point within each range.

Ports

NameDirectionTypeNotes
InInputPointPoints to transform.
OutOutputPointTransformed points.

Settings

Offset

FieldTypeDefaultDescription
offsetMinVector3(0, 0, 0)Minimum translation per axis.
offsetMaxVector3(0, 0, 0)Maximum translation per axis.
absoluteOffsetboolfalseIf true, the offset is applied in world space. If false, the offset is applied in the point's local space (relative to the point's own orientation).

Rotation (Euler degrees)

FieldTypeDefaultDescription
rotationMinVector3(0, 0, 0)Minimum rotation (degrees) per axis.
rotationMaxVector3(0, 0, 0)Maximum rotation (degrees) per axis.

Scale

FieldTypeDefaultDescription
scaleMinVector3(1, 1, 1)Minimum scale per axis.
scaleMaxVector3(1, 1, 1)Maximum scale per axis.
uniformScaleboolfalseIf true, only the X component of scaleMin/scaleMax is used, and the same value is applied to all three axes.

Notes

  • This node respects the graph's global seed (UseSeed = true). Changing the seed changes all random offsets/rotations/scales.
  • Setting offsetMin == offsetMax (per axis) produces a fixed, non-random offset on that axis.
  • Setting rotationMin == rotationMax produces a fixed rotation. A common setup is rotationMin.y = 0, rotationMax.y = 360 for random yaw.
  • Uses a Burst-compiled parallel job, making it efficient for large point counts.
  • The transform is applied on top of the existing point transform, not as a replacement.

Procedural Placement Graph for Unity