@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>,
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
var
|
|
207
|
-
var
|
|
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;
|
|
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
|
-
|
|
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"
|
|
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>,
|
|
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
|
-
|
|
248
|
-
var
|
|
249
|
-
var
|
|
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"
|
|
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
|
-
'
|
|
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
|
-
'
|
|
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
|
-
'
|
|
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
|
|
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
|
|
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
|
-
'
|
|
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', '
|
|
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
|
-
'
|
|
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
|
-
'
|
|
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', ['
|
|
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
|
};
|