@kitware/vtk.js 22.1.8 → 22.2.3

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.
@@ -8,7 +8,7 @@ import { registerOverride } from './ViewNodeFactory.js';
8
8
  var BufferUsage = vtkWebGPUBufferManager.BufferUsage,
9
9
  PrimitiveTypes = vtkWebGPUBufferManager.PrimitiveTypes;
10
10
  var vtkErrorMacro = vtkErrorMacro$1;
11
- var vtkWebGPUSphereMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n[[stage(vertex)]]\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.x, vertexBC.y, vertexBC.z, 1.0);\n\n //VTK::Color::Impl\n\n // compute the projected vertex position\n output.centerVC = vertexVC.xyz;\n output.radiusVC = length(offsetMC)*0.5;\n\n // make the triangle face the camera\n if (rendererUBO.cameraParallel == 0u)\n {\n var dir: vec3<f32> = normalize(-vertexVC.xyz);\n var base2: vec3<f32> = normalize(cross(dir,vec3<f32>(1.0,0.0,0.0)));\n var base1: vec3<f32> = cross(base2,dir);\n dir = vertexVC.xyz + offsetMC.x*base1 + offsetMC.y*base2;\n vertexVC = vec4<f32>(dir, 1.0);\n }\n else\n {\n // add in the offset\n var tmp2: vec2<f32> = vertexVC.xy + offsetMC;\n vertexVC = vec4<f32>(tmp2, vertexVC.zw);\n }\n\n output.vertexVC = vertexVC.xyz;\n\n //VTK::Position::Impl\n\n return output;\n}\n"; // ----------------------------------------------------------------------------
11
+ var vtkWebGPUSphereMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n@stage(vertex)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.x, vertexBC.y, vertexBC.z, 1.0);\n\n //VTK::Color::Impl\n\n // compute the projected vertex position\n output.centerVC = vertexVC.xyz;\n output.radiusVC = length(offsetMC)*0.5;\n\n // make the triangle face the camera\n if (rendererUBO.cameraParallel == 0u)\n {\n var dir: vec3<f32> = normalize(-vertexVC.xyz);\n var base2: vec3<f32> = normalize(cross(dir,vec3<f32>(1.0,0.0,0.0)));\n var base1: vec3<f32> = cross(base2,dir);\n dir = vertexVC.xyz + offsetMC.x*base1 + offsetMC.y*base2;\n vertexVC = vec4<f32>(dir, 1.0);\n }\n else\n {\n // add in the offset\n var tmp2: vec2<f32> = vertexVC.xy + offsetMC;\n vertexVC = vec4<f32>(tmp2, vertexVC.zw);\n }\n\n output.vertexVC = vertexVC.xyz;\n\n //VTK::Position::Impl\n\n return output;\n}\n"; // ----------------------------------------------------------------------------
12
12
  // vtkWebGPUSphereMapper methods
13
13
  // ----------------------------------------------------------------------------
14
14
 
@@ -22,7 +22,7 @@ function vtkWebGPUSphereMapper(publicAPI, model) {
22
22
  vDesc.addOutput('vec3<f32>', 'centerVC');
23
23
  vDesc.addOutput('f32', 'radiusVC');
24
24
  var fDesc = pipeline.getShaderDescription('fragment');
25
- fDesc.addBuiltinOutput('f32', '[[builtin(frag_depth)]] fragDepth');
25
+ fDesc.addBuiltinOutput('f32', '@builtin(frag_depth) fragDepth');
26
26
  var sphereFrag = "\n // compute the eye position and unit direction\n var vertexVC: vec4<f32>;\n var EyePos: vec3<f32>;\n var EyeDir: vec3<f32>;\n var invertedDepth: f32 = 1.0;\n if (rendererUBO.cameraParallel != 0u) {\n EyePos = vec3<f32>(input.vertexVC.x, input.vertexVC.y, input.vertexVC.z + 3.0*input.radiusVC);\n EyeDir = vec3<f32>(0.0, 0.0, -1.0);\n }\n else {\n EyeDir = input.vertexVC.xyz;\n EyePos = vec3<f32>(0.0,0.0,0.0);\n var lengthED: f32 = length(EyeDir);\n EyeDir = normalize(EyeDir);\n // we adjust the EyePos to be closer if it is too far away\n // to prevent floating point precision noise\n if (lengthED > input.radiusVC*3.0) {\n EyePos = input.vertexVC.xyz - EyeDir*3.0*input.radiusVC;\n }\n }\n\n // translate to Sphere center\n EyePos = EyePos - input.centerVC;\n // scale to radius 1.0\n EyePos = EyePos * (1.0 / input.radiusVC);\n // find the intersection\n var b: f32 = 2.0*dot(EyePos,EyeDir);\n var c: f32 = dot(EyePos,EyePos) - 1.0;\n var d: f32 = b*b - 4.0*c;\n var normal: vec3<f32> = vec3<f32>(0.0,0.0,1.0);\n if (d < 0.0) { discard; }\n else {\n var t: f32 = (-b - invertedDepth*sqrt(d))*0.5;\n\n // compute the normal, for unit sphere this is just\n // the intersection point\n normal = invertedDepth*normalize(EyePos + t*EyeDir);\n // compute the intersection point in VC\n vertexVC = vec4<f32>(normal * input.radiusVC + input.centerVC, 1.0);\n }\n // compute the pixel's depth\n var pos: vec4<f32> = rendererUBO.VCPCMatrix * vertexVC;\n output.fragDepth = pos.z / pos.w;\n ";
27
27
  var code = fDesc.getCode();
28
28
  code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [sphereFrag]).result;
