@driftengine/core 4.8.3 → 4.8.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/CHANGELOG.json +82 -0
- package/README.md +1 -1
- package/dist/build/shaderComments.js +0 -0
- package/dist/geometry/meshConcat.js +2 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.js +16 -1
- package/dist/math/scalar.js +1 -1
- package/dist/render/anisotropicLobe.d.ts +7 -0
- package/dist/render/anisotropicLobe.js +33 -0
- package/dist/render/backend/api.d.ts +41 -4
- package/dist/render/backend/select.js +8 -0
- package/dist/render/backend/webgl2/clothTextures.d.ts +27 -0
- package/dist/render/backend/webgl2/clothTextures.js +93 -0
- package/dist/render/backend/webgl2/renderer.d.ts +136 -3
- package/dist/render/backend/webgl2/renderer.js +604 -63
- package/dist/render/backend/webgl2/skinScatter.d.ts +50 -0
- package/dist/render/backend/webgl2/skinScatter.js +256 -0
- package/dist/render/backend/webgpu/buffers.d.ts +25 -11
- package/dist/render/backend/webgpu/buffers.js +98 -49
- package/dist/render/backend/webgpu/clothSolvePack.d.ts +27 -0
- package/dist/render/backend/webgpu/clothSolvePack.js +129 -0
- package/dist/render/backend/webgpu/clothTextures.d.ts +68 -0
- package/dist/render/backend/webgpu/clothTextures.js +145 -0
- package/dist/render/backend/webgpu/compressedUpload.d.ts +18 -0
- package/dist/render/backend/webgpu/compressedUpload.js +38 -0
- package/dist/render/backend/webgpu/computeHost.d.ts +21 -0
- package/dist/render/backend/webgpu/computeHost.js +5 -0
- package/dist/render/backend/webgpu/depthPass.d.ts +16 -6
- package/dist/render/backend/webgpu/depthPass.js +39 -9
- package/dist/render/backend/webgpu/drawCommand.js +6 -2
- package/dist/render/backend/webgpu/flatPass.d.ts +38 -4
- package/dist/render/backend/webgpu/flatPass.js +109 -12
- package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +74 -0
- package/dist/render/backend/webgpu/gpuSkinnedCloth.js +452 -0
- package/dist/render/backend/webgpu/motionPass.d.ts +20 -0
- package/dist/render/backend/webgpu/motionPass.js +106 -9
- package/dist/render/backend/webgpu/postPass.d.ts +3 -1
- package/dist/render/backend/webgpu/postPass.js +6 -3
- package/dist/render/backend/webgpu/renderer.d.ts +113 -5
- package/dist/render/backend/webgpu/renderer.js +498 -48
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +33 -0
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +469 -0
- package/dist/render/backend/webgpu/skinScatterPass.d.ts +51 -0
- package/dist/render/backend/webgpu/skinScatterPass.js +253 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +4 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.js +37 -12
- package/dist/render/clothBindingData.d.ts +41 -0
- package/dist/render/clothBindingData.js +72 -0
- package/dist/render/clothPlacement.d.ts +25 -0
- package/dist/render/clothPlacement.js +85 -0
- package/dist/render/compressedSource.d.ts +66 -0
- package/dist/render/compressedSource.js +138 -0
- package/dist/render/cutoutCaster.d.ts +2 -0
- package/dist/render/cutoutCaster.js +2 -0
- package/dist/render/cutoutDither.d.ts +51 -0
- package/dist/render/cutoutDither.js +90 -0
- package/dist/render/eyeRefraction.d.ts +35 -0
- package/dist/render/eyeRefraction.js +40 -0
- package/dist/render/glCompressed.d.ts +27 -0
- package/dist/render/glCompressed.js +53 -0
- package/dist/render/hairLobes.d.ts +70 -0
- package/dist/render/hairLobes.js +120 -0
- package/dist/render/lightBudget.d.ts +22 -0
- package/dist/render/lightBudget.js +22 -0
- package/dist/render/mesh.d.ts +7 -0
- package/dist/render/mesh.js +24 -0
- package/dist/render/recon/motionVectors.d.ts +4 -2
- package/dist/render/recon/motionVectors.js +6 -3
- package/dist/render/renderQuality.d.ts +20 -0
- package/dist/render/renderQuality.js +5 -0
- package/dist/render/rendererHarness.js +4 -0
- package/dist/render/sceneTarget.d.ts +12 -0
- package/dist/render/sceneTarget.js +14 -0
- package/dist/render/shaders/clothBinding.d.ts +22 -0
- package/dist/render/shaders/clothBinding.js +80 -0
- package/dist/render/shaders/depth.js +42 -6
- package/dist/render/shaders/flat/anisotropic.d.ts +15 -0
- package/dist/render/shaders/flat/anisotropic.js +68 -0
- package/dist/render/shaders/flat/eye.d.ts +1 -0
- package/dist/render/shaders/flat/eye.js +81 -0
- package/dist/render/shaders/flat/hair.d.ts +1 -0
- package/dist/render/shaders/flat/hair.js +101 -0
- package/dist/render/shaders/flat/index.js +36 -2
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +113 -17
- package/dist/render/shaders/flat/models.d.ts +14 -0
- package/dist/render/shaders/flat/models.js +273 -0
- package/dist/render/shaders/flat/preamble.js +26 -24
- package/dist/render/shaders/flat/skin.d.ts +1 -0
- package/dist/render/shaders/flat/skin.js +114 -0
- package/dist/render/shaders/generated/depth.wgsl.d.ts +38 -16
- package/dist/render/shaders/generated/depth.wgsl.js +38 -16
- package/dist/render/shaders/generated/flat.wgsl.d.ts +1790 -1704
- package/dist/render/shaders/generated/flat.wgsl.js +1828 -1742
- package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +48 -0
- package/dist/render/shaders/generated/skinBlur.wgsl.js +54 -0
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +102 -0
- package/dist/render/shaders/skinBlur.d.ts +1 -0
- package/dist/render/shaders/skinBlur.js +103 -0
- package/dist/render/shaders/skinning.d.ts +3 -1
- package/dist/render/shaders/skinning.js +31 -4
- package/dist/render/shadowCasters.d.ts +13 -1
- package/dist/render/skinBlur.d.ts +41 -0
- package/dist/render/skinBlur.js +49 -0
- package/dist/render/skinScatter.d.ts +67 -0
- package/dist/render/skinScatter.js +80 -0
- package/dist/render/skinnedClothRun.d.ts +26 -0
- package/dist/render/skinnedClothRun.js +84 -0
- package/dist/render/surfaceModel.d.ts +129 -0
- package/dist/render/surfaceModel.js +152 -0
- package/dist/render/surfaceTexture.d.ts +44 -4
- package/dist/render/surfaceTexture.js +60 -46
- package/dist/render/vertexDefaults.js +7 -0
- package/package.json +6 -6
- package/src/build/shaderComments.ts +0 -0
- package/src/geometry/meshConcat.ts +2 -0
- package/src/index.ts +40 -1
- package/src/math/scalar.ts +1 -1
- package/src/render/anisotropicLobe.ts +41 -0
- package/src/render/backend/api.ts +52 -3
- package/src/render/backend/select.ts +8 -0
- package/src/render/backend/webgl2/clothTextures.ts +120 -0
- package/src/render/backend/webgl2/renderer.ts +693 -64
- package/src/render/backend/webgl2/skinScatter.ts +309 -0
- package/src/render/backend/webgpu/buffers.ts +137 -63
- package/src/render/backend/webgpu/clothSolvePack.ts +161 -0
- package/src/render/backend/webgpu/clothTextures.ts +194 -0
- package/src/render/backend/webgpu/compressedUpload.ts +65 -0
- package/src/render/backend/webgpu/computeHost.ts +25 -0
- package/src/render/backend/webgpu/depthPass.ts +39 -7
- package/src/render/backend/webgpu/drawCommand.ts +6 -2
- package/src/render/backend/webgpu/flatPass.ts +145 -7
- package/src/render/backend/webgpu/gpuSkinnedCloth.ts +502 -0
- package/src/render/backend/webgpu/motionPass.ts +128 -9
- package/src/render/backend/webgpu/postPass.ts +5 -1
- package/src/render/backend/webgpu/renderer.ts +663 -43
- package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +470 -0
- package/src/render/backend/webgpu/skinScatterPass.ts +309 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +42 -12
- package/src/render/clothBindingData.ts +89 -0
- package/src/render/clothPlacement.ts +114 -0
- package/src/render/compressedSource.ts +198 -0
- package/src/render/cutoutCaster.ts +5 -0
- package/src/render/cutoutDither.ts +99 -0
- package/src/render/eyeRefraction.ts +72 -0
- package/src/render/glCompressed.ts +86 -0
- package/src/render/hairLobes.ts +188 -0
- package/src/render/lightBudget.ts +25 -0
- package/src/render/mesh.ts +23 -0
- package/src/render/recon/motionVectors.ts +6 -3
- package/src/render/renderQuality.ts +28 -0
- package/src/render/rendererHarness.ts +4 -0
- package/src/render/sceneTarget.ts +21 -0
- package/src/render/shaders/clothBinding.ts +81 -0
- package/src/render/shaders/depth.ts +42 -6
- package/src/render/shaders/flat/anisotropic.ts +68 -0
- package/src/render/shaders/flat/eye.ts +82 -0
- package/src/render/shaders/flat/hair.ts +102 -0
- package/src/render/shaders/flat/index.ts +36 -2
- package/src/render/shaders/flat/main.ts +113 -17
- package/src/render/shaders/flat/models.ts +286 -0
- package/src/render/shaders/flat/preamble.ts +26 -24
- package/src/render/shaders/flat/skin.ts +116 -0
- package/src/render/shaders/generated/depth.wgsl.ts +38 -16
- package/src/render/shaders/generated/flat.wgsl.ts +1828 -1742
- package/src/render/shaders/generated/skinBlur.wgsl.ts +56 -0
- package/src/render/shaders/recon/motion.wgsl.ts +102 -0
- package/src/render/shaders/skinBlur.ts +105 -0
- package/src/render/shaders/skinning.ts +31 -4
- package/src/render/shadowCasters.ts +13 -0
- package/src/render/skinBlur.ts +53 -0
- package/src/render/skinScatter.ts +92 -0
- package/src/render/skinnedClothRun.ts +128 -0
- package/src/render/surfaceModel.ts +274 -0
- package/src/render/surfaceTexture.ts +123 -63
- package/src/render/vertexDefaults.ts +7 -0
- package/dist/math/exact.d.ts +0 -76
- package/dist/math/exact.js +0 -327
- package/src/math/exact.ts +0 -340
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export declare const SKIN_BLUR_FRAG_WGSL = "struct Uniforms {\n uStep: vec2<f32>,\n uDepthToViewZ: vec4<f32>,\n uFocal: f32,\n uProfiles: array<vec4<f32>, 8>,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uSkin_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSkin_s: sampler;\nvar<private> vUv_1: vec2<f32>;\nvar<private> fragColor: vec4<f32>;\n@group(0) @binding(34) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uDepth_s: sampler;\n\nfn burleyMass_u0028_f1_u003b_vf3_u003b(x: ptr<function, f32>, d: ptr<function, vec3<f32>>) -> vec3<f32> {\n let _e51 = (*x);\n let _e53 = (*d);\n let _e57 = (*x);\n let _e59 = (*d);\n return (vec3(0.5f) - ((exp((vec3(-(_e51)) / _e53)) + (exp((vec3(-(_e57)) / (_e59 * 3f))) * 3f)) * 0.125f));\n}\n\nfn viewZ_u0028_f1_u003b(depth: ptr<function, f32>) -> f32 {\n var ndc: f32;\n\n let _e51 = (*depth);\n ndc = (1f - (_e51 * 2f));\n let _e56 = unnamed.uDepthToViewZ[0u];\n let _e57 = ndc;\n let _e61 = unnamed.uDepthToViewZ[1u];\n let _e65 = unnamed.uDepthToViewZ[2u];\n let _e66 = ndc;\n let _e70 = unnamed.uDepthToViewZ[3u];\n return (((_e56 * _e57) + _e61) / ((_e65 * _e66) + _e70));\n}\n\nfn main_1() {\n var own: vec4<f32>;\n var depth_1: f32;\n var profile: i32;\n var d_1: vec3<f32>;\n var widest: f32;\n var z: f32;\n var param: f32;\n var pixels: f32;\n var centre: vec3<f32>;\n var param_1: f32;\n var param_2: vec3<f32>;\n var sum: vec3<f32>;\n var weight: vec3<f32>;\n var i: i32;\n var outer: vec3<f32>;\n var local: vec3<f32>;\n var indexable: array<f32, 6>;\n var param_3: f32;\n var param_4: vec3<f32>;\n var w: vec3<f32>;\n var indexable_1: array<f32, 6>;\n var param_5: f32;\n var param_6: vec3<f32>;\n var side: i32;\n var uv: vec2<f32>;\n var indexable_2: array<f32, 7>;\n var tap: vec4<f32>;\n var tapZ: f32;\n var param_7: f32;\n var keep: f32;\n var cover: f32;\n\n let _e80 = vUv_1;\n let _e81 = textureSampleLevel(uSkin_t, uSkin_s, _e80, 0f);\n own = _e81;\n let _e83 = own[3u];\n if (_e83 < 0.0001f) {\n fragColor = vec4<f32>(0f, 0f, 0f, 0f);\n return;\n }\n let _e85 = vUv_1;\n let _e86 = textureSampleLevel(uDepth_t, uDepth_s, _e85, 0f);\n depth_1 = _e86.x;\n let _e88 = depth_1;\n if (_e88 <= 0f) {\n let _e90 = own;\n fragColor = _e90;\n return;\n }\n let _e92 = own[3u];\n profile = clamp((i32(((_e92 * 8f) + 0.5f)) - 1i), 0i, 7i);\n let _e98 = profile;\n let _e101 = unnamed.uProfiles[_e98];\n d_1 = max(_e101.xyz, vec3<f32>(0.000001f, 0.000001f, 0.000001f));\n let _e105 = d_1[0u];\n let _e107 = d_1[1u];\n let _e109 = d_1[2u];\n widest = max(_e105, max(_e107, _e109));\n let _e112 = depth_1;\n param = _e112;\n let _e113 = viewZ_u0028_f1_u003b((¶m));\n z = abs(_e113);\n let _e115 = widest;\n let _e117 = unnamed.uFocal;\n let _e119 = z;\n pixels = ((_e115 * _e117) / max(_e119, 0.0001f));\n let _e122 = pixels;\n if (_e122 < 0.5f) {\n let _e124 = own;\n fragColor = _e124;\n return;\n }\n let _e125 = widest;\n param_1 = (0.2f * _e125);\n let _e127 = d_1;\n param_2 = _e127;\n let _e128 = burleyMass_u0028_f1_u003b_vf3_u003b((¶m_1), (¶m_2));\n centre = (_e128 * 2f);\n let _e130 = own;\n let _e132 = centre;\n sum = (_e130.xyz * _e132);\n let _e134 = centre;\n weight = _e134;\n i = 1i;\n loop {\n let _e135 = i;\n if (_e135 < 7i) {\n let _e137 = i;\n if (_e137 < 6i) {\n let _e139 = i;\n indexable = array<f32, 6>(0.2f, 0.75f, 1.6f, 2.8f, 4.55f, 7.3f);\n let _e142 = indexable[min(_e139, 5i)];\n let _e143 = widest;\n param_3 = (_e142 * _e143);\n let _e145 = d_1;\n param_4 = _e145;\n let _e146 = burleyMass_u0028_f1_u003b_vf3_u003b((¶m_3), (¶m_4));\n local = _e146;\n } else {\n local = vec3<f32>(0.5f, 0.5f, 0.5f);\n }\n let _e147 = local;\n outer = _e147;\n let _e148 = outer;\n let _e149 = i;\n indexable_1 = array<f32, 6>(0.2f, 0.75f, 1.6f, 2.8f, 4.55f, 7.3f);\n let _e152 = indexable_1[(_e149 - 1i)];\n let _e153 = widest;\n param_5 = (_e152 * _e153);\n let _e155 = d_1;\n param_6 = _e155;\n let _e156 = burleyMass_u0028_f1_u003b_vf3_u003b((¶m_5), (¶m_6));\n w = (_e148 - _e156);\n side = -1i;\n loop {\n let _e158 = side;\n if (_e158 <= 1i) {\n let _e160 = vUv_1;\n let _e162 = unnamed.uStep;\n let _e163 = side;\n let _e165 = i;\n indexable_2 = array<f32, 7>(0f, 0.4f, 1.1f, 2.1f, 3.5f, 5.6f, 9f);\n let _e167 = indexable_2[_e165];\n let _e169 = pixels;\n uv = (_e160 + (_e162 * ((f32(_e163) * _e167) * _e169)));\n let _e173 = uv;\n let _e174 = textureSampleLevel(uSkin_t, uSkin_s, _e173, 0f);\n tap = _e174;\n let _e175 = uv;\n let _e176 = textureSampleLevel(uDepth_t, uDepth_s, _e175, 0f);\n param_7 = _e176.x;\n let _e178 = viewZ_u0028_f1_u003b((¶m_7));\n tapZ = abs(_e178);\n let _e180 = tapZ;\n let _e181 = z;\n let _e184 = widest;\n keep = clamp((1f - (abs((_e180 - _e181)) / (4f * _e184))), 0f, 1f);\n let _e190 = tap[3u];\n let _e192 = own[3u];\n cover = clamp((_e190 / _e192), 0f, 1f);\n let _e195 = tap;\n let _e197 = w;\n let _e199 = keep;\n let _e201 = sum;\n sum = (_e201 + ((_e195.xyz * _e197) * _e199));\n let _e203 = w;\n let _e204 = cover;\n let _e205 = keep;\n let _e208 = weight;\n weight = (_e208 + (_e203 * (_e204 * _e205)));\n continue;\n } else {\n break;\n }\n continuing {\n let _e210 = side;\n side = (_e210 + 2i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e212 = i;\n i = (_e212 + 1i);\n }\n }\n let _e214 = sum;\n let _e215 = weight;\n let _e216 = (_e214 / _e215);\n let _e218 = own[3u];\n fragColor = vec4<f32>(_e216.x, _e216.y, _e216.z, _e218);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>) -> @location(0) vec4<f32> {\n vUv_1 = vUv;\n main_1();\n let _e3 = fragColor;\n return _e3;\n}\n";
|
|
2
|
+
/**
|
|
3
|
+
* What the transform assigned, so the renderer binds the same numbers.
|
|
4
|
+
*
|
|
5
|
+
* A permuted shader has one entry per variant, keyed as `FLAT_FRAG_WGSL` is.
|
|
6
|
+
*/
|
|
7
|
+
export declare const SKINBLUR_BINDINGS: {
|
|
8
|
+
readonly SKIN_BLUR_FRAG: {
|
|
9
|
+
readonly uniforms: 1;
|
|
10
|
+
readonly uniformSize: 176;
|
|
11
|
+
readonly fields: {
|
|
12
|
+
readonly uStep: {
|
|
13
|
+
readonly offset: 0;
|
|
14
|
+
readonly size: 8;
|
|
15
|
+
readonly type: "vec2";
|
|
16
|
+
};
|
|
17
|
+
readonly uDepthToViewZ: {
|
|
18
|
+
readonly offset: 16;
|
|
19
|
+
readonly size: 16;
|
|
20
|
+
readonly type: "vec4";
|
|
21
|
+
};
|
|
22
|
+
readonly uFocal: {
|
|
23
|
+
readonly offset: 32;
|
|
24
|
+
readonly size: 4;
|
|
25
|
+
readonly type: "float";
|
|
26
|
+
};
|
|
27
|
+
readonly uProfiles: {
|
|
28
|
+
readonly offset: 48;
|
|
29
|
+
readonly size: 128;
|
|
30
|
+
readonly type: "vec4";
|
|
31
|
+
readonly length: 8;
|
|
32
|
+
readonly stride: 16;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
readonly textures: {
|
|
36
|
+
readonly uSkin: {
|
|
37
|
+
readonly texture: 32;
|
|
38
|
+
readonly sampler: 33;
|
|
39
|
+
readonly type: "sampler2D";
|
|
40
|
+
};
|
|
41
|
+
readonly uDepth: {
|
|
42
|
+
readonly texture: 34;
|
|
43
|
+
readonly sampler: 35;
|
|
44
|
+
readonly type: "sampler2D";
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Generated from ../skinBlur.ts by `npm run wgsl`. Do not edit.
|
|
3
|
+
*
|
|
4
|
+
* The GLSL beside this file is the source of truth. A hand edit here is discarded by
|
|
5
|
+
* the next generation, and `npm run wgsl:check` fails the build when this is stale.
|
|
6
|
+
*/
|
|
7
|
+
export const SKIN_BLUR_FRAG_WGSL = "struct Uniforms {\n uStep: vec2<f32>,\n uDepthToViewZ: vec4<f32>,\n uFocal: f32,\n uProfiles: array<vec4<f32>, 8>,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uSkin_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSkin_s: sampler;\nvar<private> vUv_1: vec2<f32>;\nvar<private> fragColor: vec4<f32>;\n@group(0) @binding(34) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uDepth_s: sampler;\n\nfn burleyMass_u0028_f1_u003b_vf3_u003b(x: ptr<function, f32>, d: ptr<function, vec3<f32>>) -> vec3<f32> {\n let _e51 = (*x);\n let _e53 = (*d);\n let _e57 = (*x);\n let _e59 = (*d);\n return (vec3(0.5f) - ((exp((vec3(-(_e51)) / _e53)) + (exp((vec3(-(_e57)) / (_e59 * 3f))) * 3f)) * 0.125f));\n}\n\nfn viewZ_u0028_f1_u003b(depth: ptr<function, f32>) -> f32 {\n var ndc: f32;\n\n let _e51 = (*depth);\n ndc = (1f - (_e51 * 2f));\n let _e56 = unnamed.uDepthToViewZ[0u];\n let _e57 = ndc;\n let _e61 = unnamed.uDepthToViewZ[1u];\n let _e65 = unnamed.uDepthToViewZ[2u];\n let _e66 = ndc;\n let _e70 = unnamed.uDepthToViewZ[3u];\n return (((_e56 * _e57) + _e61) / ((_e65 * _e66) + _e70));\n}\n\nfn main_1() {\n var own: vec4<f32>;\n var depth_1: f32;\n var profile: i32;\n var d_1: vec3<f32>;\n var widest: f32;\n var z: f32;\n var param: f32;\n var pixels: f32;\n var centre: vec3<f32>;\n var param_1: f32;\n var param_2: vec3<f32>;\n var sum: vec3<f32>;\n var weight: vec3<f32>;\n var i: i32;\n var outer: vec3<f32>;\n var local: vec3<f32>;\n var indexable: array<f32, 6>;\n var param_3: f32;\n var param_4: vec3<f32>;\n var w: vec3<f32>;\n var indexable_1: array<f32, 6>;\n var param_5: f32;\n var param_6: vec3<f32>;\n var side: i32;\n var uv: vec2<f32>;\n var indexable_2: array<f32, 7>;\n var tap: vec4<f32>;\n var tapZ: f32;\n var param_7: f32;\n var keep: f32;\n var cover: f32;\n\n let _e80 = vUv_1;\n let _e81 = textureSampleLevel(uSkin_t, uSkin_s, _e80, 0f);\n own = _e81;\n let _e83 = own[3u];\n if (_e83 < 0.0001f) {\n fragColor = vec4<f32>(0f, 0f, 0f, 0f);\n return;\n }\n let _e85 = vUv_1;\n let _e86 = textureSampleLevel(uDepth_t, uDepth_s, _e85, 0f);\n depth_1 = _e86.x;\n let _e88 = depth_1;\n if (_e88 <= 0f) {\n let _e90 = own;\n fragColor = _e90;\n return;\n }\n let _e92 = own[3u];\n profile = clamp((i32(((_e92 * 8f) + 0.5f)) - 1i), 0i, 7i);\n let _e98 = profile;\n let _e101 = unnamed.uProfiles[_e98];\n d_1 = max(_e101.xyz, vec3<f32>(0.000001f, 0.000001f, 0.000001f));\n let _e105 = d_1[0u];\n let _e107 = d_1[1u];\n let _e109 = d_1[2u];\n widest = max(_e105, max(_e107, _e109));\n let _e112 = depth_1;\n param = _e112;\n let _e113 = viewZ_u0028_f1_u003b((¶m));\n z = abs(_e113);\n let _e115 = widest;\n let _e117 = unnamed.uFocal;\n let _e119 = z;\n pixels = ((_e115 * _e117) / max(_e119, 0.0001f));\n let _e122 = pixels;\n if (_e122 < 0.5f) {\n let _e124 = own;\n fragColor = _e124;\n return;\n }\n let _e125 = widest;\n param_1 = (0.2f * _e125);\n let _e127 = d_1;\n param_2 = _e127;\n let _e128 = burleyMass_u0028_f1_u003b_vf3_u003b((¶m_1), (¶m_2));\n centre = (_e128 * 2f);\n let _e130 = own;\n let _e132 = centre;\n sum = (_e130.xyz * _e132);\n let _e134 = centre;\n weight = _e134;\n i = 1i;\n loop {\n let _e135 = i;\n if (_e135 < 7i) {\n let _e137 = i;\n if (_e137 < 6i) {\n let _e139 = i;\n indexable = array<f32, 6>(0.2f, 0.75f, 1.6f, 2.8f, 4.55f, 7.3f);\n let _e142 = indexable[min(_e139, 5i)];\n let _e143 = widest;\n param_3 = (_e142 * _e143);\n let _e145 = d_1;\n param_4 = _e145;\n let _e146 = burleyMass_u0028_f1_u003b_vf3_u003b((¶m_3), (¶m_4));\n local = _e146;\n } else {\n local = vec3<f32>(0.5f, 0.5f, 0.5f);\n }\n let _e147 = local;\n outer = _e147;\n let _e148 = outer;\n let _e149 = i;\n indexable_1 = array<f32, 6>(0.2f, 0.75f, 1.6f, 2.8f, 4.55f, 7.3f);\n let _e152 = indexable_1[(_e149 - 1i)];\n let _e153 = widest;\n param_5 = (_e152 * _e153);\n let _e155 = d_1;\n param_6 = _e155;\n let _e156 = burleyMass_u0028_f1_u003b_vf3_u003b((¶m_5), (¶m_6));\n w = (_e148 - _e156);\n side = -1i;\n loop {\n let _e158 = side;\n if (_e158 <= 1i) {\n let _e160 = vUv_1;\n let _e162 = unnamed.uStep;\n let _e163 = side;\n let _e165 = i;\n indexable_2 = array<f32, 7>(0f, 0.4f, 1.1f, 2.1f, 3.5f, 5.6f, 9f);\n let _e167 = indexable_2[_e165];\n let _e169 = pixels;\n uv = (_e160 + (_e162 * ((f32(_e163) * _e167) * _e169)));\n let _e173 = uv;\n let _e174 = textureSampleLevel(uSkin_t, uSkin_s, _e173, 0f);\n tap = _e174;\n let _e175 = uv;\n let _e176 = textureSampleLevel(uDepth_t, uDepth_s, _e175, 0f);\n param_7 = _e176.x;\n let _e178 = viewZ_u0028_f1_u003b((¶m_7));\n tapZ = abs(_e178);\n let _e180 = tapZ;\n let _e181 = z;\n let _e184 = widest;\n keep = clamp((1f - (abs((_e180 - _e181)) / (4f * _e184))), 0f, 1f);\n let _e190 = tap[3u];\n let _e192 = own[3u];\n cover = clamp((_e190 / _e192), 0f, 1f);\n let _e195 = tap;\n let _e197 = w;\n let _e199 = keep;\n let _e201 = sum;\n sum = (_e201 + ((_e195.xyz * _e197) * _e199));\n let _e203 = w;\n let _e204 = cover;\n let _e205 = keep;\n let _e208 = weight;\n weight = (_e208 + (_e203 * (_e204 * _e205)));\n continue;\n } else {\n break;\n }\n continuing {\n let _e210 = side;\n side = (_e210 + 2i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e212 = i;\n i = (_e212 + 1i);\n }\n }\n let _e214 = sum;\n let _e215 = weight;\n let _e216 = (_e214 / _e215);\n let _e218 = own[3u];\n fragColor = vec4<f32>(_e216.x, _e216.y, _e216.z, _e218);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>) -> @location(0) vec4<f32> {\n vUv_1 = vUv;\n main_1();\n let _e3 = fragColor;\n return _e3;\n}\n";
|
|
8
|
+
/**
|
|
9
|
+
* What the transform assigned, so the renderer binds the same numbers.
|
|
10
|
+
*
|
|
11
|
+
* A permuted shader has one entry per variant, keyed as `FLAT_FRAG_WGSL` is.
|
|
12
|
+
*/
|
|
13
|
+
export const SKINBLUR_BINDINGS = {
|
|
14
|
+
"SKIN_BLUR_FRAG": {
|
|
15
|
+
"uniforms": 1,
|
|
16
|
+
"uniformSize": 176,
|
|
17
|
+
"fields": {
|
|
18
|
+
"uStep": {
|
|
19
|
+
"offset": 0,
|
|
20
|
+
"size": 8,
|
|
21
|
+
"type": "vec2"
|
|
22
|
+
},
|
|
23
|
+
"uDepthToViewZ": {
|
|
24
|
+
"offset": 16,
|
|
25
|
+
"size": 16,
|
|
26
|
+
"type": "vec4"
|
|
27
|
+
},
|
|
28
|
+
"uFocal": {
|
|
29
|
+
"offset": 32,
|
|
30
|
+
"size": 4,
|
|
31
|
+
"type": "float"
|
|
32
|
+
},
|
|
33
|
+
"uProfiles": {
|
|
34
|
+
"offset": 48,
|
|
35
|
+
"size": 128,
|
|
36
|
+
"type": "vec4",
|
|
37
|
+
"length": 8,
|
|
38
|
+
"stride": 16
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"textures": {
|
|
42
|
+
"uSkin": {
|
|
43
|
+
"texture": 32,
|
|
44
|
+
"sampler": 33,
|
|
45
|
+
"type": "sampler2D"
|
|
46
|
+
},
|
|
47
|
+
"uDepth": {
|
|
48
|
+
"texture": 34,
|
|
49
|
+
"sampler": 35,
|
|
50
|
+
"type": "sampler2D"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -41,4 +41,4 @@ export declare const MOTION_DRAW_STRIDE = 256;
|
|
|
41
41
|
export declare const MOTION_DRAW_FLOATS = 32;
|
|
42
42
|
/** The motion target's format. Half float holds a uv to a hundredth of a pixel and a view depth. */
|
|
43
43
|
export declare const MOTION_TARGET_FORMAT: GPUTextureFormat;
|
|
44
|
-
export declare const RECON_MOTION_WGSL = "\nstruct MotionFrame {\n /* The scene's own clip transform, with the generated shaders' y negation already folded in. */\n raster: mat4x4<f32>,\n /* This frame's and last frame's view-projections, unjittered, in the matrices' own convention. */\n viewProj: mat4x4<f32>,\n previousViewProj: mat4x4<f32>,\n}\n\nstruct MotionDraw {\n model: mat4x4<f32>,\n previousModel: mat4x4<f32>,\n}\n\n@group(0) @binding(0) var<uniform> frame: MotionFrame;\n@group(0) @binding(1) var<uniform> draw: MotionDraw;\n\nstruct Varyings {\n @builtin(position) clip: vec4<f32>,\n /* Clip positions rather than uv: an interpolator divides by w for us, so dividing these by their\n own interpolated w in the fragment stage is the perspective-correct answer at every pixel. */\n @location(0) now: vec4<f32>,\n @location(1) was: vec4<f32>,\n}\n\n@vertex\nfn motionVert(@location(0) position: vec3<f32>) -> Varyings {\n let world = draw.model * vec4<f32>(position, 1.0);\n let wasWorld = draw.previousModel * vec4<f32>(position, 1.0);\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n/* Normalised device coordinates to the uv the resolve measures in: v increases upward, as the\n references' images do, and the accessor that reads this target is what flips the texture's rows. */\nfn motionUv(clip: vec4<f32>) -> vec2<f32> {\n return clip.xy / clip.w * 0.5 + vec2<f32>(0.5);\n}\n\n/*\n * The skinned stage: the joints this frame and last frame, read from two palette textures of the\n * frame's ring. The same four weighted products in the same order as the scene's own skinning, so\n * the depth this stage produces is the depth the scene wrote.\n */\n@group(1) @binding(0) var palette: texture_2d<f32>;\n@group(1) @binding(1) var previousPalette: texture_2d<f32>;\n\nfn jointOf(source: texture_2d<f32>, index: i32) -> mat4x4<f32> {\n let x = index * 4;\n return mat4x4<f32>(\n textureLoad(source, vec2<i32>(x, 0), 0),\n textureLoad(source, vec2<i32>(x + 1, 0), 0),\n textureLoad(source, vec2<i32>(x + 2, 0), 0),\n textureLoad(source, vec2<i32>(x + 3, 0), 0));\n}\n\nfn skinOf(source: texture_2d<f32>, joints: vec4<f32>, weights: vec4<f32>) -> mat4x4<f32> {\n return jointOf(source, i32(joints.x)) * weights.x\n + jointOf(source, i32(joints.y)) * weights.y\n + jointOf(source, i32(joints.z)) * weights.z\n + jointOf(source, i32(joints.w)) * weights.w;\n}\n\n@vertex\nfn motionSkinnedVert(\n @location(0) position: vec3<f32>,\n @location(11) joints: vec4<f32>,\n @location(12) weights: vec4<f32>,\n) -> Varyings {\n let world = draw.model * (skinOf(palette, joints, weights) * vec4<f32>(position, 1.0));\n let wasWorld =\n draw.previousModel * (skinOf(previousPalette, joints, weights) * vec4<f32>(position, 1.0));\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n/*\n * The rewritten stage: a mesh whose vertices were rewritten this frame reads last frame's rows from\n * a second buffer of the same stride, so each vertex carries both of its positions.\n */\n@vertex\nfn motionDynamicVert(\n @location(0) position: vec3<f32>,\n @location(1) previousPosition: vec3<f32>,\n) -> Varyings {\n let world = draw.model * vec4<f32>(position, 1.0);\n let wasWorld = draw.previousModel * vec4<f32>(previousPosition, 1.0);\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n/*\n * The instanced stage: each instance's matrix this frame and last frame, read from the batch's\n * placement and the copy of last frame's it kept. Slot for slot, so an instance is paired with\n * itself; the per-draw matrices are not read.\n */\n@vertex\nfn motionInstancedVert(\n @location(0) position: vec3<f32>,\n @location(2) m0: vec4<f32>,\n @location(3) m1: vec4<f32>,\n @location(4) m2: vec4<f32>,\n @location(5) m3: vec4<f32>,\n @location(6) p0: vec4<f32>,\n @location(7) p1: vec4<f32>,\n @location(8) p2: vec4<f32>,\n @location(9) p3: vec4<f32>,\n) -> Varyings {\n let world = mat4x4<f32>(m0, m1, m2, m3) * vec4<f32>(position, 1.0);\n let wasWorld = mat4x4<f32>(p0, p1, p2, p3) * vec4<f32>(position, 1.0);\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n@fragment\nfn motionFrag(in: Varyings) -> @location(0) vec4<f32> {\n /*\n * A surface behind last frame's eye has a w that is not positive, and there is no uv for it. The\n * flag stays set: the disocclusion refuses a depth that is not positive, so the resolve drops the\n * history rather than reading it from wherever a divide by a negative w would have pointed.\n */\n let offset = select(vec2<f32>(0.0), motionUv(in.was) - motionUv(in.now), in.was.w > 0.0);\n return vec4<f32>(offset, in.was.w, 1.0);\n}\n";
|
|
44
|
+
export declare const RECON_MOTION_WGSL = "\nstruct MotionFrame {\n /* The scene's own clip transform, with the generated shaders' y negation already folded in. */\n raster: mat4x4<f32>,\n /* This frame's and last frame's view-projections, unjittered, in the matrices' own convention. */\n viewProj: mat4x4<f32>,\n previousViewProj: mat4x4<f32>,\n}\n\nstruct MotionDraw {\n model: mat4x4<f32>,\n previousModel: mat4x4<f32>,\n}\n\n@group(0) @binding(0) var<uniform> frame: MotionFrame;\n@group(0) @binding(1) var<uniform> draw: MotionDraw;\n\nstruct Varyings {\n @builtin(position) clip: vec4<f32>,\n /* Clip positions rather than uv: an interpolator divides by w for us, so dividing these by their\n own interpolated w in the fragment stage is the perspective-correct answer at every pixel. */\n @location(0) now: vec4<f32>,\n @location(1) was: vec4<f32>,\n}\n\n@vertex\nfn motionVert(@location(0) position: vec3<f32>) -> Varyings {\n let world = draw.model * vec4<f32>(position, 1.0);\n let wasWorld = draw.previousModel * vec4<f32>(position, 1.0);\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n/* Normalised device coordinates to the uv the resolve measures in: v increases upward, as the\n references' images do, and the accessor that reads this target is what flips the texture's rows. */\nfn motionUv(clip: vec4<f32>) -> vec2<f32> {\n return clip.xy / clip.w * 0.5 + vec2<f32>(0.5);\n}\n\n/*\n * The skinned stage: the joints this frame and last frame, read from two palette textures of the\n * frame's ring. The same four weighted products in the same order as the scene's own skinning, so\n * the depth this stage produces is the depth the scene wrote.\n */\n@group(1) @binding(0) var palette: texture_2d<f32>;\n@group(1) @binding(1) var previousPalette: texture_2d<f32>;\n\nfn jointOf(source: texture_2d<f32>, index: i32) -> mat4x4<f32> {\n let x = index * 4;\n return mat4x4<f32>(\n textureLoad(source, vec2<i32>(x, 0), 0),\n textureLoad(source, vec2<i32>(x + 1, 0), 0),\n textureLoad(source, vec2<i32>(x + 2, 0), 0),\n textureLoad(source, vec2<i32>(x + 3, 0), 0));\n}\n\nfn skinOf(source: texture_2d<f32>, joints: vec4<f32>, weights: vec4<f32>) -> mat4x4<f32> {\n return jointOf(source, i32(joints.x)) * weights.x\n + jointOf(source, i32(joints.y)) * weights.y\n + jointOf(source, i32(joints.z)) * weights.z\n + jointOf(source, i32(joints.w)) * weights.w;\n}\n\n@vertex\nfn motionSkinnedVert(\n @location(0) position: vec3<f32>,\n @location(11) joints: vec4<f32>,\n @location(12) weights: vec4<f32>,\n) -> Varyings {\n let world = draw.model * (skinOf(palette, joints, weights) * vec4<f32>(position, 1.0));\n let wasWorld =\n draw.previousModel * (skinOf(previousPalette, joints, weights) * vec4<f32>(position, 1.0));\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n/*\n * The same for a rig with eight influences a vertex, the second four at the scene's own locations\n * 14 and 15 and summed after the first, as `skinMatrix()` sums them with `SKIN_EIGHT` on \u2014 or the\n * motion of a face or a shoulder would be the four heaviest joints' alone.\n */\n@vertex\nfn motionSkinnedEightVert(\n @location(0) position: vec3<f32>,\n @location(11) joints: vec4<f32>,\n @location(12) weights: vec4<f32>,\n @location(14) joints2: vec4<f32>,\n @location(15) weights2: vec4<f32>,\n) -> Varyings {\n let skin = skinOf(palette, joints, weights) + skinOf(palette, joints2, weights2);\n let wasSkin =\n skinOf(previousPalette, joints, weights) + skinOf(previousPalette, joints2, weights2);\n let world = draw.model * (skin * vec4<f32>(position, 1.0));\n let wasWorld = draw.previousModel * (wasSkin * vec4<f32>(position, 1.0));\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n/*\n * The cloth-bound stage: a skinned vertex moved toward its simulation triangle by its painted\n * weight, as shaders/clothBinding.ts moves it in the scene, once with this frame's particles and\n * once with last frame's. **The same arithmetic in the same order**, or the depth this stage writes\n * is not the scene's and the equal test admits none of the garment. The binding's turn is not\n * needed: a motion is where a point went, not which way it faces.\n */\n@group(2) @binding(0) var clothBinding: texture_2d<f32>;\n@group(2) @binding(1) var clothParticles: texture_2d<f32>;\n@group(2) @binding(2) var previousClothParticles: texture_2d<f32>;\n\nfn clothTexel(i: i32, width: i32) -> vec2<i32> {\n return vec2<i32>(i % width, i / width);\n}\n\nfn clothPoint(particles: texture_2d<f32>, indices: vec4<f32>, at: vec4<f32>) -> vec3<f32> {\n let width = i32(textureDimensions(particles, 0).x);\n let a = i32(indices.x);\n let b = i32(indices.y);\n let c = i32(indices.z);\n let pa = textureLoad(particles, clothTexel(a, width), 0).xyz;\n if (a == b && b == c) {\n return pa;\n }\n let pb = textureLoad(particles, clothTexel(b, width), 0).xyz;\n let pc = textureLoad(particles, clothTexel(c, width), 0).xyz;\n let n = normalize(cross(pb - pa, pc - pa));\n return pa * (1.0 - at.x - at.y) + pb * at.x + pc * at.y + n * at.z;\n}\n\n/* A skinned point now and last frame, carried to the cloth by the vertex's own weight. */\nfn clothVaryings(vertex: u32, world: vec4<f32>, wasWorld: vec4<f32>) -> Varyings {\n let width = i32(textureDimensions(clothBinding, 0).x);\n let indices = textureLoad(clothBinding, clothTexel(i32(vertex) * 2, width), 0);\n let at = textureLoad(clothBinding, clothTexel(i32(vertex) * 2 + 1, width), 0);\n let follow = indices.w;\n let placed = vec4<f32>(mix(world.xyz, clothPoint(clothParticles, indices, at), follow), world.w);\n let wasPlaced = vec4<f32>(\n mix(wasWorld.xyz, clothPoint(previousClothParticles, indices, at), follow),\n wasWorld.w);\n var out: Varyings;\n out.clip = frame.raster * placed;\n out.now = frame.viewProj * placed;\n out.was = frame.previousViewProj * wasPlaced;\n return out;\n}\n\n@vertex\nfn motionClothVert(\n @builtin(vertex_index) vertex: u32,\n @location(0) position: vec3<f32>,\n @location(11) joints: vec4<f32>,\n @location(12) weights: vec4<f32>,\n) -> Varyings {\n let world = draw.model * (skinOf(palette, joints, weights) * vec4<f32>(position, 1.0));\n let wasWorld =\n draw.previousModel * (skinOf(previousPalette, joints, weights) * vec4<f32>(position, 1.0));\n return clothVaryings(vertex, world, wasWorld);\n}\n\n@vertex\nfn motionClothEightVert(\n @builtin(vertex_index) vertex: u32,\n @location(0) position: vec3<f32>,\n @location(11) joints: vec4<f32>,\n @location(12) weights: vec4<f32>,\n @location(14) joints2: vec4<f32>,\n @location(15) weights2: vec4<f32>,\n) -> Varyings {\n let skin = skinOf(palette, joints, weights) + skinOf(palette, joints2, weights2);\n let wasSkin =\n skinOf(previousPalette, joints, weights) + skinOf(previousPalette, joints2, weights2);\n let world = draw.model * (skin * vec4<f32>(position, 1.0));\n let wasWorld = draw.previousModel * (wasSkin * vec4<f32>(position, 1.0));\n return clothVaryings(vertex, world, wasWorld);\n}\n\n/*\n * The rewritten stage: a mesh whose vertices were rewritten this frame reads last frame's rows from\n * a second buffer of the same stride, so each vertex carries both of its positions.\n */\n@vertex\nfn motionDynamicVert(\n @location(0) position: vec3<f32>,\n @location(1) previousPosition: vec3<f32>,\n) -> Varyings {\n let world = draw.model * vec4<f32>(position, 1.0);\n let wasWorld = draw.previousModel * vec4<f32>(previousPosition, 1.0);\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n/*\n * The instanced stage: each instance's matrix this frame and last frame, read from the batch's\n * placement and the copy of last frame's it kept. Slot for slot, so an instance is paired with\n * itself; the per-draw matrices are not read.\n */\n@vertex\nfn motionInstancedVert(\n @location(0) position: vec3<f32>,\n @location(2) m0: vec4<f32>,\n @location(3) m1: vec4<f32>,\n @location(4) m2: vec4<f32>,\n @location(5) m3: vec4<f32>,\n @location(6) p0: vec4<f32>,\n @location(7) p1: vec4<f32>,\n @location(8) p2: vec4<f32>,\n @location(9) p3: vec4<f32>,\n) -> Varyings {\n let world = mat4x4<f32>(m0, m1, m2, m3) * vec4<f32>(position, 1.0);\n let wasWorld = mat4x4<f32>(p0, p1, p2, p3) * vec4<f32>(position, 1.0);\n var out: Varyings;\n out.clip = frame.raster * world;\n out.now = frame.viewProj * world;\n out.was = frame.previousViewProj * wasWorld;\n return out;\n}\n\n@fragment\nfn motionFrag(in: Varyings) -> @location(0) vec4<f32> {\n /*\n * A surface behind last frame's eye has a w that is not positive, and there is no uv for it. The\n * flag stays set: the disocclusion refuses a depth that is not positive, so the resolve drops the\n * history rather than reading it from wherever a divide by a negative w would have pointed.\n */\n let offset = select(vec2<f32>(0.0), motionUv(in.was) - motionUv(in.now), in.was.w > 0.0);\n return vec4<f32>(offset, in.was.w, 1.0);\n}\n";
|
|
@@ -123,6 +123,108 @@ fn motionSkinnedVert(
|
|
|
123
123
|
return out;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/*
|
|
127
|
+
* The same for a rig with eight influences a vertex, the second four at the scene's own locations
|
|
128
|
+
* 14 and 15 and summed after the first, as \`skinMatrix()\` sums them with \`SKIN_EIGHT\` on — or the
|
|
129
|
+
* motion of a face or a shoulder would be the four heaviest joints' alone.
|
|
130
|
+
*/
|
|
131
|
+
@vertex
|
|
132
|
+
fn motionSkinnedEightVert(
|
|
133
|
+
@location(0) position: vec3<f32>,
|
|
134
|
+
@location(11) joints: vec4<f32>,
|
|
135
|
+
@location(12) weights: vec4<f32>,
|
|
136
|
+
@location(14) joints2: vec4<f32>,
|
|
137
|
+
@location(15) weights2: vec4<f32>,
|
|
138
|
+
) -> Varyings {
|
|
139
|
+
let skin = skinOf(palette, joints, weights) + skinOf(palette, joints2, weights2);
|
|
140
|
+
let wasSkin =
|
|
141
|
+
skinOf(previousPalette, joints, weights) + skinOf(previousPalette, joints2, weights2);
|
|
142
|
+
let world = draw.model * (skin * vec4<f32>(position, 1.0));
|
|
143
|
+
let wasWorld = draw.previousModel * (wasSkin * vec4<f32>(position, 1.0));
|
|
144
|
+
var out: Varyings;
|
|
145
|
+
out.clip = frame.raster * world;
|
|
146
|
+
out.now = frame.viewProj * world;
|
|
147
|
+
out.was = frame.previousViewProj * wasWorld;
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/*
|
|
152
|
+
* The cloth-bound stage: a skinned vertex moved toward its simulation triangle by its painted
|
|
153
|
+
* weight, as shaders/clothBinding.ts moves it in the scene, once with this frame's particles and
|
|
154
|
+
* once with last frame's. **The same arithmetic in the same order**, or the depth this stage writes
|
|
155
|
+
* is not the scene's and the equal test admits none of the garment. The binding's turn is not
|
|
156
|
+
* needed: a motion is where a point went, not which way it faces.
|
|
157
|
+
*/
|
|
158
|
+
@group(2) @binding(0) var clothBinding: texture_2d<f32>;
|
|
159
|
+
@group(2) @binding(1) var clothParticles: texture_2d<f32>;
|
|
160
|
+
@group(2) @binding(2) var previousClothParticles: texture_2d<f32>;
|
|
161
|
+
|
|
162
|
+
fn clothTexel(i: i32, width: i32) -> vec2<i32> {
|
|
163
|
+
return vec2<i32>(i % width, i / width);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
fn clothPoint(particles: texture_2d<f32>, indices: vec4<f32>, at: vec4<f32>) -> vec3<f32> {
|
|
167
|
+
let width = i32(textureDimensions(particles, 0).x);
|
|
168
|
+
let a = i32(indices.x);
|
|
169
|
+
let b = i32(indices.y);
|
|
170
|
+
let c = i32(indices.z);
|
|
171
|
+
let pa = textureLoad(particles, clothTexel(a, width), 0).xyz;
|
|
172
|
+
if (a == b && b == c) {
|
|
173
|
+
return pa;
|
|
174
|
+
}
|
|
175
|
+
let pb = textureLoad(particles, clothTexel(b, width), 0).xyz;
|
|
176
|
+
let pc = textureLoad(particles, clothTexel(c, width), 0).xyz;
|
|
177
|
+
let n = normalize(cross(pb - pa, pc - pa));
|
|
178
|
+
return pa * (1.0 - at.x - at.y) + pb * at.x + pc * at.y + n * at.z;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* A skinned point now and last frame, carried to the cloth by the vertex's own weight. */
|
|
182
|
+
fn clothVaryings(vertex: u32, world: vec4<f32>, wasWorld: vec4<f32>) -> Varyings {
|
|
183
|
+
let width = i32(textureDimensions(clothBinding, 0).x);
|
|
184
|
+
let indices = textureLoad(clothBinding, clothTexel(i32(vertex) * 2, width), 0);
|
|
185
|
+
let at = textureLoad(clothBinding, clothTexel(i32(vertex) * 2 + 1, width), 0);
|
|
186
|
+
let follow = indices.w;
|
|
187
|
+
let placed = vec4<f32>(mix(world.xyz, clothPoint(clothParticles, indices, at), follow), world.w);
|
|
188
|
+
let wasPlaced = vec4<f32>(
|
|
189
|
+
mix(wasWorld.xyz, clothPoint(previousClothParticles, indices, at), follow),
|
|
190
|
+
wasWorld.w);
|
|
191
|
+
var out: Varyings;
|
|
192
|
+
out.clip = frame.raster * placed;
|
|
193
|
+
out.now = frame.viewProj * placed;
|
|
194
|
+
out.was = frame.previousViewProj * wasPlaced;
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@vertex
|
|
199
|
+
fn motionClothVert(
|
|
200
|
+
@builtin(vertex_index) vertex: u32,
|
|
201
|
+
@location(0) position: vec3<f32>,
|
|
202
|
+
@location(11) joints: vec4<f32>,
|
|
203
|
+
@location(12) weights: vec4<f32>,
|
|
204
|
+
) -> Varyings {
|
|
205
|
+
let world = draw.model * (skinOf(palette, joints, weights) * vec4<f32>(position, 1.0));
|
|
206
|
+
let wasWorld =
|
|
207
|
+
draw.previousModel * (skinOf(previousPalette, joints, weights) * vec4<f32>(position, 1.0));
|
|
208
|
+
return clothVaryings(vertex, world, wasWorld);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@vertex
|
|
212
|
+
fn motionClothEightVert(
|
|
213
|
+
@builtin(vertex_index) vertex: u32,
|
|
214
|
+
@location(0) position: vec3<f32>,
|
|
215
|
+
@location(11) joints: vec4<f32>,
|
|
216
|
+
@location(12) weights: vec4<f32>,
|
|
217
|
+
@location(14) joints2: vec4<f32>,
|
|
218
|
+
@location(15) weights2: vec4<f32>,
|
|
219
|
+
) -> Varyings {
|
|
220
|
+
let skin = skinOf(palette, joints, weights) + skinOf(palette, joints2, weights2);
|
|
221
|
+
let wasSkin =
|
|
222
|
+
skinOf(previousPalette, joints, weights) + skinOf(previousPalette, joints2, weights2);
|
|
223
|
+
let world = draw.model * (skin * vec4<f32>(position, 1.0));
|
|
224
|
+
let wasWorld = draw.previousModel * (wasSkin * vec4<f32>(position, 1.0));
|
|
225
|
+
return clothVaryings(vertex, world, wasWorld);
|
|
226
|
+
}
|
|
227
|
+
|
|
126
228
|
/*
|
|
127
229
|
* The rewritten stage: a mesh whose vertices were rewritten this frame reads last frame's rows from
|
|
128
230
|
* a second buffer of the same stride, so each vertex carries both of its positions.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SKIN_BLUR_FRAG: string;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skin's screen-space scattering: one axis of the blur that spreads the diffuse pass by Burley's
|
|
3
|
+
* profile, and on the second axis the sum the frame takes back. `skinBlur.ts` beside the render
|
|
4
|
+
* directory is the kernel's reference and says what it gives up.
|
|
5
|
+
*
|
|
6
|
+
* **One pass, run twice**: along x into a target of its own, keeping the profile in the alpha, then
|
|
7
|
+
* along y blended additively into the frame — its colour added, the frame's alpha kept.
|
|
8
|
+
*
|
|
9
|
+
* **Refuses what is not the same skin**: a neighbour that wrote no skin, or one further in depth
|
|
10
|
+
* than four of the profile's widest distances, takes no weight, and what is kept is divided by
|
|
11
|
+
* what was kept, so a cheek's light does not pull toward the black beside its silhouette. A tap
|
|
12
|
+
* part skin is counted for the part it is: the target is read as coverage-weighted, which is what
|
|
13
|
+
* a filtered tap across an edge already is.
|
|
14
|
+
*/
|
|
15
|
+
import { glslIsFarDepth, glslSceneDepthToNdc } from '../depthConvention.js';
|
|
16
|
+
import { SKIN_BLUR_EDGES, SKIN_BLUR_TAPS, SKIN_PROFILES } from '../skinBlur.js';
|
|
17
|
+
const list = (values) => values.map((v) => v.toFixed(2)).join(', ');
|
|
18
|
+
export const SKIN_BLUR_FRAG = `#version 300 es
|
|
19
|
+
precision highp float;
|
|
20
|
+
|
|
21
|
+
in vec2 vUv;
|
|
22
|
+
|
|
23
|
+
/** The diffuse pass, or the first axis' result: diffuse in rgb, the profile as (index + 1) / 8. */
|
|
24
|
+
uniform sampler2D uSkin;
|
|
25
|
+
/** highp, for the reason the ambient occlusion blur gives: eight bits of depth find false edges. */
|
|
26
|
+
uniform highp sampler2D uDepth;
|
|
27
|
+
/** One texel along the axis being blurred, in UV. The other component is zero. */
|
|
28
|
+
uniform vec2 uStep;
|
|
29
|
+
/** A depth sample to view-space metres, as the ambient occlusion blur takes it. */
|
|
30
|
+
uniform vec4 uDepthToViewZ;
|
|
31
|
+
/** How many pixels a metre spans at a metre's distance. */
|
|
32
|
+
uniform float uFocal;
|
|
33
|
+
/** Each profile's scatter distance per channel, in metres. */
|
|
34
|
+
uniform vec4 uProfiles[${SKIN_PROFILES}];
|
|
35
|
+
|
|
36
|
+
out vec4 fragColor;
|
|
37
|
+
|
|
38
|
+
const float TAPS[${SKIN_BLUR_TAPS.length}] = float[${SKIN_BLUR_TAPS.length}](${list(SKIN_BLUR_TAPS)});
|
|
39
|
+
const float EDGES[${SKIN_BLUR_EDGES.length}] = float[${SKIN_BLUR_EDGES.length}](${list(SKIN_BLUR_EDGES)});
|
|
40
|
+
|
|
41
|
+
float viewZ(float depth) {
|
|
42
|
+
float ndc = ${glslSceneDepthToNdc('depth')};
|
|
43
|
+
return (uDepthToViewZ.x * ndc + uDepthToViewZ.y) / (uDepthToViewZ.z * ndc + uDepthToViewZ.w);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Burley's profile across a line, integrated from 0 to x: one half at infinity. */
|
|
47
|
+
vec3 burleyMass(float x, vec3 d) {
|
|
48
|
+
return 0.5 - (exp(-x / d) + 3.0 * exp(-x / (3.0 * d))) * 0.125;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void main() {
|
|
52
|
+
vec4 own = textureLod(uSkin, vUv, 0.0);
|
|
53
|
+
/*
|
|
54
|
+
* Not skin: nothing here to spread, and nothing to add. Any alpha is skin, because a pixel a
|
|
55
|
+
* silhouette crosses under multisampling resolves to its covered share of the profile's code, and
|
|
56
|
+
* its colour to that share of the diffuse, which is exactly what it owes the frame.
|
|
57
|
+
*/
|
|
58
|
+
if (own.a < 1e-4) {
|
|
59
|
+
fragColor = vec4(0.0);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
float depth = textureLod(uDepth, vUv, 0.0).r;
|
|
63
|
+
if (${glslIsFarDepth('depth')}) {
|
|
64
|
+
fragColor = own;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
/* A part-covered pixel's code is its share of the whole: read it as the nearest, which is the
|
|
68
|
+
right profile at half coverage and up, and a neighbouring one only on a silhouette below it. */
|
|
69
|
+
int profile = clamp(int(own.a * 8.0 + 0.5) - 1, 0, ${SKIN_PROFILES - 1});
|
|
70
|
+
vec3 d = max(uProfiles[profile].xyz, vec3(1e-6));
|
|
71
|
+
float widest = max(d.r, max(d.g, d.b));
|
|
72
|
+
float z = abs(viewZ(depth));
|
|
73
|
+
/* The widest distance in pixels here: under half of one, there is nothing to spread across. */
|
|
74
|
+
float pixels = widest * uFocal / max(z, 1e-4);
|
|
75
|
+
if (pixels < 0.5) {
|
|
76
|
+
fragColor = own;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
vec3 centre = 2.0 * burleyMass(EDGES[0] * widest, d);
|
|
80
|
+
vec3 sum = own.rgb * centre;
|
|
81
|
+
vec3 weight = centre;
|
|
82
|
+
for (int i = 1; i < ${SKIN_BLUR_TAPS.length}; i++) {
|
|
83
|
+
vec3 outer = i < ${SKIN_BLUR_EDGES.length} ? burleyMass(EDGES[min(i, ${SKIN_BLUR_EDGES.length - 1})] * widest, d) : vec3(0.5);
|
|
84
|
+
vec3 w = outer - burleyMass(EDGES[i - 1] * widest, d);
|
|
85
|
+
for (int side = -1; side <= 1; side += 2) {
|
|
86
|
+
vec2 uv = vUv + uStep * (float(side) * TAPS[i] * pixels);
|
|
87
|
+
vec4 tap = textureLod(uSkin, uv, 0.0);
|
|
88
|
+
float tapZ = abs(viewZ(textureLod(uDepth, uv, 0.0).r));
|
|
89
|
+
float keep = clamp(1.0 - abs(tapZ - z) / (4.0 * widest), 0.0, 1.0);
|
|
90
|
+
/*
|
|
91
|
+
* How much of the tap is skin: a filtered tap astride a silhouette is part skin and part
|
|
92
|
+
* the black beside it, in colour and in alpha alike, so its alpha over this pixel's says the
|
|
93
|
+
* share, and the colour is already that share of the skin's — counted as such, it neither
|
|
94
|
+
* darkens the edge nor drops out.
|
|
95
|
+
*/
|
|
96
|
+
float cover = clamp(tap.a / own.a, 0.0, 1.0);
|
|
97
|
+
sum += tap.rgb * w * keep;
|
|
98
|
+
weight += w * (cover * keep);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
fragColor = vec4(sum / weight, own.a);
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
@@ -14,4 +14,6 @@
|
|
|
14
14
|
* What would make it wrong is a second vertex flag: four variants dedupe less well than two, so
|
|
15
15
|
* re-measure before adding one.
|
|
16
16
|
*/
|
|
17
|
-
export declare const SKINNING_GLSL = "\n/**\n * The joint palette, four texels a matrix, one row.\n *\n * A texture rather than a `uniform mat4[]`. The 2026-08-07 rule that keeps samples out of\n * unprovable branches is about *implicit derivatives*, which a vertex stage does not compute, so\n * it has nothing to say here \u2014 and `texelFetch` takes an integer coordinate with no level\n * inferred at all. What a uniform array would have cost is the cap: MAX_VERTEX_UNIFORM_VECTORS is\n * 256 on the WebGL2 floor and this shader already spends fifteen, which leaves sixty joints.\n *\n * What this costs is a texture upload per skinned draw. What would make it wrong is a profile\n * showing that upload is the limit; the fix is one texture for every character with a row offset.\n */\nuniform highp sampler2D uJointPalette;\n\nlayout(location = 11) in vec4 aJoints;\nlayout(location = 12) in vec4 aWeights;\n\n/** One joint's matrix, read as four consecutive texels of row 0. */\nmat4 jointMatrix(int index) {\n int x = index * 4;\n return mat4(\n texelFetch(uJointPalette, ivec2(x, 0), 0),\n texelFetch(uJointPalette, ivec2(x + 1, 0), 0),\n texelFetch(uJointPalette, ivec2(x + 2, 0), 0),\n texelFetch(uJointPalette, ivec2(x + 3, 0), 0));\n}\n\n/**\n * The four influences, weighted.\n *\n * Weights are normalised by the importer rather than here: normalising per vertex per frame costs\n * a divide on every vertex to correct data an importer should have fixed once, and `gltfSkin.ts`\n * warns when a set does not sum to one. What would make it wrong is a caller building a MeshData\n * by hand with unnormalised weights, which shades slightly dark or bright rather than breaking.\n */\nmat4 skinMatrix() {\n
|
|
17
|
+
export declare const SKINNING_GLSL = "\n/**\n * The joint palette, four texels a matrix, one row.\n *\n * A texture rather than a `uniform mat4[]`. The 2026-08-07 rule that keeps samples out of\n * unprovable branches is about *implicit derivatives*, which a vertex stage does not compute, so\n * it has nothing to say here \u2014 and `texelFetch` takes an integer coordinate with no level\n * inferred at all. What a uniform array would have cost is the cap: MAX_VERTEX_UNIFORM_VECTORS is\n * 256 on the WebGL2 floor and this shader already spends fifteen, which leaves sixty joints.\n *\n * What this costs is a texture upload per skinned draw. What would make it wrong is a profile\n * showing that upload is the limit; the fix is one texture for every character with a row offset.\n */\nuniform highp sampler2D uJointPalette;\n\nlayout(location = 11) in vec4 aJoints;\nlayout(location = 12) in vec4 aWeights;\n/*\n * **The fifth to eighth influences, read only by a pipeline built for a mesh that has them.**\n *\n * Declared in every skinned variant at the last two locations WebGL2 guarantees \u2014 13 is the channel,\n * and an instanced draw, which takes 11 to 15, cannot skin \u2014 and fed zeros by the absent-attribute\n * constants for a mesh with four. `SKIN_EIGHT` is a pipeline constant rather than a permutation,\n * so the generated vertex stages do not double: off, the device compiles the second sum away and a\n * four-influence mesh pays nothing; on, it is four more palette reads a vertex.\n */\nconst bool SKIN_EIGHT = false; // wgsl:override\nlayout(location = 14) in vec4 aJoints2;\nlayout(location = 15) in vec4 aWeights2;\n\n/** One joint's matrix, read as four consecutive texels of row 0. */\nmat4 jointMatrix(int index) {\n int x = index * 4;\n return mat4(\n texelFetch(uJointPalette, ivec2(x, 0), 0),\n texelFetch(uJointPalette, ivec2(x + 1, 0), 0),\n texelFetch(uJointPalette, ivec2(x + 2, 0), 0),\n texelFetch(uJointPalette, ivec2(x + 3, 0), 0));\n}\n\n/**\n * The four influences, weighted.\n *\n * Weights are normalised by the importer rather than here: normalising per vertex per frame costs\n * a divide on every vertex to correct data an importer should have fixed once, and `gltfSkin.ts`\n * warns when a set does not sum to one. What would make it wrong is a caller building a MeshData\n * by hand with unnormalised weights, which shades slightly dark or bright rather than breaking.\n */\nmat4 skinMatrix() {\n mat4 m = jointMatrix(int(aJoints.x)) * aWeights.x\n + jointMatrix(int(aJoints.y)) * aWeights.y\n + jointMatrix(int(aJoints.z)) * aWeights.z\n + jointMatrix(int(aJoints.w)) * aWeights.w;\n if (SKIN_EIGHT) {\n m += jointMatrix(int(aJoints2.x)) * aWeights2.x\n + jointMatrix(int(aJoints2.y)) * aWeights2.y\n + jointMatrix(int(aJoints2.z)) * aWeights2.z\n + jointMatrix(int(aJoints2.w)) * aWeights2.w;\n }\n return m;\n}\n\n";
|
|
18
|
+
/** The source above with the eight-influence switch on, for a WebGL2 program built for such a mesh. */
|
|
19
|
+
export declare function skinEight(source: string): string;
|
|
@@ -31,6 +31,18 @@ uniform highp sampler2D uJointPalette;
|
|
|
31
31
|
|
|
32
32
|
layout(location = 11) in vec4 aJoints;
|
|
33
33
|
layout(location = 12) in vec4 aWeights;
|
|
34
|
+
/*
|
|
35
|
+
* **The fifth to eighth influences, read only by a pipeline built for a mesh that has them.**
|
|
36
|
+
*
|
|
37
|
+
* Declared in every skinned variant at the last two locations WebGL2 guarantees — 13 is the channel,
|
|
38
|
+
* and an instanced draw, which takes 11 to 15, cannot skin — and fed zeros by the absent-attribute
|
|
39
|
+
* constants for a mesh with four. \`SKIN_EIGHT\` is a pipeline constant rather than a permutation,
|
|
40
|
+
* so the generated vertex stages do not double: off, the device compiles the second sum away and a
|
|
41
|
+
* four-influence mesh pays nothing; on, it is four more palette reads a vertex.
|
|
42
|
+
*/
|
|
43
|
+
const bool SKIN_EIGHT = false; // wgsl:override
|
|
44
|
+
layout(location = 14) in vec4 aJoints2;
|
|
45
|
+
layout(location = 15) in vec4 aWeights2;
|
|
34
46
|
|
|
35
47
|
/** One joint's matrix, read as four consecutive texels of row 0. */
|
|
36
48
|
mat4 jointMatrix(int index) {
|
|
@@ -51,9 +63,24 @@ mat4 jointMatrix(int index) {
|
|
|
51
63
|
* by hand with unnormalised weights, which shades slightly dark or bright rather than breaking.
|
|
52
64
|
*/
|
|
53
65
|
mat4 skinMatrix() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
mat4 m = jointMatrix(int(aJoints.x)) * aWeights.x
|
|
67
|
+
+ jointMatrix(int(aJoints.y)) * aWeights.y
|
|
68
|
+
+ jointMatrix(int(aJoints.z)) * aWeights.z
|
|
69
|
+
+ jointMatrix(int(aJoints.w)) * aWeights.w;
|
|
70
|
+
if (SKIN_EIGHT) {
|
|
71
|
+
m += jointMatrix(int(aJoints2.x)) * aWeights2.x
|
|
72
|
+
+ jointMatrix(int(aJoints2.y)) * aWeights2.y
|
|
73
|
+
+ jointMatrix(int(aJoints2.z)) * aWeights2.z
|
|
74
|
+
+ jointMatrix(int(aJoints2.w)) * aWeights2.w;
|
|
75
|
+
}
|
|
76
|
+
return m;
|
|
58
77
|
}
|
|
78
|
+
|
|
59
79
|
`;
|
|
80
|
+
/** The source above with the eight-influence switch on, for a WebGL2 program built for such a mesh. */
|
|
81
|
+
export function skinEight(source) {
|
|
82
|
+
const off = 'const bool SKIN_EIGHT = false;';
|
|
83
|
+
if (!source.includes(off))
|
|
84
|
+
throw new Error('skinEight: the source carries no SKIN_EIGHT switch');
|
|
85
|
+
return source.replace(off, 'const bool SKIN_EIGHT = true;');
|
|
86
|
+
}
|
|
@@ -2,6 +2,7 @@ import { type GlassOptions, type ResolvedGlass } from './glass.ts';
|
|
|
2
2
|
import type { ReadonlyMat4 } from 'gl-matrix';
|
|
3
3
|
import type { InstanceData } from './instancedMesh.ts';
|
|
4
4
|
import type { InstancedHandle, MeshHandle, ScatterHandle } from './backend/api.ts';
|
|
5
|
+
import type { ClothBindingHandle, ClothParticlesHandle } from './backend/api.ts';
|
|
5
6
|
import type { MeshInstances } from './instances.ts';
|
|
6
7
|
import type { SurfaceMaterial } from './surfaceTexture.ts';
|
|
7
8
|
import type { SurfaceTextureHandle } from './backend/api.ts';
|
|
@@ -60,6 +61,11 @@ export declare function castsDepth(material: SceneCasterMaterial | undefined): b
|
|
|
60
61
|
* states from the other side, so a caster is exactly one of the two.
|
|
61
62
|
*/
|
|
62
63
|
export declare function glassOf(material: SceneCasterMaterial | undefined, out: ResolvedGlass): boolean;
|
|
64
|
+
/** A skinned caster's cloth: the mesh's binding and the character's particles. See `setCloth`. */
|
|
65
|
+
export interface ShadowCasterCloth {
|
|
66
|
+
readonly binding: ClothBindingHandle;
|
|
67
|
+
readonly particles: ClothParticlesHandle;
|
|
68
|
+
}
|
|
63
69
|
export interface ShadowCasterSink {
|
|
64
70
|
/** A rigid mesh at a model transform: the world, a prop, a static piece of scenery. */
|
|
65
71
|
mesh(mesh: MeshHandle, model: ReadonlyMat4, material?: SceneCasterMaterial): void;
|
|
@@ -73,7 +79,13 @@ export interface ShadowCasterSink {
|
|
|
73
79
|
*
|
|
74
80
|
* Sixteen floats a joint, column-major, exactly as `Skeleton.palette` produces.
|
|
75
81
|
*/
|
|
76
|
-
skinnedMesh(mesh: MeshHandle, model: ReadonlyMat4, palette: Float32Array, material?: SceneCasterMaterial
|
|
82
|
+
skinnedMesh(mesh: MeshHandle, model: ReadonlyMat4, palette: Float32Array, material?: SceneCasterMaterial,
|
|
83
|
+
/**
|
|
84
|
+
* The cloth the visible draw places this mesh by, if any — for the reason the palette is not
|
|
85
|
+
* optional in spirit: a garment cast from its skinning alone throws a shadow that does not
|
|
86
|
+
* move as the cloth does.
|
|
87
|
+
*/
|
|
88
|
+
cloth?: ShadowCasterCloth): void;
|
|
77
89
|
/**
|
|
78
90
|
* An instanced batch of rigid meshes, placed by the same matrices the visible draw uses.
|
|
79
91
|
*
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skin's screen-space scattering, as `shaders/skinBlur.ts` spreads it: the reference its tests hold
|
|
3
|
+
* the kernel to, and nothing at run time calls it.
|
|
4
|
+
*
|
|
5
|
+
* **What it spreads.** With `skinScattering: 'screen-space'`, a skin draw writes its specular to the
|
|
6
|
+
* frame and its diffuse — the light that went beneath the surface — to a target of its own, with the
|
|
7
|
+
* profile it scatters by in the alpha. Before anything blended is drawn, that target is blurred
|
|
8
|
+
* along the screen's two axes by Burley's normalised diffusion, one width per channel, and added
|
|
9
|
+
* back: light that entered a cheek leaves it a centimetre away, reddest furthest, across the
|
|
10
|
+
* pixels that centimetre covers at the cheek's distance. The pre-integrated fit stays in the lit
|
|
11
|
+
* stage for what this cannot see — a terminator's curvature — and this carries what that cannot:
|
|
12
|
+
* light crossing a shadow's edge, or a nostril's rim, in the picture rather than in a fit.
|
|
13
|
+
*
|
|
14
|
+
* **Separable, which the profile is not**: two 1D passes with Burley's profile integrated across a
|
|
15
|
+
* line, as Jimenez's separable subsurface scattering does. What it gives up is the radial shape, a
|
|
16
|
+
* blur a little squarer than the profile; what it buys is thirteen taps an axis rather than a disc.
|
|
17
|
+
*
|
|
18
|
+
* **Each tap is the profile's mass over its cell, in closed form**, so a channel's weights sum to
|
|
19
|
+
* one before any are refused, and a channel that travels a quarter as far as the widest keeps most
|
|
20
|
+
* of its light at the centre. The taps are placed in units of the widest channel's distance and
|
|
21
|
+
* closer together near the centre, where the profile's sharp peak is.
|
|
22
|
+
*/
|
|
23
|
+
/** The taps' distances from the centre, one side, in units of the widest channel's distance. */
|
|
24
|
+
export declare const SKIN_BLUR_TAPS: readonly [0, 0.4, 1.1, 2.1, 3.5, 5.6, 9];
|
|
25
|
+
/**
|
|
26
|
+
* Where each tap's cell ends, in the same units: halfway to the next tap, and the last cell runs
|
|
27
|
+
* to infinity, so the profile's whole mass is somewhere.
|
|
28
|
+
*/
|
|
29
|
+
export declare const SKIN_BLUR_EDGES: readonly [0.2, 0.75, 1.6, 2.8, 4.55, 7.3];
|
|
30
|
+
/** How many profiles a frame's skin can name: `SkinModel.profile`. */
|
|
31
|
+
export declare const SKIN_PROFILES = 8;
|
|
32
|
+
/**
|
|
33
|
+
* Burley's profile across a line, `(e^(−x/d) + e^(−x/3d)) / 8d`, integrated from 0 to `x`: half of
|
|
34
|
+
* it lies on each side, so this reaches ½ at infinity.
|
|
35
|
+
*/
|
|
36
|
+
export declare function burleyMass(x: number, d: number): number;
|
|
37
|
+
/**
|
|
38
|
+
* Tap `tap`'s weight for one channel scattering `d`, the taps spaced by `widest`: the centre's cell
|
|
39
|
+
* is both sides of it, every other cell one side, and a tap on each side takes this weight.
|
|
40
|
+
*/
|
|
41
|
+
export declare function skinBlurWeight(tap: number, d: number, widest: number): number;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skin's screen-space scattering, as `shaders/skinBlur.ts` spreads it: the reference its tests hold
|
|
3
|
+
* the kernel to, and nothing at run time calls it.
|
|
4
|
+
*
|
|
5
|
+
* **What it spreads.** With `skinScattering: 'screen-space'`, a skin draw writes its specular to the
|
|
6
|
+
* frame and its diffuse — the light that went beneath the surface — to a target of its own, with the
|
|
7
|
+
* profile it scatters by in the alpha. Before anything blended is drawn, that target is blurred
|
|
8
|
+
* along the screen's two axes by Burley's normalised diffusion, one width per channel, and added
|
|
9
|
+
* back: light that entered a cheek leaves it a centimetre away, reddest furthest, across the
|
|
10
|
+
* pixels that centimetre covers at the cheek's distance. The pre-integrated fit stays in the lit
|
|
11
|
+
* stage for what this cannot see — a terminator's curvature — and this carries what that cannot:
|
|
12
|
+
* light crossing a shadow's edge, or a nostril's rim, in the picture rather than in a fit.
|
|
13
|
+
*
|
|
14
|
+
* **Separable, which the profile is not**: two 1D passes with Burley's profile integrated across a
|
|
15
|
+
* line, as Jimenez's separable subsurface scattering does. What it gives up is the radial shape, a
|
|
16
|
+
* blur a little squarer than the profile; what it buys is thirteen taps an axis rather than a disc.
|
|
17
|
+
*
|
|
18
|
+
* **Each tap is the profile's mass over its cell, in closed form**, so a channel's weights sum to
|
|
19
|
+
* one before any are refused, and a channel that travels a quarter as far as the widest keeps most
|
|
20
|
+
* of its light at the centre. The taps are placed in units of the widest channel's distance and
|
|
21
|
+
* closer together near the centre, where the profile's sharp peak is.
|
|
22
|
+
*/
|
|
23
|
+
/** The taps' distances from the centre, one side, in units of the widest channel's distance. */
|
|
24
|
+
export const SKIN_BLUR_TAPS = [0, 0.4, 1.1, 2.1, 3.5, 5.6, 9];
|
|
25
|
+
/**
|
|
26
|
+
* Where each tap's cell ends, in the same units: halfway to the next tap, and the last cell runs
|
|
27
|
+
* to infinity, so the profile's whole mass is somewhere.
|
|
28
|
+
*/
|
|
29
|
+
export const SKIN_BLUR_EDGES = [0.2, 0.75, 1.6, 2.8, 4.55, 7.3];
|
|
30
|
+
/** How many profiles a frame's skin can name: `SkinModel.profile`. */
|
|
31
|
+
export const SKIN_PROFILES = 8;
|
|
32
|
+
/**
|
|
33
|
+
* Burley's profile across a line, `(e^(−x/d) + e^(−x/3d)) / 8d`, integrated from 0 to `x`: half of
|
|
34
|
+
* it lies on each side, so this reaches ½ at infinity.
|
|
35
|
+
*/
|
|
36
|
+
export function burleyMass(x, d) {
|
|
37
|
+
return 0.5 - (Math.exp(-x / d) + 3 * Math.exp(-x / (3 * d))) / 8;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Tap `tap`'s weight for one channel scattering `d`, the taps spaced by `widest`: the centre's cell
|
|
41
|
+
* is both sides of it, every other cell one side, and a tap on each side takes this weight.
|
|
42
|
+
*/
|
|
43
|
+
export function skinBlurWeight(tap, d, widest) {
|
|
44
|
+
if (tap === 0)
|
|
45
|
+
return 2 * burleyMass(SKIN_BLUR_EDGES[0] * widest, d);
|
|
46
|
+
const inner = SKIN_BLUR_EDGES[tap - 1] * widest;
|
|
47
|
+
const outer = tap < SKIN_BLUR_EDGES.length ? SKIN_BLUR_EDGES[tap] * widest : Infinity;
|
|
48
|
+
return (outer === Infinity ? 0.5 : burleyMass(outer, d)) - burleyMass(inner, d);
|
|
49
|
+
}
|