@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spot-light.js","sourceRoot":"","sources":["../src/spot-light.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,OAAO,SAAU,SAAQ,SAAS;IACtC,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,iFAAiF;IACjF,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;IAChC,oFAAoF;IACpF,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;IAChC,WAAW,GAAG,KAAK,CAAC;IACpB,eAAe,GAAG,GAAG,CAAC;IACtB,gBAAgB,GAAG,IAAI,CAAC;IAExB,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;IAED,wFAAwF;IACxF,iBAAiB,CAAC,GAAiB;QACjC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAChD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACd,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACd,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAE,CAAC;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QAClB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QAClB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QAClB,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Scene } from '@certe/atmos-core';
|
|
2
|
+
import type { Mat4Type } from '@certe/atmos-math';
|
|
3
|
+
/**
|
|
4
|
+
* Single 2D perspective shadow map for spot lights.
|
|
5
|
+
* Uses perspective projection matching the spot cone (FOV = outerAngle * 2).
|
|
6
|
+
*/
|
|
7
|
+
export declare class SpotShadowPass {
|
|
8
|
+
private readonly _device;
|
|
9
|
+
private readonly _pipeline;
|
|
10
|
+
private readonly _lightVPBuffer;
|
|
11
|
+
private readonly _lightVPBindGroup;
|
|
12
|
+
private readonly _depthTexture;
|
|
13
|
+
private readonly _sampler;
|
|
14
|
+
readonly shadowMapView: GPUTextureView;
|
|
15
|
+
readonly resolution: number;
|
|
16
|
+
private readonly _view;
|
|
17
|
+
private readonly _proj;
|
|
18
|
+
private readonly _vp;
|
|
19
|
+
private readonly _target;
|
|
20
|
+
private readonly _up;
|
|
21
|
+
get lightVPBuffer(): GPUBuffer;
|
|
22
|
+
get shadowSampler(): GPUSampler;
|
|
23
|
+
constructor(device: GPUDevice, objectBindGroupLayout: GPUBindGroupLayout, resolution?: number);
|
|
24
|
+
/**
|
|
25
|
+
* Render shadow map from the spot light's perspective.
|
|
26
|
+
* @param lightPos World position of the spot light
|
|
27
|
+
* @param lightDir Normalized world direction of the spot light
|
|
28
|
+
* @param outerAngle Half-angle in radians
|
|
29
|
+
* @param range Light range (used as far plane)
|
|
30
|
+
*/
|
|
31
|
+
execute(encoder: GPUCommandEncoder, scene: Scene, lightPos: Float32Array, lightDir: Float32Array, outerAngle: number, range: number, extraDraw?: (pass: GPURenderPassEncoder) => void): void;
|
|
32
|
+
/** Return the computed view-projection matrix (valid after execute). */
|
|
33
|
+
getViewProjection(): Mat4Type;
|
|
34
|
+
destroy(): void;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=spot-shadow-pass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spot-shadow-pass.d.ts","sourceRoot":"","sources":["../src/spot-shadow-pass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAOlD;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAY;IAC3C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAe;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAa;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,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,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuB;IAE3C,IAAI,aAAa,IAAI,SAAS,CAAgC;IAC9D,IAAI,aAAa,IAAI,UAAU,CAA0B;gBAGvD,MAAM,EAAE,SAAS,EACjB,qBAAqB,EAAE,kBAAkB,EACzC,UAAU,SAAqB;IA4DjC;;;;;;OAMG;IACH,OAAO,CACL,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EACxC,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAC9C,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EACjC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,GAC/C,IAAI;IA4DP,wEAAwE;IACxE,iBAAiB,IAAI,QAAQ;IAE7B,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Mat4 } from '@certe/atmos-math';
|
|
2
|
+
import { SHADOW_VERTEX_SHADER } from './shadow-shader.js';
|
|
3
|
+
import { VERTEX_STRIDE_BYTES } from './geometry.js';
|
|
4
|
+
import { MeshRenderer } from './mesh-renderer.js';
|
|
5
|
+
const DEFAULT_RESOLUTION = 1024;
|
|
6
|
+
/**
|
|
7
|
+
* Single 2D perspective shadow map for spot lights.
|
|
8
|
+
* Uses perspective projection matching the spot cone (FOV = outerAngle * 2).
|
|
9
|
+
*/
|
|
10
|
+
export class SpotShadowPass {
|
|
11
|
+
_device;
|
|
12
|
+
_pipeline;
|
|
13
|
+
_lightVPBuffer;
|
|
14
|
+
_lightVPBindGroup;
|
|
15
|
+
_depthTexture;
|
|
16
|
+
_sampler;
|
|
17
|
+
shadowMapView;
|
|
18
|
+
resolution;
|
|
19
|
+
_view = Mat4.create();
|
|
20
|
+
_proj = Mat4.create();
|
|
21
|
+
_vp = Mat4.create();
|
|
22
|
+
_target = new Float32Array(3);
|
|
23
|
+
_up = new Float32Array(3);
|
|
24
|
+
get lightVPBuffer() { return this._lightVPBuffer; }
|
|
25
|
+
get shadowSampler() { return this._sampler; }
|
|
26
|
+
constructor(device, objectBindGroupLayout, resolution = DEFAULT_RESOLUTION) {
|
|
27
|
+
this._device = device;
|
|
28
|
+
this.resolution = resolution;
|
|
29
|
+
this._lightVPBuffer = device.createBuffer({
|
|
30
|
+
size: 64,
|
|
31
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
32
|
+
});
|
|
33
|
+
const lightVPBGL = device.createBindGroupLayout({
|
|
34
|
+
entries: [
|
|
35
|
+
{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
this._lightVPBindGroup = device.createBindGroup({
|
|
39
|
+
layout: lightVPBGL,
|
|
40
|
+
entries: [
|
|
41
|
+
{ binding: 0, resource: { buffer: this._lightVPBuffer } },
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
this._depthTexture = device.createTexture({
|
|
45
|
+
size: [resolution, resolution],
|
|
46
|
+
format: 'depth32float',
|
|
47
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
48
|
+
});
|
|
49
|
+
this.shadowMapView = this._depthTexture.createView();
|
|
50
|
+
this._sampler = device.createSampler({ compare: 'less' });
|
|
51
|
+
const shaderModule = device.createShaderModule({ code: SHADOW_VERTEX_SHADER });
|
|
52
|
+
const pipelineLayout = device.createPipelineLayout({
|
|
53
|
+
bindGroupLayouts: [objectBindGroupLayout, lightVPBGL],
|
|
54
|
+
});
|
|
55
|
+
this._pipeline = device.createRenderPipeline({
|
|
56
|
+
layout: pipelineLayout,
|
|
57
|
+
vertex: {
|
|
58
|
+
module: shaderModule,
|
|
59
|
+
entryPoint: 'main',
|
|
60
|
+
buffers: [{
|
|
61
|
+
arrayStride: VERTEX_STRIDE_BYTES,
|
|
62
|
+
attributes: [
|
|
63
|
+
{ shaderLocation: 0, offset: 0, format: 'float32x3' },
|
|
64
|
+
],
|
|
65
|
+
}],
|
|
66
|
+
},
|
|
67
|
+
primitive: { topology: 'triangle-list', cullMode: 'back' },
|
|
68
|
+
depthStencil: {
|
|
69
|
+
depthWriteEnabled: true,
|
|
70
|
+
depthCompare: 'less',
|
|
71
|
+
format: 'depth32float',
|
|
72
|
+
depthBias: 2,
|
|
73
|
+
depthBiasSlopeScale: 2.0,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Render shadow map from the spot light's perspective.
|
|
79
|
+
* @param lightPos World position of the spot light
|
|
80
|
+
* @param lightDir Normalized world direction of the spot light
|
|
81
|
+
* @param outerAngle Half-angle in radians
|
|
82
|
+
* @param range Light range (used as far plane)
|
|
83
|
+
*/
|
|
84
|
+
execute(encoder, scene, lightPos, lightDir, outerAngle, range, extraDraw) {
|
|
85
|
+
// Perspective projection: FOV = outerAngle * 2, aspect 1:1
|
|
86
|
+
const fov = outerAngle * 2;
|
|
87
|
+
Mat4.perspective(this._proj, fov, 1.0, 0.1, range);
|
|
88
|
+
// View matrix: lookAt from lightPos toward lightPos + lightDir
|
|
89
|
+
this._target[0] = lightPos[0] + lightDir[0];
|
|
90
|
+
this._target[1] = lightPos[1] + lightDir[1];
|
|
91
|
+
this._target[2] = lightPos[2] + lightDir[2];
|
|
92
|
+
// Pick an up vector that isn't collinear with lightDir
|
|
93
|
+
const absY = Math.abs(lightDir[1]);
|
|
94
|
+
this._up[0] = 0;
|
|
95
|
+
this._up[1] = absY > 0.99 ? 0 : 1;
|
|
96
|
+
this._up[2] = absY > 0.99 ? 1 : 0;
|
|
97
|
+
Mat4.lookAt(this._view, lightPos, this._target, this._up);
|
|
98
|
+
Mat4.multiply(this._vp, this._proj, this._view);
|
|
99
|
+
this._device.queue.writeBuffer(this._lightVPBuffer, 0, this._vp);
|
|
100
|
+
// Collect casters within range
|
|
101
|
+
const lx = lightPos[0], ly = lightPos[1], lz = lightPos[2];
|
|
102
|
+
const casters = [];
|
|
103
|
+
for (const obj of scene.getAllObjects()) {
|
|
104
|
+
const mr = obj.getComponent(MeshRenderer);
|
|
105
|
+
if (!mr || !mr.enabled || !mr.castShadow || !mr.mesh || !mr.bindGroup)
|
|
106
|
+
continue;
|
|
107
|
+
const bs = mr.worldBoundingSphere;
|
|
108
|
+
if (bs) {
|
|
109
|
+
const dx = bs.center[0] - lx;
|
|
110
|
+
const dy = bs.center[1] - ly;
|
|
111
|
+
const dz = bs.center[2] - lz;
|
|
112
|
+
if (dx * dx + dy * dy + dz * dz > (range + bs.radius) * (range + bs.radius))
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
casters.push(mr);
|
|
116
|
+
}
|
|
117
|
+
const pass = encoder.beginRenderPass({
|
|
118
|
+
colorAttachments: [],
|
|
119
|
+
depthStencilAttachment: {
|
|
120
|
+
view: this.shadowMapView,
|
|
121
|
+
depthClearValue: 1.0,
|
|
122
|
+
depthLoadOp: 'clear',
|
|
123
|
+
depthStoreOp: 'store',
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
pass.setPipeline(this._pipeline);
|
|
127
|
+
pass.setBindGroup(1, this._lightVPBindGroup);
|
|
128
|
+
for (const mr of casters) {
|
|
129
|
+
pass.setBindGroup(0, mr.bindGroup);
|
|
130
|
+
pass.setVertexBuffer(0, mr.mesh.vertexBuffer);
|
|
131
|
+
pass.setIndexBuffer(mr.mesh.indexBuffer, mr.mesh.indexFormat);
|
|
132
|
+
pass.drawIndexed(mr.mesh.indexCount);
|
|
133
|
+
}
|
|
134
|
+
extraDraw?.(pass);
|
|
135
|
+
pass.end();
|
|
136
|
+
}
|
|
137
|
+
/** Return the computed view-projection matrix (valid after execute). */
|
|
138
|
+
getViewProjection() { return this._vp; }
|
|
139
|
+
destroy() {
|
|
140
|
+
this._depthTexture.destroy();
|
|
141
|
+
this._lightVPBuffer.destroy();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=spot-shadow-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spot-shadow-pass.js","sourceRoot":"","sources":["../src/spot-shadow-pass.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC;;;GAGG;AACH,MAAM,OAAO,cAAc;IACR,OAAO,CAAY;IACnB,SAAS,CAAoB;IAC7B,cAAc,CAAY;IAC1B,iBAAiB,CAAe;IAChC,aAAa,CAAa;IAC1B,QAAQ,CAAa;IAC7B,aAAa,CAAiB;IAC9B,UAAU,CAAS;IAEX,KAAK,GAAa,IAAI,CAAC,MAAM,EAAE,CAAC;IAChC,KAAK,GAAa,IAAI,CAAC,MAAM,EAAE,CAAC;IAChC,GAAG,GAAa,IAAI,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,GAAG,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;IAE3C,IAAI,aAAa,KAAgB,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAC9D,IAAI,aAAa,KAAiB,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEzD,YACE,MAAiB,EACjB,qBAAyC,EACzC,UAAU,GAAG,kBAAkB;QAE/B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAE7B,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC;YACxC,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,QAAQ;SACxD,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,MAAM,CAAC,qBAAqB,CAAC;YAC9C,OAAO,EAAE;gBACP,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;aAC/E;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,eAAe,CAAC;YAC9C,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE;gBACP,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE;aAC1D;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;YACxC,IAAI,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;YAC9B,MAAM,EAAE,cAAc;YACtB,KAAK,EAAE,eAAe,CAAC,iBAAiB,GAAG,eAAe,CAAC,eAAe;SAC3E,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;QAErD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAE1D,MAAM,YAAY,GAAG,MAAM,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;QAC/E,MAAM,cAAc,GAAG,MAAM,CAAC,oBAAoB,CAAC;YACjD,gBAAgB,EAAE,CAAC,qBAAqB,EAAE,UAAU,CAAC;SACtD,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,oBAAoB,CAAC;YAC3C,MAAM,EAAE,cAAc;YACtB,MAAM,EAAE;gBACN,MAAM,EAAE,YAAY;gBACpB,UAAU,EAAE,MAAM;gBAClB,OAAO,EAAE,CAAC;wBACR,WAAW,EAAE,mBAAmB;wBAChC,UAAU,EAAE;4BACV,EAAE,cAAc,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE;yBACtD;qBACF,CAAC;aACH;YACD,SAAS,EAAE,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE;YAC1D,YAAY,EAAE;gBACZ,iBAAiB,EAAE,IAAI;gBACvB,YAAY,EAAE,MAAM;gBACpB,MAAM,EAAE,cAAc;gBACtB,SAAS,EAAE,CAAC;gBACZ,mBAAmB,EAAE,GAAG;aACzB;SACF,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CACL,OAA0B,EAAE,KAAY,EACxC,QAAsB,EAAE,QAAsB,EAC9C,UAAkB,EAAE,KAAa,EACjC,SAAgD;QAEhD,2DAA2D;QAC3D,MAAM,GAAG,GAAG,UAAU,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAEnD,+DAA+D;QAC/D,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAE9C,uDAAuD;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,IAAI,CAAC,GAAiC,CAAC,CAAC;QAE/F,+BAA+B;QAC/B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC9D,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,aAAa,EAAE,EAAE,CAAC;YACxC,MAAM,EAAE,GAAG,GAAG,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;YAC1C,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,SAAS;gBAAE,SAAS;YAChF,MAAM,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC;YAClC,IAAI,EAAE,EAAE,CAAC;gBACP,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC;gBAC9B,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC;gBAC9B,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC;gBAC9B,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC;oBAAE,SAAS;YACxF,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC;YACnC,gBAAgB,EAAE,EAAE;YACpB,sBAAsB,EAAE;gBACtB,IAAI,EAAE,IAAI,CAAC,aAAa;gBACxB,eAAe,EAAE,GAAG;gBACpB,WAAW,EAAE,OAAO;gBACpB,YAAY,EAAE,OAAO;aACtB;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAE7C,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YACzB,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,SAAU,CAAC,CAAC;YACpC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,EAAE,CAAC,IAAK,CAAC,YAAY,CAAC,CAAC;YAC/C,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,IAAK,CAAC,WAAW,EAAE,EAAE,CAAC,IAAK,CAAC,WAAW,CAAC,CAAC;YAChE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAK,CAAC,UAAU,CAAC,CAAC;QACxC,CAAC;QAED,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC;QAElB,IAAI,CAAC,GAAG,EAAE,CAAC;IACb,CAAC;IAED,wEAAwE;IACxE,iBAAiB,KAAe,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAElD,OAAO;QACL,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen-Space Ambient Occlusion pass.
|
|
3
|
+
* 1. Compute noisy AO at half resolution from depth buffer
|
|
4
|
+
* 2. Blur the result with a 4x4 box filter
|
|
5
|
+
* Output: blurred AO texture view (r8unorm, half-res)
|
|
6
|
+
*/
|
|
7
|
+
import type { Mat4Type } from '@certe/atmos-math';
|
|
8
|
+
export declare class SSAOPass {
|
|
9
|
+
radius: number;
|
|
10
|
+
bias: number;
|
|
11
|
+
intensity: number;
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
private readonly _device;
|
|
14
|
+
private readonly _ssaoPipeline;
|
|
15
|
+
private readonly _blurPipeline;
|
|
16
|
+
private readonly _ssaoBGL;
|
|
17
|
+
private readonly _blurBGL;
|
|
18
|
+
private readonly _paramsBuffer;
|
|
19
|
+
private readonly _noiseTexture;
|
|
20
|
+
private readonly _linearSampler;
|
|
21
|
+
private readonly _kernel;
|
|
22
|
+
private readonly _paramsData;
|
|
23
|
+
private _aoTexture;
|
|
24
|
+
private _aoView;
|
|
25
|
+
private _blurTexture;
|
|
26
|
+
private _blurView;
|
|
27
|
+
private _width;
|
|
28
|
+
private _height;
|
|
29
|
+
private _whiteTexture;
|
|
30
|
+
private _whiteView;
|
|
31
|
+
constructor(device: GPUDevice);
|
|
32
|
+
private _ensureTextures;
|
|
33
|
+
/** Execute SSAO. Returns AO texture view (white if disabled or no depth). */
|
|
34
|
+
execute(encoder: GPUCommandEncoder, depthView: GPUTextureView | null, projMatrix: Mat4Type, invProjMatrix: Mat4Type, screenW: number, screenH: number): GPUTextureView;
|
|
35
|
+
destroy(): void;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=ssao-pass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssao-pass.d.ts","sourceRoot":"","sources":["../src/ssao-pass.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAOlD,qBAAa,QAAQ;IACnB,MAAM,SAAO;IACb,IAAI,SAAS;IACb,SAAS,SAAO;IAChB,OAAO,UAAQ;IAEf,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAY;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmB;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAa;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAe;IAE3C,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAK;IAGpB,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAiB;gBAEvB,MAAM,EAAE,SAAS;IAgG7B,OAAO,CAAC,eAAe;IAuBvB,6EAA6E;IAC7E,OAAO,CACL,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,cAAc,GAAG,IAAI,EAChC,UAAU,EAAE,QAAQ,EACpB,aAAa,EAAE,QAAQ,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,cAAc;IA+DjB,OAAO,IAAI,IAAI;CAOhB"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen-Space Ambient Occlusion pass.
|
|
3
|
+
* 1. Compute noisy AO at half resolution from depth buffer
|
|
4
|
+
* 2. Blur the result with a 4x4 box filter
|
|
5
|
+
* Output: blurred AO texture view (r8unorm, half-res)
|
|
6
|
+
*/
|
|
7
|
+
import { SSAO_SHADER, SSAO_BLUR_SHADER, SSAO_KERNEL_SIZE } from './ssao-shader.js';
|
|
8
|
+
import { drawFullscreenTriangle } from './fullscreen-quad.js';
|
|
9
|
+
const AO_FORMAT = 'r8unorm';
|
|
10
|
+
/** SSAO uniform layout: invProj(64) + proj(64) + radius(4) + bias(4) + intensity(4) + pad(4) + kernel(256) = 400 */
|
|
11
|
+
const PARAMS_SIZE = 400;
|
|
12
|
+
export class SSAOPass {
|
|
13
|
+
radius = 0.5;
|
|
14
|
+
bias = 0.025;
|
|
15
|
+
intensity = 1.5;
|
|
16
|
+
enabled = true;
|
|
17
|
+
_device;
|
|
18
|
+
_ssaoPipeline;
|
|
19
|
+
_blurPipeline;
|
|
20
|
+
_ssaoBGL;
|
|
21
|
+
_blurBGL;
|
|
22
|
+
_paramsBuffer;
|
|
23
|
+
_noiseTexture;
|
|
24
|
+
_linearSampler;
|
|
25
|
+
_kernel;
|
|
26
|
+
_paramsData;
|
|
27
|
+
_aoTexture = null;
|
|
28
|
+
_aoView = null;
|
|
29
|
+
_blurTexture = null;
|
|
30
|
+
_blurView = null;
|
|
31
|
+
_width = 0;
|
|
32
|
+
_height = 0;
|
|
33
|
+
// Fallback 1x1 white AO (used when SSAO is disabled)
|
|
34
|
+
_whiteTexture;
|
|
35
|
+
_whiteView;
|
|
36
|
+
constructor(device) {
|
|
37
|
+
this._device = device;
|
|
38
|
+
// Generate hemisphere kernel
|
|
39
|
+
this._kernel = new Float32Array(SSAO_KERNEL_SIZE * 4);
|
|
40
|
+
for (let i = 0; i < SSAO_KERNEL_SIZE; i++) {
|
|
41
|
+
// Random point in hemisphere
|
|
42
|
+
let x = Math.random() * 2 - 1;
|
|
43
|
+
let y = Math.random() * 2 - 1;
|
|
44
|
+
let z = Math.random(); // hemisphere: z >= 0
|
|
45
|
+
const len = Math.sqrt(x * x + y * y + z * z) || 1;
|
|
46
|
+
x /= len;
|
|
47
|
+
y /= len;
|
|
48
|
+
z /= len;
|
|
49
|
+
// Accelerating distribution: more samples close to origin
|
|
50
|
+
let scale = (i + 1) / SSAO_KERNEL_SIZE;
|
|
51
|
+
scale = 0.1 + scale * scale * 0.9;
|
|
52
|
+
this._kernel[i * 4] = x * scale;
|
|
53
|
+
this._kernel[i * 4 + 1] = y * scale;
|
|
54
|
+
this._kernel[i * 4 + 2] = z * scale;
|
|
55
|
+
this._kernel[i * 4 + 3] = 0;
|
|
56
|
+
}
|
|
57
|
+
// 4x4 noise texture (random tangent-space rotations)
|
|
58
|
+
const noiseData = new Uint8Array(4 * 4 * 4);
|
|
59
|
+
for (let i = 0; i < 16; i++) {
|
|
60
|
+
const angle = Math.random() * Math.PI * 2;
|
|
61
|
+
noiseData[i * 4] = Math.floor((Math.cos(angle) * 0.5 + 0.5) * 255);
|
|
62
|
+
noiseData[i * 4 + 1] = Math.floor((Math.sin(angle) * 0.5 + 0.5) * 255);
|
|
63
|
+
noiseData[i * 4 + 2] = 0;
|
|
64
|
+
noiseData[i * 4 + 3] = 255;
|
|
65
|
+
}
|
|
66
|
+
const noiseTex = device.createTexture({
|
|
67
|
+
size: [4, 4],
|
|
68
|
+
format: 'rgba8unorm',
|
|
69
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
|
|
70
|
+
});
|
|
71
|
+
device.queue.writeTexture({ texture: noiseTex }, noiseData, { bytesPerRow: 16 }, [4, 4]);
|
|
72
|
+
const noiseSampler = device.createSampler({
|
|
73
|
+
magFilter: 'nearest',
|
|
74
|
+
minFilter: 'nearest',
|
|
75
|
+
addressModeU: 'repeat',
|
|
76
|
+
addressModeV: 'repeat',
|
|
77
|
+
});
|
|
78
|
+
this._noiseTexture = { texture: noiseTex, view: noiseTex.createView(), sampler: noiseSampler };
|
|
79
|
+
this._linearSampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' });
|
|
80
|
+
this._paramsData = new Float32Array(PARAMS_SIZE / 4);
|
|
81
|
+
this._paramsBuffer = device.createBuffer({
|
|
82
|
+
size: PARAMS_SIZE,
|
|
83
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
84
|
+
});
|
|
85
|
+
// SSAO bind group layout
|
|
86
|
+
this._ssaoBGL = device.createBindGroupLayout({
|
|
87
|
+
entries: [
|
|
88
|
+
{ binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'depth' } },
|
|
89
|
+
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
|
|
90
|
+
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
|
|
91
|
+
{ binding: 3, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
// Blur bind group layout
|
|
95
|
+
this._blurBGL = device.createBindGroupLayout({
|
|
96
|
+
entries: [
|
|
97
|
+
{ binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
|
|
98
|
+
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
|
|
99
|
+
],
|
|
100
|
+
});
|
|
101
|
+
const ssaoModule = device.createShaderModule({ code: SSAO_SHADER });
|
|
102
|
+
this._ssaoPipeline = device.createRenderPipeline({
|
|
103
|
+
layout: device.createPipelineLayout({ bindGroupLayouts: [this._ssaoBGL] }),
|
|
104
|
+
vertex: { module: ssaoModule, entryPoint: 'vs' },
|
|
105
|
+
fragment: { module: ssaoModule, entryPoint: 'fs', targets: [{ format: AO_FORMAT }] },
|
|
106
|
+
primitive: { topology: 'triangle-list' },
|
|
107
|
+
});
|
|
108
|
+
const blurModule = device.createShaderModule({ code: SSAO_BLUR_SHADER });
|
|
109
|
+
this._blurPipeline = device.createRenderPipeline({
|
|
110
|
+
layout: device.createPipelineLayout({ bindGroupLayouts: [this._blurBGL] }),
|
|
111
|
+
vertex: { module: blurModule, entryPoint: 'vs' },
|
|
112
|
+
fragment: { module: blurModule, entryPoint: 'fs', targets: [{ format: AO_FORMAT }] },
|
|
113
|
+
primitive: { topology: 'triangle-list' },
|
|
114
|
+
});
|
|
115
|
+
// 1x1 white fallback
|
|
116
|
+
this._whiteTexture = device.createTexture({
|
|
117
|
+
size: [1, 1], format: AO_FORMAT,
|
|
118
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
|
|
119
|
+
});
|
|
120
|
+
device.queue.writeTexture({ texture: this._whiteTexture }, new Uint8Array([255]), { bytesPerRow: 1 }, [1, 1]);
|
|
121
|
+
this._whiteView = this._whiteTexture.createView();
|
|
122
|
+
}
|
|
123
|
+
_ensureTextures(w, h) {
|
|
124
|
+
const hw = Math.max(1, Math.floor(w / 2));
|
|
125
|
+
const hh = Math.max(1, Math.floor(h / 2));
|
|
126
|
+
if (this._width === hw && this._height === hh)
|
|
127
|
+
return;
|
|
128
|
+
this._width = hw;
|
|
129
|
+
this._height = hh;
|
|
130
|
+
this._aoTexture?.destroy();
|
|
131
|
+
this._blurTexture?.destroy();
|
|
132
|
+
this._aoTexture = this._device.createTexture({
|
|
133
|
+
size: { width: hw, height: hh }, format: AO_FORMAT,
|
|
134
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
135
|
+
});
|
|
136
|
+
this._aoView = this._aoTexture.createView();
|
|
137
|
+
this._blurTexture = this._device.createTexture({
|
|
138
|
+
size: { width: hw, height: hh }, format: AO_FORMAT,
|
|
139
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
140
|
+
});
|
|
141
|
+
this._blurView = this._blurTexture.createView();
|
|
142
|
+
}
|
|
143
|
+
/** Execute SSAO. Returns AO texture view (white if disabled or no depth). */
|
|
144
|
+
execute(encoder, depthView, projMatrix, invProjMatrix, screenW, screenH) {
|
|
145
|
+
if (!this.enabled || !depthView)
|
|
146
|
+
return this._whiteView;
|
|
147
|
+
this._ensureTextures(screenW, screenH);
|
|
148
|
+
// Write params (reuse cached array to avoid per-frame allocation)
|
|
149
|
+
const data = this._paramsData;
|
|
150
|
+
data.set(invProjMatrix, 0); // offset 0: invProj
|
|
151
|
+
data.set(projMatrix, 16); // offset 16: proj
|
|
152
|
+
data[32] = this.radius;
|
|
153
|
+
data[33] = this.bias;
|
|
154
|
+
data[34] = this.intensity;
|
|
155
|
+
data[35] = 0;
|
|
156
|
+
data.set(this._kernel, 36); // offset 36: kernel[16]
|
|
157
|
+
this._device.queue.writeBuffer(this._paramsBuffer, 0, data);
|
|
158
|
+
// SSAO pass
|
|
159
|
+
const ssaoBG = this._device.createBindGroup({
|
|
160
|
+
layout: this._ssaoBGL,
|
|
161
|
+
entries: [
|
|
162
|
+
{ binding: 0, resource: depthView },
|
|
163
|
+
{ binding: 1, resource: this._noiseTexture.view },
|
|
164
|
+
{ binding: 2, resource: this._noiseTexture.sampler },
|
|
165
|
+
{ binding: 3, resource: { buffer: this._paramsBuffer } },
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
const ssaoPass = encoder.beginRenderPass({
|
|
169
|
+
colorAttachments: [{
|
|
170
|
+
view: this._aoView,
|
|
171
|
+
loadOp: 'clear', storeOp: 'store',
|
|
172
|
+
clearValue: { r: 1, g: 1, b: 1, a: 1 },
|
|
173
|
+
}],
|
|
174
|
+
});
|
|
175
|
+
ssaoPass.setPipeline(this._ssaoPipeline);
|
|
176
|
+
ssaoPass.setBindGroup(0, ssaoBG);
|
|
177
|
+
drawFullscreenTriangle(ssaoPass);
|
|
178
|
+
ssaoPass.end();
|
|
179
|
+
// Blur pass
|
|
180
|
+
const blurBG = this._device.createBindGroup({
|
|
181
|
+
layout: this._blurBGL,
|
|
182
|
+
entries: [
|
|
183
|
+
{ binding: 0, resource: this._aoView },
|
|
184
|
+
{ binding: 1, resource: this._linearSampler },
|
|
185
|
+
],
|
|
186
|
+
});
|
|
187
|
+
const blurPass = encoder.beginRenderPass({
|
|
188
|
+
colorAttachments: [{
|
|
189
|
+
view: this._blurView,
|
|
190
|
+
loadOp: 'clear', storeOp: 'store',
|
|
191
|
+
clearValue: { r: 1, g: 1, b: 1, a: 1 },
|
|
192
|
+
}],
|
|
193
|
+
});
|
|
194
|
+
blurPass.setPipeline(this._blurPipeline);
|
|
195
|
+
blurPass.setBindGroup(0, blurBG);
|
|
196
|
+
drawFullscreenTriangle(blurPass);
|
|
197
|
+
blurPass.end();
|
|
198
|
+
return this._blurView;
|
|
199
|
+
}
|
|
200
|
+
destroy() {
|
|
201
|
+
this._aoTexture?.destroy();
|
|
202
|
+
this._blurTexture?.destroy();
|
|
203
|
+
this._paramsBuffer.destroy();
|
|
204
|
+
this._whiteTexture.destroy();
|
|
205
|
+
this._noiseTexture.texture.destroy();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=ssao-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssao-pass.js","sourceRoot":"","sources":["../src/ssao-pass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WGSL shaders for Screen-Space Ambient Occlusion.
|
|
3
|
+
* SSAO pass: hemisphere sampling with depth-reconstructed normals.
|
|
4
|
+
* Blur pass: bilateral blur to smooth the noisy AO result.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SSAO_KERNEL_SIZE = 16;
|
|
7
|
+
export declare const SSAO_SHADER: string;
|
|
8
|
+
export declare const SSAO_BLUR_SHADER: string;
|
|
9
|
+
//# sourceMappingURL=ssao-shader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssao-shader.d.ts","sourceRoot":"","sources":["../src/ssao-shader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,eAAO,MAAM,WAAW,QAyFvB,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAqB5B,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WGSL shaders for Screen-Space Ambient Occlusion.
|
|
3
|
+
* SSAO pass: hemisphere sampling with depth-reconstructed normals.
|
|
4
|
+
* Blur pass: bilateral blur to smooth the noisy AO result.
|
|
5
|
+
*/
|
|
6
|
+
import { FULLSCREEN_VERTEX_SHADER } from './fullscreen-quad.js';
|
|
7
|
+
export const SSAO_KERNEL_SIZE = 16;
|
|
8
|
+
export const SSAO_SHADER = FULLSCREEN_VERTEX_SHADER + /* wgsl */ `
|
|
9
|
+
const KERNEL_SIZE: u32 = 16u;
|
|
10
|
+
|
|
11
|
+
struct SSAOParams {
|
|
12
|
+
invProj: mat4x4<f32>,
|
|
13
|
+
proj: mat4x4<f32>,
|
|
14
|
+
radius: f32,
|
|
15
|
+
bias: f32,
|
|
16
|
+
intensity: f32,
|
|
17
|
+
_pad: f32,
|
|
18
|
+
kernel: array<vec4<f32>, 16>,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
@group(0) @binding(0) var depthTexture: texture_depth_2d;
|
|
22
|
+
@group(0) @binding(1) var noiseTex: texture_2d<f32>;
|
|
23
|
+
@group(0) @binding(2) var noiseSampler: sampler;
|
|
24
|
+
@group(0) @binding(3) var<uniform> params: SSAOParams;
|
|
25
|
+
|
|
26
|
+
fn reconstructViewPos(uv: vec2<f32>, depth: f32) -> vec3<f32> {
|
|
27
|
+
let ndc = vec4(uv * 2.0 - 1.0, depth, 1.0);
|
|
28
|
+
let viewH = params.invProj * ndc;
|
|
29
|
+
return viewH.xyz / viewH.w;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fn sampleDepth(coord: vec2<i32>) -> f32 {
|
|
33
|
+
let dims = textureDimensions(depthTexture, 0);
|
|
34
|
+
let c = clamp(coord, vec2(0), vec2<i32>(dims) - vec2(1));
|
|
35
|
+
return textureLoad(depthTexture, c, 0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@fragment
|
|
39
|
+
fn fs(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
|
40
|
+
let dims = textureDimensions(depthTexture, 0);
|
|
41
|
+
let coord = vec2<i32>(uv * vec2<f32>(dims));
|
|
42
|
+
let depth = sampleDepth(coord);
|
|
43
|
+
|
|
44
|
+
// Noise for random kernel rotation (tile 4x4 noise over screen)
|
|
45
|
+
// Must be called before any non-uniform control flow (WGSL requirement)
|
|
46
|
+
let noiseScale = vec2<f32>(dims) / 4.0;
|
|
47
|
+
let rvec = textureSample(noiseTex, noiseSampler, uv * noiseScale).xyz * 2.0 - 1.0;
|
|
48
|
+
|
|
49
|
+
// Skip far plane (no early return to maintain uniform control flow)
|
|
50
|
+
let isSky = depth >= 1.0;
|
|
51
|
+
|
|
52
|
+
let posV = reconstructViewPos(uv, depth);
|
|
53
|
+
|
|
54
|
+
// Reconstruct view-space normal using smallest-depth-delta method
|
|
55
|
+
// to avoid dark-edge artifacts at triangle boundaries.
|
|
56
|
+
let texelX = 1.0 / f32(dims.x);
|
|
57
|
+
let texelY = 1.0 / f32(dims.y);
|
|
58
|
+
let posL = reconstructViewPos(uv + vec2(-texelX, 0.0), sampleDepth(coord + vec2(-1, 0)));
|
|
59
|
+
let posR = reconstructViewPos(uv + vec2( texelX, 0.0), sampleDepth(coord + vec2( 1, 0)));
|
|
60
|
+
let posB = reconstructViewPos(uv + vec2(0.0, -texelY), sampleDepth(coord + vec2(0, -1)));
|
|
61
|
+
let posT = reconstructViewPos(uv + vec2(0.0, texelY), sampleDepth(coord + vec2(0, 1)));
|
|
62
|
+
// Pick the derivative with the smaller depth discontinuity per axis
|
|
63
|
+
let dxL = posV - posL;
|
|
64
|
+
let dxR = posR - posV;
|
|
65
|
+
let dyB = posV - posB;
|
|
66
|
+
let dyT = posT - posV;
|
|
67
|
+
let dx = select(dxR, dxL, abs(dxL.z) < abs(dxR.z));
|
|
68
|
+
let dy = select(dyT, dyB, abs(dyB.z) < abs(dyT.z));
|
|
69
|
+
let normalV = normalize(cross(dx, dy));
|
|
70
|
+
|
|
71
|
+
// Gram-Schmidt to build TBN from normal + random vector
|
|
72
|
+
let tangent = normalize(rvec - normalV * dot(rvec, normalV));
|
|
73
|
+
let bitangent = cross(normalV, tangent);
|
|
74
|
+
let TBN = mat3x3(tangent, bitangent, normalV);
|
|
75
|
+
|
|
76
|
+
var occlusion = 0.0;
|
|
77
|
+
for (var i = 0u; i < KERNEL_SIZE; i = i + 1u) {
|
|
78
|
+
let sampleOffset = TBN * params.kernel[i].xyz;
|
|
79
|
+
let samplePos = posV + sampleOffset * params.radius;
|
|
80
|
+
|
|
81
|
+
let offset4 = params.proj * vec4(samplePos, 1.0);
|
|
82
|
+
let offsetUV = (offset4.xy / offset4.w) * 0.5 + 0.5;
|
|
83
|
+
|
|
84
|
+
let sampleCoord = vec2<i32>(offsetUV * vec2<f32>(dims));
|
|
85
|
+
let sampledDepth = sampleDepth(sampleCoord);
|
|
86
|
+
let samplePosZ = reconstructViewPos(offsetUV, sampledDepth).z;
|
|
87
|
+
|
|
88
|
+
let rangeCheck = smoothstep(0.0, 1.0, params.radius / abs(posV.z - samplePosZ));
|
|
89
|
+
let occluded = select(0.0, 1.0, samplePosZ >= samplePos.z + params.bias);
|
|
90
|
+
occlusion = occlusion + occluded * rangeCheck;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let ao = 1.0 - (occlusion / f32(KERNEL_SIZE)) * params.intensity;
|
|
94
|
+
let result = select(ao, 1.0, isSky);
|
|
95
|
+
return vec4(result, result, result, 1.0);
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
export const SSAO_BLUR_SHADER = FULLSCREEN_VERTEX_SHADER + /* wgsl */ `
|
|
99
|
+
@group(0) @binding(0) var aoTexture: texture_2d<f32>;
|
|
100
|
+
@group(0) @binding(1) var aoSampler: sampler;
|
|
101
|
+
|
|
102
|
+
@fragment
|
|
103
|
+
fn fs(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
|
104
|
+
let dims = vec2<f32>(textureDimensions(aoTexture, 0));
|
|
105
|
+
let texelSize = 1.0 / dims;
|
|
106
|
+
|
|
107
|
+
// 4x4 box blur
|
|
108
|
+
var result = 0.0;
|
|
109
|
+
for (var y: i32 = -2; y <= 1; y = y + 1) {
|
|
110
|
+
for (var x: i32 = -2; x <= 1; x = x + 1) {
|
|
111
|
+
let offset = vec2<f32>(f32(x) + 0.5, f32(y) + 0.5) * texelSize;
|
|
112
|
+
result = result + textureSample(aoTexture, aoSampler, uv + offset).r;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
result = result / 16.0;
|
|
116
|
+
|
|
117
|
+
return vec4(result, result, result, 1.0);
|
|
118
|
+
}
|
|
119
|
+
`;
|
|
120
|
+
//# sourceMappingURL=ssao-shader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssao-shader.js","sourceRoot":"","sources":["../src/ssao-shader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAEnC,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,GAAG,UAAU,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyF/D,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,wBAAwB,GAAG,UAAU,CAAA;;;;;;;;;;;;;;;;;;;;;CAqBpE,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TerrainMeshRenderer: MeshRenderer variant for terrain splat-map rendering.
|
|
3
|
+
*
|
|
4
|
+
* Uses the terrain pipeline (40B vertex stride) and binds 3 splat textures
|
|
5
|
+
* instead of the standard PBR albedo/normal/MR textures.
|
|
6
|
+
*/
|
|
7
|
+
import { Component } from '@certe/atmos-core';
|
|
8
|
+
import type { Mat4Type } from '@certe/atmos-math';
|
|
9
|
+
import type { Mesh } from './mesh.js';
|
|
10
|
+
import type { TerrainPipelineResources } from './terrain-pipeline.js';
|
|
11
|
+
import type { Material } from './material.js';
|
|
12
|
+
import type { GPUTextureHandle } from './texture.js';
|
|
13
|
+
import type { BoundingSphere } from './bounds.js';
|
|
14
|
+
export declare class TerrainMeshRenderer extends Component {
|
|
15
|
+
mesh: Mesh | null;
|
|
16
|
+
material: Material | null;
|
|
17
|
+
castShadow: boolean;
|
|
18
|
+
receiveSSAO: boolean;
|
|
19
|
+
splatTextures: [GPUTextureHandle, GPUTextureHandle, GPUTextureHandle] | null;
|
|
20
|
+
uniformBuffer: GPUBuffer | null;
|
|
21
|
+
bindGroup: GPUBindGroup | null;
|
|
22
|
+
materialBindGroup: GPUBindGroup | null;
|
|
23
|
+
private _device;
|
|
24
|
+
private _terrainPipeline;
|
|
25
|
+
private readonly _mvp;
|
|
26
|
+
private readonly _invModel;
|
|
27
|
+
private readonly _normalMat;
|
|
28
|
+
private readonly _matData;
|
|
29
|
+
private readonly _worldBoundsCenter;
|
|
30
|
+
private readonly _worldBounds;
|
|
31
|
+
init(device: GPUDevice, terrainPipeline: TerrainPipelineResources, mesh: Mesh, material?: Material, splatTextures?: [GPUTextureHandle, GPUTextureHandle, GPUTextureHandle]): void;
|
|
32
|
+
initMaterialBindGroup(sceneBuffer: GPUBuffer): void;
|
|
33
|
+
writeUniforms(viewProjection: Mat4Type): void;
|
|
34
|
+
draw(pass: GPURenderPassEncoder): void;
|
|
35
|
+
get worldBoundingSphere(): BoundingSphere | null;
|
|
36
|
+
onDestroy(): void;
|
|
37
|
+
destroyMesh(): void;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=terrain-mesh-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terrain-mesh-renderer.d.ts","sourceRoot":"","sources":["../src/terrain-mesh-renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,qBAAa,mBAAoB,SAAQ,SAAS;IAChD,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IACzB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IACjC,UAAU,UAAQ;IAClB,WAAW,UAAS;IACpB,aAAa,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,GAAG,IAAI,CAAQ;IAEpF,aAAa,EAAE,SAAS,GAAG,IAAI,CAAQ;IACvC,SAAS,EAAE,YAAY,GAAG,IAAI,CAAQ;IACtC,iBAAiB,EAAE,YAAY,GAAG,IAAI,CAAQ;IAE9C,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,gBAAgB,CAAyC;IAEjE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+C;IAExE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAuB;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkE;IAE/F,IAAI,CACF,MAAM,EAAE,SAAS,EACjB,eAAe,EAAE,wBAAwB,EACzC,IAAI,EAAE,IAAI,EACV,QAAQ,CAAC,EAAE,QAAQ,EACnB,aAAa,CAAC,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,GACrE,IAAI;IAoBP,qBAAqB,CAAC,WAAW,EAAE,SAAS,GAAG,IAAI;IA8BnD,aAAa,CAAC,cAAc,EAAE,QAAQ,GAAG,IAAI;IAmB7C,IAAI,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;IAUtC,IAAI,mBAAmB,IAAI,cAAc,GAAG,IAAI,CAkB/C;IAED,SAAS,IAAI,IAAI;IAOjB,WAAW,IAAI,IAAI;CAOpB"}
|