@forgeax/engine-shader 0.1.2
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/LICENSE +202 -0
- package/README.md +99 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/ShaderRegistry.d.ts +208 -0
- package/dist/ShaderRegistry.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-background.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-background.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-cubemap-orientation.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-cubemap-orientation.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-preetham-numeric.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-preetham-numeric.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-preetham-red.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-preetham-red.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-preetham.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-preetham.test.d.ts.map +1 -0
- package/dist/__tests__/atmosphere-three-r184-reference.test.d.ts +2 -0
- package/dist/__tests__/atmosphere-three-r184-reference.test.d.ts.map +1 -0
- package/dist/__tests__/bloom-fxaa-tonemap.unit.test.d.ts +2 -0
- package/dist/__tests__/bloom-fxaa-tonemap.unit.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-texture-sampling-contract.test.d.ts +2 -0
- package/dist/__tests__/builtin-texture-sampling-contract.test.d.ts.map +1 -0
- package/dist/__tests__/default-standard-pbr-alpha.unit.test.d.ts +2 -0
- package/dist/__tests__/default-standard-pbr-alpha.unit.test.d.ts.map +1 -0
- package/dist/__tests__/deferred-lighting-ssao.test.d.ts +2 -0
- package/dist/__tests__/deferred-lighting-ssao.test.d.ts.map +1 -0
- package/dist/__tests__/fog-oracle.unit.test.d.ts +2 -0
- package/dist/__tests__/fog-oracle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fog-orthographic-ray.unit.test.d.ts +2 -0
- package/dist/__tests__/fog-orthographic-ray.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-matrix.integration.test.d.ts +2 -0
- package/dist/__tests__/fog-producer-matrix.integration.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-ssao-compile.test.d.ts +2 -0
- package/dist/__tests__/hdrp-ssao-compile.test.d.ts.map +1 -0
- package/dist/__tests__/ibl-irradiance.unit.test.d.ts +2 -0
- package/dist/__tests__/ibl-irradiance.unit.test.d.ts.map +1 -0
- package/dist/__tests__/ibl-sampling.unit.test.d.ts +2 -0
- package/dist/__tests__/ibl-sampling.unit.test.d.ts.map +1 -0
- package/dist/__tests__/lighting-punctual.unit.test.d.ts +2 -0
- package/dist/__tests__/lighting-punctual.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-artifact-dedup.unit.test.d.ts +2 -0
- package/dist/__tests__/material-artifact-dedup.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-builtins.unit.test.d.ts +2 -0
- package/dist/__tests__/material-builtins.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/material-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-derived-builtins.integration.test.d.ts +2 -0
- package/dist/__tests__/material-derived-builtins.integration.test.d.ts.map +1 -0
- package/dist/__tests__/public-surface.unit.test.d.ts +2 -0
- package/dist/__tests__/public-surface.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-temporal.unit.test.d.ts +2 -0
- package/dist/__tests__/scene-temporal.unit.test.d.ts.map +1 -0
- package/dist/__tests__/shader-registry-transaction.unit.test.d.ts +2 -0
- package/dist/__tests__/shader-registry-transaction.unit.test.d.ts.map +1 -0
- package/dist/__tests__/shader.unit.test.d.ts +2 -0
- package/dist/__tests__/shader.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-lit-shader.test.d.ts +2 -0
- package/dist/__tests__/sprite-lit-shader.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-variants.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-variants.unit.test.d.ts.map +1 -0
- package/dist/__tests__/taa-resolve.unit.test.d.ts +2 -0
- package/dist/__tests__/taa-resolve.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transparent-pbr.unit.test.d.ts +2 -0
- package/dist/__tests__/transparent-pbr.unit.test.d.ts.map +1 -0
- package/dist/__tests__/vertex-color-variant.unit.test.d.ts +2 -0
- package/dist/__tests__/vertex-color-variant.unit.test.d.ts.map +1 -0
- package/dist/errors.d.ts +96 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +560 -0
- package/dist/index.mjs.map +1 -0
- package/dist/material/artifact-registry.d.ts +31 -0
- package/dist/material/artifact-registry.d.ts.map +1 -0
- package/dist/material/artifact-types.d.ts +13 -0
- package/dist/material/artifact-types.d.ts.map +1 -0
- package/dist/material-schemas.d.ts +8 -0
- package/dist/material-schemas.d.ts.map +1 -0
- package/dist/register-default-sprite-lit.d.ts +40 -0
- package/dist/register-default-sprite-lit.d.ts.map +1 -0
- package/dist/register-default-standard-pbr-skin.d.ts +34 -0
- package/dist/register-default-standard-pbr-skin.d.ts.map +1 -0
- package/dist/tonemap.d.ts +13 -0
- package/dist/tonemap.d.ts.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +58 -0
- package/src/ShaderRegistry.ts +519 -0
- package/src/__tests__/atmosphere-background.test.ts +33 -0
- package/src/__tests__/atmosphere-cubemap-orientation.test.ts +68 -0
- package/src/__tests__/atmosphere-preetham-numeric.test.ts +122 -0
- package/src/__tests__/atmosphere-preetham-red.test.ts +52 -0
- package/src/__tests__/atmosphere-preetham.test.ts +132 -0
- package/src/__tests__/atmosphere-three-r184-reference.test.ts +122 -0
- package/src/__tests__/bloom-fxaa-tonemap.unit.test.ts +31 -0
- package/src/__tests__/builtin-texture-sampling-contract.test.ts +56 -0
- package/src/__tests__/default-standard-pbr-alpha.unit.test.ts +19 -0
- package/src/__tests__/deferred-lighting-ssao.test.ts +114 -0
- package/src/__tests__/fog-oracle.unit.test.ts +132 -0
- package/src/__tests__/fog-orthographic-ray.unit.test.ts +62 -0
- package/src/__tests__/fog-producer-matrix.integration.test.ts +77 -0
- package/src/__tests__/hdrp-ssao-compile.test.ts +185 -0
- package/src/__tests__/ibl-irradiance.unit.test.ts +43 -0
- package/src/__tests__/ibl-sampling.unit.test.ts +40 -0
- package/src/__tests__/lighting-punctual.unit.test.ts +66 -0
- package/src/__tests__/manifest.fixture.json +22 -0
- package/src/__tests__/material-artifact-dedup.unit.test.ts +21 -0
- package/src/__tests__/material-builtins.unit.test.ts +111 -0
- package/src/__tests__/material-contract.unit.test.ts +79 -0
- package/src/__tests__/material-derived-builtins.integration.test.ts +30 -0
- package/src/__tests__/public-surface.unit.test.ts +9 -0
- package/src/__tests__/scene-temporal.unit.test.ts +32 -0
- package/src/__tests__/shader-registry-transaction.unit.test.ts +116 -0
- package/src/__tests__/shader.unit.test.ts +1909 -0
- package/src/__tests__/sprite-lit-shader.test.ts +240 -0
- package/src/__tests__/sprite-variants.unit.test.ts +209 -0
- package/src/__tests__/taa-resolve.unit.test.ts +32 -0
- package/src/__tests__/transparent-pbr.unit.test.ts +21 -0
- package/src/__tests__/vertex-color-variant.unit.test.ts +52 -0
- package/src/atmosphere-background.wgsl +80 -0
- package/src/atmosphere-cubemap.wgsl +72 -0
- package/src/atmosphere-ibl.wgsl +127 -0
- package/src/atmosphere-preetham.wgsl +214 -0
- package/src/bloom-blur.wgsl +89 -0
- package/src/bloom-bright.wgsl +50 -0
- package/src/bloom-composite.wgsl +54 -0
- package/src/brdf.wgsl +25 -0
- package/src/common.wgsl +523 -0
- package/src/default-standard-pbr-skin.wgsl +538 -0
- package/src/default-standard-pbr.wgsl +794 -0
- package/src/errors.ts +169 -0
- package/src/fog.wgsl +27 -0
- package/src/fxaa.wgsl +259 -0
- package/src/hdrp-cluster-forward.wgsl +186 -0
- package/src/hdrp-deferred-lighting.wgsl +69 -0
- package/src/hdrp-ssao.wgsl +174 -0
- package/src/ibl-brdf-lut.wgsl +92 -0
- package/src/ibl-equirect-to-cube.wgsl +56 -0
- package/src/ibl-irradiance.wgsl +89 -0
- package/src/ibl-prefilter.wgsl +101 -0
- package/src/ibl-sampling.wgsl +58 -0
- package/src/ibl-shared.wgsl +118 -0
- package/src/index.ts +166 -0
- package/src/lighting-directional.wgsl +471 -0
- package/src/lighting-punctual.wgsl +274 -0
- package/src/material/artifact-registry.ts +78 -0
- package/src/material/artifact-types.ts +26 -0
- package/src/material-schemas.ts +48 -0
- package/src/msdf-text.wgsl +208 -0
- package/src/pbr-temporal.wgsl +73 -0
- package/src/register-default-sprite-lit.ts +87 -0
- package/src/register-default-standard-pbr-skin.ts +74 -0
- package/src/shadow-pcf.wgsl +120 -0
- package/src/shadow_caster.wgsl +54 -0
- package/src/skybox.wgsl +75 -0
- package/src/sprite-lit.wgsl +307 -0
- package/src/sprite.wgsl +365 -0
- package/src/taa-resolve.wgsl +129 -0
- package/src/tbn.wgsl +54 -0
- package/src/tonemap.ts +13 -0
- package/src/tonemap.wgsl +177 -0
- package/src/types.ts +59 -0
- package/src/unlit.wgsl +186 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#define_import_path forgeax_view::taa_resolve
|
|
2
|
+
|
|
3
|
+
#import forgeax_view::common::fullscreen_triangle
|
|
4
|
+
#import forgeax_view::common::FullscreenOutput
|
|
5
|
+
|
|
6
|
+
struct TaaResolveParams {
|
|
7
|
+
currentJitterUv : vec2<f32>,
|
|
8
|
+
historyValid : u32,
|
|
9
|
+
temporalFrameIndex : u32,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
struct TaaResolveOutput {
|
|
13
|
+
@location(0) color : vec4<f32>,
|
|
14
|
+
@location(1) temporal : vec4<f32>,
|
|
15
|
+
};
|
|
16
|
+
|
|
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;
|
|
23
|
+
|
|
24
|
+
fn rgbToYCoCg(rgb : vec3<f32>) -> vec3<f32> {
|
|
25
|
+
return vec3<f32>(
|
|
26
|
+
dot(rgb, vec3<f32>(0.25, 0.5, 0.25)),
|
|
27
|
+
dot(rgb, vec3<f32>(0.5, 0.0, -0.5)),
|
|
28
|
+
dot(rgb, vec3<f32>(-0.25, 0.5, -0.25)),
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fn yCoCgToRgb(value : vec3<f32>) -> vec3<f32> {
|
|
33
|
+
return vec3<f32>(value.x + value.y - value.z, value.x + value.z, value.x - value.y - value.z);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fn luminance(rgb : vec3<f32>) -> f32 {
|
|
37
|
+
return dot(rgb, vec3<f32>(0.2126, 0.7152, 0.0722));
|
|
38
|
+
}
|
|
39
|
+
|
|
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);
|
|
45
|
+
}
|
|
46
|
+
|
|
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;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@vertex
|
|
64
|
+
fn vs_taa_resolve(@builtin(vertex_index) vertexIndex : u32) -> FullscreenOutput {
|
|
65
|
+
return fullscreen_triangle(vertexIndex);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@fragment
|
|
69
|
+
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);
|
|
73
|
+
let temporal = closestCurrentTemporal(pixel, dimensions);
|
|
74
|
+
|
|
75
|
+
var output : TaaResolveOutput;
|
|
76
|
+
output.temporal = temporal;
|
|
77
|
+
output.color = current;
|
|
78
|
+
|
|
79
|
+
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);
|
|
86
|
+
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);
|
|
115
|
+
let reactiveFactor = 1.0 - clamp(temporal.w, 0.0, 1.0);
|
|
116
|
+
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);
|
|
121
|
+
let lumaFactor = (1.0 - unbiasedLumaDelta) * (1.0 - unbiasedLumaDelta);
|
|
122
|
+
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;
|
|
129
|
+
}
|
package/src/tbn.wgsl
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#define_import_path forgeax_pbr::tbn
|
|
2
|
+
|
|
3
|
+
// @forgeax/engine-shader - tbn.wgsl (feat-20260523-shader-template-instance-split
|
|
4
|
+
// M5 / T01).
|
|
5
|
+
//
|
|
6
|
+
// Tangent-space normal decode + TBN basis composition helpers extracted from
|
|
7
|
+
// pbr.wgsl fs_main body. Pure-function module (zero @group / @binding) so it
|
|
8
|
+
// composes cleanly into any material shader that wants tangent-space normal
|
|
9
|
+
// mapping with the host's per-vertex tangent (vec4 with handedness in .w).
|
|
10
|
+
//
|
|
11
|
+
// RG-only tangent normal decode mirrors pbr.wgsl pre-split semantics
|
|
12
|
+
// (charter P5 byte-equivalent extraction). The default 1x1 normal fallback
|
|
13
|
+
// texture RG=(128,128) decodes to tangent (0,0,1) -- zero perturbation when
|
|
14
|
+
// normalTexture is absent (host-side defaultNormalTextureView). RG encoding
|
|
15
|
+
// also matches BC5 / RG normal maps and tolerates RGB normal maps (b is
|
|
16
|
+
// dropped, z is recomputed -- equivalent for unit vectors).
|
|
17
|
+
//
|
|
18
|
+
// Exports:
|
|
19
|
+
// - decodeTangentSpaceNormalRg(rg) -> vec3<f32> (pure)
|
|
20
|
+
// - scaleTangentSpaceNormal(tn, scale) -> vec3<f32> (pure)
|
|
21
|
+
// - applyTBN(worldNormal, worldTangent, tn) -> vec3<f32> (pure)
|
|
22
|
+
|
|
23
|
+
// Decode a tangent-space normal from the RG channels of a normal-map sample.
|
|
24
|
+
// Z is reconstructed via z = sqrt(saturate(1 - x^2 - y^2)); saturate guards
|
|
25
|
+
// against numerically-out-of-unit (x,y) producing NaN.
|
|
26
|
+
fn decodeTangentSpaceNormalRg(rg: vec2<f32>) -> vec3<f32> {
|
|
27
|
+
let xy = rg * 2.0 - vec2<f32>(1.0);
|
|
28
|
+
let z = sqrt(saturate(1.0 - dot(xy, xy)));
|
|
29
|
+
return vec3<f32>(xy, z);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Scale the XY perturbation while reconstructing Z so normalScale=0 restores
|
|
33
|
+
// the flat tangent normal and normalScale=1 preserves the sampled normal.
|
|
34
|
+
fn scaleTangentSpaceNormal(tn: vec3<f32>, scale: f32) -> vec3<f32> {
|
|
35
|
+
let xy = tn.xy * scale;
|
|
36
|
+
let z = sqrt(saturate(1.0 - dot(xy, xy)));
|
|
37
|
+
return vec3<f32>(xy, z);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Build the TBN basis from interpolated world-space normal + per-vertex
|
|
41
|
+
// tangent (xyz with handedness sign in .w), then transform a tangent-space
|
|
42
|
+
// normal `tn` into world-space. Re-normalises the input world normal +
|
|
43
|
+
// re-orthogonalises the tangent against the normal so that small interpolation
|
|
44
|
+
// drift across triangle barycentrics does not skew the basis.
|
|
45
|
+
fn applyTBN(
|
|
46
|
+
worldNormal : vec3<f32>,
|
|
47
|
+
worldTangent : vec4<f32>,
|
|
48
|
+
tn : vec3<f32>,
|
|
49
|
+
) -> vec3<f32> {
|
|
50
|
+
let n0 = normalize(worldNormal);
|
|
51
|
+
let t0 = normalize(worldTangent.xyz - dot(worldTangent.xyz, n0) * n0);
|
|
52
|
+
let b0 = cross(n0, t0) * worldTangent.w;
|
|
53
|
+
return normalize(t0 * tn.x + b0 * tn.y + n0 * tn.z);
|
|
54
|
+
}
|
package/src/tonemap.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Numeric mode IDs consumed by the built-in tonemap WGSL module. */
|
|
2
|
+
export const TONEMAP_SHADER_MODE = {
|
|
3
|
+
none: 0,
|
|
4
|
+
reinhardExtended: 1,
|
|
5
|
+
linear: 2,
|
|
6
|
+
cineon: 3,
|
|
7
|
+
acesFilmic: 4,
|
|
8
|
+
agx: 5,
|
|
9
|
+
neutral: 6,
|
|
10
|
+
reinhard: 7,
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export type TonemapShaderMode = (typeof TONEMAP_SHADER_MODE)[keyof typeof TONEMAP_SHADER_MODE];
|
package/src/tonemap.wgsl
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#define_import_path forgeax_view::tonemap
|
|
2
|
+
|
|
3
|
+
// @forgeax/engine-shader - Three r184 tone mapping output module.
|
|
4
|
+
//
|
|
5
|
+
// The public modes and formulas are the Three.js r184 oracle. The numeric
|
|
6
|
+
// values are the binding contract mirrored by TONEMAP_SHADER_MODE in tonemap.ts.
|
|
7
|
+
// `reinhard-extended` remains Forgeax's existing luminance-domain curve; the
|
|
8
|
+
// distinct `reinhard` mode is Three's per-channel Reinhard curve.
|
|
9
|
+
|
|
10
|
+
#import forgeax_view::common::FullscreenOutput
|
|
11
|
+
#import forgeax_view::common::fullscreen_triangle
|
|
12
|
+
#import forgeax_view::common::linearToSrgbOetf
|
|
13
|
+
|
|
14
|
+
const TONEMAP_LUMINANCE_EPSILON : f32 = 1e-5;
|
|
15
|
+
|
|
16
|
+
struct TonemapParams {
|
|
17
|
+
exposure : f32,
|
|
18
|
+
whitePoint : f32,
|
|
19
|
+
mode : u32,
|
|
20
|
+
pad1 : f32,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
@group(1) @binding(0) var hdr : texture_2d<f32>;
|
|
24
|
+
@group(1) @binding(1) var samp : sampler;
|
|
25
|
+
@group(1) @binding(2) var<uniform> params : TonemapParams;
|
|
26
|
+
|
|
27
|
+
@vertex
|
|
28
|
+
fn vs_main(@builtin(vertex_index) vertex_index : u32) -> FullscreenOutput {
|
|
29
|
+
return fullscreen_triangle(vertex_index);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fn tonemapReinhardExtended(color : vec3<f32>) -> vec3<f32> {
|
|
33
|
+
let luma = dot(color, vec3<f32>(0.2126, 0.7152, 0.0722));
|
|
34
|
+
let lw_sq = params.whitePoint * params.whitePoint;
|
|
35
|
+
let luma_prime = (luma * (1.0 + luma / lw_sq)) / (1.0 + luma);
|
|
36
|
+
let scale = luma_prime / max(luma, TONEMAP_LUMINANCE_EPSILON);
|
|
37
|
+
return color * scale;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn tonemapLinear(color : vec3<f32>) -> vec3<f32> {
|
|
41
|
+
return clamp(color, vec3<f32>(0.0), vec3<f32>(1.0));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fn tonemapReinhard(color : vec3<f32>) -> vec3<f32> {
|
|
45
|
+
return clamp(color / (color + vec3<f32>(1.0)), vec3<f32>(0.0), vec3<f32>(1.0));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fn tonemapCineon(color : vec3<f32>) -> vec3<f32> {
|
|
49
|
+
let x = max(color - vec3<f32>(0.004), vec3<f32>(0.0));
|
|
50
|
+
let a = x * (6.2 * x + vec3<f32>(0.5));
|
|
51
|
+
let b = x * (6.2 * x + vec3<f32>(1.7)) + vec3<f32>(0.06);
|
|
52
|
+
return pow(a / b, vec3<f32>(2.2));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fn acesInput(color : vec3<f32>) -> vec3<f32> {
|
|
56
|
+
return vec3<f32>(
|
|
57
|
+
dot(vec3<f32>(0.59719, 0.35458, 0.04823), color),
|
|
58
|
+
dot(vec3<f32>(0.07600, 0.90834, 0.01566), color),
|
|
59
|
+
dot(vec3<f32>(0.02840, 0.13383, 0.83777), color),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn acesOutput(color : vec3<f32>) -> vec3<f32> {
|
|
64
|
+
return vec3<f32>(
|
|
65
|
+
dot(vec3<f32>(1.60475, -0.53108, -0.07367), color),
|
|
66
|
+
dot(vec3<f32>(-0.10208, 1.10813, -0.00605), color),
|
|
67
|
+
dot(vec3<f32>(-0.00327, -0.07276, 1.07602), color),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn tonemapAcesFilmic(color : vec3<f32>) -> vec3<f32> {
|
|
72
|
+
let input = acesInput(color / vec3<f32>(0.6));
|
|
73
|
+
let a = input * (input + vec3<f32>(0.0245786)) - vec3<f32>(0.000090537);
|
|
74
|
+
let b = input * ((input + vec3<f32>(0.4329510)) * vec3<f32>(0.983729)) + vec3<f32>(0.238081);
|
|
75
|
+
return clamp(acesOutput(a / b), vec3<f32>(0.0), vec3<f32>(1.0));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn rec2020FromSrgb(color : vec3<f32>) -> vec3<f32> {
|
|
79
|
+
return vec3<f32>(
|
|
80
|
+
dot(vec3<f32>(0.6274, 0.3293, 0.0433), color),
|
|
81
|
+
dot(vec3<f32>(0.0691, 0.9195, 0.0113), color),
|
|
82
|
+
dot(vec3<f32>(0.0164, 0.0880, 0.8956), color),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fn srgbFromRec2020(color : vec3<f32>) -> vec3<f32> {
|
|
87
|
+
return vec3<f32>(
|
|
88
|
+
dot(vec3<f32>(1.6605, -0.5876, -0.0728), color),
|
|
89
|
+
dot(vec3<f32>(-0.1246, 1.1329, -0.0083), color),
|
|
90
|
+
dot(vec3<f32>(-0.0182, -0.1006, 1.1187), color),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
fn agxContrastApprox(x : vec3<f32>) -> vec3<f32> {
|
|
95
|
+
let x2 = x * x;
|
|
96
|
+
let x4 = x2 * x2;
|
|
97
|
+
return 15.5 * x4 * x2
|
|
98
|
+
- 40.14 * x4 * x
|
|
99
|
+
+ 31.96 * x4
|
|
100
|
+
- 6.868 * x2 * x
|
|
101
|
+
+ 0.4298 * x2
|
|
102
|
+
+ 0.1191 * x
|
|
103
|
+
- vec3<f32>(0.00232);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fn agxInset(color : vec3<f32>) -> vec3<f32> {
|
|
107
|
+
return vec3<f32>(
|
|
108
|
+
dot(vec3<f32>(0.856627153315983, 0.0951212405381588, 0.0482516061458583), color),
|
|
109
|
+
dot(vec3<f32>(0.137318972929847, 0.761241990602591, 0.101439036467562), color),
|
|
110
|
+
dot(vec3<f32>(0.11189821299995, 0.0767994186031903, 0.811302368396859), color),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
fn agxOutset(color : vec3<f32>) -> vec3<f32> {
|
|
115
|
+
return vec3<f32>(
|
|
116
|
+
dot(vec3<f32>(1.1271005818144368, -0.11060664309660323, -0.016493938717834573), color),
|
|
117
|
+
dot(vec3<f32>(-0.1413297634984383, 1.157823702216272, -0.016493938717834257), color),
|
|
118
|
+
dot(vec3<f32>(-0.14132976349843826, -0.11060664309660294, 1.2519364065950405), color),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fn tonemapAgx(color : vec3<f32>) -> vec3<f32> {
|
|
123
|
+
let min_ev = -12.47393;
|
|
124
|
+
let max_ev = 4.026069;
|
|
125
|
+
let rec2020 = agxInset(rec2020FromSrgb(color));
|
|
126
|
+
let log_color = log2(max(rec2020, vec3<f32>(1e-10)));
|
|
127
|
+
let normalized = clamp(
|
|
128
|
+
(log_color - vec3<f32>(min_ev)) / vec3<f32>(max_ev - min_ev),
|
|
129
|
+
vec3<f32>(0.0),
|
|
130
|
+
vec3<f32>(1.0),
|
|
131
|
+
);
|
|
132
|
+
let contrasted = agxContrastApprox(normalized);
|
|
133
|
+
let encoded = pow(max(agxOutset(contrasted), vec3<f32>(0.0)), vec3<f32>(2.2));
|
|
134
|
+
return clamp(srgbFromRec2020(encoded), vec3<f32>(0.0), vec3<f32>(1.0));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fn tonemapNeutral(color : vec3<f32>) -> vec3<f32> {
|
|
138
|
+
let start_compression = 0.8 - 0.04;
|
|
139
|
+
let desaturation = 0.15;
|
|
140
|
+
let x = min(color.r, min(color.g, color.b));
|
|
141
|
+
let offset = select(0.04, x - 6.25 * x * x, x < 0.08);
|
|
142
|
+
var compressed = color - vec3<f32>(offset);
|
|
143
|
+
let peak = max(compressed.r, max(compressed.g, compressed.b));
|
|
144
|
+
if (peak < start_compression) {
|
|
145
|
+
return compressed;
|
|
146
|
+
}
|
|
147
|
+
let d = 1.0 - start_compression;
|
|
148
|
+
let new_peak = 1.0 - d * d / (peak + d - start_compression);
|
|
149
|
+
compressed *= new_peak / peak;
|
|
150
|
+
let g = 1.0 - 1.0 / (desaturation * (peak - new_peak) + 1.0);
|
|
151
|
+
return mix(compressed, vec3<f32>(new_peak), g);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@fragment
|
|
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.
|
|
158
|
+
let source = textureSample(hdr, samp, in.uv);
|
|
159
|
+
let sample : vec3<f32> = source.rgb;
|
|
160
|
+
let exposed : vec3<f32> = sample * params.exposure;
|
|
161
|
+
var mapped : vec3<f32>;
|
|
162
|
+
switch (params.mode) {
|
|
163
|
+
case 1u: { mapped = tonemapReinhardExtended(exposed); }
|
|
164
|
+
case 2u: { mapped = tonemapLinear(exposed); }
|
|
165
|
+
case 3u: { mapped = tonemapCineon(exposed); }
|
|
166
|
+
case 4u: { mapped = tonemapAcesFilmic(exposed); }
|
|
167
|
+
case 5u: { mapped = tonemapAgx(exposed); }
|
|
168
|
+
case 6u: { mapped = tonemapNeutral(exposed); }
|
|
169
|
+
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); }
|
|
173
|
+
}
|
|
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);
|
|
177
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// @forgeax/engine-shader/types — shared variant types consumed by the runtime
|
|
2
|
+
// variant resolution layer (createRenderer.ts M3). The SSOT for the manifest
|
|
3
|
+
// schema stays in @forgeax/engine-vite-plugin-shader; this file re-declares the
|
|
4
|
+
// runtime-visible subset so the engine-shader package avoids a physical import
|
|
5
|
+
// of the build-time plugin (physical-isolation grep gate).
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Single variant within a material-shader manifest entry.
|
|
9
|
+
* `definesKey` is the canonical defines string (sorted `key=value` pairs joined
|
|
10
|
+
* with `+`). Empty key `""` denotes the default variant (all axes `true`).
|
|
11
|
+
*
|
|
12
|
+
* Authored by vite-plugin-shader Cartesian compile at buildStart; consumed by
|
|
13
|
+
* createRenderer variant resolution at engine boot (plan-strategy D-6).
|
|
14
|
+
*
|
|
15
|
+
* feat-20260613 fix-issue-2 (D-1 / D-2 bindingLayout cut): the runtime
|
|
16
|
+
* derives the BGL from `derive(paramSchema).bglEntries`; manifest entries
|
|
17
|
+
* no longer carry a bindingLayout sidecar (§Change stance: no v1/v2
|
|
18
|
+
* dual-path, no incremental drop window).
|
|
19
|
+
*/
|
|
20
|
+
export interface MaterialShaderManifestVariant {
|
|
21
|
+
readonly definesKey: string;
|
|
22
|
+
readonly defines: Record<string, boolean>;
|
|
23
|
+
readonly composedWgsl: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A material-shader entry in manifest.json carrying zero or more variants.
|
|
28
|
+
*
|
|
29
|
+
* When `variants` is empty the entry is single-variant (no `#pragma variant_axis`
|
|
30
|
+
* in the source). Otherwise `composedWgsl` carries the default
|
|
31
|
+
* (all-true) variant for backward compat; the `variants[]` array contains every
|
|
32
|
+
* compiled combination.
|
|
33
|
+
*
|
|
34
|
+
* For Engine.create() internal use only; AI users never see this type.
|
|
35
|
+
*/
|
|
36
|
+
export interface MaterialShaderManifestEntry {
|
|
37
|
+
readonly identifier: string;
|
|
38
|
+
readonly sourcePath: string;
|
|
39
|
+
readonly composedWgsl: string;
|
|
40
|
+
readonly paramSchema: string;
|
|
41
|
+
readonly variants: readonly MaterialShaderManifestVariant[];
|
|
42
|
+
/**
|
|
43
|
+
* feat-20260629 M4: uvSetCount from naga vertex @location reflection.
|
|
44
|
+
* Populated by vite-plugin-shader at build time from compileShader output.
|
|
45
|
+
* The runtime reads this for clamp-to-last alias in deriveVertexBufferLayout.
|
|
46
|
+
*/
|
|
47
|
+
readonly uvSetCount?: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Look up a variant by canonical defines key.
|
|
52
|
+
* Returns `undefined` when no variant matches the requested key.
|
|
53
|
+
*/
|
|
54
|
+
export function findVariantByKey(
|
|
55
|
+
entry: MaterialShaderManifestEntry,
|
|
56
|
+
definesKey: string,
|
|
57
|
+
): MaterialShaderManifestVariant | undefined {
|
|
58
|
+
return entry.variants.find((v) => v.definesKey === definesKey);
|
|
59
|
+
}
|
package/src/unlit.wgsl
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#define_import_path forgeax_material::unlit
|
|
2
|
+
#import forgeax_view::common::{View, FogViewParams, FogRay, Mesh, InstanceData, view, meshes, instances, sampleMaterialTextureLinear, packSceneTemporal}
|
|
3
|
+
#import forgeax_view::fog::{apply_fog}
|
|
4
|
+
|
|
5
|
+
#pragma variant_axis STORAGE_BUFFER_AVAILABLE
|
|
6
|
+
#pragma variant_axis VERTEX_COLOR_AVAILABLE
|
|
7
|
+
|
|
8
|
+
// @forgeax/engine-shader - unlit.wgsl (M5 feat-20260511-asset-system-v1;
|
|
9
|
+
// refactored M5 T-18 feat-20260512-naga-oil-composition-hmr to pull View +
|
|
10
|
+
// Mesh via naga_oil #import; expanded feat-20260518-pbr-direct-lighting-mvp
|
|
11
|
+
// M2 / w8 to share binding 0-6 layout + 12-floats VsIn with pbr.wgsl).
|
|
12
|
+
//
|
|
13
|
+
// Minimal unlit material shader: world * view * proj transform + flat
|
|
14
|
+
// fragment output of `material.baseColor * sample(baseColorTexture)`. No
|
|
15
|
+
// lighting, no normal mapping, no metallic/roughness. Consumed by
|
|
16
|
+
// RenderSystem when the material dispatch tag resolves to 'unlit'
|
|
17
|
+
// (plan-strategy D-P4 / requirements AC-07). The pipeline binds:
|
|
18
|
+
//
|
|
19
|
+
// @group(0) @binding(0) view uniform (see common.wgsl;
|
|
20
|
+
// unlit only reads
|
|
21
|
+
// worldViewProj)
|
|
22
|
+
// @group(1) @binding(0) material uniform (vec4 baseColor;
|
|
23
|
+
// metallic/roughness
|
|
24
|
+
// unused on this path)
|
|
25
|
+
// @group(1) @binding(1) baseColorSampler sampler
|
|
26
|
+
// @group(1) @binding(2) baseColorTexture texture_2d<f32>
|
|
27
|
+
// @group(2) @binding(0) meshes storage (see common.wgsl;
|
|
28
|
+
// normalMatrix not
|
|
29
|
+
// consumed in unlit)
|
|
30
|
+
// @group(3) @binding(0) instances storage (per-instance
|
|
31
|
+
// localFromInstance mat4;
|
|
32
|
+
// indexed by @builtin
|
|
33
|
+
// (instance_index);
|
|
34
|
+
// see common.wgsl)
|
|
35
|
+
//
|
|
36
|
+
// Material bindings are derived from the built-in paramSchema. Procedural
|
|
37
|
+
// geometry (M4) emits 12-floats vertex stride
|
|
38
|
+
// (pos+normal+uv+tangent); BUILTIN_CUBE / TRIANGLE keep 6-floats stride and
|
|
39
|
+
// route to a dedicated unlit pipeline branch wired by RenderSystem (M3 w22).
|
|
40
|
+
// This shader file consumes the 12-floats path; the 6-floats path is the
|
|
41
|
+
// vertex pipeline branch's responsibility.
|
|
42
|
+
|
|
43
|
+
struct Material {
|
|
44
|
+
baseColor : vec4<f32>,
|
|
45
|
+
alphaCutoff : f32,
|
|
46
|
+
baseColorTextureCoordinatesTransform : vec4<f32>,
|
|
47
|
+
baseColorTextureCoordinatesMetadata : vec4<f32>,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
@group(1) @binding(0) var<uniform> material : Material;
|
|
51
|
+
@group(1) @binding(1) var baseColorSampler : sampler;
|
|
52
|
+
@group(1) @binding(2) var baseColorTexture : texture_2d<f32>;
|
|
53
|
+
|
|
54
|
+
// Preserve filtering reflection for the bound texture passed to the helper.
|
|
55
|
+
fn materialTextureFilteringWitness() {
|
|
56
|
+
let base = baseColorTexture;
|
|
57
|
+
let baseWitness = textureSample(base, baseColorSampler, vec2<f32>(0.0));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
struct VsIn {
|
|
61
|
+
@location(0) pos : vec3<f32>,
|
|
62
|
+
@location(1) normal : vec3<f32>,
|
|
63
|
+
@location(2) uv : vec2<f32>,
|
|
64
|
+
@location(3) tangent : vec4<f32>,
|
|
65
|
+
#ifdef VERTEX_COLOR_AVAILABLE
|
|
66
|
+
@location(13) color : vec4<f32>,
|
|
67
|
+
#endif
|
|
68
|
+
};
|
|
69
|
+
struct VsOut {
|
|
70
|
+
@builtin(position) clip : vec4<f32>,
|
|
71
|
+
@location(0) uv : vec2<f32>,
|
|
72
|
+
@location(1) worldPos : vec3<f32>,
|
|
73
|
+
#ifdef VERTEX_COLOR_AVAILABLE
|
|
74
|
+
@location(14) color : vec4<f32>,
|
|
75
|
+
#endif
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
@vertex
|
|
79
|
+
fn vs_main(in : VsIn, @builtin(instance_index) idx : u32) -> VsOut {
|
|
80
|
+
// feat-20260604-instances-per-instance-transform-shader-group3-bin M1 / w5:
|
|
81
|
+
// entity world from meshes[0] (dynamic-offset window), per-instance local
|
|
82
|
+
// from instances[idx] (flat @group(3) buffer indexed by instance_index).
|
|
83
|
+
// Combine: entity_world * per_instance_local.
|
|
84
|
+
let world = meshes[0].worldFromLocal * instances[idx].localFromInstance * vec4<f32>(in.pos, 1.0);
|
|
85
|
+
var out : VsOut;
|
|
86
|
+
out.clip = view.worldViewProj * world;
|
|
87
|
+
out.uv = in.uv;
|
|
88
|
+
out.worldPos = world.xyz;
|
|
89
|
+
#ifdef VERTEX_COLOR_AVAILABLE
|
|
90
|
+
out.color = in.color;
|
|
91
|
+
#endif
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fn materialVertexColor(in : VsOut) -> vec4<f32> {
|
|
96
|
+
#ifdef VERTEX_COLOR_AVAILABLE
|
|
97
|
+
return in.color;
|
|
98
|
+
#else
|
|
99
|
+
return vec4<f32>(1.0);
|
|
100
|
+
#endif
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fn applySceneFog(viewParams : View, color : vec3<f32>, alpha : f32, worldPos : vec3<f32>) -> vec4<f32> {
|
|
104
|
+
var origin = viewParams.cameraPos;
|
|
105
|
+
var direction = normalize(worldPos - origin);
|
|
106
|
+
var rayDistance = length(worldPos - origin);
|
|
107
|
+
if (viewParams.temporalProjection.z >= 0.5) {
|
|
108
|
+
let nearH = viewParams.inverseViewProj * vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
|
109
|
+
let farH = viewParams.inverseViewProj * vec4<f32>(0.0, 0.0, 1.0, 1.0);
|
|
110
|
+
let nearPoint = nearH.xyz / nearH.w;
|
|
111
|
+
let farPoint = farH.xyz / farH.w;
|
|
112
|
+
direction = normalize(farPoint - nearPoint);
|
|
113
|
+
origin = worldPos - direction * dot(worldPos - viewParams.cameraPos, direction);
|
|
114
|
+
rayDistance = max(dot(worldPos - origin, direction), 0.0);
|
|
115
|
+
}
|
|
116
|
+
return apply_fog(viewParams.fog, FogRay(origin, direction, rayDistance), vec4<f32>(color, alpha));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@fragment
|
|
120
|
+
fn fs_main(in : VsOut) -> @location(0) vec4<f32> {
|
|
121
|
+
let texSample = sampleMaterialTextureLinear(baseColorTexture, baseColorSampler, in.uv, material.baseColorTextureCoordinatesMetadata.zw);
|
|
122
|
+
let vertexColor = materialVertexColor(in);
|
|
123
|
+
let alpha = material.baseColor.a * texSample.a * vertexColor.a;
|
|
124
|
+
if (material.alphaCutoff > 0.0 && alpha < material.alphaCutoff) {
|
|
125
|
+
discard;
|
|
126
|
+
}
|
|
127
|
+
return applySceneFog(
|
|
128
|
+
view,
|
|
129
|
+
material.baseColor.rgb * texSample.rgb * vertexColor.rgb,
|
|
130
|
+
alpha,
|
|
131
|
+
in.worldPos,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
struct TemporalVsOut {
|
|
136
|
+
@builtin(position) clip : vec4<f32>,
|
|
137
|
+
@location(0) uv : vec2<f32>,
|
|
138
|
+
@location(1) @interpolate(linear) currentClip : vec4<f32>,
|
|
139
|
+
@location(2) @interpolate(linear) previousClip : vec4<f32>,
|
|
140
|
+
#ifdef VERTEX_COLOR_AVAILABLE
|
|
141
|
+
@location(14) color : vec4<f32>,
|
|
142
|
+
#endif
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
@vertex
|
|
146
|
+
fn vs_temporal(in : VsIn, @builtin(instance_index) idx : u32) -> TemporalVsOut {
|
|
147
|
+
let currentWorld =
|
|
148
|
+
meshes[0].worldFromLocal * instances[idx].localFromInstance * vec4<f32>(in.pos, 1.0);
|
|
149
|
+
var previousWorld = currentWorld;
|
|
150
|
+
#if STORAGE_BUFFER_AVAILABLE == true
|
|
151
|
+
previousWorld = meshes[0].previousWorldFromLocal *
|
|
152
|
+
instances[idx].previousLocalFromInstance * vec4<f32>(in.pos, 1.0);
|
|
153
|
+
#endif
|
|
154
|
+
var out : TemporalVsOut;
|
|
155
|
+
out.currentClip = view.temporalCurrentViewProj * currentWorld;
|
|
156
|
+
out.clip = out.currentClip;
|
|
157
|
+
out.previousClip = view.temporalPreviousViewProj * previousWorld;
|
|
158
|
+
out.uv = in.uv;
|
|
159
|
+
#ifdef VERTEX_COLOR_AVAILABLE
|
|
160
|
+
out.color = in.color;
|
|
161
|
+
#endif
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
fn temporalVertexColor(in : TemporalVsOut) -> vec4<f32> {
|
|
166
|
+
#ifdef VERTEX_COLOR_AVAILABLE
|
|
167
|
+
return in.color;
|
|
168
|
+
#else
|
|
169
|
+
return vec4<f32>(1.0);
|
|
170
|
+
#endif
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@fragment
|
|
174
|
+
fn fs_temporal(in : TemporalVsOut) -> @location(0) vec4<f32> {
|
|
175
|
+
let texSample = sampleMaterialTextureLinear(baseColorTexture, baseColorSampler, in.uv, material.baseColorTextureCoordinatesMetadata.zw);
|
|
176
|
+
let vertexColor = temporalVertexColor(in);
|
|
177
|
+
let alpha = material.baseColor.a * texSample.a * vertexColor.a;
|
|
178
|
+
if (material.alphaCutoff > 0.0 && alpha < material.alphaCutoff) {
|
|
179
|
+
discard;
|
|
180
|
+
}
|
|
181
|
+
var reactive = 1.0;
|
|
182
|
+
#if STORAGE_BUFFER_AVAILABLE == true
|
|
183
|
+
reactive = meshes[0].temporal.x;
|
|
184
|
+
#endif
|
|
185
|
+
return packSceneTemporal(in.currentClip, in.previousClip, reactive);
|
|
186
|
+
}
|