Skip to content

Add native MDL scene data and frame animation time - #373

Merged
tarcila merged 4 commits into
NVIDIA:next_releasefrom
kvankooten:mdl-scene-data-time
Oct 17, 2026
Merged

tarcila merged 4 commits into
NVIDIA:next_releasefrom
kvankooten:mdl-scene-data-time

Conversation

@kvankooten

@kvankooten kvankooten commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Native MDL scene-data lookups currently return their defaults, and state::animation_time() always receives zero. This change connects MDL float/color scene-data lookups to existing ANARI attributes and exposes frame-local mdl.animationTime in seconds.

Applications bind an MDL name with a material parameter such as sceneData.temperature = "attribute0", while continuing to supply arrays and constants on geometry/instances. Lookups reuse attribute interpolation; uniform eligibility is inferred from the effective source. Missing or unsupported values use the shader's fallback. Updating frame time resets accumulation, including with manual accumulation versions, without recompiling materials.

This PR contains only the MDL feature, rebased onto next_release. The independent quad-light changes are separate PRs.

Validation: Fresh Windows Release build with CUDA 13.2, OptiX 7.7, ANARI SDK 0.16.0 and MDL SDK 2025.0.5. All 8 feature/host tests and 8 existing native/MDL lighting regressions passed.

Open design questions retained for discussion:

  • Should named bindings also be expressible per geometry, and how should that interact with material-local bindings?
  • Should a later extension expose shared world-level scene values such as wetness, so applications can update one value used by multiple materials?

Animation time in this change is explicit frame state, constant throughout each frame; shutter-time sampling and shared world-level scene data remain separate follow-ups.

The combined rendering-integration branch also passed all 19 feature, host and rendering checks, including shaping-plus-texture composition.

@jeffamstutz

Copy link
Copy Markdown
Collaborator

I think we can parse this into two concepts, as each I think is something to independently handle.

the user can specify an attribute name (such as "temperature") to be bound to a particular anari attribute array (such as "attribute0"), through a parameter on the material

What is the expected API stream you are going for with this? The question to answer here is what the trade offs are for the application resolving this before hitting the ANARI device or whether there's something special about the device doing this itself. This seems like two (or three?) conflated concepts: [1] naming a custom attribute (i.e. appending the list of attributes laid out in the spec) and [2] injecting attribute data on a geometry external to the geometry itself, whether you just want external data via something like a sampler, or want this to be bound to the geometry somehow, either per-primitive/per-vertex/face-varying.

It also introduces the concept of animation time in MDL, which is also a scene data parameter, but defined for all materials (the whole scene/world).

