greenlight-motion 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +4 -0
- package/README.md +37 -9
- package/THIRD_PARTY_LICENSES.md +1 -1
- package/cli/index.mjs +118 -13
- package/cli/plugin3d.mjs +202 -0
- package/dist/assets/rigWorker-CGpWyn_f.js +1 -0
- package/dist/bundle-inputs.json +36 -0
- package/dist/greenlight-motion-script.mjs +16524 -202
- package/dist/greenlight-motion.js +698 -688
- package/dist/greenlight-motion.mjs +78778 -74492
- package/dist/script-inputs.json +6 -1
- package/package.json +9 -1
- package/schema/capabilities.json +1 -1
- package/skill/SKILL.md +22 -11
- package/skill/references/scene-script.md +86 -0
- package/skill/references/video-3d.md +223 -8
- package/skill/references/video-camera.md +3 -2
- package/skill/references/video-effects.md +13 -1
- package/skill/references/video-keyframes.md +6 -0
- package/skill/references/video-particles.md +5 -11
- package/skill/references/video-paths.md +2 -1
- package/skill/references/video-projects.md +18 -11
- package/skill/references/video-shapes.md +1 -0
- package/skill/references/video-text.md +43 -7
- package/skill/references/video-world3d.md +1548 -0
- package/skill/references/world3d-schema.json +15118 -0
|
@@ -0,0 +1,1548 @@
|
|
|
1
|
+
> **A 3D Scene in GreenLight Motion:** a scene script's `world.scene` is `rig.scene` below, and `world.render`, `world.look`
|
|
2
|
+
> and `world.exposure` are `rig.render`, `rig.look` and `rig.exposure`. The script writes `"renderer": "world"`, `"lights": []` and
|
|
3
|
+
> `"cyclorama": { "shape": "none" }` itself, so the Rig adds no lights and no backdrop: light comes from `scene.lights` and
|
|
4
|
+
> `scene.env` (the bundled HDRIs, default `studio_small_03_1k`), and a floor or a studio sweep is an object you model. A
|
|
5
|
+
> `world` is in metres (real sizes). The renderer ignores a field it does not know, but the script checks every field
|
|
6
|
+
> first and fails the build with the right name. Your own files (models, textures, splats) are not part of a `world` here,
|
|
7
|
+
> and titles are the script's scenes. Ignore the `/api/...` routes and the Rig's settings below. To check the picture, use
|
|
8
|
+
> look_at_video's critique in a chat, or `npx greenlight-motion check` locally.
|
|
9
|
+
|
|
10
|
+
# GreenLight Dash — build 3D in the Scene, with no Blender
|
|
11
|
+
|
|
12
|
+
> Read [video-projects.md](video-projects.md) for the versioned-write contract and [video-3d.md](video-3d.md) for model layers and the Rig. Load only what the task needs.
|
|
13
|
+
|
|
14
|
+
The Scene layer (the `rig` clip) can hold a whole world that an agent wrote as JSON: geometry from a node graph, materials, lights, simulations and keyframes. It renders together with the 3D layers on the timeline, in **Draft 3D** while the user works and path traced in **Final 3D**. Nothing here needs Blender or any other install, but **a 3D Scene needs the WebGPU engine**: in an editor on WebGL, or on a computer with no WebGPU, the preview and the Scene panel show a notice instead of the Scene (the panel's "Switch to WebGPU" sets the engine), and 2D layers keep drawing. Renders and stills of a project with a Scene always run on WebGPU, automatically, whatever the app's engine or the request's `renderer`.
|
|
15
|
+
|
|
16
|
+
## Contents
|
|
17
|
+
|
|
18
|
+
- [Turn it on and write a scene](#turn-it-on-and-write-a-scene)
|
|
19
|
+
- [The scene format](#the-scene-format): [materials](#materials), [glass and liquids](#glass-and-liquids), [glowing surfaces](#glowing-surfaces), [procedural materials](#procedural-materials), [texture graphs](#texture-graphs-smart-materials-with-wear-and-dirt-graph), [animated materials](#animated-materials-edge-glow-live-noise-beam-sweep-graph-presets), [`translucency` and `subsurface`](#light-through-a-sheet-light-into-a-body-translucency-and-subsurface), [`iridescence`, `metal`, `anisotropy`, `roundEdges`](#thin-film-real-metals-brushed-metal-round-edges-iridescence-metal-anisotropy-roundedges), [car paint, dust, toon](#car-paint-dust-and-toon-flakes-coatbump-dust-toon), [the material library](#the-material-library-preset), [`displacement`](#real-relief-from-a-height-displacement), [`reveal`](#a-surface-that-comes-and-goes-reveal), [objects and graphs](#objects-and-graphs-blender-outside-houdini-inside)
|
|
20
|
+
- [Ops](#ops): [solids](#solids), [sheets and points](#sheets-and-points), [modifiers](#modifiers-one-input-the-node-before-unless-in-says-otherwise), [several inputs](#several-inputs-set-in), [points to copies](#points-to-copies), [harder shapes](#harder-shapes), [rooms and furniture](#rooms-and-furniture), [escape hatch](#escape-hatch)
|
|
21
|
+
- [Lights in the scene](#lights-in-the-scene): [kelvin, watts, lumens, IES](#light-in-a-lighting-designers-units-kelvin-power-lumens-ies), [highlight placement](#put-the-highlight-where-you-want-it-highlight), [studio presets](#studio-presets-type-studio), [light and shadow linking](#which-light-reaches-what-tags-light-linking-and-shadow-linking), [light mix and passes](#light-mix-and-light-passes-looklightmix-renderlightpasses), [ray visibility and holdouts](#what-each-kind-of-ray-sees-visibility-holdout), [render passes and masks](#render-passes-and-masks-renderpasses-lookpassmix-world-mattes)
|
|
22
|
+
- [Shadows in Draft](#shadows-in-draft)
|
|
23
|
+
- [Fog and haze](#fog-and-haze)
|
|
24
|
+
- [Smoke and fire](#smoke-and-fire)
|
|
25
|
+
- [Cloth and soft bodies](#cloth-and-soft-bodies)
|
|
26
|
+
- [Water, sand, snow and goo](#water-sand-snow-and-goo)
|
|
27
|
+
- [Rigid bodies](#rigid-bodies)
|
|
28
|
+
- [Pictures in the world (`inWorld`)](#pictures-in-the-world-inworld)
|
|
29
|
+
- [Motion blur](#motion-blur)
|
|
30
|
+
|
|
31
|
+
## Turn it on and write a scene
|
|
32
|
+
|
|
33
|
+
Everything lives on the `rig` clip's item, in `rig`. Write it through the ordinary project PATCH (live project, versioned write).
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
"rig": {
|
|
37
|
+
"renderer": "world",
|
|
38
|
+
"cyclorama": { "shape": "none" },
|
|
39
|
+
"lights": [],
|
|
40
|
+
"env": { "source": "preset", "preset": "studio_small_03_1k", "intensity": 0.6 },
|
|
41
|
+
"exposure": 1,
|
|
42
|
+
"look": { "contrast": 1.3, "saturation": 1.1, "bloom": 0.1, "glare": 0, "halation": 0.05, "vignette": 0.15, "grain": 0.1 },
|
|
43
|
+
"render": { "mode": "final", "spp": 64, "bounces": 8, "denoise": true },
|
|
44
|
+
"scene": {
|
|
45
|
+
"camera": { "at": [0, 0.3, 2.2], "target": [0, 0.1, 0], "fov": 28 },
|
|
46
|
+
"lights": [{ "id": "key", "type": "sun", "dir": [0.4, 1, 0.3], "intensity": 3, "size": 2 }],
|
|
47
|
+
"materials": { "clay": { "base": "#c9a184", "roughness": 0.6 } },
|
|
48
|
+
"objects": [{ "id": "ball", "material": "clay", "graph": [{ "op": "sphere", "radius": 0.2 }] }]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Every Rig is a 3D Scene drawn by this world renderer, on the WebGPU engine only, unless `rig.renderer` is `"classic"`. Write `"renderer": "world"` anyway: only with it does `"lights": []` mean no Rig lights instead of coming back as the default key, fill and rim (below).
|
|
54
|
+
- `scene` holds `objects`, `materials`, `lights`, `camera`, `env`, `sims`, `layers2d`, `volumes` (baked only) and `physics`, in the format below. `rig.env.tint` colours the environment's light, in Draft and Final. The Rig's own backdrop, lights and environment join it, and every `model3d` layer on the timeline stands in the same world, so objects shadow each other.
|
|
55
|
+
- The letters of a 3D Text layer (`text3d`, [below](#3d-text-in-the-world)), and those of a flat text layer with `textInWorld` ([below](#flat-text-in-the-world)). Shadows in the world come only from what it holds (scene objects, the backdrop, model layers, 3D Text, flat letters with `castShadow`, sims), so a flat layer's `shadowPlate.castShadow` casts none on it.
|
|
56
|
+
- A model the world draws takes no `opacity` or `blendMode`: bring it in or out with scale, position or rotation keys.
|
|
57
|
+
- `scene.camera` films the shot, keys included, and then the Camera layer has no say. Leave it out to film with the Camera layer: its moves, and its depth of field and focus pick, which in Final set the tracer's thin lens so Final blurs exactly as Draft ([video-camera.md](video-camera.md#depth-of-field)). `scene.camera`'s `up` does not animate, so a camera that banks belongs on the Camera layer (`camRoll`). A `.blend` import puts its shot on the Camera layer (blender.md (GreenLight Dash only)).
|
|
58
|
+
- `render` is what every render and still of the project uses: `mode` `"draft"` (the default) or `"final"`. Final traces every frame, so expect seconds per frame. Like Draft, it renders on WebGPU, which every render and still of a project with a Scene uses automatically (rendering.md (GreenLight Dash only)).
|
|
59
|
+
- Final's quality fields, with their defaults and ranges: `spp` [64, 1–4096], `bounces` [8, 1–32], `transparentBounces` [5, 0–32] (layers of glass a ray passes through), `glossy` [0.5, 0–1] (blurs reflections of reflections so they don't sparkle; glass whose caustic the caustic pass draws stays sharp), `clamp` [0 = off, up to 1000] (caps one sample's brightness against fireflies), `denoise` [true], `denoiseLook` ["natural" (the default: a fifth of the traced picture, its fireflies out, mixed back over the denoised one, so grain and surface detail stay), "clean" (the denoiser alone, smoothest) or "raw" (the samples the denoiser read, shown without it)], and `exposure` [1, 0.05–4], which scales Final's picture only, to match Draft or a Cycles frame (a `.blend` import sets it).
|
|
60
|
+
- `"lightPasses": true` keeps each light group's light apart in Final, so `look.lightMix` rebalances a finished trace without tracing
|
|
61
|
+
again ([Light mix and light passes](#light-mix-and-light-passes-looklightmix-renderlightpasses)).
|
|
62
|
+
- Bounces by kind of surface, each under `bounces` and unset by default (then only `bounces` limits it): `diffuseBounces` [0–32] (off
|
|
63
|
+
matte paint, plaster, wood, cloth), `specularBounces` [0–32] (off metal, a clear coat, a mirror, the reflection off glass) and
|
|
64
|
+
`transmissionBounces` [0–32] (through glass and liquid, thin glass, translucent leaves and lampshades; `transparentBounces` is cut-out
|
|
65
|
+
alpha, a different count) and `volumeBounces` [0–32] (scatters in a medium: the scene's [fog](#fog-and-haze) and a sim's smoke and
|
|
66
|
+
fire). A path that runs out of one kind ends there, its last hit still lit directly: `diffuseBounces: 0` is
|
|
67
|
+
direct light only on matte surfaces (no colour bleeding, darker corners), `specularBounces: 1` keeps a mirror's reflection but not
|
|
68
|
+
the reflection of a reflection, `transmissionBounces: 2` lets a ray in and out of one solid glass (a thin wall, an open mesh or `thinWalled`, is one
|
|
69
|
+
surface: one transmission), `volumeBounces: 0` lights fog and smoke by the light that reaches them and no further (single scattering:
|
|
70
|
+
thinner, darker smoke; the fog's own `bounces` counts depth in the path instead, this counts the scatters themselves). They are for the look and for control (a darker, more graphic room; a mirror that shows no infinite
|
|
71
|
+
regress; liquid in glass that needs many passes while the walls need few: `transmissionBounces: 12` with `diffuseBounces: 3`), not
|
|
72
|
+
for speed: with the radiance cache a room's paths already end early, and `diffuseBounces: 1` saved about 5 % of a Final still there.
|
|
73
|
+
Every bounce left out takes its light away, so a lower limit is a darker picture. Setting one builds the tracer's kernels once with
|
|
74
|
+
the counts; a scene that sets none (or none below `bounces`) traces as before.
|
|
75
|
+
- Nested glass is counted apart: clear glass and water (roughness under 0.1) never spend `bounces` (they have a budget of their own,
|
|
76
|
+
below), and where see-through bodies that do spend them nest or touch (frosted glass, rough ice: closed transmissive objects whose
|
|
77
|
+
boxes overlap) and `transmissionBounces` is unset, a path's first 4 passes through a surface do not count against `bounces`. A path
|
|
78
|
+
through a drink crosses two surfaces a body; at the default 8 its ice is clear, and a path that passes through nothing ends where it
|
|
79
|
+
did. Set `transmissionBounces` to take the count back into your own hands.
|
|
80
|
+
- Through smooth glass and water (roughness under 0.1) the denoiser follows what lies behind them, as Cycles' denoising guides do: a
|
|
81
|
+
drop on a petal, a glass of water or a lens keeps the picture it refracts sharp instead of being smoothed as one clear surface.
|
|
82
|
+
- `denoise: false` traces for no denoiser (another way of picking light samples, with less grain, and no carried light between video
|
|
83
|
+
frames), so its picture is not the denoised one's samples. To see exactly what the denoiser starts from, keep `denoise: true` and set
|
|
84
|
+
`denoiseLook: "raw"`: same trace, same samples, the denoiser still runs (same time), only the picture shown or rendered is its input.
|
|
85
|
+
Natural, Clean and Raw are the same trace shown three ways; in the editor's preview a change between them shows at once.
|
|
86
|
+
- Final ends its light paths in a radiance cache of the room's light after their first bounce, in stills and video renders alike. In a room, `spp: 32` looks like 64 without it, in about half the time and with no extra flicker. In an open scene lit mostly by the sky it gains little, so halving the samples there is not free. `"radianceCache": false` in `render` turns it off.
|
|
87
|
+
- `look` and `exposure` are the film look, and changing them never rebuilds the world. A `look` field left out takes its default:
|
|
88
|
+
`contrast` 1.25, `saturation` 1.3, `bloomThreshold` 1, and 0 for `bloom`, `glare`, `halation`, `vignette` and `grain`.
|
|
89
|
+
- `look.whiteBalance` is the camera's white balance in kelvin, as on a camera: the colour of the light it takes for white. Unset (or
|
|
90
|
+
6500) changes nothing; 7000 to 8000 warms a room lit by an overcast sky (white walls with the faint warm cast interior photographers
|
|
91
|
+
give them), 3200 to 4500 cools a room lit by lamps. A photographic interior also wants `contrast` 1.1 to 1.15 and `saturation` 1
|
|
92
|
+
to 1.1 (the defaults are a film's).
|
|
93
|
+
- `look.localTone` (0 to 1, off by default) is local tone mapping, what an interior photographer's exposure blend does: a room lit
|
|
94
|
+
through its window is five or six stops under the sky, and one exposure either blows the window, its frame and the wall round it out
|
|
95
|
+
or leaves the room grey. With it the picture's large-scale brightness more than `localToneKnee` stops (default 1) over the scene's grey
|
|
96
|
+
is brought down by that share, while everything smaller (texture, contact shadows, threads, the window's bars against the sky) keeps
|
|
97
|
+
its contrast: expose for the room and the window holds. `localToneShadows` (0 to 1, default a third of `localTone`) lifts the large
|
|
98
|
+
dark areas, `localToneContrast` (1 to 2, default 1) deepens the large-scale light under the knee (a room's fall-off from its window:
|
|
99
|
+
its far corner darker, its ceiling darker toward the back), `localToneDetail` (default 1; 1.1 to 1.3 a photographer's clarity) scales
|
|
100
|
+
the kept detail. Draft and Final alike; a look without it costs nothing. A daylit room: `{ "localTone": 0.6, "localToneKnee": 1.6,
|
|
101
|
+
"localToneShadows": 0, "localToneContrast": 1.5, "localToneDetail": 1.1, "contrast": 1.35 }` with the exposure that puts the walls
|
|
102
|
+
by the window near white, and the view out of the window (`env.view`) at its natural `intensity` 1. Past about 1.7 contrast or 1.2
|
|
103
|
+
detail the strongest edges (a dark sofa against a white wall, leaves against the window) pick up thin halos.
|
|
104
|
+
- `look.view` picks the view transform, as Blender's View Transform: `"agx"` (the default film curve, with `contrast` and `saturation`),
|
|
105
|
+
`"aces"` (ACES 1.3's RRT and sRGB output, by Stephen Hill's fit: more contrast, highlights rolling to white), `"neutral"` (Khronos
|
|
106
|
+
PBR Neutral: colours exactly as authored up to near white, for product colours that must read true) or `"standard"` (plain sRGB,
|
|
107
|
+
clipping). `contrast` and `saturation` shape AgX only; the scene's exposure means the same light in every view (`exposure` 1/1.35 is
|
|
108
|
+
Blender's view at exposure 0). Measured against Blender 5.1's own views of the same light: Neutral and Standard within 2 levels of
|
|
109
|
+
255; ACES within 1.5 on greys and up to 11 on fully saturated primaries (the fit leaves out ACES's gamut corrections).
|
|
110
|
+
- `look.lut` grades the filmed picture with a look-up table: a `.cube` 3D LUT URL (`"/media/…/look.cube"`, from any grading tool),
|
|
111
|
+
`{ "cube": "<the file's text>" }`, or a built-in grade: `"tealOrange"`, `"warmFade"`, `"bleach"`, `"cool"`, `"mono"` (`"identity"`
|
|
112
|
+
changes nothing). It takes the picture after the view transform (display sRGB), as grading tools expect; `look.lutStrength` (0 to 1)
|
|
113
|
+
mixes it. A file that does not parse leaves the picture ungraded and says why in `scene.warnings`.
|
|
114
|
+
- `look.aberration` (0 to 1) is a lens's lateral chromatic aberration: red and blue fringes that grow toward the corners (1 is about
|
|
115
|
+
0.8 % of the half width at the corners). Draft and Final.
|
|
116
|
+
- `look.tone: "plate"` films the picture through sRGB alone instead of the film curve (AgX with `contrast` and `saturation`): for objects put into real footage, whose environment and floor were read off the footage the same way, so a grey the footage shows at half brightness comes back at half, and a sky reflected in chrome is as bright as the sky in the shot. Set it with `contrast: 1, saturation: 1`; the footage call (GreenLight Dash only) sets all three. With it, `look.soften` (px, 0–3) blurs the world's picture where it joins the layers below, coverage with it, to the footage's own softness, and `look.black` (0–0.15) lifts the world's surfaces' darks to the footage's black level (toward `look.blackTint`, [r, g, b] at unit brightness, default grey; a catcher's shadow is never lifted); 0 (the default) skips both. While `soften` is on, `look.grain` is laid on after that blur (so the blur does not take the footage's grain away again). `look.sharpen` (0–1) adds the world's own fine detail back as a camera's sharpening does, inside the objects only (never at their outline); `look.wrap` (0–1) wraps the light of the layers right under the Scene onto the objects' edges (a light wrap: a dark object on a bright table, a window behind it), only where those layers are full-frame, camera-locked footage at the bottom of the stack. The footage call measures and sets all of them; `env.keyDir` ([x, y, z], y up) names the direction the environment's key light comes from, which Draft's directional shadow follows.
|
|
117
|
+
- Every `model3d` layer keeps its `screen` and `screens` artwork, its GLB clips and its pose ([video-3d.md](video-3d.md#characters--the-pose-pipeline-model3dconfigpose): crossfades, morphs, bones, look-at and IK aimed at Scene objects by `"@id"`, a Scene object held by a bone with `attach`) in the world, in both modes. Its colour filters, its Grow Fill and the real-3D Overlay Effects with `inWorldScene: "onObject"` run in the world on the model itself, in Draft and Final alike, and it keeps its shadow. While an effect with `inWorldScene: "ownPass"` (RGB Split, Digital Glitch, Pixel Stretch, Slit Scan, Spectral Curtain, Flash Blink) is live, the model leaves the world for its own pass, and so does a model with a blur or any other flat effect: it then casts no shadow and Final does not trace it; it stays where the world showed it, lit and filmed as the world lights and films it. Effects with `inWorldScene: "skipped"` are not available on a model in a world Scene ([effects-depth.md](video-effects.md#in-a-world-scene-rigrenderer-world)). `"renderer": "classic"` turns the world off for the whole Rig.
|
|
118
|
+
- A material's `maps` and an object's `model` take media URLs (`"maps": { "base": "/media/…" }`, `"model": "/media/….glb"`). `env.hdri` takes an `.hdr` URL. A picture in `maps.base` is multiplied by the material's `base`, so leave `base` out (white) to show the picture's own colours.
|
|
119
|
+
- The environment lights everything, shadows included, so it sets how dark a sun's shadow can be. With the studio preset and a sun at 3, Final measured the shadow at 58% of the lit floor with the environment at 0.05, 87% at 0.2 and 98% at 0.6, where the frame is nearly white. For a sunny look with clear shadows keep the environment at 0.05 to 0.15; the 0.6 above is a soft studio look.
|
|
120
|
+
- `"lights": []` on a Rig with `"renderer": "world"` means no Rig lights: the scene's own lights and the environment light the world. Leave `lights` (or `renderer`) out to get the Rig's default key, fill and rim, which cast no shadows and so lighten every shadow your sun casts. An `ambient` or `hemisphere` Rig light adds its intensity to the environment's and its colour tints the share it adds, as it rests and as a colour key (`scc:<lid>:col`) moves it, as on a classic Rig (a red one at 1.5 over an environment at 0.5: the 1.5 it adds is red, the environment's own 0.5 stays as it is; a dark `#20222a` at 0.05 adds almost nothing). A `hemisphere`'s `color` tints the environment's upper half and its `groundColor` the lower half. With no environment map (`env.source: "none"`) an `ambient` or `hemisphere` lights the world as a flat environment of its own colour, as bright as on a classic Rig. A Solid or picture backdrop is as opaque as its `opacity` (0.6 lets 40 % of the layers below through), at rest and keyed (`sc:cyc:opacity`).
|
|
121
|
+
|
|
122
|
+
A new Scene layer, whole, as it goes into the project's `clips` and `channels` (a `rig` clip's empty `url` is right; only `model3d` clips need one):
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
"clips": [{ "id": "c-rig", "source": "LOCAL", "mediaType": "rig", "url": "", "name": "Scene", "duration": 6 }],
|
|
126
|
+
"channels": [{ "id": "ch-rig", "name": "Scene", "kind": "rig", "visible": true, "unsnapped": true,
|
|
127
|
+
"items": [{ "id": "i-rig", "clipId": "c-rig", "trimStart": 0, "trimEnd": 6, "freeStart": 0, "rig": { "renderer": "world", "lights": [], "scene": { } } }] }]
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## The scene format
|
|
131
|
+
|
|
132
|
+
A scene is plain JSON. An agent writes it, the project stores it, and the renderer reads it. Every field below is optional;
|
|
133
|
+
an object with no `graph` is a plain group. The renderer silently ignores a field it does not know, so a misspelled one (`transmision`)
|
|
134
|
+
changes nothing in the picture: check every scene with `POST /api/world3d/validate` before rendering, and ask
|
|
135
|
+
`GET /api/world3d/help?path=…` about any field ([Check your work](#check-your-work)). The whole schema, every field with its type,
|
|
136
|
+
range and default, is [world3d-schema.json](world3d-schema.json) next to this page.
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"camera": { "at": [0, 1.2, 2.4], "target": [0, 0.2, 0], "fov": 28, "keys": { "at": [{ "t": 0, "v": [0, 1.2, 2.4] }] } },
|
|
141
|
+
"env": { "hdri": "/media/…/studio.hdr", "intensity": 1, "rotation": 0, "background": "env" },
|
|
142
|
+
"lights": [{ "id": "key", "type": "sun", "dir": [0.4, 1, 0.3], "color": "#fff4e6", "intensity": 3, "size": 2 }],
|
|
143
|
+
"materials": { "oak": { "base": "#8a6a4c", "roughness": 0.55, "metalness": 0, "maps": { "base": "/media/…/oak.png" }, "uvScale": [2, 2] } },
|
|
144
|
+
"objects": [
|
|
145
|
+
{ "id": "desk", "name": "Desk", "parent": null, "at": [0, 0, 0], "rot": [0, 0, 0], "scale": [1, 1, 1], "material": "oak",
|
|
146
|
+
"graph": [{ "op": "box", "size": [1.6, 0.04, 0.8], "bevel": 0.004 }],
|
|
147
|
+
"keys": { "at": [{ "t": 0, "v": [0, 0, 0], "ease": "out" }, { "t": 1, "v": [0, 0.1, 0] }] } }
|
|
148
|
+
],
|
|
149
|
+
"layers2d": [{ "id": "title", "kind": "text", "text": "Hello", "at": [0, 0.3, 0], "height": 0.1 }],
|
|
150
|
+
"sims": [{ "recipe": "sparks_in_wind", "id": "sparks", "at": [0, 0, 0] }]
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Units are metres and degrees. Y is up. Times are seconds. The Scene clip's length and the project's frame rate set the duration and
|
|
155
|
+
fps, so a scene carries none (`version`, `duration` and `fps` are ignored here).
|
|
156
|
+
|
|
157
|
+
- The camera's `fov` is vertical. `camera.fStop` and `camera.focus` (metres, keyable) give the scene camera depth of field: Final traces
|
|
158
|
+
the thin lens, and Draft blurs each pixel over the same lens's circle for its depth, up to a 24th of the frame's height across (a
|
|
159
|
+
macro shot's far background, which Final blurs further, stays a little sharper in Draft). The lens is the focal length that gives `fov` on a film `sensor` [36] mm wide: at 16:9, fov 28 is about
|
|
160
|
+
41 mm and fov 20 about 57 mm. Set `lens` (mm) instead of `fov` to choose it directly.
|
|
161
|
+
- The camera sees the whole set however big it is: its far plane follows the set's farthest corner (and a sim's `area`), never under
|
|
162
|
+
200 m, and its near plane stays 2 cm (it rises with a very big set, never past half the way to the nearest thing). Nothing past 200 m is
|
|
163
|
+
cut any more, in Draft or Final.
|
|
164
|
+
- Orthographic camera (isometric product and architecture shots): `"projection": "ortho"` with `orthoHeight`, the frame's height in metres
|
|
165
|
+
(its width follows the video's aspect; left out, the frame the perspective camera has at `target`). Rays are parallel, so a thing is as
|
|
166
|
+
big far as near and lines that are parallel in the world stay parallel; there is no depth of field. The camera still stands at `at` and
|
|
167
|
+
looks at `target`: nothing between it and its near plane, or behind it, shows, so stand it well back (`"at": [6, 5, 6], "target": [0, 0.4, 0]`
|
|
168
|
+
is a classic isometric look down on a set at the origin). `orthoHeight` is keyable (an orthographic zoom). A model layer that leaves
|
|
169
|
+
the world for its own pass (a blur, a flat effect, one of the six that move its picture) is filmed orthographic too, and sorts with the
|
|
170
|
+
world by depth as in a perspective Scene. The view out of the windows (`env.view`) stands as a flat backdrop for it (its `distance`).
|
|
171
|
+
```json
|
|
172
|
+
"camera": { "projection": "ortho", "orthoHeight": 2.4, "at": [6, 5, 6], "target": [0, 0.4, 0] }
|
|
173
|
+
```
|
|
174
|
+
- Lens shift: `"shift": [x, y]` slides the frame by shares of its width and height without turning the camera, so verticals stay vertical
|
|
175
|
+
(a view camera's rise and fall). For a building or a tall product seen from low down, keep the camera level (`target` at the same height
|
|
176
|
+
as `at`) and raise the frame: `"shift": [0, 0.3]`. Works with both projections; keyable.
|
|
177
|
+
- Tilt-shift (Scheimpflug): `"tilt"` leans the plane of sharp focus that many degrees off the film, hinged on the `focus` point (an object,
|
|
178
|
+
the target, or the point `focus` metres out on the axis); it needs `fStop`. Positive leans the plane's top away from the camera:
|
|
179
|
+
`tilt` = 90 minus how steeply the camera looks down puts a whole ground in focus, near to far (for a camera looking down 35 degrees, 55).
|
|
180
|
+
The "miniature" look is the other way round: a plane leaned almost onto the line of sight keeps only a thin band through the focus point
|
|
181
|
+
sharp, the blur growing steadily above and below it: `tilt` -85 to -88 for a tabletop a few metres off, -89 to -89.5 for a street seen
|
|
182
|
+
from tens of metres (or the same positive), with `fStop` 1.4 to 2.8; the nearer to 90, the thinner the band. The band is thinnest with the focus point near the middle of the frame: aim `target` at what should be sharp and slide
|
|
183
|
+
the frame with `shift` to compose. `tiltRotation` turns the hinge about the view (90: a vertical sharp band). `tilt` is keyable. Final
|
|
184
|
+
traces the tilted lens; Draft blurs by the same lens, so the band sits on the same rows in both. Flat text in the world
|
|
185
|
+
(`textInWorld`) and splats blur by the same tilted plane, in Draft and Final.
|
|
186
|
+
```json
|
|
187
|
+
"camera": { "at": [8, 20, 30], "target": [-0.75, 0.33, 9.3], "fov": 26, "shift": [0, 0.12], "fStop": 2, "tilt": -89.5 }
|
|
188
|
+
```
|
|
189
|
+
- Bokeh: `blades` (0 round, 5 to 9 a stopped-down lens's polygon), `bokehRotation` (degrees), `anamorphic` (an anamorphic lens's oval
|
|
190
|
+
bokeh: that many times taller than wide, its height the round bokeh's, as Cycles' aperture ratio; 1.33 to 2 as real anamorphic lenses) and `catEye` (0 to 1: toward the frame's edges the lens barrel cuts each out-of-focus
|
|
191
|
+
highlight into a lemon shape pointing at the middle, as on a fast lens wide open; 0.3 to 0.5 a vintage lens). Final traces them; they
|
|
192
|
+
need `fStop`.
|
|
193
|
+
- Physical exposure: `iso` and `shutter` (seconds or `"1/125"`) with `fStop` set the picture's exposure as on a camera: ISO 100, 1/50 s,
|
|
194
|
+
f/4 is exposure 1, and each doubling of ISO or of the shutter time, or each stop wider (`fStop` / 1.41), is one stop brighter. Only a
|
|
195
|
+
camera that sets `iso` or `shutter` takes it (`fStop` alone stays depth of field); it multiplies the Rig's `exposure`, in Draft and
|
|
196
|
+
Final, and `iso` and `shutter` are keyable (an exposure ramp, or an iris pull with `fStop` keyed too). The shutter here is exposure
|
|
197
|
+
only; motion blur has its own settings.
|
|
198
|
+
- `distortion` bends the whole frame as a real lens does: above 0 barrel (a wide lens: straight lines bow outward), below 0 pincushion
|
|
199
|
+
(a long lens); 0.05 to 0.15 reads as a real lens. The corners stay where they were (nothing goes black) and the picture, its depth and
|
|
200
|
+
its masks bend together, in Draft and Final.
|
|
201
|
+
```json
|
|
202
|
+
"camera": { "at": [0.6, 0.3, 1.4], "target": [0, 0.1, 0], "lens": 35, "fStop": 1.8, "focus": "@bottle", "catEye": 0.4, "iso": 400, "shutter": "1/100", "distortion": 0.06 }
|
|
203
|
+
```
|
|
204
|
+
- Lights are in [Lights in the scene](#lights-in-the-scene): where each kind stands and where it points.
|
|
205
|
+
- `env` (`hdri`, `intensity` [1] (it scales `flat` too), `rotation` degrees, `tint`, `flat`, `background`, `opaque`) merges over the Rig's environment
|
|
206
|
+
(`rig.env`, a bundled preset by default; `hdri` takes an `.hdr` URL, the presets are `/hdr/<preset>.hdr`). It lights everything, but
|
|
207
|
+
where no object is, the frame shows what lies below the Scene layer (the project background, black by default), not the panorama:
|
|
208
|
+
set `"opaque": true` to see the environment there (a sky through a window, a studio around a product), or `background` to a colour
|
|
209
|
+
(`"#e9e4dc"`) for a plain backdrop. `"background": "none"` keeps the frame see-through even so. A colour background is only what the
|
|
210
|
+
camera sees where no object is: the panorama still lights the scene and shows in reflections.
|
|
211
|
+
- `env.view` is the view out of the windows: a picture the eye sees where the sky shows (through an opening or a `pane`), at the
|
|
212
|
+
picture's own resolution, while the room is lit by the environment as before (nothing that lights reads it). Without one the sky
|
|
213
|
+
map shows there, a 1k panorama blurred about 8 times through a window at 1080p. A photo of the street: `"view": { "image":
|
|
214
|
+
"/media/…/street.jpg", "fov": 90, "dir": [-1, 0.05, -0.4] }`: `fov` [60] degrees across the picture's width, `dir` where its middle
|
|
215
|
+
looks in the world (out of the window, a little toward where the camera looks through it), `up` [[0, 1, 0]]; take it wider than the
|
|
216
|
+
window as seen from the camera (90 to 110), as its outer 2.5 % fade into the sky. A whole equirect panorama (2:1) is
|
|
217
|
+
`"panorama": true`, turned with `rotation`. `intensity` [1] is its brightness as a share of the sky it covers (1 gives it the
|
|
218
|
+
environment's mean brightness over the same directions: no exposure of its own; 1.5 to 3 for a street a few stops brighter than
|
|
219
|
+
the room, as a camera exposed for the room sees it). `haze` [0] lays the picture's own mean over it (dirty glass, the air across a
|
|
220
|
+
street: 0.15 to 0.3 from inside a room). Needs `background` `"env"` (and `opaque`). An orthographic camera's rays are parallel, so
|
|
221
|
+
it sees the picture as a flat backdrop `distance` [20] metres out from the scene's origin along `dir`, as wide as `fov` makes it there:
|
|
222
|
+
each window shows the part straight behind it. Nearer (`"distance": 8`) shows more of the picture through a window; a perspective
|
|
223
|
+
camera ignores it. A `panorama` view is a sky at infinity: an orthographic camera sees its one colour along the view, as of the sky.
|
|
224
|
+
- An object takes `castShadow: false` (it throws no shadow, in Draft and Final) and `receiveShadow: false`. Its `tags` let lights pick
|
|
225
|
+
it (light and shadow linking), `visibility` says which kinds of rays see it, and `holdout: true` cuts it out of the picture as a
|
|
226
|
+
matte ([Which light reaches what](#which-light-reaches-what-tags-light-linking-and-shadow-linking), [What each kind of ray sees](#what-each-kind-of-ray-sees-visibility-holdout)).
|
|
227
|
+
- `"portal": true` marks an opening the environment's light comes in through: the window or open door of a closed room. Give it a flat `plane` the size of the opening, standing in it (`{ "op": "plane", "size": [w, h] }` then `{ "op": "transform", "rot": [90, 0, 0] }` for a wall that faces ±z), placed at the opening's inner face. It is never drawn, casts nothing and does nothing without an environment. In Final most of the environment's light samples then aim through the scene's portals, so a room lit only through its window is clean much sooner; light that comes in elsewhere is still found. Up to 8 portals; leave them out of an open set (no ceiling or missing walls). A set built with the `room` op needs none: while the camera is inside that room its window openings are portals by themselves (doors are not), unless the scene has portal objects of its own (then only those count).
|
|
228
|
+
- A material with `emission` lights the set in Final as a light: a screen, lit keys, an LED panel or a bulb is sampled directly, so the light it throws on what is near is clean at the usual samples (emission maps included: a screen lights the keyboard in its own colours). Glows share the light samples with the lights and the environment by how much each brings where it lands, so a small glow beside a sun costs the sun nothing. Not for a glow that is transparent, alpha-cut, translucent or subsurface, on a mesh with several materials, skinned or with shape keys, past the 16th glowing object or 65 536 glowing triangles, nor in a scene with a Grow Fill or a `reveal`: those glows still light the set, only noisier.
|
|
229
|
+
- A material with `screen` shows a video or a layer of the same project on any object (a tablet, a TV, a billboard built with ops): `"screen": { "url": "/media/….mp4" }` or `{ "layer": "<item or channel id>" }` (an HTML clip live from its page with no bake, a video in step with the timeline, an image). The picture lies over the object's UVs as a map in `maps` does (give it `uvPlanar` with `fit`, or `uvBox`), and glows (`"shading": "screen"`, default) or is the surface's colour under the set's light (`"lit"`). `look: "monitor"` makes it a monitor: glass coat with soft reflections (`glass` [0.1], its roughness) over a near-black panel, blacks lifted by `blackLevel` [0.02]. `strength` [1] scales the glow; `fit` `cover` (default) / `contain` / `stretch`; a url video takes `offset` (seconds) and `loop` [true]; `resolution: [w, h]` lays an HTML page out at that size. The material's own fields (`base`, `roughness`, `coat`, …) still win. A glowing screen lights the set in Final as a light (see `emission` above), following the picture it shows; with `look: "monitor"` Draft gets a soft light from it too, in the picture's average colour (no shadows; `"light": false` leaves it out). A model's glowing screen (`model3d` `screens`) without that look lights, in Draft, what stands in front of it within about one and a half screen diagonals (a keyboard under a monitor). The canvas is the source's own size and is uploaded again only when the source shows another frame: a paused video or a still page never restarts Final. MP4/MOV only for video.
|
|
230
|
+
- A spot light with a `radius` is a disc of light that glossy surfaces reflect cleanly in Final (as an area light is), not only a soft shadow.
|
|
231
|
+
- `layers2d` are flat pictures and words standing in the world: `kind: "image"` with `src` (a media url), or text (`text`, `fontPx` [160], `weight` [700], `font`, `color` [`#ffffff`]). `height` is in metres [0.2] (or give `width`; the other follows the picture), `at` and `rot` place it, `opacity` fades it. Objects in front hide it unless `ignoreDepth: true`. `receiveShadow: true` makes it a lit card that takes the set's shadows, and `castShadow: true` throws its shape's shadow. `screen: { "x", "y" }` (0..1 of the frame) pins it to the screen instead, with `height` then a fraction of the frame height [0.05]. `kind: "layer"` with `layer: "<item or channel id>"` stands a layer of the same project in the world as a card: an HTML clip (live, no bake), a video or an image, at its own aspect, hidden by what is in front and hiding what is behind, in Draft and Final; with `receiveShadow: true` it is lit by the set and traced in Final, without it it keeps its exact colours. Hide the source layer's channel to show it only in the world. In the editor only `kind: "layer"` cards reach the world.
|
|
232
|
+
- `sims` are simulations on the GPU (particles, smoke and fire, curves, and cloth, hair, sand and soft bodies; more solvers to come): a recipe such as `sparks_in_wind`, `pulse_explosion` or `cloth_drop_on_sphere`, or a whole `sim/1` graph of emitters, forces, fields, colliders and agent-written step snippets. They draw as lit objects, are traced in Final, and repeat exactly on every scrub and render. Everything about them is in sim.md (GreenLight Dash only). (The old `particles` field is gone and is ignored.)
|
|
233
|
+
|
|
234
|
+
### Materials
|
|
235
|
+
|
|
236
|
+
A material is a name in `scene.materials` that objects point at with `material` (or `materials` by slot). Every field is optional:
|
|
237
|
+
|
|
238
|
+
| Field | Range [default] | What it does |
|
|
239
|
+
|---|---|---|
|
|
240
|
+
| `base` | colour [`#ffffff`] | Surface colour (sRGB). Multiplies `maps.base` and a pattern's colours. |
|
|
241
|
+
| `roughness` | 0–1 [0.5] | 0 mirror, 1 matte; on glass it frosts the glass. |
|
|
242
|
+
| `metalness` | 0–1 [0] | 1 is metal. For real metals use `metal` (below). |
|
|
243
|
+
| `specular` | 0–2 [1] | Strength of a non-metal's reflection. |
|
|
244
|
+
| `coat`, `coatRoughness` | 0–1 [0, 0.1] | A clear lacquer on top. |
|
|
245
|
+
| `sheen`, `sheenColor`, `sheenRoughness` | 0–1, colour, 0–1 | Velvet rim light: cloth, felt. |
|
|
246
|
+
| `fabric` | true or `{ weave, threads, relief, contrast, variation }` | Cloth that reads as cloth: see [cloth](#cloth-fabric). |
|
|
247
|
+
| `pane` | bool [false] | Thin window glass: see [glass and liquids](#glass-and-liquids). |
|
|
248
|
+
| `transmission`, `ior`, `thinWalled`, `attenuationColor`, `attenuationDistance`, `priority`, `dispersion` | see [glass and liquids](#glass-and-liquids) | |
|
|
249
|
+
| `emission`, `emissionStrength` | see [glowing surfaces](#glowing-surfaces) | |
|
|
250
|
+
| `alpha` | 0–1 [1] | Opacity. Not for glass: glass is `transmission`. |
|
|
251
|
+
| `doubleSided` | bool [false] | Draw both sides: sheets need it, closed solids do not. |
|
|
252
|
+
| `maps` | `{ base, normal, roughness, metalness, emission, transmission, alpha }` | Media URLs, following the mesh's uvs. `normalStrength`, `normalFlipY`, `alphaFromBase` go with them. |
|
|
253
|
+
| `uvScale`, `uvOffset`, `uvRotation` | [u, v], [u, v], degrees | Repeat, shift and turn every map and pattern. `uvOffset` [0.5, 0] moves the picture half a tile toward −u (it shifts where the map is read). |
|
|
254
|
+
| `procedural`, `translucency`, `subsurface`, `iridescence`, `metal`, `anisotropy`, `roundEdges`, `displacement`, `reveal` | below | |
|
|
255
|
+
| `flakes`, `coatBump`, `dust`, `toon` | [car paint, dust, toon](#car-paint-dust-and-toon-flakes-coatbump-dust-toon) | |
|
|
256
|
+
| `preset` | a name from [the material library](#the-material-library-preset) | Over a hundred ready materials; the material's own fields go over it. |
|
|
257
|
+
|
|
258
|
+
Three.js and Blender names do not work here: `emissive` is `emission`, `emissiveIntensity` is `emissionStrength`, `color` is `base`,
|
|
259
|
+
`opacity` is `alpha`, `clearcoat` is `coat`, `metallic` is `metalness`. The validator says so and names the right one.
|
|
260
|
+
|
|
261
|
+
#### Glass and liquids
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
"materials": {
|
|
265
|
+
"glass": { "base": "#ffffff", "roughness": 0.02, "transmission": 1, "ior": 1.5, "priority": 1 },
|
|
266
|
+
"perfume": { "transmission": 1, "ior": 1.36, "attenuationColor": "#e8a440", "attenuationDistance": 0.3, "priority": 2 },
|
|
267
|
+
"frosted": { "transmission": 1, "ior": 1.5, "roughness": 0.35 }
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
- `transmission` 1 makes the surface let light through and bend it: glass, water, perfume, ice. `roughness` 0 to 0.05 is clear glass,
|
|
272
|
+
0.2 to 0.4 frosted. `ior` is how much it bends: 1.33 water, 1.36 alcohol and perfume, 1.45 oil, 1.5 glass, 2.42 diamond.
|
|
273
|
+
- A transmissive object on a **closed** mesh is a solid body, as real glass and Cycles' glass are: light bends going in and coming out,
|
|
274
|
+
so a glass ball is a lens (the view behind it turned over, a bright caustic under it in Final), a bottle's walls, ice and the water in a
|
|
275
|
+
glass refract. On an **open** mesh (a `plane`, a `grid`, a single-surface cup, a leaf) it is a thin wall that tints and reflects but bends
|
|
276
|
+
nothing, so a sheet made of a plane reads as a pane. Draft and Final alike. `thinWalled: true` makes it a thin wall on any mesh (a soap
|
|
277
|
+
bubble, a light bulb or a bauble modelled as one closed surface: the `soapBubble` preset has it); `thinWalled: false` a solid body on
|
|
278
|
+
any mesh (a pool's or a sea's surface made of a plane). Model a bottle's glass with real walls (a `lathe` whose profile goes up the
|
|
279
|
+
outside and back down the inside, or a `boolean` subtract of a smaller body) and the liquid as its own closed object inside: a lathe of
|
|
280
|
+
one wall is open, a thin glass surface.
|
|
281
|
+
- `attenuationColor` is the colour the light takes on after `attenuationDistance` metres inside: the tint of the liquid. It is
|
|
282
|
+
Beer–Lambert absorption: after `d` metres each channel keeps `attenuationColor ^ (d / attenuationDistance)` of its light, so a deeper
|
|
283
|
+
body is darker and more saturated. Keep the distance near the object's own size: for a 10 cm bottle, 0.2 to 0.5 m reads as light
|
|
284
|
+
amber, 0.08 to 0.1 as deep amber, 0.03 nearly black. Unset is clear. `base` on a transmissive material tints only its surface; the
|
|
285
|
+
body's colour is `attenuationColor` (the validator says so when a liquid has a `color`).
|
|
286
|
+
- A liquid in its glass: give the liquid `priority` 2 and the glass 1, and let the liquid touch or slightly overlap the inner wall
|
|
287
|
+
(a millimetre into it): where the two overlap, the higher priority is what is there, so no air film appears between them. A liquid
|
|
288
|
+
that stops short of the wall shows a bright rim of air.
|
|
289
|
+
- Glass, water and ice that nest get 4 passes through surfaces free of `bounces` (above), so a drink or a bottle is right at the default;
|
|
290
|
+
raise `bounces` for deeper stacks (a glass behind a glass behind a bottle), and `spp` to 128 or more for a glass close-up.
|
|
291
|
+
- `dispersion` (0.1 to 1) splits white light into colours in Final (crystal, prisms, gems): it is 20 divided by the material's Abbe
|
|
292
|
+
number (glTF's KHR_materials_dispersion), so crown glass is 0.34, flint glass 0.5 to 0.6, diamond 0.36 (`ior` 2.42), sapphire 0.28.
|
|
293
|
+
Final traces it spectrally: every path that meets such a surface takes one wavelength between 360 and 830 nm, bends by that
|
|
294
|
+
wavelength's index and carries that wavelength's colour, so a prism shows a continuous spectrum and a diamond its fire; the colours
|
|
295
|
+
average back to the light's own (white light stays white where nothing splits it). The colours are noise until enough wavelengths are
|
|
296
|
+
drawn: give a gem close-up 512 to 2048 `spp`. Draft shows the glass without the split. Light focused through glass onto the set
|
|
297
|
+
(caustics) turns on by itself in Final where it shows; `scene.caustics: false` turns it off. It works with every camera: perspective,
|
|
298
|
+
orthographic and tilt-shift. A caustic seen through glass shows too: the bright spot a dew drop focuses on the petal under it, seen
|
|
299
|
+
through the drop; a glass's caustic on the table, seen through the glass (a photon map read along the camera's own rays through the
|
|
300
|
+
glass, a pixel wide). The photons start on the glass itself, most where the camera sees the glass big (near and in view), so the
|
|
301
|
+
drops in focus get theirs even beside a meadow of dew far behind. A caustic far out of focus (dew throwing the sun onto the blurred background of a macro shot) is a soft
|
|
302
|
+
blur, not a haze of bright specks. Light a drop focuses on the sunny side of a petal or leaf shows through the sheet to the other
|
|
303
|
+
side (its translucency). An HDRI with a sun in it (a small, very bright patch, as a clear-sky map has) throws its caustics too, as a
|
|
304
|
+
sun light does. Its light adds to a sun light set the same way: the two together are two suns' worth (a clear-sky map at 0.6 sends
|
|
305
|
+
about as much from its sun as a sun light of 3.5). A close-up whose drops or glass catch a sun says `"caustics": true` so the pass, not the probe,
|
|
306
|
+
decides. With caustics on and a lens with an aperture (`fStop`), the sun seen in or through a drop or glass far out of focus (the
|
|
307
|
+
sparkle of backlit dew, a sunlit glass rim behind the subject) is drawn as the soft bokeh disc it is, smooth at the Final's samples, not
|
|
308
|
+
a scatter of specks (a round aperture, no `blades`, no `anamorphic`, a camera that does not move under the shutter; a tilt-shift or
|
|
309
|
+
orthographic camera keeps the specks). Such discs are real light: a Final's `clamp` no longer takes them.
|
|
310
|
+
Smooth glass and water (transmission over 0.5, roughness under 0.1) have a bounce budget of their own (24 hits through or off them)
|
|
311
|
+
beside `bounces`, so light caught inside a drop by total internal reflection stays (before, a white floor with dew read up to a third
|
|
312
|
+
darker inside the drops at `bounces` 12). A surface under water or inside glass (a petal under a drop, a stone in a glass of
|
|
313
|
+
water) has its gloss against that water, not air: much less glossy, as a wet petal under a drop is. A translucent leaf or petal under a drop, lit
|
|
314
|
+
from behind, glows through the drop about as brightly as the bare petal beside it (as a backlit petal with dew does), and a drop made by
|
|
315
|
+
the `drops` op (a cap open at its foot, `thinWalled: false`) is water closed by the surface it sits on: through that surface is air.
|
|
316
|
+
What the camera sees through or in clear glass is direct light to `clamp`; light that a drop
|
|
317
|
+
focuses onto the surface under it is a caustic, which `clamp` takes: dew lit by a small bright panel beside the lens (a catch light,
|
|
318
|
+
as macro photographers use) glows inside each drop only with `clamp` off (at `clamp: 6` under half of that glow stays and the drops
|
|
319
|
+
look flat). Leave `clamp` off for dew and glass close-ups.
|
|
320
|
+
- Final traces all of this for real. Draft shows glass see-through and bent, tinted by `attenuationColor` over its depth, and no
|
|
321
|
+
caustics. A liquid in its glass, ice in a drink: Draft draws what is held first (a transmissive object whose middle lies inside a
|
|
322
|
+
bigger one's box) and the glass then shows it through its walls (the walls bend the view as sheets), so a perfume shows its amber and
|
|
323
|
+
its level in Draft too; the way the light bends at the liquid's own surface is Final's. A glTF model's own glass (a file's
|
|
324
|
+
transmissive material) is drawn by the same Draft glass as the scene's (a closed glass ball in a file turns the view over in Draft too).
|
|
325
|
+
Judge glass and liquids in Final (`render-still` with `"mode": "final"`).
|
|
326
|
+
- Window glass is `"pane": true`, not `transmission`: thin, flat, clear glass in a frame (`{ "pane": true }`, only `ior` [1.52] to
|
|
327
|
+
set). In Final every ray goes through it unbent, less what its two faces reflect (Fresnel: about 8 % head on, more at a slant): the
|
|
328
|
+
sky's and the sun's light come into the room through it (no caustic specks, no dark room), a room's window portals stay open behind
|
|
329
|
+
it, and it reflects the room faintly over the view. Draft draws it as clear glass. Give it to the `room` op's `glass` part (a 6 mm
|
|
330
|
+
sheet in each frame): `{ "id": "glass", "material": "pane", "graph": [{ "op": "room", ..., "part": "glass" }] }`. A glass object
|
|
331
|
+
(a bottle, a tumbler) stays `transmission`.
|
|
332
|
+
|
|
333
|
+
#### Cloth (`fabric`)
|
|
334
|
+
|
|
335
|
+
```json
|
|
336
|
+
"materials": {
|
|
337
|
+
"sofa": { "graph": { "preset": "wornFabric", "color": "#b3b0aa" }, "fabric": { "weave": "basket", "threads": 300 } },
|
|
338
|
+
"throw": { "base": "#d8cdb9", "doubleSided": true, "fabric": { "weave": "knit", "threads": 85, "relief": 1.4 } },
|
|
339
|
+
"rug": { "graph": { "preset": "woolRug" }, "fabric": { "weave": "pile", "threads": 420 } }
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
- `fabric` gives a surface the threads' relief, the crevices between them and each thread's own shade, at a scale no texture bake can
|
|
344
|
+
hold, and a cloth's response: a soft sheen at grazing angles, a weak specular, fully rough (the material's own `sheen`, `specular`,
|
|
345
|
+
`roughness` win). Without it a sofa reads as grey clay or vinyl and a rug as a printed mat.
|
|
346
|
+
- `weave`: `plain` (linen, cotton), `twill` (diagonal: denim, upholstery), `basket` (two by two: woven upholstery), `knit` (V stitches
|
|
347
|
+
in columns: a throw, a jumper), `pile` (tufts: a wool rug, velvet, towelling). `threads` [300] per metre: fine linen 300 to 600,
|
|
348
|
+
upholstery 150 to 300, a chunky knit 60 to 120, a rug's pile 300 to 800. `relief` [1] 0 to 2, `contrast` [0.5] how dark the
|
|
349
|
+
crevices are, `variation` [0.5] how much the yarn's shade varies: a thread's shade drifts along its run a few crossings at a time,
|
|
350
|
+
soft heathered patches of a few threads, and the dye lot and the yarn's twist wander over a hand's width, none of it lined up with
|
|
351
|
+
the weave, so from across a room the cloth reads as an uneven woven texture, not a printed check.
|
|
352
|
+
- It follows the mesh's own uv in metres (every op's mesh has it; `uvBox` after ops that rebuild one). It goes over a texture graph
|
|
353
|
+
(whose bake keeps the wear, the grime and the colour) or a plain `base`; seen from afar the cloth keeps the material's colour.
|
|
354
|
+
- Final traces the threads at every sample, so they average over a pixel as a camera averages them: no texture, nothing to alias.
|
|
355
|
+
Draft draws the same threads and fades them to their mean where a thread is narrower than half a pixel (no shimmer, no moiré).
|
|
356
|
+
|
|
357
|
+
#### Glowing surfaces
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
"materials": {
|
|
361
|
+
"screen": { "base": "#000000", "emission": "#ffffff", "emissionStrength": 3, "maps": { "emission": "/media/…/ui.png" } },
|
|
362
|
+
"bulb": { "base": "#fff3e0", "emission": "#ffd9a0", "emissionStrength": 12 },
|
|
363
|
+
"neon": { "base": "#200810", "emission": "#ff2a6a", "emissionStrength": 8 }
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
- `emission` is the colour the surface gives off (black, the default, is none) and `emissionStrength` multiplies it. In Final a glowing
|
|
368
|
+
surface is a real light: it lights what is around it, and the strength sets how much. A monitor in a dark room is about 1 to 2 (a
|
|
369
|
+
night desk scene uses 1.2 for its screen and 2 for glowing mouse pads), a bulb or a neon tube that lights the room 8 to 15 (its bulb
|
|
370
|
+
is 12), a city picture seen through a window at night 0.3 to 0.5. Draft shows it glowing (with `rig.look.bloom`); of what glows, Draft
|
|
371
|
+
lights the set only from the four brightest small parts (under about 20 cm across, no picture: a bulb in a lampshade, so the shade
|
|
372
|
+
glows from inside), out to 15 times their radius (at least 40 cm) and without shadows, and not from a part shut in by an opaque object a few times its
|
|
373
|
+
size (a bulb in a metal lamp head, a pad under keys): give such a lamp a `spot` or `point` light for its Draft light. A light inside its
|
|
374
|
+
own bulb mesh lights only through what of it clears the bulb: a `point` there gives nothing (Draft and Final alike); a `spot` with a
|
|
375
|
+
`radius` is a disc in Final, so it lights the set from the part of its disc outside the bulb and the shade's opening, and Draft does the
|
|
376
|
+
same. Place the lamp in the bulb and give it a radius about the bulb's, or put it just outside the bulb, in the shade's opening.
|
|
377
|
+
- `emission` may be a colour temperature, `"2700K"`: a black body's colour at that many kelvin (a filament 2700, a candle flame 1900, a cool LED 4000 to 5000), with luminance 1, so `emissionStrength` still sets how bright.
|
|
378
|
+
- `maps.emission` is a picture that glows in its own colours (a screen's content): set `emission` to `#ffffff` so the picture is not
|
|
379
|
+
tinted, and `base` dark so the screen is black where the picture is.
|
|
380
|
+
- A small glowing object needs many samples to light a room without speckles; for a lamp, put a `point` light inside the bulb as well
|
|
381
|
+
and keep the bulb's own `emissionStrength` for how it looks.
|
|
382
|
+
- A lamp shade that glows from the bulb inside is `translucency` (below) with a `point` light inside, not emission.
|
|
383
|
+
|
|
384
|
+
### Procedural materials
|
|
385
|
+
|
|
386
|
+
A material can be a pattern instead of pictures. It is baked into tileable maps (colour, roughness, bump, and metal or glow where the pattern has them) that Draft and Final both read, so it costs nothing at render time:
|
|
387
|
+
|
|
388
|
+
```json
|
|
389
|
+
"materials": {
|
|
390
|
+
"mat": { "procedural": { "pattern": "grid", "scale": 4 } },
|
|
391
|
+
"floor": { "procedural": { "pattern": "wood", "planks": 6, "colors": ["#d6b48e", "#93673f"] }, "uvScale": [3, 3] },
|
|
392
|
+
"steel": { "procedural": { "pattern": "brushed", "direction": "u" } }
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
- `pattern`: `noise`, `marble`, `wood`, `grid` (a cutting mat), `tiles`, `bricks`, `checker`, `dots`, `brushed` (metal), `scratches`, `cells` (flagstones; negative `relief` is hammered metal), `terrazzo`, `weave` (fabric), `concrete`, `veins` (a petal's or a leaf's veins, [below](#petals-leaves-flowers-and-stems)). Each looks right with nothing else set.
|
|
397
|
+
- Shared: `colors` (a ramp: `'#hex'`, `[at, '#hex']`), `scale` (repeats per UV tile, made whole so it tiles), `roughness` (a number or `[min, max]`), `metalness` (a number, or `[main, accent]` for metal lines), `bump` [1], `seed`, `size` [512] (up to 2048 for close-ups), `emit` (the lines, grout or dots glow).
|
|
398
|
+
- Pattern params: `noise { octaves, warp }`, `marble { veins, warp }`, `wood { rings, planks }`, `grid { divisions [5] fine lines per major cell, minor [0.12] their strength from 0 to 1, width [1], groove [0] }` (`scale` is major cells per UV tile), `tiles { grout, stagger, variation }`, `bricks { aspect, mortar }`, `dots { radius, relief (-1 holes) }`, `brushed { direction 'u' | 'v' }`, `scratches { count, length }`, `cells { border, relief }`, `terrazzo { density, chipSize }`, `weave { style 'plain' | 'twill' | 'basket' }`, `concrete { pores, aggregate }`, `veins { kind 'petal' | 'leaf', count, fork, width, wander, vary, contrast, bleed, net, along, blotch, angle, aspect, wear }`.
|
|
399
|
+
- `wood` runs along u: the grain and each board are long in u, and `planks` stacks that many boards across v (`rings` growth rings across a board). So lay u along the length of a board, a shelf or a table top; `uvRotation: 90` on the material turns it. `brushed` with `direction: "u"` brushes along u.
|
|
400
|
+
- The pattern follows the mesh's UVs: give solids `uvBox` (or `uvPlanar`, `uvCylinder`) after any op that rebuilds them. `uvScale` repeats the tile. `base` multiplies the pattern's colours, so leave it out. A map in `maps` wins over the pattern's own.
|
|
401
|
+
|
|
402
|
+
### Texture graphs: smart materials with wear and dirt (`graph`)
|
|
403
|
+
|
|
404
|
+
A material can be a chain of nodes (Houdini Copernicus, Substance) whose outputs are maps: colour, roughness, metalness, height (made into the normal), emission, opacity. The graph is baked once on the GPU into ordinary textures that Draft and Final both read, byte for byte, so it costs nothing at render time. No pictures are downloaded. Start from a preset and set its numbers:
|
|
405
|
+
|
|
406
|
+
```json
|
|
407
|
+
"materials": {
|
|
408
|
+
"floor": { "graph": { "preset": "wornPlanks", "boards": 6.5, "wear": 0.6, "dirt": 0.5, "size": 4096 } },
|
|
409
|
+
"wall": { "graph": { "preset": "paintedPlaster", "color": "#dcd6ca", "dirt": 0.6, "floor": 0, "size": 2048 } },
|
|
410
|
+
"tin": { "graph": { "preset": "rustyMetal", "rust": 0.3, "keys": { "rust": [{ "t": 0, "v": 0.1 }, { "t": 4, "v": 0.8 }] } } }
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Presets (every number keyable through `keys`, as an object's fields are):
|
|
415
|
+
|
|
416
|
+
- `paintedPlaster` { color ["#e2ddd2"], roughness [0.85], relief [1], trowel [0.6], clouds [0.5], dirt [0.85], dirtHeight [0.35], corners [0.5], dirtColor ["#75685a"], floor [0], seed [0] }: Painted plaster wall: trowel strokes under the paint that catch a grazing light, tone clouds a few percent apart over metres, sand and a roller stipple in the paint, grime in the band above the floor and in the corners and behind furniture.
|
|
417
|
+
- `wornPlanks` { colors [["#c6a47e","#ab8862","#8c6b4b","#6c4f36","#4c3624"]], boards [6.5], length [1.4], variation [0.6], gloss [0.34], wear [0.5], dirt [0.7], seam ["#2b1d13"], seed [0] }: Worn plank floor: boards of random length, each its own piece of oak and its own tone, fine seams, a satin finish worn dull where people walk, dirt along walls, in the seams and around furniture legs.
|
|
418
|
+
- `wornFabric` { color ["#56677a"], threads [240], style ["twill"], wear [0.5], edgeWidth [0.012], pilling [0.5], dirt [0.35], seed [0] }: Upholstery fabric: a fine real weave with heathered threads; worn on the raised edges and where people sit, the thread tops polished smoother and a little lighter with tiny pills, the weave still showing through; grime in the creases; a sheen like cloth.
|
|
419
|
+
- `rustyMetal` { color ["#8e9399"], rust [0.5], cavities [0.7], streaks [0.5], pitting [0.5], rubbed [0.5], colors [["#2a160b","#4b250f","#743914","#97501f","#b87a44"]], roughness [0.42], edgeWidth [0.008], floor [0], seed [0] }: Steel going to rust: dull brushed steel; rust starts where water sits (cavities, inner corners, faces that look up, the foot near the floor) and creeps out from there in broken patches, flaky and pitted, with stains running down below it; edges rubbed back to bright steel in places.
|
|
420
|
+
- `scratchedPlastic` { color ["#c8392b"], roughness [0.3], scratches [0.6], edgeWear [0.45], edgeWidth [0.004], dirt [0.3], seed [0] }: Moulded plastic in use: a slight texture in the gloss; hairline scratches, straight, in two crossing strokes, many short and a few long, gathered where it is handled, seen as rougher lines and faint grooves in the gloss rather than in colour; the very edges rubbed duller; grime in the cavities.
|
|
421
|
+
- `stainedConcrete` { color ["#9c988f"], stains [0.55], pores [0.6], formwork [0.6], clouds [0.5], dust [0.3], dirt [0.45], floor [0], seed [0] }: Cast concrete: tone clouds over metres and panel to panel, the formwork's joint lines and its tie holes, sand, air pockets of every size, dark water stains running down from the top, dust settled on top faces, grime at the foot and in corners.
|
|
422
|
+
- `leather` { color ["#5a311c"], grain [1], wear [0.45], edgeWidth [0.005], roughness [0.48], seed [0] }: Leather: a fine pebbled grain and soft creases, a slight tone drift, burnished lighter and smoother on the edges and where it is handled.
|
|
423
|
+
- `lacqueredWood` { colors [["#8f6646","#775238","#5f402b","#47301f","#2f1f14"]], rings [22], width [6], cut ["solid"], axis ["auto"], along ["u"], figure [1.2], wear [0.3], edgeWidth [0.004], gloss [0.05], seed [0] }: Lacquered hardwood furniture: fine grain with pores under a clear glossy coat, cut from a solid log (rings on the end faces, long grain on the sides, the same piece of wood all round), the lacquer rubbed through on the edges.
|
|
424
|
+
- `oakBoards` { colors [["#e6d2b0","#d8bf98","#c6a77e","#ae8d63","#8f714c"]], boards [5], length [2.2], variation [0.4], gloss [0.46], wear [0.25], dirt [0.45], seam ["#5a4630"], seed [0] }: Pale oak boards, white-oiled: long boards each its own piece and tone, fine seams, a matte oil finish, a little wear where people walk and dirt along walls and around legs.
|
|
425
|
+
- `walnutBoards` { colors [["#7a5238","#64412b","#503221","#3d2518","#2b1a10"]], boards [6], length [1.6], variation [0.55], gloss [0.34], wear [0.2], dirt [0.3], seam ["#21150d"], seed [0] }: Walnut boards: dark, purple-brown and wild-grained, a satin oil finish, fine seams.
|
|
426
|
+
- `parquet` { colors [["#d9bc92","#c9a676","#b38c5c","#977148","#795734"]], width [0.07], ratio [5], variation [0.6], gloss [0.3], wear [0.3], dirt [0.4], seam ["#3b2a1a"], seed [0] }: Herringbone parquet: short oak blocks at right angles in a diagonal herringbone, each its own piece and tone, fine seams, a satin lacquer, dirt along walls and around legs.
|
|
427
|
+
- `ceramicTiles` { color ["#eeebe4"], grout ["#a19b91"], size [0.15], joint [0.003], variation [0.4], gloss [0.07], dirt [0.5], seed [0] }: Glazed ceramic tiles: square tiles each a shade apart and a touch out of level, a glossy glaze with a slight wave, grout lines darkened with dirt.
|
|
428
|
+
- `marble` { color ["#f1efea"], veins ["#8f8b84"], amount [0.6], scale [2.5], polish [0.06], seed [0] }: Polished marble: a white ground with soft grey clouds, a few strong veins that wander and branch, finer veins between them and hairlines, each fading at its ends; a mirror polish.
|
|
429
|
+
- `terrazzo` { base ["#e7e2d8"], chips [["#b6afa3","#5e5a54","#c9744f","#efe9dc","#7c8985","#2f2d2b"]], chipSize [0.014], density [0.55], polish [0.16], seed [0] }: Terrazzo: chips of stone in a pale cement, cut and polished flat; big and small chips, each its own colour.
|
|
430
|
+
- `linen` { color ["#ddd5c6"], threads [320], slub [0.6], seed [0] }: Linen: an open plain weave of uneven, slubby threads in a natural tone, each thread a shade apart; matte, with a soft sheen.
|
|
431
|
+
- `velvet` { color ["#3c4f5c"], crush [0.5], seed [0] }: Velvet: a dense pile that turns lighter where it lies the other way (crushed patches), deep in the folds, a strong soft sheen at grazing angles.
|
|
432
|
+
- `woolRug` { colors [["#ece6da","#3a3631"]], pattern ["diamonds"], size [0.22], line [0.08], pile [1], seed [0], hand [0] }: Wool rug: a dense tufted pile in two colours with a simple motif (diamonds, a hand-drawn diamond lattice, stripes or plain), tufts each a shade apart, soft and matte.
|
|
433
|
+
- `paper` { kind ["paper"], color [null], seed [0] }: Paper or cardboard: fibres in the sheet and specks, matte; cardboard brown with its corrugation showing faintly through.
|
|
434
|
+
- `rubber` { color ["#272727"], roughness [0.7], dust [0.3], seed [0] }: Rubber: dark, soft and satin-matte, a fine moulded grain, a little dust on the faces that look up.
|
|
435
|
+
- `brushedAluminium` { color ["#c9ccd0"], roughness [0.28], brush [1], seed [0] }: Brushed aluminium: fine straight brush lines that stretch the highlights across them, a soft satin sheen.
|
|
436
|
+
- `anodisedAluminium` { color ["#30405a"], roughness [0.36], wear [0.3], edgeWidth [0.002], seed [0] }: Anodised aluminium: a coloured metal with a fine bead-blasted satin finish, the colour a little deeper in the hollows and paler on worn edges.
|
|
437
|
+
- `chippedPaint` { color ["#3f6e69"], chips [0.5], rust [0.3], edgeWidth [0.006], roughness [0.45], seed [0] }: Painted metal, chipped: a satin paint coat knocked off on the edges and in small flakes, bare steel (rusting a little) in the chips, the coat a step thick at their rims.
|
|
438
|
+
- `glazedCeramic` { color ["#d9d3c7"], body ["#b9a58c"], pooling [0.6], speckle [0.35], gloss [0.06], edgeWidth [0.004], seed [0] }: Glazed ceramic (a pot, a mug): a glossy glaze that pools deeper in the hollows and thins to the body on the edges, fine iron specks, a slight wave.
|
|
439
|
+
- `frostedGlass` { frost [0.38], pattern ["plain"], band [0.04], tint ["#f4f7f6"], seed [0] }: Frosted glass: clear glass whose surface is etched matte (light passes, the view behind blurs); `stripes` leaves clear bands.
|
|
440
|
+
- `asphalt` { color ["#3b3b3b"], aggregate [0.6], cracks [0.3], wear [0.4], seed [0] }: Asphalt: grey stone aggregate set in black binder, the top worn paler where it is driven on, fine cracks.
|
|
441
|
+
- `edgeGlow` { color ["#4de3ff"], intensity [7], width [0.006], core [0.3], edges ["convex"], threshold [22], anim ["steady"], speed [1], axis ["x"], run [0.25], base ["#15171b"], roughness [0.32], metalness [0.3] }: Light along the edges of the shape, read from its curvature (not from the picture: the lines do not flicker as it turns), steady, pulsing, or a lit stretch running along an axis: neon edges on 3D text, a product, a wall. The material's emission: it shows in reflections and through glass, and lights the set in Final.
|
|
442
|
+
- `fractalNoise` { colors [["#5a1e0c","#d9743a","#f3b48a","#fff4ea"]], scale [14], octaves [5], gain [0.5], type ["plain"], contrast [1.7], brightness [0], evolution [0.35], driftX [0], driftY [0.02], driftZ [0], roughLow [0.6], roughHigh [0.22], metalness [0], emission [0], emissionFrom [0.62], seed [0] }: Fractal noise in the object's own 3D space, alive in time: it boils in place and can flow through the object, and never slides over the surface as the object moves. Colours from a ramp, roughness from the noise, and a glow from its bright end if asked (lava, plasma, smoke on glass, living stone).
|
|
443
|
+
- `motionBeam` { axis ["x"], width [0.22], soft [0.6], speed [0.4], position [null], trail [0.6], color1 ["#ffc93f"], color2 ["#2fd07a"], color3 ["#3f7bff"], intensity [6], mode ["glow"], tint [0.4], sheenGlow [0.15], glossRoughness [0.05], base ["#e9e6e1"], roughness [0.35], metalness [0] }: A band of light that travels along an axis of the object (Gradient Motion Beam): three colours head to tail, a fading trail, by speed or keyed by hand; as a glow, or as a sheen (the surface turns glossy under it). A glow lights the set in Final.
|
|
444
|
+
- `sweep` { angle [14], width [0.16], core [0.25], color ["#ffe2a4"], intensity [3.5], start [0.3], duration [1.4], gap [0.6], repeat ["loop"], easing ["sine"], progress [null], mode ["glow"], sheenGlow [0.15], glossRoughness [0.05], base ["#e2673f"], roughness [0.5], metalness [0] }: A bright band that sweeps across the object once or again and again (Gradient Sweep): timed by start, duration and gap, or keyed by hand; as a glow, or as a sheen (a glint of gloss crossing a product). A glow lights the set in Final.
|
|
445
|
+
|
|
446
|
+
- A preset brings plain fields where it needs them (lacquered wood a `coat`, fabric and leather `sheen`); the material's own fields win, and any other material field (`coat`, `sheen`, `transmission` …) works beside a graph. `base`, `roughness` and `metalness` on the material multiply the graph's maps; leave them out.
|
|
447
|
+
- Wear and dirt follow the object's shape, so such a graph bakes **per object**, on an atlas of the object's own (a second uv set made for it): edges are found from the mesh itself (a bevelled corner and a sharp one wear alike), cavities and nearby objects by rays against the whole scene as it stands at the scene's time, height and direction in the world. With wear and dirt at 0 a preset bakes once, **tiled** over the mesh's uv like a picture (repeated by `uvScale`), and every object wearing it shares it. A per-object bake never repeats: `"space": "object"` in `graph` asks for one without wear or dirt (a big floor with no visible tiling).
|
|
448
|
+
- Patterns are sized for a uv in metres: give solids `uvBox` (or `uvPlanar`, `uvCylinder`) at scale 1; `uvScale` multiplies. Plaster, concrete, rust, plastic and leather read the object's space from three sides when they bake per object, so they need no uv and show no seams; wood, planks and fabric follow the uv's u as the grain or the warp.
|
|
449
|
+
- `size` is the bake's width in texels, 256 to 4096. Leave it out and a per-object bake is sized for what the camera sees: a texel about one pixel of a 1080-line picture over nine tenths of what is seen of the object (over the shot, when the camera moves), so a wall far off gets 1024 and the same wall in a close-up 4096; an object the camera never sees gets 512; a tiled bake is 1024. Set `size` for a sharper close-up than that, or for a 4K render. Memory: a map is size² × 4 bytes and a third more for its mipmaps, three maps per bake (colour, roughness and metalness together, normal): 16 MB at 1024, 64 MB at 2048, 256 MB at 4096. The scene's maps share a budget, `textureBudget` in MB (256 when left out, next to `objects` on the Scene): the tiled bakes count in it, and past it the largest automatic per-object bake halves first, one step at a time, never below 512, so a close product shot keeps its 1:1 texels on the hero and gives up a little on the wall behind it (the texgraph product shot: 585 MB at the old sizes, 201 MB now; at 1080p the picture differs by under 1/255 on average, the plaster's finest trowel relief a little softer at 1:1). Sizes set by hand are never changed; raise `textureBudget` (or set `size`) for a 4K still. Objects with the same mesh and graph share one bake when the graph reads nothing of where they stand (no `ao`, `proximity`, `direction` or world `height`). Use sheets (`plane`, `grid`) for floors and walls whose back is never seen: a box spends half its atlas on its hidden faces.
|
|
450
|
+
- Bakes are kept by their numbers, like the geometry graph's nodes: changing one material bakes that one again. Wear and dirt are read where things stand when the scene is built (at its current time); objects that move in the shot carry their maps with them. A keyed number bakes again, in place, on every frame where its value changes (tens of milliseconds per object, about 80 at 2048 with wear and dirt); renders wait for it, so keep keyed graphs for things that change on screen.
|
|
451
|
+
- The atlas is made once per mesh: up to 2,000 points by xatlas (tens of milliseconds to half a second), past that a quick one with an island per side the faces look to (milliseconds at any size, a few more seams).
|
|
452
|
+
- Limits: instanced copies (`copyToPoints`), meshes with shape keys and meshes with translucency by group wear their graph tiled, with edges and cavities read as none; the still's `scene.warnings` says which. A GLB model keeps its own materials unless the object names a `material`, which each of its meshes then wears on an atlas of its own (skinned and morphing meshes tiled).
|
|
453
|
+
- `"inspect": true` on a still adds `scene.inspect.textureGraphs`: every bake kept, `{ material, object, space, size, bakeMs, atlasMs, mb }`, and the total `gpuMB`.
|
|
454
|
+
|
|
455
|
+
Your own graph: `nodes` is a list like a geometry graph's (each `{ "op", "id", ... }`, a node's main input is the node before unless given as `"#id"`), `out` names the maps:
|
|
456
|
+
|
|
457
|
+
```json
|
|
458
|
+
"stone": { "graph": { "size": 2048, "params": { "dark": 0.4 },
|
|
459
|
+
"nodes": [
|
|
460
|
+
{ "id": "cells", "op": "voronoi", "scale": 6 },
|
|
461
|
+
{ "id": "joint", "op": "math", "a": "#cells.g", "fn": "smoothstep", "low": 0, "high": 0.05 },
|
|
462
|
+
{ "id": "tone", "op": "gradientMap", "in": "#cells.b", "colors": ["#6b665e", "#a49d90"] },
|
|
463
|
+
{ "id": "edge", "op": "curvature", "width": 0.01 },
|
|
464
|
+
{ "id": "worn", "op": "blend", "a": "#tone", "b": "#edge", "mode": "screen", "opacity": 0.4 },
|
|
465
|
+
{ "id": "rough", "op": "math", "a": "#joint", "fn": "remap", "low": 0.95, "high": "$dark" }
|
|
466
|
+
],
|
|
467
|
+
"out": { "base": "#worn", "roughness": "#rough", "metalness": 0, "height": "#joint", "heightScale": 0.003 },
|
|
468
|
+
"keys": { "dark": [{ "t": 0, "v": 0.4 }, { "t": 2, "v": 0.8 }] } } }
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
- `out`: `base`, `roughness`, `metalness`, `height`, `emission`, `opacity`, each `"#id"` (or `"#id.g"` for one channel of a node), a number or a colour; `heightScale` is the relief in metres at height 1 [0.001], `emissionStrength` [1]. A number or colour bakes no map.
|
|
472
|
+
- `params` are numbers your nodes use as `"$name"`, and `keys` animate them (as an object's `keys`).
|
|
473
|
+
- `coord` on the graph or on a generator: `uv` (default), `triplanar` (object space from three sides, per-object bakes), `world` (world space from three sides: what runs with gravity, stains and drips, keeps running down on a turned object), `atlas`, or `at: "#planks"` to read the coordinates of a planks or tiles node (every board its own piece of wood).
|
|
474
|
+
- A node outputs four channels or one; `"#id.r"` … `"#id.a"` picks one. Unknown ops and fields are errors that name the right ones.
|
|
475
|
+
|
|
476
|
+
Nodes (params with defaults; `scale` is repeats per uv tile, made whole in a tiled bake so it tiles):
|
|
477
|
+
|
|
478
|
+
- `ao { radius [0.25], power [1] }`: how open the surface is within `radius` metres: 1 open, toward 0 in corners, under and between things (dirt collects there).
|
|
479
|
+
- `beam { axis [[1,0,0]], width [0.18], soft [0.6], speed [0.5], position, trail [0.5], c1 ["#ffc93f"], c2 ["#2fd07a"], c3 ["#3f7bff"] }`: a band of light that travels along an axis of the object (Gradient Motion Beam): rgb its colours (head, middle, tail), a how much; by `speed`, or keyed by hand with `position`.
|
|
480
|
+
- `blend { a, b, mask, mode ["mix"], opacity [1] }`: b over a by mask (or opacity): mix, multiply, add, screen, overlay, subtract, max, min, difference.
|
|
481
|
+
- `blur { in, radius [0.01] }`: a soft blur, `radius` as a share of the tile (wraps at the seams when tiled).
|
|
482
|
+
- `constant { value [1], color }`: one value or colour everywhere.
|
|
483
|
+
- `curvature { width [0.006], mode ["convex"], threshold [20] }`: edges of the object: 1 on a convex edge or corner, fading over `width` metres (worn paint, polished corners); concave for inner corners.
|
|
484
|
+
- `curve { in, points [[[0,0],[1,1]]] }`: a curve through up to 8 points [x, y], smooth between them.
|
|
485
|
+
- `direction { axis [[0,1,0]], from [0.3], to [1] }`: how much the surface faces `axis` (world): 1 facing it, 0 at `from` and below (dust on top: axis up, from 0.5).
|
|
486
|
+
- `edgeGlow { color ["#4de3ff"], width [0.006], core [0.3], threshold [22], edges ["convex"], anim ["steady"], speed [1], axis ["x"], run [0.25] }`: light along the edges of the shape (its curvature, not the picture's edges: steady as the object turns): rgb the glow's colour, a how much; steady, pulsing, or a lit stretch that runs along an axis.
|
|
487
|
+
- `fbm { scale [[4,4]], seed [0], coord ["uv"], octaves [6], gain [0.5], type ["plain"], warp [0], contrast [1] }`: fractal gradient noise, 0..1 around 0.5: plaster, stone, stains, any soft mottling.
|
|
488
|
+
- `fractal3d { scale [9], octaves [5], gain [0.5], type ["plain"], contrast [1.4], brightness [0], evolution [0.35], drift [[0,0,0]], seed [0] }`: fractal noise in the object's own 3D space, alive in time: it boils in place (`evolution`, time is its fourth axis) and can flow through the object (`drift`), never sliding over the surface as the object moves; 0..1 around 0.5.
|
|
489
|
+
- `gradient { kind ["u"], coord ["uv"] }`: a ramp across the tile: linear along u or v, radial or box from the centre (not periodic).
|
|
490
|
+
- `gradientMap { in, colors [["#000000","#ffffff"]] }`: colours from a value through a ramp (the value is the input's r).
|
|
491
|
+
- `height { from [0], to [0.3], space ["world"] }`: height in the world: 1 at `from` metres, 0 at `to` (a band of dirt above the floor: from 0, to 0.3).
|
|
492
|
+
- `heightToAO { in, radius [0.01], strength [4] }`: cavities of a height map: 1 open, darker where the height sits below its surroundings.
|
|
493
|
+
- `herringbone { scale [[8,8]], seed [0], coord ["uv"], ratio [5], gap [0.03], bevel [0.05] }`: herringbone parquet: boards at right angles, the pattern turned 45 degrees. r = height (1 on a board, down to 0 in the seam), g = a random per board, b and a = coordinates on the board (along it in board widths, across 0..1): feed them to `at` of wood so every board is its own piece. Per-object bakes (it does not wrap).
|
|
494
|
+
- `image { src [""], scale [[1,1]], coord ["uv"] }`: a picture (a media url, `tex:<name>` or a data: url): its colour in linear light, alpha in a, repeated `scale` times per uv tile.
|
|
495
|
+
- `levels { in, inLow [0], inHigh [1], gamma [1], outLow [0], outHigh [1] }`: levels: inLow..inHigh to outLow..outHigh with a gamma.
|
|
496
|
+
- `math { a, b, fn ["add"], value [1], low [0], high [1] }`: arithmetic in `fn` on a and b (b may be the number `value`): add, subtract, multiply, divide, min, max, power, invert (1 - a), abs, clamp (low..high), remap (0..1 to low..high), step (1 where a >= b), smoothstep (low..high; high below low falls instead of rising), mix (a to b by `value`).
|
|
497
|
+
- `pattern { name ["noise"], output ["color"], scale [[1,1]], coord ["uv"] }`: one of the 14 procedural patterns (wood, marble, tiles, bricks, weave, concrete ...), baked on the CPU as the materials' `procedural` and read here: `output` picks colour (linear rgb), height, roughness or the accent mask.
|
|
498
|
+
- `planks { count [6], length [0.5], lengthJitter [0.6], gap [0.012], bevel [0.06], seed [0], coord ["uv"] }`: boards: r = height (1 on a board, down to 0 in the seam), g = a random per board, b and a = the coordinates on the board (along it in board widths, across it 0..1); feed b, a to `at` of wood or noise so every board is its own piece.
|
|
499
|
+
- `position { }`: the object-space position (metres) in rgb, for patterns of your own through math.
|
|
500
|
+
- `proximity { radius [0.2], power [1] }`: how close other objects are: 1 touching, 0 beyond `radius` metres (dirt on a floor around furniture legs).
|
|
501
|
+
- `scratches { scale [[6,6]], seed [0], coord ["uv"], count [3], length [0.8], width [0.004], angle [20], directions [1], turn [70], spread [10], curve [0] }`: thin scratches as grooves: the depth of the deepest scratch here, 0 elsewhere; straight, along a few preferred directions, many short and a few long, each its own depth. Feed roughness and height with it, colour barely.
|
|
502
|
+
- `shape { scale [[1,1]], seed [0], coord ["uv"], kind ["circle"], size [[0.35,0.35]], softness [0.01], thickness [0.05], jitter [0] }`: a shape by its signed distance, repeated per cell: 1 inside, 0 outside, soft at `softness`.
|
|
503
|
+
- `slopeBlur { in, length [0.08], dir [[0,1]] }`: smears `in` downward along a direction in uv (drips, streaks); tiled bakes only.
|
|
504
|
+
- `sweep { angle [14], width [0.16], core [0.25], color ["#ffe2a4"], start [0.3], duration [1.4], gap [0.6], loop [true], easing ["sine"], progress }`: a bright band that sweeps across the object once or again and again (Gradient Sweep): rgb its light (core toward white), a the band (for a sheen: glossy under it); timed, or keyed by hand with `progress`.
|
|
505
|
+
- `tileRandom { in, min [0], max [1] }`: a value per board or tile, from the g of planks or tiles, between `min` and `max`.
|
|
506
|
+
- `tiles { count [[4,4]], stagger [0], gap [0.04], bevel [0.05], seed [0], coord ["uv"], offset [[0,0]] }`: tiles or bricks: r = height (1 on a tile, 0 in the joint), g = a random per tile, b and a = coordinates on the tile 0..1.
|
|
507
|
+
- `voronoi { scale [[4,4]], seed [0], coord ["uv"], jitter [0.9] }`: cells: r = distance to the cell centre, g = distance to the nearest border (crisp edges), b = a random per cell, a = the second distance.
|
|
508
|
+
- `warp { in, by, amount [0.02] }`: reads `in` displaced by the r and g of `by` (0.5 = no move), `amount` of a tile; tiled bakes only.
|
|
509
|
+
- `weave { scale [[48,48]], seed [0], coord ["uv"], style ["plain"], gap [0.12], fuzz [0.5] }`: woven threads: r = height of the thread on top, g = which thread is on top (0 warp, 1 weft), b = fibre fuzz, a = a random per thread.
|
|
510
|
+
- `wood { scale [[1,1]], seed [0], coord ["uv"], rings [22], figure [1], grain [0.6], pores [0.5], along ["u"], solid [false], axis ["auto"] }`: wood grain: r = ring value (0 light earlywood, 1 dark latewood), g = fine streaks along the grain (0..1 around 0.5), b = open pores, a = figure; grain runs along u. Read it on boards with `at` (every board its own piece), or on an object by its uv.
|
|
511
|
+
|
|
512
|
+
### Animated materials: edge glow, live noise, beam, sweep (graph presets)
|
|
513
|
+
|
|
514
|
+
Four texture-graph presets are alive in time: the material moves on the object as the shot plays. They are materials, not screen
|
|
515
|
+
effects: they lie on the object in its own space (the pattern turns and moves with it, it never slides over the surface), they show in
|
|
516
|
+
reflections and through glass, and in Final their glow lights the set (a glowing object is sampled as a light). They work on any mesh
|
|
517
|
+
object: 3D text (`text`), walls and panels, products, imported meshes. Each is baked on the GPU into the object's own maps on every
|
|
518
|
+
frame its numbers change, and Draft and Final read the same maps.
|
|
519
|
+
|
|
520
|
+
- `edgeGlow`: light along the edges of the shape, read from its curvature (dihedral angles, not the picture's edges: the lines do not
|
|
521
|
+
flicker as the object turns), `steady`, `pulse` or a lit stretch that `run`s along `axis`; `edges` convex, concave or both. A bevel's
|
|
522
|
+
small steps add up to the corner they round, so a bevelled letter glows like a sharp one; smooth curved surfaces stay dark below
|
|
523
|
+
`threshold` degrees.
|
|
524
|
+
- `fractalNoise`: fractal noise in the object's 3D space: `evolution` makes it boil in place (time is its fourth axis), `driftX/Y/Z` let it
|
|
525
|
+
flow through the object (metres a second, in the object's own space); colours from `colors`, roughness from `roughLow` to
|
|
526
|
+
`roughHigh`; `emission` above 0 makes its bright end glow (lava, plasma).
|
|
527
|
+
- `motionBeam`: a band that travels along the object's `axis` (Gradient Motion Beam): `color1` head, `color2`, `color3` tail, a fading
|
|
528
|
+
`trail`, `speed` passes a second, or keyed by hand with `position` (0 at the start of the object, 1 at its end). `tint` colours the
|
|
529
|
+
surface under it.
|
|
530
|
+
- `sweep`: a band sweeping across the object at `angle` (degrees in the object's own x-y plane), timed by `start`, `duration`, `gap` and
|
|
531
|
+
`repeat` (loop or once) with an `easing`, or keyed by hand with `progress` (0 before the object, 1 past it).
|
|
532
|
+
- `motionBeam` and `sweep` take `mode`: `glow` (the band emits) or `sheen` (the surface turns glossy under the band, `glossRoughness`, and
|
|
533
|
+
the band still glows by `sheenGlow` of `intensity`: a glint of light crossing a product).
|
|
534
|
+
- Every number keys through the graph's `keys`, as an object's fields do. The glow's strength (`intensity`, or `emission` for the noise)
|
|
535
|
+
is the material's emission strength: keying it bakes nothing. Colours do not interpolate between keys (they switch at each key).
|
|
536
|
+
- `hold` (seconds) keeps the material at that moment, keys included, while the shot runs on: an object that turns under a still pattern.
|
|
537
|
+
- In a video project the Scene item can key them as Rig tracks too: `propertyKeyframes["sc:g~<material>:<param>"]` (positions in % of
|
|
538
|
+
the clip, as every Rig track); the world takes the value in place and bakes again.
|
|
539
|
+
- The surface under the glow is the preset's `base`, `roughness` and `metalness` (the noise's colours are its own base); any other
|
|
540
|
+
material field (`coat`, `sheen` …) works beside it, and a `base` on the material itself wins over the preset's.
|
|
541
|
+
- The library has ready ones: `neonEdges`, `neonEdgesRun`, `neonEdgesPulse`, `lavaNoise`, `plasmaNoise`, `livingStone`, `beamGlow`,
|
|
542
|
+
`beamSheen`, `sweepGlow`, `sweepGlint` (`{ "preset": "neonEdgesRun" }` on a material; its `graph` fields go over the preset's).
|
|
543
|
+
|
|
544
|
+
A worked example: neon letters with a lit stretch running across them and a glow that fades up, a wall panel with a beam, and a product
|
|
545
|
+
with a gloss glint that crosses it twice. The floor is glossy, so all three show in it, and the glass pane in front of the word shows them
|
|
546
|
+
through it.
|
|
547
|
+
|
|
548
|
+
```json
|
|
549
|
+
{
|
|
550
|
+
"camera": { "at": [0.03, 0.22, 0.95], "target": [0, 0.12, 0], "fov": 34 },
|
|
551
|
+
"env": { "hdri": "studio", "intensity": 0.15, "background": "#0b0c0f" },
|
|
552
|
+
"lights": [{ "id": "key", "type": "sun", "dir": [-0.5, 0.75, 0.6], "intensity": 1.2 }],
|
|
553
|
+
"materials": {
|
|
554
|
+
"neon": { "graph": { "preset": "edgeGlow", "color": "#4de3ff", "width": 0.004, "anim": "run", "speed": 0.5, "axis": "x", "run": 0.35,
|
|
555
|
+
"keys": { "intensity": [{ "t": 0, "v": 0 }, { "t": 1, "v": 8 }] } } },
|
|
556
|
+
"panel": { "graph": { "preset": "motionBeam", "axis": "x", "width": 0.22, "speed": 0.4, "intensity": 6, "tint": 0.4 }, "coat": 0.3 },
|
|
557
|
+
"bottle": { "graph": { "preset": "sweep", "mode": "sheen", "angle": 62, "start": 0.3, "duration": 1, "gap": 0.5, "intensity": 4, "sheenGlow": 0.4, "base": "#c8392b", "roughness": 0.5 }, "coat": 0.3 },
|
|
558
|
+
"floor": { "base": "#0e0f12", "roughness": 0.1, "coat": 0.6 },
|
|
559
|
+
"glass": { "transmission": 1, "roughness": 0.02, "ior": 1.5, "thickness": 0.006 }
|
|
560
|
+
},
|
|
561
|
+
"objects": [
|
|
562
|
+
{ "id": "floor", "material": "floor", "graph": [{ "op": "plane", "size": [10, 10] }] },
|
|
563
|
+
{ "id": "word", "material": "neon", "at": [0, 0.02, 0.1], "graph": [{ "op": "text", "text": "GLOW", "size": 0.1, "depth": 0.04, "bevel": 0.004 }, { "op": "smooth", "angle": 35 }],
|
|
564
|
+
"keys": { "rot": [{ "t": 0, "v": [0, -25, 0], "ease": "linear" }, { "t": 4, "v": [0, 25, 0] }] } },
|
|
565
|
+
{ "id": "pane", "material": "glass", "at": [0.14, 0.09, 0.2], "rot": [0, -22, 0], "graph": [{ "op": "box", "size": [0.17, 0.2, 0.006] }] },
|
|
566
|
+
{ "id": "wall", "material": "panel", "at": [0, 0.22, -0.35], "graph": [{ "op": "box", "size": [0.9, 0.42, 0.03], "bevel": 0.004 }] },
|
|
567
|
+
{ "id": "product", "material": "bottle", "at": [-0.23, 0, 0.12], "graph": [{ "op": "lathe", "profile": [[0, 0], [0.046, 0], [0.052, 0.006], [0.052, 0.15], [0.03, 0.18], [0.017, 0.196], [0, 0.196]], "segments": 96 }, { "op": "smooth", "angle": 40 }] }
|
|
568
|
+
]
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
- Cost: an object bake on the object's own atlas (as wear and dirt), sized for what the camera sees but at most 1024 texels unless
|
|
573
|
+
`size` asks for more (a 4K close-up: `"size": 2048`); the surface it reads is made once and kept while the material plays, so a frame
|
|
574
|
+
bakes only the material's own passes, and only on frames where its numbers change (a steady edge glow, a still noise or a beam at
|
|
575
|
+
speed 0 bake once). Final copies only the changed maps into its atlas. A scene without these presets runs none of it.
|
|
576
|
+
`"inspect": true` on a still lists each bake with `animated`, `refreshMs` (the last frame's bake) and `surfaceMb` (what it keeps).
|
|
577
|
+
- Draft shows them on the object and through glass; in a glossy floor Draft shows what its reflections show of the scene, Final shows
|
|
578
|
+
them traced. A glow lights the set in Final only (Draft's lights are the scene's lights).
|
|
579
|
+
- On a GLB model, name the material on the object (`{ "id": "shoe", "model": "...", "material": "neon" }`): every mesh of the file
|
|
580
|
+
then wears it, baked on each mesh's own atlas (a model with no `material` keeps the file's own materials).
|
|
581
|
+
- Limits: instanced copies (`copyToPoints`), meshes with shape keys and skinned or morphing model meshes wear the graph tiled (over the
|
|
582
|
+
uv tile, no object space); the still's `scene.warnings` says which.
|
|
583
|
+
|
|
584
|
+
### Light through a sheet, light into a body: `translucency` and `subsurface`
|
|
585
|
+
|
|
586
|
+
```json
|
|
587
|
+
"materials": {
|
|
588
|
+
"shade": { "base": "#efe3cc", "roughness": 0.9, "translucency": 0.7, "doubleSided": true },
|
|
589
|
+
"wax": { "base": "#f2e7d3", "roughness": 0.35, "subsurface": 1, "subsurfaceRadius": [1, 0.85, 0.6], "subsurfaceScale": 0.03 }
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
- `translucency` (0 to 1) is for thin sheets: curtains, lampshades, paper, leaves. That share of the diffuse colour lets light through to the other side, in `translucencyColor` (default: `base`, with its map). Make the sheet `doubleSided`. A `point` light inside a translucent shade lights the shade and, in Final, the room through it; sun behind a curtain throws its colour on the floor. A sheet stops a light's beam and glows with it: it throws a shadow in Draft and Final alike, and another sheet in that shadow is lit by its glow, so light through two petals is a deeper colour, not black.
|
|
594
|
+
- `subsurface` (0 to 1) is for things light goes into: skin, wax, soap, marble, milk, jade. It is Blender's Subsurface Weight: `subsurfaceRadius` `[r, g, b]` is how far each colour travels, in metres before `subsurfaceScale` (defaults `[1, 0.2, 0.1]` and 0.05, as Blender), `subsurfaceAnisotropy` -0.9 to 0.9. The colour is `base`. Use a closed mesh; the radius must be small against the object (a few millimetres for a 10 cm thing) or it turns to jelly. Starting points: skin `[1, 0.35, 0.2]` × 0.02, wax `[1, 0.85, 0.6]` × 0.03, soap `[0.8, 1, 0.9]` × 0.012, marble `[1, 1, 1]` × 0.008.
|
|
595
|
+
- Final traces both for real (a random walk inside the mesh for subsurface). Draft approximates: light wraps past the shadow edge for subsurface, and a sheet glows from behind and casts a lighter shadow for translucency. A material has one or the other; with both, `subsurface` wins. A `.blend` import carries Principled Subsurface, and a Translucent BSDF mixed into a Principled at a set amount becomes `translucency`.
|
|
596
|
+
|
|
597
|
+
### Thin film, real metals, brushed metal, round edges: `iridescence`, `metal`, `anisotropy`, `roundEdges`
|
|
598
|
+
|
|
599
|
+
```json
|
|
600
|
+
"materials": {
|
|
601
|
+
"bubble": { "base": "#ffffff", "roughness": 0, "transmission": 1, "ior": 1, "iridescence": 1, "iridescenceThickness": 380 },
|
|
602
|
+
"oil": { "base": "#0e0e10", "roughness": 0.08, "iridescence": 1, "iridescenceIOR": 1.45, "iridescenceThickness": [250, 750] },
|
|
603
|
+
"cap": { "metal": "gold", "roughness": 0.18 },
|
|
604
|
+
"brushed": { "metal": "aluminium", "roughness": 0.18, "anisotropy": 0.8 },
|
|
605
|
+
"dial": { "metal": "aluminium", "roughness": 0.2, "anisotropy": 0.85, "brush": "spun" },
|
|
606
|
+
"part": { "base": "#2a4f8a", "roughness": 0.25, "roundEdges": 0.004 }
|
|
607
|
+
}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
- `iridescence` (0 to 1) is a thin film on the surface: soap, oil, coated glass, heat-tinted or coated metal. Its colour turns with the angle and with `iridescenceThickness` in nanometres (default 400; 200 to 800 shows colours, thicker turns pastel). `iridescenceIOR` is the film's own (default 1.33 soap water, 1.45 oil, 1.4 a lens coating). A pair `[min, max]` lays a soft swirl of thicknesses over the surface, so the colours run in bands (needs uvs). A soap bubble is `transmission: 1, ior: 1, roughness: 0, iridescence: 1` (both sides of a film are drawn by themselves, no `doubleSided` needed; it casts no shadow); a coated bottle is glass with `iridescence` 0.5 to 1. The rim of a bubble turns green, gold and magenta as in Cycles. In the editor, glass and bubbles in front of an empty, see-through background keep their reflections and rims when the layer is composited, in the preview, Draft and Final: what they reflect goes over the layers below as light.
|
|
611
|
+
- `metal` makes a real metal from its complex index of refraction: `gold`, `silver`, `copper`, `aluminium`, `chrome`, `iron`, `titanium`, or `{ "n": [r, g, b], "k": [r, g, b] }` for any other (Blender's Metallic BSDF Physical Conductor numbers work as they are). It sets `metalness` 1 and the colour, so leave `base` out; `roughness`, `coat`, `iridescence` and maps work as usual. Its edges keep the metal's own colour, which a `base` colour on `metalness: 1` cannot.
|
|
612
|
+
- `anisotropy` (0 to 1) is brushed metal: highlights stretch across the brush lines. `brush: "linear"` (default) runs the lines along `brushAxis` in the object's own space (default `[1, 0, 0]`); `brush: "spun"` lays them in circles around `brushAxis` (default `[0, 1, 0]`), the turned look of a watch dial, a pan base or a speaker cap, whose highlight is a streak through the middle. `anisotropyRotation` turns the lines (degrees). 0.6 to 0.9 with `roughness` 0.15 to 0.3 reads as brushed.
|
|
613
|
+
- `roundEdges` (metres) rounds a mesh's sharp edges at render time, in the shading only: CAD parts, boxes and extrusions catch a thin highlight along every edge as a product shot's bevelled ones do. 0.002 to 0.01 for objects of 10 to 30 cm; keep it under a third of the thinnest wall. Draft and Final both round them (Draft from the mesh's sharp edges worked out once when the scene builds, up to 200 000 triangles a mesh; past that Draft shows the edges sharp and `scene.warnings` says so), and only edges of the same object round; for a silhouette that is round too, model it with the `bevel` op. It costs Final time where such objects fill the frame (+50 to 70 % on a close product shot of such parts), so give it to the hero objects, not the room.
|
|
614
|
+
- A `.blend` import carries Principled Thin Film (thickness and IOR) and a Metallic BSDF set to Physical Conductor (its n and k, as `metal`).
|
|
615
|
+
|
|
616
|
+
### Car paint, dust and toon: `flakes`, `coatBump`, `dust`, `toon`
|
|
617
|
+
|
|
618
|
+
```json
|
|
619
|
+
"materials": {
|
|
620
|
+
"carRed": { "base": "#8c0d10", "coat": 1, "coatRoughness": 0.03, "flakes": { "amount": 0.7, "size": 0.15 }, "coatBump": 0.3 },
|
|
621
|
+
"dustyCrate": { "base": "#262a30", "roughness": 0.35, "dust": { "amount": 0.8 } },
|
|
622
|
+
"cel": { "base": "#ff7a1a", "toon": { "steps": 3, "outlineWidth": 3 } }
|
|
623
|
+
}
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
- Car paint is three layers: the paint (`base`), metallic `flakes` in it, and a clear coat (`coat`, `coatRoughness`) with its own relief
|
|
627
|
+
(`coatBump`, orange peel). `flakes`: a number 0 to 1 (how many and how bright) or `{ amount [0.6], size [0.15] mm, spread [18]
|
|
628
|
+
degrees each flake's tilt, seed }`; each flake glints on its own where the light catches it, so a highlight sparkles and a sparkle runs
|
|
629
|
+
across the body. Unset `metalness` becomes 0.35 + 0.6 × amount and `roughness` 0.32. `coatBump`: a number 0 to 1 or `{ amount [0.4],
|
|
630
|
+
scale [4] mm, seed }`: the coat's reflection wobbles softly while the paint under it keeps its own (0.2 to 0.4 a factory finish, 0.7 a
|
|
631
|
+
respray); it needs `coat`. Both follow the mesh's uv in metres (`uvBox` on solids) and are two small maps made on the spot (no download).
|
|
632
|
+
Final traces every flake, so the glitter averages over a pixel as a camera's does; Draft draws the same flakes (close up each flake,
|
|
633
|
+
further off the grain of many in a pixel, their spread widening the sheen), so a paint's glitter and highlight read in Draft as in
|
|
634
|
+
Final. `flakes` replaces `maps.normal`.
|
|
635
|
+
- `dust` settles on what faces up: a number 0 to 1 or `{ amount [0.5], color ["#c9c2b4"], up [0.5] (1 lets it reach down the sides),
|
|
636
|
+
seed }`: lighter, matte, in soft patches, thinner on steeper faces, following each object's shape. It makes the material a per-object
|
|
637
|
+
texture graph of its own `base`, `roughness` and `metalness` (a material with a `graph` keeps its preset's own dirt and dust), so it
|
|
638
|
+
costs a bake at build and nothing per frame. A `coat` stays glossy over it: lower `coat` on a dusty car.
|
|
639
|
+
- `toon` is cel shading for motion design: `true` or `{ steps [3] bands of light, shade [0.35] the darkest band as a share of the colour,
|
|
640
|
+
outline [true], outlineWidth [2] px, outlineColor ["#000000"] }`. The surface takes its light in hard bands of `base` and an outline
|
|
641
|
+
follows its silhouette and creases at a constant width on screen. Draft and Final draw it the same (cel shading is the raster's; in
|
|
642
|
+
Final the object still casts its traced shadow and bounces its colour onto the set). A light's shadow falls on it only on the side
|
|
643
|
+
facing that light, read 1 cm off its surface (its bands already draw where it turns from the light, down to `shade` on the far side;
|
|
644
|
+
its own shadow there laid stair-stepped dashes along the bands), and no ambient occlusion patches its bands. Other surface fields do not apply to it.
|
|
645
|
+
|
|
646
|
+
### The material library: `preset`
|
|
647
|
+
|
|
648
|
+
Over a hundred ready materials, made here (no download): `{ "preset": "<name>" }` on a material. Each is a set of the material's
|
|
649
|
+
own fields (metals by their real n and k, glass and gems with dispersion, liquids with their priority, car paints with flakes and orange
|
|
650
|
+
peel, the texture graphs' surfaces with their wear), and the material's own fields go over it: `{ "preset": "carPaintRed", "base": "#1e4d2b" }`
|
|
651
|
+
is a green car paint, `{ "preset": "marbleWhite", "graph": { "preset": "marble", "veins": "#6a5a4a" } }` a marble of other veins.
|
|
652
|
+
Solids that wear a pattern, a texture graph, flakes or cloth want a uv (`uvBox` after the ops). Patterns are at their real size (a marble's
|
|
653
|
+
veins some 40 cm apart, planks 15 cm wide): on a small object a pattern shows a piece of itself; its graph preset's own size fields change that (`{ "preset": "marbleWhite",
|
|
654
|
+
"graph": { "preset": "marble", "scale": 12 } }`: veins 12 a metre).
|
|
655
|
+
Coloured glass, stones and liquids take their colour by depth (`attenuationDistance`), set for the size they are used at (a bottle's wall
|
|
656
|
+
a few millimetres thick, a stone a centimetre across, a glass of wine): on a big solid object they go dark as the real thing would, so
|
|
657
|
+
raise `attenuationDistance` with the object (`{ "preset": "ruby", "attenuationDistance": 0.05 }` for a 10 cm ruby ornament).
|
|
658
|
+
|
|
659
|
+
- Metals: `goldPolished`, `goldSatin`, `goldBrushed`, `silverPolished`, `silverSatin`, `copperPolished`, `copperSatin`, `copperRough`, `aluminiumPolished`, `aluminiumSatin`, `aluminiumBrushed`, `aluminiumAnodisedBlue`, `aluminiumAnodisedRed`, `aluminiumAnodisedBlack`, `chromePolished`, `chromeSatin`, `ironRough`, `ironCast`, `steelBrushed`, `steelSpun`, `steelRusty`, `steelPaintedChipped`, `titaniumSatin`, `titaniumBrushed`, `brassPolished`, `bronzeSatin`, `hammeredMetal`.
|
|
660
|
+
- Plastics and rubber: `plasticGlossyWhite`, `plasticGlossyBlack`, `plasticGlossyRed`, `plasticGlossyYellow`, `plasticGlossyBlue`, `plasticMatteWhite`, `plasticMatteGrey`, `plasticMatteBlack`, `plasticSoftTouch`, `plasticScratched`, `plasticTranslucent`, `acrylicClear`, `acrylicFrosted`, `rubberBlack`, `rubberRed`.
|
|
661
|
+
- Glass and gems: `glassClear`, `glassFrosted`, `glassGreen`, `glassAmber`, `glassBlue`, `crystal`, `diamond`, `sapphire`, `ruby`, `emerald`, `ice`.
|
|
662
|
+
- Liquids: `water`, `perfume`, `whisky`, `redWine`, `oliveOil`, `soapBubble`.
|
|
663
|
+
- Paints and car paints: `carPaintRed`, `carPaintBlue`, `carPaintSilver`, `carPaintBlack`, `carPaintWhitePearl`, `carPaintGreen`, `carPaintOrange`, `carPaintMatteGrey`, `carPaintDusty`, `wallPaintMatte`, `wallPaintSatin`, `lacquerBlack`, `enamelWhite`.
|
|
664
|
+
- Wood: `oakBoards`, `walnutBoards`, `parquetHerringbone`, `plankFloorWorn`, `lacqueredWood`, `woodProcedural`.
|
|
665
|
+
- Stone, concrete, brick: `marbleWhite`, `marbleBlack`, `marbleGreen`, `terrazzo`, `concreteCast`, `concreteProcedural`, `granite`, `slate`, `bricks`, `asphalt`, `plaster`.
|
|
666
|
+
- Ceramic: `ceramicTiles`, `ceramicGlazed`, `porcelain`.
|
|
667
|
+
- Cloth, leather, paper: `linen`, `velvetBlue`, `velvetRed`, `upholsteryWorn`, `denim`, `knitWool`, `woolRug`, `leatherBrown`, `leatherBlack`, `paper`, `cardboard`.
|
|
668
|
+
- Skin, wax and other bodies light goes into: `skin`, `wax`, `soap`, `jade`, `leaf`.
|
|
669
|
+
- Glows: `neonPink`, `neonBlue`, `ledWhite`, `tungstenBulb`, `candleFlame`, `screenOff`.
|
|
670
|
+
- Toon: `toonOrange`, `toonTeal`, `toonViolet`, `toonWhite`.
|
|
671
|
+
- Animated (alive in time, see [animated materials](#animated-materials-edge-glow-live-noise-beam-sweep-graph-presets)): `neonEdges`, `neonEdgesRun`, `neonEdgesPulse`, `lavaNoise`, `plasmaNoise`, `livingStone`, `beamGlow`, `beamSheen`, `sweepGlow`, `sweepGlint`.
|
|
672
|
+
- Dusty: `dustyBlackPlastic`, `dustyChrome`, `dustyShelf`.
|
|
673
|
+
|
|
674
|
+
### Real relief from a height: `displacement`
|
|
675
|
+
|
|
676
|
+
```json
|
|
677
|
+
"materials": {
|
|
678
|
+
"wall": { "base": "#a65a3f", "roughness": 0.85, "displacement": { "height": "/media/…/bricks_height.png", "scale": 0.02, "midlevel": 0, "detail": 0.004 } },
|
|
679
|
+
"path": { "procedural": { "pattern": "cells", "relief": 1 }, "displacement": { "height": "pattern", "scale": 0.015 } }
|
|
680
|
+
}
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
- The mesh is cut into smaller triangles and every point moves along its normal by (height - `midlevel`) × `scale` metres, as Blender's
|
|
684
|
+
Displacement node with Displacement Only (and its Displace modifier) does: real geometry, so the silhouette, the shadows and the
|
|
685
|
+
contact with the floor are the relief's, the same in Draft and Final.
|
|
686
|
+
- `height`: a picture (a media URL or `tex:<name>`), read raw (white 1, black 0) over the mesh's uv with the material's `uvScale`,
|
|
687
|
+
`uvOffset` and `uvRotation`, as its maps are; or `"pattern"`, the material's own `procedural` pattern's relief. `scale` [0.01] metres at
|
|
688
|
+
height 1; `midlevel` [0.5] the height that stays put (0 pushes out only, as for bricks that stand out of their mortar).
|
|
689
|
+
- `detail` (metres) is the longest edge the mesh is cut down to [a 200th of its size]: a few millimetres for relief you look at closely.
|
|
690
|
+
Each halving makes 4 times the triangles; `maxTriangles` [400 000] caps a mesh (the detail then stops short and `scene.warnings`
|
|
691
|
+
says so), and a scene's displaced meshes together stay under 1 600 000. Points at one place (a uv seam, a box's edge) move together, so
|
|
692
|
+
the surface does not tear; a hard edge stays hard.
|
|
693
|
+
- The mesh needs uvs (every op's mesh has them; `uvBox` after ops that rebuild one). A normal map still adds its finer detail on top.
|
|
694
|
+
Cheaper relief that does not change the silhouette is a texture graph's `height` (a normal map).
|
|
695
|
+
|
|
696
|
+
### A surface that comes and goes: `reveal`
|
|
697
|
+
|
|
698
|
+
A material with `"reveal": { "map": "/media/…/reveal.png", "fps": 24 }` is there only between two frames, each texel its own: ink drawn on over a shot and wiped away later. A `.blend` import writes it from keyed material values (blender.md (GreenLight Dash only)). The map lies over the uv like the material's other maps (`uvScale`, `uvOffset`). Each texel's rgb holds two frames counted from the scene's time 0 at `fps`, twelve bits each: it comes on at `r * 16 + (g >> 4)` and goes at `(g & 15) * 256 + b`, and 4095 is never. Outside its frames a texel is not there at all: not drawn, no shadow, no depth, and no ray hits it in Final. When an imported surface also switches between two looks, each look is a material of its own (`<name> · early`, then `<name>`) on twin objects sharing one mesh, and their `reveal` maps take turns.
|
|
699
|
+
|
|
700
|
+
### Objects and graphs (Blender outside, Houdini inside)
|
|
701
|
+
|
|
702
|
+
`objects` is a tree (`parent`). Each object's geometry is its `graph`: an array of nodes. A node is `{ "op": "...", ...params }`
|
|
703
|
+
and may have an `"id"`. By default a node's input is the node before it, which is why a plain chain reads like a modifier
|
|
704
|
+
stack. `"in"` overrides that:
|
|
705
|
+
|
|
706
|
+
- `"in": "#a"` or `"in": ["#a", "#b"]`: other nodes of this graph, by id.
|
|
707
|
+
- `"in": "@desk"`: the output of another object, in that object's local space (Houdini's Object Merge).
|
|
708
|
+
|
|
709
|
+
The graph's output is its last node. A graph may be a single op (a source) or many.
|
|
710
|
+
|
|
711
|
+
Results are cached per node by a hash of `op + params + inputs`, so changing one parameter recomputes that node and the
|
|
712
|
+
ones after it, and nothing before. Ops never change their inputs and give the same result for the same `seed`.
|
|
713
|
+
|
|
714
|
+
`"bypass": true` on a node switches it off, and what fed it goes straight through. A graph the user edits in the editor is written back to these same fields, with every node given an `id` and an explicit `in`.
|
|
715
|
+
|
|
716
|
+
## Ops
|
|
717
|
+
|
|
718
|
+
Every line is `op { params }`: what it does. Defaults are in brackets; every param is optional unless marked **required**. Sizes
|
|
719
|
+
are metres, angles degrees. `size` may be a number or `[x, y, z]`. Sources made from a size (box, sphere, cylinder, cone, torus,
|
|
720
|
+
capsule, plane, grid) are centred on the origin; sources made from coordinates you give keep them (a `lathe` profile's y, the points of
|
|
721
|
+
`tube`, `ribbon`, `pointsOnCurve`, `sdf` and `skin`, an `extrude` outline's x and y, with its depth centred on z = 0), and `text`
|
|
722
|
+
stands on y = 0. A cylinder 0.08 tall therefore runs from y = −0.04 to 0.04: move it with `transform` or the object's `at`.
|
|
723
|
+
|
|
724
|
+
A node is `{ "op": "...", ...params, "id": "...", "in": ... }`. **Sources** (the first two groups) take no input, so a source in
|
|
725
|
+
the middle of a graph does not chain from the node above it: build the parts, then join them by id.
|
|
726
|
+
|
|
727
|
+
```json
|
|
728
|
+
[
|
|
729
|
+
{ "op": "box", "id": "body", "size": 1, "bevel": 0.05 },
|
|
730
|
+
{ "op": "cylinder", "id": "hole", "radiusTop": 0.2, "radiusBottom": 0.2, "height": 2 },
|
|
731
|
+
{ "op": "boolean", "in": ["#body", "#hole"], "mode": "subtract" },
|
|
732
|
+
{ "op": "smooth", "angle": 40 }
|
|
733
|
+
]
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Solids
|
|
737
|
+
|
|
738
|
+
- `box { size [1], segments [1], bevel [0], bevelSegments [4] }`: `size` is one number (a cube) or `[x, y, z]`, and so is `segments`. `bevel` is the rounding radius, real rounded edges and corners, too big is clamped. `bevelSegments` counts around a 90-degree edge and rounds up to even; 1 is a flat chamfer. Its own uvs are for patterns: a picture (`maps.base`) comes out upside down on its front and back and turned a quarter on the other four faces; for a picture use `decal`, `uvTriplanar`, or `uvPlanar` with the flips given there.
|
|
739
|
+
- `sphere { radius [0.5], segments [32], rings [16] }`.
|
|
740
|
+
- `cylinder { radiusTop [0.5], radiusBottom [0.5], height [1], radial [32], bevel [0], bevelSegments [4], caps [true] }`: `bevel` rounds both rims.
|
|
741
|
+
- `cone { radius [0.5], height [1], radial [32], bevel [0], bevelSegments [4] }`.
|
|
742
|
+
- `torus { radius [0.5], tube [0.15], radial [16], tubular [48] }`: lies flat around Y. `radial` goes round the tube, `tubular` round the ring.
|
|
743
|
+
- `capsule { radius [0.25], height [1], radial [24], rings [8] }`: `height` is the whole capsule, caps included.
|
|
744
|
+
- `lathe { profile **required**, segments [32], angle [35], closed [false], round [0], roundSegments [6] }`: spins `[[radius, y], ...]` around Y. Either drawing direction works. A profile starting and ending at radius 0 is a closed solid; `closed` joins the last point to the first (a ring). `angle` is the sharp-corner limit: a bend sharper than it is a crease. `round` (metres) turns every corner of the profile into an arc, so a bottle whose shoulder is drawn as two straight runs shades as one smooth surface instead of a crease and a flat band: give bottles, jars and caps `round` 0.003 to 0.01 (for 10 to 30 cm), or draw the profile with enough points.
|
|
745
|
+
- `extrude { polygon | shape | svg **required**, depth [0.1], bevel [0], bevelSegments [3], curveSegments [12] }`: pushes a 2D outline along Z. `depth` is the whole thickness, centred on z = 0. The bevel cuts into the outline, so the silhouette stays exact; keep it under half the thinnest stroke and under half the depth.
|
|
746
|
+
- `polygon`: `[[x, y], ...]`, with `holes: [[[x, y], ...], ...]`.
|
|
747
|
+
- `shape`: `{ outer, holes }`, `{ rect: [w, h], radius }` or `{ circle: r }`.
|
|
748
|
+
- `svg`: a path `d` string or a whole `<svg>`. M L H V C S Q T A Z, absolute and relative, holes from nesting. `size` fits the longer side to that many metres, `center` [true], `flipY` [true].
|
|
749
|
+
- `tube { path **required**, radius [0.02], radial [12], closed [false], tension [0.5], segments [auto], caps [true] }`: Blender's curve with bevel depth. `path` is `[[x, y, z], ...]`, a spline through those points. `tension` 0 is the straight polyline.
|
|
750
|
+
- `text { text **required**, size [0.2], depth [0.05], bevel [0], bevelSegments [3], curveSegments [6], align ['center'] }`: Droid Sans Bold. `size` is about the capital height. Letters stand on y = 0 and run along +X. `align` is left, center or right.
|
|
751
|
+
|
|
752
|
+
### Sheets and points
|
|
753
|
+
|
|
754
|
+
Sheets lie flat on XZ facing +Y, unlike three's upright plane. Point sources make points, not triangles.
|
|
755
|
+
|
|
756
|
+
- `plane { size [1], segments [1] }`: `size` and `segments` take a number or `[x, z]`. Its own uvs put a picture's top row toward +z, so a camera standing at +z sees it upside down; after `uvPlanar` with `axis: 'y'` it reads upright from there.
|
|
757
|
+
- `grid { size [1], segments [10], cols, rows }`: a plane with more cells.
|
|
758
|
+
- `pointsGrid { size [1], count | spacing [0.1], jitter [0], seed [0], y [0] }`: points on XZ with both edges included, x running first, row 0 at -Z. `count` is a number or `[x, z]`. `jitter` 1 moves a point up to half a cell.
|
|
759
|
+
- `pointsOnCurve { path **required**, count | spacing [0.1], closed [false], tension [0.5] }`: even spacing along a spline. N and orient follow the tangent, so `align: "normal"` lines +Y up with the path.
|
|
760
|
+
|
|
761
|
+
### Modifiers: one input, the node before unless `in` says otherwise
|
|
762
|
+
|
|
763
|
+
- `transform { at, rot, scale }`: moves mesh, points and instances together. T * R * S, Euler XYZ like three.
|
|
764
|
+
- `solidify { thickness [0.01], offset [-1], angle [30] }`: adds thickness. -1 keeps the input as the outside and grows inward, 1 grows outward, 0 splits it. A sheet comes back a closed slab.
|
|
765
|
+
- `smooth { angle [30], weight ['area-angle'] }`: recomputes normals, sharp above `angle`. This is Weighted Normal: big flat faces stay flat next to small bevels. `weight` is area-angle, area, angle or none. It changes shading only, never positions.
|
|
766
|
+
- `hair { count [2000], length [0.1], lengthJitter [0.25], width [0.002], segments [8], droop [0.25], curl [0.1], curlScale [0.5], clumps [0], clumpAmount [0.7], lean [0.3], seed [0], root ['#3a2a1e'], tip ['#8a6a4a'] }`: strands grown from the input mesh as real geometry, seen by raster and the tracer alike. `root` and `tip` colour each strand. `clumps` is how many guides they gather around, which is what makes hair read as hair. Stay under about 50,000 strands for a responsive Draft.
|
|
767
|
+
- `displace { amount [0.05], scale [1], seed [0], octaves [3], angle [60] }`: seeded 3D noise along the normals, up to `amount` either way. `scale` is noise frequency per metre. Subdivide first; it only moves the vertices that exist.
|
|
768
|
+
- `twist { axis ['y'], amount [90] }`: rotates slices around `axis`, -amount/2 at one end of the mesh to +amount/2 at the other.
|
|
769
|
+
- `bend { axis ['y'], amount [90], toward [next axis] }`: curls a mesh that runs along `axis` into an arc of `amount` degrees, keeping its length, turning towards `toward`. The middle stays put.
|
|
770
|
+
- `taper { axis ['y'], amount [-0.5] }`: scales across `axis`, unchanged at the low end and `1 + amount` at the high end. -1 is a point.
|
|
771
|
+
- `wireframe { thickness [0.02], radial [6], joints [true], quads [true] }`: every edge becomes a strut, with a ball on each joint. `thickness` is the strut's diameter. `quads` leaves out the diagonals of quads. The struts are separate closed shells that overlap, so `boolean` union them if a single skin matters.
|
|
772
|
+
- `array { count [2], offset [[1, 0, 0]], rotate [[0, 0, 0]], scale [1] }`: each copy is the last one moved by the same step, so offset + rotate makes a spiral. Real geometry: for thousands of copies use points and `copyToPoints`.
|
|
773
|
+
- `radialArray { count [6], axis ['y'], radius [0], angle [360] }`: copies spun around `axis`, each first pushed out by `radius` (along x for the y axis).
|
|
774
|
+
- `mirror { axis ['x'], weld [true] }`: reflects across the plane through the origin and keeps both sides. `weld` (true or a distance) closes the seam and removes faces lying in the plane. Model the half with +x.
|
|
775
|
+
- `subdivideLinear { levels [1] }`: each triangle becomes four and the surface does not move. No smoothing: this is for `displace` to have vertices to push.
|
|
776
|
+
- `decimate { ratio, error, angle [40] }`: fewer triangles. `ratio` is the fraction to keep; `error` caps surface movement as a fraction of the mesh's size. A closed solid stays closed, so a very low ratio stops above its target. Keeps uv seams.
|
|
777
|
+
- `uvBox { scale [1] }`: per-face projection along the dominant axis. uv unit = 1/scale metres. The easy default for hard surfaces and patterns (wood, stone, fabric). Each face is projected as `uvPlanar` does along the axis it faces: top and bottom u = +x, v = +z; front and back u = +x, v = +y; sides u = +z, v = +y. So a picture comes out upside down on the front and back and mirrored on one side of each pair: for pictures use `decal`, or `uvPlanar` with the flips below.
|
|
778
|
+
- `uvPlanar { axis ['z'], scale [1], fit [false], offset [0, 0] }`: flat projection. `fit` maps the bounds to 0..1, then `scale` (a number or `[u, v]`) and `offset` place that square. A picture's top row is at v = 0, and the axes run:
|
|
779
|
+
- `axis: 'y'`: u along +x, v along +z, so seen from above with +z toward you it reads upright. One cell of a picture atlas, such as a key's legend on a 10 × 10 sheet: `{ "axis": "y", "fit": true, "scale": 0.1, "offset": [col / 10, row / 10] }`.
|
|
780
|
+
- `axis: 'z'`: u along +x, v along +y, so a picture comes out UPSIDE DOWN seen from +z (the front). Stand it upright with `{ "axis": "z", "fit": true, "scale": [1, -1], "offset": [0, 1] }`.
|
|
781
|
+
- `axis: 'x'`: u along +z, v along +y, so seen from +x it is upside down AND mirrored: `{ "axis": "x", "fit": true, "scale": [-1, -1], "offset": [1, 1] }`; seen from -x, `"scale": [1, -1], "offset": [0, 1]`.
|
|
782
|
+
- A label on a bottle or a box is easier with `decal` (below): its uvs come out upright with no flipping.
|
|
783
|
+
- `uvCylinder { axis ['y'], scale [1], repeat [1] }`: u wraps around `axis` `repeat` times, v is height * scale.
|
|
784
|
+
- `uvUnwrap { }`: a real atlas with no overlaps, uvs in 0..1, for baking. 65535 distinct points at most. `unwrap` (below) is usually better: seams, pins, less stretch, a stretch report.
|
|
785
|
+
|
|
786
|
+
### Several inputs: set `in`
|
|
787
|
+
|
|
788
|
+
- `boolean { mode ['union'], cutMaterial }`, `in: ["#a", "#b", ...]`: union, subtract (the first minus all the others) or intersect. Every input must be a closed solid, so `solidify` a sheet first. Untouched surfaces keep their shading, uvs, materials and vertex groups; the cut is a hard edge and wears the cutter's material, or slot `cutMaterial`. Colours are dropped.
|
|
789
|
+
- `merge { }`, `in: [...]`: joins meshes, points and instances without cutting anything.
|
|
790
|
+
|
|
791
|
+
### Points to copies
|
|
792
|
+
|
|
793
|
+
- `scatter { count | density **required**, seed [0], minDistance [0], relax [0], slope, height, mask }`: random points on the input mesh, evenly by area, with N from the surface. Attributes: P N pscale orient Cd id, plus `uv`.
|
|
794
|
+
- `count` is a target; a surface that fills up under `minDistance` gives fewer. `density` is points per square metre, and a filter removes points in proportion.
|
|
795
|
+
- `relax`: each point is the best of 1 + 4 * relax candidates, spreading them more evenly. Try 1 to 3.
|
|
796
|
+
- `slope: [min, max]`: degrees from straight up. `height: [min, max]`: on y.
|
|
797
|
+
- `mask`: an expression string using P, N, uv, noise(x, y, z) and returning 0..1 (`"P[0] > 0 ? 1 : 0"`), a JS function (P, N, uv), or `{ texture: { data, width, height, channel } }`. Values are a probability.
|
|
798
|
+
- `attrib { expr **required**, seed [0] }`: a wrangle, run once per point. In scope: `P N Cd orient` (arrays to write into), `pscale` (assign to it), `id i count`, `rand(n)` (0..1, per point; a different n is a different number), `noise(x, y, z)` (-1..1), and `attr` for custom attributes (`attr.kind = rand(1) < 0.5 ? 0 : 1`). Math works and is seeded. fetch, document, window, globalThis, process, Date and eval are undefined. Changing N re-aims orient unless the expression also sets orient.
|
|
799
|
+
- `copyToPoints { align ['normal'], randomRotate, randomScale, pick ['random'], seed [0], sources }`: instances of meshes on points, one instances entry per source. Input is the points, then the sources: `in: ["#pts", "#rock", "#tree"]`, or `in: "#pts", sources: ["#rock", "#tree"]`. `align` is normal (+Y along orient) or up (upright). `randomRotate: [x, y, z]` is degrees either way. `randomScale: [a, b]` multiplies pscale. `pick` is random or `attr:<name>` (a custom attribute, floored, modulo the sources). Cd becomes instance colour: linear RGB, multiplying the material's `base` (see `script` for converting a hex colour).
|
|
800
|
+
- `instanceRealize { }`: bakes instances into one real mesh, with colours in the optional `mesh.color` (3 per vertex). Use it before a modifier or boolean.
|
|
801
|
+
|
|
802
|
+
Meshes, points and instances are different kinds of output. A modifier needs a mesh, and says so if it gets something else.
|
|
803
|
+
|
|
804
|
+
### Harder shapes
|
|
805
|
+
|
|
806
|
+
- `sdf { shapes **required**, blend [0.1], resolution [64], voxel }`: solids that melt into each other like clay. A source. Each shape is `{ type, at, rot, ... }`, where `rot` is degrees, as on objects:
|
|
807
|
+
- `sphere { radius }`, `box { size, round }`, `capsule { height, radius }`, `cylinder { radius, height, round }`, `torus { radius, tube }`;
|
|
808
|
+
- `stroke { path, radius }`: clay along a path, `[[x, y, z], ...]` or `[[x, y, z, radius], ...]` so it can swell and thin; `radius` may also be one number per point.
|
|
809
|
+
- `subtract: true` carves, and a shape's own `blend` overrides the op's. A shape's `material` (a slot) colours the part of the surface it makes, a carved hollow included. Raise `resolution` (cells across the longest side) or set `voxel` (cell size in metres) for detail; the cost is its cube.
|
|
810
|
+
- `skin { paths | points + edges, radius [0.05], blend [0.02], resolution [64], voxel, smooth [1] }`: a body around a skeleton, Blender's Skin modifier. A source. `paths` is a list of branches, each `[[x, y, z, radius], ...]`; a branch that starts on another's point grows out of it. Or `points` with `edges: [[i, j], ...]` and `radius` as one number or one per point. Each bone tapers from one radius to the next and the joints melt together by `blend`. Ends are round. Use it for limbs, stems, cables with a bulge, creatures.
|
|
811
|
+
- `softUnion { blend [0.1], resolution [48], voxel }` with `in`: any closed meshes melted into one. About a second at 64.
|
|
812
|
+
- `remesh { resolution [64] | voxel, smooth [0], uv [false] }`: Blender's voxel remesh. The mesh comes back as an even skin of small triangles from the volume it encloses: overlapping parts become one body, long thin triangles become even ones, and sharp edges round off by about a cell. It needs a closed solid. Materials, region names and vertex groups come along; uvs only with `uv: true` (seams kept), else project again after it (`uvBox`). Do this before `inflate`, `displace` or anything that needs even triangles.
|
|
813
|
+
- `relax { iterations [5], strength [0.5], keepVolume [true], boundary [false] }`: smooths the surface itself, Blender's Smooth modifier (`smooth` only changes shading). With `keepVolume` it softens without shrinking. Open edges stay put unless `boundary`.
|
|
814
|
+
- `subdivide { levels [1], sharp [0], box | sphere | mask }`: Blender's Subdivision Surface (Catmull-Clark). Triangulated quads are paired back first, so a box comes out round and even. `sharp` keeps edges sharper than that many degrees as hard creases (a box with `sharp: 30` keeps its outline and rounds nothing; use it with more `segments` for a soft box with crisp edges); picked points crease too. Each level is 4 times the triangles: stay at 2 or 3.
|
|
815
|
+
- `bevel { width [0.02], segments [3], angle [30], profile [0.5], clamp [true], box | sphere | mask }`: Blender's Bevel with the Angle limit, on any edges sharper than `angle`, which is what makes a product catch light on its edges. `width` is how far it cuts into each face (the radius on a right angle). `segments: 1` is a chamfer; `profile` 0.5 is round, 0.25 a straight cut, towards 1 sharper, towards 0 a cove. A pick limits it to edges with both ends picked. Corners where three bevels meet are rounded properly. The mesh must be manifold where it bevels. Textured? `uvBox` after it.
|
|
816
|
+
- `inflate { pressure [1.6], shrink [0], steps [90], stretch [0.0005], bend [0.02], pin, smooth [0] }`: blows a closed mesh up like a pillow, a cloth with air in it settled to rest: puffy keys, throw pillows, balloon letters. `pressure` is the volume it ends at, as a multiple of the start; flat sides bulge and edges pinch. `shrink` (up to 0.3) shrinks the cloth before the air goes in, so it ends taut. Needs even triangles: a `box` with `segments` 16 or more, or `remesh` first.
|
|
817
|
+
- **It makes a flat slab much taller, whatever the numbers.** Measured on a 0.6 × 0.16 × 0.6 m seat cushion: `bevel` → `remesh` → `inflate` came out 0.33 to 0.43 m tall (2.1 to 2.7 times) for every `pressure` from 1.05 to 1.6 and `shrink` from 0.05 to 0.14, with the footprint 3 to 12 % smaller; `segments` 16 and `shrink` 0 came out 0.28 m (1.7 times). A thinner start does not help: 0.065 and 0.1 m slabs came out 0.25 and 0.40 m tall, their footprint drawn in to 0.46 m. The air goes to the middle: the result is a lens, round on top and pinched at the edges. To keep that look but lower, follow it with `{ "op": "transform", "scale": [1, 0.45, 1] }`.
|
|
818
|
+
- **So not for upholstery.** Sofa seat and back cushions, mattresses and padded panels keep their size as a bevelled box: `{ "op": "box", "size": [0.6, 0.16, 0.6], "bevel": 0.03, "bevelSegments": 6 }`, or for a soft crown `{ "op": "box", "size": [0.6, 0.16, 0.6], "segments": 4, "bevel": 0.04 }` then `{ "op": "subdivide", "levels": 1 }`. A `weave` or `noise` pattern and `sheen` 0.3 make them read as fabric.
|
|
819
|
+
- **Puffy things:** smooth, taut pillows (throw pillows, lentil-shaped keys, a long space bar) are `bevel`, then `remesh`, then `inflate` with `shrink` 0.1 to 0.15; check the size it ends at with `inspect` and scale it after. Crinkled, mylar-like pillows with pinched corners are a `box` with `segments` 16 and `shrink` 0: the slack folds at the corners.
|
|
820
|
+
- Without `shrink`, slack cloth has to buckle somewhere: on a long, thin shape the middle sinks below its edges (a trough), and a remeshed shape crinkles all over.
|
|
821
|
+
Each shell gets its own air. `pin` (`box`, `sphere` or `mask`) holds points still. Normals come out smooth.
|
|
822
|
+
- `drape { steps [150], thickness [0.004], friction [0.6], floor, pin, gravity, stretch [0], bend [0.002], resolution [64] }` with `in: [cloth, collider, ...]`: the first input falls onto the rest and settles: a tablecloth, a throw over a chair, a sheet over a statue. The cloth needs vertices (`grid` with 48 to 96 segments). `floor` is a height it cannot pass. Inputs from `@object` arrive in that object's own space, so give the cloth the same placement or line them up with `transform`. The cloth does not collide with itself, and colliders thinner than two grid cells need a higher `resolution`.
|
|
823
|
+
- `project { direction [[0, -1, 0]], offset [0], from [0] }` with `in: [what, onto]`: lays a mesh on another, like shrinkwrap. Each point drops to the first surface along `direction`, and points that miss go, unless `keep: true`. `offset` keeps it clear of the surface and `from` starts the ray further back.
|
|
824
|
+
- `ribbon { path **required**, width [0.1], twist [0], taper [1], closed, tension, segments }`: a flat strip along a path. A source. Give its material `doubleSided: true`.
|
|
825
|
+
- `wrangle { code **required**, seed }`: runs on every point. `P`, `N` and `uv` are arrays to change in place, with `i`, `count` and `noise(x, y, z)` to hand: `"P[1] += noise(P[0] * 4, 0, P[2] * 4) * 0.1"`.
|
|
826
|
+
- `deletePoints { box | sphere | mask }`: takes points away, and every triangle using one. `box` is `{ min, max }`, `sphere` is `[x, y, z, radius]`, and `mask` is an expression over `P`, `N`, `uv` and `noise` that is above 0.5 for the points to go.
|
|
827
|
+
- `assign { material [1], name, box | sphere | mask | region | facing | group }`: gives picked triangles another material. Name them on the object: `"materials": ["paint", "chrome"]`, where the number is the place in that list. `name` makes the slot a named region that later nodes pick with `region` (a new name with no `material` takes the next free slot). Every op carries the slots on: ops that keep or split triangles exactly, and ops that build a new surface (`boolean`, `remesh`, `softUnion`, `decimate`, `wireframe`) by nearest surface. A slot past the object's `materials` list wears the object's own `material`.
|
|
828
|
+
|
|
829
|
+
### Editing a mesh, UVs and decals
|
|
830
|
+
|
|
831
|
+
Edits work on the faces of a mesh you already have, as nodes, so the whole history stays editable: change the box's size and the inset, the cut panel and the label all follow. Faces are the polygons the triangles came from (a box face is one quad). Untouched faces keep their uvs, materials and normals exactly, hand-set normals included; new faces shade smooth below `angle` [30].
|
|
832
|
+
|
|
833
|
+
**Picking faces.** Every edit takes the usual `box | sphere | mask` (a face is picked when all its points are) plus `region: "label" | 2 | [..]` (a named region or slot), `facing: [0, 1, 0]` or `{ "dir": [0, 1, 0], "angle": 30 }` (faces looking that way), `group: "top"` or `{ "name": "top", "min": 0.5 }` (faces whose points all weigh that much). Everything given must hold; `invert: true` flips it.
|
|
834
|
+
|
|
835
|
+
- `inset { thickness [0.01], depth [0], individual [false], name, material, sides, pick }`: a border `thickness` wide inside the picked region (each face its own with `individual`); `depth` moves the inside in (−) or out. `name` makes the inside a region (its own slot) for the next node; `sides` gives the border faces a slot.
|
|
836
|
+
- `extrudeFaces { distance [0.05], along ['region'], individual, name, material, sides, pick }`: moves the picked faces with walls joining them to where they were. `along`: `'region'` (the region's mean normal), `'normals'` (each point along its own, even thickness), or `[x, y, z]`. Negative pushes in: a recessed panel is `inset` with a `name`, then `extrudeFaces { region: name, distance: -0.003 }`.
|
|
837
|
+
- `loopCut { axis ['y'] | [x, y, z], cuts [1] | at }`: rings of new edges where planes across `axis` cross the surface, `cuts` spread evenly or at the offsets in `at`. Nothing moves; it gives the next pick a line to stop at.
|
|
838
|
+
- `bridge { segments [1], twist [0], material, name, pick }`: joins two open loops with a band. With a pick, the picked faces go first and the holes they leave are joined (two facing panels make a tunnel); without, the mesh's own two open loops. Unequal loops zip with triangles.
|
|
839
|
+
- `weld { distance [0.0001] }`: merges points closer than that, drops collapsed and doubled triangles. Closes cracks between parts.
|
|
840
|
+
- `fillHoles { sides [0], material }`: caps open loops of up to `sides` edges (0 any), flat in their own plane.
|
|
841
|
+
- `recalcNormals { angle [30], inside [false] }`: turns every face the same way as its neighbours and every part outward. For imported or scripted meshes that shade black in patches.
|
|
842
|
+
- `setNormals { mode ['smooth'], direction, center, axis, pick }`: hand-set normals on the picked faces (all if none): `smooth` (no hard edges), `flat`, `direction` (foliage cards facing up), `outward` from `center` (a soft bush), `cylinder` (away from the `axis` through `center`). Later ops keep them where the surface stays (moves, mirrors, booleans, unwraps, decals, edits elsewhere); ops that reshape it (`smooth`, `subdivide`, `bevel`, `remesh`) work them out again.
|
|
843
|
+
- `vertexGroup { name **required**, weight [1], mode ['set'], falloff, pick }`: a named weight per point, 0 to 1, stored as `mesh['group:<name>']` (a Float32Array per vertex). `box`/`sphere` give 1 inside (`falloff: 'linear' | 'smooth'` fades a sphere to its edge), a `mask` its own value (`"P[1] * 2"`), the face picks keep their points. `mode`: set, replace, add, subtract, max, multiply. Ops that take a `group` read it; groups ride through every op, interpolated on new points.
|
|
844
|
+
|
|
845
|
+
**UVs.**
|
|
846
|
+
|
|
847
|
+
- `seams { angle | pick, mode ['add'] }`: marks where `unwrap` must cut: edges sharper than `angle`, edges with both points in a `box`/`sphere`/`mask` (draw a seam with a thin box), or the border of faces picked by `region`/`facing`/`group`. `mode: 'clear'` unmarks. Mark them right before the unwrap.
|
|
848
|
+
- `pins { list: [{ at: [x, y, z], uv: [u, v] }] | pick }`: points `unwrap` must put at exact uvs (the mesh point nearest each `at`); a pick pins its points where their uvs are now. A piece with two or more pins is solved through them and not repacked. Four corners pinned to the picture's corners, with the picture's `aspect`, lay it exactly on a curved card.
|
|
849
|
+
- `unwrap { angle [66], bySlot [true], margin [0.005], tiles [1], aspect [1], maxStretch [1.25] }`: a conformal unwrap (least-squares conformal maps) with low stretch. It cuts at marked seams, edges sharper than `angle` and material borders, opens closed pieces and cone tips, splits any piece that would fold, overlap or stretch past `maxStretch`, gives every piece the same texel density and packs them into 0..1 with `margin` between (or across `tiles` UDIM tiles). Pictures read the right way round from outside (never mirrored); which way up a piece lies is the packer's choice, so pin it when that matters. `aspect` is the texture's width over its height: give it for a picture that is not square, or it lands squeezed. The result reports `mesh.uvStats`: `{ charts, l2, worst, angle, flipped, fill }`, where `l2` is texture stretch (1 is none; under 1.01 is invisible), `worst` the stretch 95 % of the area stays under, `flipped` folded triangles. Prefer it to `uvUnwrap`.
|
|
850
|
+
- `udim { material [0] }`: uvs in UDIM tile 1001 + col + 10 · row become slot `material` + that offset, with uvs back in 0..1, so each tile is an ordinary material with its own maps, the same in Draft and Final: `"materials": ["tile1001", "tile1002"]`. Regions are named `udim1001`, `udim1002`, ….
|
|
851
|
+
- `uvTriplanar { scale [1], offset }`: each face takes the picture from the side it faces most, in metres, all six sides the right way round (`uvBox` mirrors three). It switches sides at 45 degrees with no blend band; for one continuous map use `unwrap`.
|
|
852
|
+
|
|
853
|
+
**Decals: a label on a product.** `decal` cuts the mesh exactly along the label's edges, so the label's border is geometry (crisp in Final at any distance), and gives its faces uvs 0..1 across the label with the picture's top row at v = 0.
|
|
854
|
+
|
|
855
|
+
- `decal { projection ['box'], at, normal [[0, 0, 1]], up [[0, 1, 0]], size **required** [w, h], depth, angle [70], material, name ['decal'], mode ['region'], offset [0.0004], flip }`:
|
|
856
|
+
- `box`: `at` is the label's middle on the surface, `normal` the way it faces; it reaches `depth` [half the smaller side] either side of `at`. For a box face or a flat panel.
|
|
857
|
+
- `cylinder`: `axis` [[0, 1, 0]], `at` a point on the axis at the label's middle height, `normal` from the axis towards the label's middle; `size` is [width along the surface, height], so it wraps with no stretch; `radius` is measured when left out. For bottles, jars, cans and tubes.
|
|
858
|
+
- Faces turned more than `angle` away are left out, so a label never smears down a side.
|
|
859
|
+
- `mode: 'region'`: the label's faces become a region with their own slot, for an opaque label (paper, foil). Give that slot a material with the picture in `maps.base`: `"materials": ["glass", "label"]`.
|
|
860
|
+
- `mode: 'layer'`: a sheet `offset` above the surface for a picture with see-through parts (a logo); its material reads the picture's alpha with `"alphaFromBase": true`. The object stays whole underneath, but the sheet is open, so put a layer decal after any `boolean`.
|
|
861
|
+
- `shrinkwrap { mode ['nearest'], offset [0], direction, both, keep }`, `in: [what, onto]`: lays one mesh on another, each point to the nearest surface point taking its normal, or (`mode: 'project'`) along `direction` (`'normal'`: along each point's own normal). What finds nothing goes unless `keep`.
|
|
862
|
+
|
|
863
|
+
A box with a recessed panel and a label, every step editable:
|
|
864
|
+
|
|
865
|
+
```json
|
|
866
|
+
[
|
|
867
|
+
{ "op": "box", "id": "body", "size": [0.18, 0.24, 0.06], "bevel": 0.004 },
|
|
868
|
+
{ "op": "inset", "thickness": 0.012, "facing": { "dir": [0, 0, 1], "angle": 5 }, "name": "panel" },
|
|
869
|
+
{ "op": "extrudeFaces", "region": "panel", "distance": -0.002 },
|
|
870
|
+
{ "op": "decal", "at": [0, 0, 0.028], "normal": [0, 0, 1], "size": [0.12, 0.06], "depth": 0.004, "name": "label" }
|
|
871
|
+
]
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
with `"materials": ["paint", "paint", "paper"]` on the object (body, panel, label).
|
|
875
|
+
|
|
876
|
+
### Deforming, sculpting and organic shapes
|
|
877
|
+
|
|
878
|
+
**Vertex groups.** A group is a named weight per point, 0 to 1, kept on the mesh as `group:<name>`. Ops that only move points carry
|
|
879
|
+
groups on. The weight ops below write them. Every deformation takes `weights: "group:<name>"` (or a number) to scale its effect point by
|
|
880
|
+
point: 0 stays put, 1 is the full op. This works on `bend`, `twist`, `taper`, `displace`, `wrangle`, `relax`, `transform`, `lattice` and
|
|
881
|
+
`sculpt`. Without `weights` they behave as before. A name the mesh does not carry is an error that lists the groups it does carry.
|
|
882
|
+
Ops that rebuild the points (`subdivide`, `remesh`, `smooth`, `boolean`...) may drop groups, so make weights after them.
|
|
883
|
+
|
|
884
|
+
- Each weight op writes `group` ['weight'] and combines with a group of that name already there by `mode`: replace (default), add,
|
|
885
|
+
subtract, multiply, max or min. Shaping: `falloff` (linear, smooth, sharp, root), `ramp` (`[[t, w], ...]` or evenly spaced
|
|
886
|
+
`[w0, w1, ...]`) and `invert`.
|
|
887
|
+
- `weightGradient { axis ['y'], from, to | path }`: 0 at `from`, 1 at `to` (default: the mesh's two ends on that axis). With `path`, the
|
|
888
|
+
weight is the share of the way along it at the nearest point.
|
|
889
|
+
- `weightProximity { point | path, radius [0.25], inner [0], falloff ['smooth'] }`: 1 within `inner` of a point or a path, 0 from
|
|
890
|
+
`radius` out. Near another mesh: `in: ["#this", "@other"]`, measured to its surface.
|
|
891
|
+
- `weightNoise { scale [2], octaves [3], contrast [1], offset [0], seed }`: seeded noise around 0.5.
|
|
892
|
+
- `weightMask { mask | box | sphere, soft [0] }`: an expression over `P`, `N`, `uv`, `w` (the group so far) and `noise`, returning 0..1
|
|
893
|
+
(`"P[1] > 0.2 ? 1 : 0"`). Or a `box` / `sphere` with `soft` metres of fade at its edge.
|
|
894
|
+
- `weightSmooth { iterations [4], strength [0.5] }`: blurs a group over the surface.
|
|
895
|
+
|
|
896
|
+
**Lattice.** `lattice { divisions [[3, 3, 3]], box, points | moves, interpolation ['bezier'], weights, shapeKey, value [1] }` is a cage of
|
|
897
|
+
control points around the mesh (its bounds by default, or `box: { min, max }`). Moving the cage's points bends everything inside it
|
|
898
|
+
smoothly. This is free-form deformation, and points outside the box stay where they are.
|
|
899
|
+
- `divisions` is the number of control points per axis, 2 to 12. A point is `[i, j, k]` from the low corner.
|
|
900
|
+
- `moves: [{ at: [i, j, k], by: [dx, dy, dz] }]` moves a few points. `points` lists every point's move, x fastest, then y, then z.
|
|
901
|
+
- `interpolation: 'linear'` bends in straight pieces instead.
|
|
902
|
+
- `shapeKey: "name"` leaves the mesh as it is and makes the bend a shape key, so it plays on the timeline (see below) at weight `value`.
|
|
903
|
+
|
|
904
|
+
**Shape keys.** `shapeKeys { targets: [{ name, value [0], graph | input | frames }] }` keeps the input as the basis and adds named poses
|
|
905
|
+
of the same points.
|
|
906
|
+
- `graph` is a chain of ops run on the basis: `[{ "op": "bend", "amount": 40 }]`, a `lattice`, a `sculpt`, a `wrangle`. Inside it,
|
|
907
|
+
`"in": "@basis"` names the basis.
|
|
908
|
+
- `input: 1` is this node's second input (`in: ["#base", "#other"]`), which must have the same points.
|
|
909
|
+
- `frames: [{ at: 0.5, graph }, { at: 1, graph }]` gives in-between poses. A move between frames follows them (a turn stays round),
|
|
910
|
+
and past the last frame it carries on along the last step.
|
|
911
|
+
- The output shows each key at its `value`. On the timeline, the object's `"keys": { "shape:<name>": [{ "t": 0, "v": 0 }, { "t": 2, "v": 1 }] }`
|
|
912
|
+
plays it, and `"shapes": { "<name>": 0.4 }` on the object sets it without a track.
|
|
913
|
+
- A frame only mixes the poses into the mesh's own buffers. It never rebuilds the world: on a 100K-triangle mesh this costs about 2 ms
|
|
914
|
+
a frame. Final traces each pose, and keys blur in an export with motion blur on.
|
|
915
|
+
- Put `shapeKeys` near the end. Ops after it that only move points keep the keys, and `transform` turns them with the mesh. Ops that
|
|
916
|
+
rebuild points (`subdivide`, `remesh`, `boolean`...) drop them.
|
|
917
|
+
|
|
918
|
+
**Sculpt strokes.** `sculpt { strokes: [...], weights }` holds the strokes as data. They stay editable, and they run again on whatever
|
|
919
|
+
comes in after an upstream edit: a bigger sphere above them gets the same strokes on its own surface.
|
|
920
|
+
- A stroke is `{ brush, path: [[x, y, z], ...], radius [0.05], strength, falloff ['smooth'], symmetry, project ['surface'], spacing [0.25] }`.
|
|
921
|
+
The path is in the object's own space (world space for an object at the origin). One point is a single dab; a longer path drags the
|
|
922
|
+
brush, with a dab every `spacing` radii.
|
|
923
|
+
- Brushes:
|
|
924
|
+
- `draw` raises along the area's normal; a negative `strength` carves.
|
|
925
|
+
- `inflate` pushes each point along its own normal.
|
|
926
|
+
- `grab` carries what was under the path's start along the path; `snakeHook` takes hold again at every dab, pulling out a horn
|
|
927
|
+
or a tentacle.
|
|
928
|
+
- `smooth` relaxes the surface.
|
|
929
|
+
- `crease` cuts a sharp groove (`pinch` [0.5] pulls the sides in); `pinch` only pulls them in.
|
|
930
|
+
- `flatten` moves points onto the area's plane; `clay` builds up flat-topped layers.
|
|
931
|
+
- `falloff` is smooth, sphere, sharp, linear or constant.
|
|
932
|
+
- Aiming: by default each dab lands on the nearest surface. `project: [dx, dy, dz]` shoots it along that direction instead (from the
|
|
933
|
+
camera's side, e.g. `[0, 0, -1]` for a surface facing +z). `project: false` uses the path exactly.
|
|
934
|
+
- `symmetry: "x"` (or `"xz"`) mirrors the stroke across those planes through the origin.
|
|
935
|
+
- `backfaces: true` also moves the points facing away.
|
|
936
|
+
- Strokes move the points that exist, so give the mesh enough of them: about 8 or more across a dab's radius. `remesh` or `subdivide`
|
|
937
|
+
first, or a source with more `segments`.
|
|
938
|
+
|
|
939
|
+
**Petals, leaves, flowers and stems.** Sources for organic hero shapes, each a smooth sheet with clean uvs.
|
|
940
|
+
- `petal { length [0.5], width [0.3], outline ['tulip'], tip, tipShape, cup [70], curl [30], curlPower [1.6], flare [0], twist [0], ruffle [0.004], ruffleFrequency [3], ruffleDepth [0.35], midrib [0.003], thickness [0], thicknessTip [0.4], baseColor ['#eef0c8'], tipColor ['#ffffff'], segments [[28, 48]], seed }`:
|
|
941
|
+
- It stands on its base at the origin and grows along +Y, its outer face toward +Z. u runs across (0 to 1) and v along (base to tip).
|
|
942
|
+
- `outline`: tulip, rose, oval, round, lance or heart, or a list of widths along the body as shares of `width`. The last `tip` of the
|
|
943
|
+
length closes as a superellipse: `tipShape` 0 is round, 1 pointed, below 0 square.
|
|
944
|
+
- `cup` is the degrees of arc across the widest row, edges curling toward -Z. `curl` is the degrees the centre line turns toward the
|
|
945
|
+
cup by the tip (negative arches it back). `flare` turns the top quarter outward, a lip (a flower head's petals have 12). `twist` is
|
|
946
|
+
in degrees.
|
|
947
|
+
- `ruffle` is the edge's waves in metres, `ruffleFrequency` waves per side, within `ruffleDepth` half-widths of the rim. `midrib` is a
|
|
948
|
+
keel down the middle in metres (negative: a groove).
|
|
949
|
+
- `thickness` above 0 makes a closed slab that is thinner toward the tip (`thicknessTip`) and the rim. 0 is one sheet: give its
|
|
950
|
+
material `doubleSided: true`.
|
|
951
|
+
- Every shape of the same `segments` has the same points, so petals make good shape keys.
|
|
952
|
+
- It writes `group:edge` (0 on the rim, 1 a half-width in; the base counts as inside), `group:along` (0 base to 1 tip) and
|
|
953
|
+
`group:thick` (how thick a real petal is there: full at the base, thinner toward the tip, nothing at the rim).
|
|
954
|
+
- `baseColor` to `tipColor` is a tone along it as vertex colours, which multiply the material's: yellow-green at the base, creamy
|
|
955
|
+
at the tip by default. `null` for none.
|
|
956
|
+
- `leaf { length [0.6], width [0.16], outline ['lance'], tip, tipShape, cup [25], curl [-25], curlPower [1.4], flare [0], twist [12], ruffle [0.003], ruffleFrequency [6], ruffleDepth [0.35], midrib [-0.004], thickness [0], thicknessTip [0.4], baseColor, tipColor, segments [[28, 48]], seed }`: the same op as `petal` with a leaf's defaults: a lance outline, a gentle arch back, a groove down the middle, a slight twist, and no tone (give `baseColor` and `tipColor` for one).
|
|
957
|
+
A blade of grass is a leaf too: `{ "op": "leaf", "length": 0.3, "width": 0.0075, "cup": 35,
|
|
958
|
+
"curl": -30, "twist": 25, "ruffle": 0, "segments": [4, 16] }`, copied onto points (`scatter`, `copyToPoints` with `align: "up"`).
|
|
959
|
+
- `flowerHead { petals [3], layers [2], open [0.3], petal: { ... }, coverage [0.92], inner [0.9], lag [0.3], openAngle [58], openCup [55], mouth [0.62], jitter [0.5], seed, frames [8], center [true] }`:
|
|
960
|
+
- It is petals around +Y on the origin. `petals` is per layer, so the default is a tulip's six tepals in two whorls of three.
|
|
961
|
+
- Closed, each layer's petals meet on one egg-shaped surface (`coverage` of a full turn), and each inner layer (`inner` its size)
|
|
962
|
+
nests inside and turns half a step. `mouth` is how far the top draws in, as a share of the widest. `petal` takes any petal param;
|
|
963
|
+
the petal's params may also stand on the head itself (`width`, `ruffle`, `flare`...), which is where the Nodes panel writes them.
|
|
964
|
+
- Its opening is the shape key `open`, 0 a closed bud to 1 wide open, in `frames` in-betweens. Inner layers open later by `lag`,
|
|
965
|
+
petals lean out to `openAngle` and flatten their cup to `openCup`. Play it with the object's `keys: { "shape:open": [...] }`:
|
|
966
|
+
a bloom costs no rebuild.
|
|
967
|
+
- `center` adds a pistil and a ring of stamens on material slot 1 (`"materials": ["petal", "centre"]`).
|
|
968
|
+
- No two petals alike: `jitter` (0 to 1) and `seed` vary each petal's length (so the tips stand at different heights, ±10 % at the
|
|
969
|
+
default 0.5), width (±6 %), turn, lean and twist (a few degrees), the cup of one side and the tone (its colours ±4 % lighter or
|
|
970
|
+
darker and ±2 % warmer or cooler, so the petals of one flower photograph a shade apart); and half the petals wear their material's
|
|
971
|
+
pattern mirrored across, so a `veins` petal's veins are not one petal's printed on all of them. Outer petals only lean out and loosen,
|
|
972
|
+
inner ones only lean in and tighten, so none passes through another. The petals lean out at the top by 16 degrees (`flare`).
|
|
973
|
+
- A petal built elsewhere comes in through `in: "#id"`, swung open about its base.
|
|
974
|
+
- `stem { path [[[0, -0.6, 0], [0.004, -0.3, 0.025], [0, 0.012, 0]]], radius [0.014], taper [0.85], profile, receptacle [0.044], receptacleLength [0.07], bend [8], toward ['z'], radial [16], segments, tension [0.5], caps [true], ribs [0], ribDepth [0.04] }`:
|
|
975
|
+
a closed tube that thins from `radius` to `taper` of it at the top (or follows `profile`, shares of `radius` base to top), then swells
|
|
976
|
+
smoothly into a domed receptacle `receptacle` wide over its last `receptacleLength`: the bulge a flower's petals grow from, as wide as
|
|
977
|
+
the default flower head's ring of petals. `receptacle: 0` leaves it out. `bend` curls it that many degrees more toward `toward`,
|
|
978
|
+
keeping its top where the path ends, so a stem from the default path stands right under a head at the origin. `ribs` long ridges run
|
|
979
|
+
up it, `ribDepth` of its radius high, fading out into the receptacle (a tulip's stem 6 to 8 at 0.03 to 0.05: it is not a turned rod).
|
|
980
|
+
It writes `group:along`. `tube` with `taper` and `bend` also makes a stem, without the receptacle.
|
|
981
|
+
|
|
982
|
+
- `drops { count [40], radius [[0.0006, 0.003]], contact [110], flatten [0.3], lean [0.5], up [0.15], side ['up'], gap [0.1], sink [0.1], wobble [0.3], mask, segments [20], seed [0] }`: water drops resting on the input surface (dew on a petal or a leaf, rain beading on a car, condensation on a bottle), as their own mesh in the input's space.
|
|
983
|
+
Make them an object of their own with a water material, in the same place as the surface (`in: "@petals"`
|
|
984
|
+
brings that object's mesh in its own space, so give the drops object the same `at`, `rot` and `scale`).
|
|
985
|
+
- Each drop is a spherical cap meeting the surface at `contact` degrees (a waxy petal or a water-repellent leaf 100 to 150,
|
|
986
|
+
glass 20 to 60; past 90 it bulges out over its own footprint), give or take 8. `radius` is the footprint's radius in metres: a pair
|
|
987
|
+
gives a range, small drops far more common than big ones, as dew forms; no two overlap (`gap` is the space between them as a share of
|
|
988
|
+
their radii), and none hangs over the surface's open edge (a petal's rim, a blade's side).
|
|
989
|
+
- Gravity: drops near water's capillary length (2.7 mm) and bigger slump flatter by `flatten` (0 none, 0.9 a puddle), and on a slope
|
|
990
|
+
they lean and run downhill by `lean`. A drop pinned on a real surface is not a perfect circle: `wobble` (0 to 1) bends its contact
|
|
991
|
+
line in two or three soft lobes (0: a lens-perfect bead).
|
|
992
|
+
- Where: `side` `"up"` puts each drop on whichever face of the surface looks up (a sheet's normals may point either way), `"out"` on
|
|
993
|
+
the side its normals point to, `"in"` on the other; `up` (-1 to 1) is how far that side must look up (0.15: not on steep faces;
|
|
994
|
+
-0.5: on near-vertical petals too, as dew sits on everything; -1: hanging under a leaf as well). `mask` is an expression over `P`,
|
|
995
|
+
`N`, `uv` (as `scatter`'s) for where they may sit.
|
|
996
|
+
- A drop is open at its foot: the surface it rests on is its other side, as a real drop's is, and its rim sits `sink` of its radius into
|
|
997
|
+
the surface, so no film of air shows between drop and petal on a curve. So the light that comes through a backlit petal or leaf
|
|
998
|
+
goes on into the drops on it (a closed base would stand behind the sheet as a thin slab of water and keep that light out). A cap is an
|
|
999
|
+
open mesh, so give the water `thinWalled: false` (a body, not a film): `{ "transmission": 1, "ior": 1.333, "roughness": 0,
|
|
1000
|
+
"thinWalled": false }`: each drop is then a little lens that shows the scene
|
|
1001
|
+
behind it upside down and, in Final, throws a caustic onto the surface under it. About 400 triangles a drop at `segments` 20.
|
|
1002
|
+
|
|
1003
|
+
**Thin, glowing edges.** A material's translucency can follow a group:
|
|
1004
|
+
`{ "translucency": 0.9, "translucencyInner": 0.5, "translucencyAttr": "group:thick", "doubleSided": true }`. Each point gets `translucency`
|
|
1005
|
+
where the group is 0 (the petal's thin rim and tip) and `translucencyInner` where it is 1 (its thick base), so the edges let more light
|
|
1006
|
+
through when lit from behind, in Draft and Final. The share rides in the mesh's colour alpha, which the material reads as vertex colours.
|
|
1007
|
+
|
|
1008
|
+
**Veins.** The procedural pattern `veins` draws a petal's or a leaf's veins over the sheet's own uv (u across, v base to tip: one uv tile
|
|
1009
|
+
is one whole petal or leaf, so keep its `scale` at 1):
|
|
1010
|
+
- `kind: "petal"`: `count` [26] fine veins across the base that run to the tip, meander (`wander` [0.6]) and fork as the petal widens
|
|
1011
|
+
(`fork` [1], 0 never); in the world they fan out from the base and draw together at the tip, as a real petal's do. `vary` [0.5]: how
|
|
1012
|
+
unevenly they are spaced and how unlike in strength (a few strong among many faint; 0 even and alike reads as printed lines). `kind: "leaf"`: a
|
|
1013
|
+
midrib, `count` [26; 10 to 16 reads as a leaf] side veins each side at `angle` [50] degrees that arch toward the tip near the rim
|
|
1014
|
+
(`aspect` [3.5], the leaf's length over its width, keeps that angle true in the world), and a fine net between them (`net` [0.25]).
|
|
1015
|
+
- `colors`: the sheet's ramp from base to tip (`along` [0.6] how much it follows the length; `blotch` [0.5] soft patches of tone), then
|
|
1016
|
+
the vein colour last: a petal's veins a deeper, more saturated shade of the petal, a leaf's paler than its green (a leaf with no
|
|
1017
|
+
`colors` is green). `contrast` [0.55] how strongly the veins take it, `bleed` [0.45] how far it spreads into the sheet beside them (the
|
|
1018
|
+
pigment that gathers along veins). The veins are a faint groove and a little smoother than the sheet (`roughness` [[0.32, 0.45]]).
|
|
1019
|
+
- `wear` [0] (0 to 1): a real petal's or leaf's wear: a ragged browned rim (wider toward the tip), soft water-soaked bruises and faint
|
|
1020
|
+
creases where it was folded in the bud, in colour, roughness and relief. 0.2 to 0.4 for a fresh cut flower: a sheet with none reads
|
|
1021
|
+
as printed.
|
|
1022
|
+
- It bakes once, 1024 a side by default (`size` 2048 for a petal that fills the frame; about 0.2 s at 1024). The petal op's tone
|
|
1023
|
+
(`baseColor` to `tipColor`) multiplies it, and with `translucencyColor` left out the light through a backlit petal takes the veins'
|
|
1024
|
+
colours: the veins show dark and rich against the glow, the way a backlit petal photographs.
|
|
1025
|
+
|
|
1026
|
+
A tulip, lit from behind:
|
|
1027
|
+
|
|
1028
|
+
```json
|
|
1029
|
+
"materials": {
|
|
1030
|
+
"petal": { "procedural": { "pattern": "veins", "colors": ["#f8f0e2", "#efe2c8", "#e6d6ba", "#c9b48a"], "size": 2048 },
|
|
1031
|
+
"translucency": 0.9, "translucencyInner": 0.5, "translucencyAttr": "group:thick", "sheen": 0.35, "doubleSided": true },
|
|
1032
|
+
"water": { "transmission": 1, "ior": 1.333, "roughness": 0, "thinWalled": false },
|
|
1033
|
+
"centre": { "base": "#b9a64e", "roughness": 0.6 },
|
|
1034
|
+
"stem": { "base": "#5e7d36", "roughness": 0.5 }
|
|
1035
|
+
},
|
|
1036
|
+
"lights": [{ "id": "back", "type": "sun", "dir": [-0.35, 0.42, -1], "color": "#ffd9a8", "intensity": 5, "size": 3 }],
|
|
1037
|
+
"objects": [
|
|
1038
|
+
{ "id": "tulip", "material": "petal", "materials": ["petal", "centre"],
|
|
1039
|
+
"graph": [{ "op": "flowerHead" }, { "op": "sculpt", "strokes": [{ "brush": "crease", "path": [[0.03, 0.27, 0.6], [0.045, 0.36, 0.6]], "project": [0, 0, -1], "radius": 0.035, "strength": 0.35 }] }],
|
|
1040
|
+
"keys": { "shape:open": [{ "t": 0, "v": 0.05 }, { "t": 3, "v": 0.6 }] } },
|
|
1041
|
+
{ "id": "stem", "material": "stem", "graph": [{ "op": "stem" }] },
|
|
1042
|
+
{ "id": "dew", "material": "water", "graph": [{ "op": "drops", "in": "@stem", "side": "out", "up": -0.9, "count": 8, "radius": [0.002, 0.005] }] }
|
|
1043
|
+
]
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
Drops on a flower that opens on a key sit where its shown pose (`open`) puts the petals; they do not follow the opening, so give dew to a
|
|
1047
|
+
flower that holds still (or move the camera instead). The whole macro shot of this kind, a backlit tulip with dew in a meadow at sunrise,
|
|
1048
|
+
is tests/flower/hero.mjs in the app's repository.
|
|
1049
|
+
|
|
1050
|
+
### Rooms and furniture
|
|
1051
|
+
|
|
1052
|
+
Sources that build a room from its floor plan and furniture from parts, with their sizes as numbers. Each gives one mesh whose triangles are in named material slots: list the materials on the object in that order (`"materials": [...]`), or take one slot alone with `part` (then the object wears `material`), or several with a list (`"part": ["pot", "soil"]`: those slots kept, `materials` still in the op's full order). Vertex colours (books, leaves) show only on an object with one material. Their uvs are in metres (box projection), so smart materials keep their real size. Furniture faces +z and stands on y = 0; turn it with the object's `rot`.
|
|
1053
|
+
|
|
1054
|
+
- `room { plan **required**, height [2.6], thickness [0.12], openings [], skirting [0.08], cornice [0], window {}, door {}, part }`: walls with thickness round `plan` (the inner corners `[[x, z], ...]`, either way round; wall `i` runs from corner `i` to `i + 1`), the floor and ceiling inside it, skirting along the walls (broken at doors), an optional cornice, and every opening's own parts. An opening is `{ wall, at, width, height, sill, kind }`: `at` is metres from the wall's first corner to the opening's middle, `sill` its bottom above the floor, `kind` `"window"` (defaults 1.2 x 1.4 at 0.9) or `"door"` (0.85 x 2.05 at 0). The wall is cut round it, so its reveals (the wall's thickness inside the opening) are real faces. `window` sets every window's `frame` [0.055], `depth` [0.07], `mullions` [[1, 1]] (panes across, up), `glass` [0.006], `sill` [0.025], `sillDepth` [0.18]; `door` sets `casing` [0.07], `leaf` [0.04] and `open` [0] (degrees). An opening's own `window` or `door` overrides them. Slots and `part`: `walls`, `floor`, `ceiling`, `skirting`, `cornice`, `frames` (window frames and door casings), `glass`, `sills`, `doors`, `portals`. Make one object per part you want (each its own material and its own texture bake); they all take the same plan.
|
|
1055
|
+
- `portals`: each window opening's rectangle on the room side. Final already takes a room's windows as portals while the camera is inside it, so this part is only needed to mark them by hand (an object made of it with `"portal": true`; any portal object in the scene turns the automatic ones off).
|
|
1056
|
+
- `window { width [1.2], height [1.4], thickness [0.12], frame, depth, mullions, glass, sill, sillDepth, part }` and `door { width [0.85], height [2.05], thickness, casing, leaf, open, part }`: one alone, its bottom middle at the origin, the wall's inner face at z = 0 and the room toward -z. Window slots: `frames`, `glass`, `sills`, `portal`; door slots: `casing`, `leaf`.
|
|
1057
|
+
- `curtain { width [1.4], height [2.4], pleats [7], fullness [1.8], wind [0], steps [120], rail [true], natural [0], seed, part }`: a curtain gathered into pleats on a rail at y = `height`, let fall and settled by the cloth solver with its top held (about half a second); `wind` blows it sideways (+x) while it settles; `steps: 0` hangs it unsettled, in even folds with a straight hem (a sheer cafe curtain on the lower panes). `natural` (0 to 1; 0.7 to 0.9 for a lived-in room) hangs it as cloth really hangs: the heading gathered into tight even pleats at the rail, the folds below of their own widths and depths, opening out and wandering toward a heavier turned-up hem, the leading edge swung back a little. Slots: `cloth`, `rail`. Give the cloth `doubleSided: true` (and a little `translucency` for linen against a window).
|
|
1058
|
+
- `sofa { width [2.0], depth [0.9], height [0.8], seat [0.43], arms [0.16], back [0.2], cushions [3], legs [0.1], softness [0.045], lived [0], part }` and `armchair { ... }` (the same, 0.88 wide, one cushion): plinth, arms with a welt round their front panels, boxed seat cushions with a dent where people sit and stuffed back cushions leaning back (all piped), short legs. `lived` (0 to 1) is a sofa people sit on: softer seat cushions sagging deeper, each its own way, crowned and creased where people sit, piped, the back cushions slumped, and the arms' tops and fronts and the seats' front edges a shade lighter where they are rubbed (0.6 to 0.9 for a lived-in room). The rubbed parts are vertex colours, which show on an object whose upholstery is its only material: make the upholstery its own object (`part: "upholstery"`) and the legs another (`part: "legs"`). Slots: `upholstery`, `legs`.
|
|
1059
|
+
- `cushion { width [0.45], height [0.45], thickness [0.15], sag [0], piping [0], slump [0], creases [0], seed, part }`: a stuffed cushion: plump in the middle, thinning to a seam all round, its edges drawn in between pointed corners, faint creases from the corners, each `seed` a little uneven. `sag` (metres) presses a dent into its +z face where someone sat; `piping` (a radius, 0.003 to 0.006) runs a corded welt along the seam; `slump` (0 to 1) gives it weight, as a scatter cushion leaning on a sofa's back: its top flops forward with a soft crease across its front, its foot spreads and flattens (0.4 to 0.8 reads as a real cushion); `creases` (0 to 1) wrinkles its +z face where it was sat on: a few shallow valleys fanning round the dent and pulled toward its -y edge. It lies in x/y facing ±z, its middle at the origin: stand it on a sofa with the object's `at` and lean it back with `rot` [-15, 0, 0]; lay a seat cushion flat with `rot` [-90, 0, 0]. The sofa's own seat and back cushions are these (seats with a dent, all piped). Slot: `cushion`.
|
|
1060
|
+
- `throw { width [0.8], length [1.6], thickness [0.008], over [0.16], height [0.62], inside [0.2], folds [5], drop [0.12], fringe [0], seed, part }`: a heavy throw (a wool blanket) dropped over a sofa's arm: across the arm's top (`over` wide, its top `height` above the floor), `inside` metres down the inner face toward the seat and the rest down the outer face, in soft heavy folds that grow from nothing where it rests on the arm to their full depth at the hem, the hem `drop` metres lower at one side than the other; every `seed` folds it its own way, with a real `thickness` all round. The arm runs along z (`width` no more than the arm is deep), its top's middle at x = 0, y = `height`, the seat toward -x: put the object's `at` at the arm's middle on the floor ([sofa x + width / 2 - arms / 2, 0, sofa z] for a sofa's right arm; `rot` [0, 180, 0] for the left one), `height` = the sofa's `height` × 0.78, `over` = its `arms`. Give it a knitted `fabric` and `doubleSided`. `fringe` (metres, 0.03 to 0.08) hangs tassels from both hems, each its own length and a little askew. Slot: `throw`.
|
|
1061
|
+
- `coffeeTable { width [1.1], depth [0.6], height [0.42], top [0.03], leg [0.04], round [false], shelf [0], part }` and `diningTable` (1.8 x 0.9 x 0.75): a top on four tapered legs; `round: true` makes it a disc `width` across; `shelf` a lower shelf at that height. Slots: `top`, `legs`.
|
|
1062
|
+
- `chair { width [0.45], depth [0.5], seat [0.46], height [0.84], leg [0.032], part }`: a wooden chair, its back at -z. Slots: `seat`, `frame`.
|
|
1063
|
+
- `shelf { width [0.8], depth [0.3], height [1.8], shelves [5], board [0.022], back [true], books [0.75], palette ['bold'], spines ['simple'], seed, part }`: an open bookcase; `books` (0 to 1) fills its shelves with books of their own size and colour (`palette: "muted"`: a real shelf's spines, mostly white, cream and black paperbacks and faded cloth, a few colours; `"library"`: a lived-in shelf's mix, a third white and cream paperbacks, the rest dark cloth and jackets (navy, black, oxblood, bottle green, slate) with a few ochres and greys; `"bold"` saturated cloth colours): two cover boards proud of a cream page block (seen from above), a spine with a title band or label on many, a few lying flat in stacks, one leaning on the end of a row. `spines: "real"` builds the books as a shelf holds them, for a room that has to pass as a photograph: real sizes (paperbacks, trade books, hardcovers and a few tall art books, runs of a series alike), spines toward the room a little in and out, a hardcover's rounded back with a coloured headband at head and tail and its boards proud of the pages, a paperback's flat back, the cloth worn lighter at the head, tail and hinges, and the lettering as type sets it: the title running down the spine in words of letters of their own widths, the author's name smaller below, a publisher's mark at the foot (a wide spine: the title across it), light on dark books, dark on light ones, gilt on some cloth; bigger books stacked flat at a row's end. The books carry vertex colours, which show on an object with one material: make the books their own object (`part: "books"`, a white `base` or a graph) and the boards another (`part: "boards"`). An object with `materials` wears no vertex colours, so its books would all be one colour. Slots: `boards`, `books`.
|
|
1064
|
+
- `lamp { kind ['floor'], height [1.55], shade [[0.17, 0.22, 0.26]], base [0.14], stem [0.012], part }`: a floor lamp, or `kind: "table"` (0.55 high, a turned base). The shade is an open, thin cone (top radius, bottom radius, height): give it `translucency` 0.5 to 0.8 and `doubleSided`, and put a `point` light at its middle (y = height - shade height / 2). Slots: `body`, `shade`, `bulb`.
|
|
1065
|
+
- `rug { width [2.0], depth [1.4], thickness [0.012], round [0.02], border [0], ripple [0], curl [0], pile [0], fringe [0], seed, part }`: a rug; `border` (metres) binds its edge with a band a little proud of the pile (slot `border`), `ripple` (metres, 0.003 to 0.008) lifts it in a few soft waves and `curl` (0.01 to 0.04) lifts its +x +z corner, as a rug that is walked on lies. `pile` (metres, 0.008 to 0.02 for a hand-knotted wool rug) stands a deep pile on it: its top lumpy where the tufts lean together, rolled down over a ragged edge that wanders a few millimetres. `fringe` (metres, 0.04 to 0.1) knots the warp's ends into tassels at its two short ends, lying on the floor each a little askew (slot `fringe`: give it a plain off-white wool, e.g. `fabric: { "weave": "knit", "threads": 900 }`). Slots: `rug` (the `woolRug` preset; `pattern: "lattice"` is the hand-knotted diamond lattice, and its `hand` (0 to 1, 0.6 to 0.8 for a real one) makes the lines wander further, swell, thin and fade here and there, and the ground drift in soft bands of dye, an abrash), `border`, `fringe`.
|
|
1066
|
+
- `plant { pot [0.13], potHeight [0.26], height [0.55], leaves [11], stems, leafLength [0.24], leafWidth [0.09], droop [0.5], leaf {}, kind ['leafy'], seed, part }`: a pot with soil and a leafy plant: `stems` (about one per five leaves when left out) rise from the soil leaning out, with `leaves` on short stalks along their upper part, turning round each stem, larger and drooping more (`droop` 0 to 1) lower down, upright at the tip. `leaf` takes the `leaf` op's params (`outline: "oval"`, `ruffle`, `cup`...). The leaves carry colours (vertex colours): each leaf a shade of `leafColor` [[0.1, 0.22, 0.06], linear], young ones at the tips lighter, a paler midrib, a dry brown tip on `browning` [0.2] of the old ones. They show on an object of the leaves alone with a white material (`part: "leaves"`, `"base": "#ffffff"`, a green `translucencyColor`); the rest as a second object with `part: ["pot", "soil", "stems"]` (a list keeps those parts and their slots, so `materials` still lists all four). A floor plant is 30 to 50 leaves on 3 stems at 1.2 to 1.5 m; a sill plant 15 small ones on 5. `kind: "fig"` is a fiddle-leaf fig: leathery leaves wider toward their tip with a waist below, a sunken midrib and pale lateral veins (colours), a wavy edge, on stout petioles that arch up from the branch and bend down into the blade, and woody branches as thick as a thumb at the soil (give `stems` a bark brown); leave `leaf` out for its own leaves (what `leaf` sets wins; they are single sheets: a leaf with `thickness` takes a window's light through two faces and comes out much darker in Final). Use the same `kind` on both of the plant's objects. Slots: `pot`, `soil`, `leaves`, `stems`. Leaves want `translucency` 0.3 and `doubleSided`.
|
|
1067
|
+
- `pictureFrame { width [0.5], height [0.7], frame [0.035], depth [0.025], mat [0.05], part }`: a frame with a mat and a picture, hanging from its back at z = 0 and facing +z. The picture's uv runs 0..1 across it (an image map, or a graph). Slots: `frame`, `mat`, `picture`.
|
|
1068
|
+
|
|
1069
|
+
A whole room (one object per part; the window's daylight from the scene's sun and the environment, whose sky is seen through the window: `"opaque": true`, or the layers under the Scene show through the glassless opening; the window is Final's portal by itself):
|
|
1070
|
+
|
|
1071
|
+
```json
|
|
1072
|
+
"materials": {
|
|
1073
|
+
"plaster": { "graph": { "preset": "paintedPlaster", "color": "#ece9e3" } },
|
|
1074
|
+
"oak": { "graph": { "preset": "oakBoards" } },
|
|
1075
|
+
"white": { "base": "#efede8", "roughness": 0.45 },
|
|
1076
|
+
"linen": { "graph": { "preset": "linen" }, "doubleSided": true, "translucency": 0.45, "fabric": { "threads": 300 } },
|
|
1077
|
+
"pane": { "pane": true },
|
|
1078
|
+
"fabric": { "graph": { "preset": "wornFabric", "color": "#b7b4ae" }, "fabric": { "weave": "basket", "threads": 300 } },
|
|
1079
|
+
"furniture": { "graph": { "preset": "lacqueredWood" } },
|
|
1080
|
+
"rug": { "graph": { "preset": "woolRug", "pattern": "diamonds" }, "fabric": { "weave": "pile", "threads": 420 } },
|
|
1081
|
+
"shade": { "graph": { "preset": "linen" }, "translucency": 0.7, "doubleSided": true },
|
|
1082
|
+
"mustard": { "graph": { "preset": "velvet", "color": "#c4952f" } },
|
|
1083
|
+
"black": { "base": "#1d1d1f", "roughness": 0.42, "metalness": 0.9 },
|
|
1084
|
+
"bulb": { "base": "#fff4e0", "emission": "#ffd9a0", "emissionStrength": 6 },
|
|
1085
|
+
"pot": { "graph": { "preset": "glazedCeramic", "color": "#e8e4dc" } },
|
|
1086
|
+
"soil": { "base": "#3a2e25", "roughness": 0.95 },
|
|
1087
|
+
"leaves": { "base": "#3f6a34", "roughness": 0.55, "translucency": 0.3, "doubleSided": true },
|
|
1088
|
+
"stems": { "base": "#4b6b35", "roughness": 0.6 }
|
|
1089
|
+
},
|
|
1090
|
+
"objects": [
|
|
1091
|
+
{ "id": "walls", "material": "plaster", "graph": [{ "op": "room", "plan": [[-2.3, -2.7], [2.3, -2.7], [2.3, 2.7], [-2.3, 2.7]], "height": 2.7, "thickness": 0.14,
|
|
1092
|
+
"openings": [{ "wall": 3, "at": 3.05, "kind": "window", "width": 1.9, "height": 1.65, "sill": 0.62 }], "window": { "mullions": [2, 1] }, "part": "walls" }] },
|
|
1093
|
+
{ "id": "floor", "material": "oak", "graph": [{ "op": "room", "plan": [[-2.3, -2.7], [2.3, -2.7], [2.3, 2.7], [-2.3, 2.7]], "height": 2.7, "part": "floor" }] },
|
|
1094
|
+
{ "id": "frames", "material": "white", "graph": [{ "op": "room", "plan": [[-2.3, -2.7], [2.3, -2.7], [2.3, 2.7], [-2.3, 2.7]], "height": 2.7, "thickness": 0.14,
|
|
1095
|
+
"openings": [{ "wall": 3, "at": 3.05, "kind": "window", "width": 1.9, "height": 1.65, "sill": 0.62 }], "window": { "mullions": [2, 1] }, "part": "frames" }] },
|
|
1096
|
+
{ "id": "glass", "material": "pane", "graph": [{ "op": "room", "plan": [[-2.3, -2.7], [2.3, -2.7], [2.3, 2.7], [-2.3, 2.7]], "height": 2.7, "thickness": 0.14,
|
|
1097
|
+
"openings": [{ "wall": 3, "at": 3.05, "kind": "window", "width": 1.9, "height": 1.65, "sill": 0.62 }], "window": { "mullions": [2, 1] }, "part": "glass" }] },
|
|
1098
|
+
{ "id": "curtain", "material": "linen", "materials": ["linen", "white"], "at": [-2.12, 0, 0.95], "rot": [0, 90, 0], "graph": [{ "op": "curtain", "width": 0.75, "height": 2.45, "pleats": 6, "fullness": 2 }] },
|
|
1099
|
+
{ "id": "sofa", "materials": ["fabric", "furniture"], "material": "fabric", "at": [-0.25, 0, -2.23], "graph": [{ "op": "sofa", "width": 2.1, "cushions": 3 }] },
|
|
1100
|
+
{ "id": "rug", "material": "rug", "at": [-0.2, 0, -0.55], "graph": [{ "op": "rug", "width": 2.3, "depth": 1.6 }] },
|
|
1101
|
+
{ "id": "table", "material": "furniture", "at": [-0.2, 0.012, -0.85], "graph": [{ "op": "coffeeTable", "width": 0.82, "round": true }] },
|
|
1102
|
+
{ "id": "shelf", "material": "furniture", "at": [1.55, 0, -2.54], "graph": [{ "op": "shelf", "width": 0.9, "height": 1.95, "books": 0.8, "part": "boards" }] },
|
|
1103
|
+
{ "id": "books", "material": "white", "at": [1.55, 0, -2.54], "graph": [{ "op": "shelf", "width": 0.9, "height": 1.95, "books": 0.8, "part": "books" }] },
|
|
1104
|
+
{ "id": "cushion", "material": "mustard", "at": [-0.95, 0.68, -2.15], "rot": [-16, 8, 4], "graph": [{ "op": "cushion", "width": 0.46, "height": 0.46 }] },
|
|
1105
|
+
{ "id": "lamp", "materials": ["black", "shade", "bulb"], "material": "black", "at": [-1.55, 0, -2.05], "graph": [{ "op": "lamp", "height": 1.58 }] },
|
|
1106
|
+
{ "id": "plant", "materials": ["pot", "soil", "leaves", "stems"], "material": "pot", "at": [-1.75, 0, 1.0], "graph": [{ "op": "plant", "pot": 0.17, "potHeight": 0.34, "height": 1.35, "leaves": 40, "stems": 3, "leafWidth": 0.15, "leaf": { "outline": "oval" } }] }
|
|
1107
|
+
],
|
|
1108
|
+
"env": { "background": "env", "opaque": true },
|
|
1109
|
+
"lights": [
|
|
1110
|
+
{ "id": "sun", "type": "sun", "dir": [-0.86, 0.42, -0.29], "intensity": 4.2, "color": "#ffe9cf", "size": 0.8 },
|
|
1111
|
+
{ "id": "bulb", "type": "point", "at": [-1.55, 1.42, -2.05], "intensity": 0.6, "color": "#ffc98a" }
|
|
1112
|
+
]
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
(The frames repeat the walls' plan and openings: each object builds its own part of the same room.) The whole scene is tests/rooms/scandi.mjs in the app's repository.
|
|
1116
|
+
|
|
1117
|
+
Light a room as one day. The sky seen through the window and the light inside must agree: a sun light needs a sky preset with its own sun in the same direction (and sunlit things outside); an overcast preset (`forest_slope_1k`, `potsdamer_platz_1k`) goes with no sun light at all, the room lit by the sky through its openings and falling off from them. The view out of the window is the preset itself, blurred at 1k, unless `env.view` gives it a picture (a photo of the street: sharp at its own resolution, the room still lit by the preset); with no picture, a garden or trees read better than a street. Glaze the windows with a `pane` (the room op's `glass` part): the light still comes in and the glass reflects the room faintly. Leave Final's `clamp` off in a room (it takes the bounced light's energy: a darker, blotchy picture). A `room` op's windows are portals by themselves while the camera is inside the room; a room built from boxes needs a `portal: true` object in each window, so the sky's light converges.
|
|
1118
|
+
|
|
1119
|
+
### Escape hatch
|
|
1120
|
+
|
|
1121
|
+
- `script { code **required**, seed [0] }`: a JS function body that receives `(input, ops, ctx)` and returns a Geo or a MeshData (shapes below). `input` is the first input as a Geo. `ops` has every op above: `ops.box({ size: 1 })`, `ops.twist(geo, { amount: 30 })`, `ops.boolean(a, b, { mode: 'subtract' })`, `ops.merge([a, b])`; inputs first, params last, each returning a Geo. `ctx` has `inputs`, `params`, `seed`, `makeMesh({ position, index })`, `rand(i, stream)`, `noise(x, y, z)`. Same shadowed globals as `attrib`. Reach for it only when the ops above cannot say it.
|
|
1122
|
+
- **Parameters:** every field of the node other than `op`, `id`, `in`, `sources`, `note` and `bypass` arrives in `ctx.params`, as written. Keep the data there rather than inside `code`: the node is cached by its fields, and the editor shows them. `{ "op": "script", "code": "const { rows, gap } = ctx.params; …", "rows": 5, "gap": 0.02, "palette": ["#b04a3a", "#2f5d8a"] }` gives `ctx.params.rows` 5.
|
|
1123
|
+
- **Colours:** an instance colour (`instances[].colors`, 3 numbers per copy) and a mesh's vertex colours (`mesh.color`) are LINEAR RGB, 0 to 1, and they multiply the material's `base` and maps: leave `base` white to see them as given. From a hex colour `#rrggbb`, each channel c = value / 255 becomes c / 12.92 when c ≤ 0.04045, else ((c + 0.055) / 1.055) ^ 2.4: `#b04a3a` is [0.434, 0.068, 0.042]. `Cd` written by `attrib` and carried by `copyToPoints` is the same.
|
|
1124
|
+
|
|
1125
|
+
```js
|
|
1126
|
+
Geo = {
|
|
1127
|
+
mesh: MeshData | null, // triangles
|
|
1128
|
+
points: PointSet | null, // from scatter and point ops
|
|
1129
|
+
instances: [{ source: MeshData, matrices: Float32Array /* 16 per copy */, colors: Float32Array | null /* 3 per copy */ }]
|
|
1130
|
+
}
|
|
1131
|
+
MeshData = { position: Float32Array, normal: Float32Array, uv: Float32Array, index: Uint32Array }
|
|
1132
|
+
PointSet = { count, P: Float32Array, N: Float32Array, pscale: Float32Array, orient: Float32Array /* xyzw */, Cd: Float32Array, id: Uint32Array, ...custom }
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
In the editor, `attrib`, `script` and string masks run in an isolated evaluator: an opaque-origin frame with no network, no storage and no way to see the page, stopped after 20 seconds. They can compute anything and reach nothing, so they cannot fetch, and everything they need arrives through `input`, `ops` and `ctx`.
|
|
1136
|
+
|
|
1137
|
+
## Lights in the scene
|
|
1138
|
+
|
|
1139
|
+
`rig.scene.lights[]` are lights in metres, in the same space as the objects. Each has an `id` (unique: keys and the critique name it),
|
|
1140
|
+
a `type`, `color` (sRGB, or a colour temperature such as `"3200K"`) [`#ffffff`], `intensity` [1] and `castShadow` [true]. The `type` decides which other fields it reads, and a
|
|
1141
|
+
field of another type is ignored (the validator says so):
|
|
1142
|
+
|
|
1143
|
+
| type | Where it is and where it points | Size and shape | `intensity` |
|
|
1144
|
+
|---|---|---|---|
|
|
1145
|
+
| `sun` | `dir` [[0.4, 1, 0.3]]: points FROM the set TOWARD the sun (any length). `[0, 1, 0]` noon overhead; y below 0 lights from underneath. Parallel rays everywhere. | `size` [1]: degrees across the sky; 0.5 the real sun (crisp shadows), 2 to 5 hazy. | Irradiance, Blender's Sun Strength: 1 to 4 daylight. |
|
|
1146
|
+
| `area` | `at` [[0, 2, 0]]: the panel's centre. `target` [[0, 0, 0]]: the point it faces. It lights only the side facing `target`. | `width`, `height` [1, 1] metres: `width` lies level (horizontal), `height` along the panel's up; `circular: true` makes it a disc `width` across; `spread` [180] degrees narrows its cone (a softbox grid). | The panel's radiance (light leaving it straight out), so its light is intensity × area: halve the width and double the intensity for the same light. A 0.5 m panel about 1 m from the subject: 3 to 10. Twice the distance needs four times the intensity. |
|
|
1147
|
+
| `spot` | `at` [[0, 2, 0]]: the lamp. `target` [[0, 0, 0]]: what it points at. | `angle` [30]: HALF the cone, degrees. `penumbra` [0.3]: soft edge 0 to 1. `radius` [0]: bulb size in metres (softer shadows). | Candela-like, falling off with distance squared: 1 to 5 for a lamp about 0.5 m away. |
|
|
1148
|
+
| `point` | `at` [[0, 2, 0]]: the bulb; it shines every way. | None: a point light has no size, so its shadows stay hard (`radius` does nothing on it). For a soft little lamp use a small `area` with `circular: true`, or a `spot` with `radius`. | As a spot. A candle flame: 0.1 to 0.3, warm (`#ffb35c`). |
|
|
1149
|
+
|
|
1150
|
+
```json
|
|
1151
|
+
"lights": [
|
|
1152
|
+
{ "id": "key", "type": "area", "at": [-0.6, 0.7, 0.6], "target": [0, 0.12, 0], "width": 0.6, "height": 0.6, "intensity": 6 },
|
|
1153
|
+
{ "id": "rim", "type": "spot", "at": [0.5, 0.6, -0.7], "target": "@bottle", "angle": 20, "penumbra": 0.5, "intensity": 4 },
|
|
1154
|
+
{ "id": "sun", "type": "sun", "dir": [-0.5, 0.6, 0.4], "intensity": 2, "size": 1.5 }
|
|
1155
|
+
]
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
`at` and `target` take numbers or an object to follow (`"@bottle"`, below). A fifth type, `studio`, is a ready set of lights sized to a
|
|
1159
|
+
subject ([Studio presets](#studio-presets-type-studio)); `highlight` places a light by where its reflection must land
|
|
1160
|
+
([below](#put-the-highlight-where-you-want-it-highlight)).
|
|
1161
|
+
|
|
1162
|
+
- Classic product light: a big `area` key 30 to 60 degrees to one side of the camera and a little above, aimed at the subject; a `spot`
|
|
1163
|
+
or a strip `area` behind the subject for a rim on glass edges; the environment low (0.1 to 0.3) for fill. A key standing right behind
|
|
1164
|
+
the camera lights the subject flat. The still's critique says where each light stands against the shot ([Check your work](#check-your-work)).
|
|
1165
|
+
- `spread` in degrees on an `area`. `intensity` is the light leaving the panel straight out, so a narrow spread keeps its power only if you raise it by `tan(h) / (tan(h) - h)`, where `h` is half the spread in radians. That is how a Blender light comes across.
|
|
1166
|
+
- `texture: { "image": url }` or `{ "pattern": "window" }` (or `blinds`, `leaves`) on a `spot` or `area`: the spot projects it, the
|
|
1167
|
+
panel wears it. In Draft and Final alike a panel's picture lights each point with the part of it that point sees: the floor under a
|
|
1168
|
+
stained-glass panel takes each pane's colour, and a glossy surface reflects the picture. `gobo: { "pattern" | "image", "distance", "scale", "rotation", "extent" }` on any light puts real geometry between it
|
|
1169
|
+
and the set, out of frame, so the shadow carries the pattern.
|
|
1170
|
+
- `castShadow: false` on any light: it lights but throws no shadow.
|
|
1171
|
+
- Scene lights have no `parent` and no `keys`. To follow an object, name it: `"target": "@bottle"` aims a `spot` or `area` at the
|
|
1172
|
+
middle of that object's box, `"at": "@bulb"` puts the light there, and `{ "object": "bottle", "point": [0, 0.12, 0] }` names a point
|
|
1173
|
+
in the object's own space (its `at`, `rot` and `scale` apply). A light that names an object is placed again on every frame the object
|
|
1174
|
+
moves (its keys, a body that falls), in Draft and Final.
|
|
1175
|
+
- A light inside a closed object (a bulb in its glass, a point light in a candle's flame) is shut in by it: give that object
|
|
1176
|
+
`castShadow: false` so the light gets out. In Final a point light inside a closed glass jar does light the table through the glass.
|
|
1177
|
+
- A light itself is never drawn: a panel or a bulb inside the frame is invisible to the camera, in Draft and Final. Glossy surfaces
|
|
1178
|
+
and glass reflect an `area` panel in Final (the long highlight of a strip softbox on a bottle). To see a lamp, model it and give it
|
|
1179
|
+
`emission`.
|
|
1180
|
+
- Light from a glowing surface (a screen, a bulb's glass) is the material's `emission` ([glowing surfaces](#glowing-surfaces)).
|
|
1181
|
+
|
|
1182
|
+
### Light in a lighting designer's units: `kelvin`, `power`, `lumens`, `ies`
|
|
1183
|
+
|
|
1184
|
+
```json
|
|
1185
|
+
"lights": [
|
|
1186
|
+
{ "id": "bulb", "type": "point", "at": [0, 1.9, 0], "kelvin": 2700, "power": 60 },
|
|
1187
|
+
{ "id": "down", "type": "point", "at": [-0.8, 2.4, -0.3], "ies": "downlight", "color": "3000K", "lumens": 900 },
|
|
1188
|
+
{ "id": "wash", "type": "point", "at": [0, 2.4, -0.35], "ies": "/media/…/wallwasher.ies", "iesRotation": 90 },
|
|
1189
|
+
{ "id": "accent", "type": "spot", "at": [1, 2.4, 0], "target": "@vase", "ies": "spot", "intensity": 6 }
|
|
1190
|
+
]
|
|
1191
|
+
```
|
|
1192
|
+
|
|
1193
|
+
- Colour temperature: `kelvin` (800 to 40 000) or `color: "3200K"`: the colour of a black body at that temperature, the same as
|
|
1194
|
+
Blender's Blackbody, with luminance 1, so `intensity` still says how bright. 1900 a candle, 2700 a warm bulb, 3200 tungsten, 4000 a
|
|
1195
|
+
cool white LED, 5600 daylight, 6500 overcast. With both, `color` tints the temperature's colour.
|
|
1196
|
+
- `power` in watts as Blender counts them (a Blender light's Power carries over as it is): a `point` or `spot` gives power / 4π per
|
|
1197
|
+
steradian (`intensity` = power / 12.57), an `area` panel's radiance is power / (π × its area). `lumens` at Blender's 683 lumens per
|
|
1198
|
+
watt. `intensity` wins when both are given; a `sun`'s `intensity` is already W/m². Real bulbs are dim at the default exposure (an 800 lm
|
|
1199
|
+
bulb is intensity 0.09, where a lamp in a product shot is 1 to 5): raise `exposure` as a camera would indoors, or use `intensity`.
|
|
1200
|
+
- `ies` on a `point` or `spot`: a luminaire's measured light by direction (an IES LM-63 file: its media URL, or `{ "text": "<the file>" }`),
|
|
1201
|
+
or a preset: `downlight` (a recessed downlight's wide cone cut off at about 60°), `spot` (a tight 12° beam with a faint halo), `flood`
|
|
1202
|
+
(a broad beam to about 50°), `wallwash` (thrown to one side, up a wall), `batwing` (an office troffer, brightest about 35° off the axis),
|
|
1203
|
+
`pendant` (mostly down, a soft glow up). The profile is the beam: a spot's `angle`, `penumbra` and `radius` no longer apply. Its axis
|
|
1204
|
+
(the profile's 0°) points at `target` (a `point` without one: straight down). `iesRotation` (degrees) turns it around the axis; aimed
|
|
1205
|
+
straight down its C0 plane points along +z and C90 along -x, as in Blender, so a file lights the same here and there. Brightness:
|
|
1206
|
+
`intensity` is the profile's brightest direction; `power` or `lumens` its whole light; none of them, a file's own candela (÷ 683). In
|
|
1207
|
+
Draft and Final alike (measured against Cycles' IES texture: within 1 level of 255 in Final); its shadow is a point light's.
|
|
1208
|
+
|
|
1209
|
+
### Put the highlight where you want it: `highlight`
|
|
1210
|
+
|
|
1211
|
+
On a glossy object the bright reflection of a light (the highlight) moves when the light moves. Say where it must land and the light
|
|
1212
|
+
is placed for it: on the mirror direction from the surface there (the half-way vector between the camera and the light is the
|
|
1213
|
+
surface's normal), corrected for the material's roughness, `distance` metres out, aimed at the point. It works on `area`, `spot`,
|
|
1214
|
+
`point` and `sun` (a sun gets its `dir`), and replaces their `at` and `target`. It is solved again when the object or the camera moves.
|
|
1215
|
+
|
|
1216
|
+
```json
|
|
1217
|
+
{ "id": "kicker", "type": "area", "width": 0.08, "height": 0.4, "intensity": 30,
|
|
1218
|
+
"highlight": { "object": "bottle", "screen": [0.56, 0.38], "distance": 0.7 } }
|
|
1219
|
+
```
|
|
1220
|
+
|
|
1221
|
+
- `screen`: where in the rendered picture, [u, v] from its top left (0 to 1), through the camera that films the Scene (`scene.camera`,
|
|
1222
|
+
`fov` vertical, at the project's own frame: `videoSize`); the camera's ray there must meet the object. Or `point`: a point in the
|
|
1223
|
+
object's own space; the surface point the camera sees nearest it is used.
|
|
1224
|
+
- `distance` [the light's own `at` distance, else 2.5 times the object's size]: further is a smaller, crisper highlight from the same
|
|
1225
|
+
panel; a bigger panel (`width`, `height`) is a bigger, softer one. The panel stands where the solve puts it, and nothing moves it out
|
|
1226
|
+
of the way: keep it smaller than its distance, and check with the still's `critique.lights` (each light's place as built, a studio
|
|
1227
|
+
preset's parts too) that the floor or another object does not stand in front of it.
|
|
1228
|
+
- The surface's own normal there decides the reflection: pick a point on a smooth stretch, a few millimetres from a crease or a profile
|
|
1229
|
+
corner (a lathe profile's points are creases unless smoothed), where a small error in the point moves the normal a lot.
|
|
1230
|
+
- The light's other fields work as on any light: its links (`lights`, `excludes`, `shadowFrom`, `shadowExcludes`) choose what it lights
|
|
1231
|
+
and what shadows it, and do not change where it is put.
|
|
1232
|
+
- The highlight lands within a pixel or two of the point in Draft and Final. On a straight stretch of a round body (a cylinder's side)
|
|
1233
|
+
the reflection is a line along it: the line passes through the point, and where along it the brightest part falls depends on the
|
|
1234
|
+
panel's height. On a very rough surface (roughness 0.6 and up) it is a broad glow whose brightest pixel is less sharply placed.
|
|
1235
|
+
|
|
1236
|
+
### Studio presets: `"type": "studio"`
|
|
1237
|
+
|
|
1238
|
+
One entry stands for a whole studio set-up, sized to the subject and placed against the camera:
|
|
1239
|
+
|
|
1240
|
+
```json
|
|
1241
|
+
{ "id": "studio", "type": "studio", "preset": "bottleStrip", "subject": "bottle", "intensity": 1 }
|
|
1242
|
+
```
|
|
1243
|
+
|
|
1244
|
+
| `preset` | Lights (each an `area` light named `<id>.<part>`) | For |
|
|
1245
|
+
|---|---|---|
|
|
1246
|
+
| `threePoint` | `key` 45 degrees to one side and 30 up, `fill` big and soft on the other side (no shadow), `rim` strip behind | people, products, anything |
|
|
1247
|
+
| `topSoftbox` | `top` a big panel overhead, `fill` low and soft in front (no shadow) | table tops, food, cosmetics, packshots |
|
|
1248
|
+
| `rim` | `left` and `right` strips behind | outlines, dark subjects on dark |
|
|
1249
|
+
| `bottleStrip` | `left` and `right` tall narrow strips a little behind the sides, `top` soft overhead (no shadow) | glass and glossy bottles: a clean line down each edge |
|
|
1250
|
+
|
|
1251
|
+
- `subject` (an object id) sizes and aims them: its box, children included. Left out: every object no wider than 2 m (floors and walls
|
|
1252
|
+
left out). `side` ["left"] is the key's side as the camera sees it; `distance` [1] scales how far they stand; `intensity` [1] scales
|
|
1253
|
+
them all (1 lights the subject as a studio would, whatever its size); `color` tints them; `castShadow`, `lights`, `excludes`,
|
|
1254
|
+
`shadowFrom` and `shadowExcludes` go to every part.
|
|
1255
|
+
- Mix a preset with lights of your own (a `highlight` light for the one reflection that matters). The still's critique lists each part.
|
|
1256
|
+
|
|
1257
|
+
### Which light reaches what: `tags`, light linking and shadow linking
|
|
1258
|
+
|
|
1259
|
+
Give objects `tags` and let each light pick objects by them. The same rule holds in Draft and Final.
|
|
1260
|
+
|
|
1261
|
+
```json
|
|
1262
|
+
"objects": [
|
|
1263
|
+
{ "id": "bottle", "tags": ["hero", "glass"], "material": "glass", "graph": [ … ] },
|
|
1264
|
+
{ "id": "backdrop", "tags": ["set"], "material": "paper", "graph": [ … ] }
|
|
1265
|
+
],
|
|
1266
|
+
"lights": [
|
|
1267
|
+
{ "id": "key", "type": "area", "at": [-0.6, 0.7, 0.6], "target": [0, 0.12, 0], "width": 0.5, "height": 0.5, "intensity": 8, "lights": ["hero"] },
|
|
1268
|
+
{ "id": "wash", "type": "spot", "at": [0, 1.4, 1.2], "target": [0, 0.3, -0.5], "angle": 30, "intensity": 6, "excludes": ["hero"] },
|
|
1269
|
+
{ "id": "sun", "type": "sun", "dir": [-0.4, 1, 0.3], "intensity": 2, "shadowExcludes": ["glass"] }
|
|
1270
|
+
]
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
- `lights: [tags]`: the light lights only objects with one of these tags. `excludes: [tags]`: it never lights objects with one of
|
|
1274
|
+
them. Both may be given; `excludes` wins.
|
|
1275
|
+
- `shadowFrom: [tags]`: only objects with one of these tags throw this light's shadow (the light passes through the rest).
|
|
1276
|
+
`shadowExcludes: [tags]`: objects with one of them throw no shadow from this light, while they still shadow every other light and
|
|
1277
|
+
are still lit by this one. For an object that shadows no light at all, use the object's `castShadow: false`.
|
|
1278
|
+
- A child object has its parent's tags too. An object with no tags (and the Rig's backdrop, `model3d` layers and 3D Text, which take
|
|
1279
|
+
no tags) is lit by a light only when that light has no `lights` list, and shadows it only when it has no `shadowFrom` list.
|
|
1280
|
+
- A tag no object has is an `unknown_ref` error from validate (`didYouMean` names the close ones). Up to 15 lights in a scene may
|
|
1281
|
+
carry link fields; past that, validate warns and the extra lights light every object.
|
|
1282
|
+
- Glossy surfaces still reflect a linked `area` panel in Final, but only surfaces it lights do.
|
|
1283
|
+
|
|
1284
|
+
### Light mix and light passes: `look.lightMix`, `render.lightPasses`
|
|
1285
|
+
|
|
1286
|
+
`rig.look.lightMix` changes each light group's strength and colour over what the lights themselves say, without touching the scene:
|
|
1287
|
+
|
|
1288
|
+
```json
|
|
1289
|
+
"look": { "lightMix": { "key": { "intensity": 1.4, "color": "#ffe2c4" }, "studio": { "intensity": 0.7 }, "environment": { "intensity": 0.5 }, "emission": { "intensity": 2 } } },
|
|
1290
|
+
"render": { "mode": "final", "spp": 64, "lightPasses": true }
|
|
1291
|
+
```
|
|
1292
|
+
|
|
1293
|
+
- A group is a light's `group` (lights with one group change together), else the light's own `id`; a studio preset's parts are one
|
|
1294
|
+
group named by the preset's `id`. `environment` is the environment's light (not the background the camera sees) and `emission` the
|
|
1295
|
+
glowing surfaces; those two take `intensity` only, and `emission` changes only in Final with passes.
|
|
1296
|
+
- Draft takes the mix at once (the lights' own numbers). A Final without passes traces again with the mixed lights.
|
|
1297
|
+
- `"lightPasses": true` in `render`: Final keeps each light group's light apart while it traces (up to 6 groups, plus the environment and
|
|
1298
|
+
the glows; lights past the sixth group stay as they are), so a new mix on a finished Final is mixed and denoised again in a moment
|
|
1299
|
+
instead of traced again. The mixed picture is the traced one with each group's light reweighed: exact, the same as tracing the lights
|
|
1300
|
+
at those strengths. It needs `denoise`, turns the radiance cache and the video light reuse off for that render (a room traces slower),
|
|
1301
|
+
and takes 16 bytes a pixel for each group (33 MB a group at 1080p; a 4K frame keeps two light groups apart).
|
|
1302
|
+
- A light mix is also how to try a balance: render once, then change only `lightMix`.
|
|
1303
|
+
|
|
1304
|
+
### What each kind of ray sees: `visibility`, `holdout`
|
|
1305
|
+
|
|
1306
|
+
- `visibility` on an object: `{ "camera": false }` leaves it out of the picture while it still throws its shadow and shows in
|
|
1307
|
+
reflections (a bounce card or a flag that must not be seen). `{ "reflection": false }` keeps it out of glossy reflections (chrome,
|
|
1308
|
+
glass, lacquer) while it still bounces light onto matte surfaces; `{ "refraction": false }` keeps it from being seen through glass
|
|
1309
|
+
and liquids; `{ "indirect": false }` takes its bounce light away and what matte surfaces bounce onto it. `{ "shadow": false }` is
|
|
1310
|
+
`castShadow: false`. Each is true unless set false. `camera` and `shadow` work in Draft and Final; `reflection`, `refraction` and
|
|
1311
|
+
`indirect` are Final's (Draft traces no such rays).
|
|
1312
|
+
- `"holdout": true` on an object cuts a hole in the picture where the camera sees it: those pixels are see-through (alpha 0), so the
|
|
1313
|
+
layers below the Scene layer show there, whatever `env.background` and `env.opaque` say. The object still hides what is behind it,
|
|
1314
|
+
still casts its shadow and still shows in reflections, in Draft and Final. Use it to leave room for footage or another layer that
|
|
1315
|
+
must pass in front of part of the set. For a floor that shows only the shadows on it, use `catcher` (real 3D in footage (GreenLight Dash only)).
|
|
1316
|
+
|
|
1317
|
+
```json
|
|
1318
|
+
"objects": [
|
|
1319
|
+
{ "id": "card", "tags": ["fill"], "visibility": { "camera": false, "reflection": false }, "material": "white", "graph": [{ "op": "plane", "size": [0.6, 0.8] }, { "op": "transform", "rot": [90, 0, 0] }] },
|
|
1320
|
+
{ "id": "doorway", "holdout": true, "graph": [{ "op": "box", "size": [0.9, 2, 0.05] }] }
|
|
1321
|
+
]
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
### Render passes and masks: `render.passes`, `look.passMix`, world mattes
|
|
1325
|
+
|
|
1326
|
+
The Scene's picture split into passes, and masks of its objects, made by the Scene itself and used in the same project: no other
|
|
1327
|
+
render, no compositing program.
|
|
1328
|
+
|
|
1329
|
+
- `rig.render.passes.show` makes the Scene layer show one pass instead of its picture, in the preview, stills and renders (render a
|
|
1330
|
+
still or a video of the project to get the pass as media):
|
|
1331
|
+
- light passes, Final only (Draft shows the picture): `"diffuse"` (light off matte surfaces and the diffuse part of every material,
|
|
1332
|
+
direct and bounced), `"specular"` (reflections, refraction through glass, a clear coat, sheen), `"emission"` (what the camera sees
|
|
1333
|
+
straight: glowing surfaces, lights and the background). The three add up to the picture and are filmed with its curve and `look`,
|
|
1334
|
+
each through the denoiser.
|
|
1335
|
+
- data passes, Draft and Final, shown as they are (no curve, no look, no denoiser): `"albedo"` (surface colour, unlit), `"normal"`
|
|
1336
|
+
(world-space normal, rgb = n × 0.5 + 0.5), `"depth"` (white near, black far: `depthRange` [near, far] metres, else from the nearest thing in view to 2.5 times the focus distance; sharp, never
|
|
1337
|
+
blurred by depth of field), `"objects"` and `"materials"` (an ID colour each; the same name is always the same colour), `"mask"`
|
|
1338
|
+
(white where `mask.objects` / `mask.materials` are, black elsewhere, each edge pixel its share of coverage). In Final the IDs and
|
|
1339
|
+
the mask come from the traced samples (a cryptomatte of two ranks a pixel), so they follow depth of field; Draft draws them with the
|
|
1340
|
+
raster, 4x multisampled.
|
|
1341
|
+
- `rig.look.passMix` `{ "diffuse": 1, "specular": 1, "emission": 1 }` rebalances Final's light by kind after the trace, as a compositor
|
|
1342
|
+
would from the passes: `{ "specular": 1.5 }` makes every reflection and refraction half as bright again, `{ "diffuse": 0.8 }` darkens
|
|
1343
|
+
the matte light. It is exact (the passes add up to the picture), changing it later is one denoise, not a new trace; Draft is
|
|
1344
|
+
unchanged. Unset or all 1 traces exactly as before.
|
|
1345
|
+
- **World matte**: any layer's `trackMatte` can take its matte from the Scene's objects instead of another layer: `"trackMatte":
|
|
1346
|
+
{ "sourceId": "<the Scene layer's item id>", "mode": "alpha", "objects": ["bottle"] }` (or `"materials": ["glass"]`, or both). The
|
|
1347
|
+
layer then shows only where those objects are in the Scene's picture (an object covers everything under it), `"alphaInverted"`
|
|
1348
|
+
everywhere but there, with soft edges where they cover part of a pixel, in Draft and Final (Final's from its samples). Unlike an
|
|
1349
|
+
ordinary matte the Scene stays in the picture. Put the matted layer above the Scene layer: on a `cameraLocked` channel it lies flat
|
|
1350
|
+
over the picture (a title, a picture on a screen); on an ordinary channel it stands in the 3D space and the Scene's depth still hides it
|
|
1351
|
+
where the set is in front of its plane. A `cameraLocked` channel with only `cameraLocked` channels under it (the Scene's own channel
|
|
1352
|
+
does not count) is the frame's background plate and goes under the Scene, matte or not: keep an ordinary channel below it. Up to three different object sets per project; each costs one flat draw a frame in
|
|
1353
|
+
Draft and nothing to the trace but a few bytes a pixel. Use it for a title that passes behind a product (`alphaInverted` on the
|
|
1354
|
+
product), a picture or video shown only on one object, or a grade on one object (a copy of the footage graded and matted to it).
|
|
1355
|
+
|
|
1356
|
+
```json
|
|
1357
|
+
"render": { "mode": "final", "spp": 128, "passes": { "show": "mask", "mask": { "objects": ["bottle", "cap"] } } },
|
|
1358
|
+
"look": { "passMix": { "specular": 1.4 } }
|
|
1359
|
+
```
|
|
1360
|
+
|
|
1361
|
+
**The Rig's backdrop** (`rig.cyclorama`) stands in the same world: its floor is at y = −0.42 × the composition height / 1000 metres
|
|
1362
|
+
(−0.454 m at 1080p), centred on x = z = 0, and its sizes are multiples of the composition height (`width` 3.4 is 3.67 m at 1080p). A
|
|
1363
|
+
scene built around y = 0 (a table top, a product) is best with `"cyclorama": { "shape": "none" }` and its own floor or backdrop object.
|
|
1364
|
+
|
|
1365
|
+
**Rig lights** (`rig.lights[]`, one set for every 3D layer, [video-3d.md](video-3d.md#scene-rig--one-set-for-every-3d-layer)) are placed differently:
|
|
1366
|
+
around the rig origin by `az` (degrees around the vertical, measured from +Z, the camera's side, toward +X: 0 is in front of the subject
|
|
1367
|
+
toward the camera, 90 camera-right, -90 camera-left, 180 behind the subject), `elev` (degrees above the horizon, 90 overhead) and `dist`
|
|
1368
|
+
(composition pixels; one world metre is 1000). A `spot` or `area` Rig light aims at `targetX`, `targetY`, `targetZ` in pixels, with +Y up.
|
|
1369
|
+
A Rig light's `intensity` is what the subject receives, as a directional of that strength would give, whatever its distance. With
|
|
1370
|
+
`"renderer": "world"`, write the scene's own lights in `rig.scene.lights` and set `rig.lights: []`.
|
|
1371
|
+
|
|
1372
|
+
## Shadows in Draft
|
|
1373
|
+
|
|
1374
|
+
The editor's Draft preview leaves shadows out unless the Rig's `"render": { "draftShadows": true }` (next to `renderer` and `scene`) asks for them, because they are about half of what a big frame costs, so a shadow missing from the preview is not a fault. Renders and stills always have them, in Draft and Final. A light with a pattern keeps its shadow in the preview, because its shadow map draws the pattern. Without shadows the preview still lets the sky light a room only through its openings, and lights an open set's backdrop from what stands in front of it, as renders do: a room lit through its window is as bright in the preview as in a render, shadows aside.
|
|
1375
|
+
|
|
1376
|
+
## Fog and haze
|
|
1377
|
+
|
|
1378
|
+
`rig.scene.fog` fills the air of the set with an even medium that scatters light: dust in a room, haze, a smoky club. Beams show where
|
|
1379
|
+
light passes through it (a spot's cone, sun shafts through a window, a lamp's glow) and the shadows of what stands in the light run
|
|
1380
|
+
through the beams; things far away fade toward the fog's own light. Final traces it (the light it scatters from every kind of light and
|
|
1381
|
+
from the environment, the shadows in the beams, what it takes from the light of what is behind it, and the fog's own light scattered
|
|
1382
|
+
again); Draft draws the same fog through its lights, so the beams and the haze are there in the preview and in a Draft render.
|
|
1383
|
+
|
|
1384
|
+
```json
|
|
1385
|
+
"fog": { "density": 0.1, "color": "#ece6dc", "anisotropy": 0.5, "min": [-2, 0, -2], "max": [2, 2.6, 2] }
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
- `density` [0, none]: how thick, per metre. A metre of it takes 1 − e^(−density) of the light that crosses it: 0.02 to 0.05 a faint
|
|
1389
|
+
haze, 0.08 to 0.15 a dusty room where a sun shaft reads, 0.3 and up a smoky club (the far wall of a 4 m room is then a third as bright).
|
|
1390
|
+
- `color` [`#ffffff`]: the share of the light it takes that it scatters back out, per channel. White is bright fog; darker absorbs more
|
|
1391
|
+
(smoke); a tint colours the beams and the haze.
|
|
1392
|
+
- `anisotropy` [0]: which way it scatters. 0 evenly; 0.3 to 0.7 forward, as dust and haze do: a beam glows when the camera looks along it
|
|
1393
|
+
toward the light and is faint from the side. Below 0, back toward the light.
|
|
1394
|
+
- `bounces` [2], Final only: how deep into a light path it still scatters. 1 lights it by the light that reaches it (shafts, cones, a
|
|
1395
|
+
lamp's glow); 2 to 4 adds its own light scattered again, which thick fog needs to look soft and bright. More costs time.
|
|
1396
|
+
`rig.render.volumeBounces` caps the scatters themselves, for the fog and the sims' smoke alike ([render](#turn-it-on-and-write-a-scene)).
|
|
1397
|
+
- `min`, `max`: the corners of its box, metres. Left out, the box round everything in the scene. In a room give the room's inside, so
|
|
1398
|
+
the sky outside its window stays clear and the sun reaching the window is not dimmed on the way.
|
|
1399
|
+
- Beams need a dark set and a strong, small light: a `spot` (its cone), a `sun` through an opening (a window, a gap in a roof, the trees),
|
|
1400
|
+
or the environment's own sun through a window. A soft `area` light and an even sky light the fog evenly: haze, no beams. Lights' shadows
|
|
1401
|
+
are what draw the shafts, so leave `castShadow` on.
|
|
1402
|
+
- It costs little: a Final still of a room in fog at 1080p and 64 samples takes about as long as without it (0 to 0.5 s more; the first
|
|
1403
|
+
one of a scene a second or two more while its shaders compile); Draft adds 1 to 4 ms a frame. A scene without `fog` costs nothing.
|
|
1404
|
+
- Draft scatters the light of every light once, with each light's shadows, and adds the environment's light where the set leaves the sky
|
|
1405
|
+
open. It leaves out light scattered twice and light that surfaces throw back into the fog: the darkest air around a beam, and a floor
|
|
1406
|
+
under a bright beam, are darker in Draft than in Final. Judge thick fog in Final.
|
|
1407
|
+
- A solid see-through object (a glass ball, a bottle, any closed glass) keeps the fog out: inside it is its own medium, so clear
|
|
1408
|
+
glass stays clear and a tinted one tints by its own `attenuationColor` (Final; Draft draws the fog behind glass from where the eye's ray
|
|
1409
|
+
leaves it). A thin `pane` or a thin-walled glass is a surface, not a room of its own: the fog goes on through it.
|
|
1410
|
+
- Glass in front of fog, smoke or fire shows them through it in Draft as in Final (bent and tinted by a solid glass as the rest is).
|
|
1411
|
+
- Over a see-through background (no `opaque`) fog and smoke cover what they hide and no more: the picture's alpha is 1 − their
|
|
1412
|
+
transmittance along each ray, so a render with alpha lays them over other footage exactly.
|
|
1413
|
+
- Smoke and fire from a sim are their own ([Smoke and fire](#smoke-and-fire)) and stand in the fog together with it.
|
|
1414
|
+
|
|
1415
|
+
## Smoke and fire
|
|
1416
|
+
|
|
1417
|
+
Smoke, fire and explosions are a sim's gas: `rig.scene.sims` with a recipe (`pulse_explosion`, `campfire`, `smoke_column`) or a
|
|
1418
|
+
`sim/1` graph with a `gas` block. They render in Draft and Final, push particles, and repeat exactly on every scrub and render. Final
|
|
1419
|
+
traces them: smoke lit and shaded by every light and casting its shadow, fire glowing and lighting the set, both seen in mirrors and
|
|
1420
|
+
through glass. Final traces the first four gases of a scene; a fifth and later one is laid over the traced picture as
|
|
1421
|
+
Draft draws it (not lit by the scene's lights, not in mirrors or through glass, no shadow), and the still's `scene.warnings` names it:
|
|
1422
|
+
put its gas into one of the first four sims. Everything is in sim.md (GreenLight Dash only).
|
|
1423
|
+
|
|
1424
|
+
```json
|
|
1425
|
+
"sims": [{ "recipe": "campfire", "at": [0, 0, 0], "size": 0.3 }]
|
|
1426
|
+
```
|
|
1427
|
+
|
|
1428
|
+
`volumes` now holds only a `.blend` import's baked smoke and fire (`baked`), played back from its file; live `volumes` entries
|
|
1429
|
+
(`preset`, `sources`) are gone and are ignored.
|
|
1430
|
+
|
|
1431
|
+
## Particles: snow, dust, smoke, sparks, bokeh, stars
|
|
1432
|
+
|
|
1433
|
+
Particles in the world are a sim's sets (sim.md (GreenLight Dash only)), drawn as what they are, never added up into light (a dense cloud stays as
|
|
1434
|
+
bright as the light that reaches it):
|
|
1435
|
+
- **lit cards** (`look: "card"`): sprites facing the camera with a texture (built-in `smoke`, `spark`, `dust`, `snow`, `leaf`, `drop`, made by
|
|
1436
|
+
the texture graph; or the agent's own graph, or the user's picture or flipbook sheet), lit and shadowed by the scene's lights, letting light
|
|
1437
|
+
through from behind, blended back to front;
|
|
1438
|
+
- **into a volume** (`look: "volume"`): a cloud of puffs splatted each frame into a box of density that renders as a sim's gas does (Final:
|
|
1439
|
+
lit by every light, shading itself, shadowing the set);
|
|
1440
|
+
- **glowing points** (a round look with an `emissive` material): in Final they are lights, so sparks and embers light the floor round them;
|
|
1441
|
+
`rig.look.bloom` makes them bloom.
|
|
1442
|
+
|
|
1443
|
+
Recipes: `snow`, `dust_in_beam` (with a beam of light and the scene's `fog` for the air), `smoke`, `sparks_in_wind`, `embers`, `bokeh`
|
|
1444
|
+
(with the camera's `fStop` and `focus`: Final's real out-of-focus discs), `stars`.
|
|
1445
|
+
|
|
1446
|
+
```json
|
|
1447
|
+
"sims": [{ "recipe": "snow", "at": [0, 3, 0], "area": [5, 0.1, 4], "count": 7000 }, { "recipe": "embers", "at": [0, 0.05, 0] }]
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1450
|
+
## Cloth and soft bodies
|
|
1451
|
+
|
|
1452
|
+
Cloth, hair, sand and soft bodies are a sim's XPBD pieces (sim.md (GreenLight Dash only) §2b): `rig.scene.sims` with a `cloth`, `hair`, `grains` or
|
|
1453
|
+
`softbody` maker, or a recipe (`cloth_drop_on_sphere`, `flag_in_explosion_wind`, `grains_on_cloth`, `hair_in_wind`). They run on the GPU,
|
|
1454
|
+
collide with themselves and with each other, and a cloth made from an object (`"mesh": "<object id>"`) takes that object's place. An
|
|
1455
|
+
object's own `sim` field is gone (it is ignored): write the cloth as a sim. To settle a cloth into a shape that never moves, use the
|
|
1456
|
+
`drape` or `inflate` graph ops.
|
|
1457
|
+
|
|
1458
|
+
## Water, sand, snow and goo
|
|
1459
|
+
|
|
1460
|
+
Liquids, sand, snow and goo are a sim's MPM set (sim.md (GreenLight Dash only) §2d): `rig.scene.sims` with `fill`, `pour` and an `mpm` op, or a recipe
|
|
1461
|
+
(`water_splash_with_debris`, `water_pour`, `sand_pour_pile`, `snowball_smash`, `goo_drop`). Every material shares one grid on the GPU, so
|
|
1462
|
+
they push each other; the sim's colliders, scene objects (`mpm.objects`) and its rigid pieces stand in the way, and the liquid pushes the
|
|
1463
|
+
pieces back (a crate floats). Water and goo draw as a real surface (refracting in Draft, traced as a dielectric in Final), sand as grains.
|
|
1464
|
+
The old `matter` field is gone and is ignored.
|
|
1465
|
+
|
|
1466
|
+
## Rigid bodies
|
|
1467
|
+
|
|
1468
|
+
Objects that fall, hit and stack. Add `rigid` to any object. On a `model3d` layer, `model3dConfig.physics: "falls"` does the same, and `"solid"` makes it a fixed body that others hit ([video-3d.md](video-3d.md)). They are bodies of the scene's own rigid sim (the sims' rigid solver, sim.md (GreenLight Dash only) §2c, where pieces, fracture, glue and swarms live too).
|
|
1469
|
+
|
|
1470
|
+
```json
|
|
1471
|
+
{
|
|
1472
|
+
"physics": { "gravity": [0, -9.8, 0], "floor": 0 },
|
|
1473
|
+
"objects": [
|
|
1474
|
+
{ "id": "ramp", "material": "steel", "at": [-2.5, 0.9, 0], "rot": [0, 0, -22], "graph": [{ "op": "box", "size": [3.6, 0.14, 2] }], "rigid": { "fixed": true, "shape": "box" } },
|
|
1475
|
+
{ "id": "crate", "material": "wood", "at": [1, 0.25, 0], "graph": [{ "op": "box", "size": [0.5, 0.5, 0.5] }], "rigid": { "shape": "box", "density": 0.25 } },
|
|
1476
|
+
{ "id": "ball", "material": "steel", "at": [-4, 2.5, 0], "graph": [{ "op": "sphere", "radius": 0.26 }], "rigid": { "density": 8, "start": 0.3, "bounce": 0.1 } }
|
|
1477
|
+
]
|
|
1478
|
+
}
|
|
1479
|
+
```
|
|
1480
|
+
|
|
1481
|
+
- `rigid: true` falls with the defaults. Options: `fixed` (never moves, others hit it), `keyed` (follows the object's keys and pushes what is in the way), `shape`, `mass` or `density`, `bounce` [0.25], `friction` [0.6], `velocity`, `spin`, `start` (seconds to hold it in the air).
|
|
1482
|
+
- `shape`: `sphere` (the default for a sphere), `hull` (the default otherwise: the object's outline wrapped tight, so a C shape collides as a solid lump), `box`, or `mesh` (exact, and only for `fixed` things). Use `box` and `sphere` when the object is one: they are cheaper and steadier.
|
|
1483
|
+
- `physics.fps`: the steps a second the physics takes (4 substeps each, up to 240), the scene's frame rate unless set. A fast collision (a ball hitting the floor at 10 m/s) wants more.
|
|
1484
|
+
- `physics.floor` is the ground's height, or `null` for none. With no `physics` block, the editor puts the floor at the set's floor and uses a gravity of `[0, -5, 0]`.
|
|
1485
|
+
- The fall is a sim: checkpoints make seeking back exact, and a render gets the same fall every time.
|
|
1486
|
+
- A layer with `physics` on starts from wherever the layer stands. Moving the layer starts the fall again, and keyframes on its position are not followed.
|
|
1487
|
+
|
|
1488
|
+
## Motion blur
|
|
1489
|
+
|
|
1490
|
+
With `"motionBlurEnabled": true` ([video-projects.md](video-projects.md#motion-blur-render-only)) a render blurs a frame when something in the Scene moves across its shutter, not only a layer's transform:
|
|
1491
|
+
|
|
1492
|
+
- a scene object's, a flat layer's (`layers2d`) or `scene.camera`'s keys (`at`, `rot`, `scale`; the camera's `at`, `target`, `fov`, `lens`, `focus`, `fStop`), and a rigged object's `pose` (its clips, keys and targets);
|
|
1493
|
+
- what runs by itself: bodies (`rigid`, and model layers with `physics: "falls"`) until they rest, `sims` while their clip runs (gas, cloth and the rest of XPBD included, liquids too), baked smoke and fire, and a `.blend` import's baked playback while its frames run (a baked track that holds still counts as still);
|
|
1494
|
+
- the Rig's own keyframes (`sc:` and `scc:` tracks: lights, the backdrop, the environment);
|
|
1495
|
+
- 3D Text letters a Text Animator moves: a keyed track while it changes, a Time cascade while a letter is in flight, Flow, Wiggle, Scramble and a blinking caret (the same rule holds for 2D text, flat letters in the world included);
|
|
1496
|
+
- a model layer's own GLB clips while they play and the pose changes.
|
|
1497
|
+
|
|
1498
|
+
A frame where all of it rests renders once, as sharp as with blur off.
|
|
1499
|
+
|
|
1500
|
+
In **Final** a frame whose motion is all inside the world is traced **once**: each camera sample takes its own time inside the shutter
|
|
1501
|
+
(spread evenly over it, pixel by pixel), and everything stands where it is at that time, so a moving object or a camera move blurs as a
|
|
1502
|
+
continuous smear, in about the time of a sharp frame. What the world traces that way, and what still renders the frame as an
|
|
1503
|
+
accumulation of sub-frames (each one a full trace):
|
|
1504
|
+
|
|
1505
|
+
- traced once: scene objects (`at`, `rot`, `scale` keys, parents included), lit flat layers (`layers2d` with `receiveShadow`) and
|
|
1506
|
+
`scene.camera`'s `at` / `target` keys, or the Camera layer's move when it films the Scene; a zoom (`fov`, `lens`, the Camera layer's
|
|
1507
|
+
zoom), a focus pull (`focus`) and a change of aperture (`fStop`, the Camera layer's aperture) on a perspective lens; what changes shape:
|
|
1508
|
+
a rigged object's `pose` and a skinned model, shape keys, a sim's cloth and soft bodies (each vertex at the shutter's opening, middle and
|
|
1509
|
+
close); `sims`: their particles (spheres, points, sparks, cards, birds, models, and cubes, chunks and leaves) each straight along its own
|
|
1510
|
+
velocity, birds beating their wings through the shutter (each at its own beats a second), a gas's smoke and fire carried along its own
|
|
1511
|
+
flow, in a dense box or on bricks (the gas an emitter puts in within the shutter stays at the emitter, and the burn's heat and smoke are
|
|
1512
|
+
added for each sample's time; liquids stand as at the frame); bodies (`rigid`, model layers with `physics: "falls"`) as the solver takes
|
|
1513
|
+
them through the shutter, step by step (one that hits the floor inside the shutter bounces in the blur); lights that move (one that follows a moving object, one inside a model) and the
|
|
1514
|
+
Rig's own keys on its lights (`sc:<lid>:intensity` and the light's other numbers, `scc:<lid>:col`: each sample sees the light's
|
|
1515
|
+
colour, strength, place, size and cone at its own time); moving glowing surfaces (`emission`, a `screen`: their light comes from where
|
|
1516
|
+
they are at each sample's time); translucent sheets, and subsurface bodies (the light's walk inside goes through the body where it
|
|
1517
|
+
stands, and as it is bent, at each sample's time: a wax or skin figure that swings its arm too); a shadow catcher over footage (a Scene
|
|
1518
|
+
put into footage: the shadow and the objects' coverage are the shutter's); the model layers the world draws (their keys, their GLB clips,
|
|
1519
|
+
their `pose`, their morphs); a `.blend` import's baked tracks (an object's matrix at each frame), baked shapes (each point between its
|
|
1520
|
+
frames), remade meshes (each point toward the surface of the frames around), baked grains and flocks (each copy along its move between
|
|
1521
|
+
frames) and `volumes` (baked smoke and fire, marched at eight times across the shutter and averaged); the Rig's keys on its environment
|
|
1522
|
+
(`sc:env:intensity`, `sc:env:rotY`), an Ambient's or a Hemisphere's colour and strength, and its backdrop's colour (`scc:cyc:col`): each
|
|
1523
|
+
sample sees the map and the paint as they are at its time; an aperture that opens from a pinhole (`fStop` 0: the frame is traced through
|
|
1524
|
+
the widest aperture of its shutter, each sample's point on the lens scaled to its own time's);
|
|
1525
|
+
- accumulated: the Rig's keys on the environment's map, its exposure or tint, the backdrop's shape or opacity, or a light switched on or
|
|
1526
|
+
off; an orthographic or tilted lens that changes; keyed texture graphs; caustics; unlit `layers2d` cards or flat letters
|
|
1527
|
+
while the camera moves or zooms; a model layer the world does not draw (one of the six effects live, a blur, a flat effect), a model
|
|
1528
|
+
layer moved by a parent or a motion track; and any other layer of the project that moves on that frame. The footage is held at the
|
|
1529
|
+
frame's own picture.
|
|
1530
|
+
|
|
1531
|
+
Where the Scene lets the layers below show through (no `opaque` environment, no colour `background`), a moving edge over that sky is
|
|
1532
|
+
see-through in proportion to how much of the shutter something covers it, and it goes over the layers below in linear light: the frame is
|
|
1533
|
+
what the many sub-frames, each laid over them and averaged as light, give (an arm sweeping over dark footage keeps its brightness; laid
|
|
1534
|
+
in display values it came out about a third darker). The same over a gradient, a pattern or a picture `background` that fills the frame. A
|
|
1535
|
+
frame without motion, and a moving frame's pixels the world covers whole, go over them exactly as before.
|
|
1536
|
+
|
|
1537
|
+
A shadow catcher's shadow (a `catcher` object, a Rig backdrop in "Shadows only", a Scene put into footage) is the share of the light the
|
|
1538
|
+
objects take from the floor, and it is taken from the footage, or the project's background, in linear light: a shadow that takes half the
|
|
1539
|
+
light leaves half of it (laid in display values it left about a fifth, so shadows came out far darker than real shadows in the same shot).
|
|
1540
|
+
|
|
1541
|
+
In **Draft** a frame whose motion is all inside the world draws the world at each sub-frame's time and averages their light before the
|
|
1542
|
+
film look, as Final's trace does, so Draft's blur and Final's agree in direction, length and look (a fast object's tails fade alike);
|
|
1543
|
+
the Rig's keyed lights, the model layers the world draws, the bodies and the birds' wingbeats stand where they are at each sub-frame's
|
|
1544
|
+
time; over a see-through sky the moving edges' coverage is the shutter's and goes over the layers below in linear light, as in Final. A Draft Scene with gas, `volumes`, splats, effects on
|
|
1545
|
+
objects, flat letters or a shadow catcher, or a frame where another layer moves too, averages its sub-frames as pictures, as a 2D
|
|
1546
|
+
project does. A sim's particles in Draft are drawn at the
|
|
1547
|
+
time drawn (moved on by their velocity from the sim's own frame), so the sub-frames between two sim frames see them move. A static frame
|
|
1548
|
+
traces exactly as with blur off.
|