Hi,
I’m using vtk-wasm-sdk docker to compile my own wasm bundle to use in my web app.
This is my render volume code:
void renderLoadedVolume() {
std::cout << "=== renderLoadedVolume called ===" << std::endl;
if (!g_renderWindow) {
std::cerr << "Error: g_renderWindow is null!" << std::endl;
return;
}
std::cout << "RenderWindow OK" << std::endl;
if (!g_renderer) {
std::cerr << "Error: g_renderer is null!" << std::endl;
return;
}
std::cout << "Renderer OK" << std::endl;
if (!g_imageData) {
std::cerr << "Error: g_imageData is null!" << std::endl;
return;
}
std::cout << "ImageData OK" << std::endl;
// Check image data properties
int* dims = g_imageData->GetDimensions();
std::cout << "Dimensions: " << dims[0] << " x " << dims[1] << " x " << dims[2] << std::endl;
double* spacing = g_imageData->GetSpacing();
std::cout << "Spacing: " << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << std::endl;
double* origin = g_imageData->GetOrigin();
std::cout << "Origin: " << origin[0] << ", " << origin[1] << ", " << origin[2] << std::endl;
double scalarRange[2];
g_imageData->GetScalarRange(scalarRange);
std::cout << "Scalar range: " << scalarRange[0] << " to " << scalarRange[1] << std::endl;
int scalarType = g_imageData->GetScalarType();
std::cout << "Scalar type: " << scalarType << " (VTK_SHORT=" << VTK_SHORT << ", VTK_UNSIGNED_SHORT=" << VTK_UNSIGNED_SHORT << ")" << std::endl;
vtkIdType numPoints = g_imageData->GetNumberOfPoints();
std::cout << "Number of points: " << numPoints << std::endl;
if (numPoints == 0) {
std::cerr << "Error: No data points in image!" << std::endl;
return;
}
// Check if dimensions are valid
if (dims[0] <= 1 || dims[1] <= 1 || dims[2] <= 1) {
std::cerr << "Error: Invalid dimensions - need 3D volume!" << std::endl;
return;
}
std::cout << "Creating volume mapper..." << std::endl;
g_volumeMapper = vtkSmartPointer<vtkSmartVolumeMapper>::New();
if (!g_volumeMapper) {
std::cerr << "Error: Failed to create volume mapper!" << std::endl;
return;
}
auto cast = vtkSmartPointer<vtkImageCast>::New();
cast->SetInputData(g_imageData);
cast->SetOutputScalarTypeToFloat();
cast->Update();
g_volumeMapper->SetInputData(cast->GetOutput());
g_volumeMapper->SetBlendModeToComposite();
// Disable auto-adjust so we control sample distance on interaction start/stop
g_volumeMapper->SetAutoAdjustSampleDistances(false);
// Compute fine/coarse sample distances from voxel spacing
g_fineSampleDistance = std::min({spacing[0], spacing[1], spacing[2]}) * 0.5;
g_coarseSampleDistance = g_fineSampleDistance * 4.0;
g_volumeMapper->SetSampleDistance(g_fineSampleDistance);
std::cout << "Volume mapper created (fine=" << g_fineSampleDistance
<< " coarse=" << g_coarseSampleDistance << ")" << std::endl;
std::cout << "Creating color transfer function (Bone preset)..." << std::endl;
g_colorFunc = vtkSmartPointer<vtkColorTransferFunction>::New();
// AddRGBPoint(scalar, R, G, B, midpoint, sharpness)
g_colorFunc->AddRGBPoint(-3024.0, 0.0, 0.0, 0.0, 0.5, 0.0);
g_colorFunc->AddRGBPoint(-2800.0, 0.0, 0.0, 0.0, 0.5, 0.0);
g_colorFunc->AddRGBPoint(90.0, 1.0, 1.0, 0.0, 0.5, 0.0);
g_colorFunc->AddRGBPoint(150.0, 1.0, 0.1, 0.0, 0.5, 0.0);
g_colorFunc->AddRGBPoint(280.0, 1.0, 0.77, 0.73, 0.5, 0.0);
g_colorFunc->AddRGBPoint(520.0, 1.0, 0.95, 0.6, 0.5, 0.0);
g_colorFunc->AddRGBPoint(700.0, 1.0, 1.0, 1.0, 0.5, 0.0);
g_colorFunc->AddRGBPoint(2000.0, 1.0, 1.0, 1.0, 0.5, 0.0);
g_colorFunc->AddRGBPoint(3071.0, 0.0, 0.0, 1.0, 0.5, 0.0);
std::cout << "Color transfer function created" << std::endl;
std::cout << "Creating opacity transfer function (Bone preset)..." << std::endl;
g_opacityFunc = vtkSmartPointer<vtkPiecewiseFunction>::New();
// AddPoint(scalar, opacity, midpoint, sharpness)
g_opacityFunc->AddPoint(-3024.0, 0.0, 0.5, 0.0);
g_opacityFunc->AddPoint(100.0, 0.0, 0.5, 0.0);
g_opacityFunc->AddPoint(250.0, 0.2, 0.5, 0.0);
g_opacityFunc->AddPoint(430.0, 0.5, 0.5, 0.0);
g_opacityFunc->AddPoint(580.0, 0.8, 0.5, 0.0);
g_opacityFunc->AddPoint(1500.0, 1.0, 0.5, 0.0);
g_opacityFunc->AddPoint(3071.0, 0.6, 0.5, 0.0);
std::cout << "Opacity transfer function created" << std::endl;
std::cout << "Creating volume property..." << std::endl;
g_gradientOpacityFunc = vtkSmartPointer<vtkPiecewiseFunction>::New();
g_gradientOpacityFunc->AddPoint(0, 1);
g_gradientOpacityFunc->AddPoint(255, 1);
std::cout << "Gradient opacity transfer function created" << std::endl;
g_volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
g_volumeProperty->SetIndependentComponents(true);
g_volumeProperty->SetColor(g_colorFunc);
g_volumeProperty->SetScalarOpacity(g_opacityFunc);
// Toggle gradient rendering
g_volumeProperty->SetGradientOpacity(g_gradientOpacityFunc);
g_volumeProperty->SetAmbient(0.1);
g_volumeProperty->SetDiffuse(0.9);
g_volumeProperty->SetSpecular(0.2);
g_volumeProperty->SetSpecularPower(10);
g_volumeProperty->SetInterpolationTypeToLinear();
// Toggle shade rendering
g_volumeProperty->ShadeOff();
double minSpacing = std::min({spacing[0], spacing[1], spacing[2]});
g_volumeProperty->SetScalarOpacityUnitDistance(minSpacing);
std::cout << "Volume property created, unit distance: " << minSpacing << std::endl;
std::cout << "Creating volume actor..." << std::endl;
g_actor = vtkSmartPointer<vtkVolume>::New();
g_actor->SetMapper(g_volumeMapper);
g_actor->SetProperty(g_volumeProperty);
std::cout << "Volume actor created" << std::endl;
std::cout << "Adding volume to renderer..." << std::endl;
g_renderer->AddActor(g_actor);
std::cout << "Volume added to renderer" << std::endl;
std::cout << "Resetting camera..." << std::endl;
g_renderer->ResetCamera();
// Face-on (coronal) view: camera at anterior (+Y in RAS), head up (-Z = superior)
{
auto cam = g_renderer->GetActiveCamera();
double* fp = cam->GetFocalPoint();
double dist = cam->GetDistance();
cam->SetPosition(fp[0], fp[1] + dist, fp[2]);
cam->SetViewUp(0, 0, -1);
}
std::cout << "Camera reset" << std::endl;
std::cout << "Rendering..." << std::endl;
g_renderWindow->Render();
std::cout << "Render complete" << std::endl;
std::cout << "Starting interactor..." << std::endl;
g_interactor->SetStillUpdateRate(0);
g_interactor->SetDesiredUpdateRate(40);
// Observers: immediately switch sample distance on interaction start/stop
auto startCb = vtkSmartPointer<vtkCallbackCommand>::New();
startCb->SetCallback([](vtkObject*, unsigned long, void*, void*) {
if (g_volumeMapper) {
g_volumeMapper->SetSampleDistance(g_coarseSampleDistance);
std::cout << "Interaction start -> coarse (" << g_coarseSampleDistance << ")" << std::endl;
}
});
g_interactor->AddObserver(vtkCommand::StartInteractionEvent, startCb);
auto endCb = vtkSmartPointer<vtkCallbackCommand>::New();
endCb->SetCallback([](vtkObject*, unsigned long, void*, void*) {
if (g_volumeMapper) {
g_volumeMapper->SetSampleDistance(g_fineSampleDistance);
std::cout << "Interaction end -> fine (" << g_fineSampleDistance << ")" << std::endl;
if (g_renderWindow) g_renderWindow->Render();
}
});
g_interactor->AddObserver(vtkCommand::EndInteractionEvent, endCb);
g_interactor->Start();
std::cout << "Interactor started" << std::endl;
std::cout << "=== renderLoadedVolume finished ===" << std::endl;
}
The moment I set gradient opacity to volume property I get this error
I’m not sure what this error is
