@kitware/vtk.js 34.3.0 → 34.3.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.
@@ -71,6 +71,30 @@ struct PBRData {
71
71
  specular: vec3<f32>,
72
72
  }
73
73
 
74
+ struct Material {
75
+ ior: f32,
76
+ roughness: f32,
77
+ metallic: f32,
78
+ base: vec3<f32>,
79
+ };
80
+
81
+ struct DirectionalLight {
82
+ direction: vec3<f32>,
83
+ color: vec3<f32>,
84
+ };
85
+
86
+ struct PointLight {
87
+ position: vec3<f32>,
88
+ color: vec3<f32>,
89
+ };
90
+
91
+ struct SpotLight {
92
+ position: vec3<f32>,
93
+ direction: vec3<f32>,
94
+ cones: vec2<f32>,
95
+ color: vec3<f32>,
96
+ };
97
+
74
98
  const pi: f32 = 3.14159265359;
75
99
 
76
100
  // Dot product with the max already in it
@@ -175,53 +199,51 @@ fn cookTorrance(D: f32, F: f32, G: f32, N: vec3<f32>, V: vec3<f32>, L: vec3<f32>
175
199
  }
176
200
 
177
201
  // Different lighting calculations for different light sources
178
- fn calcDirectionalLight(N: vec3<f32>, V: vec3<f32>, ior: f32, roughness: f32, metallic: f32, direction: vec3<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData {
179
- var L: vec3<f32> = normalize(direction); // Light Vector
202
+ fn calcDirectionalLight(N: vec3<f32>, V: vec3<f32>, mat: Material, light: DirectionalLight) -> PBRData {
203
+ var L: vec3<f32> = normalize(light.direction); // Light Vector
180
204
  var H: vec3<f32> = normalize(L + V); // Halfway Vector
181
205
 
182
- var alpha = roughness*roughness;
183
- var k: f32 = alpha*alpha / 2;
206
+ var alpha = mat.roughness * mat.roughness;
207
+ var k: f32 = alpha * alpha / 2.0;
184
208
 
185
209
  var D: f32 = trGGX(N, H, alpha); // Distribution
186
210
  // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel
187
211
  var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry
188
212
 
189
213
  var brdf: f32 = cookTorrance(D, 1.0, G, N, V, L); // Fresnel term is replaced with 1 because it is added later
190
- var incoming: vec3<f32> = color;
214
+ var incoming: vec3<f32> = light.color;
191
215
  var angle: f32 = mdot(L, N);
192
216
  angle = pow(angle, 1.5);
193
217
 
194
- var specular: vec3<f32> = brdf*incoming*angle;
218
+ var specular: vec3<f32> = brdf * incoming * angle;
195
219
  // Oren-Nayar gives a clay-like effect when fully rough which some people may not want, so it might be better to give a separate
196
220
  // control property for the diffuse vs specular roughness
197
- var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);
221
+ var diffuse: vec3<f32> = incoming * fujiiOrenNayar(mat.base, mat.roughness, N, L, V);
198
222
  // Stores the specular and diffuse separately to allow for finer post processing
199
223
  var out = PBRData(diffuse, specular);
200
224
 
201
225
  return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)
202
226
  }
203
227
 
204
- // TODO: find some way to reduce the number of arguments going in here
205
- fn calcPointLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, ior: f32, roughness: f32, metallic: f32, position: vec3<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData {
206
- var L: vec3<f32> = normalize(position - fragPos); // Light Vector
207
- var H: vec3<f32> = normalize(L + V); // Halfway Vector
208
- var dist = distance(position, fragPos);
228
+ fn calcPointLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, mat: Material, light: PointLight) -> PBRData {
229
+ var L: vec3<f32> = normalize(light.position - fragPos);
230
+ var H: vec3<f32> = normalize(L + V);
231
+ var dist = distance(light.position, fragPos);
209
232
 
210
- var alpha = roughness*roughness;
211
- var k: f32 = alpha*alpha / 2.0; // could also be pow(alpha + 1.0, 2) / 8
233
+ var alpha = mat.roughness * mat.roughness;
234
+ var k: f32 = alpha * alpha / 2.0;
212
235
 
213
236
  var D: f32 = trGGX(N, H, alpha); // Distribution
214
- // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel
237
+ var F: f32 = schlickFresnelIOR(V, N, mat.ior, k); // Fresnel
215
238
  var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry
216
239
 
217
240
  var brdf: f32 = cookTorrance(D, 1.0, G, N, V, L);
218
- var incoming: vec3<f32> = color * (1.0 / (dist*dist));
241
+ var incoming: vec3<f32> = light.color * (1.0 / (dist * dist));
219
242
  var angle: f32 = mdot(L, N);
220
- angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly "seams" bewteen light sources
221
-
222
- var specular: vec3<f32> = brdf*incoming*angle;
223
- var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);
243
+ angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly "seams" between light sources
224
244
 