@@ -31,7 +31,7 @@ function vtkWebGPUSphereMapper(publicAPI, model) {
31
31
 
32
32
  publicAPI.replaceShaderPosition = function (hash, pipeline, vertexInput) {
33
33
  var vDesc = pipeline.getShaderDescription('vertex');
34
- vDesc.addBuiltinOutput('vec4<f32>', '[[builtin(position)]] Position');
34
+ vDesc.addBuiltinOutput('vec4<f32>', '@builtin(position) Position');
35
35
  var code = vDesc.getCode();
36
36
  code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', [' output.Position = rendererUBO.VCPCMatrix*vertexVC;']).result;
37
37
  vDesc.setCode(code);
@@ -27,7 +27,7 @@ var vtkErrorMacro = vtkErrorMacro$1; // Vertices
27
27
  // 4: 011
28
28
  // 5: 111
29
29
 
30
- var vtkWebGPUStickMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n[[stage(vertex)]]\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var offsetsArray: array<vec3<f32>, 12> = array<vec3<f32>, 12>(\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(-1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n vec3<f32>(-1.0, 1.0, 1.0)\n );\n\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.x, vertexBC.y, vertexBC.z, 1.0);\n\n //VTK::Color::Impl\n\n // compute the projected vertex position\n output.centerVC = vertexVC.xyz;\n output.radiusVC = radiusMC;\n output.lengthVC = length(orientMC);\n output.orientVC = (rendererUBO.WCVCNormals * vec4<f32>(normalize(orientMC), 0.0)).xyz;\n\n // make sure it is pointing out of the screen\n if (output.orientVC.z < 0.0)\n {\n output.orientVC = -output.orientVC;\n }\n\n // make the basis\n var xbase: vec3<f32>;\n var ybase: vec3<f32>;\n var dir: vec3<f32> = vec3<f32>(0.0,0.0,1.0);\n if (rendererUBO.cameraParallel == 0u)\n {\n dir = normalize(-vertexVC.xyz);\n }\n if (abs(dot(dir,output.orientVC)) == 1.0)\n {\n xbase = normalize(cross(vec3<f32>(0.0,1.0,0.0),output.orientVC));\n ybase = cross(xbase,output.orientVC);\n }\n else\n {\n xbase = normalize(cross(output.orientVC,dir));\n ybase = cross(output.orientVC,xbase);\n }\n\n\n var vertIdx: u32 = input.vertexIndex % 12u;\n var offsets: vec3<f32> = offsetsArray[vertIdx];\n\n vertexVC = vec4<f32>(vertexVC.xyz +\n output.radiusVC * offsets.x * xbase +\n output.radiusVC * offsets.y * ybase +\n 0.5 * output.lengthVC * offsets.z * output.orientVC, 1.0);\n\n output.vertexVC = vertexVC;\n\n //VTK::Position::Impl\n\n return output;\n}\n"; // ----------------------------------------------------------------------------
30
+ var vtkWebGPUStickMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n@stage(vertex)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var offsetsArray: array<vec3<f32>, 12> = array<vec3<f32>, 12>(\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(-1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n vec3<f32>(-1.0, 1.0, 1.0)\n );\n\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.x, vertexBC.y, vertexBC.z, 1.0);\n\n //VTK::Color::Impl\n\n // compute the projected vertex position\n output.centerVC = vertexVC.xyz;\n output.radiusVC = radiusMC;\n output.lengthVC = length(orientMC);\n output.orientVC = (rendererUBO.WCVCNormals * vec4<f32>(normalize(orientMC), 0.0)).xyz;\n\n // make sure it is pointing out of the screen\n if (output.orientVC.z < 0.0)\n {\n output.orientVC = -output.orientVC;\n }\n\n // make the basis\n var xbase: vec3<f32>;\n var ybase: vec3<f32>;\n var dir: vec3<f32> = vec3<f32>(0.0,0.0,1.0);\n if (rendererUBO.cameraParallel == 0u)\n {\n dir = normalize(-vertexVC.xyz);\n }\n if (abs(dot(dir,output.orientVC)) == 1.0)\n {\n xbase = normalize(cross(vec3<f32>(0.0,1.0,0.0),output.orientVC));\n ybase = cross(xbase,output.orientVC);\n }\n else\n {\n xbase = normalize(cross(output.orientVC,dir));\n ybase = cross(output.orientVC,xbase);\n }\n\n\n var vertIdx: u32 = input.vertexIndex % 12u;\n var offsets: vec3<f32> = offsetsArray[vertIdx];\n\n vertexVC = vec4<f32>(vertexVC.xyz +\n output.radiusVC * offsets.x * xbase +\n output.radiusVC * offsets.y * ybase +\n 0.5 * output.lengthVC * offsets.z * output.orientVC, 1.0);\n\n output.vertexVC = vertexVC;\n\n //VTK::Position::Impl\n\n return output;\n}\n"; // ----------------------------------------------------------------------------
31
31
  // vtkWebGPUStickMapper methods
32
32
  // ----------------------------------------------------------------------------
33
33
 
@@ -42,9 +42,9 @@ function vtkWebGPUStickMapper(publicAPI, model) {
42
42
  vDesc.addOutput('vec3<f32>', 'orientVC');
43
43
  vDesc.addOutput('f32', 'radiusVC');
44
44
  vDesc.addOutput('f32', 'lengthVC');
45
- vDesc.addBuiltinInput('u32', '[[builtin(vertex_index)]] vertexIndex');
45
+ vDesc.addBuiltinInput('u32', '@builtin(vertex_index) vertexIndex');
46
46
  var fDesc = pipeline.getShaderDescription('fragment');
47
- fDesc.addBuiltinOutput('f32', '[[builtin(frag_depth)]] fragDepth');
47
+ fDesc.addBuiltinOutput('f32', '@builtin(frag_depth) fragDepth');
48
48
  var stickFrag = "\n // compute the eye position and unit direction\n var vertexVC: vec4<f32>;\n var EyePos: vec3<f32>;\n var EyeDir: vec3<f32>;\n\n if (rendererUBO.cameraParallel != 0u)\n {\n EyePos = vec3<f32>(input.vertexVC.x, input.vertexVC.y, input.vertexVC.z + 3.0*input.radiusVC);\n EyeDir = vec3<f32>(0.0, 0.0, -1.0);\n }\n else\n {\n EyeDir = input.vertexVC.xyz;\n EyePos = vec3<f32>(0.0,0.0,0.0);\n var lengthED: f32 = length(EyeDir);\n EyeDir = normalize(EyeDir);\n // we adjust the EyePos to be closer if it is too far away\n // to prevent floating point precision noise\n if (lengthED > input.radiusVC*3.0)\n {\n EyePos = input.vertexVC.xyz - EyeDir*3.0*input.radiusVC;\n }\n }\n // translate to Sphere center\n EyePos = EyePos - input.centerVC;\n\n // rotate to new basis\n // base1, base2, orientVC\n var base1: vec3<f32>;\n if (abs(input.orientVC.z) < 0.99)\n {\n base1 = normalize(cross(input.orientVC,vec3<f32>(0.0,0.0,1.0)));\n }\n else\n {\n base1 = normalize(cross(input.orientVC,vec3<f32>(0.0,1.0,0.0)));\n }\n var base2: vec3<f32> = cross(input.orientVC,base1);\n EyePos = vec3<f32>(dot(EyePos,base1),dot(EyePos,base2),dot(EyePos,input.orientVC));\n EyeDir = vec3<f32>(dot(EyeDir,base1),dot(EyeDir,base2),dot(EyeDir,input.orientVC));\n\n // scale to radius 1.0\n EyePos = EyePos * (1.0 / input.radiusVC);\n\n // find the intersection\n var a: f32 = EyeDir.x*EyeDir.x + EyeDir.y*EyeDir.y;\n var b: f32 = 2.0*(EyePos.x*EyeDir.x + EyePos.y*EyeDir.y);\n var c: f32 = EyePos.x*EyePos.x + EyePos.y*EyePos.y - 1.0;\n var d: f32 = b*b - 4.0*a*c;\n var normal: vec3<f32> = vec3<f32>(0.0,0.0,1.0);\n if (d < 0.0) { discard; }\n else\n {\n var t: f32 = (-b - sqrt(d))*(0.5 / a);\n var tz: f32 = EyePos.z + t*EyeDir.z;\n var iPoint: vec3<f32> = EyePos + t*EyeDir;\n if (abs(iPoint.z)*input.radiusVC > input.lengthVC*0.5)\n {\n // test for end cap\n var t2: f32 = (-b + sqrt(d))*(0.5 / a);\n var tz2: f32 = EyePos.z + t2*EyeDir.z;\n if (tz2*input.radiusVC > input.lengthVC*0.5 || tz*input.radiusVC < -0.5*input.lengthVC) { discard; }\n else\n {\n normal = input.orientVC;\n var t3: f32 = (input.lengthVC*0.5/input.radiusVC - EyePos.z)/EyeDir.z;\n iPoint = EyePos + t3*EyeDir;\n vertexVC = vec4<f32>(input.radiusVC*(iPoint.x*base1 + iPoint.y*base2 + iPoint.z*input.orientVC) + input.centerVC, 1.0);\n }\n }\n else\n {\n // The normal is the iPoint.xy rotated back into VC\n normal = iPoint.x*base1 + iPoint.y*base2;\n // rescale rerotate and translate\n vertexVC = vec4<f32>(input.radiusVC*(normal + iPoint.z*input.orientVC) + input.centerVC, 1.0);\n }\n // compute the pixel's depth\n var pos: vec4<f32> = rendererUBO.VCPCMatrix * vertexVC;\n output.fragDepth = pos.z / pos.w;\n }\n ";
49
49
  var code = fDesc.getCode();
50
50
  code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [stickFrag]).result;
@@ -53,7 +53,7 @@ function vtkWebGPUStickMapper(publicAPI, model) {
53
53
 
54
54
  publicAPI.replaceShaderPosition = function (hash, pipeline, vertexInput) {
55
55
  var vDesc = pipeline.getShaderDescription('vertex');
56
- vDesc.addBuiltinOutput('vec4<f32>', '[[builtin(position)]] Position');
56
+ vDesc.addBuiltinOutput('vec4<f32>', '@builtin(position) Position');
57
57
  var code = vDesc.getCode();
58
58
  code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', [' output.Position = rendererUBO.VCPCMatrix*vertexVC;']).result;
59
59
  vDesc.setCode(code);
@@ -178,7 +178,7 @@ function vtkWebGPUStorageBuffer(publicAPI, model) {
178
178
  lines.push(" ".concat(entry.name, ": ").concat(entry.type, ";"));
179
179
  }
180
180
 
181
- lines.push("\n};\nstruct ".concat(model.name, "Struct\n{\n values: array<").concat(model.name, "StructEntry>;\n};\n[[binding(").concat(binding, "), group(").concat(group, ")]] var<storage, read> ").concat(model.name, ": ").concat(model.name, "Struct;\n"));
181
+ lines.push("\n};\nstruct ".concat(model.name, "Struct\n{\n values: array<").concat(model.name, "StructEntry>;\n};\n@binding(").concat(binding, ") @group(").concat(group, ") var<storage, read> ").concat(model.name, ": ").concat(model.name, "Struct;\n"));
182
182
  return lines.join('\n');
183
183
  };
184
184
 
@@ -38,10 +38,10 @@ function vtkWebGPUTextureView(publicAPI, model) {
38
38
  ttype = 'u32';
39
39
  }
40
40
 
41
- var result = "[[binding(".concat(binding, "), group(").concat(group, ")]] var ").concat(model.name, ": texture_").concat(model.options.dimension, "<").concat(ttype, ">;");
41
+ var result = "@binding(".concat(binding, ") @group(").concat(group, ") var ").concat(model.name, ": texture_").concat(model.options.dimension, "<").concat(ttype, ">;");
42
42
 
43
43
  if (model.bindGroupLayoutEntry.texture.sampleType === 'depth') {
44
- result = "[[binding(".concat(binding, "), group(").concat(group, ")]] var ").concat(model.name, ": texture_depth_").concat(model.options.dimension, ";");
44
+ result = "@binding(".concat(binding, ") @group(").concat(group, ") var ").concat(model.name, ": texture_depth_").concat(model.options.dimension, ";");
45
45
  }
46
46
 
47
47
  return result;
@@ -308,7 +308,7 @@ function vtkWebGPUUniformBuffer(publicAPI, model) {
308
308
  lines.push(" ".concat(entry.name, ": ").concat(entry.type, ";"));
309
309
  }
310
310
 
311
- lines.push("};\n[[binding(".concat(binding, "), group(").concat(group, ")]] var<uniform> ").concat(model.name, ": ").concat(model.name, "Struct;"));
311
+ lines.push("};\n@binding(".concat(binding, ") @group(").concat(group, ") var<uniform> ").concat(model.name, ": ").concat(model.name, "Struct;"));
312
312
  return lines.join('\n');
313
313
  };
314
314
  } // ----------------------------------------------------------------------------
@@ -112,7 +112,7 @@ function vtkWebGPUVertexInput(publicAPI, model) {
112
112
  result += ',\n';
113
113
  }
114
114
 
115
- result = "".concat(result, " [[location(").concat(nameCount, ")]] ").concat(model.inputs[i].names[nm], " : ").concat(type);
115
+ result = "".concat(result, " @location(").concat(nameCount, ") ").concat(model.inputs[i].names[nm], " : ").concat(type);
116
116
  nameCount++;
117
117
  }
