Skip to content

geometry

geometry

MCP tools for SOP geometry inspection and manipulation.

Functions:

Name Description
compare_volumes

How much of one field sits in each band of another field.

find_nearest_point

Find the nearest point(s) to a given position.

get_attrib_stats

Aggregate statistics for numeric attributes: min, max, mean, sum.

get_attrib_values

Read attribute values as a flat array with pagination.

get_attribute_info

Get metadata for a geometry attribute.

get_bounding_box

Get the bounding box of a SOP node's geometry.

get_geometry_info

Get geometry summary for a SOP node.

get_group_members

Get element indices in a geometry group, with pagination.

get_groups

List all geometry groups on a SOP node.

get_points

Read point positions and attributes with pagination.

get_prim_intrinsics

Get intrinsic values for primitives: one, many, or all of them.

get_prims

Read primitive data and attributes with pagination.

get_volume_info

Per-volume name, resolution, active voxels, value range, mean and sum.

sample_geometry

Sample evenly distributed points from a SOP node's geometry.

sample_volume

Read named volume fields at world positions, or at another SOP's points.

set_detail_attrib

Set a detail attribute on a SOP node.

Functions:

compare_volumes async

compare_volumes(
    ctx: Context,
    node_path: str,
    field: str,
    against: str,
    against_node: str | None = None,
    bands: int | list[float] = 10,
) -> dict

How much of one field sits in each band of another field.

"How much density is inside the collider" is field="density", against="surface" (an SDF), bands=[-1000, 0, 1000]: the first band's field_total is what is inside. Both are sampled on a grid over field's box.

Parameters:

Name Type Description Default
node_path
str

SOP holding field.

required
field
str

Volume to total, e.g. "density".

required
against
str

Volume whose value picks the band, e.g. a collider SDF.

required
against_node
str | None

SOP holding against, when not node_path.

None
bands
int | list[float]

Band count, or a list of band edges.

10

find_nearest_point async

find_nearest_point(
    ctx: Context, node_path: str, position: list[float], max_results: int = 1
) -> dict

Find the nearest point(s) to a given position.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
position
list[float]

Query position as [x, y, z].

required
max_results
int

Max nearest points to return.

1

get_attrib_stats async

get_attrib_stats(
    ctx: Context,
    node_path: str | None = None,
    attribs: list[str] | None = None,
    attrib_class: str = "point",
    frames: list[float] | None = None,
    node_paths: list[str] | None = None,
    percentiles: list[float] | None = None,
    group: str | None = None,
    unique: bool = False,
    distance_to: str | None = None,
) -> dict

Aggregate statistics for numeric attributes: min, max, mean, sum.

Use this to prove something is happening, rather than reading values. get_geometry_info names the attributes; get_attrib_values returns every value, which on a 60k-point cache tells you nothing you can read. Vector attributes also report per-component ranges, so a velocity field's per-axis extremes come back in the same call.

Parameters:

Name Type Description Default
node_path
str | None

SOP node path.

None
attribs
list[str] | None

Attribute names. Omit for every attribute of the class. A name written "age/life" is the ratio of two attributes, per element (elements dividing by zero are counted, not used).

None
attrib_class
str

"point", "prim", "vertex" (uv and N usually live there) or "detail".

'point'
frames
list[float] | None

Measure at each of these frames: a row per node per frame, frames cooked in increasing order, the current frame put back. element_count is the point count and P's per-component min/max the bounds, so a sim's count and spread over time is ONE call.

None
node_paths
list[str] | None

Several nodes (variants) in the same call, instead of node_path.

None
percentiles
list[float] | None

e.g. [5, 50, 95] for the distribution (50 = median).

None
group
str | None

Only the elements in this group pattern, as a SOP group field takes it: "grp", "@id>=0", "0-99"; space-separated parts add up. Point and prim classes.

None
unique
bool

Count distinct values of integer and string attributes (unique_count, most_common); for the prim class also vertices_per_prim, a trail's length and its distribution.

False
distance_to
str | None

A SOP whose surface each point's distance is measured to (distance_to in the reply: min / max / mean, percentiles): particles crawling on or hovering over a mesh. Point class; the scene is not changed. Both are taken in their own SOP space: object transforms are not applied, so use it within one object.

None

get_attrib_values async

get_attrib_values(
    ctx: Context,
    node_path: str,
    attrib_name: str,
    attrib_class: str = "point",
    start: int = 0,
    count: int = 200,
) -> dict

Read attribute values as a flat array with pagination.

For spot-checking a few values prefer sample_geometry — it returns a representative spread of points with all their attributes in one call. Use get_attrib_values when you need a specific slice of one attribute.

Values are element-major: for a float3 attribute every 3 consecutive values belong to one element. Check has_more and increment start to read subsequent pages.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
attrib_name
str

Attribute name.

required
attrib_class
str

"point", "prim", "vertex", or "detail".

'point'
start
int

First element index to return.

0
count
int

Max elements per page (default 200).

200

get_attribute_info async

get_attribute_info(
    ctx: Context, node_path: str, attrib_name: str, attrib_class: str = "point"
) -> dict

Get metadata for a geometry attribute.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
attrib_name
str

Attribute name.

required
attrib_class
str

"point", "prim", "vertex", or "detail".

'point'

get_bounding_box async

get_bounding_box(ctx: Context, node_path: str) -> dict

Get the bounding box of a SOP node's geometry.

Parameters:

Name Type Description Default
node_path
str

Node path.

required

get_geometry_info async

