@forgeax/engine-shader 0.1.7 → 0.1.19

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.
Files changed (99) hide show
  1. package/README.md +34 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/ShaderRegistry.d.ts.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.mjs +53 -2
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/material-schemas.d.ts.map +1 -1
  9. package/package.json +6 -3
  10. package/src/ShaderRegistry.ts +50 -0
  11. package/src/__tests__/bloom-fxaa-tonemap.unit.test.ts +86 -12
  12. package/src/__tests__/default-standard-pbr-transmission.unit.test.ts +181 -0
  13. package/src/__tests__/lighting-punctual.unit.test.ts +1 -1
  14. package/src/__tests__/material-builtins.unit.test.ts +38 -1
  15. package/src/__tests__/material-contract.unit.test.ts +123 -0
  16. package/src/__tests__/motion-blur.unit.test.ts +44 -0
  17. package/src/__tests__/scene-temporal.unit.test.ts +23 -5
  18. package/src/__tests__/shader-manifest-transmission.unit.test.ts +75 -0
  19. package/src/__tests__/shader.unit.test.ts +43 -3
  20. package/src/__tests__/sprite-variants.unit.test.ts +19 -0
  21. package/src/__tests__/taa-resolve.unit.test.ts +75 -3
  22. package/src/__tests__/transmission-thickness-scale.unit.test.ts +19 -0
  23. package/src/common.wgsl +30 -30
  24. package/src/default-standard-pbr-skin.wgsl +27 -9
  25. package/src/default-standard-pbr.wgsl +209 -28
  26. package/src/fxaa.wgsl +5 -6
  27. package/src/index.ts +3 -0
  28. package/src/material-schemas.ts +7 -0
  29. package/src/motion-blur.wgsl +77 -0
  30. package/src/pbr-temporal.wgsl +15 -2
  31. package/src/scene-temporal.wgsl +54 -0
  32. package/src/shadow_caster.wgsl +27 -2
  33. package/src/sprite-lit.wgsl +5 -4
  34. package/src/sprite.wgsl +5 -4
  35. package/src/taa-resolve.wgsl +76 -81
  36. package/src/tonemap.wgsl +7 -9
  37. package/src/unlit.wgsl +6 -5
  38. package/dist/__tests__/atmosphere-background.test.d.ts +0 -2
  39. package/dist/__tests__/atmosphere-background.test.d.ts.map +0 -1
  40. package/dist/__tests__/atmosphere-cubemap-orientation.test.d.ts +0 -2
  41. package/dist/__tests__/atmosphere-cubemap-orientation.test.d.ts.map +0 -1
  42. package/dist/__tests__/atmosphere-preetham-numeric.test.d.ts +0 -2
  43. package/dist/__tests__/atmosphere-preetham-numeric.test.d.ts.map +0 -1
  44. package/dist/__tests__/atmosphere-preetham-red.test.d.ts +0 -2
  45. package/dist/__tests__/atmosphere-preetham-red.test.d.ts.map +0 -1
  46. package/dist/__tests__/atmosphere-preetham.test.d.ts +0 -2
  47. package/dist/__tests__/atmosphere-preetham.test.d.ts.map +0 -1
  48. package/dist/__tests__/atmosphere-three-r184-reference.test.d.ts +0 -2
  49. package/dist/__tests__/atmosphere-three-r184-reference.test.d.ts.map +0 -1
  50. package/dist/__tests__/bloom-fxaa-tonemap.unit.test.d.ts +0 -2
  51. package/dist/__tests__/bloom-fxaa-tonemap.unit.test.d.ts.map +0 -1
  52. package/dist/__tests__/builtin-texture-sampling-contract.test.d.ts +0 -2
  53. package/dist/__tests__/builtin-texture-sampling-contract.test.d.ts.map +0 -1
  54. package/dist/__tests__/default-standard-pbr-alpha.unit.test.d.ts +0 -2
  55. package/dist/__tests__/default-standard-pbr-alpha.unit.test.d.ts.map +0 -1
  56. package/dist/__tests__/deferred-lighting-ssao.test.d.ts +0 -2
  57. package/dist/__tests__/deferred-lighting-ssao.test.d.ts.map +0 -1
  58. package/dist/__tests__/fog-oracle.unit.test.d.ts +0 -2
  59. package/dist/__tests__/fog-oracle.unit.test.d.ts.map +0 -1
  60. package/dist/__tests__/fog-orthographic-ray.unit.test.d.ts +0 -2
  61. package/dist/__tests__/fog-orthographic-ray.unit.test.d.ts.map +0 -1
  62. package/dist/__tests__/fog-producer-matrix.integration.test.d.ts +0 -2
  63. package/dist/__tests__/fog-producer-matrix.integration.test.d.ts.map +0 -1
  64. package/dist/__tests__/hdrp-ssao-compile.test.d.ts +0 -2
  65. package/dist/__tests__/hdrp-ssao-compile.test.d.ts.map +0 -1
  66. package/dist/__tests__/ibl-irradiance.unit.test.d.ts +0 -2
  67. package/dist/__tests__/ibl-irradiance.unit.test.d.ts.map +0 -1
  68. package/dist/__tests__/ibl-sampling.unit.test.d.ts +0 -2
  69. package/dist/__tests__/ibl-sampling.unit.test.d.ts.map +0 -1
  70. package/dist/__tests__/lighting-punctual.unit.test.d.ts +0 -2
  71. package/dist/__tests__/lighting-punctual.unit.test.d.ts.map +0 -1
  72. package/dist/__tests__/material-artifact-dedup.unit.test.d.ts +0 -2
  73. package/dist/__tests__/material-artifact-dedup.unit.test.d.ts.map +0 -1
  74. package/dist/__tests__/material-builtins.unit.test.d.ts +0 -2
  75. package/dist/__tests__/material-builtins.unit.test.d.ts.map +0 -1
  76. package/dist/__tests__/material-contract.unit.test.d.ts +0 -2
  77. package/dist/__tests__/material-contract.unit.test.d.ts.map +0 -1
  78. package/dist/__tests__/material-derived-builtins.integration.test.d.ts +0 -2
  79. package/dist/__tests__/material-derived-builtins.integration.test.d.ts.map +0 -1
  80. package/dist/__tests__/points-lines-shader.unit.test.d.ts +0 -2
  81. package/dist/__tests__/points-lines-shader.unit.test.d.ts.map +0 -1
  82. package/dist/__tests__/public-surface.unit.test.d.ts +0 -2
  83. package/dist/__tests__/public-surface.unit.test.d.ts.map +0 -1
  84. package/dist/__tests__/scene-temporal.unit.test.d.ts +0 -2
  85. package/dist/__tests__/scene-temporal.unit.test.d.ts.map +0 -1
  86. package/dist/__tests__/shader-registry-transaction.unit.test.d.ts +0 -2
  87. package/dist/__tests__/shader-registry-transaction.unit.test.d.ts.map +0 -1
  88. package/dist/__tests__/shader.unit.test.d.ts +0 -2
  89. package/dist/__tests__/shader.unit.test.d.ts.map +0 -1
  90. package/dist/__tests__/sprite-lit-shader.test.d.ts +0 -2
  91. package/dist/__tests__/sprite-lit-shader.test.d.ts.map +0 -1
  92. package/dist/__tests__/sprite-variants.unit.test.d.ts +0 -2
  93. package/dist/__tests__/sprite-variants.unit.test.d.ts.map +0 -1
  94. package/dist/__tests__/taa-resolve.unit.test.d.ts +0 -2
  95. package/dist/__tests__/taa-resolve.unit.test.d.ts.map +0 -1
  96. package/dist/__tests__/transparent-pbr.unit.test.d.ts +0 -2
  97. package/dist/__tests__/transparent-pbr.unit.test.d.ts.map +0 -1
  98. package/dist/__tests__/vertex-color-variant.unit.test.d.ts +0 -2
  99. package/dist/__tests__/vertex-color-variant.unit.test.d.ts.map +0 -1
