Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Examples/Volume/VolumeMapperBlendModes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import '@kitware/vtk.js/IO/Core/DataAccessHelper/JSZipDataAccessHelper';

import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
import vtkHttpDataSetReader from '@kitware/vtk.js/IO/Core/HttpDataSetReader';
import vtkURLExtract from '@kitware/vtk.js/Common/Core/URLExtract';
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction';
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
Expand All @@ -20,6 +21,9 @@ import GUI from 'lil-gui';
// Standard rendering code setup
// ----------------------------------------------------------------------------

const userParms = vtkURLExtract.extractURLParameters();
const viewAPI = userParms.viewAPI || 'WebGL';

const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
background: [0.3, 0.3, 0.3],
});
Expand All @@ -33,6 +37,7 @@ const gui = new GUI();
// ----------------------------------------------------------------------------
// UI params
const params = {
viewAPI,
BlendMode: 5,
IpScalarMin: 0.0,
IpScalarMax: 1.0,
Expand All @@ -45,6 +50,13 @@ const params = {
const reader = vtkHttpDataSetReader.newInstance({ fetchGzip: true });
const initialSampleDistance = 1.3;

gui
.add(params, 'viewAPI', ['WebGL', 'WebGPU'])
.name('Renderer')
.onChange((api) => {
window.location = `?viewAPI=${api}`;
});

const actor = vtkVolume.newInstance();
const actorProperty = actor.getProperty();
const mapper = vtkVolumeMapper.newInstance();
Expand Down
14 changes: 14 additions & 0 deletions Sources/Rendering/Core/VolumeMapper/example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import vtkMath from '@kitware/vtk.js/Common/Core/Math';
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction';
import vtkProperty from '@kitware/vtk.js/Rendering/Core/Property';
import vtkSphereSource from '@kitware/vtk.js/Filters/Sources/SphereSource';
import vtkURLExtract from '@kitware/vtk.js/Common/Core/URLExtract';
import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
import vtkVolumeMapper from '@kitware/vtk.js/Rendering/Core/VolumeMapper';

Expand All @@ -30,8 +31,12 @@ const { Representation, Shading } = vtkProperty;
// Standard rendering code setup
// ----------------------------------------------------------------------------

const userParams = vtkURLExtract.extractURLParameters();
const viewAPI = userParams.viewAPI || 'WebGL';

const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
background: [0, 0, 0],
defaultViewAPI: viewAPI,
});
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();
Expand All @@ -51,6 +56,7 @@ let volumeController;
let presetController;
let forceNearestControllers = [];
const params = {
viewAPI,
ParallelProjection: false,
Lighting: true,
LAO: false,
Expand Down Expand Up @@ -271,6 +277,14 @@ reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`).then(() => {

// TEST ==============

gui
.add(params, 'viewAPI', ['WebGL', 'WebGPU'])
.name('Renderer')
.onChange((api) => {
const query = new URLSearchParams(window.location.search);
query.set('viewAPI', api);
window.location.search = query.toString();
});
gui
.add(params, 'ParallelProjection')
.name('Parallel Projection')
Expand Down
10 changes: 8 additions & 2 deletions Sources/Rendering/WebGPU/Renderer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ function vtkWebGPURenderer(publicAPI, model) {
model.UBO.setArray('SCVCMatrix', keyMats.scvc);
model.UBO.setArray('VCPCMatrix', keyMats.vcpc);
model.UBO.setArray('WCVCNormals', keyMats.normalMatrix);
model.UBO.setValue('LightCount', model.renderable.getLights().length);
model.UBO.setValue(
'LightCount',
model.renderable.getLights().filter((light) => light.getSwitch() > 0)
.length
);
model.UBO.setValue(
'MaxEnvironmentMipLevel',
model.renderable.getEnvironmentTexture()?.getMipLevel()
Expand All @@ -166,7 +170,9 @@ function vtkWebGPURenderer(publicAPI, model) {
};

publicAPI.updateSSBO = () => {
const lights = model.renderable.getLights();
const lights = model.renderable
.getLights()
.filter((light) => light.getSwitch() > 0);
const keyMats = model.webgpuCamera.getKeyMatrices(publicAPI);

let lightTimeString = `${model.renderable.getMTime()}`;
Expand Down
16 changes: 16 additions & 0 deletions Sources/Rendering/WebGPU/TextureManager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ function vtkWebGPUTextureManager(publicAPI, model) {
break;
}

if (numComp === 3) {
const source = req.nativeArray;
const padded = macro.newTypedArray(
source.constructor.name,
(source.length / 3) * 4
);
const alpha = source.BYTES_PER_ELEMENT === 1 ? 255 : 1;
for (let i = 0, j = 0; i < source.length; i += 3, j += 4) {
padded[j] = source[i];
padded[j + 1] = source[i + 1];
padded[j + 2] = source[i + 2];
padded[j + 3] = alpha;
}
req.nativeArray = padded;
}

const dataType = req.dataArray.getDataType();
switch (dataType) {
case VtkDataTypes.UNSIGNED_CHAR:
Expand Down
41 changes: 33 additions & 8 deletions Sources/Rendering/WebGPU/VolumePass/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,22 @@ function vtkWebGPUVolumePass(publicAPI, model) {
});
model._depthRangeEncoder.setPipelineHash('volr');
model._depthRangeEncoder.setReplaceShaderCodeFunction((pipeline) => {
// Clamp vertex z to [0, w] so cube faces outside the camera frustum
// are NOT clipped by the GPU. Instead they contribute depth values at
// the near/far planes, ensuring every pixel covered by the volume has
// valid depth range values (fixes gaps at the silhouette when the
// near plane cuts into the volume).
const vDesc = pipeline.getShaderDescription('vertex');
let vCode = vDesc.getCode();
vCode = vCode.replace(
'output.Position = rendererUBO.SCPCMatrix*vertexBC;',
[
'output.Position = rendererUBO.SCPCMatrix*vertexBC;',
'output.Position.z = clamp(output.Position.z, 0.0, output.Position.w);',
].join('\n')
);
vDesc.setCode(vCode);

const fDesc = pipeline.getShaderDescription('fragment');
fDesc.addOutput('vec4<f32>', 'outColor1');
fDesc.addOutput('vec4<f32>', 'outColor2');
Expand All @@ -465,23 +481,32 @@ function vtkWebGPUVolumePass(publicAPI, model) {
code,
'//VTK::RenderEncoder::Impl',
[
'output.outColor1 = vec4<f32>(input.fragPos.z, 0.0, 0.0, 0.0);',
'output.outColor2 = vec4<f32>(stopval, 0.0, 0.0, 0.0);',
// Store the complement (1 - depth) so the r16float attachments
// keep their precision near the camera: reversed-z depths cluster
// near 1.0 where half floats are coarse (~5e-4 steps), while near
// 0.0 they resolve ~1e-7. The raycast quad decodes with 1 - value.
// max(depth) becomes min(1 - depth) and vice versa, hence the
// swapped blend operations and clear values on the attachments.
'output.outColor1 = vec4<f32>(1.0 - input.fragPos.z, 0.0, 0.0, 0.0);',
'output.outColor2 = vec4<f32>(1.0 - stopval, 0.0, 0.0, 0.0);',
]
).result;
fDesc.setCode(code);
});
// the attachments store 1 - depth (see the shader replacement above),
// so the entry (max depth) attachment blends with min and clears to 1,
// and the exit (min depth) attachment blends with max and clears to 0
model._depthRangeEncoder.setDescription({
colorAttachments: [
{
view: null,
clearValue: [0.0, 0.0, 0.0, 0.0],
clearValue: [1.0, 1.0, 1.0, 1.0],
loadOp: 'clear',
storeOp: 'store',
},
{
view: null,
clearValue: [1.0, 1.0, 1.0, 1.0],
clearValue: [0.0, 0.0, 0.0, 0.0],
loadOp: 'clear',
storeOp: 'store',
},
Expand All @@ -497,9 +522,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
color: {
srcFactor: 'one',
dstFactor: 'one',
operation: 'max',
operation: 'min',
},
alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'max' },
alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'min' },
},
},
{
Expand All @@ -508,9 +533,9 @@ function vtkWebGPUVolumePass(publicAPI, model) {
color: {
srcFactor: 'one',
dstFactor: 'one',
operation: 'min',
operation: 'max',
},
alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'min' },
alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'max' },
},
},
],
Expand Down
Loading
Loading