目前vtk9.2.2版本中已经集成了ray marching(光线步进)算法实现的体渲染功能,官方博客中已经介绍为电影级体渲染了,如图:
此效果是在3d显示器上的显示效果,就此效果来看说是电影级渲染效果也没什么问题,但是和光线追踪来实现的CVR还是差一些,下图为光线追踪的方法来实现的CVR。
首先可以先了解下这几个名词概念
Ray Marching 光线步进 基本只用于volumetric(体积绘制)
RayTracing 光线追踪 在与物体相交后会选一个随机方向继续跟踪,并根据BRDF计算颜色(全局照明 (GI),反射)
Ray Casting 光线投射 该算法的计算不会停留在物体的表面,而会沿着射线穿过物体内部进行采样,且不会产生二次射线。我们在VTK中使用的vtkGPUVolumeRayCastMapper就是光线投射原理。
VTK实现Ray Marching也是基于光线投射的mapper,只是加了两个接口控制。并且最好自己加上灯光,且控制灯光的旋转等。
vtkNew<vtkGPUVolumeRayCastMapper> mapper;
mapper->SetAutoAdjustSampleDistances(0);
mapper->SetSampleDistance(0.5);
//mapper->UseJitteringOn();
mapper->SetInputData(reader->GetOutput());
mapper->SetGlobalIlluminationReach(0.75);
mapper->SetVolumetricScatteringBlending(1.0);
SetGlobalIlluminationReach 控制着射向光线的次级光线的范围/范围。值0.0表示只渲染局部阴影(但它更快),值1.0表示渲染所有阴影(但它更慢)。
SetVolumetricScatteringBlending 控制散射模型混合的效果。
效果实现:
代码:
#include <vtkNew.h>
#include <vtkNIFTIImageReader.h>
#include <vtkFixedPointVolumeRayCastMapper.h>
#include <vtkImageGaussianSmooth.h>
#include <vtkVolumeProperty.h>
#include <vtkPiecewiseFunction.h>
#include <vtkColorTransferFunction.h>
#include <vtkVolume.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkPiecewiseFunction.h>
#include <vtkColorTransferFunction.h>
#include <vtkWindowToImageFilter.h>
#include <vtkLight.h>
using namespace std;
int main()
{
vtkNew<vtkNIFTIImageReader> reader;
reader->SetFileName(R"(./00001741.nii.gz)");
reader->Update();
vtkNew<vtkGPUVolumeRayCastMapper> mapper;
mapper->SetAutoAdjustSampleDistances(0);
mapper->SetSampleDistance(0.5);
//mapper->UseJitteringOn();
mapper->SetInputData(reader->GetOutput());
mapper->SetGlobalIlluminationReach(0.75);
mapper->SetVolumetricScatteringBlending(1.0);
vtkNew<vtkVolume> volume;
volume->SetMapper(mapper);
vtkNew<vtkVolumeProperty> volumeProperty;
volumeProperty->SetInterpolationTypeToLinear();
volumeProperty->ShadeOn(); //打开或者关闭阴影测试
volumeProperty->SetAmbient(0.55);
volumeProperty->SetDiffuse(0.85); //漫反射
volumeProperty->SetSpecular(0.54); //镜面反射
volumeProperty->SetSpecularPower(69); //镜面反射
//设置不透明度
vtkNew<vtkPiecewiseFunction> compositeOpacity;
compositeOpacity->AddPoint(-1000, 0.00);
compositeOpacity->AddPoint(100, 0.00);
compositeOpacity->AddPoint(300, 0.879);
compositeOpacity->AddPoint(478, 0.879);
compositeOpacity->AddPoint(1500, 0.901);
volumeProperty->SetScalarOpacity(compositeOpacity); //设置不透明度传输函数
vtkNew<vtkColorTransferFunction> color;
color->AddRGBPoint(-1000, 0.00, 0.00, 0.00);
color->AddRGBPoint(100, 220/255., 21/255., 3/255.);
color->AddRGBPoint(300, 250/255., 1.00, 189/255.);
color->AddRGBPoint(478, 224/255., 1, 249/255.);
color->AddRGBPoint(1500, 1, 1, 1);
volumeProperty->SetColor(color);
volume->SetProperty(volumeProperty);
vtkNew<vtkRenderer> ren;
ren->AddActor(volume);
ren->SetBackground(0, 0, 0);
ren->ResetCamera();
vtkCamera* camera = ren->GetActiveCamera();
camera->Elevation(-70);
ren->ClearLights();
ren->RemoveAllLights();
double* lightPosition = camera->GetPosition();
double lightPositions[3] = { lightPosition[0], lightPosition[1], lightPosition[2]-100 };
vtkNew<vtkLight> light;
light->SetLightTypeToSceneLight();
light->SetPosition(lightPositions);
light->SetPositional(true);
light->SetAmbientColor(0.3, 0.2, 0.1);
light->SetConeAngle(60);
light->SetFocalPoint(camera->GetFocalPoint());
light->SetIntensity(1.2);
ren->AddLight(light);
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(ren);
vtkNew<vtkRenderWindowInteractor> iren;
vtkNew<vtkInteractorStyleTrackballCamera> style;
iren->SetRenderWindow(renWin);
iren->SetInteractorStyle(style);
renWin->SetSize(1024, 768);
renWin->Render();
iren->Start();
return 0;
}