matrix-engine-wgpu 1.3.19 → 1.4.1

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.
@@ -1,75 +1,137 @@
1
1
  export let fragmentWGSL = `override shadowDepthTextureSize: f32 = 1024.0;
2
2
 
3
+ // Created by Nikola Lukic with chatgtp assist.
4
+
3
5
  struct Scene {
4
- lightViewProjMatrix : mat4x4f,
5
- cameraViewProjMatrix : mat4x4f,
6
- lightPos : vec3f,
7
- padding : f32, // Required for alignment
8
- }
6
+ lightViewProjMatrix : mat4x4f,
7
+ cameraViewProjMatrix : mat4x4f,
8
+ cameraPos : vec3f,
9
+ padding2 : f32, // align to 16 bytes
10
+ lightPos : vec3f,
11
+ padding : f32, // align to 16 bytes
12
+ };
9
13
 
10
14
  struct SpotLight {
11
- position: vec3f,
12
- _pad1: f32,
13
- direction: vec3f,
14
- _pad2: f32,
15
- innerCutoff: f32,
16
- outerCutoff: f32,
17
- _pad3: vec2f,
18
- }
15
+ position : vec3f,
16
+ _pad1 : f32,
17
+
18
+ direction : vec3f,
19
+ _pad2 : f32,
20
+
21
+ innerCutoff : f32,
22
+ outerCutoff : f32,
23
+ intensity : f32,
24
+ _pad3 : f32,
25
+
26
+ color : vec3f,
27
+ _pad4 : f32,
28
+
29
+ range : f32,
30
+ ambientFactor : f32,
31
+ shadowBias : f32,
32
+ _pad5 : f32,
33
+
34
+ lightViewProj : mat4x4<f32>,
35
+ };
36
+
37
+ const MAX_SPOTLIGHTS = 20u;
19
38
 
20
39
  @group(0) @binding(0) var<uniform> scene : Scene;
21
- @group(0) @binding(1) var shadowMap: texture_depth_2d;
40
+ @group(0) @binding(1) var shadowMapArray: texture_depth_2d_array;
22
41
  @group(0) @binding(2) var shadowSampler: sampler_comparison;
23
42
  @group(0) @binding(3) var meshTexture: texture_2d<f32>;
24
43
  @group(0) @binding(4) var meshSampler: sampler;
25
- @group(0) @binding(5) var<uniform> spotlight: SpotLight;
44
+ @group(0) @binding(5) var<uniform> spotlights: array<SpotLight, MAX_SPOTLIGHTS>;
26
45
 
27
46
  struct FragmentInput {
28
- @location(0) shadowPos : vec3f,
29
- @location(1) fragPos : vec3f,
30
- @location(2) fragNorm : vec3f,
31
- @location(3) uv : vec2f,
47
+ @location(0) shadowPos : vec4f,
48
+ @location(1) fragPos : vec3f,
49
+ @location(2) fragNorm : vec3f,
50
+ @location(3) uv : vec2f,
32
51
  }
33
52
 
34
53
  const albedo = vec3f(0.9);
35
- const ambientFactor = 0.7;
36
54
 
37
55
  fn calculateSpotlightFactor(light: SpotLight, fragPos: vec3f) -> f32 {
38
- let L = normalize(light.position - fragPos);
39
- let theta = dot(L, normalize(-light.direction));
40
- let epsilon = light.innerCutoff - light.outerCutoff;
41
- let intensity = clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0);
42
- return intensity;
56
+ let L = normalize(light.position - fragPos);
57
+ let theta = dot(L, normalize(-light.direction));
58
+ let epsilon = light.innerCutoff - light.outerCutoff;
59
+ return clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0);
43
60
  }
44
61
 
45
- @fragment
46
- fn main(input : FragmentInput) -> @location(0) vec4f {
47
- // Shadow PFC
48
- var visibility = 0.0;
49
- let oneOverSize = 1.0 / shadowDepthTextureSize;
50
- for (var y = -1; y <= 1; y++) {
51
- for (var x = -1; x <= 1; x++) {
52
- let offset = vec2f(vec2(x, y)) * oneOverSize;
53
- visibility += textureSampleCompare(
54
- shadowMap, shadowSampler,
55
- input.shadowPos.xy + offset, input.shadowPos.z - 0.007
56
- );
57
- }
58
- }
59
- visibility /= 9.0;
62
+ fn computeSpotLight(light: SpotLight, normal: vec3f, fragPos: vec3f, viewDir: vec3f) -> vec3f {
63
+ let L = light.position - fragPos;
64
+ let distance = length(L);
65
+ let lightDir = normalize(L);
66
+
67
+ let spotFactor = calculateSpotlightFactor(light, fragPos);
68
+ let atten = clamp(1.0 - (distance / light.range), 0.0, 1.0);
60
69
 
61
- // Lambert
62
- let norm = normalize(input.fragNorm);
63
- let lightDir = normalize(scene.lightPos - input.fragPos);
64
- let lambert = max(dot(norm, lightDir), 0.0);
70
+ let diff = max(dot(normal, lightDir), 0.0);
71
+ let halfwayDir = normalize(lightDir + viewDir);
72
+ let spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
65
73
 
66
- // Spotlight effect
67
- let spotlightFactor = calculateSpotlightFactor(spotlight, input.fragPos);
74
+ let diffuse = diff * light.color * light.intensity * atten;
75
+ let specular = spec * light.color * light.intensity * atten;
68
76
 
69
- // Combine
70
- let lightIntensity = ambientFactor + lambert * visibility * spotlightFactor;
71
- let texColor = textureSample(meshTexture, meshSampler, input.uv);
77
+ return (diffuse + specular) * spotFactor;
78
+ }
79
+
80
+ // Corrected PCF for texture_depth_2d_array
81
+ fn sampleShadow(shadowUV: vec2f, layer: i32, depthRef: f32, normal: vec3f, lightDir: vec3f) -> f32 {
82
+ var visibility: f32 = 0.0;
83
+ let biasConstant: f32 = 0.001;
84
+ // Slope bias: avoid self-shadowing on steep angles
85
+ // let slopeBias: f32 = max(0.002 * (1.0 - dot(normal, lightDir)), 0.0);
86
+ let bias = biasConstant;// + slopeBias;
87
+
88
+ let oneOverSize = 1.0 / (shadowDepthTextureSize * 0.5);
72
89
 
73
- return vec4f(texColor.rgb * lightIntensity * albedo, 1.0);
90
+ // 3x3 PCF kernel
91
+ let offsets: array<vec2f, 9> = array<vec2f, 9>(
92
+ vec2(-1.0, -1.0), vec2(0.0, -1.0), vec2(1.0, -1.0),
93
+ vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
94
+ vec2(-1.0, 1.0), vec2(0.0, 1.0), vec2(1.0, 1.0)
95
+ );
96
+
97
+ for(var i: u32 = 0u; i < 9u; i = i + 1u) {
98
+ visibility += textureSampleCompare(
99
+ shadowMapArray,
100
+ shadowSampler,
101
+ shadowUV + offsets[i] * oneOverSize,
102
+ layer,
103
+ depthRef //+ bias
104
+ );
105
+ }
106
+ return visibility / 9.0;
74
107
  }
75
- `
108
+
109
+ @fragment
110
+ fn main(input: FragmentInput) -> @location(0) vec4f {
111
+ let norm = normalize(input.fragNorm);
112
+
113
+ let viewDir = normalize(scene.cameraPos - input.fragPos);
114
+ // let viewDir = normalize(scene.cameraViewProjMatrix[3].xyz - input.fragPos);
115
+
116
+ var lightContribution = vec3f(0.0);
117
+ var ambient = vec3f(0.0);
118
+
119
+ for (var i: u32 = 0u; i < MAX_SPOTLIGHTS; i = i + 1u) {
120
+ let sc = spotlights[i].lightViewProj * vec4<f32>(input.fragPos, 1.0);
121
+ let p = sc.xyz / sc.w;
122
+ let uv = clamp(p.xy * 0.5 + vec2<f32>(0.5), vec2<f32>(0.0), vec2<f32>(1.0));
123
+ let depthRef = p.z * 0.5 + 0.5;
124
+ let lightDir = normalize(spotlights[i].position - input.fragPos);
125
+ let angleFactor = 1.0 - dot(norm, lightDir);
126
+ let slopeBias = 0.01 * (1.0 - dot(norm, lightDir));
127
+ let bias = spotlights[i].shadowBias + slopeBias;
128
+ let visibility = sampleShadow(uv, i32(i), depthRef - bias, norm, lightDir);
129
+ let contrib = computeSpotLight(spotlights[i], norm, input.fragPos, viewDir);
130
+ lightContribution += contrib * visibility;
131
+ ambient += spotlights[i].ambientFactor * spotlights[i].color;
132
+ }
133
+
134
+ let texColor = textureSample(meshTexture, meshSampler, input.uv);
135
+ let finalColor = texColor.rgb * (ambient + lightContribution); // * albedo;
136
+ return vec4f(finalColor, 1.0);
137
+ }`;
@@ -48,4 +48,3 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
48
48
 
49
49
  return vec4f(textureColor.rgb * lightColor, textureColor.a);
50
50
  }`;
