@luma.gl/shaders 10.0.0-alpha.10 → 10.0.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/dist.dev.js +1923 -60
  2. package/dist/dist.min.js +1499 -148
  3. package/dist/glsl.cjs.map +1 -1
  4. package/dist/index.cjs +41 -0
  5. package/dist/index.cjs.map +3 -3
  6. package/dist/index.d.ts +20 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +11 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.cjs +40 -0
  11. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.d.ts +6 -0
  12. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.d.ts.map +1 -0
  13. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.js +15 -0
  14. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.js.map +1 -0
  15. package/dist/modules/lighting/contact-shadow/contact-shadow.cjs +348 -0
  16. package/dist/modules/lighting/contact-shadow/contact-shadow.d.ts +188 -0
  17. package/dist/modules/lighting/contact-shadow/contact-shadow.d.ts.map +1 -0
  18. package/dist/modules/lighting/contact-shadow/contact-shadow.js +307 -0
  19. package/dist/modules/lighting/contact-shadow/contact-shadow.js.map +1 -0
  20. package/dist/modules/lighting/lightmap/lightmap-filter.cjs +93 -0
  21. package/dist/modules/lighting/lightmap/lightmap-filter.d.ts +35 -0
  22. package/dist/modules/lighting/lightmap/lightmap-filter.d.ts.map +1 -0
  23. package/dist/modules/lighting/lightmap/lightmap-filter.js +71 -0
  24. package/dist/modules/lighting/lightmap/lightmap-filter.js.map +1 -0
  25. package/dist/modules/lighting/lightmap/lightmap.cjs +89 -0
  26. package/dist/modules/lighting/lightmap/lightmap.d.ts +405 -0
  27. package/dist/modules/lighting/lightmap/lightmap.d.ts.map +1 -0
  28. package/dist/modules/lighting/lightmap/lightmap.js +67 -0
  29. package/dist/modules/lighting/lightmap/lightmap.js.map +1 -0
  30. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.cjs +87 -0
  31. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.d.ts +21 -0
  32. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.d.ts.map +1 -0
  33. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.js +61 -0
  34. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.js.map +1 -0
  35. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.cjs +87 -0
  36. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.d.ts +21 -0
  37. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.d.ts.map +1 -0
  38. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.js +61 -0
  39. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.js.map +1 -0
  40. package/dist/modules/lighting/pbr-material/pbr-material-glsl.cjs +33 -11
  41. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +2 -2
  42. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
  43. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +33 -11
  44. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js.map +1 -1
  45. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.cjs +33 -11
  46. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +1 -1
  47. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
  48. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +33 -11
  49. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
  50. package/dist/modules/lighting/pbr-material/pbr-material.d.ts +3 -3
  51. package/dist/modules/lighting/pbr-shadow/pbr-shadow.cjs +97 -0
  52. package/dist/modules/lighting/pbr-shadow/pbr-shadow.d.ts +15 -0
  53. package/dist/modules/lighting/pbr-shadow/pbr-shadow.d.ts.map +1 -0
  54. package/dist/modules/lighting/pbr-shadow/pbr-shadow.js +69 -0
  55. package/dist/modules/lighting/pbr-shadow/pbr-shadow.js.map +1 -0
  56. package/dist/modules/lighting/pbr-surface/pbr-surface.cjs +114 -0
  57. package/dist/modules/lighting/pbr-surface/pbr-surface.d.ts +15 -0
  58. package/dist/modules/lighting/pbr-surface/pbr-surface.d.ts.map +1 -0
  59. package/dist/modules/lighting/pbr-surface/pbr-surface.js +88 -0
  60. package/dist/modules/lighting/pbr-surface/pbr-surface.js.map +1 -0
  61. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.cjs +379 -0
  62. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.d.ts +41 -0
  63. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.d.ts.map +1 -0
  64. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.js +345 -0
  65. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.js.map +1 -0
  66. package/dist/modules/lighting/shadow/shadow-glsl.cjs +228 -0
  67. package/dist/modules/lighting/shadow/shadow-glsl.d.ts +3 -0
  68. package/dist/modules/lighting/shadow/shadow-glsl.d.ts.map +1 -0
  69. package/dist/modules/lighting/shadow/shadow-glsl.js +204 -0
  70. package/dist/modules/lighting/shadow/shadow-glsl.js.map +1 -0
  71. package/dist/modules/lighting/shadow/shadow-types.cjs +15 -0
  72. package/dist/modules/lighting/shadow/shadow-types.d.ts +63 -0
  73. package/dist/modules/lighting/shadow/shadow-types.d.ts.map +1 -0
  74. package/dist/modules/lighting/shadow/shadow-types.js +5 -0
  75. package/dist/modules/lighting/shadow/shadow-types.js.map +1 -0
  76. package/dist/modules/lighting/shadow/shadow.cjs +458 -0
  77. package/dist/modules/lighting/shadow/shadow.d.ts +117 -0
  78. package/dist/modules/lighting/shadow/shadow.d.ts.map +1 -0
  79. package/dist/modules/lighting/shadow/shadow.js +450 -0
  80. package/dist/modules/lighting/shadow/shadow.js.map +1 -0
  81. package/dist/modules/lighting/unlit-material/unlit-material.cjs +60 -0
  82. package/dist/modules/lighting/unlit-material/unlit-material.d.ts +9 -0
  83. package/dist/modules/lighting/unlit-material/unlit-material.d.ts.map +1 -0
  84. package/dist/modules/lighting/unlit-material/unlit-material.js +40 -0
  85. package/dist/modules/lighting/unlit-material/unlit-material.js.map +1 -0
  86. package/dist/types/shader-type-decoder.cjs +12 -2
  87. package/dist/types/shader-type-decoder.d.ts +7 -7
  88. package/dist/types/shader-type-decoder.d.ts.map +1 -1
  89. package/dist/types/shader-type-decoder.js +13 -2
  90. package/dist/types/shader-type-decoder.js.map +1 -1
  91. package/dist/types.cjs.map +1 -1
  92. package/dist/wgsl.cjs.map +1 -1
  93. package/package.json +3 -3
  94. package/src/index.ts +52 -0
  95. package/src/modules/lighting/clustered-light-grid/clustered-light-grid.ts +17 -0
  96. package/src/modules/lighting/contact-shadow/contact-shadow.ts +365 -0
  97. package/src/modules/lighting/lightmap/lightmap-filter.ts +73 -0
  98. package/src/modules/lighting/lightmap/lightmap.ts +76 -0
  99. package/src/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.ts +78 -0
  100. package/src/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.ts +78 -0
  101. package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +33 -11
  102. package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +33 -11
  103. package/src/modules/lighting/pbr-shadow/pbr-shadow.ts +85 -0
  104. package/src/modules/lighting/pbr-surface/pbr-surface.ts +103 -0
  105. package/src/modules/lighting/prefiltered-environment/prefiltered-environment.ts +370 -0
  106. package/src/modules/lighting/shadow/shadow-glsl.ts +204 -0
  107. package/src/modules/lighting/shadow/shadow-types.ts +68 -0
  108. package/src/modules/lighting/shadow/shadow.ts +536 -0
  109. package/src/modules/lighting/unlit-material/unlit-material.ts +44 -0
  110. package/src/types/shader-type-decoder.ts +22 -9
