-
-
Notifications
You must be signed in to change notification settings - Fork 382
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(RenderWindow): Add an example for using a parent render window
- Loading branch information
Showing
1 changed file
with
166 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import '@kitware/vtk.js/favicon'; | ||
|
||
// Load the rendering pieces we want to use (for both WebGL and WebGPU) | ||
import '@kitware/vtk.js/Rendering/Misc/RenderingAPIs'; | ||
import '@kitware/vtk.js/Rendering/Profiles/Volume'; | ||
|
||
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction'; | ||
import vtkHttpDataSetReader from '@kitware/vtk.js/IO/Core/HttpDataSetReader'; | ||
import vtkInteractorStyleTrackballCamera from '@kitware/vtk.js/Interaction/Style/InteractorStyleTrackballCamera'; | ||
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction'; | ||
import vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer'; | ||
import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow'; | ||
import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor'; | ||
import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume'; | ||
import vtkVolumeMapper from '@kitware/vtk.js/Rendering/Core/VolumeMapper'; | ||
|
||
// Force the loading of HttpDataAccessHelper to support gzip decompression | ||
import '@kitware/vtk.js/IO/Core/DataAccessHelper/HttpDataAccessHelper'; | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Background colors | ||
// ---------------------------------------------------------------------------- | ||
|
||
async function createActor() { | ||
const actor = vtkVolume.newInstance(); | ||
const mapper = vtkVolumeMapper.newInstance(); | ||
mapper.setSampleDistance(0.7); | ||
mapper.setVolumetricScatteringBlending(0); | ||
mapper.setLocalAmbientOcclusion(0); | ||
mapper.setLAOKernelSize(10); | ||
mapper.setLAOKernelRadius(5); | ||
mapper.setComputeNormalFromOpacity(true); | ||
actor.setMapper(mapper); | ||
|
||
const ctfun = vtkColorTransferFunction.newInstance(); | ||
ctfun.addRGBPoint(0, 0, 0, 0); | ||
ctfun.addRGBPoint(95, 1.0, 1.0, 1.0); | ||
ctfun.addRGBPoint(225, 0.66, 0.66, 0.5); | ||
ctfun.addRGBPoint(255, 0.3, 0.3, 0.5); | ||
const ofun = vtkPiecewiseFunction.newInstance(); | ||
ofun.addPoint(100.0, 0.0); | ||
ofun.addPoint(255.0, 1.0); | ||
actor.getProperty().setRGBTransferFunction(0, ctfun); | ||
actor.getProperty().setScalarOpacity(0, ofun); | ||
actor.getProperty().setInterpolationTypeToLinear(); | ||
actor.getProperty().setShade(true); | ||
actor.getProperty().setAmbient(0.3); | ||
actor.getProperty().setDiffuse(1); | ||
actor.getProperty().setSpecular(1); | ||
actor.setScale(0.003, 0.003, 0.003); | ||
actor.setPosition(1, 1, -1.1); | ||
|
||
const reader = vtkHttpDataSetReader.newInstance({ fetchGzip: true }); | ||
await reader.setUrl(`${__BASE_PATH__}/data/volume/LIDC2.vti`); | ||
await reader.loadData(); | ||
const imageData = reader.getOutputData(); | ||
|
||
mapper.setInputData(imageData); | ||
|
||
return actor; | ||
} | ||
|
||
const mainRenderWindow = vtkRenderWindow.newInstance(); | ||
const mainRenderWindowView = mainRenderWindow.newAPISpecificView(); | ||
mainRenderWindow.addView(mainRenderWindowView); | ||
|
||
const rootContainer = document.createElement('div'); | ||
rootContainer.style.display = 'flex'; | ||
rootContainer.style['align-items'] = 'center'; | ||
rootContainer.style['justify-content'] = 'space-between'; | ||
rootContainer.style['flex-wrap'] = 'wrap'; | ||
document.body.appendChild(rootContainer); | ||
|
||
function applyStyle(element) { | ||
const width = Math.floor(200 + Math.random() * 200); | ||
const height = Math.floor(200 + Math.random() * 200); | ||
element.style.width = `${width}px`; | ||
element.style.height = `${height}px`; | ||
element.style.margin = '20px'; | ||
element.style.border = 'solid 2px #333'; | ||
return element; | ||
} | ||
|
||
function addRenderWindow() { | ||
// Create a child renderwindow | ||
const renderWindow = vtkRenderWindow.newInstance(); | ||
mainRenderWindow.addRenderWindow(renderWindow); | ||
|
||
// Create the corresponding view | ||
const renderWindowView = mainRenderWindowView.addMissingNode(renderWindow); | ||
|
||
// Create a container for the view | ||
const container = applyStyle(document.createElement('div')); | ||
rootContainer.appendChild(container); | ||
renderWindowView.setContainer(container); | ||
|
||
// Resize the view to the size of the container | ||
// Ideally, we would use a resize observer to resize the view and | ||
// call resizeFromChildRenderWindows on the main view when the container is resized | ||
const containerBounds = container.getBoundingClientRect(); | ||
const pixRatio = window.devicePixelRatio; | ||
const dimensions = [ | ||
containerBounds.width * pixRatio, | ||
containerBounds.height * pixRatio, | ||
]; | ||
renderWindowView.setSize(...dimensions); | ||
const canvas = renderWindowView.getCanvas(); | ||
canvas.style.width = `${container.clientWidth}px`; | ||
canvas.style.height = `${container.clientHeight}px`; | ||
|
||
// Add an interactor to the view | ||
const interactor = vtkRenderWindowInteractor.newInstance(); | ||
interactor.setView(renderWindowView); | ||
interactor.initialize(); | ||
interactor.bindEvents(canvas); | ||
interactor.setInteractorStyle( | ||
vtkInteractorStyleTrackballCamera.newInstance() | ||
); | ||
|
||
return renderWindow; | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Fill up page | ||
// ---------------------------------------------------------------------------- | ||
|
||
const childRenderWindows = []; | ||
createActor().then((actor) => { | ||
// Main view has to be initialized before the first "render" from a child render window | ||
// We initialize before creating the child render windows because the interactor initialization calls "render" on them | ||
mainRenderWindowView.initialize(); | ||
|
||
for (let i = 0; i < 64; i++) { | ||
const childRenderWindow = addRenderWindow(); | ||
|
||
// Create the corresponding renderer | ||
const background = [ | ||
0.5 * Math.random() + 0.25, | ||
0.5 * Math.random() + 0.25, | ||
0.5 * Math.random() + 0.25, | ||
]; | ||
const renderer = vtkRenderer.newInstance({ background }); | ||
childRenderWindow.addRenderer(renderer); | ||
|
||
// Add the actor and reset camera | ||
renderer.addActor(actor); | ||
const camera = renderer.getActiveCamera(); | ||
camera.yaw(90); | ||
camera.roll(90); | ||
camera.azimuth(Math.random() * 360); | ||
renderer.resetCamera(); | ||
|
||
childRenderWindows.push(childRenderWindow); | ||
} | ||
|
||
mainRenderWindowView.resizeFromChildRenderWindows(); | ||
mainRenderWindow.render(); | ||
}); | ||
|
||
// ---------------------------------------------------------------------------- | ||
// Globals | ||
// ---------------------------------------------------------------------------- | ||
|
||
global.rw = mainRenderWindow; | ||
global.glrw = mainRenderWindowView; | ||
global.childRw = childRenderWindows; |