51
-
@@ -12,11 +12,10 @@ struct Model {
12
12
  @group(1) @binding(0) var<uniform> model : Model;
13
13
 
14
14
  struct VertexOutput {
15
- @location(0) shadowPos: vec3f,
15
+ @location(0) shadowPos: vec4f, // now vec4
16
16
  @location(1) fragPos: vec3f,
17
17
  @location(2) fragNorm: vec3f,
18
- @location(3) uv : vec2f,
19
-
18
+ @location(3) uv: vec2f,
20
19
  @builtin(position) Position: vec4f,
21
20
  }
22
21
 
@@ -24,31 +23,18 @@ struct VertexOutput {
24
23
  fn main(
25
24
  @location(0) position: vec3f,
26
25
  @location(1) normal: vec3f,
27
- @location(2) uv : vec2f
26
+ @location(2) uv: vec2f
28
27
  ) -> VertexOutput {
29
28
  var output : VertexOutput;
30
29
 
31
- // XY is in (-1, 1) space, Z is in (0, 1) space
32
30
  let posFromLight = scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
33
-
34
- // Convert XY to (0, 1)
35
- // Y is flipped because texture coords are Y-down.
36
- output.shadowPos = vec3(
37
- posFromLight.xy * vec2(0.5, -0.5) + vec2(0.5),
38
- posFromLight.z
39
- );
40
-
41
- // follewed camera code
42
- // output.Position = scene.cameraViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
43
- // output.fragPos = output.Position.xyz;
44
- // output.fragNorm = normal;
31
+ output.shadowPos = posFromLight; // pass full vec4 for perspective divide
45
32
 
46
33
  let worldPos = model.modelMatrix * vec4(position, 1.0);
47
34
  output.Position = scene.cameraViewProjMatrix * worldPos;
48
- output.fragPos = worldPos.xyz; // ✅ world space
35
+ output.fragPos = worldPos.xyz;
49
36
 
50
37
  output.fragNorm = normalize((model.modelMatrix * vec4(normal, 0.0)).xyz);
51
38
  output.uv = uv;
52
39
  return output;
53
- }
54
- `;
40
+ }`;