@genex-ai/cli-demo 0.93.0-dev.247 → 0.94.0-dev.249
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/dist/index.js +25 -4
- package/package.json +1 -1
- package/templates/skills/genex-ai-model/SKILL.md +3 -2
- package/templates/skills/genex-ai-skybox/SKILL.md +3 -3
- package/templates/skills/genex-game-director/SKILL.md +321 -411
- package/templates/skills/genex-game-director/references/design-contract.md +130 -179
- package/templates/skills/genex-game-director/references/routing-map.md +242 -362
- package/templates/skills/genex-threejs-exposure-color-grading/SKILL.md +3 -7
- package/templates/skills/genex-threejs-procedural-assets/SKILL.md +112 -0
- package/templates/skills/genex-threejs-procedural-materials/SKILL.md +3 -7
- package/templates/skills/genex-threejs-procedural-vfx/SKILL.md +6 -11
- package/templates/skills/genex-threejs-shadow-systems/SKILL.md +2 -3
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +0 -4
- package/templates/skills/genex-threejs-atmosphere-aerial-perspective/SKILL.md +0 -46
- package/templates/skills/genex-threejs-atmosphere-aerial-perspective/references/atmosphere.md +0 -213
- package/templates/skills/genex-threejs-bloom/SKILL.md +0 -44
- package/templates/skills/genex-threejs-bloom/references/bloom.md +0 -187
- package/templates/skills/genex-threejs-exposure-color-grading/references/exposure-grading.md +0 -205
- package/templates/skills/genex-threejs-game-content/SKILL.md +0 -198
- package/templates/skills/genex-threejs-game-content/references/content-tables.md +0 -269
- package/templates/skills/genex-threejs-image-pipeline/SKILL.md +0 -56
- package/templates/skills/genex-threejs-image-pipeline/references/image-pipeline.md +0 -197
- package/templates/skills/genex-threejs-lighting-design/SKILL.md +0 -144
- package/templates/skills/genex-threejs-lighting-design/references/light-recipes.md +0 -137
- package/templates/skills/genex-threejs-open-world/SKILL.md +0 -149
- package/templates/skills/genex-threejs-open-world/references/terrain-streaming.md +0 -215
- package/templates/skills/genex-threejs-precipitation-surfaces/SKILL.md +0 -59
- package/templates/skills/genex-threejs-precipitation-surfaces/references/precipitation-surfaces.md +0 -181
- package/templates/skills/genex-threejs-procedural-architecture/SKILL.md +0 -50
- package/templates/skills/genex-threejs-procedural-architecture/references/architecture-systems.md +0 -509
- package/templates/skills/genex-threejs-procedural-fields/SKILL.md +0 -61
- package/templates/skills/genex-threejs-procedural-fields/references/field-systems.md +0 -232
- package/templates/skills/genex-threejs-procedural-geometry/SKILL.md +0 -39
- package/templates/skills/genex-threejs-procedural-geometry/references/mesh-systems.md +0 -202
- package/templates/skills/genex-threejs-procedural-materials/references/material-systems.md +0 -198
- package/templates/skills/genex-threejs-procedural-planets/SKILL.md +0 -48
- package/templates/skills/genex-threejs-procedural-planets/references/planet-systems.md +0 -498
- package/templates/skills/genex-threejs-procedural-vegetation/SKILL.md +0 -52
- package/templates/skills/genex-threejs-procedural-vegetation/references/vegetation-systems.md +0 -314
- package/templates/skills/genex-threejs-procedural-vfx/references/vfx-systems.md +0 -218
- package/templates/skills/genex-threejs-raymarched-space-effects/SKILL.md +0 -37
- package/templates/skills/genex-threejs-raymarched-space-effects/references/space-effects.md +0 -194
- package/templates/skills/genex-threejs-screen-space-ambient-occlusion/SKILL.md +0 -35
- package/templates/skills/genex-threejs-screen-space-ambient-occlusion/references/ambient-occlusion.md +0 -441
- package/templates/skills/genex-threejs-spectral-ocean/SKILL.md +0 -52
- package/templates/skills/genex-threejs-spectral-ocean/references/spectral-ocean.md +0 -473
- package/templates/skills/genex-threejs-temporal-surfaces/SKILL.md +0 -41
- package/templates/skills/genex-threejs-temporal-surfaces/references/temporal-surfaces.md +0 -207
- package/templates/skills/genex-threejs-visual-validation/references/visual-validation.md +0 -427
- package/templates/skills/genex-threejs-volumetric-clouds/SKILL.md +0 -49
- package/templates/skills/genex-threejs-volumetric-clouds/references/volumetric-clouds.md +0 -579
- package/templates/skills/genex-threejs-water-optics/SKILL.md +0 -57
- package/templates/skills/genex-threejs-water-optics/references/water-optics.md +0 -195
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# Curved-ray numerical integrators
|
|
2
|
-
|
|
3
|
-
Use this reference for an RK4 wormhole integrator and an artistic inverse-square curved-ray accretion volume, including state reduction, disk accumulation, background lensing, and numerical diagnostics.
|
|
4
|
-
|
|
5
|
-
## Contents
|
|
6
|
-
|
|
7
|
-
- Wormhole state reduction
|
|
8
|
-
- Wormhole RK4 integration
|
|
9
|
-
- Universe selection
|
|
10
|
-
- accretion volume screen-volume integration
|
|
11
|
-
- Disk density and color
|
|
12
|
-
- Background lensing
|
|
13
|
-
- Observed defects and boundaries
|
|
14
|
-
- Diagnostics
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
## Wormhole state reduction
|
|
18
|
-
|
|
19
|
-
The wormhole renderer uses a spherically symmetric throat model. It reduces
|
|
20
|
-
each 3D ray to a two-dimensional integration state:
|
|
21
|
-
|
|
22
|
-
```text
|
|
23
|
-
y.x = signed radial coordinate l
|
|
24
|
-
y.y = radial momentum pL
|
|
25
|
-
impact parameter b = length(cross(rayOrigin, rayDirection))
|
|
26
|
-
throat radius Rth = 1.2
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
It constructs an orbital plane:
|
|
30
|
-
|
|
31
|
-
```text
|
|
32
|
-
normal = normalize(cross(origin, direction))
|
|
33
|
-
u = normalize(origin)
|
|
34
|
-
v = cross(normal, u)
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Near-radial rays use fallback axes to avoid a zero cross product.
|
|
38
|
-
|
|
39
|
-
Initial signed coordinate:
|
|
40
|
-
|
|
41
|
-
```text
|
|
42
|
-
l = sqrt(max(length(origin)^2 - Rth^2, 0.001))
|
|
43
|
-
pL = dot(normalize(origin), direction)
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Wormhole RK4 integration
|
|
47
|
-
|
|
48
|
-
The derivative is:
|
|
49
|
-
|
|
50
|
-
```text
|
|
51
|
-
r2 = l^2 + Rth^2
|
|
52
|
-
dl/ds = r2 * pL
|
|
53
|
-
dpL/ds = b^2 * l / r2
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The shader runs fourth-order Runge–Kutta with:
|
|
57
|
-
|
|
58
|
-
```text
|
|
59
|
-
maximum iterations = 920
|
|
60
|
-
base step = 0.0042
|
|
61
|
-
per-ray step jitter = +/- 0.00045
|
|
62
|
-
escape distance = abs(l) > 40
|
|
63
|
-
azimuth accumulation = step * b
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
On escape:
|
|
67
|
-
|
|
68
|
-
```text
|
|
69
|
-
finalDirection =
|
|
70
|
-
normalize(u * cos(phi) + v * sin(phi))
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
The sign of final `l` selects which exterior universe is visible. Failure to
|
|
74
|
-
escape renders a bright fallback color, making iteration-cap pixels observable.
|
|
75
|
-
|
|
76
|
-
This is materially stronger than a UV swirl because the final environment
|
|
77
|
-
direction comes from numerical integration.
|
|
78
|
-
|
|
79
|
-
## Universe selection
|
|
80
|
-
|
|
81
|
-
The two exterior universes are independent procedural directional fields. Both
|
|
82
|
-
use five-octave FBM, animated coordinate drift, broad/fine structure, and
|
|
83
|
-
different plane orientation.
|
|
84
|
-
|
|
85
|
-
Sample those fields only after integration. Lensing must change the lookup
|
|
86
|
-
direction rather than distort an already rendered screen image.
|
|
87
|
-
|
|
88
|
-
A small direction-hashed grain of amplitude `0.01` reduces visible gradient
|
|
89
|
-
banding.
|
|
90
|
-
|
|
91
|
-
## accretion volume screen-volume integration
|
|
92
|
-
|
|
93
|
-
The black-hole effect is evaluated on a sphere surrounding the effect. Defaults:
|
|
94
|
-
|
|
95
|
-
```text
|
|
96
|
-
iterations = 128
|
|
97
|
-
step = 0.0071
|
|
98
|
-
ray jitter = 0.01
|
|
99
|
-
bending power = 0.3
|
|
100
|
-
core radius = 0.13
|
|
101
|
-
disk half-width = 0.03
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Per step:
|
|
105
|
-
|
|
106
|
-
```text
|
|
107
|
-
r = length(rayPosition)
|
|
108
|
-
steerMagnitude = step * power / r^2
|
|
109
|
-
steerRange = remapClamped(r, 1 -> 0.5, 0 -> 1)
|
|
110
|
-
newDirection = normalize(direction - radial * steerMagnitude * steerRange)
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
The ray direction is bent toward the center only inside the configured range.
|
|
114
|
-
Unlike the wormhole, this is an artistic inverse-square steering field, not a
|
|
115
|
-
validated metric geodesic.
|
|
116
|
-
|
|
117
|
-
## Disk density and color
|
|
118
|
-
|
|
119
|
-
Disk coordinates rotate around the local Z axis with radius and time:
|
|
120
|
-
|
|
121
|
-
```text
|
|
122
|
-
rotation phase = radialDistance * 4.27 - time * 0.1
|
|
123
|
-
noise UV = rotatedPosition * 2
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
A repeated deep-noise texture is multiplied by a quadratic band across
|
|
127
|
-
`[-width, 0, +width]`. Radial distance, noise value, and a nearby noise sample
|
|
128
|
-
produce a ramp coordinate.
|
|
129
|
-
|
|
130
|
-
The three-point color ramp is:
|
|
131
|
-
|
|
132
|
-
```text
|
|
133
|
-
white-hot at 0.06
|
|
134
|
-
gold at 0.33
|
|
135
|
-
dark amber at 1.0
|
|
136
|
-
emission scale 1.95
|
|
137
|
-
additional emission color (1.0, 0.72, 0.26)
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
The central sphere below `originRadius` is black. Disk opacity accumulates
|
|
141
|
-
front-to-back into `alphaAcc`; color accumulates using remaining transmittance.
|
|
142
|
-
|
|
143
|
-
## Background lensing
|
|
144
|
-
|
|
145
|
-
After the fixed loop, the final bent direction samples a deterministic
|
|
146
|
-
equirectangular star texture generated from `5200` seeded stars on a sphere.
|
|
147
|
-
|
|
148
|
-
```text
|
|
149
|
-
final = accumulated disk color
|
|
150
|
-
+ remaining transmittance * star environment
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
The deterministic star field is important: lensing motion can be compared
|
|
154
|
-
without random stars moving between runs.
|
|
155
|
-
|
|
156
|
-
## Observed defects and boundaries
|
|
157
|
-
|
|
158
|
-
- The demonstrated accretion-volume loop advances `rayPosition` twice per
|
|
159
|
-
iteration while its steering magnitude uses a single `step`. Treat the
|
|
160
|
-
effective distance step as `2 * step`, or remove the duplicate advance and
|
|
161
|
-
retune the complete density-and-bending system explicitly.
|
|
162
|
-
- accretion volume has no early exit and no termination IDs; every pixel pays the full
|
|
163
|
-
iteration count.
|
|
164
|
-
- Its disk is detected by local band density at samples, not by a continuous
|
|
165
|
-
plane-crossing test. A large step can skip a thin disk.
|
|
166
|
-
- The artistic inverse-square steering must not be described as general
|
|
167
|
-
relativity.
|
|
168
|
-
- The wormhole uses a fixed high iteration cap and per-ray step jitter but has
|
|
169
|
-
no CPU reference-ray tests.
|
|
170
|
-
- Both effects render on bounded proxy geometry; coordinate transforms must be
|
|
171
|
-
verified if the proxy is nonuniformly scaled or moved far from the origin.
|
|
172
|
-
- The star texture is finite-resolution and can alias under extreme
|
|
173
|
-
magnification.
|
|
174
|
-
|
|
175
|
-
## Diagnostics
|
|
176
|
-
|
|
177
|
-
Expose:
|
|
178
|
-
|
|
179
|
-
```text
|
|
180
|
-
wormhole l and pL
|
|
181
|
-
impact parameter and orbital-plane basis
|
|
182
|
-
RK4 step count and escaped/capped state
|
|
183
|
-
final exterior side and environment direction
|
|
184
|
-
accretion volume radius and steering magnitude
|
|
185
|
-
effective traveled distance
|
|
186
|
-
disk band, noise, ramp coordinate, and local alpha
|
|
187
|
-
accumulated alpha and remaining transmittance
|
|
188
|
-
core-hit mask
|
|
189
|
-
final bent background direction
|
|
190
|
-
NaN/invalid-state mask
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
Add CPU reference rays for the wormhole before claiming physical parity, and a
|
|
194
|
-
continuous disk-crossing variant before increasing accretion volume’s step size.
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: genex-threejs-screen-space-ambient-occlusion
|
|
3
|
-
description: Implement screen-space ambient occlusion for Genex Three.js games. Use for GTAO-style horizon sampling, bent normals, contact grounding, depth reconstruction, bilateral upsampling, halo diagnosis, and AO that supports readable form.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Genex Three.js Screen-Space Ambient Occlusion
|
|
7
|
-
|
|
8
|
-
AO estimates missing ambient visibility. It must modulate indirect lighting, not repaint all scene color with a dark multiply.
|
|
9
|
-
|
|
10
|
-
## Workflow
|
|
11
|
-
|
|
12
|
-
1. Verify linear depth and view-space normals.
|
|
13
|
-
2. Reconstruct view position consistently.
|
|
14
|
-
3. Sample horizon visibility in a controlled radius.
|
|
15
|
-
4. Estimate AO and optional bent normal.
|
|
16
|
-
5. Denoise with depth/normal-aware filters.
|
|
17
|
-
6. Apply to indirect diffuse and environment response.
|
|
18
|
-
|
|
19
|
-
Read [references/ambient-occlusion.md](references/ambient-occlusion.md).
|
|
20
|
-
|
|
21
|
-
## Failure conditions
|
|
22
|
-
|
|
23
|
-
- direct light and emission are darkened;
|
|
24
|
-
- radius is specified only in pixels;
|
|
25
|
-
- foreground silhouettes cast thick screen-space halos;
|
|
26
|
-
- depth discontinuities are blurred together;
|
|
27
|
-
- AO remains strong at distances where its world radius is subpixel;
|
|
28
|
-
- bent normals are treated as ordinary geometric normals;
|
|
29
|
-
- the implementation claims temporal accumulation even though this path has none.
|
|
30
|
-
|
|
31
|
-
## Routing boundary
|
|
32
|
-
|
|
33
|
-
This skill owns GTAO gathering, bent normals, denoising, and AO application.
|
|
34
|
-
Use `$genex-threejs-image-pipeline` only when its depth/normal buffers or pass order
|
|
35
|
-
must be coordinated with other image-space systems.
|
|
@@ -1,441 +0,0 @@
|
|
|
1
|
-
# GTAO and bent-normal pipeline
|
|
2
|
-
|
|
3
|
-
Use this reference for a bounded-cost WebGPU/TSL ambient-visibility pass with half-resolution horizon integration, bent normals, bilateral reconstruction, and directional ambient tint.
|
|
4
|
-
|
|
5
|
-
> **Renderer note:** this reference assumes `WebGPURenderer` + TSL node materials. Check the project's actual renderer first — the Genex scaffold ships vanilla WebGL three.js. On WebGL, adapt the technique with standard materials / `EffectComposer` passes or pick a simpler alternative; never switch renderers mid-project. Either way the effect obeys the device tier (`$genex-threejs-adaptive-quality`): expensive passes are desktop-tier, and on WebGPU the per-target MSAA sample count is a runtime knob the governor may drive.
|
|
6
|
-
|
|
7
|
-
## Contents
|
|
8
|
-
|
|
9
|
-
1. Gather budget and depth convention
|
|
10
|
-
2. World-radius projection and horizon integration
|
|
11
|
-
3. Bent-normal encoding
|
|
12
|
-
4. Bilateral reconstruction
|
|
13
|
-
5. Indirect-light composite
|
|
14
|
-
6. Implementation defects, adaptation, and diagnostics
|
|
15
|
-
|
|
16
|
-
## 1. Preserve the actual budget
|
|
17
|
-
|
|
18
|
-
The gather uses:
|
|
19
|
-
|
|
20
|
-
```text
|
|
21
|
-
resolution scale 0.5 × 0.5
|
|
22
|
-
slices 2
|
|
23
|
-
steps per side 4
|
|
24
|
-
sides per slice 2
|
|
25
|
-
depth taps 16 per half-resolution pixel
|
|
26
|
-
target RGBA16F
|
|
27
|
-
RGB bent direction encoded to [0, 1]
|
|
28
|
-
A scalar visibility, 1 = open
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Half linear resolution means one quarter of full-resolution fragments.
|
|
32
|
-
|
|
33
|
-
The implementation targets an approximately `2 ms` budget by combining:
|
|
34
|
-
|
|
35
|
-
- half-resolution gather;
|
|
36
|
-
- few slices;
|
|
37
|
-
- interleaved-gradient-noise rotation;
|
|
38
|
-
- direct UV marching;
|
|
39
|
-
- one view-position reconstruction per tap;
|
|
40
|
-
- sky early-outs in gather and composite.
|
|
41
|
-
|
|
42
|
-
Do not increase slices first. Validate whether the bilateral pass and stable
|
|
43
|
-
rotation already remove directional structure.
|
|
44
|
-
|
|
45
|
-
## 2. Preserve the depth convention
|
|
46
|
-
|
|
47
|
-
The implementation uses reversed depth:
|
|
48
|
-
|
|
49
|
-
```text
|
|
50
|
-
sky threshold 0.000001
|
|
51
|
-
maximum reconstruction 0.999999
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Sky is cleared to zero. Far terrain remains above the sky threshold.
|
|
55
|
-
|
|
56
|
-
Gather:
|
|
57
|
-
|
|
58
|
-
```text
|
|
59
|
-
if rawDepth <= 1e-6:
|
|
60
|
-
output visibility = 1
|
|
61
|
-
output encoded bent = encoded view normal
|
|
62
|
-
skip all 16 taps
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Composite clamps depth to `[0, 0.999999]` before linearization so sky
|
|
66
|
-
neighbours do not create extreme view-Z values.
|
|
67
|
-
|
|
68
|
-
Do not port these thresholds to a forward-depth target unchanged.
|
|
69
|
-
|
|
70
|
-
## 3. Preserve world-radius projection
|
|
71
|
-
|
|
72
|
-
Default controls:
|
|
73
|
-
|
|
74
|
-
```text
|
|
75
|
-
radius 0.5 m
|
|
76
|
-
intensity 1.0
|
|
77
|
-
power 1.6
|
|
78
|
-
thickness 0.35 m in view Z
|
|
79
|
-
bentNormalStrength 0.6
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
The horizontal projection scale is cached from:
|
|
83
|
-
|
|
84
|
-
```text
|
|
85
|
-
camera.projectionMatrix.elements[0]
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
and refreshed every frame.
|
|
89
|
-
|
|
90
|
-
World radius becomes UV reach:
|
|
91
|
-
|
|
92
|
-
```text
|
|
93
|
-
radiusUv =
|
|
94
|
-
radius
|
|
95
|
-
* projectionScaleX
|
|
96
|
-
/ max(-viewPosition.z, 0.0001)
|
|
97
|
-
* 0.5
|
|
98
|
-
|
|
99
|
-
radiusUv = clamp(radiusUv, 0.004, 0.08)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
This clamp prevents near surfaces searching half the screen and stops far
|
|
103
|
-
surfaces collapsing to a useless footprint.
|
|
104
|
-
|
|
105
|
-
Observed adaptation issue: only the X projection term is used, then one scalar
|
|
106
|
-
radius is applied to both UV axes. At unusual aspect ratios or asymmetric
|
|
107
|
-
projections, derive a `vec2` reach from both projection axes.
|
|
108
|
-
|
|
109
|
-
## 4. Rotate two horizon slices per pixel
|
|
110
|
-
|
|
111
|
-
For slice `i`:
|
|
112
|
-
|
|
113
|
-
```text
|
|
114
|
-
noise = interleavedGradientNoise(screenCoordinate)
|
|
115
|
-
angle = (i / 2 + noise) * PI
|
|
116
|
-
sliceDirection = (cos(angle), sin(angle))
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
The axis covers both positive and negative directions, so angles only span
|
|
120
|
-
`PI`, not `2 * PI`.
|
|
121
|
-
|
|
122
|
-
Step spacing:
|
|
123
|
-
|
|
124
|
-
```text
|
|
125
|
-
t = (stepIndex + noise + 0.5) / 4
|
|
126
|
-
stepUv = sliceDirection * radiusUv * t
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
The shared noise rotates slices and jitters their radial positions.
|
|
130
|
-
|
|
131
|
-
The pass has no temporal accumulation. Its stability depends on the
|
|
132
|
-
noise being screen-stable and the full-resolution spatial composite.
|
|
133
|
-
|
|
134
|
-
## 5. Keep horizon angle and distance falloff separate
|
|
135
|
-
|
|
136
|
-
For each positive and negative sample:
|
|
137
|
-
|
|
138
|
-
```text
|
|
139
|
-
delta = sampleViewPosition - centerViewPosition
|
|
140
|
-
distance = max(length(delta), 0.0001)
|
|
141
|
-
falloff = saturate(1 - distance / max(radius, 0.0001))
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Accept the sample only when:
|
|
145
|
-
|
|
146
|
-
```text
|
|
147
|
-
abs(delta.z) < thickness
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Raw horizon cosine:
|
|
151
|
-
|
|
152
|
-
```text
|
|
153
|
-
cosine = dot(delta, viewDirection) / distance
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
Apply distance falloff by mixing toward fully open:
|
|
157
|
-
|
|
158
|
-
```text
|
|
159
|
-
horizon = mix(-1, cosine, falloff)
|
|
160
|
-
maxHorizon = max(maxHorizon, horizon)
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Do not multiply the cosine directly by falloff. Mixing toward `-1` weakens a
|
|
164
|
-
distant occluder without changing the angle of a nearby one.
|
|
165
|
-
|
|
166
|
-
Per slice:
|
|
167
|
-
|
|
168
|
-
```text
|
|
169
|
-
positiveAngle = acos(clamp(positiveHorizon, -1, 1))
|
|
170
|
-
negativeAngle = acos(clamp(negativeHorizon, -1, 1))
|
|
171
|
-
visibility += saturate((positiveAngle + negativeAngle) / PI)
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Final scalar:
|
|
175
|
-
|
|
176
|
-
```text
|
|
177
|
-
visibility = visibility / 2
|
|
178
|
-
visibility = visibility ^ power
|
|
179
|
-
visibility = saturate(mix(1, visibility, intensity))
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
Disabling the pass sets intensity to zero; the gather still runs unless the
|
|
183
|
-
owner removes or bypasses the node. If disabled cost matters, bypass the pass
|
|
184
|
-
at pipeline construction or add an update/render gate.
|
|
185
|
-
|
|
186
|
-
## 6. Treat the bent direction as an observed heuristic
|
|
187
|
-
|
|
188
|
-
For accepted samples, the gather accumulates:
|
|
189
|
-
|
|
190
|
-
```text
|
|
191
|
-
bentDirection +=
|
|
192
|
-
normalize(delta)
|
|
193
|
-
* saturate(cosine * falloff)
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Then:
|
|
197
|
-
|
|
198
|
-
```text
|
|
199
|
-
bent = normalize(
|
|
200
|
-
mix(
|
|
201
|
-
viewNormal,
|
|
202
|
-
normalize(viewDirection + bentDirection),
|
|
203
|
-
bentNormalStrength
|
|
204
|
-
)
|
|
205
|
-
)
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
The output stores `bent * 0.5 + 0.5`.
|
|
209
|
-
|
|
210
|
-
Important objective finding: the accumulated vectors point toward accepted
|
|
211
|
-
sample positions. A physically derived bent normal normally points toward
|
|
212
|
-
unoccluded directions, so do not assume this sign convention is correct in an
|
|
213
|
-
adaptation.
|
|
214
|
-
|
|
215
|
-
Required validation:
|
|
216
|
-
|
|
217
|
-
```text
|
|
218
|
-
place a flat receiver beside one vertical wall
|
|
219
|
-
show geometric normal
|
|
220
|
-
show decoded bent direction
|
|
221
|
-
show environment sample direction
|
|
222
|
-
verify the direction turns away from the blocked hemisphere
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
If it turns toward the wall, negate/rederive the directional accumulator
|
|
226
|
-
before using it for environment lighting.
|
|
227
|
-
|
|
228
|
-
## 7. Own gather rendering state
|
|
229
|
-
|
|
230
|
-
`GtaoNode.updateBefore()`:
|
|
231
|
-
|
|
232
|
-
1. saves/reset renderer state through `RendererUtils`;
|
|
233
|
-
2. reads drawing-buffer dimensions;
|
|
234
|
-
3. resizes the half-resolution target;
|
|
235
|
-
4. refreshes projection scale;
|
|
236
|
-
5. renders one fullscreen `QuadMesh`;
|
|
237
|
-
6. restores renderer state.
|
|
238
|
-
|
|
239
|
-
Dispose both the target and node material.
|
|
240
|
-
|
|
241
|
-
Do not let a post node leak render target, viewport, or material state into the
|
|
242
|
-
main pipeline.
|
|
243
|
-
|
|
244
|
-
## 8. Upsample with the exact kernel
|
|
245
|
-
|
|
246
|
-
The full-resolution composite gathers eight neighbours:
|
|
247
|
-
|
|
248
|
-
```text
|
|
249
|
-
left, right, up, down
|
|
250
|
-
four diagonals
|
|
251
|
-
center omitted
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Each weight is depth-only:
|
|
255
|
-
|
|
256
|
-
```text
|
|
257
|
-
weight = exp(-abs(sampleViewZ - centerViewZ) / 0.5)
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
If total weight is above `0.01`, normalize the eight-sample sum. Otherwise use
|
|
261
|
-
the center AO texel.
|
|
262
|
-
|
|
263
|
-
This is an eight-neighbour `3×3` ring with the center skipped, not a cross.
|
|
264
|
-
|
|
265
|
-
The rationale is to cover the four-pixel interleaved-gradient-noise repeat
|
|
266
|
-
while sampling across half-resolution AO texels.
|
|
267
|
-
|
|
268
|
-
Observed limitation: `screenTexelHint()` returns only:
|
|
269
|
-
|
|
270
|
-
```text
|
|
271
|
-
1 / screenWidth
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
and uses that scalar for both X and Y offsets. At non-square viewports the
|
|
275
|
-
vertical step is wrong. Adapt as:
|
|
276
|
-
|
|
277
|
-
```text
|
|
278
|
-
texel = vec2(1 / width, 1 / height)
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
Observed limitation: the filter has no normal-similarity weight despite having
|
|
282
|
-
the normal buffer available later in the composite. Thin foreground/background
|
|
283
|
-
contacts may need:
|
|
284
|
-
|
|
285
|
-
```text
|
|
286
|
-
weight *= pow(saturate(dot(centerNormal, sampleNormal)), normalPower)
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
Add this only after confirming the depth-only kernel causes cross-edge leakage;
|
|
290
|
-
normal buffers can be noisy at hard edges.
|
|
291
|
-
|
|
292
|
-
## 9. Apply AO only to reconstructed indirect light
|
|
293
|
-
|
|
294
|
-
Do not multiply final scene color by AO.
|
|
295
|
-
|
|
296
|
-
It approximates indirect light:
|
|
297
|
-
|
|
298
|
-
```text
|
|
299
|
-
irradiance =
|
|
300
|
-
PMREM sampled along bent direction at texture level 1
|
|
301
|
-
or fallback cavity color (0.55, 0.62, 0.78)
|
|
302
|
-
|
|
303
|
-
indirectEstimate =
|
|
304
|
-
albedo
|
|
305
|
-
* environmentIntensity
|
|
306
|
-
* irradiance
|
|
307
|
-
|
|
308
|
-
indirect = min(indirectEstimate, sceneColor)
|
|
309
|
-
direct = sceneColor - indirect
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
The clamp ensures direct light never becomes negative.
|
|
313
|
-
|
|
314
|
-
Then:
|
|
315
|
-
|
|
316
|
-
```text
|
|
317
|
-
occludedIndirect = indirect * visibility
|
|
318
|
-
|
|
319
|
-
deviation =
|
|
320
|
-
saturate(1 - dot(decodedBentView, geometricViewNormal))
|
|
321
|
-
|
|
322
|
-
tintAmount =
|
|
323
|
-
deviation
|
|
324
|
-
* (1 - visibility)
|
|
325
|
-
* bentTintStrength
|
|
326
|
-
|
|
327
|
-
bentTintStrength default = 0.35
|
|
328
|
-
|
|
329
|
-
tintedIndirect =
|
|
330
|
-
mix(
|
|
331
|
-
occludedIndirect,
|
|
332
|
-
occludedIndirect * irradiance,
|
|
333
|
-
saturate(tintAmount)
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
output = direct + tintedIndirect
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
This keeps direct sun and most specular response out of the AO multiply.
|
|
340
|
-
|
|
341
|
-
The indirect reconstruction is still approximate because it works from a
|
|
342
|
-
forward-shaded scene color and an albedo MRT. Specular energy can leak into
|
|
343
|
-
the `direct` residual. Prefer a renderer-provided indirect-diffuse signal when
|
|
344
|
-
available.
|
|
345
|
-
|
|
346
|
-
## 10. Verify view/world transform semantics
|
|
347
|
-
|
|
348
|
-
The composite decodes the bent direction in view space and calls:
|
|
349
|
-
|
|
350
|
-
```text
|
|
351
|
-
transformDirection(bentView, cameraViewMatrix)
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
while describing the result as view-to-world.
|
|
355
|
-
|
|
356
|
-
Matrix-direction semantics in TSL are version-sensitive. Verify the installed
|
|
357
|
-
Three.js behavior with axis probes:
|
|
358
|
-
|
|
359
|
-
```text
|
|
360
|
-
camera facing -Z:
|
|
361
|
-
view (0, 0, 1) maps to expected world direction
|
|
362
|
-
|
|
363
|
-
camera rotated 90 degrees:
|
|
364
|
-
decoded bent direction rotates with the camera exactly once
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
Do not copy the matrix expression solely from the comment.
|
|
368
|
-
|
|
369
|
-
## 11. Temporal behavior
|
|
370
|
-
|
|
371
|
-
This pipeline has no motion vectors, history target, reprojection,
|
|
372
|
-
neighborhood clamp, or disocclusion rejection.
|
|
373
|
-
|
|
374
|
-
Do not describe it as temporally accumulated GTAO.
|
|
375
|
-
|
|
376
|
-
If adding temporal accumulation:
|
|
377
|
-
|
|
378
|
-
1. preserve raw half-resolution visibility and bent direction;
|
|
379
|
-
2. add representative depth/normal validity;
|
|
380
|
-
3. reproject with velocity;
|
|
381
|
-
4. clamp scalar visibility to the current neighborhood;
|
|
382
|
-
5. constrain bent history by angular deviation;
|
|
383
|
-
6. reset on camera cuts and resolution changes.
|
|
384
|
-
|
|
385
|
-
First verify whether the current stable-noise plus bilateral pass already meets
|
|
386
|
-
the target. Temporal history adds ghosting risk to moving procedural geometry.
|
|
387
|
-
|
|
388
|
-
## 12. Required diagnostics
|
|
389
|
-
|
|
390
|
-
Expose:
|
|
391
|
-
|
|
392
|
-
```text
|
|
393
|
-
raw reversed depth and linear view Z
|
|
394
|
-
sky classification
|
|
395
|
-
view normal
|
|
396
|
-
projected radius UV/pixels
|
|
397
|
-
slice angle and jitter
|
|
398
|
-
positive/negative horizon cosine
|
|
399
|
-
thickness acceptance
|
|
400
|
-
distance falloff
|
|
401
|
-
visibility before power/intensity
|
|
402
|
-
raw encoded and decoded bent direction
|
|
403
|
-
one-sided-wall bent-direction test
|
|
404
|
-
eight bilateral sample depths and weights
|
|
405
|
-
X/Y texel offsets
|
|
406
|
-
upsampled visibility
|
|
407
|
-
albedo and environment irradiance
|
|
408
|
-
indirect estimate before/after scene-color clamp
|
|
409
|
-
direct residual
|
|
410
|
-
tint deviation and amount
|
|
411
|
-
final direct versus indirect contribution
|
|
412
|
-
GPU time for gather and composite
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
Failure diagnosis:
|
|
416
|
-
|
|
417
|
-
```text
|
|
418
|
-
AO radius changes with distance incorrectly:
|
|
419
|
-
world radius was replaced by a fixed pixel radius
|
|
420
|
-
|
|
421
|
-
far surfaces lose all contact:
|
|
422
|
-
projected radius was not clamped to a minimum
|
|
423
|
-
|
|
424
|
-
thick silhouette halos:
|
|
425
|
-
thickness or depth-only bilateral weights cross discontinuities
|
|
426
|
-
|
|
427
|
-
vertical blur differs from horizontal blur:
|
|
428
|
-
width-derived scalar texel size was used for Y
|
|
429
|
-
|
|
430
|
-
bent tint points into walls:
|
|
431
|
-
the observed accumulator sign was accepted without a one-sided-wall test
|
|
432
|
-
|
|
433
|
-
sunlit surfaces become gray:
|
|
434
|
-
visibility multiplied final scene color instead of reconstructed indirect
|
|
435
|
-
|
|
436
|
-
disabled AO still costs the full pass:
|
|
437
|
-
intensity was set to zero without bypassing gather rendering
|
|
438
|
-
|
|
439
|
-
camera rotation changes tint incorrectly:
|
|
440
|
-
view-to-world direction transform semantics were not verified
|
|
441
|
-
```
|