OpenGL实现Volume Rendering 大致步骤
1D TF Code
在混合volume render程序中的1D TF code
- RGBA都为0~255,正好一个byte,unsigned int,char型。
- 一个节点(传输函数上的关键节点)上的信息为:intensity+color[RBGA]。
- 透明度值a用0~255存储,用的时候(float)/255.f。
- intensity大的点在update的时候必须>=原来intensity比其小的店,比较,移动等问题,用插入排序。
绘制纹理
绘制一共需要3个纹理
- 一个3D texture 存放体数据。
- 3个2D texture: ray casting 起始位置纹理,ray casting 结束位置纹理(存放的是起始和技术位置的深度值),一张深度纹理,即为2张纹理的差值。
- 1个1D texture 存放1DTF数据。244*4个byte。
GLSL过程
GLSL过程
- 创建shader -> glCreateShader();
- shader读入char* -> glShaderSource();
- 编译shader -> glCompileShader();
- 创建program -> glCreateProgram();
- 将shader连到program上 -> glAttachShader();
- 链接program -> glLinkProgram();
程序流程
程序流程
- init
- 初始化GLSL
- 初始化texture,分配空间,glTexImage2D();
- 将纹理都绑定到一个帧缓存对象。FBO需要opengl3.0或者使用扩展glew,或者用代替的framebufferobject.h/.cpp。
- 根据raw数据长宽高,载入数据到char*,再绑定到3D纹理。
- 绑定传输函数1Dtexture。
- render
- updateTFtexture,看看传输函数是否变化,有变化重新产生纹理。
- 绘制起始位置纹理:绑定FBO,转换视角,glDrawBuffer绘制到绑定的纹理上,绘制一个立方体,将顶点坐标信息当做纹理坐标。
- 绘制结束位置纹理:同上,绘制前用glDepthFunc(GL_GREATER);绘制后用glDepthFunc(GL_LESS);
- boundingBox的片段着色器为: void main { gl_FragColor = gl_TexCoord[0];//直接将纹理坐标赋值给最终颜色。 }
- glUseProgram(raycastingProgram);
- glActiveTexture()激活纹理,内容始终是GL_TEXTURE0+gen出来的纹理id。
- 穿入这些纹理。
- 将产生的最终结果绘制到窗口大小的矩形上。
- 使用正交投影。
- raycasting glsl代码:
GLSL Code
#extension GL_ARB_texture_rectangle : enable
uniform sampler1D texTransfunc;
uniform sampler2DRect texStartPos;
uniform sampler2DRect texEndPos;
uniform sampler3D texVolume;
uniform float step;
void main()
{
vec3 rayStart = texture2DRect(texStartPos, gl_TexCoord[0].st).xyz;
vec3 rayEnd = texture2DRect(texEndPos, gl_TexCoord[0].st).xyz;
vec3 start2end = rayEnd - rayStart;
if (start2end.x == 0.0 && start2end.y == 0.0 && start2end.z == 0.0) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
return;
}
vec4 color = vec4(0, 0, 0, 0);
vec3 direction = normalize(start2end);
float distance = dot(direction, start2end);
int steps = distance / step;
for(int i = 0; i < 2048; ++i) {
if(i >= steps)
break;
vec3 samplePoint = rayStart + direction * step * (i + 0.5);
float scalar = texture3D(texVolume, samplePoint).x;
vec4 sampledColor = texture1D(texTransfunc, scalar);
color = color + sampledColor * vec4(sampledColor.aaa, 1.0) * (1.0 - color.a);
if(color.a > 0.99)
break;
}
color = color + vec4(1, 1, 1, 0) * (1.0 - color.a);
color.a = 1;
gl_FragColor = color;
//gl_FragColor = texture2DRect(texStartPos, gl_TexCoord[0].st);
}