get_geometry_info(ctx: Context, node_path: str, output_index: int = 0) -> dict

Get geometry summary for a SOP node.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
output_index
int

Which output to read, for nodes with several (FLIP compress, Vellum solver, whitewater source): 0 is the first.

0

get_group_members async

get_group_members(
    ctx: Context,
    node_path: str,
    group_name: str,
    group_type: str = "point",
    start: int = 0,
    count: int = 5000,
) -> dict

Get element indices in a geometry group, with pagination.

Check has_more and increment start to read subsequent pages.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
group_name
str

Group name.

required
group_type
str

"point", "prim", or "edge".

'point'
start
int

First element index to return.

0
count
int

Max elements per page (default 5 000).

5000

get_groups async

get_groups(ctx: Context, node_path: str) -> dict

List all geometry groups on a SOP node.

Parameters:

Name Type Description Default
node_path
str

Node path.

required

get_points async

get_points(
    ctx: Context,
    node_path: str,
    attributes: list[str] | None = None,
    start: int = 0,
    count: int = 200,
    group: str | None = None,
) -> dict

Read point positions and attributes with pagination.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
attributes
list[str] | None

Attribute names to read.

None
start
int

Start index.

0
count
int

Max points per page (200 by default, about 14 KB; page on with start while has_more is true).

200
group
str | None

Point group filter.

None

get_prim_intrinsics async

get_prim_intrinsics(
    ctx: Context,
    node_path: str,
    prim_index: int | None = None,
    prim_indices: list[int] | None = None,
    prim_range: list[int] | None = None,
    intrinsics: list[str] | None = None,
) -> dict

Get intrinsic values for primitives: one, many, or all of them.

Read many prims in one call rather than one call per prim. intrinsics alone sweeps every prim for those intrinsics and answers with a prims table plus stats (min/max/avg and the prim index each extreme belongs to, per component for a vector such as bounds); prim_indices or prim_range narrow it to the prims you care about. Up to 2000 rows per call; beyond that the reply says truncated and requested_count, and stats cover only the rows returned: page with prim_range.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
prim_index
int | None

One primitive index, or None for a summary.

None
prim_indices
list[int] | None

Several primitive indices, read in one call.

None
prim_range
list[int] | None

[start, end] (end inclusive) instead of a list.

None
intrinsics
list[str] | None

Only these intrinsics, e.g. ["bounds", "packedfulltransform"]. With none of the index arguments, they are read for every prim.

None

get_prims async

get_prims(
    ctx: Context,
    node_path: str,
    attributes: list[str] | None = None,
    start: int = 0,
    count: int = 200,
    group: str | None = None,
) -> dict

Read primitive data and attributes with pagination.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
attributes
list[str] | None

Attribute names to read.

None
start
int

Start index.

0
count
int

Max prims per page (200 by default; page on with start while has_more is true).

200
group
str | None

Prim group filter.

None

get_volume_info async

get_volume_info(
    ctx: Context,
    node_path: str,
    max_volumes: int = 24,
    threshold: float | None = None,
    bins: int | list[float] = 0,
) -> dict

Per-volume name, resolution, active voxels, value range, mean and sum.

A primitive count cannot tell a correctly named non-empty density field from an empty one, which is the question worth asking before wiring a solver's sourcing. This is the SOP counterpart of get_cop_vdb.

threshold or bins read the voxels (VDB: active ones) for percentiles, a histogram, the count over threshold and box_above_threshold, the world box of the voxels over it: where the smoke is, not where the grid is.

Parameters:

Name Type Description Default
node_path
str

SOP node path holding volume or VDB primitives.

required
max_volumes
int

Cap on volumes reported.

24
threshold
float | None

Split the voxels at this value and box the ones above it.

None
bins
int | list[float]

Histogram bin count, or a list of bin edges.

0

sample_geometry async

sample_geometry(
    ctx: Context, node_path: str, sample_count: int = 100, seed: int = 0
) -> dict

Sample evenly distributed points from a SOP node's geometry.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
sample_count
int

Number of points to sample.

100
seed
int

Random seed.

0

sample_volume async

sample_volume(
    ctx: Context,
    node_path: str,
    fields: list[str],
    positions: list[list[float]] | None = None,
    from_node: str | None = None,
    limit: int = 1000,
    bins: int | list[float] = 0,
    threshold: float | None = None,
) -> dict

Read named volume fields at world positions, or at another SOP's points.

"What does the collision SDF read where the particles are" is one call with from_node, and adds no node to the scene. A VDB SDF reads its background (the band width) outside its narrow band, not the distance.

Parameters:

Name Type Description Default
node_path
str

SOP holding the volumes.

required
fields
list[str]

Volume names (the name attribute), e.g. ["density"].

required
positions
list[list[float]] | None

[[x, y, z], ...] in world space.

None
from_node
str | None

SOP whose points are the positions, instead of positions.

None
limit
int

Values are returned up to this many positions; the summary always is.

1000
bins
int | list[float]

Histogram bin count, or a list of bin edges, for the summary.

0
threshold
float | None

Count the samples above this value.

None

set_detail_attrib async

set_detail_attrib(
    ctx: Context, node_path: str, attrib_name: str, value: Value
) -> dict

Set a detail attribute on a SOP node.

Appends an Attribute Create SOP after the node and moves the display flag to it; the result includes the new node's path.

Parameters:

Name Type Description Default
node_path
str

Node path.

required
attrib_name
str

Attribute name.

required
value
Value

Value to set.

required