@@ -1,4 +1,5 @@
1
1
  #pragma variant_axis STORAGE_BUFFER_AVAILABLE
2
+ #pragma variant_axis SKINNING_DISABLED
2
3
 
3
4
  // @forgeax/engine-shader shadow_caster.wgsl
4
5
  // feat-20260520-directional-light-shadow-mapping M1c / w9 (D-9 / AC-09):
@@ -20,15 +21,28 @@
20
21
  // @group(2) binding(0) meshes : array<Mesh> -- common.wgsl
21
22
  // @group(3) binding(0) instances : array<InstanceData> -- common.wgsl
22
23
  //
23
- // Vertex layout: matches the 12F procedural layout of every mesh
24
- // (position vec3, normal vec3, uv vec2, tangent vec4; 48 B stride).
24
+ // SKINNING_DISABLED=true consumes the ordinary 12F mesh layout; the explicit
25
+ // false variant consumes JOINTS_0 / WEIGHTS_0 from the same 18F layout as pbr-skin and
26
+ // projects the animated world-space palette result into the shadow view.
25
27
 
26
28
  #import forgeax_view::common::{View, Mesh, InstanceData, ShadowCasterCascade, view, shadowCasterCascade, meshes, instances}
27
29
 
28
30
  struct VsInput {
29
31
  @location(0) position : vec3<f32>,
32
+ #if SKINNING_DISABLED == false
33
+ @location(4) skinIndex : vec4<u32>,
34
+ @location(5) skinWeight : vec4<f32>,
35
+ #endif
30
36
  };
