First of all thanks to VTK team for the great library!
BACKGROUND
Our research group is developing surgical simulators, where with one of these we use a simple vtk-pipeline to generate “x-ray-like” images from STL-files. Currently I am working hard to provide a native software for Apple M1-chips. All things are working like a charm, BUT the pipeline for generating x-ray images fails.
PROBLEM
Compiling an an Intel-Based MacBook-Pro everything works as expected.
Compiling the same code (see below) on a MacStudio with the M1-Max chipset shows a box around the object. The corresponding message is
WARN| vtkOpenGLVolumeOpacityTable (0x600002070360): This OpenGL implementation does not support the required texture size of 65536, falling back to maximum allowed, 16384.This may cause an incorrect lookup table mapping
which indicates, that something goes wrong with the vtkPiecewiseFunction
and its OpenGL Implementation which controls the volume opacity.
REMARKS
I was using VTK-9.2.2 compiled natively on both systems as listed below. When running the test program, which was compiled on the Intel-based system over the Rosetta2 framework on the Apple-M1-Chip system, everything works as expected. So the bad results show only on the Apple-M1-Chip system compiled there natively (Xcode Framework 13).
SYSTEMS
The used systems are:
ARM64:
Modellname: Mac Studio
Modell-Identifizierung: Mac13,1
Chip: Apple M1 Max
Gesamtanzahl der Kerne: 10 (8 Leistung und 2 Effizienz)
Speicher: 32 GB
Apple M1 Max:
Chipsatz-Modell: Apple M1 Max
Typ: GPU
Bus: Integriert
Gesamtanzahl der Kerne: 24
Hersteller: Apple (0x106b)
Metal-Familie: Unterstützt, Metal GPUFamily Apple 7
INTEL64:
Modellname: MacBook Pro
Modell-Identifizierung: MacBookPro16,2
Prozessortyp: Quad-Core Intel Core i7
Prozessorgeschwindigkeit: 2,3 GHz
Anzahl der Prozessoren: 1
Gesamtanzahl der Kerne: 4
L2-Cache (pro Kern): 512 KB
L3-Cache: 8 MB
Hyper-Threading Technologie: Aktiviert
Speicher: 16 GB
Intel Iris Plus Graphics:
Chipsatz-Modell: Intel Iris Plus Graphics
Typ: GPU
Bus: Integriert
VRAM (dynamisch, maximal): 1536 MB
Hersteller: Intel
Geräte-ID: 0x8a53
Versions-ID: 0x0007
Metal-Familie: Unterstützt, Metal GPUFamily macOS 2
CODE
For the pipeline the test program is as follows (File TestPipeline.cxx):
#include <vtkImplicitModeller.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkSmartVolumeMapper.h>
#include <vtkVolume.h>
#include <vtkVolumeProperty.h>
#include <vtkPiecewiseFunction.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkCleanPolyData.h>
#include <vtkImageShiftScale.h>
#include <vtkImageData.h>
#include <vtkAppendPolyData.h>
#include <vtkImageGaussianSmooth.h>
#include <vtkSphereSource.h>
#include <vtksys/SystemTools.hxx>
int main(int argc, char* argv[])
{
vtkNew<vtkNamedColors> colors;
// sphere
vtkNew<vtkSphereSource> sphereSource;
sphereSource->SetCenter(0.0, 0.0, 0.0);
sphereSource->SetRadius(5.0);
// Make the surface smooth.
sphereSource->SetPhiResolution(100);
sphereSource->SetThetaResolution(100);
// append filter
vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter->SetInputConnection(sphereSource->GetOutputPort());
// clean filter
vtkSmartPointer<vtkCleanPolyData> cleanFilter = vtkSmartPointer<vtkCleanPolyData>::New();
cleanFilter->SetInputConnection(appendFilter->GetOutputPort());
cleanFilter->Update();
// implicit modeler
vtkNew<vtkImplicitModeller> implicitModeller;
implicitModeller->SetSampleDimensions(80, 80, 80);
implicitModeller->SetInputData(cleanFilter->GetOutput());
implicitModeller->AdjustBoundsOn();
implicitModeller->SetAdjustDistance(.1); // Adjust by 10%
implicitModeller->SetMaximumDistance(.01);
implicitModeller->Update();
// sfift and scale
vtkSmartPointer<vtkImageShiftScale> ImageCast = vtkSmartPointer<vtkImageShiftScale>::New();
ImageCast->SetInputData(implicitModeller->GetOutput());
ImageCast->SetShift(1);
ImageCast->SetScale(127);
ImageCast->SetOutputScalarTypeToUnsignedShort();
ImageCast->Update();
// gaussian smooth
vtkSmartPointer<vtkImageGaussianSmooth> gaussianSmoothFilter =
vtkSmartPointer<vtkImageGaussianSmooth>::New();
gaussianSmoothFilter->SetInputConnection(ImageCast->GetOutputPort());
gaussianSmoothFilter->SetStandardDeviations(1, 1, 1);
gaussianSmoothFilter->Update();
// mapper
vtkNew<vtkSmartVolumeMapper> volumeMapper;
volumeMapper->SetRequestedRenderModeToRayCast();
volumeMapper->SetRequestedRenderModeToGPU();
volumeMapper->SetInterpolationModeToLinear();
volumeMapper->SetBlendModeToComposite();
volumeMapper->SetInputData(gaussianSmoothFilter->GetOutput());
vtkNew<vtkVolume> volume;
// Opacity transfer function
vtkSmartPointer<vtkPiecewiseFunction> opacityTransferFunction =
vtkSmartPointer<vtkPiecewiseFunction>::New();
opacityTransferFunction->AddPoint(0, 0.0);
opacityTransferFunction->AddPoint(1, 0.1);
// Volume property
vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
volumeProperty->SetScalarOpacity(opacityTransferFunction);
volumeProperty->ShadeOn();
volumeProperty->SetInterpolationTypeToLinear();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
// Renderer, Window and Interactor
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renderWindow);
// add volume
renderer->AddVolume(volume);
renderer->SetBackground(colors->GetColor3d("Wheat").GetData());
renderWindow->SetSize(640, 480);
renderWindow->SetWindowName("Test Pipeline");
renderWindow->Render();
interactor->Start();
return EXIT_SUCCESS;
}
The corresponding CMake file (CMakeLists.txt) is:
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(TestPipeline)
find_package(VTK COMPONENTS
CommonColor
CommonCore
CommonDataModel
FiltersCore
FiltersHybrid
FiltersSources
IOGeometry
IOLegacy
IOPLY
IOXML
ImagingCore
ImagingGeneral
ImagingHybrid
ImagingMath
InteractionStyle
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
RenderingVolumeOpenGL2
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "TestPipeline: Unable to find the VTK build folder.")
endif()
# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(TestPipeline MACOSX_BUNDLE TestPipeline.cxx )
target_link_libraries(TestPipeline PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS TestPipeline
MODULES ${VTK_LIBRARIES}
)