245
+ var specular: vec3<f32> = brdf * incoming * angle;
246
+ var diffuse: vec3<f32> = incoming * fujiiOrenNayar(mat.base, mat.roughness, N, L, V);
225
247
  // Stores the specular and diffuse separately to allow for finer post processing
226
248
  // Could also be done (propably more properly) with a struct
227
249
  var out = PBRData(diffuse, specular);
@@ -230,13 +252,13 @@ fn calcPointLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, ior: f32, roug
230
252
  }
231
253
 
232
254
  // For a reason unknown to me, spheres dont seem to behave propperly with head-on spot lights
233
- fn calcSpotLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, ior: f32, roughness: f32, metallic: f32, position: vec3<f32>, direction: vec3<f32>, cones: vec2<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData {
234
- var L: vec3<f32> = normalize(position - fragPos);
255
+ fn calcSpotLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, mat: Material, light: SpotLight) -> PBRData {
256
+ var L: vec3<f32> = normalize(light.position - fragPos);
235
257
  var H: vec3<f32> = normalize(L + V); // Halfway Vector
236
- var dist = distance(position, fragPos);
258
+ var dist = distance(light.position, fragPos);
237
259
 
238
- var alpha = roughness*roughness;
239
- var k: f32 = alpha*alpha / 2.0; // could also be pow(alpha + 1.0, 2) / 8
260
+ var alpha = mat.roughness * mat.roughness;
261
+ var k: f32 = alpha * alpha / 2.0; // could also be pow(alpha + 1.0, 2) / 8
240
262
 
241
263
  var D: f32 = trGGX(N, H, alpha); // Distribution
242
264
  // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel
@@ -244,20 +266,19 @@ fn calcSpotLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, ior: f32, rough
244
266
 
245
267
  var brdf: f32 = cookTorrance(D, 1.0, G, N, V, L);
246
268
 
247
- // Cones.x is the inner phi and cones.y is the outer phi
248
- var theta: f32 = mdot(normalize(direction), L);
249
- var epsilon: f32 = cones.x - cones.y;
250
- var intensity: f32 = (theta - cones.y) / epsilon;
269
+ var theta: f32 = mdot(normalize(light.direction), L);
270
+ var epsilon: f32 = light.cones.x - light.cones.y;
271
+ var intensity: f32 = (theta - light.cones.y) / epsilon;
251
272
  intensity = clamp(intensity, 0.0, 1.0);
252
- intensity /= dist*dist;
273
+ intensity /= dist * dist;
253
274
 
254
- var incoming: vec3<f32> = color * intensity;
275
+ var incoming: vec3<f32> = light.color * intensity;
255
276
 
256
277
  var angle: f32 = mdot(L, N);
257
- angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly "seams" bewteen light sources
278
+ angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly "seams" between light sources
258
279
 
259
- var specular: vec3<f32> = brdf*incoming*angle;
260
- var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);
280
+ var specular: vec3<f32> = brdf * incoming * angle;
281
+ var diffuse: vec3<f32> = incoming * fujiiOrenNayar(mat.base, mat.roughness, N, L, V);
261
282
 
262
283
  // Stores the specular and diffuse separately to allow for finer post processing
263
284
  // Could also be done (propably more properly) with a struct