31
37
 
38
+ #if SKINNING_DISABLED == false
39
+ #if STORAGE_BUFFER_AVAILABLE == true
40
+ @group(2) @binding(1) var<storage, read> palette : array<mat4x4<f32>>;
41
+ #else
42
+ @group(2) @binding(1) var<uniform> palette : array<mat4x4<f32>, 255>;
43
+ #endif
44
+ #endif
45
+
32
46
  fn _cascadeLightViewProj(layer : u32) -> mat4x4<f32> {
33
47
  switch (layer) {
34
48
  case 0u: { return view.lightViewProj_A; }
@@ -40,7 +54,18 @@ fn _cascadeLightViewProj(layer : u32) -> mat4x4<f32> {
40
54
 
41
55
  @vertex
42
56
  fn vs_main(in : VsInput, @builtin(instance_index) idx : u32) -> @builtin(position) vec4<f32> {
57
+ #if SKINNING_DISABLED == false
58
+ let skinMatrix = palette[in.skinIndex.x] * in.skinWeight.x +
59
+ palette[in.skinIndex.y] * in.skinWeight.y +
60
+ palette[in.skinIndex.z] * in.skinWeight.z +
61
+ palette[in.skinIndex.w] * in.skinWeight.w;
62
+ // Palette entries are jointWorld * inverseBind and therefore already
63
+ // produce world-space positions. Applying meshes[0].worldFromLocal again
64
+ // would double-transform a parented skinned entity.
65
+ let worldPos = skinMatrix * vec4<f32>(in.position, 1.0);
66
+ #else
43
67
  let worldPos = meshes[0].worldFromLocal * instances[idx].localFromInstance * vec4<f32>(in.position, 1.0);
68
+ #endif
44
69
  // feat-20260625-spot-light-shadow-mapping M2 / w10 (D-1): spot shadow passes
45
70
  // set `isSpot = 1u` and write their perspective matrix into
46
71
  // `spotLightViewProj`; directional cascade passes keep `isSpot = 0u` and read
@@ -1,7 +1,8 @@
1
1
  #pragma variant_axis STORAGE_BUFFER_AVAILABLE
2
2
  #define_import_path forgeax_material::sprite-lit
3
3
 
4
- #import forgeax_view::common::{View, FogViewParams, FogRay, Mesh, InstanceData, PointLight, SpotLight, view, meshes, instances, pointLightsBuffer, spotLightsBuffer, sampleMaterialTexture, packSceneTemporal}
4
+ #import forgeax_view::common::{View, FogViewParams, FogRay, Mesh, InstanceData, PointLight, SpotLight, view, meshes, instances, pointLightsBuffer, spotLightsBuffer, sampleMaterialTexture}
5
+ #import forgeax_scene_temporal::{packSceneTemporalV1}
5
6
  #import forgeax_view::fog::{apply_fog}
6
7
 
7
8
  // @forgeax/engine-shader - sprite-lit.wgsl
@@ -272,8 +273,8 @@ fn fs_main_hdr(in : VsOut) -> @location(0) vec4<f32> {
272
273
  struct TemporalVsOut {
273
274
  @builtin(position) clip : vec4<f32>,
274
275
  @location(0) uvAtlas : vec2<f32>,
275
- @location(1) @interpolate(linear) currentClip : vec4<f32>,
276
- @location(2) @interpolate(linear) previousClip : vec4<f32>,
276
+ @location(1) @interpolate(perspective) currentClip : vec4<f32>,
277
+ @location(2) @interpolate(perspective) previousClip : vec4<f32>,
277
278
  };
278
279
 
279
280
  @vertex
@@ -301,7 +302,7 @@ fn fs_temporal(in : TemporalVsOut) -> @location(0) vec4<f32> {
301
302
  if (alpha <= 0.0) {
302
303
  discard;
303
304
  }
304
- return packSceneTemporal(in.currentClip, in.previousClip, 1.0);
305
+ return packSceneTemporalV1(in.currentClip, in.previousClip, view.temporalProjection, 1.0);
305
306
  }
306
307
  // sprite-lit needs at least one light in the scene to be visible; for unlit
307
308
  // sprites use forgeax::sprite (1 string change in MaterialAsset).
package/src/sprite.wgsl CHANGED
@@ -2,7 +2,8 @@
2
2
  #pragma variant_axis STORAGE_BUFFER_AVAILABLE
3
3
  #pragma variant_axis PER_INSTANCE_REGION
4
4
 
5
- #import forgeax_view::common::{View, FogViewParams, FogRay, Mesh, InstanceData, view, meshes, instances, sampleMaterialTexture, packSceneTemporal}
5
+ #import forgeax_view::common::{View, FogViewParams, FogRay, Mesh, InstanceData, view, meshes, instances, sampleMaterialTexture}
6
+ #import forgeax_scene_temporal::{packSceneTemporalV1}
6
7
  #import forgeax_view::fog::{apply_fog}
7
8
 
8
9
  // @forgeax/engine-shader - sprite.wgsl (feat-20260520-2d-sprite-layer-mvp /
@@ -330,8 +331,8 @@ fn fs_main_hdr(in : VsOut) -> @location(0) vec4<f32> {
330
331
  struct TemporalVsOut {
331
332
  @builtin(position) clip : vec4<f32>,
332
333
  @location(0) uvAtlas : vec2<f32>,
333
- @location(1) @interpolate(linear) currentClip : vec4<f32>,
334
- @location(2) @interpolate(linear) previousClip : vec4<f32>,
334
+ @location(1) @interpolate(perspective) currentClip : vec4<f32>,
335
+ @location(2) @interpolate(perspective) previousClip : vec4<f32>,
335
336
  };
336
337
 
337
338
  @vertex
@@ -359,7 +360,7 @@ fn fs_temporal(in : TemporalVsOut) -> @location(0) vec4<f32> {
359
360
  if (alpha <= 0.0) {
360
361
  discard;
361
362
  }
362
- return packSceneTemporal(in.currentClip, in.previousClip, 1.0);
363
+ return packSceneTemporalV1(in.currentClip, in.previousClip, view.temporalProjection, 1.0);
363
364
  }
364
365
  // sprite is unlit; do NOT read the directional-light fields of the View
365
366
  // UBO -- same SSOT hard rule as the header comment above; R5 mitigation.
@@ -1,7 +1,28 @@
1
1
  #define_import_path forgeax_view::taa_resolve
2
2
 
3
- #import forgeax_view::common::fullscreen_triangle
4
- #import forgeax_view::common::FullscreenOutput
3
+ // Keep the fragment input shape explicit for compilers that tree-shake imported
4
+ // type declarations before resolving the vertex entry point.
5
+ struct FullscreenOutput {
6
+ @builtin(position) position : vec4<f32>,
7
+ @location(0) uv : vec2<f32>,
8
+ };
9
+
10
+ fn fullscreen_triangle(vertex_index : u32) -> FullscreenOutput {
11
+ var x : f32 = -1.0;
12
+ var y : f32 = -1.0;
13
+ if (vertex_index == 1u) {
14
+ x = 3.0;
15
+ }
16
+ if (vertex_index == 2u) {
17
+ y = 3.0;
18
+ }
19
+ let u : f32 = (x + 1.0) * 0.5;
20
+ let v : f32 = 1.0 - (y + 1.0) * 0.5;
21
+ var out : FullscreenOutput;
22
+ out.position = vec4<f32>(x, y, 0.0, 1.0);
23
+ out.uv = vec2<f32>(u, v);
24
+ return out;
25
+ }
5
26
 
6
27
  struct TaaResolveParams {
7
28
  currentJitterUv : vec2<f32>,
@@ -14,12 +35,15 @@ struct TaaResolveOutput {
14
35
  @location(1) temporal : vec4<f32>,
15
36
  };
16
37
 
17
- @group(0) @binding(0) var currentColor : texture_2d<f32>;
18
- @group(0) @binding(1) var currentTemporal : texture_2d<f32>;
19
- @group(0) @binding(2) var historyColor : texture_2d<f32>;
20
- @group(0) @binding(3) var historyTemporal : texture_2d<f32>;
21
- @group(0) @binding(4) var historySampler : sampler;
22
- @group(0) @binding(5) var<uniform> params : TaaResolveParams;
38
+ @group(1) @binding(0) var currentColor : texture_2d<f32>;
39
+ @group(1) @binding(1) var currentSampler : sampler;
40
+ @group(1) @binding(2) var historyColor : texture_2d<f32>;
41
+ @group(1) @binding(3) var historySampler : sampler;
42
+ @group(1) @binding(4) var historyTemporal : texture_2d<f32>;
43
+ @group(1) @binding(5) var temporalSampler : sampler;
44
+ @group(1) @binding(6) var currentTemporal : texture_2d<f32>;
45
+ @group(1) @binding(7) var currentTemporalSampler : sampler;
46
+ @group(1) @binding(8) var<uniform> params : TaaResolveParams;
23
47
 
24
48
  fn rgbToYCoCg(rgb : vec3<f32>) -> vec3<f32> {
25
49
  return vec3<f32>(
@@ -37,93 +61,64 @@ fn luminance(rgb : vec3<f32>) -> f32 {
37
61
  return dot(rgb, vec3<f32>(0.2126, 0.7152, 0.0722));
38
62
  }
39
63
 
40
- fn jitterCorrectedCurrent(uv : vec2<f32>) -> vec4<f32> {
41
- // The resolve and history live in the unjittered output domain. The main
42
- // scene raster is the only jittered consumer, so re-center its color here;
43
- // packed motion is already unjittered currentUv - previousUv.
44
- return textureSampleLevel(currentColor, historySampler, uv + params.currentJitterUv, 0.0);
64
+ fn closestCurrentTemporal(pixel : vec2<i32>, dimensions : vec2<i32>) -> vec4<f32> {
65
+ let clamped = clamp(pixel, vec2<i32>(0), dimensions - vec2<i32>(1));
66
+ return textureLoad(currentTemporal, clamped, 0);
45
67
  }
46
68
 
47
- fn closestCurrentTemporal(pixel : vec2<i32>, dimensions : vec2<i32>) -> vec4<f32> {
48
- var closest = vec4<f32>(0.0, 0.0, -1.0, 1.0);
49
- var closestDepth = 1e20;
50
- for (var y = -1; y <= 1; y += 1) {
51
- for (var x = -1; x <= 1; x += 1) {
52
- let samplePixel = clamp(pixel + vec2<i32>(x, y), vec2<i32>(0), dimensions - vec2<i32>(1));
53
- let candidate = textureLoad(currentTemporal, samplePixel, 0);
54
- if candidate.z >= 0.0 && candidate.z < closestDepth {
55
- closest = candidate;
56
- closestDepth = candidate.z;
57
- }
58
- }
59
- }
60
- return closest;
69
+ fn neighborhoodSquareMean(uv : vec2<f32>, texel : vec2<f32>) -> vec3<f32> {
70
+ let north = textureSampleLevel(currentColor, currentSampler, uv + vec2<f32>(0.0, texel.y), 0.0).rgb;
71
+ let south = textureSampleLevel(currentColor, currentSampler, uv - vec2<f32>(0.0, texel.y), 0.0).rgb;
72
+ let east = textureSampleLevel(currentColor, currentSampler, uv + vec2<f32>(texel.x, 0.0), 0.0).rgb;
73
+ let west = textureSampleLevel(currentColor, currentSampler, uv - vec2<f32>(texel.x, 0.0), 0.0).rgb;
74
+ return (north + south + east + west) * 0.25;
61
75
  }
62
76
 
63
77
  @vertex
64
- fn vs_taa_resolve(@builtin(vertex_index) vertexIndex : u32) -> FullscreenOutput {
78
+ fn vs_main(@builtin(vertex_index) vertexIndex : u32) -> FullscreenOutput {
65
79
  return fullscreen_triangle(vertexIndex);
66
80
  }
67
81
 
68
- @fragment
69
82
  fn fs_taa_resolve(in : FullscreenOutput) -> TaaResolveOutput {
70
- let dimensions = vec2<i32>(textureDimensions(currentColor));
71
- let pixel = clamp(vec2<i32>(in.position.xy), vec2<i32>(0), dimensions - vec2<i32>(1));
72
- let current = jitterCorrectedCurrent(in.uv);
83
+ let dimensions = vec2<i32>(textureDimensions(currentColor, 0));
84
+ let texel = 1.0 / vec2<f32>(dimensions);
85
+ let current = textureSampleLevel(currentColor, currentSampler, in.uv + params.currentJitterUv, 0.0);
86
+ let pixel = vec2<i32>(in.uv * vec2<f32>(dimensions));
73
87
  let temporal = closestCurrentTemporal(pixel, dimensions);
74
-
75
- var output : TaaResolveOutput;
76
- output.temporal = temporal;
77
- output.color = current;
78
-
79
88
  let historyUv = in.uv - temporal.xy;
80
- let historyInBounds = all(historyUv >= vec2<f32>(0.0)) && all(historyUv < vec2<f32>(1.0));
81
- if params.historyValid == 0u || !historyInBounds || temporal.z < 0.0 {
82
- return output;
83
- }
84
-
85
- let previousTemporal = textureSampleLevel(historyTemporal, historySampler, historyUv, 0.0);
89
+ let historyInBounds = all(historyUv >= vec2<f32>(0.0)) && all(historyUv <= vec2<f32>(1.0));
90
+ let history = textureSampleLevel(historyColor, historySampler, historyUv, 0.0);
91
+ let previousTemporal = textureSampleLevel(historyTemporal, temporalSampler, historyUv, 0.0);
86
92
  let depthDelta = abs(previousTemporal.z - temporal.z);
87
- let depthThreshold = max(0.01, temporal.z * 0.01);
88
- if previousTemporal.z < 0.0 || depthDelta > depthThreshold {
89
- return output;
90
- }
91
-
92
- var neighborhoodMin = vec3<f32>(1e20);
93
- var neighborhoodMax = vec3<f32>(-1e20);
94
- var neighborhoodMean = vec3<f32>(0.0);
95
- var neighborhoodSquareMean = vec3<f32>(0.0);
96
- for (var y = -1; y <= 1; y += 1) {
97
- for (var x = -1; x <= 1; x += 1) {
98
- let sampleUv = in.uv + vec2<f32>(f32(x), f32(y)) / vec2<f32>(dimensions);
99
- let sampleValue = rgbToYCoCg(jitterCorrectedCurrent(sampleUv).rgb);
100
- neighborhoodMin = min(neighborhoodMin, sampleValue);
101
- neighborhoodMax = max(neighborhoodMax, sampleValue);
102
- neighborhoodMean += sampleValue;
103
- neighborhoodSquareMean += sampleValue * sampleValue;
104
- }
105
- }
106
- neighborhoodMean /= 9.0;
107
- neighborhoodSquareMean /= 9.0;
108
- let sigma = sqrt(max(neighborhoodSquareMean - neighborhoodMean * neighborhoodMean, vec3<f32>(0.0)));
109
- let clipMin = max(neighborhoodMin, neighborhoodMean - sigma * 1.25);
110
- let clipMax = min(neighborhoodMax, neighborhoodMean + sigma * 1.25);
111
-
112
- let sampledHistory = textureSampleLevel(historyColor, historySampler, historyUv, 0.0);
113
- let clippedHistoryRgb = yCoCgToRgb(clamp(rgbToYCoCg(sampledHistory.rgb), clipMin, clipMax));
114
- let velocityFactor = 1.0 - clamp(length(temporal.xy) * 64.0, 0.0, 1.0);
93
+ let depthThreshold = 0.0025 + temporal.z * 0.01;
94
+ let rejected =
95
+ params.historyValid == 0u ||
96
+ !historyInBounds ||
97
+ temporal.z < 0.0 ||
98
+ previousTemporal.z < 0.0 ||
99
+ depthDelta > depthThreshold;
100
+ let neighborhood = neighborhoodSquareMean(in.uv, texel);
101
+ let neighborhoodDelta = abs(luminance(current.rgb) - luminance(neighborhood));
102
+ let clipPadding = vec3<f32>(0.5);
103
+ let clipMin = rgbToYCoCg(min(current.rgb, neighborhood - vec3<f32>(neighborhoodDelta) - clipPadding));
104
+ let clipMax = rgbToYCoCg(max(current.rgb, neighborhood + vec3<f32>(neighborhoodDelta) + clipPadding));
105
+ let clippedHistoryRgb = yCoCgToRgb(clamp(rgbToYCoCg(history.rgb), clipMin, clipMax));
115
106
  let reactiveFactor = 1.0 - clamp(temporal.w, 0.0, 1.0);
107
+ let velocityFactor = 1.0 - clamp(length(temporal.xy) * 64.0, 0.0, 1.0);
116
108
  let depthFactor = 1.0 - clamp(depthDelta / depthThreshold, 0.0, 1.0);
117
- let currentLuma = luminance(current.rgb);
118
- let historyLuma = luminance(clippedHistoryRgb);
119
- let lumaDelta = abs(historyLuma - currentLuma);
120
- let unbiasedLumaDelta = clamp(lumaDelta / max(max(currentLuma, historyLuma), 0.2), 0.0, 1.0);
109
+ let unbiasedLumaDelta = clamp(abs(luminance(current.rgb) - luminance(history.rgb)), 0.0, 1.0);
121
110
  let lumaFactor = (1.0 - unbiasedLumaDelta) * (1.0 - unbiasedLumaDelta);
122
111
  let fixedPresetWeight = mix(0.88, 0.97, lumaFactor);
123
- let startupWeight = f32(params.temporalFrameIndex) / f32(params.temporalFrameIndex + 1u);
124
- let progressiveWeight = select(fixedPresetWeight, min(startupWeight, fixedPresetWeight), params.temporalFrameIndex < 8u);
125
- let rejectionFactor = min(reactiveFactor, min(velocityFactor, depthFactor));
126
- let historyWeight = progressiveWeight * rejectionFactor;
127
- output.color = vec4<f32>(mix(current.rgb, clippedHistoryRgb, historyWeight), current.a);
128
- return output;
112
+ let progressiveWeight = select(fixedPresetWeight, 0.0, params.temporalFrameIndex < 8u);
113
+ let historyWeight = progressiveWeight * reactiveFactor * velocityFactor * depthFactor;
114
+ let resolved = select(mix(current.rgb, clippedHistoryRgb, historyWeight), current.rgb, rejected);
115
+ return TaaResolveOutput(
116
+ vec4<f32>(resolved, current.a),
117
+ temporal,
118
+ );
119
+ }
120
+
121
+ @fragment
122
+ fn fs_main(in : FullscreenOutput) -> TaaResolveOutput {
123
+ return fs_taa_resolve(in);
129
124
  }
package/src/tonemap.wgsl CHANGED
@@ -1,6 +1,6 @@
1
1
  #define_import_path forgeax_view::tonemap
2
2
 
3
- // @forgeax/engine-shader - Three r184 tone mapping output module.
3
+ // @forgeax/engine-shader - Three r184 Output Transform module.
4
4
  //
5
5
  // The public modes and formulas are the Three.js r184 oracle. The numeric
6
6
  // values are the binding contract mirrored by TONEMAP_SHADER_MODE in tonemap.ts.
@@ -153,8 +153,7 @@ fn tonemapNeutral(color : vec3<f32>) -> vec3<f32> {
153
153
 
154
154
  @fragment
155
155
  fn fs_main(in : FullscreenOutput) -> @location(0) vec4<f32> {
156
- // linearHdrColorDomain: hdr is sampled before the only HDR-to-LDR stage.
157
- // linearLdrColorDomain: the output pass emits the display-target domain.
156
+ // Output Transform consumes linear HDR and emits display-encoded color.
158
157
  let source = textureSample(hdr, samp, in.uv);
159
158
  let sample : vec3<f32> = source.rgb;
160
159
  let exposed : vec3<f32> = sample * params.exposure;
@@ -167,11 +166,10 @@ fn fs_main(in : FullscreenOutput) -> @location(0) vec4<f32> {
167
166
  case 5u: { mapped = tonemapAgx(exposed); }
168
167
  case 6u: { mapped = tonemapNeutral(exposed); }
169
168
  case 7u: { mapped = tonemapReinhard(exposed); }
170
- // Mode 0 is the linear-LDR output pass used when tone mapping is disabled.
171
- // It targets the raw canvas format and mirrors Three r184's output OETF.
172
- default: { mapped = linearToSrgbOetf(exposed); }
169
+ // Mode 0 skips the tone curve but still performs the output conversion.
170
+ default: { mapped = sample; }
173
171
  }
174
- // The mode-0 output pass is display-encoded; other modes retain their
175
- // existing tonemap output contract.
176
- return vec4<f32>(mapped, source.a);
172
+ // Every public mode reaches exactly one shared sRGB OETF.
173
+ let encoded = linearToSrgbOetf(mapped);
174
+ return vec4<f32>(encoded, source.a);
177
175
  }
package/src/unlit.wgsl CHANGED
@@ -1,5 +1,6 @@
1
1
  #define_import_path forgeax_material::unlit
2
- #import forgeax_view::common::{View, FogViewParams, FogRay, Mesh, InstanceData, view, meshes, instances, sampleMaterialTextureLinear, packSceneTemporal}
2
+ #import forgeax_view::common::{View, FogViewParams, FogRay, Mesh, InstanceData, view, meshes, instances, sampleMaterialTextureLinear}
3
+ #import forgeax_scene_temporal::{packSceneTemporalV1}
3
4
  #import forgeax_view::fog::{apply_fog}
4
5
 
5
6
  #pragma variant_axis STORAGE_BUFFER_AVAILABLE
@@ -135,8 +136,8 @@ fn fs_main(in : VsOut) -> @location(0) vec4<f32> {
135
136
  struct TemporalVsOut {
136
137
  @builtin(position) clip : vec4<f32>,
137
138
  @location(0) uv : vec2<f32>,
138
- @location(1) @interpolate(linear) currentClip : vec4<f32>,
139
- @location(2) @interpolate(linear) previousClip : vec4<f32>,
139
+ @location(1) @interpolate(perspective) currentClip : vec4<f32>,
140
+ @location(2) @interpolate(perspective) previousClip : vec4<f32>,
140
141
  #ifdef VERTEX_COLOR_AVAILABLE
141
142
  @location(14) color : vec4<f32>,
142
143
  #endif
@@ -178,9 +179,9 @@ fn fs_temporal(in : TemporalVsOut) -> @location(0) vec4<f32> {
178
179
  if (material.alphaCutoff > 0.0 && alpha < material.alphaCutoff) {
179
180
  discard;
180
181
  }
181
- var reactive = 1.0;
182
+ var reactive = 0.0;
182
183
  #if STORAGE_BUFFER_AVAILABLE == true
183
184
  reactive = meshes[0].temporal.x;
184
185
  #endif
185
- return packSceneTemporal(in.currentClip, in.previousClip, reactive);
186
+ return packSceneTemporalV1(in.currentClip, in.previousClip, view.temporalProjection, reactive);
186
187
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=atmosphere-background.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"atmosphere-background.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/atmosphere-background.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=atmosphere-cubemap-orientation.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"atmosphere-cubemap-orientation.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/atmosphere-cubemap-orientation.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=atmosphere-preetham-numeric.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"atmosphere-preetham-numeric.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/atmosphere-preetham-numeric.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=atmosphere-preetham-red.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"atmosphere-preetham-red.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/atmosphere-preetham-red.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=atmosphere-preetham.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"atmosphere-preetham.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/atmosphere-preetham.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=atmosphere-three-r184-reference.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"atmosphere-three-r184-reference.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/atmosphere-three-r184-reference.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=bloom-fxaa-tonemap.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bloom-fxaa-tonemap.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/bloom-fxaa-tonemap.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=builtin-texture-sampling-contract.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"builtin-texture-sampling-contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/builtin-texture-sampling-contract.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=default-standard-pbr-alpha.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"default-standard-pbr-alpha.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/default-standard-pbr-alpha.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=deferred-lighting-ssao.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deferred-lighting-ssao.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/deferred-lighting-ssao.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=fog-oracle.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fog-oracle.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fog-oracle.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=fog-orthographic-ray.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fog-orthographic-ray.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fog-orthographic-ray.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=fog-producer-matrix.integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fog-producer-matrix.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fog-producer-matrix.integration.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=hdrp-ssao-compile.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hdrp-ssao-compile.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/hdrp-ssao-compile.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ibl-irradiance.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ibl-irradiance.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ibl-irradiance.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ibl-sampling.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ibl-sampling.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ibl-sampling.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=lighting-punctual.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lighting-punctual.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/lighting-punctual.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=material-artifact-dedup.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"material-artifact-dedup.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/material-artifact-dedup.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=material-builtins.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"material-builtins.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/material-builtins.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=material-contract.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"material-contract.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/material-contract.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=material-derived-builtins.integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"material-derived-builtins.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/material-derived-builtins.integration.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=points-lines-shader.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"points-lines-shader.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/points-lines-shader.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=public-surface.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"public-surface.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/public-surface.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=scene-temporal.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scene-temporal.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/scene-temporal.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=shader-registry-transaction.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shader-registry-transaction.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/shader-registry-transaction.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=shader.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shader.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/shader.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=sprite-lit-shader.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sprite-lit-shader.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sprite-lit-shader.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=sprite-variants.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sprite-variants.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sprite-variants.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=taa-resolve.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"taa-resolve.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/taa-resolve.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=transparent-pbr.unit.test.d.ts.map