使用射线投影算法进行GLSL体积渲染

20

我正在学习使用光线投射算法进行体积渲染。我在这里找到了一个很好的演示和教程。但问题是,我有一张ATI显卡而不是nVidia,这使我不能在演示中使用cg着色器,所以我想把cg着色器改为glsl着色器。我已经阅读过OpenGL的红书(第7版),但对glsl和cg不熟悉。 有人能帮助我将演示中的cg着色器改为glsl吗?或者是否有任何关于使用光线投射进行体积渲染的最简单演示材料(当然是用glsl)。 这里是演示的cg着色器。它可以在我朋友的nVidia显卡上工作。最让我困惑的是我不知道如何将cg的入口部分翻译成glsl,例如:

struct vertex_fragment
 {
   float4 Position    : POSITION; // For the rasterizer
   float4 TexCoord    : TEXCOORD0; 
   float4 Color       : TEXCOORD1;
   float4 Pos         : TEXCOORD2;
 };
此外,我可以编写一个程序,将两个纹理对象绑定到两个纹理单元以提供着色器,只要在绘制屏幕时分配两个纹理坐标,例如: glMultiTexCoord2f(GL_TEXTURE0, 1.0, 0.0); glMultiTexCoord2f(GL_TEXTURE1, 1.0, 0.0); 在演示中,该程序将绑定两个纹理(一个用于backface_buffer的2D纹理,一个用于volume texture的3D纹理),但是使用只有一个纹理单元的glMultiTexCoord3f(GL_TEXTURE1, x, y, z)命令时,我认为GL_TEXTURE1是用于volume texture的,但是哪一个(纹理单元)用于backface_buffer?据我所知,为了将纹理对象绑定到着色器中,我必须获取一个纹理单元来绑定,例如:
glLinkProgram(p);   
texloc = glGetUniformLocation(p, "tex");
volume_texloc = glGetUniformLocation(p, "volume_tex");
stepsizeloc = glGetUniformLocation(p, "stepsize");
glUseProgram(p);
glUniform1i(texloc, 0); 
glUniform1i(volume_texloc, 1); 
glUniform1f(stepsizeloc, stepsize);
  //When rendering an object with this program.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, backface_buffer);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_3D, volume_texture);
程序编译和链接都没有问题,但我得到的所有三个位置(texloc、volume_texloc和stepsizeloc)都是-1。我知道它可能被优化掉了。有人能帮我将cg着色器翻译成glsl着色器吗?
编辑:如果您对使用glsl实现现代OpenGL API(C ++源代码)感兴趣,请查看Volume_Rendering_Using_GLSL

Cg着色器在ATi/AMD和nVidia上的效果同样出色(这是相对而言的,因为Cg运行时有许多崩溃错误路径)。 - ssube
提醒一下:Cg编译器可以生成GLSL代码。同时,Cg也可与AMD/ATI显卡配合使用。只有少数NVidia专用功能无法工作,但性能会稍微降低。 - datenwolf
@datenwolf 真的吗?我会试一下。不知道如何生成glsl代码? - toolchainX
这是Cg独立编译器的一个选项。除了GLSL之外,它还可以生成DirectX HLSL和OpenGL顶点/片段程序汇编代码(在GLSL出现之前的时代)。老实说,我很怀念汇编着色器。对我来说,GLSL感觉不太对。 - datenwolf
@datenwolf 我尝试了cg3.1,似乎我的电脑只支持一个非常低的级别配置文件,无法正确运行程序。 - toolchainX
前两个链接已经失效。 - Fedor
1个回答

17

问题已解决。这是glsl版本演示

顶点着色器

void main()
{
    gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
    //gl_FrontColor = gl_Color;
    gl_TexCoord[2] = gl_Position;
    gl_TexCoord[0] = gl_MultiTexCoord1;
    gl_TexCoord[1] = gl_Color;
}

片段着色器

uniform sampler2D tex;
uniform sampler3D volume_tex;
uniform float stepsize;

void main()
{
    vec2 texc = ((gl_TexCoord[2].xy/gl_TexCoord[2].w) + 1) / 2;
    vec4 start = gl_TexCoord[0];
    vec4 back_position = texture2D(tex, texc);
    vec3 dir = vec3(0.0);
    dir.x = back_position.x - start.x;
    dir.y = back_position.y - start.y;
    dir.z = back_position.z - start.z;
    float len = length(dir.xyz); // the length from front to back is calculated and used to terminate the ray
    vec3 norm_dir = normalize(dir);
    float delta = stepsize;
    vec3 delta_dir = norm_dir * delta;
    float delta_dir_len = length(delta_dir);
    vec3 vect = start.xyz;
    vec4 col_acc = vec4(0,0,0,0); // The dest color
    float alpha_acc = 0.0;                // The  dest alpha for blending
    float length_acc = 0.0;
    vec4 color_sample; // The src color 
    float alpha_sample; // The src alpha

    for(int i = 0; i < 450; i++)
    {
      color_sample = texture3D(volume_tex,vect);
      //  why multiply the stepsize?
      alpha_sample = color_sample.a*stepsize;
      // why multply 3?
      col_acc   += (1.0 - alpha_acc) * color_sample * alpha_sample*3 ;
      alpha_acc += alpha_sample;
      vect += delta_dir;
      length_acc += delta_dir_len;
      if(length_acc >= len || alpha_acc > 1.0) 
        break; // terminate if opacity > 1 or the ray is outside the volume
    }

    gl_FragColor =  col_acc;
}

如果你看过cg的原始着色器,那么cg和glsl之间只有一点点区别。将演示转换为glsl版本最困难的部分是在opengl中的cg函数,例如:

param = cgGetNamedParameter(program, par); 
cgGLSetTextureParameter(param, tex); 
cgGLEnableTextureParameter(param);

封装纹理单元和多重纹理激活(使用 glActiveTexture)和取消激活的过程非常重要,因为在这个演示中它同时使用了固定管线和可编程管线。以下是 Peter Triers GPU raycasting 教程中 main.cpp 中 void raycasting_pass() 函数中的关键片段改动:

函数 raycasting_pass

void raycasting_pass()
{
    // specify which texture to bind
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
        GL_TEXTURE_2D, final_image, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glUseProgram(p);
    glUniform1f(stepsizeIndex, stepsize);
    glActiveTexture(GL_TEXTURE1);
    glEnable(GL_TEXTURE_3D);
    glBindTexture(GL_TEXTURE_3D, volume_texture);
    glUniform1i(volume_tex, 1); 
    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, backface_buffer);
    glUniform1i(tex, 0); 

    glUseProgram(p);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    drawQuads(1.0,1.0, 1.0);  // Draw a cube
    glDisable(GL_CULL_FACE);
    glUseProgram(0);
    // recover to use only one texture unit as for the fixed pipeline
    glActiveTexture(GL_TEXTURE1);
    glDisable(GL_TEXTURE_3D);
    glActiveTexture(GL_TEXTURE0);
}

就是这样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接