@certe/atmos-renderer 0.1.0
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/LICENCE +674 -0
- package/README.md +166 -0
- package/dist/bloom-pass.d.ts +29 -0
- package/dist/bloom-pass.d.ts.map +1 -0
- package/dist/bloom-pass.js +173 -0
- package/dist/bloom-pass.js.map +1 -0
- package/dist/bloom-shader.d.ts +9 -0
- package/dist/bloom-shader.d.ts.map +1 -0
- package/dist/bloom-shader.js +69 -0
- package/dist/bloom-shader.js.map +1 -0
- package/dist/bounds.d.ts +10 -0
- package/dist/bounds.d.ts.map +1 -0
- package/dist/bounds.js +37 -0
- package/dist/bounds.js.map +1 -0
- package/dist/camera.d.ts +31 -0
- package/dist/camera.d.ts.map +1 -0
- package/dist/camera.js +53 -0
- package/dist/camera.js.map +1 -0
- package/dist/depth-prepass.d.ts +24 -0
- package/dist/depth-prepass.d.ts.map +1 -0
- package/dist/depth-prepass.js +107 -0
- package/dist/depth-prepass.js.map +1 -0
- package/dist/directional-light.d.ts +23 -0
- package/dist/directional-light.d.ts.map +1 -0
- package/dist/directional-light.js +36 -0
- package/dist/directional-light.js.map +1 -0
- package/dist/frustum.d.ts +15 -0
- package/dist/frustum.d.ts.map +1 -0
- package/dist/frustum.js +51 -0
- package/dist/frustum.js.map +1 -0
- package/dist/fullscreen-quad.d.ts +8 -0
- package/dist/fullscreen-quad.d.ts.map +1 -0
- package/dist/fullscreen-quad.js +30 -0
- package/dist/fullscreen-quad.js.map +1 -0
- package/dist/geometry.d.ts +28 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +245 -0
- package/dist/geometry.js.map +1 -0
- package/dist/grid-renderer.d.ts +10 -0
- package/dist/grid-renderer.d.ts.map +1 -0
- package/dist/grid-renderer.js +77 -0
- package/dist/grid-renderer.js.map +1 -0
- package/dist/grid-shader.d.ts +3 -0
- package/dist/grid-shader.d.ts.map +1 -0
- package/dist/grid-shader.js +89 -0
- package/dist/grid-shader.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/light.d.ts +59 -0
- package/dist/light.d.ts.map +1 -0
- package/dist/light.js +184 -0
- package/dist/light.js.map +1 -0
- package/dist/material-asset.d.ts +19 -0
- package/dist/material-asset.d.ts.map +1 -0
- package/dist/material-asset.js +30 -0
- package/dist/material-asset.js.map +1 -0
- package/dist/material.d.ts +50 -0
- package/dist/material.d.ts.map +1 -0
- package/dist/material.js +48 -0
- package/dist/material.js.map +1 -0
- package/dist/mesh-renderer.d.ts +43 -0
- package/dist/mesh-renderer.d.ts.map +1 -0
- package/dist/mesh-renderer.js +162 -0
- package/dist/mesh-renderer.js.map +1 -0
- package/dist/mesh.d.ts +16 -0
- package/dist/mesh.d.ts.map +1 -0
- package/dist/mesh.js +33 -0
- package/dist/mesh.js.map +1 -0
- package/dist/mipmap-generator.d.ts +7 -0
- package/dist/mipmap-generator.d.ts.map +1 -0
- package/dist/mipmap-generator.js +96 -0
- package/dist/mipmap-generator.js.map +1 -0
- package/dist/pbr-wgsl.d.ts +12 -0
- package/dist/pbr-wgsl.d.ts.map +1 -0
- package/dist/pbr-wgsl.js +159 -0
- package/dist/pbr-wgsl.js.map +1 -0
- package/dist/pipeline.d.ts +13 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +77 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/point-light.d.ts +16 -0
- package/dist/point-light.d.ts.map +1 -0
- package/dist/point-light.js +22 -0
- package/dist/point-light.js.map +1 -0
- package/dist/point-shadow-pass.d.ts +24 -0
- package/dist/point-shadow-pass.d.ts.map +1 -0
- package/dist/point-shadow-pass.js +192 -0
- package/dist/point-shadow-pass.js.map +1 -0
- package/dist/point-shadow-shader.d.ts +12 -0
- package/dist/point-shadow-shader.d.ts.map +1 -0
- package/dist/point-shadow-shader.js +52 -0
- package/dist/point-shadow-shader.js.map +1 -0
- package/dist/register-builtins.d.ts +2 -0
- package/dist/register-builtins.d.ts.map +1 -0
- package/dist/register-builtins.js +98 -0
- package/dist/register-builtins.js.map +1 -0
- package/dist/render-system.d.ts +99 -0
- package/dist/render-system.d.ts.map +1 -0
- package/dist/render-system.js +476 -0
- package/dist/render-system.js.map +1 -0
- package/dist/scene-depth.d.ts +36 -0
- package/dist/scene-depth.d.ts.map +1 -0
- package/dist/scene-depth.js +183 -0
- package/dist/scene-depth.js.map +1 -0
- package/dist/shader.d.ts +3 -0
- package/dist/shader.d.ts.map +1 -0
- package/dist/shader.js +144 -0
- package/dist/shader.js.map +1 -0
- package/dist/shadow-fragment-wgsl.d.ts +13 -0
- package/dist/shadow-fragment-wgsl.d.ts.map +1 -0
- package/dist/shadow-fragment-wgsl.js +205 -0
- package/dist/shadow-fragment-wgsl.js.map +1 -0
- package/dist/shadow-manager.d.ts +46 -0
- package/dist/shadow-manager.d.ts.map +1 -0
- package/dist/shadow-manager.js +259 -0
- package/dist/shadow-manager.js.map +1 -0
- package/dist/shadow-pass.d.ts +31 -0
- package/dist/shadow-pass.d.ts.map +1 -0
- package/dist/shadow-pass.js +135 -0
- package/dist/shadow-pass.js.map +1 -0
- package/dist/shadow-shader.d.ts +10 -0
- package/dist/shadow-shader.d.ts.map +1 -0
- package/dist/shadow-shader.js +24 -0
- package/dist/shadow-shader.js.map +1 -0
- package/dist/shadow-uniforms.d.ts +38 -0
- package/dist/shadow-uniforms.d.ts.map +1 -0
- package/dist/shadow-uniforms.js +97 -0
- package/dist/shadow-uniforms.js.map +1 -0
- package/dist/skinned-geometry.d.ts +14 -0
- package/dist/skinned-geometry.d.ts.map +1 -0
- package/dist/skinned-geometry.js +23 -0
- package/dist/skinned-geometry.js.map +1 -0
- package/dist/skinned-mesh-renderer.d.ts +54 -0
- package/dist/skinned-mesh-renderer.d.ts.map +1 -0
- package/dist/skinned-mesh-renderer.js +177 -0
- package/dist/skinned-mesh-renderer.js.map +1 -0
- package/dist/skinned-pipeline.d.ts +16 -0
- package/dist/skinned-pipeline.d.ts.map +1 -0
- package/dist/skinned-pipeline.js +112 -0
- package/dist/skinned-pipeline.js.map +1 -0
- package/dist/skinned-shader.d.ts +7 -0
- package/dist/skinned-shader.d.ts.map +1 -0
- package/dist/skinned-shader.js +52 -0
- package/dist/skinned-shader.js.map +1 -0
- package/dist/skinned-shadow-shader.d.ts +6 -0
- package/dist/skinned-shadow-shader.d.ts.map +1 -0
- package/dist/skinned-shadow-shader.js +31 -0
- package/dist/skinned-shadow-shader.js.map +1 -0
- package/dist/spot-light.d.ts +24 -0
- package/dist/spot-light.d.ts.map +1 -0
- package/dist/spot-light.js +41 -0
- package/dist/spot-light.js.map +1 -0
- package/dist/spot-shadow-pass.d.ts +36 -0
- package/dist/spot-shadow-pass.d.ts.map +1 -0
- package/dist/spot-shadow-pass.js +144 -0
- package/dist/spot-shadow-pass.js.map +1 -0
- package/dist/ssao-pass.d.ts +37 -0
- package/dist/ssao-pass.d.ts.map +1 -0
- package/dist/ssao-pass.js +208 -0
- package/dist/ssao-pass.js.map +1 -0
- package/dist/ssao-shader.d.ts +9 -0
- package/dist/ssao-shader.d.ts.map +1 -0
- package/dist/ssao-shader.js +120 -0
- package/dist/ssao-shader.js.map +1 -0
- package/dist/terrain-mesh-renderer.d.ts +39 -0
- package/dist/terrain-mesh-renderer.d.ts.map +1 -0
- package/dist/terrain-mesh-renderer.js +131 -0
- package/dist/terrain-mesh-renderer.js.map +1 -0
- package/dist/terrain-pipeline.d.ts +17 -0
- package/dist/terrain-pipeline.d.ts.map +1 -0
- package/dist/terrain-pipeline.js +70 -0
- package/dist/terrain-pipeline.js.map +1 -0
- package/dist/terrain-shader.d.ts +10 -0
- package/dist/terrain-shader.d.ts.map +1 -0
- package/dist/terrain-shader.js +154 -0
- package/dist/terrain-shader.js.map +1 -0
- package/dist/texture.d.ts +20 -0
- package/dist/texture.d.ts.map +1 -0
- package/dist/texture.js +87 -0
- package/dist/texture.js.map +1 -0
- package/dist/tonemap-pass.d.ts +22 -0
- package/dist/tonemap-pass.d.ts.map +1 -0
- package/dist/tonemap-pass.js +125 -0
- package/dist/tonemap-pass.js.map +1 -0
- package/dist/unlit-pipeline.d.ts +12 -0
- package/dist/unlit-pipeline.d.ts.map +1 -0
- package/dist/unlit-pipeline.js +59 -0
- package/dist/unlit-pipeline.js.map +1 -0
- package/dist/unlit-shader.d.ts +3 -0
- package/dist/unlit-shader.d.ts.map +1 -0
- package/dist/unlit-shader.js +33 -0
- package/dist/unlit-shader.js.map +1 -0
- package/dist/webgpu-device.d.ts +13 -0
- package/dist/webgpu-device.d.ts.map +1 -0
- package/dist/webgpu-device.js +70 -0
- package/dist/webgpu-device.js.map +1 -0
- package/dist/wireframe-pipeline.d.ts +7 -0
- package/dist/wireframe-pipeline.d.ts.map +1 -0
- package/dist/wireframe-pipeline.js +72 -0
- package/dist/wireframe-pipeline.js.map +1 -0
- package/package.json +28 -0
- package/src/index.ts +87 -0
package/dist/pbr-wgsl.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared PBR WGSL functions and light loop code.
|
|
3
|
+
* Concatenated into both shader.ts (standard PBR) and terrain-shader.ts (splat PBR).
|
|
4
|
+
*/
|
|
5
|
+
/** PBR helper functions: GGX distribution, geometry, Fresnel, computePBR, computeTBN */
|
|
6
|
+
export const PBR_FUNCTIONS_WGSL = /* wgsl */ `
|
|
7
|
+
// GGX/Trowbridge-Reitz normal distribution
|
|
8
|
+
fn distributionGGX(N: vec3<f32>, H: vec3<f32>, roughness: f32) -> f32 {
|
|
9
|
+
let a = roughness * roughness;
|
|
10
|
+
let a2 = a * a;
|
|
11
|
+
let NdotH = max(dot(N, H), 0.0);
|
|
12
|
+
let NdotH2 = NdotH * NdotH;
|
|
13
|
+
let denom = NdotH2 * (a2 - 1.0) + 1.0;
|
|
14
|
+
return a2 / (PI * denom * denom);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Schlick-GGX geometry function
|
|
18
|
+
fn geometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {
|
|
19
|
+
let r = roughness + 1.0;
|
|
20
|
+
let k = (r * r) / 8.0;
|
|
21
|
+
return NdotV / (NdotV * (1.0 - k) + k);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Smith's geometry function
|
|
25
|
+
fn geometrySmith(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>, roughness: f32) -> f32 {
|
|
26
|
+
let NdotV = max(dot(N, V), 0.0);
|
|
27
|
+
let NdotL = max(dot(N, L), 0.0);
|
|
28
|
+
return geometrySchlickGGX(NdotV, roughness) * geometrySchlickGGX(NdotL, roughness);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Fresnel-Schlick approximation
|
|
32
|
+
fn fresnelSchlick(cosTheta: f32, F0: vec3<f32>) -> vec3<f32> {
|
|
33
|
+
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Compute PBR contribution from a single light direction
|
|
37
|
+
fn computePBR(
|
|
38
|
+
N: vec3<f32>, V: vec3<f32>, L: vec3<f32>,
|
|
39
|
+
albedo: vec3<f32>, metallic: f32, roughness: f32,
|
|
40
|
+
F0: vec3<f32>, radiance: vec3<f32>,
|
|
41
|
+
) -> vec3<f32> {
|
|
42
|
+
let H = normalize(V + L);
|
|
43
|
+
let NDF = distributionGGX(N, H, roughness);
|
|
44
|
+
let G = geometrySmith(N, V, L, roughness);
|
|
45
|
+
let F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
|
46
|
+
|
|
47
|
+
let numerator = NDF * G * F;
|
|
48
|
+
let denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
|
|
49
|
+
let specular = numerator / denominator;
|
|
50
|
+
|
|
51
|
+
let kS = F;
|
|
52
|
+
let kD = (vec3<f32>(1.0) - kS) * (1.0 - metallic);
|
|
53
|
+
let NdotL = max(dot(N, L), 0.0);
|
|
54
|
+
|
|
55
|
+
return (kD * albedo / PI + specular) * radiance * NdotL;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Compute cotangent-frame TBN from screen-space derivatives
|
|
59
|
+
fn computeTBN(worldPos: vec3<f32>, worldNormal: vec3<f32>, uv: vec2<f32>) -> mat3x3<f32> {
|
|
60
|
+
let dp1 = dpdx(worldPos);
|
|
61
|
+
let dp2 = dpdy(worldPos);
|
|
62
|
+
let duv1 = dpdx(uv);
|
|
63
|
+
let duv2 = dpdy(uv);
|
|
64
|
+
let T = normalize(dp1 * duv2.y - dp2 * duv1.y);
|
|
65
|
+
let B = normalize(dp2 * duv1.x - dp1 * duv2.x);
|
|
66
|
+
let N = normalize(worldNormal);
|
|
67
|
+
return mat3x3(T, B, N);
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
/** Light loop WGSL: iterates dir/point/spot lights with PBR + shadow sampling.
|
|
71
|
+
* Expects: N, V, albedo, metallic, roughness, F0, worldPosition in scope. Writes to Lo. */
|
|
72
|
+
export const LIGHT_LOOP_WGSL = /* wgsl */ `
|
|
73
|
+
// Directional lights
|
|
74
|
+
for (var i = 0u; i < scene.numDirLights; i = i + 1u) {
|
|
75
|
+
let light = scene.dirLights[i];
|
|
76
|
+
let L = normalize(-light.direction.xyz);
|
|
77
|
+
let intensity = light.color.w;
|
|
78
|
+
let radiance = light.color.rgb * intensity;
|
|
79
|
+
var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);
|
|
80
|
+
let dirSlot = shadow.dirLightToSlot[i];
|
|
81
|
+
if (dirSlot != 0xFFFFFFFFu) {
|
|
82
|
+
contribution = contribution * sampleDirShadow(dirSlot, worldPosition);
|
|
83
|
+
}
|
|
84
|
+
Lo = Lo + contribution;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Point lights
|
|
88
|
+
for (var i = 0u; i < scene.numPointLights; i = i + 1u) {
|
|
89
|
+
let light = scene.pointLights[i];
|
|
90
|
+
let lightPos = light.position.xyz;
|
|
91
|
+
let range = light.position.w;
|
|
92
|
+
let intensity = light.color.w;
|
|
93
|
+
|
|
94
|
+
let toLight = lightPos - worldPosition;
|
|
95
|
+
let dist = length(toLight);
|
|
96
|
+
let L = toLight / max(dist, 0.0001);
|
|
97
|
+
|
|
98
|
+
// Smooth distance attenuation with range cutoff
|
|
99
|
+
let attenuation = max(1.0 - (dist * dist) / (range * range), 0.0);
|
|
100
|
+
let radiance = light.color.rgb * intensity * attenuation * attenuation;
|
|
101
|
+
|
|
102
|
+
var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);
|
|
103
|
+
let pointSlot = shadow.pointLightToSlot[i];
|
|
104
|
+
if (pointSlot != 0xFFFFFFFFu) {
|
|
105
|
+
contribution = contribution * samplePointShadow(pointSlot, worldPosition, N);
|
|
106
|
+
}
|
|
107
|
+
Lo = Lo + contribution;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Spot lights
|
|
111
|
+
for (var i = 0u; i < scene.numSpotLights; i = i + 1u) {
|
|
112
|
+
let light = scene.spotLights[i];
|
|
113
|
+
let lightPos = light.position.xyz;
|
|
114
|
+
let range = light.position.w;
|
|
115
|
+
let spotDir = light.direction.xyz;
|
|
116
|
+
let outerCos = light.direction.w;
|
|
117
|
+
let innerCos = light.extra.x;
|
|
118
|
+
let intensity = light.color.w;
|
|
119
|
+
|
|
120
|
+
let toLight = lightPos - worldPosition;
|
|
121
|
+
let dist = length(toLight);
|
|
122
|
+
let L = toLight / max(dist, 0.0001);
|
|
123
|
+
|
|
124
|
+
// Distance attenuation (same as point light)
|
|
125
|
+
let distAtt = max(1.0 - (dist * dist) / (range * range), 0.0);
|
|
126
|
+
|
|
127
|
+
// Cone attenuation: smoothstep between outer and inner cosines
|
|
128
|
+
let cosAngle = dot(-L, spotDir);
|
|
129
|
+
let coneAtt = smoothstep(outerCos, innerCos, cosAngle);
|
|
130
|
+
|
|
131
|
+
let attenuation = distAtt * distAtt * coneAtt;
|
|
132
|
+
let radiance = light.color.rgb * intensity * attenuation;
|
|
133
|
+
|
|
134
|
+
var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);
|
|
135
|
+
let spotSlot = shadow.spotLightToSlot[i];
|
|
136
|
+
if (spotSlot != 0xFFFFFFFFu) {
|
|
137
|
+
contribution = contribution * sampleSpotShadow(spotSlot, worldPosition);
|
|
138
|
+
}
|
|
139
|
+
Lo = Lo + contribution;
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
142
|
+
/** Fog calculation WGSL. Expects: scene, worldPosition, color in scope. Modifies color. */
|
|
143
|
+
export const FOG_WGSL = /* wgsl */ `
|
|
144
|
+
// Distance fog
|
|
145
|
+
if (scene.fogEnabled != 0u) {
|
|
146
|
+
let fogDist = length(scene.cameraPos.xyz - worldPosition);
|
|
147
|
+
var fogFactor: f32;
|
|
148
|
+
if (scene.fogMode == 0u) {
|
|
149
|
+
// Linear
|
|
150
|
+
fogFactor = saturate((scene.fogEnd - fogDist) / (scene.fogEnd - scene.fogStart));
|
|
151
|
+
} else {
|
|
152
|
+
// Exponential²
|
|
153
|
+
let d = scene.fogDensity * fogDist;
|
|
154
|
+
fogFactor = exp(-(d * d));
|
|
155
|
+
}
|
|
156
|
+
color = mix(scene.fogColor.rgb, color, fogFactor);
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
//# sourceMappingURL=pbr-wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pbr-wgsl.js","sourceRoot":"","sources":["../src/pbr-wgsl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wFAAwF;AACxF,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+D3C,CAAC;AAEF;4FAC4F;AAC5F,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqExC,CAAC;AAEF,2FAA2F;AAC3F,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAA;;;;;;;;;;;;;;;CAejC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PipelineResources {
|
|
2
|
+
pipeline: GPURenderPipeline;
|
|
3
|
+
objectBindGroupLayout: GPUBindGroupLayout;
|
|
4
|
+
materialBindGroupLayout: GPUBindGroupLayout;
|
|
5
|
+
shadowBindGroupLayout: GPUBindGroupLayout;
|
|
6
|
+
/** @deprecated Use objectBindGroupLayout instead */
|
|
7
|
+
bindGroupLayout: GPUBindGroupLayout;
|
|
8
|
+
}
|
|
9
|
+
/** HDR format used for the MSAA resolve target */
|
|
10
|
+
export declare const HDR_FORMAT: GPUTextureFormat;
|
|
11
|
+
export declare const MSAA_SAMPLE_COUNT = 4;
|
|
12
|
+
export declare function createRenderPipeline(device: GPUDevice, _format: GPUTextureFormat): PipelineResources;
|
|
13
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,qBAAqB,EAAE,kBAAkB,CAAC;IAC1C,uBAAuB,EAAE,kBAAkB,CAAC;IAC5C,qBAAqB,EAAE,kBAAkB,CAAC;IAC1C,oDAAoD;IACpD,eAAe,EAAE,kBAAkB,CAAC;CACrC;AAED,kDAAkD;AAClD,eAAO,MAAM,UAAU,EAAE,gBAAgC,CAAC;AAC1D,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,gBAAgB,GACxB,iBAAiB,CA2EnB"}
|
package/dist/pipeline.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { VERTEX_SHADER, FRAGMENT_SHADER } from './shader.js';
|
|
2
|
+
import { VERTEX_STRIDE_BYTES } from './geometry.js';
|
|
3
|
+
import { createShadowBindGroupLayout } from './shadow-uniforms.js';
|
|
4
|
+
/** HDR format used for the MSAA resolve target */
|
|
5
|
+
export const HDR_FORMAT = 'rgba16float';
|
|
6
|
+
export const MSAA_SAMPLE_COUNT = 4;
|
|
7
|
+
export function createRenderPipeline(device, _format) {
|
|
8
|
+
const vertexModule = device.createShaderModule({ code: VERTEX_SHADER });
|
|
9
|
+
const fragmentModule = device.createShaderModule({ code: FRAGMENT_SHADER });
|
|
10
|
+
// Group 0: per-object uniforms (MVP + model + normalMatrix) – vertex stage
|
|
11
|
+
const objectBindGroupLayout = device.createBindGroupLayout({
|
|
12
|
+
entries: [
|
|
13
|
+
{
|
|
14
|
+
binding: 0,
|
|
15
|
+
visibility: GPUShaderStage.VERTEX,
|
|
16
|
+
buffer: { type: 'uniform' },
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
});
|
|
20
|
+
// Group 1: per-material + per-scene uniforms + textures – fragment stage
|
|
21
|
+
const materialBindGroupLayout = device.createBindGroupLayout({
|
|
22
|
+
entries: [
|
|
23
|
+
{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
|
|
24
|
+
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
|
|
25
|
+
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
|
|
26
|
+
{ binding: 3, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
|
|
27
|
+
{ binding: 4, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
|
|
28
|
+
{ binding: 5, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
|
|
29
|
+
{ binding: 6, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
|
|
30
|
+
{ binding: 7, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
const shadowBindGroupLayout = createShadowBindGroupLayout(device);
|
|
34
|
+
const pipelineLayout = device.createPipelineLayout({
|
|
35
|
+
bindGroupLayouts: [objectBindGroupLayout, materialBindGroupLayout, shadowBindGroupLayout],
|
|
36
|
+
});
|
|
37
|
+
const pipeline = device.createRenderPipeline({
|
|
38
|
+
layout: pipelineLayout,
|
|
39
|
+
vertex: {
|
|
40
|
+
module: vertexModule,
|
|
41
|
+
entryPoint: 'main',
|
|
42
|
+
buffers: [
|
|
43
|
+
{
|
|
44
|
+
arrayStride: VERTEX_STRIDE_BYTES,
|
|
45
|
+
attributes: [
|
|
46
|
+
{ shaderLocation: 0, offset: 0, format: 'float32x3' }, // position
|
|
47
|
+
{ shaderLocation: 1, offset: 12, format: 'float32x3' }, // normal
|
|
48
|
+
{ shaderLocation: 2, offset: 24, format: 'float32x2' }, // uv
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
fragment: {
|
|
54
|
+
module: fragmentModule,
|
|
55
|
+
entryPoint: 'main',
|
|
56
|
+
targets: [{ format: HDR_FORMAT }],
|
|
57
|
+
},
|
|
58
|
+
multisample: { count: MSAA_SAMPLE_COUNT },
|
|
59
|
+
primitive: {
|
|
60
|
+
topology: 'triangle-list',
|
|
61
|
+
cullMode: 'back',
|
|
62
|
+
},
|
|
63
|
+
depthStencil: {
|
|
64
|
+
depthWriteEnabled: true,
|
|
65
|
+
depthCompare: 'less',
|
|
66
|
+
format: 'depth24plus',
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
pipeline,
|
|
71
|
+
objectBindGroupLayout,
|
|
72
|
+
materialBindGroupLayout,
|
|
73
|
+
shadowBindGroupLayout,
|
|
74
|
+
bindGroupLayout: objectBindGroupLayout,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component } from '@certe/atmos-core';
|
|
2
|
+
/**
|
|
3
|
+
* Point light component.
|
|
4
|
+
* Position is derived from the Transform's world position (worldMatrix[12..14]).
|
|
5
|
+
*/
|
|
6
|
+
export declare class PointLight extends Component {
|
|
7
|
+
color: Float32Array<ArrayBuffer>;
|
|
8
|
+
intensity: number;
|
|
9
|
+
range: number;
|
|
10
|
+
castShadows: boolean;
|
|
11
|
+
shadowIntensity: number;
|
|
12
|
+
shadowResolution: number;
|
|
13
|
+
/** Extract world position into `out`. */
|
|
14
|
+
getWorldPosition(out: Float32Array): Float32Array;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=point-light.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-light.d.ts","sourceRoot":"","sources":["../src/point-light.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C;;;GAGG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,KAAK,4BAA+B;IACpC,SAAS,SAAO;IAChB,KAAK,SAAQ;IACb,WAAW,UAAS;IACpB,eAAe,SAAO;IACtB,gBAAgB,SAAO;IAEvB,yCAAyC;IACzC,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY;CAOlD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Component } from '@certe/atmos-core';
|
|
2
|
+
/**
|
|
3
|
+
* Point light component.
|
|
4
|
+
* Position is derived from the Transform's world position (worldMatrix[12..14]).
|
|
5
|
+
*/
|
|
6
|
+
export class PointLight extends Component {
|
|
7
|
+
color = new Float32Array([1, 1, 1]);
|
|
8
|
+
intensity = 1.0;
|
|
9
|
+
range = 10.0;
|
|
10
|
+
castShadows = false;
|
|
11
|
+
shadowIntensity = 1.0;
|
|
12
|
+
shadowResolution = 512;
|
|
13
|
+
/** Extract world position into `out`. */
|
|
14
|
+
getWorldPosition(out) {
|
|
15
|
+
const m = this.gameObject.transform.worldMatrix;
|
|
16
|
+
out[0] = m[12];
|
|
17
|
+
out[1] = m[13];
|
|
18
|
+
out[2] = m[14];
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=point-light.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-light.js","sourceRoot":"","sources":["../src/point-light.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C;;;GAGG;AACH,MAAM,OAAO,UAAW,SAAQ,SAAS;IACvC,KAAK,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpC,SAAS,GAAG,GAAG,CAAC;IAChB,KAAK,GAAG,IAAI,CAAC;IACb,WAAW,GAAG,KAAK,CAAC;IACpB,eAAe,GAAG,GAAG,CAAC;IACtB,gBAAgB,GAAG,GAAG,CAAC;IAEvB,yCAAyC;IACzC,gBAAgB,CAAC,GAAiB;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAChD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAE,CAAC;QAChB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAE,CAAC;QAChB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAE,CAAC;QAChB,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Scene } from '@certe/atmos-core';
|
|
2
|
+
export declare class PointShadowPass {
|
|
3
|
+
private readonly _device;
|
|
4
|
+
private readonly _pipeline;
|
|
5
|
+
private readonly _faceBuffers;
|
|
6
|
+
private readonly _faceBindGroups;
|
|
7
|
+
private readonly _depthTexture;
|
|
8
|
+
private readonly _faceViews;
|
|
9
|
+
private readonly _sampler;
|
|
10
|
+
readonly cubeMapView: GPUTextureView;
|
|
11
|
+
readonly resolution: number;
|
|
12
|
+
private readonly _view;
|
|
13
|
+
private readonly _proj;
|
|
14
|
+
private readonly _vp;
|
|
15
|
+
private readonly _eye;
|
|
16
|
+
private readonly _target;
|
|
17
|
+
private readonly _up;
|
|
18
|
+
private readonly _uniformData;
|
|
19
|
+
get shadowSampler(): GPUSampler;
|
|
20
|
+
constructor(device: GPUDevice, objectBindGroupLayout: GPUBindGroupLayout, resolution?: number);
|
|
21
|
+
execute(encoder: GPUCommandEncoder, scene: Scene, lightPos: Float32Array, range: number, extraDraw?: (pass: GPURenderPassEncoder) => void): void;
|
|
22
|
+
destroy(): void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=point-shadow-pass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-shadow-pass.d.ts","sourceRoot":"","sources":["../src/point-shadow-pass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AA0B/C,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmB;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsB;IACtD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAa;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAG5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA2B;IAC/C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsC;IAEnE,IAAI,aAAa,IAAI,UAAU,CAE9B;gBAGC,MAAM,EAAE,SAAS,EACjB,qBAAqB,EAAE,kBAAkB,EACzC,UAAU,SAAqB;IA+FjC,OAAO,CACL,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAC/E,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,GAC/C,IAAI;IAyEP,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Mat4, Vec3 } from '@certe/atmos-math';
|
|
2
|
+
import { POINT_SHADOW_SHADER } from './point-shadow-shader.js';
|
|
3
|
+
import { VERTEX_STRIDE_BYTES } from './geometry.js';
|
|
4
|
+
import { MeshRenderer } from './mesh-renderer.js';
|
|
5
|
+
const DEFAULT_RESOLUTION = 512;
|
|
6
|
+
const NUM_FACES = 6;
|
|
7
|
+
/** Per-face buffer: mat4x4(64) + vec4(16) = 80 bytes */
|
|
8
|
+
const FACE_UNIFORM_SIZE = 80;
|
|
9
|
+
/**
|
|
10
|
+
* Cube face camera directions.
|
|
11
|
+
* Each entry: [dirX, dirY, dirZ, upX, upY, upZ]
|
|
12
|
+
*/
|
|
13
|
+
const CUBE_FACES = [
|
|
14
|
+
[1, 0, 0, 0, -1, 0], // +X
|
|
15
|
+
[-1, 0, 0, 0, -1, 0], // -X
|
|
16
|
+
[0, 1, 0, 0, 0, 1], // +Y
|
|
17
|
+
[0, -1, 0, 0, 0, -1], // -Y
|
|
18
|
+
[0, 0, 1, 0, -1, 0], // +Z
|
|
19
|
+
[0, 0, -1, 0, -1, 0], // -Z
|
|
20
|
+
];
|
|
21
|
+
export class PointShadowPass {
|
|
22
|
+
_device;
|
|
23
|
+
_pipeline;
|
|
24
|
+
_faceBuffers = [];
|
|
25
|
+
_faceBindGroups = [];
|
|
26
|
+
_depthTexture;
|
|
27
|
+
_faceViews = [];
|
|
28
|
+
_sampler;
|
|
29
|
+
cubeMapView;
|
|
30
|
+
resolution;
|
|
31
|
+
// Scratch matrices (reused each frame)
|
|
32
|
+
_view = Mat4.create();
|
|
33
|
+
_proj = Mat4.create();
|
|
34
|
+
_vp = Mat4.create();
|
|
35
|
+
_eye = new Float32Array(3);
|
|
36
|
+
_target = new Float32Array(3);
|
|
37
|
+
_up = new Float32Array(3);
|
|
38
|
+
_uniformData = new ArrayBuffer(FACE_UNIFORM_SIZE);
|
|
39
|
+
get shadowSampler() {
|
|
40
|
+
return this._sampler;
|
|
41
|
+
}
|
|
42
|
+
constructor(device, objectBindGroupLayout, resolution = DEFAULT_RESOLUTION) {
|
|
43
|
+
this._device = device;
|
|
44
|
+
this.resolution = resolution;
|
|
45
|
+
// Cube depth texture (6 layers)
|
|
46
|
+
this._depthTexture = device.createTexture({
|
|
47
|
+
size: [resolution, resolution, NUM_FACES],
|
|
48
|
+
format: 'depth32float',
|
|
49
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
50
|
+
});
|
|
51
|
+
// Per-face 2D views for render targets
|
|
52
|
+
for (let i = 0; i < NUM_FACES; i++) {
|
|
53
|
+
this._faceViews.push(this._depthTexture.createView({
|
|
54
|
+
dimension: '2d',
|
|
55
|
+
baseArrayLayer: i,
|
|
56
|
+
arrayLayerCount: 1,
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
// Cube view for shader sampling
|
|
60
|
+
this.cubeMapView = this._depthTexture.createView({ dimension: 'cube' });
|
|
61
|
+
// Comparison sampler
|
|
62
|
+
this._sampler = device.createSampler({ compare: 'less' });
|
|
63
|
+
// Bind group layout for group 1 (lightVP + lightPosAndFar)
|
|
64
|
+
const shadowBGL = device.createBindGroupLayout({
|
|
65
|
+
entries: [
|
|
66
|
+
{
|
|
67
|
+
binding: 0,
|
|
68
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
69
|
+
buffer: { type: 'uniform' },
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
// One uniform buffer + bind group per face (writeBuffer is enqueued before
|
|
74
|
+
// the command buffer executes, so a single buffer would use only the last write)
|
|
75
|
+
for (let i = 0; i < NUM_FACES; i++) {
|
|
76
|
+
const buf = device.createBuffer({
|
|
77
|
+
size: FACE_UNIFORM_SIZE,
|
|
78
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
79
|
+
});
|
|
80
|
+
this._faceBuffers.push(buf);
|
|
81
|
+
this._faceBindGroups.push(device.createBindGroup({
|
|
82
|
+
layout: shadowBGL,
|
|
83
|
+
entries: [{ binding: 0, resource: { buffer: buf } }],
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
// Shadow render pipeline (vertex + fragment for linear depth)
|
|
87
|
+
const shaderModule = device.createShaderModule({ code: POINT_SHADOW_SHADER });
|
|
88
|
+
const pipelineLayout = device.createPipelineLayout({
|
|
89
|
+
bindGroupLayouts: [objectBindGroupLayout, shadowBGL],
|
|
90
|
+
});
|
|
91
|
+
this._pipeline = device.createRenderPipeline({
|
|
92
|
+
layout: pipelineLayout,
|
|
93
|
+
vertex: {
|
|
94
|
+
module: shaderModule,
|
|
95
|
+
entryPoint: 'vs',
|
|
96
|
+
buffers: [
|
|
97
|
+
{
|
|
98
|
+
arrayStride: VERTEX_STRIDE_BYTES,
|
|
99
|
+
attributes: [
|
|
100
|
+
{ shaderLocation: 0, offset: 0, format: 'float32x3' },
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
fragment: {
|
|
106
|
+
module: shaderModule,
|
|
107
|
+
entryPoint: 'fs',
|
|
108
|
+
targets: [],
|
|
109
|
+
},
|
|
110
|
+
primitive: {
|
|
111
|
+
topology: 'triangle-list',
|
|
112
|
+
cullMode: 'front',
|
|
113
|
+
},
|
|
114
|
+
depthStencil: {
|
|
115
|
+
depthWriteEnabled: true,
|
|
116
|
+
depthCompare: 'less',
|
|
117
|
+
format: 'depth32float',
|
|
118
|
+
depthBias: 2,
|
|
119
|
+
depthBiasSlopeScale: 2.0,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
execute(encoder, scene, lightPos, range, extraDraw) {
|
|
124
|
+
const near = 0.1;
|
|
125
|
+
Mat4.perspective(this._proj, Math.PI / 2, 1.0, near, range);
|
|
126
|
+
// Flip Y: lookAt produces right-handed view but WebGPU cube map sampling
|
|
127
|
+
// expects V=0 at top matching tc convention (e.g. face +X: tc=-ry).
|
|
128
|
+
// Without this flip, all 6 faces are vertically inverted.
|
|
129
|
+
this._proj[5] = -this._proj[5];
|
|
130
|
+
const f32 = new Float32Array(this._uniformData);
|
|
131
|
+
const lx = lightPos[0], ly = lightPos[1], lz = lightPos[2];
|
|
132
|
+
// Collect shadow casters within range once (shared across all 6 faces)
|
|
133
|
+
const casters = [];
|
|
134
|
+
for (const obj of scene.getAllObjects()) {
|
|
135
|
+
const mr = obj.getComponent(MeshRenderer);
|
|
136
|
+
if (!mr || !mr.enabled || !mr.castShadow || !mr.mesh || !mr.bindGroup)
|
|
137
|
+
continue;
|
|
138
|
+
const bs = mr.worldBoundingSphere;
|
|
139
|
+
if (bs) {
|
|
140
|
+
const dx = bs.center[0] - lx;
|
|
141
|
+
const dy = bs.center[1] - ly;
|
|
142
|
+
const dz = bs.center[2] - lz;
|
|
143
|
+
if (dx * dx + dy * dy + dz * dz > (range + bs.radius) * (range + bs.radius))
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
casters.push(mr);
|
|
147
|
+
}
|
|
148
|
+
for (let face = 0; face < NUM_FACES; face++) {
|
|
149
|
+
const dir = CUBE_FACES[face];
|
|
150
|
+
Vec3.copy(this._eye, lightPos);
|
|
151
|
+
this._target[0] = lx + dir[0];
|
|
152
|
+
this._target[1] = ly + dir[1];
|
|
153
|
+
this._target[2] = lz + dir[2];
|
|
154
|
+
this._up[0] = dir[3];
|
|
155
|
+
this._up[1] = dir[4];
|
|
156
|
+
this._up[2] = dir[5];
|
|
157
|
+
Mat4.lookAt(this._view, this._eye, this._target, this._up);
|
|
158
|
+
Mat4.multiply(this._vp, this._proj, this._view);
|
|
159
|
+
f32.set(this._vp, 0);
|
|
160
|
+
f32[16] = lx;
|
|
161
|
+
f32[17] = ly;
|
|
162
|
+
f32[18] = lz;
|
|
163
|
+
f32[19] = range;
|
|
164
|
+
this._device.queue.writeBuffer(this._faceBuffers[face], 0, this._uniformData);
|
|
165
|
+
const pass = encoder.beginRenderPass({
|
|
166
|
+
colorAttachments: [],
|
|
167
|
+
depthStencilAttachment: {
|
|
168
|
+
view: this._faceViews[face],
|
|
169
|
+
depthClearValue: 1.0,
|
|
170
|
+
depthLoadOp: 'clear',
|
|
171
|
+
depthStoreOp: 'store',
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
pass.setPipeline(this._pipeline);
|
|
175
|
+
pass.setBindGroup(1, this._faceBindGroups[face]);
|
|
176
|
+
for (const mr of casters) {
|
|
177
|
+
pass.setBindGroup(0, mr.bindGroup);
|
|
178
|
+
pass.setVertexBuffer(0, mr.mesh.vertexBuffer);
|
|
179
|
+
pass.setIndexBuffer(mr.mesh.indexBuffer, mr.mesh.indexFormat);
|
|
180
|
+
pass.drawIndexed(mr.mesh.indexCount);
|
|
181
|
+
}
|
|
182
|
+
extraDraw?.(pass);
|
|
183
|
+
pass.end();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
destroy() {
|
|
187
|
+
this._depthTexture.destroy();
|
|
188
|
+
for (const buf of this._faceBuffers)
|
|
189
|
+
buf.destroy();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=point-shadow-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-shadow-pass.js","sourceRoot":"","sources":["../src/point-shadow-pass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Point light shadow shader – renders linear depth into cube map faces.
|
|
3
|
+
*
|
|
4
|
+
* Unlike directional shadows (depth-only), point shadows need a fragment shader
|
|
5
|
+
* to write linear depth (distance / far) via @builtin(frag_depth) for consistent
|
|
6
|
+
* precision across all 6 cube faces.
|
|
7
|
+
*
|
|
8
|
+
* Group 0: object uniforms (reuses existing objectBGL)
|
|
9
|
+
* Group 1: PointLightShadow { lightVP, lightPosAndFar }
|
|
10
|
+
*/
|
|
11
|
+
export declare const POINT_SHADOW_SHADER = "\nstruct ObjectUniforms {\n mvp: mat4x4<f32>,\n model: mat4x4<f32>,\n normalMatrix: mat4x4<f32>,\n};\n\nstruct PointLightShadow {\n lightVP: mat4x4<f32>,\n lightPosAndFar: vec4<f32>,\n};\n\n@group(0) @binding(0) var<uniform> object: ObjectUniforms;\n@group(1) @binding(0) var<uniform> shadow: PointLightShadow;\n\nstruct VsOut {\n @builtin(position) clipPos: vec4<f32>,\n @location(0) worldPos: vec3<f32>,\n};\n\n@vertex\nfn vs(@location(0) position: vec3<f32>) -> VsOut {\n let worldPos = (object.model * vec4<f32>(position, 1.0)).xyz;\n var out: VsOut;\n out.clipPos = shadow.lightVP * vec4<f32>(worldPos, 1.0);\n out.worldPos = worldPos;\n return out;\n}\n\nstruct FsOut {\n @builtin(frag_depth) depth: f32,\n};\n\n@fragment\nfn fs(@location(0) worldPos: vec3<f32>) -> FsOut {\n let dist = length(worldPos - shadow.lightPosAndFar.xyz);\n var out: FsOut;\n out.depth = dist / shadow.lightPosAndFar.w;\n return out;\n}\n";
|
|
12
|
+
//# sourceMappingURL=point-shadow-shader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-shadow-shader.d.ts","sourceRoot":"","sources":["../src/point-shadow-shader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,+6BAwC/B,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Point light shadow shader – renders linear depth into cube map faces.
|
|
3
|
+
*
|
|
4
|
+
* Unlike directional shadows (depth-only), point shadows need a fragment shader
|
|
5
|
+
* to write linear depth (distance / far) via @builtin(frag_depth) for consistent
|
|
6
|
+
* precision across all 6 cube faces.
|
|
7
|
+
*
|
|
8
|
+
* Group 0: object uniforms (reuses existing objectBGL)
|
|
9
|
+
* Group 1: PointLightShadow { lightVP, lightPosAndFar }
|
|
10
|
+
*/
|
|
11
|
+
export const POINT_SHADOW_SHADER = /* wgsl */ `
|
|
12
|
+
struct ObjectUniforms {
|
|
13
|
+
mvp: mat4x4<f32>,
|
|
14
|
+
model: mat4x4<f32>,
|
|
15
|
+
normalMatrix: mat4x4<f32>,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
struct PointLightShadow {
|
|
19
|
+
lightVP: mat4x4<f32>,
|
|
20
|
+
lightPosAndFar: vec4<f32>,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
@group(0) @binding(0) var<uniform> object: ObjectUniforms;
|
|
24
|
+
@group(1) @binding(0) var<uniform> shadow: PointLightShadow;
|
|
25
|
+
|
|
26
|
+
struct VsOut {
|
|
27
|
+
@builtin(position) clipPos: vec4<f32>,
|
|
28
|
+
@location(0) worldPos: vec3<f32>,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
@vertex
|
|
32
|
+
fn vs(@location(0) position: vec3<f32>) -> VsOut {
|
|
33
|
+
let worldPos = (object.model * vec4<f32>(position, 1.0)).xyz;
|
|
34
|
+
var out: VsOut;
|
|
35
|
+
out.clipPos = shadow.lightVP * vec4<f32>(worldPos, 1.0);
|
|
36
|
+
out.worldPos = worldPos;
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
struct FsOut {
|
|
41
|
+
@builtin(frag_depth) depth: f32,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
@fragment
|
|
45
|
+
fn fs(@location(0) worldPos: vec3<f32>) -> FsOut {
|
|
46
|
+
let dist = length(worldPos - shadow.lightPosAndFar.xyz);
|
|
47
|
+
var out: FsOut;
|
|
48
|
+
out.depth = dist / shadow.lightPosAndFar.w;
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
//# sourceMappingURL=point-shadow-shader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-shadow-shader.js","sourceRoot":"","sources":["../src/point-shadow-shader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwC5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-builtins.d.ts","sourceRoot":"","sources":["../src/register-builtins.ts"],"names":[],"mappings":"AASA,wBAAgB,wBAAwB,IAAI,IAAI,CA8F/C"}
|