reze-engine 0.61.3 → 0.61.5
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/engine.d.ts +74 -9
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +260 -34
- package/dist/graph/presets/body.js +1 -1
- package/dist/graph/presets/cloth_rough.js +1 -1
- package/dist/graph/presets/cloth_smooth.js +1 -1
- package/dist/graph/presets/eye.d.ts.map +1 -1
- package/dist/graph/presets/eye.js +19 -0
- package/dist/graph/presets/face.js +1 -1
- package/dist/graph/presets/hair.js +1 -1
- package/dist/graph/presets/metal.js +1 -1
- package/dist/graph/presets/pool_floor.d.ts +3 -0
- package/dist/graph/presets/pool_floor.d.ts.map +1 -0
- package/dist/graph/presets/pool_floor.js +42 -0
- package/dist/graph/presets/water.d.ts +3 -0
- package/dist/graph/presets/water.d.ts.map +1 -0
- package/dist/graph/presets/water.js +31 -0
- package/dist/graph/registry.d.ts.map +1 -1
- package/dist/graph/registry.js +11 -0
- package/dist/graph/slots.d.ts.map +1 -1
- package/dist/graph/slots.js +19 -5
- package/dist/physics/autofit.d.ts +147 -0
- package/dist/physics/autofit.d.ts.map +1 -0
- package/dist/physics/autofit.js +501 -0
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +10 -9
- package/dist/shaders/materials/nodes.d.ts +1 -1
- package/dist/shaders/materials/nodes.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.js +12 -0
- package/dist/shaders/passes/field-blit.d.ts +26 -0
- package/dist/shaders/passes/field-blit.d.ts.map +1 -0
- package/dist/shaders/passes/field-blit.js +65 -0
- package/dist/shaders/passes/ground-noise.d.ts +7 -0
- package/dist/shaders/passes/ground-noise.d.ts.map +1 -0
- package/dist/shaders/passes/ground-noise.js +88 -0
- package/dist/shaders/passes/particles.js +6 -6
- package/dist/shaders/passes/scene-contract.js +1 -1
- package/dist/shaders/passes/sim.d.ts +34 -0
- package/dist/shaders/passes/sim.d.ts.map +1 -0
- package/dist/shaders/passes/sim.js +169 -0
- package/dist/shaders/passes/subsurface.d.ts +34 -0
- package/dist/shaders/passes/subsurface.d.ts.map +1 -0
- package/dist/shaders/passes/subsurface.js +134 -0
- package/dist/shaders/scene-light-api.d.ts.map +1 -1
- package/dist/shaders/scene-light-api.js +11 -0
- package/dist/shaders/score-api.d.ts +10 -0
- package/dist/shaders/score-api.d.ts.map +1 -0
- package/dist/shaders/score-api.js +114 -0
- package/dist/shaders/shadow-api.d.ts +29 -0
- package/dist/shaders/shadow-api.d.ts.map +1 -0
- package/dist/shaders/shadow-api.js +112 -0
- package/package.json +1 -1
- package/src/engine.ts +275 -36
- package/src/graph/presets/body.ts +1 -1
- package/src/graph/presets/cloth_rough.ts +1 -1
- package/src/graph/presets/cloth_smooth.ts +1 -1
- package/src/graph/presets/eye.ts +19 -0
- package/src/graph/presets/face.ts +1 -1
- package/src/graph/presets/hair.ts +1 -1
- package/src/graph/presets/metal.ts +1 -1
- package/src/graph/registry.ts +11 -0
- package/src/graph/slots.ts +19 -5
- package/src/shaders/materials/common.ts +10 -9
- package/src/shaders/materials/nodes.ts +12 -0
- package/src/shaders/passes/particles.ts +6 -6
- package/src/shaders/passes/scene-contract.ts +1 -1
- package/src/shaders/passes/subsurface.ts +136 -0
- package/src/shaders/scene-light-api.ts +11 -0
- package/dist/_dbg-loader.mjs +0 -1100
- package/dist/physics-debug.d.ts +0 -30
- package/dist/physics-debug.d.ts.map +0 -1
- package/dist/physics-debug.js +0 -526
- package/dist/shaders/materials/body.d.ts +0 -2
- package/dist/shaders/materials/body.d.ts.map +0 -1
- package/dist/shaders/materials/body.js +0 -95
- package/dist/shaders/materials/cloth_rough.d.ts +0 -2
- package/dist/shaders/materials/cloth_rough.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_rough.js +0 -69
- package/dist/shaders/materials/cloth_smooth.d.ts +0 -2
- package/dist/shaders/materials/cloth_smooth.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_smooth.js +0 -61
- package/dist/shaders/materials/default.d.ts +0 -2
- package/dist/shaders/materials/default.d.ts.map +0 -1
- package/dist/shaders/materials/default.js +0 -43
- package/dist/shaders/materials/eye.d.ts +0 -2
- package/dist/shaders/materials/eye.d.ts.map +0 -1
- package/dist/shaders/materials/eye.js +0 -60
- package/dist/shaders/materials/face.d.ts +0 -2
- package/dist/shaders/materials/face.d.ts.map +0 -1
- package/dist/shaders/materials/face.js +0 -95
- package/dist/shaders/materials/hair.d.ts +0 -2
- package/dist/shaders/materials/hair.d.ts.map +0 -1
- package/dist/shaders/materials/hair.js +0 -90
- package/dist/shaders/materials/metal.d.ts +0 -2
- package/dist/shaders/materials/metal.d.ts.map +0 -1
- package/dist/shaders/materials/metal.js +0 -77
- package/dist/shaders/materials/mmd_classic.d.ts +0 -2
- package/dist/shaders/materials/mmd_classic.d.ts.map +0 -1
- package/dist/shaders/materials/mmd_classic.js +0 -66
- package/dist/shaders/materials/stockings.d.ts +0 -2
- package/dist/shaders/materials/stockings.d.ts.map +0 -1
- package/dist/shaders/materials/stockings.js +0 -122
- package/dist/shaders/passes/physics-debug.d.ts +0 -2
- package/dist/shaders/passes/physics-debug.d.ts.map +0 -1
- package/dist/shaders/passes/physics-debug.js +0 -69
package/src/graph/slots.ts
CHANGED
|
@@ -139,10 +139,18 @@ ${discard}
|
|
|
139
139
|
${gate}
|
|
140
140
|
let l = -light.lights[0].direction.xyz;
|
|
141
141
|
let sun = select(light.lights[0].color.xyz * light.lights[0].color.w, modelLight.sun.rgb, modelLight.sun.w > 0.5);
|
|
142
|
+
let shadow = sampleShadow(input.worldPos, n);
|
|
142
143
|
// The world: flat colour, or the HDRI's irradiance at this normal — which
|
|
143
144
|
// is what makes a loaded sky actually light her instead of only backing her.
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
// The model's fill is NOT here: see the epilogue.
|
|
146
|
+
//
|
|
147
|
+
// A model given a flat sky (setModelFlatSky - the cast, for an anime look)
|
|
148
|
+
// takes the sky's AVERAGE instead: its colour and brightness from every
|
|
149
|
+
// direction alike. The directional sky shaded a face like PBR - soft
|
|
150
|
+
// realistic gradients the toon ramp never drew - where the game gives its
|
|
151
|
+
// characters one flat base light. A flat World is its own average, so a
|
|
152
|
+
// scene without an HDRI renders exactly as before.
|
|
153
|
+
let amb = select(rzWorldAmbient(n), rzWorldAmbientAvg(), modelLight.opts.x > 0.5);
|
|
146
154
|
let tex_color = tex_s.rgb;
|
|
147
155
|
// The normal the lamps' diffuse layer is lit by, for a principled walk to
|
|
148
156
|
// compute it on the way (rzLightsDiffuseOnce). n is final from here on.
|
|
@@ -186,7 +194,13 @@ function epilogue(renderClass: RenderClass, alphaMode: AlphaMode, hasOpacity: bo
|
|
|
186
194
|
// painted sheet — is Blender's Emission shader, which no lamp reaches; adding
|
|
187
195
|
// the lamps to it turned X340's floor shadow, a white-RGB picture at a soft
|
|
188
196
|
// alpha, into a glowing disc under the spot above it.
|
|
189
|
-
|
|
197
|
+
//
|
|
198
|
+
// The model's fill (Engine.setModelFill) rides here too, as brightness: the
|
|
199
|
+
// surface colour times the fill, on every pixel of her alike. It used to
|
|
200
|
+
// enter the graph's ambient, where an NPR ramp read it as LIGHT — sliding it
|
|
201
|
+
// moved her shadows, and under a hard step flipped whole regions at once.
|
|
202
|
+
// After the graph it lifts her evenly and leaves every shadow where it is.
|
|
203
|
+
const LIT = takesLight ? ` + (rzLightsDiffuseOnce(input.worldPos, n) + modelLight.fill.rgb) * albedo` : ""
|
|
190
204
|
|
|
191
205
|
const ALBEDO = ` let albedo = tex_color;
|
|
192
206
|
`
|
|
@@ -206,13 +220,13 @@ function epilogue(renderClass: RenderClass, alphaMode: AlphaMode, hasOpacity: bo
|
|
|
206
220
|
|
|
207
221
|
var out: FSOut;
|
|
208
222
|
out.color = vec4f(final_color${LIT}${BURN}, outAlpha);
|
|
209
|
-
${FOG} out.mask = vec4f(1.0, 1.0,
|
|
223
|
+
${FOG} out.mask = vec4f(1.0, 1.0, _rzSubsurface, out.color.a);
|
|
210
224
|
${ID_WRITE} return out;
|
|
211
225
|
`
|
|
212
226
|
}
|
|
213
227
|
return `${ALBEDO} var out: FSOut;
|
|
214
228
|
out.color = vec4f(final_color${LIT}${BURN}, ${alphaBase});
|
|
215
|
-
${FOG} out.mask = vec4f(1.0, 1.0,
|
|
229
|
+
${FOG} out.mask = vec4f(1.0, 1.0, _rzSubsurface, out.color.a);
|
|
216
230
|
${ID_WRITE} return out;
|
|
217
231
|
`
|
|
218
232
|
}
|
|
@@ -189,11 +189,12 @@ fn _rzCastShadow(wp: vec3f) -> f32 {
|
|
|
189
189
|
// binding(9) brdfLut is declared inside NODES_WGSL (nodes.ts).
|
|
190
190
|
@group(1) @binding(0) var<storage, read> skinMats: array<mat4x4f>;
|
|
191
191
|
// The light this model takes apart from the scene's — see Engine.setModelFill
|
|
192
|
-
// and Engine.setModelSun. fill
|
|
193
|
-
// nobody gave one; sun replaces the scene's sun colour while its w is set,
|
|
192
|
+
// and Engine.setModelSun. fill brightens it after its graph (fill ×
|
|
193
|
+
// surface colour, graph/slots.ts), zero for a model nobody gave one; sun replaces the scene's sun colour while its w is set,
|
|
194
194
|
// which is how a stage keeps the daylight its game lit it by while the cast
|
|
195
|
-
// keeps the key the scene set for them.
|
|
196
|
-
|
|
195
|
+
// keeps the key the scene set for them. opts.x (Engine.setModelFlatSky) gives
|
|
196
|
+
// it the sky's average in place of its shape - see graph/slots.ts.
|
|
197
|
+
struct ModelLight { fill: vec4f, sun: vec4f, opts: vec4f }
|
|
197
198
|
@group(1) @binding(1) var<uniform> modelLight: ModelLight;
|
|
198
199
|
@group(2) @binding(0) var diffuseTexture: texture_2d<f32>;
|
|
199
200
|
@group(2) @binding(1) var<uniform> material: MaterialUniforms;
|
|
@@ -329,17 +330,17 @@ const COMMON_VS_WGSL = /* wgsl */ `
|
|
|
329
330
|
// Location 0: final radiance+alpha (blended into rg11b10ufloat; the HDR target
|
|
330
331
|
// has no alpha channel, but the blend equation still uses the .a you write here
|
|
331
332
|
// as the src-alpha factor that premultiplies rgb into the HDR target).
|
|
332
|
-
// Location 1: auxiliary
|
|
333
|
+
// Location 1: auxiliary rgba8unorm carrying
|
|
333
334
|
// .r = bloom mask (1 = contributes to bloom, 0 = skip — e.g. ground).
|
|
334
335
|
// .g = accumulated canvas alpha — the channel that used to live in hdr.a
|
|
335
336
|
// before the switch to rg11b10ufloat. Sampled by composite to
|
|
336
337
|
// un-premultiply color for tonemap and to set the final drawable alpha
|
|
337
338
|
// (needed for the `premultiplied` canvas alphaMode that blends the
|
|
338
339
|
// WebGPU surface over the page background).
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
// Materials write mask = vec4f(1.0, 1.0,
|
|
340
|
+
// .b = subsurface strength ÷ 4 — what a graph's `subsurface` node set, 0 for
|
|
341
|
+
// everything else. Read by the scattering pass (passes/subsurface.ts).
|
|
342
|
+
// FS output at location 1 must be vec4f — the blend state references src.a.
|
|
343
|
+
// Materials write mask = vec4f(1.0, 1.0, _rzSubsurface, color.a); ground writes
|
|
343
344
|
// vec4f(0.0, 1.0, 0.0, edgeFade). With src.a coming from the 4th component and
|
|
344
345
|
// src-alpha blending enabled:
|
|
345
346
|
// out.r = mask_r · src.a + dst.r · (1-src.a) (bloom mask, weighted by alpha)
|
|
@@ -654,6 +654,18 @@ fn shader_to_rgb_diffuse(n: vec3f, l: vec3f, sun_rgb: vec3f, ambient_rgb: vec3f,
|
|
|
654
654
|
return luminance_rec709_linear(shader_to_rgb_lit(n, l, sun_rgb, ambient_rgb, shadow));
|
|
655
655
|
}
|
|
656
656
|
|
|
657
|
+
// ─── SUBSURFACE node ────────────────────────────────────────────────
|
|
658
|
+
// Marks this fragment for the screen-space scattering pass (passes/subsurface.ts)
|
|
659
|
+
// and passes its colour through. The strength lands in the aux target's .b via
|
|
660
|
+
// the epilogue, stored as a quarter so an 8-bit channel carries 0–4: 1 is
|
|
661
|
+
// ray-mmd's skin width, 0 leaves the pixel out of the pass.
|
|
662
|
+
var<private> _rzSubsurface: f32 = 0.0;
|
|
663
|
+
|
|
664
|
+
fn rz_subsurface(strength: f32, color: vec3f) -> vec3f {
|
|
665
|
+
_rzSubsurface = clamp(strength, 0.0, 4.0) * 0.25;
|
|
666
|
+
return color;
|
|
667
|
+
}
|
|
668
|
+
|
|
657
669
|
// ─── BUMP node ──────────────────────────────────────────────────────
|
|
658
670
|
// Screen-space bump from a scalar height field. Needs dFdx/dFdy which
|
|
659
671
|
// WGSL provides as dpdx/dpdy.
|
|
@@ -391,13 +391,13 @@ struct FSOut {
|
|
|
391
391
|
// writes it; a blended one writes all four, which is what not declaring it
|
|
392
392
|
// would have meant.
|
|
393
393
|
@builtin(sample_mask) samples: u32,
|
|
394
|
-
// The scene's aux target: (bloom mask, coverage). Materials write
|
|
395
|
-
// particle that skipped it would punch a hole in the mask of whatever
|
|
396
|
-
// over.
|
|
394
|
+
// The scene's aux target: (bloom mask, coverage, subsurface). Materials write
|
|
395
|
+
// it, so a particle that skipped it would punch a hole in the mask of whatever
|
|
396
|
+
// it drew over. A particle is never skin, so its .b is 0.
|
|
397
397
|
//
|
|
398
|
-
// vec4f
|
|
399
|
-
//
|
|
400
|
-
//
|
|
398
|
+
// vec4f because that target's blend factors reference SrcAlpha, and a fragment
|
|
399
|
+
// with no alpha channel is rejected outright — "reading alpha but it is
|
|
400
|
+
// missing from fragment output".
|
|
401
401
|
// The material shaders declare vec4f here for the same reason.
|
|
402
402
|
@location(1) mask: vec4f,
|
|
403
403
|
// Declared whenever the pass carries the attachment, and padded rather than
|
|
@@ -127,7 +127,7 @@ const ADD_KEEP_ALPHA: GPUBlendState = {
|
|
|
127
127
|
alpha: { srcFactor: "zero", dstFactor: "one", operation: "add" },
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
/** Both channels sum.
|
|
130
|
+
/** Both channels sum. rgba8unorm clamps at 1, which is the saturation alpha-over
|
|
131
131
|
* would have reached anyway. */
|
|
132
132
|
const ADD_BOTH: GPUBlendState = {
|
|
133
133
|
color: { srcFactor: "one", dstFactor: "one", operation: "add" },
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen-space subsurface scattering — ray-mmd's skin pass (PostProcessScattering.fxsub,
|
|
3
|
+
* SSSGaussBlurPS), ported constant for constant.
|
|
4
|
+
*
|
|
5
|
+
* A skin surface is not shaded by the light at its own pixel alone: light that
|
|
6
|
+
* enters a little way off comes back out here, red furthest. ray-mmd models that
|
|
7
|
+
* as a separable blur of the lit skin in screen space, one axis per pass, with a
|
|
8
|
+
* per-channel Gaussian (red widest) and a depth reject so light never crosses from
|
|
9
|
+
* a forearm onto the body behind it. The width is a length ON THE SURFACE, so it
|
|
10
|
+
* is divided by depth, and it narrows where the surface turns away from the view.
|
|
11
|
+
* Then a share of the unblurred picture is laid back over it — the "spike" that
|
|
12
|
+
* keeps pores, painted lines and the terminator from dissolving.
|
|
13
|
+
*
|
|
14
|
+
* What marks a pixel as skin is the scene pass's aux .b, written by the graph's
|
|
15
|
+
* `subsurface` node (0 everywhere else), as a quarter of its strength. The strength
|
|
16
|
+
* scales the radius, as ray-mmd's sssStrength does; 1 is ray-mmd's skin, 4 the most.
|
|
17
|
+
*
|
|
18
|
+
* One departure, and it is a routing one: ray-mmd blurs the lit colour BEFORE the
|
|
19
|
+
* albedo multiply and adds specular after. This engine resolves one HDR colour per
|
|
20
|
+
* pixel, so the blur runs over the finished colour. At this radius — a few pixels,
|
|
21
|
+
* with the spike keeping 14–20% of the original — the texture is not visibly
|
|
22
|
+
* softened; the lighting is.
|
|
23
|
+
*
|
|
24
|
+
* Two entry points share the module: X reads the HDR resolve and writes the
|
|
25
|
+
* scratch target, Y reads the scratch and writes back INTO the HDR resolve. The
|
|
26
|
+
* spike mix (lerp toward the original) is done by the Y pipeline's blend state,
|
|
27
|
+
* with the blend constant holding ray-mmd's per-channel spike: the destination IS
|
|
28
|
+
* the original, so no third copy of the frame is needed.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** ray-mmd, skin profile (index 1): profileSpikeRadArr[1].xyz × (1 − sssAmount),
|
|
32
|
+
* with sssAmount = customA = 0.6 in Materials/Skin/material_skin.fx. */
|
|
33
|
+
export const SSS_SPIKE: [number, number, number] = [0.35 * 0.4, 0.4 * 0.4, 0.5 * 0.4]
|
|
34
|
+
|
|
35
|
+
export const SUBSURFACE_WGSL = /* wgsl */ `
|
|
36
|
+
@group(0) @binding(0) var srcTex: texture_2d<f32>;
|
|
37
|
+
@group(0) @binding(1) var maskTex: texture_2d<f32>;
|
|
38
|
+
@group(0) @binding(2) var depthTex: texture_depth_multisampled_2d;
|
|
39
|
+
// dofU[2] = (projA, projB): the same z-buffer inversion the composite uses.
|
|
40
|
+
@group(0) @binding(3) var<uniform> dofU: array<vec4f, 3>;
|
|
41
|
+
// sssU[0] = (direction.xy, radius, _); sssU[1] = (tanHalfFov·aspect, tanHalfFov, width, height).
|
|
42
|
+
@group(0) @binding(4) var<uniform> sssU: array<vec4f, 2>;
|
|
43
|
+
|
|
44
|
+
struct VsOut { @builtin(position) pos: vec4f };
|
|
45
|
+
|
|
46
|
+
@vertex fn vs(@builtin(vertex_index) i: u32) -> VsOut {
|
|
47
|
+
let p = vec2f(f32((i << 1u) & 2u), f32(i & 2u));
|
|
48
|
+
var o: VsOut;
|
|
49
|
+
o.pos = vec4f(p * 2.0 - 1.0, 0.0, 1.0);
|
|
50
|
+
return o;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fn size() -> vec2i { return vec2i(sssU[1].zw); }
|
|
54
|
+
|
|
55
|
+
fn texel(uv: vec2f) -> vec2i {
|
|
56
|
+
return clamp(vec2i(floor(uv * sssU[1].zw)), vec2i(0), size() - 1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fn linearDepth(c: vec2i) -> f32 {
|
|
60
|
+
let z = textureLoad(depthTex, c, 0);
|
|
61
|
+
return clamp(dofU[2].y / (z - dofU[2].x), 0.05, 100000.0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// View-space position of a texel centre — ray-mmd's GetViewPosition, with y up.
|
|
65
|
+
fn viewPos(c: vec2i, d: f32) -> vec3f {
|
|
66
|
+
let uv = (vec2f(c) + 0.5) / sssU[1].zw;
|
|
67
|
+
let ndc = vec2f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0);
|
|
68
|
+
return vec3f(ndc * sssU[1].xy * d, d);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn skin(c: vec2i) -> f32 { return textureLoad(maskTex, c, 0).b; }
|
|
72
|
+
|
|
73
|
+
fn blur(fragPos: vec4f) -> vec4f {
|
|
74
|
+
let c = vec2i(fragPos.xy);
|
|
75
|
+
let amount = skin(c) * 4.0;
|
|
76
|
+
let dir = sssU[0].xy;
|
|
77
|
+
let uv = (vec2f(c) + 0.5) / sssU[1].zw;
|
|
78
|
+
let centre = textureLoad(srcTex, c, 0);
|
|
79
|
+
|
|
80
|
+
// ray-mmd, verbatim: six offsets, and the skin variances per channel.
|
|
81
|
+
// A var, not a const: a const array cannot be indexed by the loop counter.
|
|
82
|
+
var offsets = array<f32, 6>(0.352, 0.719, 1.117, 1.579, 2.177, 3.213);
|
|
83
|
+
const profileVar = vec3f(9.6, 2.8, 2.2);
|
|
84
|
+
// mSSSSScale at the controller's default; it sets both the width and how hard
|
|
85
|
+
// a depth step rejects.
|
|
86
|
+
const SSSS_SCALE: f32 = 0.04;
|
|
87
|
+
|
|
88
|
+
let d = linearDepth(c);
|
|
89
|
+
|
|
90
|
+
// The surface's normal, rebuilt from depth (ray-mmd reads it from its G-buffer;
|
|
91
|
+
// this engine keeps none). Only its angle to the view matters: the blur narrows
|
|
92
|
+
// along an axis the surface is turning away on.
|
|
93
|
+
let s = size();
|
|
94
|
+
let cx = min(c + vec2i(1, 0), s - 1);
|
|
95
|
+
let cy = min(c + vec2i(0, 1), s - 1);
|
|
96
|
+
let P = viewPos(c, d);
|
|
97
|
+
let N = cross(viewPos(cx, linearDepth(cx)) - P, viewPos(cy, linearDepth(cy)) - P);
|
|
98
|
+
let nxz = select(vec2f(0.0, 1.0), normalize(N.xz), dot(N.xz, N.xz) > 1e-12);
|
|
99
|
+
let nyz = select(vec2f(0.0, 1.0), normalize(N.yz), dot(N.yz, N.yz) > 1e-12);
|
|
100
|
+
let scaleX = abs(dot(nxz, normalize(P.xz)));
|
|
101
|
+
let scaleY = abs(dot(nyz, normalize(P.yz)));
|
|
102
|
+
let perspectiveScale = max(dot(dir, vec2f(scaleX, scaleY)), 0.3);
|
|
103
|
+
|
|
104
|
+
let radius = 0.0055 * amount * perspectiveScale / SSSS_SCALE;
|
|
105
|
+
let step = dir * radius / d;
|
|
106
|
+
|
|
107
|
+
var weightSum = vec3f(1.0);
|
|
108
|
+
var colour = centre.rgb;
|
|
109
|
+
for (var i = 0; i < 6; i++) {
|
|
110
|
+
let o = offsets[i] / 5.5 * step;
|
|
111
|
+
for (var side = 0; side < 2; side++) {
|
|
112
|
+
let tc = texel(select(uv - o, uv + o, side == 0));
|
|
113
|
+
// Skin only: ray-mmd zeroes a non-skin pixel's depth so the depth term
|
|
114
|
+
// rejects it; the mask says the same thing directly.
|
|
115
|
+
let isSkin = select(0.0, 1.0, skin(tc) > 0.004);
|
|
116
|
+
let dd = (linearDepth(tc) - d) * 1000.0 * SSSS_SCALE;
|
|
117
|
+
let w = exp(-(offsets[i] * offsets[i] + dd * dd) / profileVar) * isSkin;
|
|
118
|
+
weightSum += w;
|
|
119
|
+
colour += w * textureLoad(srcTex, tc, 0).rgb;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return vec4f(colour / weightSum, centre.a);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@fragment fn fsX(@builtin(position) pos: vec4f) -> @location(0) vec4f {
|
|
126
|
+
// Nothing reads the scratch target off skin: the Y pass rejects those taps.
|
|
127
|
+
if (skin(vec2i(pos.xy)) <= 0.004) { return vec4f(0.0); }
|
|
128
|
+
return blur(pos);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@fragment fn fsY(@builtin(position) pos: vec4f) -> @location(0) vec4f {
|
|
132
|
+
// Off skin the HDR resolve must stay exactly as the scene left it.
|
|
133
|
+
if (skin(vec2i(pos.xy)) <= 0.004) { discard; }
|
|
134
|
+
return blur(pos);
|
|
135
|
+
}
|
|
136
|
+
`
|
|
@@ -37,6 +37,17 @@ fn rzWorldAmbient(n: vec3f) -> vec3f {
|
|
|
37
37
|
+ ${u}.sh[8].xyz * (x * x - y * y);
|
|
38
38
|
return max(c, vec3f(0.0));
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The world's light averaged over every direction: its colour and brightness,
|
|
43
|
+
* with no shape. Every term but sh[0] averages to zero over the sphere (x, xy,
|
|
44
|
+
* 3z²-1 ... all do), so the average is sh[0] itself; a flat world is its own.
|
|
45
|
+
* What an anime cast takes from a sky - see ModelLight.opts.
|
|
46
|
+
*/
|
|
47
|
+
fn rzWorldAmbientAvg() -> vec3f {
|
|
48
|
+
if (${u}.sh[0].w < 0.5) { return ${u}.ambientColor.xyz; }
|
|
49
|
+
return max(${u}.sh[0].xyz, vec3f(0.0));
|
|
50
|
+
}
|
|
40
51
|
`
|
|
41
52
|
|
|
42
53
|
/**
|