118
118
  }
@@ -33,8 +33,8 @@ var BufferUsage = vtkWebGPUBufferManager.BufferUsage,
33
33
  //
34
34
 
35
35
  var cubeFaceTriangles = [[0, 4, 6], [0, 6, 2], [1, 3, 7], [1, 7, 5], [0, 5, 4], [0, 1, 5], [2, 6, 7], [2, 7, 3], [0, 3, 1], [0, 2, 3], [4, 5, 7], [4, 7, 6]];
36
- var DepthBoundsFS = "\n//VTK::Renderer::Dec\n\n//VTK::Select::Dec\n\n//VTK::VolumePass::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n[[stage(fragment)]]\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : fragmentOutput;\n\n //VTK::Select::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::VolumePass::Impl\n\n // use the maximum (closest) of the current value and the zbuffer\n // the blend func will then take the min to find the farthest stop value\n var stopval: f32 = max(input.fragPos.z, textureLoad(opaquePassDepthTexture, vec2<i32>(i32(input.fragPos.x), i32(input.fragPos.y)), 0));\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
37
- var volumeCopyFragTemplate = "\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[[stage(fragment)]]\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = textureSample(volumePassSmallColorTexture,\n volumePassSmallColorTextureSampler, mapperUBO.tscale*input.tcoordVS);\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
36
+ var DepthBoundsFS = "\n//VTK::Renderer::Dec\n\n//VTK::Select::Dec\n\n//VTK::VolumePass::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : fragmentOutput;\n\n //VTK::Select::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::VolumePass::Impl\n\n // use the maximum (closest) of the current value and the zbuffer\n // the blend func will then take the min to find the farthest stop value\n var stopval: f32 = max(input.fragPos.z, textureLoad(opaquePassDepthTexture, vec2<i32>(i32(input.fragPos.x), i32(input.fragPos.y)), 0));\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
37
+ var volumeCopyFragTemplate = "\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@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = textureSample(volumePassSmallColorTexture,\n volumePassSmallColorTextureSampler, mapperUBO.tscale*input.tcoordVS);\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n";
38
38
  /* eslint-disable no-undef */
