Skip to content

[Bug] Part of the volume inside polydata disappear when volumerendering image along with polydata #3228

Open
@linson7017

Description

@linson7017

Bug description

When i try to render a image and a polydata with vtkjs i find that the part of the image inside the cube disappear! The cube is transparent and its opacity is 0.3. I use vtkVolumeMapper for image data and vtkMapper for polydata.
Can anyone help me with these issue? How can i blend the volume and mesh data in 3D. Many thanks!
Image

Steps to reproduce

Using the following script can reproduce the issue. Just open the html file with web browser and load an *.vti file.
This is the html code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VTK.js Volume Rendering</title>
    <script src="https://unpkg.com/vtk.js"></script>
    <script src="main.js" defer></script>
    <style>
        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        #vtkContainer {
            width: 100vw;
            height: 100vh;
        }
        #fileInput {
            position: absolute;
            top: 10px;
            left: 10px;
            z-index: 1000;
        }
    </style>
</head>
<body>
    <input type="file" id="fileInput" accept=".vti" />
    <div id="vtkContainer"></div>
</body>
</html>

This is the js code. Save it as main.js.

document.addEventListener('DOMContentLoaded', function () {
    const vtkContainer = document.getElementById('vtkContainer');
    const fileInput = document.getElementById('fileInput');

    // Create the VTK.js full screen renderer
    const fullScreenRenderer = vtk.Rendering.Misc.vtkFullScreenRenderWindow.newInstance({
        rootContainer: vtkContainer,
        background: [0, 0, 0],
    });

    const renderer = fullScreenRenderer.getRenderer();
    const renderWindow = fullScreenRenderer.getRenderWindow();

    // Listen for file input changes
    fileInput.addEventListener('change', function (event) {
        const file = event.target.files[0];
        if (!file) return;

        const reader = new FileReader();
        reader.onload = function (e) {
            const arrayBuffer = e.target.result;

            // Create the reader for the .vti file
            const vtkReader = vtk.IO.XML.vtkXMLImageDataReader.newInstance();
            vtkReader.parseAsArrayBuffer(arrayBuffer);
            const imageData = vtkReader.getOutputData();

            // Print image data information for debugging
            console.log('Image Data:', imageData);
            console.log('Bounds:', imageData.getBounds());
            console.log('Dimensions:', imageData.getDimensions());
            console.log('Scalar Range:', imageData.getPointData().getScalars().getRange());

            // Create the volume mapper and actor
            const volumeMapper = vtk.Rendering.Core.vtkVolumeMapper.newInstance();
            volumeMapper.setInputData(imageData);
			volumeMapper.setSampleDistance(0.2)

            const volumeActor = vtk.Rendering.Core.vtkVolume.newInstance();
            volumeActor.setMapper(volumeMapper);
			//volumeActor.getProperty().setBlendModeToComposite();  // 合成模式
			// volumeActor.getProperty().setBlendModeToMaximumIntensity();  // MIP模式


            // Set up color transfer function
            const colorTransferFunction = vtk.Rendering.Core.vtkColorTransferFunction.newInstance();
            colorTransferFunction.addRGBPoint(0, 1, 1, 1); // Black for low values
            colorTransferFunction.addRGBPoint(3000, 1, 1, 1); // White for high values

            // Set up opacity transfer function
            const piecewiseFunction = vtk.Common.DataModel.vtkPiecewiseFunction.newInstance();
            piecewiseFunction.addPoint(-467, 0); // Fully transparent for low values
            piecewiseFunction.addPoint(221, 0); // Fully opaque for high values
			piecewiseFunction.addPoint(537, 0);
			piecewiseFunction.addPoint(2190, 0.873);
			piecewiseFunction.addPoint(3000, 1);

            // Assign transfer functions to the volume property
            const volumeProperty = volumeActor.getProperty();
            volumeProperty.setRGBTransferFunction(0, colorTransferFunction);
            volumeProperty.setScalarOpacity(0, piecewiseFunction);
            volumeProperty.setInterpolationTypeToLinear(); // Smooth rendering

            // Add the volume actor to the renderer
            renderer.addVolume(volumeActor);

            // Create a transparent bounding box
            const bounds = imageData.getBounds(); // Get the bounds of the volume
			const center = [
                (bounds[0] + bounds[1]) / 2, // X center
                (bounds[2] + bounds[3]) / 2, // Y center
                (bounds[4] + bounds[5]) / 2, // Z center
            ];
			const size = [
                bounds[1] - bounds[0], // X size
                bounds[3] - bounds[2], // Y size
                bounds[5] - bounds[4]  // Z size
            ];
			
			bounds[0] = bounds[0]+size[0]*0.25
			bounds[1] = bounds[1]-size[0]*0.25
			bounds[2] = bounds[2]+size[1]*0.25
			bounds[3] = bounds[3]-size[1]*0.25
			bounds[4] = bounds[4]+size[2]*0.25
			bounds[5] = bounds[5]-size[2]*0.25
			
            const cubeSource = vtk.Filters.Sources.vtkCubeSource.newInstance();
            cubeSource.setBounds(bounds); // Set the cube bounds to match the volume

            const cubeMapper = vtk.Rendering.Core.vtkMapper.newInstance();
            cubeMapper.setInputConnection(cubeSource.getOutputPort());

            const cubeActor = vtk.Rendering.Core.vtkActor.newInstance();
            cubeActor.setMapper(cubeMapper);

            // Set the cube properties to make it transparent
            const cubeProperty = cubeActor.getProperty();
            cubeProperty.setColor(1, 1, 1); // White color
            cubeProperty.setOpacity(0.2); // 20% opacity
            cubeProperty.setEdgeVisibility(true); // Show edges
            cubeProperty.setEdgeColor(1, 1, 1); // White edges

            // Add the cube actor to the renderer
            renderer.addActor(cubeActor);

            // Reset the camera and render
            renderer.resetCamera();
            renderWindow.render();
        };
        reader.readAsArrayBuffer(file);
    });
});

Detailed Behavior

No response

Expected Behavior

The volume inside polydata can also be rendered

Environment

  • vtk.js version:
  • Browsers: Chrome, Edge
  • OS: Windows or Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions