Skip to content

Commit

Permalink
test(VolumeMapper): add UpdatedExtents test
Browse files Browse the repository at this point in the history
  • Loading branch information
floryst committed Jun 11, 2024
1 parent 657b587 commit 5c8f191
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 11 deletions.
22 changes: 12 additions & 10 deletions Sources/Rendering/OpenGL/Texture/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,29 +643,30 @@ function vtkOpenGLTexture(publicAPI, model) {
* Assumes X varies the fastest and Z varies the slowest.
*
* @param {*} data
* @param {*} dataDims
* @param {Extent} extent
* @param {TypedArray} outArray
* @param {number} outOffset
* @returns
*/
function readExtentIntoArray(data, extent, outArray, outOffset) {
const [, , ymin, ymax, zmin, zmax] = extent;
const [sx, sy] = getExtentSize(extent);
const sxy = sx * sy;
function readExtentIntoArray(data, dataDims, extent, outArray, outOffset) {
const [xmin, xmax, ymin, ymax, zmin, zmax] = extent;
const [dx, dy] = dataDims;
const sxy = dx * dy;

let writeOffset = outOffset;
for (let zi = zmin; zi <= zmax; zi++) {
const zOffset = zi * sxy;
for (let yi = ymin; yi <= ymax; yi++) {
const readOffset = zOffset + yi * sx;
const zyOffset = zOffset + yi * dx;
// explicit alternative to data.subarray,
// due to potential perf issues on v8
for (
let xi = readOffset, end = readOffset + sx;
xi < end;
xi++, writeOffset++
let readOffset = zyOffset + xmin, end = zyOffset + xmax;
readOffset <= end;
readOffset++, writeOffset++
) {
outArray[writeOffset] = data[xi];
outArray[writeOffset] = data[readOffset];
}
}
}
Expand All @@ -688,10 +689,11 @@ function vtkOpenGLTexture(publicAPI, model) {
0
);
const extentPixels = new constructor(numPixels);
const dataDims = [model.width, model.height, model.depth];

let writeOffset = 0;
extents.forEach((extent) => {
readExtentIntoArray(data, extent, extentPixels, writeOffset);
readExtentIntoArray(data, dataDims, extent, extentPixels, writeOffset);
writeOffset += getExtentPixelCount(extent);
});

Expand Down
2 changes: 1 addition & 1 deletion Sources/Rendering/OpenGL/VolumeMapper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1681,7 +1681,7 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
// Build the textures
// If hasUpdatedExtents, then the texture is partially updated
const updatedExtents = [...model.renderable.getUpdatedExtents()];
// clear, as we've acknowledged the update.
// clear the array to acknowledge the update.
model.renderable.setUpdatedExtents([]);

const dims = image.getDimensions();
Expand Down
124 changes: 124 additions & 0 deletions Sources/Rendering/OpenGL/VolumeMapper/test/testUpdatedExtents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import test from 'tape';
import testUtils from 'vtk.js/Sources/Testing/testUtils';

import 'vtk.js/Sources/Rendering/Misc/RenderingAPIs';

import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction';
import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction';
import vtkRenderWindow from 'vtk.js/Sources/Rendering/Core/RenderWindow';
import vtkRenderWindowInteractor from 'vtk.js/Sources/Rendering/Core/RenderWindowInteractor';
import vtkRenderer from 'vtk.js/Sources/Rendering/Core/Renderer';
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper';
import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData';

import baseline from './testUpdatedExtents.png';

test.onlyIfWebGL('Test Volume Mapper Updated Extents', async (t) => {
const gc = testUtils.createGarbageCollector(t);
t.ok('rendering', 'vtkVolumeMapper UpdatedExtents');

// Create some control UI
const container = document.querySelector('body');
const renderWindowContainer = gc.registerDOMElement(
document.createElement('div')
);
container.appendChild(renderWindowContainer);

// create what we will view
const renderWindow = gc.registerResource(vtkRenderWindow.newInstance());
const renderer = gc.registerResource(vtkRenderer.newInstance());
renderWindow.addRenderer(renderer);
renderer.setBackground(0.32, 0.34, 0.43);

const actor = gc.registerResource(vtkVolume.newInstance());

const mapper = gc.registerResource(vtkVolumeMapper.newInstance());
mapper.setSampleDistance(0.5);
actor.setMapper(mapper);

const sideLen = 100;

const imageData = vtkImageData.newInstance();
imageData.setExtent(0, sideLen - 1, 0, sideLen - 1, 0, sideLen - 1);
const pixelData = new Float32Array(sideLen * sideLen * sideLen);

const da = vtkDataArray.newInstance({
numberOfComponents: 1,
values: pixelData,
});
da.setName('scalars');
imageData.getPointData().setScalars(da);

mapper.setInputData(imageData);

// create color and opacity transfer functions
const ctfun = vtkColorTransferFunction.newInstance();
ctfun.addRGBPoint(0.0, 0.0, 0.0, 0.0);
ctfun.addRGBPoint(1.0, 1.0, 0.0, 0.5);
const ofun = vtkPiecewiseFunction.newInstance();
ofun.addPoint(0.0, 0.0);
ofun.addPoint(1.0, 1.0);
actor.getProperty().setRGBTransferFunction(0, ctfun);
actor.getProperty().setScalarOpacity(0, ofun);
actor.getProperty().setAmbient(0.5);
actor.getProperty().setShade(1);

// now create something to view it
const glwindow = gc.registerResource(renderWindow.newAPISpecificView());
glwindow.setContainer(renderWindowContainer);
renderWindow.addView(glwindow);
glwindow.setSize(400, 400);

// Interactor
const interactor = vtkRenderWindowInteractor.newInstance();
interactor.setStillUpdateRate(0.01);
interactor.setView(glwindow);
interactor.initialize();
interactor.bindEvents(renderWindowContainer);

renderer.addVolume(actor);
actor.getProperty().setInterpolationTypeToLinear();

// Initial render
renderer.resetCamera();
renderWindow.render();

const mid = sideLen / 2;
const radius = mid - 1;

// Generate a 3D sphere
let i = 0;
for (let z = 0; z < sideLen; z++) {
for (let y = 0; y < sideLen; y++) {
for (let x = 0; x < sideLen; x++) {
const dist = Math.sqrt(
(x - mid) ** 2 + (y - mid) ** 2 + (z - mid) ** 2
);
pixelData[i++] = dist < radius ? 1 : 0;
}
}
}

// Update only a portion of the volume rendering texture
mapper.setUpdatedExtents([
[0, mid - 1, 0, mid - 1, 0, mid - 1],
[mid - 1, sideLen - 1, mid - 1, sideLen - 1, mid - 1, sideLen - 1],
]);

const promise = glwindow
.captureNextImage()
.then((image) =>
testUtils.compareImages(
image,
[baseline],
'Rendering/Core/VolumeMapper/testUpdatedExtents',
t,
1.5,
gc.releaseResources
)
);
renderWindow.render();
return promise;
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5c8f191

Please sign in to comment.