39
39
 
40
40
  /* eslint-disable no-bitwise */
@@ -642,7 +642,7 @@ function extend(publicAPI, model) {
642
642
 
643
643
  model._mapper.getShaderReplacements().set('replaceShaderVolumePass', function (hash, pipeline, vertexInput) {
644
644
  var fDesc = pipeline.getShaderDescription('fragment');
645
- fDesc.addBuiltinInput('vec4<f32>', '[[builtin(position)]] fragPos');
645
+ fDesc.addBuiltinInput('vec4<f32>', '@builtin(position) fragPos');
646
646
  });
647
647
 
648
648
  model._boundsPoly = vtkPolyData.newInstance();
@@ -9,7 +9,7 @@ import vtkWebGPUSampler from './Sampler.js';
9
9
  import vtkWebGPUTypes from './Types.js';
10
10
  import { BlendMode } from '../Core/VolumeMapper/Constants.js';
11
11
 
12
- var volFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Volume::TraverseDec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\nfn getTextureValue(vTex: texture_3d<f32>, tpos: vec4<f32>) -> f32\n{\n // todo multicomponent support\n return textureSampleLevel(vTex, clampSampler, tpos.xyz, 0.0).r;\n}\n\nfn getGradient(vTex: texture_3d<f32>, tpos: vec4<f32>, vNum: i32, scalar: f32) -> vec4<f32>\n{\n var result: vec4<f32>;\n\n var tstep: vec4<f32> = volumeSSBO.values[vNum].tstep;\n result.x = getTextureValue(vTex, tpos + vec4<f32>(tstep.x, 0.0, 0.0, 1.0)) - scalar;\n result.y = getTextureValue(vTex, tpos + vec4<f32>(0.0, tstep.y, 0.0, 1.0)) - scalar;\n result.z = getTextureValue(vTex, tpos + vec4<f32>(0.0, 0.0, tstep.z, 1.0)) - scalar;\n\n // divide by spacing\n result = result / volumeSSBO.values[vNum].spacing;\n\n var grad: f32 = length(result.xyz);\n\n // // rotate to View Coords, needed for lighting and shading\n // result.xyz =\n // result.x * vPlaneNormal0 +\n // result.y * vPlaneNormal2 +\n // result.z * vPlaneNormal4;\n\n if (grad > 0.0)\n {\n result = result * (1.0 / grad);\n }\n\n result.w = grad;\n\n return result;\n}\n\nfn processVolume(vTex: texture_3d<f32>, vNum: i32, cNum: i32, posSC: vec4<f32>, tfunRows: f32) -> vec4<f32>\n{\n var outColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\n // convert to tcoords and reject if outside the volume\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*posSC;\n if (tpos.x < 0.0 || tpos.y < 0.0 || tpos.z < 0.0 ||\n tpos.x > 1.0 || tpos.y > 1.0 || tpos.z > 1.0) { return outColor; }\n\n var scalar: f32 = getTextureValue(vTex, tpos);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n\n var gofactor: f32 = 1.0;\n if (componentSSBO.values[cNum].gomin < 1.0)\n {\n var normal: vec4<f32> = getGradient(vTex, tpos, vNum, scalar);\n gofactor = clamp(normal.a*componentSSBO.values[cNum].goScale + componentSSBO.values[cNum].goShift,\n componentSSBO.values[cNum].gomin, componentSSBO.values[cNum].gomax);\n }\n\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n\n outColor = vec4<f32>(color.rgb, gofactor * opacity);\n\n//VTK::Volume::Process\n\n return outColor;\n}\n\n// adjust the start and end point of a raycast such that it intersects the unit cube.\n// This function is used to take a raycast starting point and step vector\n// and numSteps and return the startijng and ending steps for intersecting the\n// unit cube. Recall for a 3D texture, the unit cube is the range of texture coordsinates\n// that have valid values. So this funtion can be used to take a ray in texture coordinates\n// and bound it to intersecting the texture.\n//\nfn adjustBounds(tpos: vec4<f32>, tstep: vec4<f32>, numSteps: f32) -> vec2<f32>\n{\n var result: vec2<f32> = vec2<f32>(0.0, numSteps);\n var tpos2: vec4<f32> = tpos + tstep*numSteps;\n\n // move tpos to the start of the volume\n var adjust: f32 =\n min(\n max(tpos.x/tstep.x, (tpos.x - 1.0)/tstep.x),\n min(\n max((tpos.y - 1.0)/tstep.y, tpos.y/tstep.y),\n max((tpos.z - 1.0)/tstep.z, tpos.z/tstep.z)));\n if (adjust < 0.0)\n {\n result.x = result.x - adjust;\n }\n\n // adjust length to the end\n adjust =\n max(\n min(tpos2.x/tstep.x, (tpos2.x - 1.0)/tstep.x),\n max(\n min((tpos2.y - 1.0)/tstep.y, tpos2.y/tstep.y),\n min((tpos2.z - 1.0)/tstep.z, tpos2.z/tstep.z)));\n if (adjust > 0.0)\n {\n result.y = result.y - adjust;\n }\n\n return result;\n}\n\nfn getSimpleColor(scalar: f32, vNum: i32, cNum: i32) -> vec4<f32>\n{\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n return vec4<f32>(color.rgb, opacity);\n}\n\nfn traverseMax(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var maxVal: f32 = -1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar > maxVal)\n {\n maxVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(maxVal, vNum, cNum);\n}\n\nfn traverseMin(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var minVal: f32 = 1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar < minVal)\n {\n minVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(minVal, vNum, cNum);\n}\n\nfn traverseAverage(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var avgVal: f32 = 0.0;\n var sampleCount: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n avgVal = avgVal + sample;\n sampleCount = sampleCount + 1.0;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n if (sampleCount <= 0.0)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(avgVal/sampleCount, vNum, cNum);\n}\n\nfn traverseAdditive(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var sumVal: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n sumVal = sumVal + sample;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(sumVal, vNum, cNum);\n}\n\nfn composite(rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>) -> vec4<f32>\n{\n // initial ray position is at the beginning\n var rayPosSC: vec4<f32> = minPosSC;\n\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var curDist: f32 = 0.0;\n var computedColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n var sampleColor: vec4<f32>;\n//VTK::Volume::TraverseCalls\n\n loop\n {\n // for each volume, sample and accumulate color\n//VTK::Volume::CompositeCalls\n\n // increment position\n curDist = curDist + mapperUBO.SampleDistance;\n rayPosSC = rayPosSC + rayStepSC;\n\n // check if we have reached a terminating condition\n if (curDist > rayLengthSC) { break; }\n if (computedColor.a > 0.98) { break; }\n }\n return computedColor;\n}\n\n[[stage(fragment)]]\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var rayMax: f32 = textureSampleLevel(maxTexture, clampSampler, input.tcoordVS, 0.0).r;\n var rayMin: f32 = textureSampleLevel(minTexture, clampSampler, input.tcoordVS, 0.0).r;\n\n // discard empty rays\n if (rayMax <= rayMin) { discard; }\n else\n {\n // compute start and end ray positions in view coordinates\n var minPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMax, 1.0);\n minPosSC = minPosSC * (1.0 / minPosSC.w);\n var maxPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMin, 1.0);\n maxPosSC = maxPosSC * (1.0 / maxPosSC.w);\n\n var rayLengthSC: f32 = distance(minPosSC.xyz, maxPosSC.xyz);\n var rayStepSC: vec4<f32> = (maxPosSC - minPosSC)*(mapperUBO.SampleDistance/rayLengthSC);\n rayStepSC.w = 0.0;\n\n var computedColor: vec4<f32>;\n\n//VTK::Volume::Loop\n\n//VTK::RenderEncoder::Impl\n }\n\n return output;\n}\n";
12
+ var volFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Volume::TraverseDec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\nfn getTextureValue(vTex: texture_3d<f32>, tpos: vec4<f32>) -> f32\n{\n // todo multicomponent support\n return textureSampleLevel(vTex, clampSampler, tpos.xyz, 0.0).r;\n}\n\nfn getGradient(vTex: texture_3d<f32>, tpos: vec4<f32>, vNum: i32, scalar: f32) -> vec4<f32>\n{\n var result: vec4<f32>;\n\n var tstep: vec4<f32> = volumeSSBO.values[vNum].tstep;\n result.x = getTextureValue(vTex, tpos + vec4<f32>(tstep.x, 0.0, 0.0, 1.0)) - scalar;\n result.y = getTextureValue(vTex, tpos + vec4<f32>(0.0, tstep.y, 0.0, 1.0)) - scalar;\n result.z = getTextureValue(vTex, tpos + vec4<f32>(0.0, 0.0, tstep.z, 1.0)) - scalar;\n\n // divide by spacing\n result = result / volumeSSBO.values[vNum].spacing;\n\n var grad: f32 = length(result.xyz);\n\n // // rotate to View Coords, needed for lighting and shading\n // result.xyz =\n // result.x * vPlaneNormal0 +\n // result.y * vPlaneNormal2 +\n // result.z * vPlaneNormal4;\n\n if (grad > 0.0)\n {\n result = result * (1.0 / grad);\n }\n\n result.w = grad;\n\n return result;\n}\n\nfn processVolume(vTex: texture_3d<f32>, vNum: i32, cNum: i32, posSC: vec4<f32>, tfunRows: f32) -> vec4<f32>\n{\n var outColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\n // convert to tcoords and reject if outside the volume\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*posSC;\n if (tpos.x < 0.0 || tpos.y < 0.0 || tpos.z < 0.0 ||\n tpos.x > 1.0 || tpos.y > 1.0 || tpos.z > 1.0) { return outColor; }\n\n var scalar: f32 = getTextureValue(vTex, tpos);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n\n var gofactor: f32 = 1.0;\n if (componentSSBO.values[cNum].gomin < 1.0)\n {\n var normal: vec4<f32> = getGradient(vTex, tpos, vNum, scalar);\n gofactor = clamp(normal.a*componentSSBO.values[cNum].goScale + componentSSBO.values[cNum].goShift,\n componentSSBO.values[cNum].gomin, componentSSBO.values[cNum].gomax);\n }\n\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n\n outColor = vec4<f32>(color.rgb, gofactor * opacity);\n\n//VTK::Volume::Process\n\n return outColor;\n}\n\n// adjust the start and end point of a raycast such that it intersects the unit cube.\n// This function is used to take a raycast starting point and step vector\n// and numSteps and return the startijng and ending steps for intersecting the\n// unit cube. Recall for a 3D texture, the unit cube is the range of texture coordsinates\n// that have valid values. So this funtion can be used to take a ray in texture coordinates\n// and bound it to intersecting the texture.\n//\nfn adjustBounds(tpos: vec4<f32>, tstep: vec4<f32>, numSteps: f32) -> vec2<f32>\n{\n var result: vec2<f32> = vec2<f32>(0.0, numSteps);\n var tpos2: vec4<f32> = tpos + tstep*numSteps;\n\n // move tpos to the start of the volume\n var adjust: f32 =\n min(\n max(tpos.x/tstep.x, (tpos.x - 1.0)/tstep.x),\n min(\n max((tpos.y - 1.0)/tstep.y, tpos.y/tstep.y),\n max((tpos.z - 1.0)/tstep.z, tpos.z/tstep.z)));\n if (adjust < 0.0)\n {\n result.x = result.x - adjust;\n }\n\n // adjust length to the end\n adjust =\n max(\n min(tpos2.x/tstep.x, (tpos2.x - 1.0)/tstep.x),\n max(\n min((tpos2.y - 1.0)/tstep.y, tpos2.y/tstep.y),\n min((tpos2.z - 1.0)/tstep.z, tpos2.z/tstep.z)));\n if (adjust > 0.0)\n {\n result.y = result.y - adjust;\n }\n\n return result;\n}\n\nfn getSimpleColor(scalar: f32, vNum: i32, cNum: i32) -> vec4<f32>\n{\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n return vec4<f32>(color.rgb, opacity);\n}\n\nfn traverseMax(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var maxVal: f32 = -1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar > maxVal)\n {\n maxVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(maxVal, vNum, cNum);\n}\n\nfn traverseMin(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var minVal: f32 = 1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar < minVal)\n {\n minVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(minVal, vNum, cNum);\n}\n\nfn traverseAverage(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var avgVal: f32 = 0.0;\n var sampleCount: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n avgVal = avgVal + sample;\n sampleCount = sampleCount + 1.0;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n if (sampleCount <= 0.0)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(avgVal/sampleCount, vNum, cNum);\n}\n\nfn traverseAdditive(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var sumVal: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n sumVal = sumVal + sample;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(sumVal, vNum, cNum);\n}\n\nfn composite(rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>) -> vec4<f32>\n{\n // initial ray position is at the beginning\n var rayPosSC: vec4<f32> = minPosSC;\n\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var curDist: f32 = 0.0;\n var computedColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n var sampleColor: vec4<f32>;\n//VTK::Volume::TraverseCalls\n\n loop\n {\n // for each volume, sample and accumulate color\n//VTK::Volume::CompositeCalls\n\n // increment position\n curDist = curDist + mapperUBO.SampleDistance;\n rayPosSC = rayPosSC + rayStepSC;\n\n // check if we have reached a terminating condition\n if (curDist > rayLengthSC) { break; }\n if (computedColor.a > 0.98) { break; }\n }\n return computedColor;\n}\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var rayMax: f32 = textureSampleLevel(maxTexture, clampSampler, input.tcoordVS, 0.0).r;\n var rayMin: f32 = textureSampleLevel(minTexture, clampSampler, input.tcoordVS, 0.0).r;\n\n // discard empty rays\n if (rayMax <= rayMin) { discard; }\n else\n {\n // compute start and end ray positions in view coordinates\n var minPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMax, 1.0);\n minPosSC = minPosSC * (1.0 / minPosSC.w);\n var maxPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMin, 1.0);\n maxPosSC = maxPosSC * (1.0 / maxPosSC.w);\n\n var rayLengthSC: f32 = distance(minPosSC.xyz, maxPosSC.xyz);\n var rayStepSC: vec4<f32> = (maxPosSC - minPosSC)*(mapperUBO.SampleDistance/rayLengthSC);\n rayStepSC.w = 0.0;\n\n var computedColor: vec4<f32>;\n\n//VTK::Volume::Loop\n\n//VTK::RenderEncoder::Impl\n }\n\n return output;\n}\n";
13
13
  var tmpMat4 = new Float64Array(16);
14
14
  var tmp2Mat4 = new Float64Array(16); // ----------------------------------------------------------------------------
15
15
  // vtkWebGPUVolumePassFSQ methods
@@ -21,12 +21,12 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
21
21
 
22
22
  publicAPI.replaceShaderPosition = function (hash, pipeline, vertexInput) {
23
23
  var vDesc = pipeline.getShaderDescription('vertex');
24
- vDesc.addBuiltinOutput('vec4<f32>', '[[builtin(position)]] Position');
24
+ vDesc.addBuiltinOutput('vec4<f32>', '@builtin(position) Position');
25
25
  var code = vDesc.getCode();
26
26
  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;
27
27
  vDesc.setCode(code);
28
28
  var fDesc = pipeline.getShaderDescription('fragment');
29
- fDesc.addBuiltinInput('vec4<f32>', '[[builtin(position)]] fragPos');
29
+ fDesc.addBuiltinInput('vec4<f32>', '@builtin(position) fragPos');
30
30
  };
31
31
 
32
32
  model.shaderReplacements.set('replaceShaderPosition', publicAPI.replaceShaderPosition);
@@ -1,4 +1,6 @@
1
+ import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator';
1
2
  import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
3
+ import _regeneratorRuntime from '@babel/runtime/regenerator';
2
4
  import { r as radiansFromDegrees } from '../../Common/Core/Math/index.js';
3
5
  import { FieldAssociations } from '../../Common/DataModel/DataSet/Constants.js';
4
6
  import macro from '../../macros.js';
@@ -10,7 +12,8 @@ import { diff } from './WidgetManager/vdom.js';
10
12
  var ViewTypes = WidgetManagerConst.ViewTypes,
11
13
  RenderingTypes = WidgetManagerConst.RenderingTypes,
12
14
  CaptureOn = WidgetManagerConst.CaptureOn;
13
- var vtkErrorMacro = macro.vtkErrorMacro;
15
+ var vtkErrorMacro = macro.vtkErrorMacro,
16
+ vtkWarningMacro = macro.vtkWarningMacro;
14
17
  var createSvgElement = vtkSVGRepresentation.createSvgElement,
15
18
  createSvgDomElement = vtkSVGRepresentation.createSvgDomElement;
16
19
  var viewIdCount = 1; // ----------------------------------------------------------------------------
@@ -267,17 +270,48 @@ function vtkWidgetManager(publicAPI, model) {
267
270
  model.widgets.forEach(updateWidgetForRender);
268
271
  }
269
272
 
270
- function captureBuffers(x1, y1, x2, y2) {
271
- renderPickingBuffer();
272
- model.selector.setArea(x1, y1, x2, y2);
273
- model.selector.releasePixBuffers();
274
- model.previousSelectedData = null;
275
- return model.selector.captureBuffers();
273
+ function captureBuffers(_x, _x2, _x3, _x4) {
274
+ return _captureBuffers.apply(this, arguments);
275
+ }
276
+
277
+ function _captureBuffers() {
278
+ _captureBuffers = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(x1, y1, x2, y2) {
279
+ return _regeneratorRuntime.wrap(function _callee3$(_context3) {
280
+ while (1) {
281
+ switch (_context3.prev = _context3.next) {
282
+ case 0:
283
+ if (!model._captureInProgress) {
284
+ _context3.next = 2;
285
+ break;
286
+ }
287
+
288
+ return _context3.abrupt("return");
289
+
290
+ case 2:
291
+ model._captureInProgress = true;
292
+ renderPickingBuffer();
293
+ model._capturedBuffers = null;
294
+ _context3.next = 7;
295
+ return model.selector.getSourceDataAsync(model.renderer, x1, y1, x2, y2);
296
+
297
+ case 7:
298
+ model._capturedBuffers = _context3.sent;
299
+ model.previousSelectedData = null;
300
+ renderFrontBuffer();
301
+ model._captureInProgress = false;
302
+
303
+ case 11:
304
+ case "end":
305
+ return _context3.stop();
306
+ }
307
+ }
308
+ }, _callee3);
309
+ }));
310
+ return _captureBuffers.apply(this, arguments);
276
311
  }
277
312
 
278
313
  publicAPI.enablePicking = function () {
279
314
  model.pickingEnabled = true;
280
- model.pickingAvailable = true;
281
315
  publicAPI.renderWidgets();
282
316
  };
283
317
 
@@ -288,7 +322,7 @@ function vtkWidgetManager(publicAPI, model) {
288
322
  w = _model$apiSpecificRen4[0],
289
323
  h = _model$apiSpecificRen4[1];
290
324
 
291
- model.pickingAvailable = captureBuffers(0, 0, w, h);
325
+ captureBuffers(0, 0, w, h);
292
326
  }
293
327
 
294
328
  renderFrontBuffer();
@@ -297,7 +331,6 @@ function vtkWidgetManager(publicAPI, model) {
297
331
 
298
332
  publicAPI.disablePicking = function () {
299
333
  model.pickingEnabled = false;
300
- model.pickingAvailable = false;
301
334
  };
302
335
 
303
336
  publicAPI.setRenderer = function (renderer) {
@@ -307,9 +340,8 @@ function vtkWidgetManager(publicAPI, model) {
307
340
  subscriptions.pop().unsubscribe();
308
341
  }
309
342
 
310
- model.selector = model.apiSpecificRenderWindow.getSelector();
343
+ model.selector = model.apiSpecificRenderWindow.createSelector();
311
344
  model.selector.setFieldAssociation(FieldAssociations.FIELD_ASSOCIATION_POINTS);
312
- model.selector.attach(model.apiSpecificRenderWindow, model.renderer);
313
345
  subscriptions.push(model.interactor.onRenderEvent(updateSvg));
314
346
  subscriptions.push(model.apiSpecificRenderWindow.onModified(setSvgSize));
315
347
  setSvgSize();
@@ -323,61 +355,90 @@ function vtkWidgetManager(publicAPI, model) {
323
355
  model.isAnimating = false;
324
356
  publicAPI.renderWidgets();
325
357
  }));
326
- subscriptions.push(model.interactor.onMouseMove(function (_ref) {
327
- var position = _ref.position;
328
-
329
- if (model.isAnimating || !model.pickingAvailable) {
330
- return;
331
- }
332
-
333
- publicAPI.updateSelectionFromXY(position.x, position.y);
334
-
335
- var _publicAPI$getSelecte = publicAPI.getSelectedData(),
336
- requestCount = _publicAPI$getSelecte.requestCount,
337
- selectedState = _publicAPI$getSelecte.selectedState,
338
- representation = _publicAPI$getSelecte.representation,
339
- widget = _publicAPI$getSelecte.widget;
340
-
341
- if (requestCount) {
342
- // Call activate only once
343
- return;
344
- } // Default cursor behavior
345
-
346
-
347
- model.apiSpecificRenderWindow.setCursor(widget ? 'pointer' : 'default');
348
-
349
- if (model.widgetInFocus === widget && widget.hasFocus()) {
350
- widget.activateHandle({
351
- selectedState: selectedState,
352
- representation: representation
353
- }); // Ken FIXME
354
-
355
- model.interactor.render();
356
- model.interactor.render();
357
- } else {
358
- for (var i = 0; i < model.widgets.length; i++) {
359
- var w = model.widgets[i];
360
-
361
- if (w === widget && w.getNestedPickable()) {
362
- w.activateHandle({
363
- selectedState: selectedState,
364
- representation: representation
365
- });
366
- model.activeWidget = w;
367
- } else {
368
- w.deactivateAllHandles();
358
+ subscriptions.push(model.interactor.onMouseMove( /*#__PURE__*/function () {
359
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
360
+ var position, _yield$publicAPI$getS, requestCount, selectedState, representation, widget, i, w;
361
+
362
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
363
+ while (1) {
364
+ switch (_context.prev = _context.next) {
365
+ case 0:
366
+ position = _ref.position;
367
+
368
+ if (!(model.isAnimating || !model.pickingEnabled || model._selectionInProgress)) {
369
+ _context.next = 3;
370
+ break;
371
+ }
372
+
373
+ return _context.abrupt("return");
374
+
375
+ case 3:
376
+ model._selectionInProgress = true;
377
+ _context.next = 6;
378
+ return publicAPI.getSelectedDataForXY(position.x, position.y);
379
+
380
+ case 6:
381
+ _yield$publicAPI$getS = _context.sent;
382
+ requestCount = _yield$publicAPI$getS.requestCount;
383
+ selectedState = _yield$publicAPI$getS.selectedState;
384
+ representation = _yield$publicAPI$getS.representation;
385
+ widget = _yield$publicAPI$getS.widget;
386
+ model._selectionInProgress = false;
387
+
388
+ if (!requestCount) {
389
+ _context.next = 14;
390
+ break;
391
+ }
392
+
393
+ return _context.abrupt("return");
394
+
395
+ case 14:
396
+ // Default cursor behavior
397
+ model.apiSpecificRenderWindow.setCursor(widget ? 'pointer' : 'default');
398
+
399
+ if (model.widgetInFocus === widget && widget.hasFocus()) {
400
+ widget.activateHandle({
401
+ selectedState: selectedState,
402
+ representation: representation
403
+ }); // Ken FIXME
404
+
405
+ model.interactor.render();
406
+ model.interactor.render();
407
+ } else {
408
+ for (i = 0; i < model.widgets.length; i++) {
409
+ w = model.widgets[i];
410
+
411
+ if (w === widget && w.getNestedPickable()) {
412
+ w.activateHandle({
413
+ selectedState: selectedState,
414
+ representation: representation
415
+ });
416
+ model.activeWidget = w;
417
+ } else {
418
+ w.deactivateAllHandles();
419
+ }
420
+ } // Ken FIXME
421
+
422
+
423
+ model.interactor.render();
424
+ model.interactor.render();
425
+ }
426
+
427
+ case 16:
428
+ case "end":
429
+ return _context.stop();
430
+ }
369
431
  }
370
- } // Ken FIXME
432
+ }, _callee);
433
+ }));
371
434
 
372
-
373
- model.interactor.render();
374
- model.interactor.render();
375
- }
376
- }));
435
+ return function (_x5) {
436
+ return _ref2.apply(this, arguments);
437
+ };
438
+ }()));
377
439
  publicAPI.modified();