@@ -310,6 +331,7 @@ fn main(
310
331
  var ambientColor: vec4<f32> = mapperUBO.AmbientColor;
311
332
  var diffuseColor: vec4<f32> = mapperUBO.DiffuseColor;
312
333
  var opacity: f32 = mapperUBO.Opacity;
334
+ var ior: f32 = mapperUBO.BaseIOR;
313
335
 
314
336
  // This should be declared somewhere else
315
337
  var _diffuseMap: vec4<f32> = vec4<f32>(1.0);
@@ -331,6 +353,8 @@ fn main(
331
353
 
332
354
  //VTK::Select::Impl
333
355
 
356
+ // Use texture alpha for transparency
357
+ computedColor.a = mapperUBO.Opacity * _diffuseMap.a;
334
358
  if (computedColor.a == 0.0) { discard; };
335
359
 
336
360
  //VTK::Position::Impl
@@ -525,31 +549,29 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
525
549
  if (code.includes('var normal:') && model.useRendererMatrix && !isEdges(hash) && !model.is2D && !hash.includes('sel')) {
526
550
  const lightingCode = [
527
551
  // Vectors needed for light calculations
528
- ' var fragPos: vec3<f32> = vec3<f32>(input.vertexVC.xyz);', ' var V: vec3<f32> = mix(normalize(-fragPos), vec3<f32>(0, 0, 1), f32(rendererUBO.cameraParallel)); // View Vector',
552
+ ' let fragPos = vec3<f32>(input.vertexVC.xyz);', ' let V = mix(normalize(-fragPos), vec3<f32>(0, 0, 1), f32(rendererUBO.cameraParallel)); // View Vector',
529
553
  // Values needed for light calculations
530
- ' var baseColor: vec3<f32> = _diffuseMap.rgb * diffuseColor.rgb;', ' var roughness: f32 = max(0.000001, mapperUBO.Roughness * _roughnessMap.r);',
554
+ ' let baseColor = _diffuseMap.rgb * diffuseColor.rgb;', ' let roughness = max(0.000001, mapperUBO.Roughness * _roughnessMap.r);',
531
555
  // Need to have a different way of sampling greyscale values aside from .r
532
- ' var metallic: f32 = mapperUBO.Metallic * _metallicMap.r;', ' var alpha: f32 = roughness*roughness;', ' var ior: f32 = mapperUBO.BaseIOR;', ' var k: f32 = alpha*alpha / 2;',
556
+ ' let metallic = mapperUBO.Metallic * _metallicMap.r;', ' let alpha = roughness * roughness;', ' let k = alpha * alpha / 2.0;',
533
557
  // Split diffuse and specular components
534
- ' var diffuse: vec3<f32> = vec3<f32>(0.);', ' var specular: vec3<f32> = vec3<f32>(0.);', ' var emission: vec3<f32> = _emissionMap.rgb * mapperUBO.Emission;',
558
+ ' var diffuse = vec3<f32>(0.);', ' var specular = vec3<f32>(0.);', ' let emission = _emissionMap.rgb * mapperUBO.Emission;', '', ' // Material struct', ' let mat = Material(ior, roughness, metallic, baseColor);', '',
535
559
  // Summing diffuse and specular components of directional lights
536
- ' {', ' var i: i32 = 0;', ' loop {', ' if !(i < rendererUBO.LightCount) { break; }', ' switch (i32(rendererLightSSBO.values[i].LightData.x)) {', ' // Point Light', ' case 0 {', ' var color: vec3<f32> = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' var pos: vec3<f32> = (rendererLightSSBO.values[i].LightPos).xyz;', ' var calculated: PBRData = calcPointLight(normal, V, fragPos, ior, roughness, metallic, pos, color, baseColor);', ' diffuse += max(vec3<f32>(0), calculated.diffuse);', ' specular += max(vec3<f32>(0), calculated.specular);', ' }', ' // Directional light', ' case 1 {', ' var dir: vec3<f32> = (rendererUBO.WCVCNormals * vec4<f32>(normalize(rendererLightSSBO.values[i].LightDir.xyz), 0.)).xyz;', ' dir = normalize(dir);', ' var color: vec3<f32> = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' var calculated: PBRData = calcDirectionalLight(normal, V, ior, roughness, metallic, dir, color, baseColor); // diffuseColor.rgb needs to be fixed with a more dynamic diffuse color', ' diffuse += max(vec3<f32>(0), calculated.diffuse);', ' specular += max(vec3<f32>(0), calculated.specular);', ' }', ' // Spot Light', ' case 2 {', ' var color: vec3<f32> = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' var pos: vec3<f32> = (rendererLightSSBO.values[i].LightPos).xyz;', ' var dir: vec3<f32> = (rendererUBO.WCVCNormals * vec4<f32>(normalize(rendererLightSSBO.values[i].LightDir.xyz), 0.)).xyz;', ' dir = normalize(dir);', ' var cones: vec2<f32> = vec2<f32>(rendererLightSSBO.values[i].LightData.y, rendererLightSSBO.values[i].LightData.z);', ' var calculated: PBRData = calcSpotLight(normal, V, fragPos, ior, roughness, metallic, pos, dir, cones, color, baseColor);', ' diffuse += max(vec3<f32>(0), calculated.diffuse);', ' specular += max(vec3<f32>(0), calculated.specular);', ' }', ' default { continue; }', ' }', ' continuing { i++; }', ' }', ' }',
560
+ ' {', ' var i = 0;', ' loop {', ' if (!(i < rendererUBO.LightCount)) { break; }', ' switch (i32(rendererLightSSBO.values[i].LightData.x)) {', ' // Point Light', ' case 0 {', ' let color = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' let pos = (rendererLightSSBO.values[i].LightPos).xyz;', ' let pointLight = PointLight(pos, color);', ' let result = calcPointLight(normal, V, fragPos, mat, pointLight);', ' diffuse += max(vec3<f32>(0), result.diffuse);', ' specular += max(vec3<f32>(0), result.specular);', ' }', ' // Directional light', ' case 1 {', ' let dir = normalize((rendererUBO.WCVCNormals * vec4<f32>(normalize(rendererLightSSBO.values[i].LightDir.xyz), 0.)).xyz);', ' let color = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' let dirLight = DirectionalLight(dir, color);', ' let result = calcDirectionalLight(normal, V, mat, dirLight); // diffuseColor.rgb needs to be fixed with a more dynamic diffuse color', ' diffuse += max(vec3<f32>(0), result.diffuse);', ' specular += max(vec3<f32>(0), result.specular);', ' }', ' // Spot Light', ' case 2 {', ' let color = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' let pos = (rendererLightSSBO.values[i].LightPos).xyz;', ' let dir = normalize((rendererUBO.WCVCNormals * vec4<f32>(normalize(rendererLightSSBO.values[i].LightDir.xyz), 0.)).xyz);', ' let cones = vec2<f32>(rendererLightSSBO.values[i].LightData.y, rendererLightSSBO.values[i].LightData.z);', ' let spotLight = SpotLight(pos, dir, cones, color);', ' let result = calcSpotLight(normal, V, fragPos, mat, spotLight);', ' diffuse += max(vec3<f32>(0), result.diffuse);', ' specular += max(vec3<f32>(0), result.specular);', ' }', ' default { continue; }', ' }', ' continuing { i++; }', ' }', ' }',
537
561
  // Final variables for combining specular and diffuse
538
- ' var fresnel: f32 = schlickFresnelIOR(V, normal, ior, k); // Fresnel', ' fresnel = min(1.0, fresnel);', ' // This could be controlled with its own variable (that isnt base color) for better artistic control', ' var fresnelMetallic: vec3<f32> = schlickFresnelRGB(V, normal, baseColor); // Fresnel for metal, takes color into account', ' var kS: vec3<f32> = mix(vec3<f32>(fresnel), fresnelMetallic, metallic);', ' kS = min(vec3<f32>(1.0), kS);', ' var kD: vec3<f32> = (1.0 - kS) * (1.0 - metallic);', ' var PBR: vec3<f32> = mapperUBO.DiffuseIntensity*kD*diffuse + kS*specular;', ' PBR += emission;', ' computedColor = vec4<f32>(PBR, mapperUBO.Opacity);'];
562
+ ' let fresnel = min(1.0, schlickFresnelIOR(V, normal, ior, k)); // Fresnel', ' // This could be controlled with its own variable (that isnt base color) for better artistic control', ' let fresnelMetallic = schlickFresnelRGB(V, normal, baseColor); // Fresnel for metal, takes color into account', ' let kS = min(vec3<f32>(1.0), mix(vec3<f32>(fresnel), fresnelMetallic, metallic));', ' let kD = (1.0 - kS) * (1.0 - metallic);', ' let PBR = mapperUBO.DiffuseIntensity * kD * diffuse + kS * specular;', ' computedColor = vec4<f32>(PBR + emission, mapperUBO.Opacity);'];
539
563
  if (renderer.getEnvironmentTexture()?.getImageLoaded()) {
540
- lightingCode.push(' // To get diffuse IBL, the texture is sampled with normals in worldspace', ' var diffuseIBLCoords: vec3<f32> = (transpose(rendererUBO.WCVCNormals) * vec4<f32>(normal, 1.)).xyz;', ' var diffuseCoords: vec2<f32> = vecToRectCoord(diffuseIBLCoords);', ' // To get specular IBL, the texture is sampled as the worldspace reflection between the normal and view vectors', ' // Reflections are first calculated in viewspace, then converted to worldspace to sample the environment', ' var VreflN: vec3<f32> = normalize(reflect(-V, normal));', ' var reflectionIBLCoords = (transpose(rendererUBO.WCVCNormals) * vec4<f32>(VreflN, 1.)).xyz;', ' var specularCoords: vec2<f32> = vecToRectCoord(reflectionIBLCoords);', ' var diffuseIBL = textureSampleLevel(EnvironmentTexture, EnvironmentTextureSampler, diffuseCoords, rendererUBO.MaxEnvironmentMipLevel);',
564
+ lightingCode.push(' // To get diffuse IBL, the texture is sampled with normals in worldspace', ' let diffuseIBLCoords = (transpose(rendererUBO.WCVCNormals) * vec4<f32>(normal, 1.)).xyz;', ' let diffuseCoords = vecToRectCoord(diffuseIBLCoords);', ' // To get specular IBL, the texture is sampled as the worldspace reflection between the normal and view vectors', ' // Reflections are first calculated in viewspace, then converted to worldspace to sample the environment', ' let VreflN = normalize(reflect(-V, normal));', ' let reflectionIBLCoords = (transpose(rendererUBO.WCVCNormals) * vec4<f32>(VreflN, 1.)).xyz;', ' let specularCoords = vecToRectCoord(reflectionIBLCoords);', ' let diffuseIBL = textureSampleLevel(EnvironmentTexture, EnvironmentTextureSampler, diffuseCoords, rendererUBO.MaxEnvironmentMipLevel);',
541
565
  // Level multiplier should be set by UBO
542
- ' var level = roughness * rendererUBO.MaxEnvironmentMipLevel;', ' var specularIBL = textureSampleLevel(EnvironmentTexture, EnvironmentTextureSampler, specularCoords, level);',
566
+ ' let level = roughness * rendererUBO.MaxEnvironmentMipLevel;', ' let specularIBL = textureSampleLevel(EnvironmentTexture, EnvironmentTextureSampler, specularCoords, level);',
543
567
  // Manual mip smoothing since not all formats support smooth level sampling
544
- ' var specularIBLContribution: vec3<f32> = specularIBL.rgb*rendererUBO.BackgroundSpecularStrength;', ' computedColor += vec4<f32>(specularIBLContribution*kS, 0);', ' var diffuseIBLContribution: vec3<f32> = diffuseIBL.rgb*rendererUBO.BackgroundDiffuseStrength;', ' diffuseIBLContribution *= baseColor * _ambientOcclusionMap.rgb;',
545
- // Multipy by baseColor may be changed
546
- ' computedColor += vec4<f32>(diffuseIBLContribution*kD, 0);');
568
+ ' let specularIBLContribution = specularIBL.rgb * rendererUBO.BackgroundSpecularStrength;', ' computedColor += vec4<f32>(specularIBLContribution * kS, 0);', ' let diffuseIBLContribution = diffuseIBL.rgb * rendererUBO.BackgroundDiffuseStrength;', ' computedColor += vec4<f32>(diffuseIBLContribution * baseColor * _ambientOcclusionMap.rgb * kD, 0);');
547
569
  }
548
570
  code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', lightingCode).result;
549
571
  fDesc.setCode(code);
550
572
  // If theres no normals, just set the specular color to be flat
551
573
  } else {
552
- code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', [' var diffuse: vec3<f32> = diffuseColor.rgb;', ' var specular: vec3<f32> = mapperUBO.SpecularColor.rgb * mapperUBO.SpecularColor.a;', ' computedColor = vec4<f32>(diffuse * _diffuseMap.rgb, mapperUBO.Opacity);']).result;
574
+ code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', [' let diffuse = diffuseColor.rgb;', ' let specular = mapperUBO.SpecularColor.rgb * mapperUBO.SpecularColor.a;', ' computedColor = vec4<f32>(diffuse * _diffuseMap.rgb, mapperUBO.Opacity);']).result;
553
575
  fDesc.setCode(code);
554
576
  }
555
577
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "34.3.0",
3
+ "version": "34.3.1",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",