объемный рендеринг (с использованием glsl) с алгоритмом приведения лучей - PullRequest
18 голосов
/ 28 февраля 2012

Я изучаю объем рендеринга, используя алгоритм наведения лучей. Я нашел хорошее демо и учебник в здесь . но проблема в том, что у меня есть графическая карта ATI вместо nVidia, из-за чего я не могу использовать шейдер cg в демоверсии, поэтому я хочу изменить шейдер cg на шейдер glsl. Я прошел красную книгу (7 издание) OpenGL, но не знаком с 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;
 };

Более того, я могу написать программу связывания 2 текстурных объектов с 2 текстурными единицами для шейдера при условии, что я назначаю две текстовые координаты при рисовании экрана, например

glMultiTexCoord2f(GL_TEXTURE0, 1.0, 0.0);

glMultiTexCoord2f(GL_TEXTURE1, 1.0, 0.0);

В демоверсии программа будет привязана к двум текстурам (одна 2D для backface_buffer, одна 3D для volume texture), но только с одним текстурным модулем, таким как glMultiTexCoord3f(GL_TEXTURE1, x, y, z); Я думаю, что блок GL_TEXTURE1 предназначен для объемной текстуры , но какой (блок texure) для backface_buffer? насколько я знаю, чтобы связать текстуру obj в шейдере, я должен получить блок текстуры для привязки, например:

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);

программа скомпилирована нормально и связана нормально. но я получил только -1 из всех трех местоположений (texloc, volume_texloc и stepsizeloc). Я знаю, что это может быть оптимизировано. Кто-нибудь может помочь мне перевести cg-шейдер в glsl-шейдер?

Редактировать: Если вас интересует современная реализация API OpenGL (исходный код C ++) с помощью glsl: Volume_Rendering_Using_GLSL

1 Ответ

15 голосов
/ 29 февраля 2012

Проблема решена. версия 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 состоит в том, что функция cg в opengl, такая как:

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

, инкапсулирует процесс активации текстурного блока и мультитекстуры (с использованием glActiveTexture) и деактивации, котораяЭто очень важно в этой демонстрации, поскольку она использует фиксированный конвейер, а также программируемый конвейер.вот ключевой сегмент, измененный в функции void raycasting_pass() файла main.cpp демонстрации в руководстве по радиопередаче с графическим процессором Питера Трирса:

функция 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);
}

Это.

...