@@ -0,0 +1,365 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+
5
+ import type {NumberArray3, NumberArray16} from '@math.gl/core';
6
+ import type {ShaderPass} from '../../../lib/shader-module/shader-pass';
7
+
8
+ const IDENTITY_MATRIX: NumberArray16 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
9
+
10
+ export type ContactShadowBindings<TextureT = unknown> = {
11
+ depthTexture?: TextureT;
12
+ normalTexture?: TextureT;
13
+ };
14
+
15
+ export type ContactTraceUniforms = {
16
+ projectionMatrix: Readonly<NumberArray16>;
17
+ inverseProjectionMatrix: Readonly<NumberArray16>;
18
+ lightDirectionView: Readonly<NumberArray3>;
19
+ maxDistance: number;
20
+ thickness: number;
21
+ stepCount: number;
22
+ frameIndex: number;
23
+ normalBias: number;
24
+ };
25
+
26
+ /** Runtime controls accepted by the contact-shadow trace and composite passes. */
27
+ export type ContactShadowProps<TextureT = unknown> = Partial<ContactTraceUniforms> & {
28
+ strength?: number;
29
+ debugMode?: number;
30
+ directionalDirectTexture?: TextureT;
31
+ shadowDebugTexture?: TextureT;
32
+ };
33
+
34
+ export const contactShadowTrace = {
35
+ name: 'contactShadowTrace',
36
+ source: /* wgsl */ `\
37
+ struct contactShadowTraceUniforms {
38
+ projectionMatrix: mat4x4f,
39
+ inverseProjectionMatrix: mat4x4f,
40
+ lightDirectionView: vec3f,
41
+ maxDistance: f32,
42
+ thickness: f32,
43
+ stepCount: f32,
44
+ frameIndex: f32,
45
+ normalBias: f32,
46
+ };
47
+ @group(0) @binding(auto) var<uniform> contactShadowTrace: contactShadowTraceUniforms;
48
+ @group(0) @binding(auto) var depthTexture: texture_depth_2d;
49
+ @group(0) @binding(auto) var depthTextureSampler: sampler;
50
+ @group(0) @binding(auto) var normalTexture: texture_2d<f32>;
51
+ @group(0) @binding(auto) var normalTextureSampler: sampler;
52
+
53
+ fn contactShadow_reconstructViewPosition(uv: vec2f, depth: f32) -> vec3f {
54
+ let clip = vec4f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, depth, 1.0);
55
+ let view = contactShadowTrace.inverseProjectionMatrix * clip;
56
+ return view.xyz / max(abs(view.w), 0.00001);
57
+ }
58
+
59
+ fn contactShadow_projectViewPosition(position: vec3f) -> vec2f {
60
+ let clip = contactShadowTrace.projectionMatrix * vec4f(position, 1.0);
61
+ let ndc = clip.xy / max(abs(clip.w), 0.00001);
62
+ return vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
63
+ }
64
+
65
+ fn contactShadowTrace_sampleColor(
66
+ sourceTexture: texture_2d<f32>, sourceTextureSampler: sampler, texSize: vec2f, texCoord: vec2f
67
+ ) -> vec4f {
68
+ let centerDepth = textureSampleLevel(depthTexture, depthTextureSampler, texCoord, 0);
69
+ if (centerDepth >= 0.99999) { return vec4f(1.0); }
70
+ let centerNormal = normalize(textureSampleLevel(normalTexture, normalTextureSampler, texCoord, 0.0).xyz * 2.0 - 1.0);
71
+ let centerPosition = contactShadow_reconstructViewPosition(texCoord, centerDepth) + centerNormal * contactShadowTrace.normalBias;
72
+ let rayDirection = normalize(contactShadowTrace.lightDirectionView);
73
+ let noise = fract(sin(dot(texCoord * texSize + contactShadowTrace.frameIndex, vec2f(12.9898, 78.233))) * 43758.5453);
74
+ for (var index: i32 = 0; index < 40; index++) {
75
+ if (f32(index) >= contactShadowTrace.stepCount) { break; }
76
+ let fraction = (f32(index) + 0.35 + noise * 0.5) / max(contactShadowTrace.stepCount, 1.0);
77
+ let travel = contactShadowTrace.maxDistance * fraction * fraction;
78
+ let rayPosition = centerPosition + rayDirection * travel;
79
+ let sampleUv = contactShadow_projectViewPosition(rayPosition);
80
+ if (any(sampleUv <= vec2f(0.0)) || any(sampleUv >= vec2f(1.0))) { break; }
81
+ let sampleDepth = textureSampleLevel(depthTexture, depthTextureSampler, sampleUv, 0);
82
+ if (sampleDepth >= 0.99999) { continue; }
83
+ let scenePosition = contactShadow_reconstructViewPosition(sampleUv, sampleDepth);
84
+ let depthDelta = (-rayPosition.z) - (-scenePosition.z);
85
+ let hitThickness = contactShadowTrace.thickness + travel * 0.02;
86
+ if (depthDelta >= 0.0 && depthDelta <= hitThickness) {
87
+ let distanceFade = 1.0 - clamp(travel / contactShadowTrace.maxDistance, 0.0, 1.0);
88
+ return vec4f(vec3f(1.0 - distanceFade), 1.0);
89
+ }
90
+ if (depthDelta > hitThickness * 8.0) { break; }
91
+ }
92
+ return vec4f(1.0);
93
+ }`,
94
+ fs: /* glsl */ `
95
+ layout(std140) uniform contactShadowTraceUniforms {
96
+ mat4 projectionMatrix;
97
+ mat4 inverseProjectionMatrix;
98
+ vec3 lightDirectionView;
99
+ float maxDistance;
100
+ float thickness;
101
+ float stepCount;
102
+ float frameIndex;
103
+ float normalBias;
104
+ } contactShadowTrace;
105
+ uniform sampler2D depthTexture;
106
+ uniform sampler2D normalTexture;
107
+ vec3 contactShadow_reconstructViewPosition(vec2 uv, float depth) {
108
+ vec4 view = contactShadowTrace.inverseProjectionMatrix * vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
109
+ return view.xyz / max(abs(view.w), 0.00001);
110
+ }
111
+ vec2 contactShadow_projectViewPosition(vec3 position) {
112
+ vec4 clip = contactShadowTrace.projectionMatrix * vec4(position,1.0);
113
+ return clip.xy / max(abs(clip.w),0.00001) * 0.5 + 0.5;
114
+ }
115
+ vec4 contactShadowTrace_sampleColor(sampler2D sourceTexture,vec2 texSize,vec2 texCoord) {
116
+ float centerDepth = texture(depthTexture,texCoord).r;
117
+ if(centerDepth >= 0.99999) return vec4(1.0);
118
+ vec3 centerNormal = normalize(texture(normalTexture,texCoord).xyz * 2.0 - 1.0);
119
+ vec3 centerPosition = contactShadow_reconstructViewPosition(texCoord,centerDepth) + centerNormal * contactShadowTrace.normalBias;
120
+ vec3 rayDirection = normalize(contactShadowTrace.lightDirectionView);
121
+ float noise = fract(sin(dot(texCoord * texSize + contactShadowTrace.frameIndex,vec2(12.9898,78.233))) * 43758.5453);
122
+ for(int index=0;index<40;index++) {
123
+ if(float(index)>=contactShadowTrace.stepCount) break;
124
+ float fraction=(float(index)+0.35+noise*0.5)/max(contactShadowTrace.stepCount,1.0);
125
+ float travel=contactShadowTrace.maxDistance*fraction*fraction;
126
+ vec3 rayPosition=centerPosition+rayDirection*travel;
127
+ vec2 sampleUv=contactShadow_projectViewPosition(rayPosition);
128
+ if(any(lessThanEqual(sampleUv,vec2(0.0)))||any(greaterThanEqual(sampleUv,vec2(1.0))))break;
129
+ float sampleDepth=texture(depthTexture,sampleUv).r;
130
+ if(sampleDepth>=0.99999)continue;
131
+ vec3 scenePosition=contactShadow_reconstructViewPosition(sampleUv,sampleDepth);
132
+ float depthDelta=(-rayPosition.z)-(-scenePosition.z);
133
+ float hitThickness=contactShadowTrace.thickness+travel*0.02;
134
+ if(depthDelta>=0.0&&depthDelta<=hitThickness) {
135
+ float distanceFade=1.0-clamp(travel/contactShadowTrace.maxDistance,0.0,1.0);
136
+ return vec4(vec3(1.0-distanceFade),1.0);
137
+ }
138
+ if(depthDelta>hitThickness*8.0)break;
139
+ }
140
+ return vec4(1.0);
141
+ }
142
+ `,
143
+ bindingLayout: [
144
+ {name: 'depthTexture', group: 0},
145
+ {name: 'normalTexture', group: 0}
146
+ ],
147
+ props: {} as Partial<ContactTraceUniforms> & ContactShadowBindings,
148
+ uniforms: {} as ContactTraceUniforms,
149
+ bindings: {} as ContactShadowBindings,
150
+ uniformTypes: {
151
+ projectionMatrix: 'mat4x4<f32>',
152
+ inverseProjectionMatrix: 'mat4x4<f32>',
153
+ lightDirectionView: 'vec3<f32>',
154
+ maxDistance: 'f32',
155
+ thickness: 'f32',
156
+ stepCount: 'f32',
157
+ frameIndex: 'f32',
158
+ normalBias: 'f32'
159
+ },
160
+ propTypes: {
161
+ projectionMatrix: {value: IDENTITY_MATRIX, private: true},
162
+ inverseProjectionMatrix: {value: IDENTITY_MATRIX, private: true},
163
+ lightDirectionView: {value: [0, 1, 0], private: true},
164
+ maxDistance: {value: 4, min: 0.1, softMax: 16},
165
+ thickness: {value: 0.12, min: 0.005, softMax: 1},
166
+ stepCount: {value: 24, min: 1, max: 40},
167
+ frameIndex: {value: 0, private: true},
168
+ normalBias: {value: 0.035, min: 0, softMax: 0.2}
169
+ },
170
+ passes: [{sampler: true}]
171
+ } as const satisfies ShaderPass<
172
+ Partial<ContactTraceUniforms> & ContactShadowBindings,
173
+ ContactTraceUniforms,
174
+ ContactShadowBindings
175
+ >;
176
+
177
+ export type ContactBlurUniforms = {
178
+ direction: [number, number];
179
+ radius: number;
180
+ depthSigma: number;
181
+ normalPower: number;
182
+ };
183
+
184
+ export const contactShadowBilateralBlur = {
185
+ name: 'contactShadowBilateralBlur',
186
+ source: /* wgsl */ `\
187
+ struct contactShadowBilateralBlurUniforms {
188
+ direction: vec2f,
189
+ radius: f32,
190
+ depthSigma: f32,
191
+ normalPower: f32,
192
+ };
193
+ @group(0) @binding(auto) var<uniform> contactShadowBilateralBlur: contactShadowBilateralBlurUniforms;
194
+ @group(0) @binding(auto) var depthTexture: texture_depth_2d;
195
+ @group(0) @binding(auto) var depthTextureSampler: sampler;
196
+ @group(0) @binding(auto) var normalTexture: texture_2d<f32>;
197
+ @group(0) @binding(auto) var normalTextureSampler: sampler;
198
+
199
+ fn contactShadowBilateralBlur_sampleColor(
200
+ sourceTexture: texture_2d<f32>, sourceTextureSampler: sampler, texSize: vec2f, texCoord: vec2f
201
+ ) -> vec4f {
202
+ let sourceDimensions = vec2f(textureDimensions(sourceTexture));
203
+ let texel = contactShadowBilateralBlur.direction / sourceDimensions;
204
+ let centerDepth = textureSampleLevel(depthTexture, depthTextureSampler, texCoord, 0);
205
+ let centerNormal = normalize(textureSampleLevel(normalTexture, normalTextureSampler, texCoord, 0.0).xyz * 2.0 - 1.0);
206
+ var result = textureSampleLevel(sourceTexture, sourceTextureSampler, texCoord, 0.0).r;
207
+ var totalWeight = 1.0;
208
+ for (var index: i32 = 1; index <= 6; index++) {
209
+ if (f32(index) > contactShadowBilateralBlur.radius) { break; }
210
+ for (var side: i32 = -1; side <= 1; side += 2) {
211
+ let sampleUv = clamp(texCoord + texel * f32(index * side), vec2f(0.0), vec2f(1.0));
212
+ let sampleDepth = textureSampleLevel(depthTexture, depthTextureSampler, sampleUv, 0);
213
+ let sampleNormal = normalize(textureSampleLevel(normalTexture, normalTextureSampler, sampleUv, 0.0).xyz * 2.0 - 1.0);
214
+ let depthDelta = abs(sampleDepth - centerDepth);
215
+ let depthWeight = exp(-(depthDelta * depthDelta) / max(2.0 * contactShadowBilateralBlur.depthSigma * contactShadowBilateralBlur.depthSigma, 0.000001));
216
+ let normalWeight = pow(max(dot(centerNormal, sampleNormal), 0.0), contactShadowBilateralBlur.normalPower);
217
+ let spatialWeight = exp(-f32(index * index) / 8.0);
218
+ let weight = depthWeight * normalWeight * spatialWeight;
219
+ result += textureSampleLevel(sourceTexture, sourceTextureSampler, sampleUv, 0.0).r * weight;
220
+ totalWeight += weight;
221
+ }
222
+ }
223
+ let visibility = result / totalWeight;
224
+ return vec4f(vec3f(visibility), 1.0);
225
+ }`,
226
+ fs: /* glsl */ `
227
+ layout(std140) uniform contactShadowBilateralBlurUniforms {
228
+ vec2 direction;
229
+ float radius;
230
+ float depthSigma;
231
+ float normalPower;
232
+ } contactShadowBilateralBlur;
233
+ uniform sampler2D depthTexture;
234
+ uniform sampler2D normalTexture;
235
+ vec4 contactShadowBilateralBlur_sampleColor(sampler2D sourceTexture,vec2 texSize,vec2 texCoord) {
236
+ vec2 texel=contactShadowBilateralBlur.direction/vec2(textureSize(sourceTexture,0));
237
+ float centerDepth=texture(depthTexture,texCoord).r;
238
+ vec3 centerNormal=normalize(texture(normalTexture,texCoord).xyz*2.0-1.0);
239
+ float result=texture(sourceTexture,texCoord).r;
240
+ float totalWeight=1.0;
241
+ for(int index=1;index<=6;index++) {
242
+ if(float(index)>contactShadowBilateralBlur.radius)break;
243
+ for(int side=-1;side<=1;side+=2) {
244
+ vec2 sampleUv=clamp(texCoord+texel*float(index*side),vec2(0.0),vec2(1.0));
245
+ float sampleDepth=texture(depthTexture,sampleUv).r;
246
+ vec3 sampleNormal=normalize(texture(normalTexture,sampleUv).xyz*2.0-1.0);
247
+ float depthDelta=abs(sampleDepth-centerDepth);
248
+ float depthWeight=exp(-(depthDelta*depthDelta)/max(2.0*contactShadowBilateralBlur.depthSigma*contactShadowBilateralBlur.depthSigma,0.000001));
249
+ float normalWeight=pow(max(dot(centerNormal,sampleNormal),0.0),contactShadowBilateralBlur.normalPower);
250
+ float spatialWeight=exp(-float(index*index)/8.0);
251
+ float weight=depthWeight*normalWeight*spatialWeight;
252
+ result+=texture(sourceTexture,sampleUv).r*weight;totalWeight+=weight;
253
+ }
254
+ }
255
+ return vec4(vec3(result/totalWeight),1.0);
256
+ }
257
+ `,
258
+ bindingLayout: [
259
+ {name: 'depthTexture', group: 0},
260
+ {name: 'normalTexture', group: 0}
261
+ ],
262
+ props: {} as Partial<ContactBlurUniforms> & ContactShadowBindings,
263
+ uniforms: {} as ContactBlurUniforms,
264
+ bindings: {} as ContactShadowBindings,
265
+ uniformTypes: {
266
+ direction: 'vec2<f32>',
267
+ radius: 'f32',
268
+ depthSigma: 'f32',
269
+ normalPower: 'f32'
270
+ },
271
+ propTypes: {
272
+ direction: {value: [1, 0], private: true},
273
+ radius: {value: 4, min: 1, max: 6},
274
+ depthSigma: {value: 0.006, min: 0.0001, softMax: 0.05},
275
+ normalPower: {value: 24, min: 1, softMax: 64}
276
+ },
277
+ passes: [{sampler: true}]
278
+ } as const satisfies ShaderPass<
279
+ Partial<ContactBlurUniforms> & ContactShadowBindings,
280
+ ContactBlurUniforms,
281
+ ContactShadowBindings
282
+ >;
283
+
284
+ export type ContactCompositeBindings<TextureT = unknown> = {
285
+ contactShadowTexture?: TextureT;
286
+ directionalDirectTexture?: TextureT;
287
+ shadowDebugTexture?: TextureT;
288
+ };
289
+
290
+ type ContactCompositeUniforms = {strength: number; debugMode: number};
291
+
292
+ export const contactShadowComposite = {
293
+ name: 'contactShadowComposite',
294
+ source: /* wgsl */ `\
295
+ struct contactShadowCompositeUniforms {
296
+ strength: f32,
297
+ debugMode: f32,
298
+ };
299
+ @group(0) @binding(auto) var<uniform> contactShadowComposite: contactShadowCompositeUniforms;
300
+ @group(0) @binding(auto) var contactShadowTexture: texture_2d<f32>;
301
+ @group(0) @binding(auto) var contactShadowTextureSampler: sampler;
302
+ @group(0) @binding(auto) var directionalDirectTexture: texture_2d<f32>;
303
+ @group(0) @binding(auto) var directionalDirectTextureSampler: sampler;
304
+ @group(0) @binding(auto) var shadowDebugTexture: texture_2d<f32>;
305
+ @group(0) @binding(auto) var shadowDebugTextureSampler: sampler;
306
+
307
+ fn contactShadowComposite_sampleColor(
308
+ sourceTexture: texture_2d<f32>, sourceTextureSampler: sampler, texSize: vec2f, texCoord: vec2f
309
+ ) -> vec4f {
310
+ let color = textureSampleLevel(sourceTexture, sourceTextureSampler, texCoord, 0.0);
311
+ let contact = textureSampleLevel(contactShadowTexture, contactShadowTextureSampler, texCoord, 0.0).r;
312
+ let appliedContact = mix(1.0, contact, contactShadowComposite.strength);
313
+ if (contactShadowComposite.debugMode > 0.5 && contactShadowComposite.debugMode < 1.5) {
314
+ return vec4f(vec3f(contact), 1.0);
315
+ }
316
+ if (contactShadowComposite.debugMode >= 1.5) {
317
+ let factors = textureSampleLevel(shadowDebugTexture, shadowDebugTextureSampler, texCoord, 0.0).rgb;
318
+ return vec4f(vec3f(factors.x * factors.y * factors.z * contact), 1.0);
319
+ }
320
+ let directionalDirect = textureSampleLevel(
321
+ directionalDirectTexture,
322
+ directionalDirectTextureSampler,
323
+ texCoord,
324
+ 0.0
325
+ ).rgb;
326
+ return vec4f(max(color.rgb - directionalDirect * (1.0 - appliedContact), vec3f(0.0)), color.a);
327
+ }`,
328
+ fs: /* glsl */ `
329
+ layout(std140) uniform contactShadowCompositeUniforms {
330
+ float strength;
331
+ float debugMode;
332
+ } contactShadowComposite;
333
+ uniform sampler2D contactShadowTexture;
334
+ uniform sampler2D directionalDirectTexture;
335
+ uniform sampler2D shadowDebugTexture;
336
+ vec4 contactShadowComposite_sampleColor(sampler2D sourceTexture,vec2 texSize,vec2 texCoord) {
337
+ vec4 color=texture(sourceTexture,texCoord);
338
+ float contact=texture(contactShadowTexture,texCoord).r;
339
+ float appliedContact=mix(1.0,contact,contactShadowComposite.strength);
340
+ if(contactShadowComposite.debugMode>0.5&&contactShadowComposite.debugMode<1.5)return vec4(vec3(contact),1.0);
341
+ if(contactShadowComposite.debugMode>=1.5){vec3 factors=texture(shadowDebugTexture,texCoord).rgb;return vec4(vec3(factors.x*factors.y*factors.z*contact),1.0);}
342
+ vec3 directionalDirect=texture(directionalDirectTexture,texCoord).rgb;
343
+ return vec4(max(color.rgb-directionalDirect*(1.0-appliedContact),vec3(0.0)),color.a);
344
+ }
345
+ `,
346
+ bindingLayout: [
347
+ {name: 'contactShadowTexture', group: 0},
348
+ {name: 'directionalDirectTexture', group: 0},
349
+ {name: 'shadowDebugTexture', group: 0}
350
+ ],
351
+ props: {} as Partial<ContactCompositeUniforms> & ContactCompositeBindings,
352
+ uniforms: {} as ContactCompositeUniforms,
353
+ bindings: {} as ContactCompositeBindings,
354
+ uniformTypes: {strength: 'f32', debugMode: 'f32'},
355
+ propTypes: {
356
+ strength: {value: 1, min: 0, max: 1},
357
+ debugMode: {value: 0, min: 0, max: 2, private: true}
358
+ },
359
+ passes: [{sampler: true}]
360
+ } as const satisfies ShaderPass<
361
+ Partial<ContactCompositeUniforms> & ContactCompositeBindings,
362
+ ContactCompositeUniforms,
363
+ ContactCompositeBindings,
364
+ 'contactShadowFiltered'
365
+ >;
@@ -0,0 +1,73 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
3
+
4
+ import type {ShaderModule} from '../../../lib/shader-module/shader-module';
5
+
6
+ /** Internal accumulation/copy/dilation shader shared by the engine baker. */
7
+ export const lightmapFilter = {
8
+ name: 'lightmapFilter',
9
+ bindingLayout: [
10
+ {name: 'lightmapFilter', group: 0},
11
+ {name: 'currentTexture', group: 0},
12
+ {name: 'previousTexture', group: 0},
13
+ {name: 'chartTexture', group: 0}
14
+ ],
15
+ uniformTypes: {weight: 'f32', mode: 'i32'},
16
+ defaultUniforms: {weight: 1, mode: 0},
17
+ getUniforms: (props: {weight?: number; mode?: number}) => props,
18
+ source: `
19
+ struct LightmapFilterUniforms {weight: f32, mode: i32};
20
+ @group(0) @binding(auto) var<uniform> lightmapFilter: LightmapFilterUniforms;
21
+ @group(0) @binding(auto) var currentTexture: texture_2d<f32>;
22
+ @group(0) @binding(auto) var previousTexture: texture_2d<f32>;
23
+ @group(0) @binding(auto) var chartTexture: texture_2d<f32>;
24
+ fn lightmapFilter_getColor(coordinates: vec2i) -> vec4f {
25
+ let current = textureLoad(currentTexture, coordinates, 0);
26
+ if (lightmapFilter.mode == 0) {
27
+ let previous = textureLoad(previousTexture, coordinates, 0);
28
+ return vec4f(mix(previous.rgb, current.rgb, lightmapFilter.weight), current.a);
29
+ }
30
+ if (lightmapFilter.mode == 2 || current.a > 0.0) {return current;}
31
+ let chart = textureLoad(chartTexture, coordinates, 0).r;
32
+ if (chart <= 0.0) {return current;}
33
+ let size = vec2i(textureDimensions(currentTexture));
34
+ for (var y = -1; y <= 1; y++) {
35
+ for (var x = -1; x <= 1; x++) {
36
+ let neighbor = coordinates + vec2i(x, y);
37
+ if (all(neighbor >= vec2i(0)) && all(neighbor < size)) {
38
+ let candidate = textureLoad(currentTexture, neighbor, 0);
39
+ if (candidate.a == chart) {return candidate;}
40
+ }
41
+ }
42
+ }
43
+ return current;
44
+ }`,
45
+ fs: `
46
+ layout(std140) uniform lightmapFilterUniforms {
47
+ float weight;
48
+ int mode;
49
+ } lightmapFilter;
50
+ uniform sampler2D currentTexture;
51
+ uniform sampler2D previousTexture;
52
+ uniform sampler2D chartTexture;
53
+ vec4 lightmapFilter_getColor(ivec2 coordinates) {
54
+ vec4 current = texelFetch(currentTexture, coordinates, 0);
55
+ if (lightmapFilter.mode == 0) {
56
+ return vec4(mix(texelFetch(previousTexture, coordinates, 0).rgb, current.rgb, lightmapFilter.weight), current.a);
57
+ }
58
+ if (lightmapFilter.mode == 2 || current.a > 0.0) {return current;}
59
+ float chart = texelFetch(chartTexture, coordinates, 0).r;
60
+ ivec2 size = textureSize(currentTexture, 0);
61
+ if (chart <= 0.0) return current;
62
+ for (int y = -1; y <= 1; y++) {
63
+ for (int x = -1; x <= 1; x++) {
64
+ ivec2 neighbor = coordinates + ivec2(x,y);
65
+ if (all(greaterThanEqual(neighbor, ivec2(0))) && all(lessThan(neighbor,size))) {
66
+ vec4 candidate = texelFetch(currentTexture, neighbor, 0);
67
+ if (candidate.a == chart) {return candidate;}
68
+ }
69
+ }
70
+ }
71
+ return current;
72
+ }`
73
+ } as const satisfies ShaderModule<{weight?: number; mode?: number}, {weight: number; mode: number}>;
@@ -0,0 +1,76 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
3
+
4
+ import type {NumberArray9} from '@math.gl/core';
5
+ import type {ShaderModule} from '../../../lib/shader-module/shader-module';
6
+ import {pbrMaterial} from '../pbr-material/pbr-material';
7
+
8
+ export type LightmapBakeUniforms = {
9
+ uvSet: number;
10
+ uvTransform: Readonly<NumberArray9>;
11
+ chartId: number;
12
+ };
13
+
14
+ /** Texture-space rasterization controls. Chart IDs are positive integers exactly representable in the target format. */
15
+ export const lightmapBake = {
16
+ name: 'lightmapBake',
17
+ dependencies: [pbrMaterial],
18
+ bindingLayout: [{name: 'lightmapBake', group: 0}],
19
+ uniformTypes: {uvSet: 'i32', uvTransform: 'mat3x3<f32>', chartId: 'f32'},
20
+ defaultUniforms: {uvSet: 1, uvTransform: [1, 0, 0, 0, 1, 0, 0, 0, 1], chartId: 1},
21
+ getUniforms: (props: Partial<LightmapBakeUniforms>) => props,
22
+ source: `
23
+ struct LightmapBakeUniforms {uvSet: i32, uvTransform: mat3x3f, chartId: f32};
24
+ @group(0) @binding(auto) var<uniform> lightmapBake: LightmapBakeUniforms;
25
+
26
+ fn lightmap_getIrradiance(position: vec3f, normal: vec3f, directionalVisibility: f32, pointVisibility: vec4f, spotVisibility: vec4f) -> vec3f {
27
+ if (lighting.enabled == 0) {return vec3f(0.0);}
28
+ var irradiance = lighting.ambientColor;
29
+ for (var index = 0; index < lighting.directionalLightCount; index++) {
30
+ let light = lighting_getDirectionalLight(index);
31
+ irradiance += light.color * max(dot(normal, -normalize(light.direction)), 0.0) * select(1.0, directionalVisibility, index == 0);
32
+ }
33
+ for (var index = 0; index < lighting.pointLightCount; index++) {
34
+ let light = lighting_getPointLight(index);
35
+ let offset = light.position - position;
36
+ let visibility = select(1.0, pointVisibility[min(index, 3)], index < 4);
37
+ irradiance += light.color * max(dot(normal, normalize(offset)), 0.0) * visibility / max(getPointLightAttenuation(light, length(offset)), 0.0001);
38
+ }
39
+ for (var index = 0; index < lighting.spotLightCount; index++) {
40
+ let light = lighting_getSpotLight(index);
41
+ irradiance += light.color * max(dot(normal, normalize(light.position - position)), 0.0) * select(1.0, spotVisibility[min(index, 3)], index < 4) / max(getSpotLightAttenuation(light, position), 0.0001);
42
+ }
43
+ return irradiance;
44
+ }
45
+ `,
46
+ vs: `layout(std140) uniform lightmapBakeUniforms {
47
+ int uvSet;
48
+ mat3 uvTransform;
49
+ float chartId;
50
+ } lightmapBake;`,
51
+ fs: `layout(std140) uniform lightmapBakeUniforms {
52
+ int uvSet;
53
+ mat3 uvTransform;
54
+ float chartId;
55
+ } lightmapBake;
56
+
57
+ vec3 lightmap_getIrradiance(vec3 position, vec3 normal, float directionalVisibility, vec4 pointVisibility, vec4 spotVisibility) {
58
+ if (lighting.enabled == 0) {return vec3(0.0);}
59
+ vec3 irradiance = lighting.ambientColor;
60
+ for (int index = 0; index < lighting.directionalLightCount; index++) {
61
+ DirectionalLight light = lighting_getDirectionalLight(index);
62
+ irradiance += light.color * max(dot(normal, -normalize(light.direction)), 0.0) * (index == 0 ? directionalVisibility : 1.0);
63
+ }
64
+ for (int index = 0; index < lighting.pointLightCount; index++) {
65
+ PointLight light = lighting_getPointLight(index);
66
+ vec3 offset = light.position - position;
67
+ irradiance += light.color * max(dot(normal, normalize(offset)), 0.0) * (index < 4 ? pointVisibility[index] : 1.0) / max(getPointLightAttenuation(light, length(offset)), 0.0001);
68
+ }
69
+ for (int index = 0; index < lighting.spotLightCount; index++) {
70
+ SpotLight light = lighting_getSpotLight(index);
71
+ irradiance += light.color * max(dot(normal, normalize(light.position - position)), 0.0) * (index < 4 ? spotVisibility[index] : 1.0) / max(getSpotLightAttenuation(light, position), 0.0001);
72
+ }
73
+ return irradiance;
74
+ }
75
+ `
76
+ } as const satisfies ShaderModule<Partial<LightmapBakeUniforms>, LightmapBakeUniforms>;
@@ -0,0 +1,78 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
3
+
4
+ import type {NumberArray4} from '@math.gl/core';
5
+ import type {ShaderModule} from '../../../lib/shader-module/shader-module';
6
+ import {pbrMaterial} from '../pbr-material/pbr-material';
7
+
8
+ export type PBRAmbientOcclusionProps<TextureT = unknown> = {
9
+ ambientOcclusionTexture?: TextureT;
10
+ /** Origin and dimensions of the receiver viewport, in physical pixels. */
11
+ viewport?: Readonly<NumberArray4>;
12
+ strength?: number;
13
+ enabled?: boolean;
14
+ };
15
+ type AmbientUniforms = {viewport: Readonly<NumberArray4>; strength: number; enabled: number};
16
+ type AmbientBindings<TextureT = unknown> = {ambientOcclusionTexture?: TextureT};
17
+
18
+ /** Sets ambient visibility for the canonical PBR material; direct lighting and emission remain independent. */
19
+ export const pbrAmbientOcclusion: ShaderModule<
20
+ PBRAmbientOcclusionProps,
21
+ AmbientUniforms,
22
+ AmbientBindings
23
+ > = {
24
+ name: 'pbrAmbientOcclusion',
25
+ dependencies: [pbrMaterial],
26
+ bindingLayout: [
27
+ {name: 'pbrAmbientOcclusion', group: 0},
28
+ {name: 'ambientOcclusionTexture', group: 2}
29
+ ],
30
+ uniformTypes: {viewport: 'vec4<f32>', strength: 'f32', enabled: 'i32'},
31
+ defaultUniforms: {viewport: [0, 0, 1, 1], strength: 1, enabled: 1},
32
+ getUniforms(properties = {}) {
33
+ return {
34
+ ...(properties.viewport ? {viewport: properties.viewport} : {}),
35
+ ...(properties.strength === undefined ? {} : {strength: properties.strength}),
36
+ ...(properties.enabled === undefined ? {} : {enabled: Number(properties.enabled)}),
37
+ ...(properties.ambientOcclusionTexture
38
+ ? {ambientOcclusionTexture: properties.ambientOcclusionTexture}
39
+ : {})
40
+ };
41
+ },
42
+ source: /* wgsl */ `
43
+ struct PBRAmbientOcclusionUniforms {
44
+ viewport: vec4f,
45
+ strength: f32,
46
+ enabled: i32,
47
+ };
48
+ @group(0) @binding(auto) var<uniform> pbrAmbientOcclusion: PBRAmbientOcclusionUniforms;
49
+ @group(2) @binding(auto) var ambientOcclusionTexture: texture_2d<f32>;
50
+ @group(2) @binding(auto) var ambientOcclusionTextureSampler: sampler;
51
+ fn pbrAmbientOcclusion_getFactor(pixelPosition:vec2f)->f32 {
52
+ if(pbrAmbientOcclusion.enabled==0){return 1.0;}
53
+ let coordinates=(pixelPosition-pbrAmbientOcclusion.viewport.xy)/pbrAmbientOcclusion.viewport.zw;
54
+ if(any(coordinates<vec2f(0.0))||any(coordinates>vec2f(1.0))){return 1.0;}
55
+ let visibility=textureSampleLevel(ambientOcclusionTexture,ambientOcclusionTextureSampler,coordinates,0.0).r;
56
+ return mix(1.0,clamp(visibility,0.0,1.0),clamp(pbrAmbientOcclusion.strength,0.0,1.0));
57
+ }
58
+ fn pbrAmbientOcclusion_setFactor(pixelPosition:vec2f) {
59
+ pbr_ambientVisibility = pbrAmbientOcclusion_getFactor(pixelPosition);
60
+ }`,
61
+ fs: /* glsl */ `
62
+ layout(std140) uniform pbrAmbientOcclusionUniforms {
63
+ vec4 viewport;
64
+ float strength;
65
+ int enabled;
66
+ } pbrAmbientOcclusion;
67
+ uniform sampler2D ambientOcclusionTexture;
68
+ float pbrAmbientOcclusion_getFactor(vec2 pixelPosition) {
69
+ if(pbrAmbientOcclusion.enabled==0)return 1.0;
70
+ vec2 coordinates=(pixelPosition-pbrAmbientOcclusion.viewport.xy)/pbrAmbientOcclusion.viewport.zw;
71
+ if(any(lessThan(coordinates,vec2(0.0)))||any(greaterThan(coordinates,vec2(1.0))))return 1.0;
72
+ float visibility=texture(ambientOcclusionTexture,coordinates).r;
73
+ return mix(1.0,clamp(visibility,0.0,1.0),clamp(pbrAmbientOcclusion.strength,0.0,1.0));
74
+ }
75
+ void pbrAmbientOcclusion_setFactor(vec2 pixelPosition) {
76
+ pbr_ambientVisibility = pbrAmbientOcclusion_getFactor(pixelPosition);
77
+ }`
78
+ };
@@ -0,0 +1,78 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
3
+
4
+ import type {NumberArray4} from '@math.gl/core';
5
+ import type {ShaderModule} from '../../../lib/shader-module/shader-module';
6
+ import {pbrMaterial} from '../pbr-material/pbr-material';
7
+
8
+ export type PBRContactShadowProps<TextureT = unknown> = {
9
+ contactShadowTexture?: TextureT;
10
+ /** Origin and dimensions of the receiver viewport, in physical pixels. */
11
+ viewport?: Readonly<NumberArray4>;
12
+ strength?: number;
13
+ enabled?: boolean;
14
+ };
15
+ type ContactUniforms = {viewport: Readonly<NumberArray4>; strength: number; enabled: number};
16
+ type ContactBindings<TextureT = unknown> = {contactShadowTexture?: TextureT};
17
+
18
+ /** Applies a screen-space visibility mask to the first directional light only. */
19
+ export const pbrContactShadow: ShaderModule<
20
+ PBRContactShadowProps,
21
+ ContactUniforms,
22
+ ContactBindings
23
+ > = {
24
+ name: 'pbrContactShadow',
25
+ dependencies: [pbrMaterial],
26
+ bindingLayout: [
27
+ {name: 'pbrContactShadow', group: 0},
28
+ {name: 'contactShadowTexture', group: 2}
29
+ ],
30
+ uniformTypes: {viewport: 'vec4<f32>', strength: 'f32', enabled: 'i32'},
31
+ defaultUniforms: {viewport: [0, 0, 1, 1], strength: 1, enabled: 1},
32
+ getUniforms(properties = {}) {
33
+ return {
34
+ ...(properties.viewport ? {viewport: properties.viewport} : {}),
35
+ ...(properties.strength === undefined ? {} : {strength: properties.strength}),
36
+ ...(properties.enabled === undefined ? {} : {enabled: Number(properties.enabled)}),
37
+ ...(properties.contactShadowTexture
38
+ ? {contactShadowTexture: properties.contactShadowTexture}
39
+ : {})
40
+ };
41
+ },
42
+ source: /* wgsl */ `
43
+ struct PBRContactShadowUniforms {
44
+ viewport: vec4f,
45
+ strength: f32,
46
+ enabled: i32,
47
+ };
48
+ @group(0) @binding(auto) var<uniform> pbrContactShadow: PBRContactShadowUniforms;
49
+ @group(2) @binding(auto) var contactShadowTexture: texture_2d<f32>;
50
+ @group(2) @binding(auto) var contactShadowTextureSampler: sampler;
51
+ fn pbrContactShadow_getFactor(pixelPosition:vec2f)->f32 {
52
+ if(pbrContactShadow.enabled==0){return 1.0;}
53
+ let coordinates=(pixelPosition-pbrContactShadow.viewport.xy)/pbrContactShadow.viewport.zw;
54
+ if(any(coordinates<vec2f(0.0))||any(coordinates>vec2f(1.0))){return 1.0;}
55
+ let visibility=textureSampleLevel(contactShadowTexture,contactShadowTextureSampler,coordinates,0.0).r;
56
+ return mix(1.0,clamp(visibility,0.0,1.0),clamp(pbrContactShadow.strength,0.0,1.0));
57
+ }
58
+ fn pbrContactShadow_filterColor(vertexColor:vec4f,pixelPosition:vec2f)->vec4f {
59
+ return pbr_filterColorWithShadows(vertexColor,pbrContactShadow_getFactor(pixelPosition),vec4f(1.0),vec4f(1.0));
60
+ }`,
61
+ fs: /* glsl */ `
62
+ layout(std140) uniform pbrContactShadowUniforms {
63
+ vec4 viewport;
64
+ float strength;
65
+ int enabled;
66
+ } pbrContactShadow;
67
+ uniform sampler2D contactShadowTexture;
68
+ float pbrContactShadow_getFactor(vec2 pixelPosition) {
69
+ if(pbrContactShadow.enabled==0)return 1.0;
70
+ vec2 coordinates=(pixelPosition-pbrContactShadow.viewport.xy)/pbrContactShadow.viewport.zw;
71
+ if(any(lessThan(coordinates,vec2(0.0)))||any(greaterThan(coordinates,vec2(1.0))))return 1.0;
72
+ float visibility=texture(contactShadowTexture,coordinates).r;
73
+ return mix(1.0,clamp(visibility,0.0,1.0),clamp(pbrContactShadow.strength,0.0,1.0));
74
+ }
75
+ vec4 pbrContactShadow_filterColor(vec4 vertexColor,vec2 pixelPosition) {
76
+ return pbr_filterColorWithShadows(vertexColor,pbrContactShadow_getFactor(pixelPosition),vec4(1.0),vec4(1.0));
77
+ }`
78
+ };