javascriptvolume-renderingvtk.js

How to render a Float32Array cube with vtk.js?


I want to render a 3D volume with vtk.js. My issue is that all the tutorials/examples in the vtk.js documentation load and render vti files. In my case, my data is just a Float32Array which contains the values of a 3D image. How can I volume-render that using vtk.js? I need a solution that creates no additional files on the file system.


Solution

  • I managed (with a coworker's help) to render a random cube volume like this:

    // pseudo imports (avoids having to use fully qualified names)
    var vtkFullScreenRenderWindow = vtk.Rendering.Misc.vtkFullScreenRenderWindow;
    var vtkImageData = vtk.Common.DataModel.vtkImageData;
    var vtkDataArray = vtk.Common.Core.vtkDataArray;
    var vtkVolume = vtk.Rendering.Core.vtkVolume;
    var vtkVolumeMapper = vtk.Rendering.Core.vtkVolumeMapper;
    var vtkColorTransferFunction = vtk.Rendering.Core.vtkColorTransferFunction;
    var vtkPiecewiseFunction = vtk.Common.DataModel.vtkPiecewiseFunction;
    
    var VtkDataTypes = vtkDataArray.VtkDataTypes;
    
    function initRandomCubeVolume() {
        var width = 50, height = 50, depth = 50;
        var size = width * height * depth;
    
        var values = [];
        for (var i = 0; i < size; i++) {
            values[i] = Math.random();
        }
    
        var scalars = vtkDataArray.newInstance({
            values: values,
            numberOfComponents: 1, // number of channels (grayscale)
            dataType: VtkDataTypes.FLOAT, // values encoding
            name: 'scalars'
        });
    
        var imageData = vtkImageData.newInstance();
        imageData.setOrigin(0, 0, 0);
        imageData.setSpacing(1, 1, 1);
        imageData.setExtent(0, width - 1, 0, height - 1, 0, depth - 1);
        imageData.getPointData().setScalars(scalars);
    
        var volumeMapper = vtkVolumeMapper.newInstance();
        volumeMapper.setInputData(imageData);
        volumeMapper.setSampleDistance(0.7);
    
        var volumeActor = vtkVolume.newInstance();
        volumeActor.setMapper(volumeMapper);
    
        initProps(volumeActor.getProperty());
    
        var view3d = document.getElementById("view3d");
        var fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
            rootContainer: view3d,
            containerStyle: {
                height: '100%',
                overflow: 'hidden'
            },
            background: [0, 0, 0]
        });
    
        var renderer = fullScreenRenderer.getRenderer();
        renderer.addVolume(volumeActor);
        renderer.resetCamera();
        renderer.getActiveCamera().elevation(-70);
        renderer.updateLightsGeometryToFollowCamera();
    
        var renderWindow = fullScreenRenderer.getRenderWindow();
        renderWindow.render();
    }
    
    function initProps(property) {
        property.setRGBTransferFunction(0, newColorFunction());
        property.setScalarOpacity(0, newOpacityFunction());
        property.setScalarOpacityUnitDistance(0, 4.5);
        property.setInterpolationTypeToLinear();
        property.setUseGradientOpacity(0, true);
        property.setGradientOpacityMinimumValue(0, 0, 5);
        property.setGradientOpacityMinimumOpacity(0, 0.0);
    
        property.setGradientOpacityMaximumValue(0, 1);
        property.setGradientOpacityMaximumOpacity(0, 1.0);
        property.setShade(true);
        property.setAmbient(0.2);
        property.setDiffuse(0.7);
        property.setSpecular(0.3);
        property.setSpecularPower(8.0);
    
    }
    
    function newColorFunction() {
        var fun = vtkColorTransferFunction.newInstance();
        fun.addRGBPoint(0, 0.4, 0.2, 0.0);
        fun.addRGBPoint(1, 1.0, 1.0, 1.0);
        return fun;
    }
    
    function newOpacityFunction() {
        var fun = vtkPiecewiseFunction.newInstance();
        fun.addPoint(0, 0);
        fun.addPoint(0.5, 0);
        fun.addPoint(0.5, 1);
        fun.addPoint(1, 1);
        return fun;
    }
    
    initRandomCubeVolume();
    #view3d { height: calc(100vh - 20px); /* avoid scrollbar because of margins */ }
    <script src="https://unpkg.com/vtk.js"></script>
    <div id="view3d"></div>

    Resistance is futile!