World attributes and time being an attribute are two concepts that do go together nicely here. However, I want us to be very deliberate here as it walks in the direction of scene graph ambiguity (i.e. the scene now contains more than a single frame's data that must be efficiently computed), which is an increase in scope to ANARI's design philosophy.

Before getting to the consequences of introducing time as a generic attribute, what effect are you going for here? Animated streamlines? Something else? Some of these kinds of use cases can already be handled efficiently simply by using less unique objects per-scene (e.g. sharing a single material between many surfaces, so changes to it cause updates on many objects).

@jeffamstutz

Copy link
Copy Markdown
Collaborator

I also forgot to mention that world attributes replacing the built-in default attribute value is quite reasonable and straightforward to implement. That change I'm less concerned about consequences.

@tarcila

tarcila commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

I would expect this first implementation not be set in stone, with explicitly WIP extensions, so we can adjust later if something goes sideways.

The way I read this PR and discussion is about:

  • Giving access to attributeX from the MDL shader code. Not achievable today (unless working around, misusing texture coordinates), that's a pretty big plus from where I stand. It does not introduce any new concept on the API surface and could already work with a scene as formalized today by ANARI, no new extension needed.
  • Introducing an animation_time, a named scene constant. I would not tie it to any practical scene time as a first step, just a convention to pass a float value that the shader gets using state::animation_time(). That is assuming that, it can only be set on frame (so we can render two frames concurrently). Documented without any assumed scene wide impact so it does not lock anything WRT time in the graph (the current PR name mdl.animationTime makes that contract explicit already).
    I'd advise against putting that animation_time parameter on the mdl material subtype as it could conflict with actual material inputs.

About possible openings:

  • Passing arbitrary values that the shader itself can use. That is trickier. Those scene data are, from the MDL standpoint, value "at current shading point", whatever this means for the renderer. This easily makes sense for existing geometry attributes, constant values, tho I am not sure that covers it all.
    But that does not answer where the data can be pulled from (material, geometry, instancer, world, frame...) and needs some careful thinking about:

    • override priorities (that we already deal with with instance vs geometry attributes for instance).
    • semantic (does it make sense to allow geometry tied attributes on anything else than geometry or instanceTransform?).

    A simple first model could allow material/world/frame for either per material or global overrides, as this PR proposes with animation time. Uniform only (non-array/non-geometry-bound) data. Alleviates all the issues mentioned above.
    Conceptually, that links to USD primvars. It might be worth a look to see if there is something to get inspiration from.

Given the above, the PR seems a reasonable first iteration to me, still to code review tho:

  • attributeX scene data access from the shader. I think the naming indirection ("temperature" => "attribute0"), while not strictly necessary, is a clear win when reusing existing shaders. That being said:
    • I think having a default set of identity mapping "attribute0" => "attribute0" would be nice. This way, no mdl material setup is required to access attribute by their ANARI name.
    • I feel it would make more sense to declare those kind-of semantic mapping "temperature" => "attribute0" on the geometry itself (geometry names its data, enables material reuse...). To be fair the actual implementation putting that on the mdl material makes sense WRT how ANARI already works (matte.color = "attribute0", sampler.inAttribute = "attribute1"...), and sort-of focus that on being mdl-only, which is a good as preleminary step.
  • mdl.animationTime, float, new official frame mdl only parameter, so we avoid the complexity of value source, priority and such.

The rest as work in progress, or active discussions. Overall, that can most likely already be solved by setting the same parameter on all the material instances. Not as convenient as a true globals, but at least working today.

@kvankooten

Copy link
Copy Markdown
Collaborator Author

First off: my mistake, I should have said that animation time is defined on the Frame, not the World. I was already too busy in my head thinking about the generalized version with global constants. Which highlights the problem: how do we know that allowing MDL parameters on a World object or similar is going to be what's required? Maybe others also have the need to introduce globals on the frame. TBD.

Otherwise I pretty much agree with Thomas on the need for this kind of mapping, at its narrowest it could remain restricted as an MDL-only feature. However, I also implemented this exact capability on the USD device in the past, so somehow it keeps coming back. For that reason I also agree that eventually the correct place for such aliases should be on the geometry, so that every geometry can decide which array is connected to which semantic without having to create distinct materials purely to correct for the order of attribute semantics (the organization of which on sets of geometries with different sets of semantic arrays, partially shared, could then become its own fun game). For the USD device I thought I was dealing with a convenience naming only, but now I am starting to more and more understand the importance of this in terms of data/content organization on the renderer's side as well.

Specific to state::animation_time(), it's an intrinsic that is not a regular MDL param, as far as I understood it.

Copy the target-code string table into a device-owned
SceneDataDescriptor (IDs preserved, empty slots kept) and cache it per
target-code slot in MaterialRegistry, so name- and UUID-cache hits return
IDs matching the PTX. AcquiredMaterial replaces the tuple return.

Add SceneDataInstance for per-material bindings: full-snapshot update,
unknown names ignored, only attribute0-3/color accepted, last duplicate
wins. MDL resets the GPU table on source change so unbound tables still
upload. Move MaterialAttribute/MDLSceneDataBinding to a CUDA-free header
and drop ArgumentBlockInstance::targetCode().

Add descriptor/instance unit tests and API tests for shared sources,
invalid/non-string bindings and unbound source replacement.
Resolve attribute0-3 and color once per hit during MDL shading init.
xyz feeds texture coordinates (float3 ABI); w, color and presence/uniform
masks are cached in TextureHandler, which no longer holds the SurfaceHit.
Scene-data lookups and data_isvalid read the cache instead of
re-resolving attributes.

Document the sharing and data_isvalid semantics; test all strides, w and
color, uniform rejection, nonfinite w and cache refresh on removal.
resolveAttribute() only yields FACE_VARYING for triangles; other
geometries would need their own indexing and interpolation.

@tarcila tarcila left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kvankooten Thanks for the PR. I've been stacking some changes atop of yours:

  • replacing the wide exposure of MDL targetCode() by a SceneDataDescriptor sibling class to ArgumentBlockDescriptor
  • baking shading init value, instead of referencing the Hit information

@tarcila
tarcila merged commit 73c02f6 into NVIDIA:next_release Oct 17, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants