# Changelog (/docs/changelog)
Placeholder entries — version numbers and dates are illustrative until the
first public builds ship. Subscribe from your [dashboard](/dashboard) to
get release notes by email.
## 2026.2.0 — upcoming [#202620--upcoming]
**Photon RTXPT**
* DLSS Ray Reconstruction preset ladder replaces the single denoiser toggle
* AOV layers: direct/indirect split output for external compositing
* Fix: accumulation reset flashing under time-sliced material exports
**Matter**
* `Deterministic` mode — bit-identical replays at \~15% cost
* Cloth self-collision robustness pass at high substep counts
**Aura**
* Input 4 normal-map support graduates from experimental
* Fix: temporal ghosting on hard cuts with `Reset History` pulse
## 2026.1.1 [#202611]
**All plugins**
* Signed headless license tool (`nops-license.exe`) ships in the plugin
folder — see [Licensing a render farm](/docs/guides/render-farm-licensing)
* Status readout now reports the minimum driver version on refusal
**Photon OVRTX**
* Radiance cache probe refit no longer stalls on large geometry edits
## 2026.1.0 — first early-access builds [#202610--first-early-access-builds]
* Photon RTXPT, Photon OVRTX, Matter, and Aura enter early access
* Per-seat licensing with online and offline activation
* TouchDesigner 2023.12000+ / driver 560+ floors established
# Introduction (/docs)
These pages are placeholder content while the plugins are in early access —
the structure is real, the numbers are not final. Join the
[waitlist](/) to be notified when they ship.
## What is NativeOps? [#what-is-nativeops]
Every NativeOps plugin is a **native operator**: it registers itself with
TouchDesigner like a built-in, cooks on the GPU, and shows up in the OP Create
dialog next to everything else. No Python glue, no texture round-trips, no
external processes to babysit.
Written in C++/CUDA against TouchDesigner's plugin API. Zero-copy texture
sharing means frames never leave the GPU on their way through your network.
One license per machine, managed from your dashboard. Activation takes a
key, not a hardware dongle — and moves with you when you swap workstations.
## The plugins [#the-plugins]
Real-time path tracing inside TouchDesigner, built on NVIDIA's RTX Path
Tracing SDK.
The Photon front end on the ovrtx backend — the same scene semantics,
tuned for interactive previz.
GPU rigid bodies, fluids, and cloth as one operator suite — eight
operators, one solver clock.
Real-time 2D global illumination for layered scenes — emitters, occluders,
and bounce in a single TOP.
## Quick start [#quick-start]
### Buy a license [#buy-a-license]
Every plugin is sold per seat from the [products page](/products). The
license key lands in your [dashboard](/dashboard) the moment checkout
completes.
### Install the plugin [#install-the-plugin]
Drop the plugin folder into TouchDesigner's plugin path and restart.
[Installation](/docs/getting-started/installation) walks through both the
per-user and system-wide paths.
### Activate your seat [#activate-your-seat]
Paste your key into the operator's Activate parameter page — or activate
offline for air-gapped machines.
[Activation](/docs/getting-started/activation) covers both.
## Why native operators? [#why-native-operators]
Script TOPs and CHOPs run on the CPU, once per cook, with the GIL in the
way. A path tracer or a fluid solver needs thousands of GPU dispatches per
frame — that only works as a compiled plugin sharing TouchDesigner's own
GPU context.
Running a renderer in a separate process means every frame crosses process
boundaries twice. A native operator cooks inside TouchDesigner's frame
loop — the output TOP is the renderer's actual target texture.
Parameters, exports, CHOP references, time-slicing — the things that make
TouchDesigner TouchDesigner — only reach operators. NativeOps plugins
expose everything as ordinary parameters, so your existing control rigs
just work.
## Reading these docs as an agent [#reading-these-docs-as-an-agent]
Append `.md` to any page URL for its raw markdown. [/llms.txt](/llms.txt) is
the index, [/llms-full.txt](/llms-full.txt) is every page in one document, and
the **Copy page** button up top yields the same markdown.
# Overview (/docs/aura)
**Aura** lights 2D scenes the way a renderer lights 3D ones. Feed it layers —
who emits, who blocks — and it returns the scene with light that bounces,
bleeds, and wraps. Motion graphics stop looking flat without leaving TOPs.
Aura is the entry point to the NativeOps line: it runs on any CUDA-capable
GPU from the 16-series up, no RT cores required.
## The idea [#the-idea]
A 2D scene has the same light problems as a 3D one — a neon sign should
tint the wall behind it; a character crossing a doorway should catch light
from it. Aura solves radiance in screen space over your layers:
* **Emitters** — any layer's bright pixels cast light, in nits
* **Occluders** — alpha or a dedicated mask blocks and shadows
* **Bounce** — one to four bounces of colored indirect light
* **Volumetrics** — optional fog pass so beams read in empty space
## Where it sits in a network [#where-it-sits-in-a-network]
```text title="Typical chain"
comp_layers (TOP) ──► aura1 (TOP) ──► bloom / grade ──► out
```
One Aura TOP per scene, after compositing and before grade — the same slot a
lighting pass occupies in a 3D pipeline. [Inputs](/docs/aura/inputs) covers
the layer contract.
## Next steps [#next-steps]
The layer contract — what each input plug expects.
Bounce counts, distance fields, quality ladders.
# Inputs (/docs/aura/inputs)
Aura takes up to four TOP inputs. Only the first is required — each one added
unlocks a feature tier.
| Input | Content | Unlocks |
| --------------------- | ------------------------------------- | -------------------------------- |
| 1 — Scene | Your composited layers, premultiplied | Emission from bright pixels |
| 2 — Occlusion | Grayscale blocker mask | Shadows independent of alpha |
| 3 — Emission override | RGB emission map, in nits | Emitters that aren't visible |
| 4 — Normal | 2D normal map | Directional response on surfaces |
## The one rule: premultiplied alpha [#the-one-rule-premultiplied-alpha]
Aura derives occlusion from input 1's alpha when no input 2 is wired.
Straight (unpremultiplied) sources read as glowing halos around every edge.
If halos appear around composited elements, the source is straight alpha —
drop a Premultiply TOP in front, or wire a real occlusion mask into
input 2.
## Emission without visibility [#emission-without-visibility]
Input 3 answers the common request "light from off-screen": paint emitters
into the override map and they cast without being drawn.
```python title="Flicker an off-screen fire"
# noise TOP → level TOP (drives intensity) → input 3
op('aura1').par.emissionscale.expr = "1.0 + op('noise_fire')['chan1'] * 0.4"
```
Normal maps (input 4) are the cheapest large upgrade: characters rendered
from a 3D DCC with a normal AOV pick up directional 2D light that tracks
their forms — the flat-sticker look disappears.
# Parameter reference (/docs/aura/parameters)
Generated reference, same pipeline as the other plugins. Placeholder
subset below.
## Light page [#light-page]
## Quality page [#quality-page]
`Temporal Blend` above 0.9 ghosts on hard cuts. Pulse the `Reset History`
parameter from your cue system on every scene change — one line in a
Script CHOP callback.
# Activation (/docs/getting-started/activation)
Activation binds a seat from your [dashboard](/dashboard) to the current
machine. Until then the operator runs in watermark mode — full function,
watermarked output.
## Online activation [#online-activation]
### Open the Activate page [#open-the-activate-page]
Every NativeOps operator has an **Activate** parameter page. Select the
operator and switch to it.
### Paste your key [#paste-your-key]
Keys look like `NOP-1C285B2D-6CE6-4BC7-B8BE-ADB6A7E304DA` and are listed in the
[dashboard](/dashboard). Pulse **Activate**.
### Confirm the status [#confirm-the-status]
The `Status` readout flips to `Licensed` and the watermark disappears on
the next cook. The seat now shows this machine's name in your dashboard.
Activation is once per machine, not per project — every `.toe` on the
machine sees the seat.
## Offline activation [#offline-activation]
For machines that never touch the internet:
Pulse **Request Offline File** on the Activate page. The operator writes a
`machine.request` fingerprint file next to the project.
On any online machine, upload the request in the
[dashboard](/dashboard) under **Seats → Offline activation**. It returns a
signed `seat.license` file.
Copy `seat.license` into the plugin folder on the offline machine and
restart TouchDesigner.
The fingerprint covers the GPU and motherboard. Swapping either invalidates
an offline seat — deactivate from the dashboard first if hardware work is
planned.
## Deactivating [#deactivating]
Deactivate from the operator's Activate page (pulse **Deactivate**), or from
the [dashboard](/dashboard) when the machine is gone — dead SSD, returned
rental, stolen laptop. Dashboard deactivation is immediate and frees the seat
for the next machine.
Something stuck? [Troubleshooting → Activation
problems](/docs/troubleshooting/activation-problems) covers the failure modes
we know about.
# Installation (/docs/getting-started/installation)
Each plugin ships as a single folder containing the operator DLL and its
resource files. TouchDesigner discovers it on startup — there is no installer
and nothing touches the registry.
Downloads are signed and versioned per TouchDesigner build line. Grab the
build matching your TouchDesigner version from the
[dashboard](/dashboard) — a `2025.30000` plugin will refuse to load in a
`2023.12000` session.
## Install locations [#install-locations]
Drop the plugin folder into your user plugin path. TouchDesigner scans it
on every launch, and updates don't need admin rights.
```text title="Windows"
%USERPROFILE%/Documents/Derivative/Plugins/PhotonRTXPT/
```
For lab machines and render nodes where every user shares one install:
```text title="Windows (requires admin)"
C:/Program Files/Derivative/TouchDesigner/Plugins/PhotonRTXPT/
```
Ship the plugin inside a project folder for fully portable setups — the
path is scanned relative to the `.toe` file:
```text title="Relative to your .toe"
./Plugins/PhotonRTXPT/
```
Project-local plugins still need an activated seat on the machine that
opens the project. Bundling the DLL does not bundle the license.
## What lands on disk [#what-lands-on-disk]
## Verify the install [#verify-the-install]
Restart TouchDesigner. Plugins are scanned once at startup — a running
session will not pick up a new folder.
Open the OP Create dialog (double-click the network background). The
operator appears under the **Custom** tab — `Photon RTXPT` in this
example.
Drop the operator into a network. Until a seat is activated it cooks in
watermark mode — full function, watermarked output. Continue to
[Activation](/docs/getting-started/activation).
Developing on a laptop and deploying to a media server? Install per-user on
the laptop and system-wide on the server — the license seat follows the
machine, not the install location.
# Licensing (/docs/getting-started/licensing)
A **seat** is one plugin activated on one machine. Licenses are sold per
plugin, per seat, with updates included for the duration of the license term.
## The model [#the-model]
* **Per machine, not per user.** Any user account on an activated machine can
use the plugin. Two workstations need two seats.
* **Floating by deactivation.** Moving to a new machine is
deactivate-then-activate from the [dashboard](/dashboard) — no support
ticket required.
* **Watermark mode is not a trial clock.** An unactivated operator never
expires; it cooks full-rate with a watermark. Evaluate as long as you like.
Render nodes cook headless with the same seat type — there is no separate
render license. If a machine opens the `.toe`, it needs a seat.
## What a key looks like [#what-a-key-looks-like]
```text
NOP-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
NOP-1C285B2D-6CE6-4BC7-B8BE-ADB6A7E304DA
```
The `NOP-` prefix, then a UUID — 32 hex characters, uppercase, in the
usual 8-4-4-4-12 grouping. Case and hyphens are part of the key.
Keys are plugin-scoped: a Photon RTXPT key will not activate Matter. Every key
you own is listed in the [dashboard](/dashboard) with its activation state and
the machine it's bound to.
## FAQ [#faq]
One seat is one machine at a time. Deactivate on the desktop, activate on
the laptop — it takes about a minute in the dashboard. If you switch
machines daily, a second seat is the honest answer.
The operator keeps working at the last version released during your term.
Renewing restores update access — nothing on your machine deactivates.
Yes — activation has an offline path built for media servers that never
touch the internet. See
[Activation → Offline](/docs/getting-started/activation#offline-activation).
Planned, not live. [Contact us](/contact) with your institution and we'll
sort something out manually in the meantime.
# Requirements (/docs/getting-started/requirements)
NativeOps plugins are native CUDA code sharing TouchDesigner's GPU. The
requirements below are hard floors, not recommendations — the operators check
them at load time and say so in the status parameter when one is missing.
## Supported platforms [#supported-platforms]
| | Minimum | Recommended |
| ------------- | --------------- | -------------------- |
| TouchDesigner | 2023.12000 | 2025.30000+ |
| Windows | Windows 10 21H2 | Windows 11 |
| NVIDIA driver | 560.xx | Latest Studio driver |
| CUDA compute | 7.5 (Turing) | 8.9+ (Ada) |
| VRAM | 6 GB | 12 GB+ |
macOS is not supported. Every NativeOps plugin depends on CUDA — and Photon
additionally on the RTX SDKs — which do not exist on Apple silicon. This is
an NVIDIA-only product line by design.
## GPU generations [#gpu-generations]
The RTX requirement differs by plugin:
| Plugin | Needs RT cores | Runs on GTX |
| ------------ | ---------------------------- | ---------------- |
| Photon RTXPT | Yes — RTX 20-series or newer | No |
| Photon OVRTX | Yes — RTX 20-series or newer | No |
| Matter | No — any CUDA 7.5+ GPU | Yes (16-series+) |
| Aura | No — any CUDA 7.5+ GPU | Yes (16-series+) |
Multi-GPU rigs: the operator cooks on whichever adapter TouchDesigner is
running on. Affinity across GPUs is on the [roadmap](/roadmap), not in the
current builds.
## Checking your machine [#checking-your-machine]
```python title="Textport"
# TouchDesigner build
print(app.build)
# GPU + driver as TouchDesigner sees them
print(project.paths) # placeholder — see the Guides section
```
If the machine falls short, [Troubleshooting → GPU
requirements](/docs/troubleshooting/gpu-requirements) has the full
decision tree.
# Your first path-traced frame (/docs/guides/first-render)
This guide assumes an [installed](/docs/getting-started/installation) and
[activated](/docs/getting-started/activation) Photon RTXPT. Watermark mode
works too — everything renders, watermarked.
### Make some geometry [#make-some-geometry]
A Grid SOP as the floor and a Torus SOP floating above it. Nothing
fancy — this scene is about light, not modeling.
### Drop the renderer [#drop-the-renderer]
Add a `Photon RTXPT` TOP from the OP Create dialog's **Custom** tab.
Point its `Geometry` parameter at the container holding both SOPs:
```python title="Or from the Textport"
op('photon_rtxpt1').par.geometry = '/project1/geo1'
```
You already have an image — the default camera orbits the scene bounds
and a default dome light fills it.
### Light it on purpose [#light-it-on-purpose]
Add a `Photon Light` COMP, type **Area**, and set intensity to
`10000` lumens. Kill the default dome by setting the renderer's
`Default Dome` toggle off. One soft key from the left — already worth a
screenshot.
### Give the floor a material [#give-the-floor-a-material]
Add a `Photon Material` COMP, set `Roughness` to `0.15`, and bind it:
```python
op('photon_mat1').par.bindpaths = '*/grid*'
```
The torus keeps the default gray; the floor picks up a soft reflection
of it.
### Let it converge [#let-it-converge]
Stop moving the camera and watch the sample counter climb in the info
overlay — the image resolves in a second or two. That's accumulation;
it resets on any move and the denoiser hides the restart.
## Where to go from here [#where-to-go-from-here]
Glass and emission are two parameters away.
Swap the area for a sun + dome pairing.
Drop a Movie File Out TOP after the renderer and you have path-traced
playblasts — accumulation makes still-camera exports look like offline
renders.
# Guides (/docs/guides)
Reference pages say what a parameter does; guides say what to do. Each one is
a complete path through a real task, with the wrong turns marked.
Empty network to a denoised Photon RTXPT render in ten minutes.
Seats on headless nodes — offline activation at rack scale.
More guides land with the plugins — coupling recipes for Matter, an Aura
scene-lighting cookbook, and a DMX-to-Photon rig walkthrough are next in
the queue. [Tell us](/contact) what you're stuck on.
# Licensing a render farm (/docs/guides/render-farm-licensing)
Render nodes are the worst-case licensing client: no browser, often no
internet, imaged from a common template. This guide runs the
[offline activation](/docs/getting-started/activation#offline-activation)
flow at rack scale.
Do **not** bake an activated seat into a machine image. The license
fingerprint covers GPU and motherboard — clones fail validation on first
cook and show up in your dashboard as conflicting activations.
## The flow [#the-flow]
### Generate requests on every node [#generate-requests-on-every-node]
Photon and Matter ship a headless license tool next to the DLL —
scriptable over your farm's remote execution:
```powershell title="Per node, via your farm manager"
& "C:\Program Files\Derivative\TouchDesigner\Plugins\PhotonRTXPT\nops-license.exe" `
request --out \\filer\licenses\requests\$env:COMPUTERNAME.request
```
### Bulk-upload in the dashboard [#bulk-upload-in-the-dashboard]
[Dashboard → Seats → Offline activation](/dashboard) accepts a zip of
request files and returns a zip of `seat.license` files, one per node,
named by machine.
### Distribute the license files [#distribute-the-license-files]
```powershell title="Back out over the same channel"
Copy-Item "\\filer\licenses\issued\$env:COMPUTERNAME.license" `
-Destination "C:\Program Files\Derivative\TouchDesigner\Plugins\PhotonRTXPT\seat.license"
```
Nodes pick the file up on the next TouchDesigner launch — no reboot.
### Verify from the farm manager [#verify-from-the-farm-manager]
The tool exits nonzero on an unlicensed node, so your farm's health
check can gate dispatch:
```powershell
& "...\nops-license.exe" status --quiet # 0 = licensed
```
## Swapping hardware [#swapping-hardware]
GPU replacement invalidates that node's fingerprint. Deactivate the seat in
the dashboard *before* the swap and reissue afterwards — takes two minutes
and avoids the conflicting-activation flag.
Farm seats are ordinary seats — same price, same dashboard. If a node dies
mid-season, dashboard-deactivate it and the seat is immediately free for
the replacement.
# Coupling (/docs/matter/coupling)
**Coupling** is the suite's reason to exist: all body types integrate on the
same clock, so forces exchange *inside* a substep instead of one frame late.
A splash pushes the boat during the same step the boat displaces the water.
## What couples with what [#what-couples-with-what]
| | Rigid | Fluid | Cloth |
| --------- | ------------------ | ---------------------- | ------------------------- |
| **Rigid** | contacts, stacking | buoyancy, drag, splash | drape, collide |
| **Fluid** | displacement | — | soak weight, surface drag |
| **Cloth** | wraps, tears | porous flow-through | self-collision |
## Enabling it [#enabling-it]
Coupling is on by default between bodies in the same solver. The switch that
matters is the pair mask:
```python title="Turn off fluid→cloth for a cheap win"
solver = op('matter_solver1')
solver.par.couplefluidcloth = False # banner ignores the rain
```
Pair masks are the first performance lever. A courtyard scene where rain
never believably moves the flags can drop fluid→cloth and win the substep
back.
## Walkthrough: boat on water [#walkthrough-boat-on-water]
Drop a `Matter Solver`, a `Matter Fluid` fed by a tank-shaped SOP, and a
`Matter Rigid` pointed at the boat mesh with `Collision Shape:
auto-convex`.
Set boat `Density` below the fluid's rest density — 400 kg/m³ floats
convincingly against water's 1000.
Read the boat transform out of `Matter Out` into a Geometry COMP
instance. The camera never knows the hull is a proxy.
Coupled systems share the substep budget — a fluid at 2 substeps forces
the rigids it touches down to 2 as well. If stacking gets soft the moment
fluid enters the scene, raise the solver's substeps, not the rigid's
stiffness.
# Overview (/docs/matter)
**Matter** is a simulation suite, not a collection of solvers. Rigid bodies,
fluids, cloth, and constraints all step on one clock inside one CUDA context —
which is what lets a fluid push a box that tears a cloth, in real time,
without a frame of latency between them.
Matter runs on any CUDA 7.5+ GPU — RT cores not required. A GTX 16-series
laptop runs the small examples; see
[Requirements](/docs/getting-started/requirements).
## The suite [#the-suite]
One solver, three body types, two force fields, an emitter, and a
readback CHOP — the whole surface.
Solvers exchange impulses inside a substep, not across frames — the
feature the suite is built around.
## Design rules [#design-rules]
* **Determinism switch.** `Deterministic` on the solver trades \~15% speed for
bit-identical replays — same inputs, same frames, every run.
* **SOPs in, SOPs/TOPs out.** Colliders and emitters are plain geometry;
results come back as point clouds, meshes, or velocity fields.
* **Budgeted stepping.** Like Photon OVRTX, the solver takes a millisecond
budget and reduces substeps before it ever stalls your frame.
## FAQ [#faq]
No — Matter's solvers are written for the GPU-resident, two-way-coupled
case. A wrapper around a CPU engine can't share substep impulses with a
GPU fluid without copying state across the bus every step.
Placeholder targets on a 4080: \~20k active rigid bodies, \~2M fluid
particles, or \~500k cloth vertices — budget-shared when mixed. Real
numbers land with the benchmark project.
The readback CHOP/SOP pair feeds TouchDesigner's native caching (Cache
SOP, File Out). A dedicated bake operator is on the
[roadmap](/roadmap).
# Operators (/docs/matter/operators)
Eight operators, one pattern: the **solver** owns time, everything else
declares state or reads it back.
| Operator | Family | Role |
| ------------------- | ------ | ------------------------------------------- |
| `Matter Solver` | COMP | The clock — owns substeps, gravity, budget |
| `Matter Rigid` | COMP | Rigid body set from SOP instances |
| `Matter Fluid` | COMP | SPH fluid volume |
| `Matter Cloth` | COMP | Cloth / soft shell from a mesh |
| `Matter Constraint` | COMP | Joints, motors, pins between bodies |
| `Matter Force` | COMP | Field forces — wind, vortex, attractors |
| `Matter Emitter` | COMP | Streams new particles / bodies at rate |
| `Matter Out` | CHOP | Readback — transforms, velocities, contacts |
## Network shape [#network-shape]
```text title="Typical wiring"
matter_solver1
├─ matter_rigid_crates (SOP: crate instances)
├─ matter_fluid_tank (SOP: emission volume)
├─ matter_cloth_banner (SOP: banner mesh)
├─ matter_force_wind
└─ matter_out1 (CHOP → instancing network)
```
Bodies register with the solver whose path their `Solver` parameter names —
parenting in the network editor is for humans, the path is what binds.
One solver per interacting system. Two solvers never exchange forces — use
that deliberately to isolate a background sim from a hero sim at different
budgets.
## Reading results [#reading-results]
```python title="Contacts drive audio"
contacts = op('matter_out1')['contact_impulse']
if contacts.eval() > 4.0:
op('audio_hit').par.play.pulse()
```
`Matter Out` exposes contacts as CHOP events with impulse magnitude —
collision-driven sound and lighting cost one export, no Python per frame.
# Parameter reference (/docs/matter/parameters)
Generated reference (same pipeline as Photon's) — Matter is the reason it
exists: eight operators, \~160 parameters, derived from USD Physics schemas.
Placeholder subset below.
## Matter Solver — Sim page [#matter-solver--sim-page]
## Matter Rigid — Body page [#matter-rigid--body-page]
## Full table [#full-table]
| Operator | Page | Parameters |
| ---------- | -------- | ----------------------------------------------- |
| Solver | Sim | substeps, budget, gravity, deterministic, scale |
| Solver | Advanced | broadphase, sleep threshold, CFL target |
| Rigid | Body | density, friction, restitution, shape |
| Fluid | Volume | rest density, viscosity, surface tension |
| Cloth | Shell | stretch, bend, thickness, self-collide |
| Constraint | Joint | type, limits, motor target, stiffness |
| Force | Field | type, strength, falloff, noise |
| Emitter | Rate | rate, speed, lifetime, inherit velocity |
| Out | Channels | transforms, velocities, contacts, ids |
# Overview (/docs/photon-ovrtx)
**Photon OVRTX** is the second Photon renderer. Same operators, same
materials, same lights — a different engine underneath. Where
[RTXPT](/docs/photon-rtxpt) converges to a reference-grade frame, OVRTX
holds a stable interactive image under constant scene churn.
Scenes are **portable between the two Photons**. The operator surface is
shared, so switching engines is replacing one TOP — bindings, lights, and
cameras carry over untouched.
## When to reach for OVRTX [#when-to-reach-for-ovrtx]
| You are doing | Use |
| --------------------------------------------- | --------------------------- |
| Previz with a director dragging lights around | **OVRTX** |
| Look development toward a final still | [RTXPT](/docs/photon-rtxpt) |
| Live show output at frame rate | **OVRTX** |
| Fixture-accurate lighting sign-off | [RTXPT](/docs/photon-rtxpt) |
## What differs from RTXPT [#what-differs-from-rtxpt]
* **Radiance caching** — indirect light amortizes across frames; a moving
camera doesn't restart the world
* **Fixed frame budget** — set milliseconds, not samples; quality scales to
fit the frame time you have left
* **No accumulation state** — every frame is complete, so downstream
feedback loops behave
The trade: OVRTX's indirect lighting is approximate. Caustics, deep glass,
and long light chains resolve on RTXPT only.
## Next steps [#next-steps]
Shared surface, engine-specific pages flagged.
The OVRTX-only parameters, next to the shared set.
# Lights (/docs/photon-ovrtx/lights)
Light types and units are shared with
[RTXPT → Lights](/docs/photon-rtxpt/lights) — lumens, lux, nits, EV. What
changes on OVRTX is *how many* lights stay cheap.
## Light counts [#light-counts]
RTXPT samples lights stochastically — hundreds are fine. OVRTX shades a
bounded set per pixel:
| Tier | Count | Cost |
| ------------------- | --------- | ----------------------------------- |
| Shadowed key lights | up to 8 | full shadows every frame |
| Cached contributors | up to 256 | shadows via radiance cache |
| Beyond that | unlimited | ambient pool, no individual shadows |
The engine promotes and demotes lights automatically by contribution;
pin one with its **Priority** parameter when a cue depends on it.
Concert rigs: leave moving heads in the cached tier and pin only
followspots. Promotion churn during a blackout snap is what the Priority
pin exists for.
A DMX-driven light strobing at cache frequency defeats the cache — flag
fast-flicker fixtures with `Animate → Realtime` so they bypass it and
shade directly.
# Materials (/docs/photon-ovrtx/materials)
Materials are **defined once, rendered twice** — the same
`Photon Material` COMP feeds both engines. This page covers what OVRTX does
differently with them; the models themselves are documented under
[RTXPT → Materials](/docs/photon-rtxpt/materials).
## Fidelity by model [#fidelity-by-model]
| Model | On OVRTX | Notes |
| ---------- | ----------- | --------------------------------------------- |
| Principled | Full | Indistinguishable from RTXPT in most lighting |
| Emission | Full | Feeds the radiance cache directly |
| Glass | Approximate | Single refraction event; no nested interfaces |
Glass-heavy hero shots are the one place scene portability has an
asterisk: OVRTX renders one refraction bounce and estimates the rest.
Preview on OVRTX, sign off on RTXPT.
## Texture streaming [#texture-streaming]
OVRTX streams bound TOP textures at half resolution while their content
changes, snapping to full when stable for a few frames — this keeps Movie
File In TOPs from stalling the frame budget.
```python title="Force full-res for a critical surface"
op('photon_mat_screen').par.streamquality = 'full' # opt out per material
```
The half-res window is invisible on diffuse channels and noticeable on
normal maps — flag hero normal-mapped materials `full` and leave the rest
on `auto`.
# Operators (/docs/photon-ovrtx/operators)
OVRTX reuses the Photon helper COMPs — only the renderer TOP is its own
operator. If both plugins are installed, the helpers serve whichever
renderer collects them.
| Operator | Family | Shared with RTXPT |
| ----------------- | ------ | ----------------- |
| `Photon OVRTX` | TOP | — (the engine) |
| `Photon Material` | COMP | Yes |
| `Photon Light` | COMP | Yes |
| `Photon Camera` | COMP | Yes |
## The frame budget [#the-frame-budget]
The defining OVRTX control is on the Render page:
```python title="Textport"
render = op('/project1/photon_ovrtx1')
render.par.framebudget = 8.0 # ms — leave headroom for the rest of the network
```
The engine spends its budget in priority order — primary visibility first,
then shadows, then the radiance cache. Starve it and the image degrades
gracefully instead of dropping frames.
Running at 60 fps with a 16.6 ms frame? Give OVRTX 8–10 ms and keep the
rest for compositing. The `Perform` page's cook-time readout tells you
what the whole chain actually costs.
A `Photon Material` bound in an RTXPT project needs no edits here — engine
differences are absorbed by the renderer, not pushed into your scene.
# Parameter reference (/docs/photon-ovrtx/parameters)
Generated reference — same pipeline as
[RTXPT's](/docs/photon-rtxpt/parameters). Placeholder subset until the
generator lands. Shared pages (Scene, Output, Activate) are identical
across both Photons and documented once there.
## Render page (OVRTX) [#render-page-ovrtx]
## Reading the health readouts [#reading-the-health-readouts]
The Info page reports where the budget went:
| Readout | Healthy | Investigate when |
| ---------------- | -------- | ---------------------------------------------- |
| `budget_used_ms` | ≤ budget | pegged at budget every frame |
| `cache_hit_rate` | > 0.8 | \< 0.5 — density too low for the scene scale |
| `stale_probes` | \~0 | climbing — geometry churning faster than refit |
`Cache Density` below 0.1 in a stadium-scale scene allocates probe grids in
the gigabytes. Scale density with scene scale — the default 0.5 assumes
meters.
# Overview (/docs/photon-rtxpt)
**Photon RTXPT** is a path tracer that lives in your network. Geometry comes
in as SOPs or USD, lights and cameras are COMPs you already know, and the
render lands in a TOP — denoised, tone-mapped, and ready for compositing.
Photon RTXPT requires an RTX GPU (20-series or newer) — the path tracer
runs on RT cores. See [Requirements](/docs/getting-started/requirements).
## How it renders [#how-it-renders]
A **frame is a cook**. Every time the operator cooks it traces a configurable
number of paths per pixel, accumulates against the previous frames when the
scene is static, and runs the DLSS Ray Reconstruction denoiser before output.
Move the camera and accumulation resets automatically.
SOP and USD inputs become RTX acceleration structures incrementally —
only what changed re-uploads, so animated geometry stays interactive.
Materials, lights, and camera exposure follow the same physical units as
offline renderers — lumens, EV, and metric scene scale.
## What's in the box [#whats-in-the-box]
* One render TOP with the full parameter surface —
[operators](/docs/photon-rtxpt/operators) has the map
* Principled, emission, and glass [materials](/docs/photon-rtxpt/materials)
* Area, sun, dome, and mesh [lights](/docs/photon-rtxpt/lights)
* A [parameter reference](/docs/photon-rtxpt/parameters) generated from the
same source that registers them in TouchDesigner
## Next steps [#next-steps]
The operator set and how they wire together.
Every page, every parameter, with ranges and defaults.
From empty network to a denoised path-traced frame.
Confirm your hardware before you buy.
# Lights (/docs/photon-rtxpt/lights)
Every **Photon Light** works in physical units — lumens for emitters, lux for
the sun, EV-relative intensity everywhere. Match a lighting plot's numbers
and the render agrees with the venue.
## Light types [#light-types]
| Type | Shape | Intensity unit | Shadows |
| ---- | -------------------- | -------------- | ----------------------- |
| Area | rect / disc / sphere | lumens | soft, size-driven |
| Sun | directional | lux | sharp, angular-diameter |
| Dome | HDRI environment | EV offset | image-based |
| Mesh | any SOP | nits | from geometry |
## Driving lights live [#driving-lights-live]
Light parameters accept CHOP exports without resetting accumulation — they're
part of the light-sampling pass, not the scene build.
```python title="DMX → Photon"
# sACN in a CHOP, mapped straight onto a light
op('photonlight_key').par.intensity.expr = "op('sacn1')['u1c1'] * 15000"
```
Dome + area is the standard stage recipe: dome at −2 EV for ambience, area
lights carrying the key. Start there before adding mesh emitters — they are
the most expensive type to sample.
A mesh light with thousands of triangles samples poorly and shows as noise
in shadows. Decimate emitter geometry to the silhouette — the light looks
identical and converges far faster.
# Materials (/docs/photon-rtxpt/materials)
A **Photon Material** binds a look to geometry by path pattern. Any channel
can be a constant or a TOP — textures stay on the GPU end to end.
## Material models [#material-models]
The workhorse — a Disney-style BSDF matching what your offline renderer
calls Standard Surface.
| Channel | Takes | Default |
| ---------- | ----------- | -------- |
| Base Color | RGB / TOP | 0.8 gray |
| Roughness | float / TOP | 0.5 |
| Metallic | float / TOP | 0 |
| Normal | TOP | — |
Anything can glow. Emission is in **nits** so LED-wall content reads at
believable levels next to physical lights.
| Channel | Takes | Default |
| ----------------- | ------------ | ------- |
| Emission Color | RGB / TOP | white |
| Intensity (nits) | float / CHOP | 100 |
| Visible to Camera | toggle | on |
Real refraction, not a transparency hack. Budget bounces accordingly —
see the Note below.
| Channel | Takes | Default |
| ---------------- | ----------- | ------- |
| IOR | float | 1.45 |
| Roughness | float / TOP | 0 |
| Absorption Color | RGB | white |
Glass needs path depth: at the default 4 bounces a glass-in-front-of-glass
shot goes black where paths run out. Raise `Max Bounces` to 6–8 for
transmissive scenes and watch the ms/frame readout.
## Binding [#binding]
```python title="Photon Material COMP — Binding page"
# Bind by path pattern, most-specific pattern wins
op('photon_mat_floor').par.bindpaths = '*/floor_geo'
op('photon_mat_hero').par.bindpaths = '*/hero/*'
```
Unbound geometry gets the default gray Principled — a scene never fails to
render because a pattern missed.
Wildcards make LOD swaps free: bind `*/statue_*` once and every resolution
variant inherits the same look.
# Operators (/docs/photon-rtxpt/operators)
Photon RTXPT installs one renderer and three helper operators. The renderer
owns the GPU pipeline; the helpers describe the scene.
| Operator | Family | Role |
| ----------------- | ------ | ----------------------------------------------- |
| `Photon RTXPT` | TOP | The renderer — traces, denoises, outputs |
| `Photon Material` | COMP | A material definition bound by path or wildcard |
| `Photon Light` | COMP | A light — area, sun, dome, or mesh emitter |
| `Photon Camera` | COMP | Physical camera: focal length, aperture, EV |
## Assembling a scene [#assembling-a-scene]
```python title="Textport — minimal scene"
render = op('/project1/photon_rtxpt1')
render.par.geometry = '/project1/geo1' # any SOP hierarchy
render.par.camera = '/project1/photoncam1' # falls back to a default cam
render.par.lights = '/project1/photonlight*' # wildcard collect
```
The renderer collects by **path pattern** — the same wildcard rules as any
TouchDesigner parameter that takes an OP path. Drop a new
`Photon Light` matching the pattern and it joins the next cook.
Helper COMPs cook at parameter-change time only. The renderer is the only
operator doing per-frame work — keep your cull flags on the SOPs feeding
it, not on the Photon COMPs.
## Cook behavior [#cook-behavior]
* **Static scene** → progressive accumulation, up to the `Max Samples` cap
* **Camera move** → accumulation resets, denoiser bridges the gap
* **Geometry edit** → only the touched acceleration structure rebuilds
Time-sliced CHOP exports into material parameters force a full reset every
frame. Route animated values through the `Photon Material` COMP's dedicated
Animate page instead — those update without invalidating accumulation.
# Parameter reference (/docs/photon-rtxpt/parameters)
This reference is **generated** — the same source that registers parameters
with TouchDesigner emits these tables, so they cannot drift from the build.
Placeholder subset below until the generator lands.
## Render page [#render-page]
## Output page [#output-page]
## Full table [#full-table]
| Page | Parameter | Type | Default |
| -------- | -------------- | ---------- | ----------- |
| Render | Samples / Cook | int | 1 |
| Render | Max Samples | int | 1024 |
| Render | Max Bounces | int | 4 |
| Render | Denoiser | menu | DLSS-RR |
| Render | Exposure | float | 0 |
| Output | Resolution | wh | 1920 × 1080 |
| Output | Tone Map | menu | ACES |
| Output | AOV Layers | toggles | off |
| Scene | Geometry | OP path | — |
| Scene | Camera | OP path | — |
| Scene | Lights | OP pattern | — |
| Scene | Scene Scale | float | 1.0 |
| Advanced | Ray Offset | float | 0.0001 |
| Advanced | Firefly Clamp | float | 8.0 |
| Activate | License Key | string | — |
# Activation problems (/docs/troubleshooting/activation-problems)
Activation failures are deliberately specific — the `Status` readout names
the exact refusal. Find yours below.
Three causes, in frequency order: a typo (keys are
`NOP-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX` — 36 characters after the
prefix, so the dashboard's copy button beats retyping), a key for a *different plugin* (keys are plugin-scoped), or a
revoked key after a refund. The [dashboard](/dashboard) shows each
key's plugin and state.
The seat is active elsewhere — possibly a dead machine that never got
the chance to deactivate. Free it from the
[dashboard](/dashboard) (**Seats → Deactivate**); the change is
immediate, no support ticket needed.
The `seat.license` was issued for different hardware. Regenerate the
`machine.request` *on the machine as it is now* and reissue — this hits
people who swapped a GPU, and farm operators who cloned an image with a
request file baked in.
Offline licenses carry a signed timestamp. Air-gapped machines drift;
more than 48 hours breaks validation. Set the clock (GPS/NTP appliance
on show networks), regenerate, reissue.
The machine can't reach the licensing endpoint. Corporate TLS
inspection is the usual culprit — ask IT to exempt
`licensing.nativeops.tools`, or use
[offline activation](/docs/getting-started/activation#offline-activation),
which exists for exactly this network.
None of it matching? [Contact support](/contact) with the Info DAT
diagnostics dump (right-click the operator → **Copy Diagnostics**) — it
includes the last ten status transitions, which is usually the answer.
# Drivers (/docs/troubleshooting/drivers)
Driver bugs present as **device-lost crashes** mid-session or as denoiser
artifacts — not as load failures. If the operator loads and then the GPU
resets under load, start here.
Short version: run the latest **Studio** driver. Game Ready drivers ship
first and regress compute paths more often; Studio is the same driver on a
slower, better-tested cadence.
## Known ranges (placeholder) [#known-ranges-placeholder]
| Driver range | Symptom | Verdict |
| --------------- | ------------------------------- | ---------------- |
| 572.00 – 572.42 | DLSS-RR denoiser NaN flashes | Skip |
| 566.xx | Stable everywhere we test | Floor for Photon |
| \< 560.00 | Load refused (`Driver too old`) | Hard floor |
## The clean-install ritual [#the-clean-install-ritual]
When a machine misbehaves on a driver that's fine elsewhere:
Download the current Studio driver directly from NVIDIA — not Windows
Update, not GeForce Experience.
Run the installer with **Custom → Perform a clean installation**
checked. This clears cached shader blobs and stale settings profiles,
which is the actual fix more often than the driver version.
Reboot, then delete TouchDesigner's own shader cache folder so nothing
stale is replayed against the new driver.
Enterprise/vPro fleets that pin drivers via SCCM: the pinned driver is
usually months behind the floor. The plugins print the minimum version in
the status string — hand that line to IT, it is the whole conversation.
# GPU requirements (/docs/troubleshooting/gpu-requirements)
At load, every operator runs the same checks in order and stops at the first
failure — the `Status` readout names it. Work down the same list.
### `No CUDA device` [#no-cuda-device]
TouchDesigner isn't running on the NVIDIA GPU. On laptops, force it:
NVIDIA Control Panel → Manage 3D Settings → Program Settings →
TouchDesigner → **High-performance NVIDIA processor**.
### `CUDA version` — compute capability below 7.5 [#cuda-version--compute-capability-below-75]
The GPU predates Turing (GTX 10-series or older). No setting fixes
this — see the support matrix in
[Requirements](/docs/getting-started/requirements).
### `GPU unsupported` — RT cores missing (Photon only) [#gpu-unsupported--rt-cores-missing-photon-only]
GTX 16-series has CUDA 7.5 but no RT cores: Matter and Aura run, the
Photons refuse. This is the one row where plugins diverge.
### `Out of memory` at first cook [#out-of-memory-at-first-cook]
The checks passed; the scene doesn't fit. Drop the internal resolution
preset, or close Chrome — its GPU process routinely holds 1–2 GB.
## FAQ [#faq]
Almost always Optimus: the laptop is cooking TouchDesigner on the iGPU.
The `No CUDA device` step above fixes it. Verify with the Info DAT —
`gpu_name` should say NVIDIA, not Intel/AMD.
Not yet — the operator cooks on TouchDesigner's active adapter.
Multi-GPU affinity is on the [roadmap](/roadmap).
Shared system memory counts toward nothing: the 6 GB floor means
dedicated VRAM. A 4 GB dedicated + 8 GB shared laptop fails the check
honestly.
# Troubleshooting (/docs/troubleshooting)
Every NativeOps operator reports its state in the `Status` readout on the
Common page. That string is the fastest route to the right page below.
| Status says | Go to |
| --------------------------------------- | ---------------------------------------------------------------- |
| `GPU unsupported` / `CUDA version` | [GPU requirements](/docs/troubleshooting/gpu-requirements) |
| `Driver too old` / device-lost crashes | [Drivers](/docs/troubleshooting/drivers) |
| `License invalid` / `Activation failed` | [Activation problems](/docs/troubleshooting/activation-problems) |
| Operator missing from OP Create | [Installation](/docs/getting-started/installation) |
The load-time hardware checks and what each failure means.
Known-bad driver ranges and the clean-install ritual that fixes most
device-lost errors.
Key rejected, seat conflicts, offline files that won't take.
Filing a [support request](/contact)? Attach the operator's Info DAT dump
(right-click → **Copy Diagnostics**) — it carries the plugin build, driver,
GPU, and the last ten status transitions, and it turns most tickets into
one-reply fixes.