378
440
 
379
441
  if (model.pickingEnabled) {
380
- // also sets pickingAvailable
381
442
  publicAPI.enablePicking();
382
443
  }
383
444
 
@@ -453,7 +514,93 @@ function vtkWidgetManager(publicAPI, model) {
453
514
  }
454
515
  };
455
516
 
517
+ publicAPI.getSelectedDataForXY = /*#__PURE__*/function () {
518
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(x, y) {
519
+ var i, widget, hoveredSVGReps, selection, capturedRegion;
520
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
521
+ while (1) {
522
+ switch (_context2.prev = _context2.next) {
523
+ case 0:
524
+ model.selections = null;
525
+
526
+ if (!model.pickingEnabled) {
527
+ _context2.next = 24;
528
+ break;
529
+ }
530
+
531
+ i = 0;
532
+
533
+ case 3:
534
+ if (!(i < model.widgets.length)) {
535
+ _context2.next = 16;
536
+ break;
537
+ }
538
+
539
+ widget = model.widgets[i];
540
+ hoveredSVGReps = widget.getRepresentations().filter(function (r) {
541
+ return r.isA('vtkSVGRepresentation') && r.getHover() != null;
542
+ });
543
+
544
+ if (!hoveredSVGReps.length) {
545
+ _context2.next = 13;
546
+ break;
547
+ }
548
+
549
+ selection = vtkSelectionNode.newInstance();
550
+ selection.getProperties().compositeID = hoveredSVGReps[0].getHover();
551
+ selection.getProperties().widget = widget;
552
+ selection.getProperties().representation = hoveredSVGReps[0];
553
+ model.selections = [selection];
554
+ return _context2.abrupt("return", publicAPI.getSelectedData());
555
+
556
+ case 13:
557
+ ++i;
558
+ _context2.next = 3;
559
+ break;
560
+
561
+ case 16:
562
+ if (!(!model._capturedBuffers || model.captureOn === CaptureOn.MOUSE_MOVE)) {
563
+ _context2.next = 19;
564
+ break;
565
+ }
566
+
567
+ _context2.next = 19;
568
+ return captureBuffers(x, y, x, y);
569
+
570
+ case 19:
571
+ // or do we need a pixel that is outside the last capture?
572
+ capturedRegion = model._capturedBuffers.area;
573
+
574
+ if (!(x < capturedRegion[0] || x > capturedRegion[2] || y < capturedRegion[1] || y > capturedRegion[3])) {
575
+ _context2.next = 23;
576
+ break;
577
+ }
578
+
579
+ _context2.next = 23;
580
+ return captureBuffers(x, y, x, y);
581
+
582
+ case 23:
583
+ model.selections = model._capturedBuffers.generateSelection(x, y, x, y);
584
+
585
+ case 24:
586
+ return _context2.abrupt("return", publicAPI.getSelectedData());
587
+
588
+ case 25:
589
+ case "end":
590
+ return _context2.stop();
591
+ }
592
+ }
593
+ }, _callee2);
594
+ }));
595
+
596
+ return function (_x6, _x7) {
597
+ return _ref3.apply(this, arguments);
598
+ };
599
+ }();
600
+
456
601
  publicAPI.updateSelectionFromXY = function (x, y) {
602
+ vtkWarningMacro('updateSelectionFromXY is deprecated, please use getSelectedDataForXY');
603
+
457
604
  if (model.pickingEnabled) {
458
605
  // First pick SVG representation
459
606
  for (var i = 0; i < model.widgets.length; ++i) {
@@ -473,20 +620,14 @@ function vtkWidgetManager(publicAPI, model) {
473
620
  } // Then pick regular representations.
474
621
 
475
622
 
476
- var pickingAvailable = model.pickingAvailable;
477
-
478
623
  if (model.captureOn === CaptureOn.MOUSE_MOVE) {
479
- pickingAvailable = captureBuffers(x, y, x, y);
480
- renderFrontBuffer();
481
- }
482
-
483
- if (pickingAvailable) {
484
- model.selections = model.selector.generateSelection(x, y, x, y);
624
+ captureBuffers(x, y, x, y);
485
625
  }
486
626
  }
487
627
  };
488
628
 
489
629
  publicAPI.updateSelectionFromMouseEvent = function (event) {
630
+ vtkWarningMacro('updateSelectionFromMouseEvent is deprecated, please use getSelectedDataForXY');
490
631
  var pageX = event.pageX,
491
632
  pageY = event.pageY;
492
633
 
@@ -603,7 +744,6 @@ var DEFAULT_VALUES = {
603
744
  widgets: [],
604
745
  renderer: null,
605
746
  viewType: ViewTypes.DEFAULT,
606
- pickingAvailable: false,
607
747
  isAnimating: false,
608
748
  pickingEnabled: true,
609
749
  selections: null,
@@ -48,13 +48,16 @@ function widgetBehavior(publicAPI, model) {
48
48
  return handles.reduce(function (_ref, handle) {
49
49
  var closestHandle = _ref.closestHandle,
50
50
  closestDistance = _ref.closestDistance;
51
- var distance = vec3.squaredDistance(model.moveHandle.getOrigin(), handle.getOrigin());
52
51
 
53
- if (handle !== model.moveHandle) {
54
- return {
55
- closestHandle: distance < closestDistance ? handle : closestHandle,
56
- closestDistance: distance < closestDistance ? distance : closestDistance
57
- };
52
+ if (handle !== model.moveHandle && model.moveHandle.getOrigin() && handle.getOrigin()) {
53
+ var distance = vec3.squaredDistance(model.moveHandle.getOrigin(), handle.getOrigin());
54
+
55
+ if (distance < closestDistance) {
56
+ return {
57
+ closestHandle: handle,
58
+ closestDistance: distance
59
+ };
60
+ }
58
61
  }
59
62
 
60
63
  return {