@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.
- package/IO/Core/ImageStream/DefaultProtocol.d.ts +8 -8
- package/IO/Core/ImageStream.d.ts +17 -15
- package/Rendering/Core/ScalarBarActor.d.ts +39 -3
- package/Rendering/Core/ScalarBarActor.js +28 -8
- package/Rendering/Misc/SynchronizableRenderWindow.d.ts +73 -0
- package/Rendering/OpenGL/RenderWindow.d.ts +107 -106
- package/Rendering/OpenGL/RenderWindow.js +6 -0
- package/Rendering/SceneGraph/RenderWindowViewNode.js +5 -0
- package/Rendering/WebGPU/FullScreenQuad.js +1 -1
- package/Rendering/WebGPU/Glyph3DMapper.js +2 -2
- package/Rendering/WebGPU/HardwareSelector.js +1 -0
- package/Rendering/WebGPU/ImageMapper.js +2 -2
- package/Rendering/WebGPU/MapperHelper.js +4 -4
- package/Rendering/WebGPU/OrderIndependentTranslucentPass.js +3 -3
- package/Rendering/WebGPU/PolyDataMapper.js +4 -4
- package/Rendering/WebGPU/RenderWindow.js +10 -1
- package/Rendering/WebGPU/Renderer.js +1 -1
- package/Rendering/WebGPU/Sampler.js +1 -1
- package/Rendering/WebGPU/ShaderDescription.js +4 -4
- package/Rendering/WebGPU/SphereMapper.js +3 -3
- package/Rendering/WebGPU/StickMapper.js +4 -4
- package/Rendering/WebGPU/StorageBuffer.js +1 -1
- package/Rendering/WebGPU/TextureView.js +2 -2
- package/Rendering/WebGPU/UniformBuffer.js +1 -1
- package/Rendering/WebGPU/VertexInput.js +1 -1
- package/Rendering/WebGPU/VolumePass.js +3 -3
- package/Rendering/WebGPU/VolumePassFSQ.js +3 -3
- package/Widgets/Core/WidgetManager.js +211 -71
- package/Widgets/Widgets3D/SplineWidget/behavior.js +9 -6
- package/package.json +4 -4
|
@@ -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
|
|
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', '
|
|
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>', '
|
|
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
|
|
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', '
|
|
45
|
+
vDesc.addBuiltinInput('u32', '@builtin(vertex_index) vertexIndex');
|
|
46
46
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
47
|
-
fDesc.addBuiltinOutput('f32', '
|
|
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>', '
|
|
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
|
|
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 = "
|
|
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 = "
|
|
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
|
|
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, "
|
|
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
|
|
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
|
|
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>', '
|
|
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>', '
|
|
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>', '
|
|
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(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
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.
|
|
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 (
|
|
327
|
-
var
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
return
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
}
|
|
432
|
+
}, _callee);
|
|
433
|
+
}));
|
|
371
434
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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 {
|