@kitware/vtk.js 25.3.0 → 25.6.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/IO/Core/DataAccessHelper/HtmlDataAccessHelper.js +4 -8
- package/IO/Core/DataAccessHelper/HttpDataAccessHelper.js +6 -14
- package/IO/Core/DataAccessHelper/JSZipDataAccessHelper.js +60 -57
- package/IO/Core/ZipMultiDataSetReader.js +19 -29
- package/IO/Core/ZipMultiDataSetWriter.js +7 -23
- package/IO/Misc/SkyboxReader.js +67 -75
- package/IO/XML/XMLReader.js +2 -2
- package/IO/XML/XMLWriter.js +2 -2
- package/Interaction/Style/InteractorStyleTrackballCamera.js +16 -0
- package/README.md +2 -2
- package/Rendering/Core/Actor2D.d.ts +12 -6
- package/Rendering/Core/ColorTransferFunction/ColorMaps.d.ts +24 -0
- package/Rendering/Core/Property2D.d.ts +1 -1
- package/Rendering/Core/Renderer.d.ts +43 -3
- package/Rendering/Core/Renderer.js +5 -1
- package/Rendering/Core/Texture.d.ts +22 -0
- package/Rendering/Core/Texture.js +159 -10
- package/Rendering/Core/VolumeProperty.d.ts +4 -4
- package/Rendering/Core/VolumeProperty.js +1 -1
- package/Rendering/OpenGL/RenderWindow/ContextProxy.js +65 -0
- package/Rendering/OpenGL/RenderWindow.js +3 -1
- package/Rendering/WebGPU/CellArrayMapper.js +43 -13
- package/Rendering/WebGPU/ForwardPass.js +93 -15
- package/Rendering/WebGPU/FullScreenQuad.js +2 -1
- package/Rendering/WebGPU/OpaquePass.js +1 -1
- package/Rendering/WebGPU/OrderIndependentTranslucentPass.js +1 -1
- package/Rendering/WebGPU/RenderEncoder.js +9 -5
- package/Rendering/WebGPU/RenderWindow.js +15 -13
- package/Rendering/WebGPU/Renderer.js +77 -5
- package/Rendering/WebGPU/Sampler.js +4 -0
- package/Rendering/WebGPU/Texture.js +78 -46
- package/Rendering/WebGPU/TextureManager.js +5 -3
- package/Rendering/WebGPU/TextureView.js +15 -2
- package/Rendering/WebGPU/VolumePass.js +1 -1
- package/index.d.ts +1 -0
- package/index.js +0 -2
- package/package.json +4 -5
- package/ThirdParty/index.js +0 -9
|
@@ -18,7 +18,7 @@ var ScalarMode = vtkMapper.ScalarMode;
|
|
|
18
18
|
var CoordinateSystem = vtkProp.CoordinateSystem;
|
|
19
19
|
var DisplayLocation = vtkProperty2D.DisplayLocation;
|
|
20
20
|
var vtkWebGPUPolyDataVS = "\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n//VTK::Normal::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Select::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@vertex\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n var vertex: vec4<f32> = vertexBC;\n\n //VTK::Color::Impl\n\n //VTK::Normal::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::Select::Impl\n\n //VTK::Position::Impl\n\n return output;\n}\n";
|
|
21
|
-
var vtkWebGPUPolyDataFS = "\nstruct PBRData {\n diffuse: vec3<f32>,\n specular: vec3<f32>,\n}\n\n// Dot product with the max already in it\nfn mdot(a: vec3<f32>, b: vec3<f32>) -> f32 {\n return max(0.0, dot(a, b));\n}\n\n// Lambertian diffuse model\nfn lambertDiffuse(base: vec3<f32>, N: vec3<f32>, L: vec3<f32>) -> vec3<f32> {\n var pi: f32 = 3.14159265359; \n var NdotL: f32 = mdot(N, L);\n NdotL = pow(NdotL, 1.5);\n return (base/pi)*NdotL;\n}\n\n// Yasuhiro Fujii improvement on the Oren-Nayar model\n// https://mimosa-pudica.net/improved-oren-nayar.html\n// p is surface color, o is roughness\nfn fujiiOrenNayar(p: vec3<f32>, o: f32, N: vec3<f32>, L: vec3<f32>, V: vec3<f32>) -> vec3<f32> {\n var invpi: f32 = 0.31830988618; // 1/pi\n\n var o2 = o*o;\n var NdotL: f32 = mdot(N, L);\n NdotL = pow(NdotL, 1.5); // Less physically accurate, but hides the \"seams\" between lights better\n\n var NdotV: f32 = mdot(N, V);\n var LdotV: f32 = mdot(L, V);\n\n var s: f32 = LdotV - NdotL*NdotV;\n var t: f32 = mix(1, max(NdotL, NdotV), step(0, s)); // Mix with step is the equivalent of an if statement\n var A: vec3<f32> = 0.5*(o2 / (o2 + 0.33)) + 0.17*p*(o2 / (o2 + 0.13));\n A = invpi*(1 - A);\n var B: f32 = 0.45*(o2 / (o2 + 0.09));\n B = invpi*B;\n\n return p*NdotL*(A + B*(s/t));\n}\n\n// Fresnel portion of BRDF (IOR only, simplified)\nfn schlickFresnelIOR(V: vec3<f32>, N: vec3<f32>, ior: f32, k: f32) -> f32 {\n var NdotV: f32 = mdot(V, N);\n // var R0: f32 = pow((ior - 1.0) / (ior + 1.0), 2); // 1.0 is about the ior of air, and it is assumed that light will be traveling through air\n var F0: f32 = (pow((ior - 1.0), 2) + k*k) / (pow((ior + 1.0), 2) + k*k); // This takes into account the roughness, whic the other one does not\n return F0 + (1 - F0) * pow((1-NdotV), 5); \n}\n\n// Fresnel portion of BRDF (Color ior, better)\nfn schlickFresnelRGB(V: vec3<f32>, N: vec3<f32>, F0: vec3<f32>) -> vec3<f32> {\n var NdotV: f32 = mdot(V, N);\n return F0 + (1 - F0) * pow((1-NdotV), 5); \n}\n\n// Normal portion of BRDF\n// https://learnopengl.com/PBR/Theory\n// Trowbridge-Reitz GGX functions: normal, halfway, roughness^2\nfn trGGX(N: vec3<f32>, H: vec3<f32>, a: f32) -> f32 {\n var pi: f32 = 3.14159265359; \n\n var a2: f32 = a*a;\n var NdotH = mdot(N, H);\n var NdotH2 = NdotH*NdotH;\n \n var denom: f32 = NdotH2 * (a2 - 1.0) + 1.0;\n\n return a2 / max((pi*denom*denom), 0.000001);\n}\n\n// A VERY bad approximation of anisotropy. Real anisotropic calculations require tangent and bitangent\nfn anisotrophicTrGGX(N: vec3<f32>, H: vec3<f32>, O: vec3<f32>, s: f32, a: f32) -> f32 {\n var Op: vec3<f32> = (rendererUBO.WCVCNormals * vec4<f32>(normalize(O) * s, 0.)).xyz;\n\n var ggx1: f32 = trGGX(N + Op*s, H, a);\n var ggx2: f32 = trGGX(N - Op*s, H, a);\n return (0.5 * ggx1 + 0.5 * ggx2);\n}\n\n// Geometry portion of BRDF\nfn schlickGGX(N: vec3<f32>, X: vec3<f32>, k: f32) -> f32 {\n var NdotX = mdot(N, X);\n return NdotX / max(0.000001, (NdotX*(1-k) + k));\n}\n\nfn smithSurfaceRoughness(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>, k: f32) -> f32 {\n var ggx1: f32 = max(0.01, schlickGGX(N, V, k)); // Prevents void zones at the cost of some accuracy\n var ggx2: f32 = schlickGGX(N, L, k);\n return ggx1*ggx2;\n}\n\n// BRDF Combination\nfn cookTorrance(D: f32, F: f32, G: f32, N: vec3<f32>, V: vec3<f32>, L: vec3<f32>) -> f32 {\n var num: f32 = D*F*G;\n var denom: f32 = 4*mdot(V, N)*mdot(L, N);\n\n return num / max(denom, 0.000001);\n}\n\n// Different lighting calculations for different light sources\nfn calcDirectionalLight(N: vec3<f32>, V: vec3<f32>, ior: f32, roughness: f32, metallic: f32, direction: vec3<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData { \n var L: vec3<f32> = normalize(direction); // Light Vector\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2;\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); // Fresnel term is replaced with 1 because it is added later\n var incoming: vec3<f32> = color;\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5);\n\n var specular: vec3<f32> = brdf*incoming*angle;\n // 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\n // control property for the diffuse vs specular roughness\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V); \n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// TODO: find some way to reduce the number of arguments going in here\nfn 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 {\n var L: vec3<f32> = normalize(position - fragPos); // Light Vector\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n var dist = distance(position, fragPos);\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2; // could also be pow(alpha + 1.0, 2) / 8\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); \n var incoming: vec3<f32> = color * (1. / (dist*dist));\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly \"seams\" bewteen light sources\n\n var specular: vec3<f32> = brdf*incoming*angle;\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);\n\n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// For a reason unknown to me, spheres dont seem to behave propperly with head-on spot lights\nfn 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 {\n var L: vec3<f32> = normalize(position - fragPos);\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n var dist = distance(position, fragPos);\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2; // could also be pow(alpha + 1.0, 2) / 8\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); \n \n // Cones.x is the inner phi and cones.y is the outer phi\n var theta: f32 = mdot(normalize(direction), L);\n var epsilon: f32 = cones.x - cones.y;\n var intensity: f32 = (theta - cones.y) / epsilon;\n intensity = clamp(intensity, 0.0, 1.0);\n intensity /= dist*dist;\n\n var incoming: vec3<f32> = color * intensity;\n\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly \"seams\" bewteen light sources\n\n var specular: vec3<f32> = brdf*incoming*angle;\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);\n\n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// Environment mapping stuff\n// Takes in a vector and converts it to an equivalent coordinate in a rectilinear texture. Should be replaced with cubemaps at some point\nfn vecToRectCoord(dir: vec3<f32>) -> vec2<f32> {\n var tau: f32 = 6.28318530718;\n var out: vec2<f32> = vec2<f32>(0.);\n\n out.x = atan2(dir.z, dir.x) / tau;\n out.x += 0.5;\n\n out.y = (dir.y * .5) + .5;\n\n return out;\n}\n\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n//VTK::TCoord::Dec\n\n// optional surface normal declaration\n//VTK::Normal::Dec\n\n//VTK::Select::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : fragmentOutput;\n\n // Temporary ambient, diffuse, and opacity\n var ambientColor: vec4<f32> = mapperUBO.AmbientColor;\n var diffuseColor: vec4<f32> = mapperUBO.DiffuseColor;\n var opacity: f32 = mapperUBO.Opacity;\n\n // This should be declared somewhere else\n var _diffuseMap: vec4<f32> = vec4<f32>(1);\n var _roughnessMap: vec4<f32> = vec4<f32>(1);\n var _metallicMap: vec4<f32> = vec4<f32>(1);\n var _normalMap: vec4<f32> = vec4<f32>(0, 0, 1, 0); // normal map was setting off the normal vector detection in fragment\n var _ambientOcclusionMap: vec4<f32> = vec4<f32>(0);\n var _emissionMap: vec4<f32> = vec4<f32>(0);\n\n //VTK::Color::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::Normal::Impl\n\n var computedColor: vec4<f32> = vec4<f32>(diffuseColor.rgb, 1.);\n\n //VTK::Light::Impl\n\n //VTK::Select::Impl\n\n if (computedColor.a == 0.0) { discard; };\n\n //VTK::Position::Impl\n\n //VTK::RenderEncoder::Impl\n\n return output;\n}\n";
|
|
21
|
+
var vtkWebGPUPolyDataFS = "\nstruct PBRData {\n diffuse: vec3<f32>,\n specular: vec3<f32>,\n}\n\n// Dot product with the max already in it\nfn mdot(a: vec3<f32>, b: vec3<f32>) -> f32 {\n return max(0.0, dot(a, b));\n}\n// Dot product with a max in it that does not allow for negative values\n// Physically based rendering is accurate as long as normals are accurate,\n// however this is pretty often not the case. In order to prevent negative\n// values from ruining light calculations and creating zones of zero light,\n// this remapping is used, which smoothly clamps the dot product between\n// zero and one while still maintaining a good amount of accuracy.\nfn cdot(a: vec3<f32>, b: vec3<f32>) -> f32 {\n var d: f32 = max(0.0, dot(a, b));\n d = pow((d + 1) / 2.0, 2.6);\n return d;\n}\n\n// Lambertian diffuse model\nfn lambertDiffuse(base: vec3<f32>, N: vec3<f32>, L: vec3<f32>) -> vec3<f32> {\n var pi: f32 = 3.14159265359; \n var NdotL: f32 = mdot(N, L);\n NdotL = pow(NdotL, 1.5);\n return (base/pi)*NdotL;\n}\n\n// Yasuhiro Fujii improvement on the Oren-Nayar model\n// https://mimosa-pudica.net/improved-oren-nayar.html\n// p is surface color, o is roughness\nfn fujiiOrenNayar(p: vec3<f32>, o: f32, N: vec3<f32>, L: vec3<f32>, V: vec3<f32>) -> vec3<f32> {\n var invpi: f32 = 0.31830988618; // 1/pi\n\n var o2 = o*o;\n var NdotL: f32 = mdot(N, L);\n NdotL = pow(NdotL, 1.5); // Less physically accurate, but hides the \"seams\" between lights better\n\n var NdotV: f32 = mdot(N, V);\n var LdotV: f32 = mdot(L, V);\n\n var s: f32 = LdotV - NdotL*NdotV;\n var t: f32 = mix(1, max(NdotL, NdotV), step(0, s)); // Mix with step is the equivalent of an if statement\n var A: vec3<f32> = 0.5*(o2 / (o2 + 0.33)) + 0.17*p*(o2 / (o2 + 0.13));\n A = invpi*(1 - A);\n var B: f32 = 0.45*(o2 / (o2 + 0.09));\n B = invpi*B;\n\n return p*NdotL*(A + B*(s/t));\n}\n\n// Fresnel portion of BRDF (IOR only, simplified)\nfn schlickFresnelIOR(V: vec3<f32>, N: vec3<f32>, ior: f32, k: f32) -> f32 {\n var NdotV: f32 = mdot(V, N);\n var F0: f32 = (pow((ior - 1.0), 2) + k*k) / (pow((ior + 1.0), 2) + k*k); // This takes into account the roughness, which the other one does not\n return F0 + (1 - F0) * pow((1-NdotV), 5); \n}\n\n// Fresnel portion of BRDF (Color ior, better)\nfn schlickFresnelRGB(V: vec3<f32>, N: vec3<f32>, F0: vec3<f32>) -> vec3<f32> {\n var NdotV: f32 = mdot(V, N);\n return F0 + (1 - F0) * pow((1-NdotV), 5); \n}\n\n// Normal portion of BRDF\n// https://learnopengl.com/PBR/Theory\n// Trowbridge-Reitz GGX functions: normal, halfway, roughness^2\nfn trGGX(N: vec3<f32>, H: vec3<f32>, a: f32) -> f32 {\n var pi: f32 = 3.14159265359; \n\n var a2: f32 = a*a;\n var NdotH = mdot(N, H);\n var NdotH2 = NdotH*NdotH;\n \n var denom: f32 = NdotH2 * (a2 - 1.0) + 1.0;\n\n return a2 / max((pi*denom*denom), 0.000001);\n}\n\n// A VERY bad approximation of anisotropy. Real anisotropic calculations require tangent and bitangent\nfn anisotrophicTrGGX(N: vec3<f32>, H: vec3<f32>, O: vec3<f32>, s: f32, a: f32) -> f32 {\n var Op: vec3<f32> = (rendererUBO.WCVCNormals * vec4<f32>(normalize(O) * s, 0.)).xyz;\n\n var ggx1: f32 = trGGX(N + Op*s, H, a);\n var ggx2: f32 = trGGX(N - Op*s, H, a);\n return (0.5 * ggx1 + 0.5 * ggx2);\n}\n\n// Geometry portion of BRDF\nfn schlickGGX(N: vec3<f32>, X: vec3<f32>, k: f32) -> f32 {\n var NdotX = cdot(N, X);\n return NdotX / max(0.000001, (NdotX*(1-k) + k));\n}\n\nfn smithSurfaceRoughness(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>, k: f32) -> f32 {\n var ggx1: f32 = min(1, schlickGGX(N, V, k));\n var ggx2: f32 = min(1, schlickGGX(N, L, k));\n return ggx1*ggx2;\n}\n\n// BRDF Combination\nfn cookTorrance(D: f32, F: f32, G: f32, N: vec3<f32>, V: vec3<f32>, L: vec3<f32>) -> f32 {\n var num: f32 = D*F*G;\n var denom: f32 = 4*cdot(V, N)*cdot(L, N);\n\n return num / max(denom, 0.000001);\n}\n\n// Different lighting calculations for different light sources\nfn calcDirectionalLight(N: vec3<f32>, V: vec3<f32>, ior: f32, roughness: f32, metallic: f32, direction: vec3<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData { \n var L: vec3<f32> = normalize(direction); // Light Vector\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2;\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); // Fresnel term is replaced with 1 because it is added later\n var incoming: vec3<f32> = color;\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5);\n\n var specular: vec3<f32> = brdf*incoming*angle;\n // 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\n // control property for the diffuse vs specular roughness\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V); \n // Stores the specular and diffuse separately to allow for finer post processing\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// TODO: find some way to reduce the number of arguments going in here\nfn 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 {\n var L: vec3<f32> = normalize(position - fragPos); // Light Vector\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n var dist = distance(position, fragPos);\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2; // could also be pow(alpha + 1.0, 2) / 8\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); \n var incoming: vec3<f32> = color * (1. / (dist*dist));\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly \"seams\" bewteen light sources\n\n var specular: vec3<f32> = brdf*incoming*angle;\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);\n\n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// For a reason unknown to me, spheres dont seem to behave propperly with head-on spot lights\nfn 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 {\n var L: vec3<f32> = normalize(position - fragPos);\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n var dist = distance(position, fragPos);\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2; // could also be pow(alpha + 1.0, 2) / 8\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); \n \n // Cones.x is the inner phi and cones.y is the outer phi\n var theta: f32 = mdot(normalize(direction), L);\n var epsilon: f32 = cones.x - cones.y;\n var intensity: f32 = (theta - cones.y) / epsilon;\n intensity = clamp(intensity, 0.0, 1.0);\n intensity /= dist*dist;\n\n var incoming: vec3<f32> = color * intensity;\n\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly \"seams\" bewteen light sources\n\n var specular: vec3<f32> = brdf*incoming*angle;\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);\n\n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// Environment mapping stuff\n// Takes in a vector and converts it to an equivalent coordinate in a rectilinear texture. Should be replaced with cubemaps at some point\nfn vecToRectCoord(dir: vec3<f32>) -> vec2<f32> {\n var tau: f32 = 6.28318530718;\n var pi: f32 = 3.14159265359;\n var out: vec2<f32> = vec2<f32>(0.0);\n\n out.x = atan2(dir.z, dir.x) / tau;\n out.x += 0.5;\n\n var phix: f32 = length(vec2(dir.x, dir.z));\n out.y = atan2(dir.y, phix) / pi + 0.5;\n\n return out;\n}\n\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n//VTK::TCoord::Dec\n\n// optional surface normal declaration\n//VTK::Normal::Dec\n\n//VTK::Select::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : fragmentOutput;\n\n // Temporary ambient, diffuse, and opacity\n var ambientColor: vec4<f32> = mapperUBO.AmbientColor;\n var diffuseColor: vec4<f32> = mapperUBO.DiffuseColor;\n var opacity: f32 = mapperUBO.Opacity;\n\n // This should be declared somewhere else\n var _diffuseMap: vec4<f32> = vec4<f32>(1);\n var _roughnessMap: vec4<f32> = vec4<f32>(1);\n var _metallicMap: vec4<f32> = vec4<f32>(1);\n var _normalMap: vec4<f32> = vec4<f32>(0, 0, 1, 0); // normal map was setting off the normal vector detection in fragment\n var _ambientOcclusionMap: vec4<f32> = vec4<f32>(1);\n var _emissionMap: vec4<f32> = vec4<f32>(0);\n\n //VTK::Color::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::Normal::Impl\n\n var computedColor: vec4<f32> = vec4<f32>(diffuseColor.rgb, 1.0);\n\n //VTK::Light::Impl\n\n //VTK::Select::Impl\n\n if (computedColor.a == 0.0) { discard; };\n\n //VTK::Position::Impl\n\n //VTK::RenderEncoder::Impl\n\n return output;\n}\n";
|
|
22
22
|
|
|
23
23
|
function isEdges(hash) {
|
|
24
24
|
// edge pipelines have "edge" in them
|
|
@@ -209,7 +209,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
209
209
|
code = fDesc.getCode();
|
|
210
210
|
|
|
211
211
|
if (actor.getProperty().getNormalTexture()) {
|
|
212
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [' var normal: vec3<f32> = input.normalVC;', ' if (!input.frontFacing) { normal = -normal; }', ' var tangent: vec3<f32> = input.tangentVC;', ' var bitangent: vec3<f32> = input.bitangentVC;', ' var TCVCMatrix: mat3x3<f32> = mat3x3<f32>(', ' tangent.x, bitangent.x, normal.x,', ' tangent.y, bitangent.y, normal.y,', ' tangent.z, bitangent.z, normal.z,', ' );', '
|
|
212
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [' var normal: vec3<f32> = input.normalVC;', ' if (!input.frontFacing) { normal = -normal; }', ' var tangent: vec3<f32> = input.tangentVC;', ' var bitangent: vec3<f32> = input.bitangentVC;', ' var TCVCMatrix: mat3x3<f32> = mat3x3<f32>(', ' tangent.x, bitangent.x, normal.x,', ' tangent.y, bitangent.y, normal.y,', ' tangent.z, bitangent.z, normal.z,', ' );', ' var mappedNormal: vec3<f32> = TCVCMatrix * (_normalMap.xyz * 2 - 1);', ' normal = mix(normal, mappedNormal, mapperUBO.NormalStrength);', ' normal = normalize(normal);']).result;
|
|
213
213
|
} else {
|
|
214
214
|
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [' var normal: vec3<f32> = input.normalVC;', ' if (!input.frontFacing) { normal = -normal; }', ' normal = normalize(normal);']).result;
|
|
215
215
|
}
|
|
@@ -225,18 +225,30 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
225
225
|
if (hash.includes('sel')) return;
|
|
226
226
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
227
227
|
if (!vDesc.hasOutput('vertexVC')) vDesc.addOutput('vec4<f32>', 'vertexVC');
|
|
228
|
+
var renderer = model.WebGPURenderer.getRenderable();
|
|
228
229
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
229
230
|
var code = fDesc.getCode(); // Code that runs if the fragment shader includes normals
|
|
230
231
|
|
|
231
232
|
if (code.includes('var normal:') && model.useRendererMatrix && !isEdges(hash) && !model.is2D && !hash.includes('sel')) {
|
|
232
|
-
|
|
233
|
+
var _renderer$getEnvironm;
|
|
234
|
+
|
|
235
|
+
var lightingCode = [// Constants
|
|
233
236
|
' var pi: f32 = 3.14159265359;', // Vectors needed for light calculations
|
|
234
237
|
' 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', // Values needed for light calculations
|
|
235
238
|
' var baseColor: vec3<f32> = _diffuseMap.rgb * diffuseColor.rgb;', ' var roughness: f32 = max(0.000001, mapperUBO.Roughness * _roughnessMap.r);', // Need to have a different way of sampling greyscale values aside from .r
|
|
236
239
|
' var metallic: f32 = mapperUBO.Metallic * _metallicMap.r;', ' var alpha: f32 = roughness*roughness;', ' var ior: f32 = mapperUBO.BaseIOR;', ' var k: f32 = alpha*alpha / 2;', // Split diffuse and specular components
|
|
237
240
|
' var diffuse: vec3<f32> = vec3<f32>(0.);', ' var specular: vec3<f32> = vec3<f32>(0.);', ' var emission: vec3<f32> = _emissionMap.rgb * mapperUBO.Emission;', // Summing diffuse and specular components of directional lights
|
|
238
241
|
' {', ' 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++; }', ' }', ' }', // Final variables for combining specular and diffuse
|
|
239
|
-
' var fresnel: f32 = schlickFresnelIOR(V, normal, ior, k); // Fresnel', ' fresnel = min(1, 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), 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);']
|
|
242
|
+
' var fresnel: f32 = schlickFresnelIOR(V, normal, ior, k); // Fresnel', ' fresnel = min(1, 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), 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);'];
|
|
243
|
+
|
|
244
|
+
if ((_renderer$getEnvironm = renderer.getEnvironmentTexture()) !== null && _renderer$getEnvironm !== void 0 && _renderer$getEnvironm.getImageLoaded()) {
|
|
245
|
+
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);', // Level multiplier should be set by UBO
|
|
246
|
+
' var level = roughness * rendererUBO.MaxEnvironmentMipLevel;', ' var specularIBL = textureSampleLevel(EnvironmentTexture, EnvironmentTextureSampler, specularCoords, level);', // Manual mip smoothing since not all formats support smooth level sampling
|
|
247
|
+
' 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;', // Multipy by baseColor may be changed
|
|
248
|
+
' computedColor += vec4<f32>(diffuseIBLContribution*kD, 0);');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', lightingCode).result;
|
|
240
252
|
fDesc.setCode(code); // If theres no normals, just set the specular color to be flat
|
|
241
253
|
} else {
|
|
242
254
|
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;
|
|
@@ -287,8 +299,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
287
299
|
var numComp = vtkWebGPUTypes.getNumberOfComponentsFromBufferFormat(tcoords.getArrayInformation()[0].format);
|
|
288
300
|
var code = vDesc.getCode();
|
|
289
301
|
vDesc.addOutput("vec".concat(numComp, "<f32>"), 'tcoordVS');
|
|
290
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::TCoord::Impl', [' output.tcoordVS = tcoord;'
|
|
291
|
-
]).result;
|
|
302
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::TCoord::Impl', [' output.tcoordVS = tcoord;']).result;
|
|
292
303
|
vDesc.setCode(code);
|
|
293
304
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
294
305
|
code = fDesc.getCode();
|
|
@@ -568,7 +579,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
568
579
|
};
|
|
569
580
|
|
|
570
581
|
publicAPI.updateTextures = function () {
|
|
571
|
-
var _model$renderable$get2, _model$renderable2, _actor$getProperty$ge14, _actor$getProperty8, _actor$getProperty$ge15, _actor$getProperty9, _actor$getProperty$ge16, _actor$getProperty10, _actor$getProperty$ge17, _actor$getProperty11, _actor$getProperty$ge18, _actor$getProperty12, _actor$getProperty$ge19, _actor$getProperty13, _renderer$
|
|
582
|
+
var _model$renderable$get2, _model$renderable2, _actor$getProperty$ge14, _actor$getProperty8, _actor$getProperty$ge15, _actor$getProperty9, _actor$getProperty$ge16, _actor$getProperty10, _actor$getProperty$ge17, _actor$getProperty11, _actor$getProperty$ge18, _actor$getProperty12, _actor$getProperty$ge19, _actor$getProperty13, _renderer$getEnvironm2;
|
|
572
583
|
|
|
573
584
|
// we keep track of new and used textures so
|
|
574
585
|
// that we can clean up any unused textures so we don't hold onto them
|
|
@@ -634,8 +645,8 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
634
645
|
textures.push(_pair7);
|
|
635
646
|
}
|
|
636
647
|
|
|
637
|
-
if ((_renderer$
|
|
638
|
-
var _pair8 = ['
|
|
648
|
+
if ((_renderer$getEnvironm2 = renderer.getEnvironmentTexture) !== null && _renderer$getEnvironm2 !== void 0 && _renderer$getEnvironm2.call(renderer)) {
|
|
649
|
+
var _pair8 = ['Environment', renderer.getEnvironmentTexture()];
|
|
639
650
|
textures.push(_pair8);
|
|
640
651
|
}
|
|
641
652
|
|
|
@@ -671,10 +682,29 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
671
682
|
model.textures.push(newTex);
|
|
672
683
|
model.textureViews.push(tview);
|
|
673
684
|
var interpolate = srcTexture.getInterpolate() ? 'linear' : 'nearest';
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
685
|
+
var addressMode = null;
|
|
686
|
+
if (!addressMode && srcTexture.getEdgeClamp() && srcTexture.getRepeat()) addressMode = 'mirror-repeat';
|
|
687
|
+
if (!addressMode && srcTexture.getEdgeClamp()) addressMode = 'clamp-to-edge';
|
|
688
|
+
if (!addressMode && srcTexture.getRepeat()) addressMode = 'repeat';
|
|
689
|
+
|
|
690
|
+
if (textureName !== 'Environment') {
|
|
691
|
+
tview.addSampler(model.device, {
|
|
692
|
+
addressModeU: addressMode,
|
|
693
|
+
addressModeV: addressMode,
|
|
694
|
+
addressModeW: addressMode,
|
|
695
|
+
minFilter: interpolate,
|
|
696
|
+
magFilter: interpolate
|
|
697
|
+
});
|
|
698
|
+
} else {
|
|
699
|
+
tview.addSampler(model.device, {
|
|
700
|
+
addressModeU: 'repeat',
|
|
701
|
+
addressModeV: 'clamp-to-edge',
|
|
702
|
+
addressModeW: 'repeat',
|
|
703
|
+
minFilter: interpolate,
|
|
704
|
+
magFilter: interpolate,
|
|
705
|
+
mipmapFilter: 'linear'
|
|
706
|
+
});
|
|
707
|
+
}
|
|
678
708
|
}
|
|
679
709
|
}
|
|
680
710
|
} // remove unused textures
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import macro from '../../macros.js';
|
|
2
|
+
import vtkWebGPUFullScreenQuad from './FullScreenQuad.js';
|
|
2
3
|
import vtkWebGPUOpaquePass from './OpaquePass.js';
|
|
3
4
|
import vtkWebGPUOrderIndepenentTranslucentPass from './OrderIndependentTranslucentPass.js';
|
|
5
|
+
import vtkWebGPURenderEncoder from './RenderEncoder.js';
|
|
4
6
|
import vtkWebGPUVolumePass from './VolumePass.js';
|
|
5
7
|
import vtkRenderPass from '../SceneGraph/RenderPass.js';
|
|
8
|
+
import vtkWebGPUSampler from './Sampler.js';
|
|
9
|
+
import vtkWebGPUTextureView from './TextureView.js';
|
|
10
|
+
|
|
11
|
+
var finalBlitFragTemplate = "\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = clamp(textureSampleLevel(opaquePassColorTexture, finalPassSampler, input.tcoordVS, 0),vec4<f32>(0.0),vec4<f32>(1.0));\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n"; // ----------------------------------------------------------------------------
|
|
6
12
|
|
|
7
13
|
function vtkForwardPass(publicAPI, model) {
|
|
8
14
|
// Set our className
|
|
@@ -69,24 +75,96 @@ function vtkForwardPass(publicAPI, model) {
|
|
|
69
75
|
model.volumePass.setDepthTextureView(model.opaquePass.getDepthTextureView());
|
|
70
76
|
model.volumePass.setVolumes(model.volumes);
|
|
71
77
|
model.volumePass.traverse(renNode, viewNode);
|
|
72
|
-
}
|
|
78
|
+
} // blit the result into the swap chain
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
publicAPI.finalPass(viewNode, renNode);
|
|
73
82
|
}
|
|
74
83
|
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
publicAPI.finalPass = function (viewNode, renNode) {
|
|
88
|
+
if (!model._finalBlitEncoder) {
|
|
89
|
+
publicAPI.createFinalBlitEncoder(viewNode);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
model._finalBlitOutputTextureView.createFromTextureHandle(viewNode.getCurrentTexture(), {
|
|
93
|
+
depth: 1,
|
|
94
|
+
format: viewNode.getPresentationFormat()
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
model._finalBlitEncoder.attachTextureViews();
|
|
98
|
+
|
|
99
|
+
model._finalBlitEncoder.begin(viewNode.getCommandEncoder());
|
|
100
|
+
|
|
101
|
+
renNode.scissorAndViewport(model._finalBlitEncoder);
|
|
102
|
+
|
|
103
|
+
model._fullScreenQuad.prepareAndDraw(model._finalBlitEncoder);
|
|
104
|
+
|
|
105
|
+
model._finalBlitEncoder.end();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
publicAPI.createFinalBlitEncoder = function (viewNode) {
|
|
109
|
+
model._finalBlitEncoder = vtkWebGPURenderEncoder.newInstance({
|
|
110
|
+
label: 'forwardPassBlit'
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
model._finalBlitEncoder.setDescription({
|
|
114
|
+
colorAttachments: [{
|
|
115
|
+
view: null,
|
|
116
|
+
loadOp: 'load',
|
|
117
|
+
storeOp: 'store'
|
|
118
|
+
}]
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
model._finalBlitEncoder.setPipelineHash('fpf');
|
|
122
|
+
|
|
123
|
+
model._finalBlitEncoder.setPipelineSettings({
|
|
124
|
+
primitive: {
|
|
125
|
+
cullMode: 'none'
|
|
126
|
+
},
|
|
127
|
+
fragment: {
|
|
128
|
+
targets: [{
|
|
129
|
+
format: viewNode.getPresentationFormat(),
|
|
130
|
+
blend: {
|
|
131
|
+
color: {
|
|
132
|
+
srcFactor: 'src-alpha',
|
|
133
|
+
dstFactor: 'one-minus-src-alpha'
|
|
134
|
+
},
|
|
135
|
+
alpha: {
|
|
136
|
+
srcfactor: 'one',
|
|
137
|
+
dstFactor: 'one-minus-src-alpha'
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}]
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
model._fsqSampler = vtkWebGPUSampler.newInstance({
|
|
145
|
+
label: 'finalPassSampler'
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
model._fsqSampler.create(viewNode.getDevice(), {
|
|
149
|
+
minFilter: 'linear',
|
|
150
|
+
magFilter: 'linear'
|
|
89
151
|
});
|
|
152
|
+
|
|
153
|
+
model._fullScreenQuad = vtkWebGPUFullScreenQuad.newInstance();
|
|
154
|
+
|
|
155
|
+
model._fullScreenQuad.setDevice(viewNode.getDevice());
|
|
156
|
+
|
|
157
|
+
model._fullScreenQuad.setPipelineHash('fpfsq');
|
|
158
|
+
|
|
159
|
+
model._fullScreenQuad.setTextureViews([model.opaquePass.getColorTextureView()]);
|
|
160
|
+
|
|
161
|
+
model._fullScreenQuad.setAdditionalBindables([model._fsqSampler]);
|
|
162
|
+
|
|
163
|
+
model._fullScreenQuad.setFragmentShaderTemplate(finalBlitFragTemplate);
|
|
164
|
+
|
|
165
|
+
model._finalBlitOutputTextureView = vtkWebGPUTextureView.newInstance();
|
|
166
|
+
|
|
167
|
+
model._finalBlitEncoder.setColorTextureView(0, model._finalBlitOutputTextureView);
|
|
90
168
|
};
|
|
91
169
|
|
|
92
170
|
publicAPI.incrementOpaqueActorCount = function () {
|
|
@@ -12,8 +12,9 @@ function vtkWebGPUFullScreenQuad(publicAPI, model) {
|
|
|
12
12
|
publicAPI.replaceShaderPosition = function (hash, pipeline, vertexInput) {
|
|
13
13
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
14
14
|
vDesc.addBuiltinOutput('vec4<f32>', '@builtin(position) Position');
|
|
15
|
+
vDesc.addOutput('vec4<f32>', 'vertexVC');
|
|
15
16
|
var code = vDesc.getCode();
|
|
16
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', ['output.tcoordVS = vec2<f32>(vertexBC.x * 0.5 + 0.5, 1.0 - vertexBC.y * 0.5 - 0.5);', 'output.Position = vec4<f32>(vertexBC, 1.0);']).result;
|
|
17
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', ['output.tcoordVS = vec2<f32>(vertexBC.x * 0.5 + 0.5, 1.0 - vertexBC.y * 0.5 - 0.5);', 'output.Position = vec4<f32>(vertexBC, 1.0);', 'output.vertexVC = vec4<f32>(vertexBC, 1);']).result;
|
|
17
18
|
vDesc.setCode(code);
|
|
18
19
|
};
|
|
19
20
|
|
|
@@ -51,9 +51,11 @@ function vtkWebGPURenderEncoder(publicAPI, model) {
|
|
|
51
51
|
console.trace();
|
|
52
52
|
} else {
|
|
53
53
|
for (var i = 0; i < model.colorTextureViews.length; i++) {
|
|
54
|
-
var
|
|
54
|
+
var _model$colorTextureVi;
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
var fmt = (_model$colorTextureVi = model.colorTextureViews[i].getTexture()) === null || _model$colorTextureVi === void 0 ? void 0 : _model$colorTextureVi.getFormat();
|
|
57
|
+
|
|
58
|
+
if (fmt && fmt !== pd.fragment.targets[i].format) {
|
|
57
59
|
console.log("mismatched attachments for attachment ".concat(i, " on pipeline ").concat(pd.fragment.targets[i].format, " while encoder has ").concat(fmt));
|
|
58
60
|
console.trace();
|
|
59
61
|
}
|
|
@@ -65,9 +67,11 @@ function vtkWebGPURenderEncoder(publicAPI, model) {
|
|
|
65
67
|
console.log('mismatched depth attachments');
|
|
66
68
|
console.trace();
|
|
67
69
|
} else if (model.depthTextureView) {
|
|
68
|
-
var
|
|
70
|
+
var _model$depthTextureVi;
|
|
71
|
+
|
|
72
|
+
var dfmt = (_model$depthTextureVi = model.depthTextureView.getTexture()) === null || _model$depthTextureVi === void 0 ? void 0 : _model$depthTextureVi.getFormat();
|
|
69
73
|
|
|
70
|
-
if (dfmt !== pd.depthStencil.format) {
|
|
74
|
+
if (dfmt && dfmt !== pd.depthStencil.format) {
|
|
71
75
|
console.log("mismatched depth attachments on pipeline ".concat(pd.depthStencil.format, " while encoder has ").concat(dfmt));
|
|
72
76
|
console.trace();
|
|
73
77
|
}
|
|
@@ -202,7 +206,7 @@ function extend(publicAPI, model) {
|
|
|
202
206
|
},
|
|
203
207
|
fragment: {
|
|
204
208
|
targets: [{
|
|
205
|
-
format: '
|
|
209
|
+
format: 'rgba16float',
|
|
206
210
|
blend: {
|
|
207
211
|
color: {
|
|
208
212
|
srcFactor: 'src-alpha',
|
|
@@ -9,6 +9,7 @@ import vtkWebGPUHardwareSelector from './HardwareSelector.js';
|
|
|
9
9
|
import vtkWebGPUViewNodeFactory from './ViewNodeFactory.js';
|
|
10
10
|
import vtkRenderPass from '../SceneGraph/RenderPass.js';
|
|
11
11
|
import vtkRenderWindowViewNode from '../SceneGraph/RenderWindowViewNode.js';
|
|
12
|
+
import HalfFloat from '../../Common/Core/HalfFloat.js';
|
|
12
13
|
|
|
13
14
|
var vtkErrorMacro = macro.vtkErrorMacro; // const IS_CHROME = navigator.userAgent.indexOf('Chrome') !== -1;
|
|
14
15
|
|
|
@@ -67,14 +68,14 @@ function vtkWebGPURenderWindow(publicAPI, model) {
|
|
|
67
68
|
publicAPI.recreateSwapChain = function () {
|
|
68
69
|
if (model.context) {
|
|
69
70
|
model.context.unconfigure();
|
|
70
|
-
|
|
71
|
+
model.presentationFormat = navigator.gpu.getPreferredCanvasFormat(model.adapter);
|
|
71
72
|
/* eslint-disable no-undef */
|
|
72
73
|
|
|
73
74
|
/* eslint-disable no-bitwise */
|
|
74
75
|
|
|
75
76
|
model.context.configure({
|
|
76
77
|
device: model.device.getHandle(),
|
|
77
|
-
format: presentationFormat,
|
|
78
|
+
format: model.presentationFormat,
|
|
78
79
|
alphaMode: 'premultiplied',
|
|
79
80
|
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_DST,
|
|
80
81
|
width: model.size[0],
|
|
@@ -545,10 +546,10 @@ function vtkWebGPURenderWindow(publicAPI, model) {
|
|
|
545
546
|
result = {
|
|
546
547
|
width: texture.getWidth(),
|
|
547
548
|
height: texture.getHeight()
|
|
548
|
-
}; // must be a multiple of 256 bytes, so
|
|
549
|
+
}; // must be a multiple of 256 bytes, so 32 texels with rgba16
|
|
549
550
|
|
|
550
|
-
result.colorBufferWidth =
|
|
551
|
-
result.colorBufferSizeInBytes = result.colorBufferWidth * result.height *
|
|
551
|
+
result.colorBufferWidth = 32 * Math.floor((result.width + 31) / 32);
|
|
552
|
+
result.colorBufferSizeInBytes = result.colorBufferWidth * result.height * 8;
|
|
552
553
|
colorBuffer = vtkWebGPUBuffer.newInstance();
|
|
553
554
|
colorBuffer.setDevice(device);
|
|
554
555
|
/* eslint-disable no-bitwise */
|
|
@@ -565,7 +566,7 @@ function vtkWebGPURenderWindow(publicAPI, model) {
|
|
|
565
566
|
texture: texture.getHandle()
|
|
566
567
|
}, {
|
|
567
568
|
buffer: colorBuffer.getHandle(),
|
|
568
|
-
bytesPerRow:
|
|
569
|
+
bytesPerRow: 8 * result.colorBufferWidth,
|
|
569
570
|
rowsPerImage: result.height
|
|
570
571
|
}, {
|
|
571
572
|
width: result.width,
|
|
@@ -581,7 +582,7 @@ function vtkWebGPURenderWindow(publicAPI, model) {
|
|
|
581
582
|
|
|
582
583
|
case 14:
|
|
583
584
|
/* eslint-enable no-undef */
|
|
584
|
-
result.colorValues = new
|
|
585
|
+
result.colorValues = new Uint16Array(colorBuffer.getMappedRange().slice());
|
|
585
586
|
colorBuffer.unmap(); // repack the array
|
|
586
587
|
|
|
587
588
|
tmparray = new Uint8ClampedArray(result.height * result.width * 4);
|
|
@@ -590,10 +591,10 @@ function vtkWebGPURenderWindow(publicAPI, model) {
|
|
|
590
591
|
for (x = 0; x < result.width; x++) {
|
|
591
592
|
doffset = (y * result.width + x) * 4;
|
|
592
593
|
soffset = (y * result.colorBufferWidth + x) * 4;
|
|
593
|
-
tmparray[doffset] = result.colorValues[soffset
|
|
594
|
-
tmparray[doffset + 1] = result.colorValues[soffset + 1];
|
|
595
|
-
tmparray[doffset + 2] = result.colorValues[soffset];
|
|
596
|
-
tmparray[doffset + 3] = result.colorValues[soffset + 3];
|
|
594
|
+
tmparray[doffset] = 255.0 * HalfFloat.fromHalf(result.colorValues[soffset]);
|
|
595
|
+
tmparray[doffset + 1] = 255.0 * HalfFloat.fromHalf(result.colorValues[soffset + 1]);
|
|
596
|
+
tmparray[doffset + 2] = 255.0 * HalfFloat.fromHalf(result.colorValues[soffset + 2]);
|
|
597
|
+
tmparray[doffset + 3] = 255.0 * HalfFloat.fromHalf(result.colorValues[soffset + 3]);
|
|
597
598
|
}
|
|
598
599
|
}
|
|
599
600
|
|
|
@@ -635,7 +636,8 @@ var DEFAULT_VALUES = {
|
|
|
635
636
|
useOffScreen: false,
|
|
636
637
|
useBackgroundImage: false,
|
|
637
638
|
nextPropID: 1,
|
|
638
|
-
xrSupported: false
|
|
639
|
+
xrSupported: false,
|
|
640
|
+
presentationFormat: null
|
|
639
641
|
}; // ----------------------------------------------------------------------------
|
|
640
642
|
|
|
641
643
|
function extend(publicAPI, model) {
|
|
@@ -671,7 +673,7 @@ function extend(publicAPI, model) {
|
|
|
671
673
|
macro.event(publicAPI, model, 'imageReady');
|
|
672
674
|
macro.event(publicAPI, model, 'initialized'); // Build VTK API
|
|
673
675
|
|
|
674
|
-
macro.get(publicAPI, model, ['commandEncoder', 'device', 'useBackgroundImage', 'xrSupported']);
|
|
676
|
+
macro.get(publicAPI, model, ['commandEncoder', 'device', 'presentationFormat', 'useBackgroundImage', 'xrSupported']);
|
|
675
677
|
macro.setGet(publicAPI, model, ['initialized', 'context', 'canvas', 'device', 'renderPasses', 'notifyStartCaptureImage', 'cursor', 'useOffScreen']);
|
|
676
678
|
macro.setGetArray(publicAPI, model, ['size'], 2); // Object methods
|
|
677
679
|
|
|
@@ -9,7 +9,12 @@ import vtkWebGPUUniformBuffer from './UniformBuffer.js';
|
|
|
9
9
|
import { registerOverride } from './ViewNodeFactory.js';
|
|
10
10
|
|
|
11
11
|
var vtkDebugMacro = vtkDebugMacro$1;
|
|
12
|
-
var
|
|
12
|
+
var clearFragColorTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = mapperUBO.BackgroundColor;\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
|
|
13
|
+
var clearFragTextureTemplate = "\nfn vecToRectCoord(dir: vec3<f32>) -> vec2<f32> {\n var tau: f32 = 6.28318530718;\n var pi: f32 = 3.14159265359;\n var out: vec2<f32> = vec2<f32>(0.0);\n\n out.x = atan2(dir.z, dir.x) / tau;\n out.x += 0.5;\n\n var phix: f32 = length(vec2(dir.x, dir.z));\n out.y = atan2(dir.y, phix) / pi + 0.5;\n\n return out;\n}\n\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var tcoord: vec4<f32> = vec4<f32>(input.vertexVC.xy, -1, 1);\n var V: vec4<f32> = normalize(mapperUBO.FSQMatrix * tcoord); // vec2<f32>((input.tcoordVS.x - 0.5) * 2, -(input.tcoordVS.y - 0.5) * 2);\n // textureSampleLevel gets rid of some ugly artifacts\n var background = textureSampleLevel(EnvironmentTexture, EnvironmentTextureSampler, vecToRectCoord(V.xyz), 0);\n var computedColor: vec4<f32> = vec4<f32>(background.rgb, 1);\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
|
|
14
|
+
|
|
15
|
+
var _fsqClearMat4 = new Float64Array(16);
|
|
16
|
+
|
|
17
|
+
var _tNormalMat4 = new Float64Array(16); // Light type index gives either 0, 1, or 2 which indicates what type of light there is.
|
|
13
18
|
// While technically, there are only spot and directional lights, within the CellArrayMapper
|
|
14
19
|
// there is a third, positional light. It is technically just a variant of a spot light with
|
|
15
20
|
// a cone angle of 90 or above, however certain calculations can be skipped if it is treated
|
|
@@ -19,6 +24,7 @@ var clearFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::
|
|
|
19
24
|
// 1 -> directional light
|
|
20
25
|
// 2 -> spot light
|
|
21
26
|
|
|
27
|
+
|
|
22
28
|
function getLightTypeIndex(light) {
|
|
23
29
|
if (light.getPositional()) {
|
|
24
30
|
if (light.getConeAngle() >= 90) {
|
|
@@ -124,6 +130,8 @@ function vtkWebGPURenderer(publicAPI, model) {
|
|
|
124
130
|
var utime = model.UBO.getSendTime();
|
|
125
131
|
|
|
126
132
|
if (model._parent.getMTime() > utime || publicAPI.getMTime() > utime || model.camera.getMTime() > utime || model.renderable.getMTime() > utime) {
|
|
133
|
+
var _model$renderable$get;
|
|
134
|
+
|
|
127
135
|
var keyMats = model.webgpuCamera.getKeyMatrices(publicAPI);
|
|
128
136
|
model.UBO.setArray('WCVCMatrix', keyMats.wcvc);
|
|
129
137
|
model.UBO.setArray('SCPCMatrix', keyMats.scpc);
|
|
@@ -132,6 +140,9 @@ function vtkWebGPURenderer(publicAPI, model) {
|
|
|
132
140
|
model.UBO.setArray('VCPCMatrix', keyMats.vcpc);
|
|
133
141
|
model.UBO.setArray('WCVCNormals', keyMats.normalMatrix);
|
|
134
142
|
model.UBO.setValue('LightCount', model.renderable.getLights().length);
|
|
143
|
+
model.UBO.setValue('MaxEnvironmentMipLevel', (_model$renderable$get = model.renderable.getEnvironmentTexture()) === null || _model$renderable$get === void 0 ? void 0 : _model$renderable$get.getMipLevel());
|
|
144
|
+
model.UBO.setValue('BackgroundDiffuseStrength', model.renderable.getEnvironmentTextureDiffuseStrength());
|
|
145
|
+
model.UBO.setValue('BackgroundSpecularStrength', model.renderable.getEnvironmentTextureSpecularStrength());
|
|
135
146
|
var tsize = publicAPI.getYInvertedTiledSizeAndOrigin();
|
|
136
147
|
model.UBO.setArray('viewportSize', [tsize.usize, tsize.vsize]);
|
|
137
148
|
model.UBO.setValue('cameraParallel', model.camera.getParallelProjection());
|
|
@@ -162,8 +173,7 @@ function vtkWebGPURenderer(publicAPI, model) {
|
|
|
162
173
|
|
|
163
174
|
var viewCoordinatePosition = lights[_i].getPosition();
|
|
164
175
|
|
|
165
|
-
vec3.transformMat4(viewCoordinatePosition, viewCoordinatePosition, keyMats.wcvc); //
|
|
166
|
-
// viewCoordinatePosition
|
|
176
|
+
vec3.transformMat4(viewCoordinatePosition, viewCoordinatePosition, keyMats.wcvc); // viewCoordinatePosition
|
|
167
177
|
|
|
168
178
|
lightPosArray[offset] = viewCoordinatePosition[0];
|
|
169
179
|
lightPosArray[offset + 1] = viewCoordinatePosition[1];
|
|
@@ -240,26 +250,85 @@ function vtkWebGPURenderer(publicAPI, model) {
|
|
|
240
250
|
};
|
|
241
251
|
|
|
242
252
|
publicAPI.clear = function () {
|
|
253
|
+
var _model$backgroundTex;
|
|
254
|
+
|
|
243
255
|
if (model.renderable.getTransparent() || model.suppressClear) {
|
|
244
256
|
return;
|
|
245
257
|
}
|
|
246
258
|
|
|
247
|
-
var device = model._parent.getDevice();
|
|
259
|
+
var device = model._parent.getDevice(); // Normal Solid Color
|
|
260
|
+
|
|
248
261
|
|
|
249
262
|
if (!model.clearFSQ) {
|
|
250
263
|
model.clearFSQ = vtkWebGPUFullScreenQuad.newInstance();
|
|
251
264
|
model.clearFSQ.setDevice(device);
|
|
252
265
|
model.clearFSQ.setPipelineHash('clearfsq');
|
|
253
|
-
model.clearFSQ.setFragmentShaderTemplate(
|
|
266
|
+
model.clearFSQ.setFragmentShaderTemplate(clearFragColorTemplate);
|
|
254
267
|
var ubo = vtkWebGPUUniformBuffer.newInstance({
|
|
255
268
|
label: 'mapperUBO'
|
|
256
269
|
});
|
|
270
|
+
ubo.addEntry('FSQMatrix', 'mat4x4<f32>');
|
|
257
271
|
ubo.addEntry('BackgroundColor', 'vec4<f32>');
|
|
258
272
|
model.clearFSQ.setUBO(ubo);
|
|
273
|
+
model.backgroundTex = model.renderable.getEnvironmentTexture();
|
|
274
|
+
} // Textured Background
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
if (model.clearFSQ.getPipelineHash() !== 'clearfsqwithtexture' && model.renderable.getUseEnvironmentTextureAsBackground() && (_model$backgroundTex = model.backgroundTex) !== null && _model$backgroundTex !== void 0 && _model$backgroundTex.getImageLoaded()) {
|
|
278
|
+
model.clearFSQ.setFragmentShaderTemplate(clearFragTextureTemplate);
|
|
279
|
+
|
|
280
|
+
var _ubo = vtkWebGPUUniformBuffer.newInstance({
|
|
281
|
+
label: 'mapperUBO'
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
_ubo.addEntry('FSQMatrix', 'mat4x4<f32>');
|
|
285
|
+
|
|
286
|
+
_ubo.addEntry('BackgroundColor', 'vec4<f32>');
|
|
287
|
+
|
|
288
|
+
model.clearFSQ.setUBO(_ubo);
|
|
289
|
+
var environmentTextureHash = device.getTextureManager().getTextureForVTKTexture(model.backgroundTex);
|
|
290
|
+
|
|
291
|
+
if (environmentTextureHash.getReady()) {
|
|
292
|
+
var tview = environmentTextureHash.createView("EnvironmentTexture");
|
|
293
|
+
model.clearFSQ.setTextureViews([tview]);
|
|
294
|
+
model.backgroundTexLoaded = true;
|
|
295
|
+
var interpolate = model.backgroundTex.getInterpolate() ? 'linear' : 'nearest';
|
|
296
|
+
tview.addSampler(device, {
|
|
297
|
+
addressModeU: 'repeat',
|
|
298
|
+
addressModeV: 'clamp-to-edge',
|
|
299
|
+
addressModeW: 'repeat',
|
|
300
|
+
minFilter: interpolate,
|
|
301
|
+
magFilter: interpolate,
|
|
302
|
+
mipmapFilter: 'linear'
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
model.clearFSQ.setPipelineHash('clearfsqwithtexture');
|
|
307
|
+
} else if (model.clearFSQ.getPipelineHash() === 'clearfsqwithtexture' && !model.renderable.getUseEnvironmentTextureAsBackground()) {
|
|
308
|
+
// In case the mode is changed at runtime
|
|
309
|
+
model.clearFSQ = vtkWebGPUFullScreenQuad.newInstance();
|
|
310
|
+
model.clearFSQ.setDevice(device);
|
|
311
|
+
model.clearFSQ.setPipelineHash('clearfsq');
|
|
312
|
+
model.clearFSQ.setFragmentShaderTemplate(clearFragColorTemplate);
|
|
313
|
+
|
|
314
|
+
var _ubo2 = vtkWebGPUUniformBuffer.newInstance({
|
|
315
|
+
label: 'mapperUBO'
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
_ubo2.addEntry('FSQMatrix', 'mat4x4<f32>');
|
|
319
|
+
|
|
320
|
+
_ubo2.addEntry('BackgroundColor', 'vec4<f32>');
|
|
321
|
+
|
|
322
|
+
model.clearFSQ.setUBO(_ubo2);
|
|
259
323
|
}
|
|
260
324
|
|
|
325
|
+
var keyMats = model.webgpuCamera.getKeyMatrices(publicAPI);
|
|
261
326
|
var background = model.renderable.getBackgroundByReference();
|
|
262
327
|
model.clearFSQ.getUBO().setArray('BackgroundColor', background);
|
|
328
|
+
mat4.transpose(_tNormalMat4, keyMats.normalMatrix);
|
|
329
|
+
mat4.mul(_fsqClearMat4, keyMats.scvc, keyMats.pcsc);
|
|
330
|
+
mat4.mul(_fsqClearMat4, _tNormalMat4, _fsqClearMat4);
|
|
331
|
+
model.clearFSQ.getUBO().setArray('FSQMatrix', _fsqClearMat4);
|
|
263
332
|
model.clearFSQ.getUBO().sendIfNeeded(device);
|
|
264
333
|
model.clearFSQ.prepareAndDraw(model.renderEncoder);
|
|
265
334
|
};
|
|
@@ -395,6 +464,9 @@ function extend(publicAPI, model) {
|
|
|
395
464
|
model.UBO.addEntry('WCVCNormals', 'mat4x4<f32>');
|
|
396
465
|
model.UBO.addEntry('viewportSize', 'vec2<f32>');
|
|
397
466
|
model.UBO.addEntry('LightCount', 'i32');
|
|
467
|
+
model.UBO.addEntry('MaxEnvironmentMipLevel', 'f32');
|
|
468
|
+
model.UBO.addEntry('BackgroundDiffuseStrength', 'f32');
|
|
469
|
+
model.UBO.addEntry('BackgroundSpecularStrength', 'f32');
|
|
398
470
|
model.UBO.addEntry('cameraParallel', 'u32'); // SSBO (Light data)
|
|
399
471
|
|
|
400
472
|
model.SSBO = vtkWebGPUStorageBuffer.newInstance({
|
|
@@ -12,8 +12,12 @@ function vtkWebGPUSampler(publicAPI, model) {
|
|
|
12
12
|
publicAPI.create = function (device) {
|
|
13
13
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
14
14
|
model.device = device;
|
|
15
|
+
model.options.addressModeU = options.addressModeU ? options.addressModeU : 'clamp-to-edge';
|
|
16
|
+
model.options.addressModeV = options.addressModeV ? options.addressModeV : 'clamp-to-edge';
|
|
17
|
+
model.options.addressModeW = options.addressModeW ? options.addressModeW : 'clamp-to-edge';
|
|
15
18
|
model.options.magFilter = options.magFilter ? options.magFilter : 'nearest';
|
|
16
19
|
model.options.minFilter = options.minFilter ? options.minFilter : 'nearest';
|
|
20
|
+
model.options.mipmapFilter = options.mipmapFilter ? options.mipmapFilter : 'nearest';
|
|
17
21
|
model.options.label = model.label;
|
|
18
22
|
model.handle = model.device.getHandle().createSampler(model.options);
|
|
19
23
|
model.bindGroupTime.modified();
|