레이 캐스팅 알고리즘을 사용한 볼륨 렌더링(glsl 사용)
-
13-11-2019 - |
문제
레이 캐스팅 알고리즘을 이용한 볼륨 렌더링을 배우고 있습니다.나는 좋은 데모와 튜토리얼을 찾았습니다. 여기.하지만 문제는 nVidia 대신 ATI 그래픽 카드가 있어서 데모에서 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;
};
게다가 화면을 그릴 때 2개의 texcoord를 할당하면 2개의 텍스처 단위가 있는 2개의 텍스처 개체를 셰이더에 바인딩하는 프로그램을 작성할 수 있습니다.
glMultiTexCoord2f(GL_TEXTURE0, 1.0, 0.0);
glMultiTexCoord2f(GL_TEXTURE1, 1.0, 0.0);
데모에서 프로그램은 두 개의 텍스처(하나는 2D backface_buffer
3D 1개 volume texture
), 그러나 다음과 같은 텍스처 단위가 하나만 있습니다. glMultiTexCoord3f(GL_TEXTURE1, x, y, z);
내 생각 엔 GL_TEXTURE1
단위는 볼륨 텍스처를 위한 것이지만 어떤 것(텍스처 단위)이 볼륨 텍스처를 위한 것입니까? 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);
프로그램이 잘 컴파일되고 링크가 잘 되었습니다.하지만 세 위치(texloc, Volume_texloc 및 stepsizeloc) 중 -1만 얻었습니다.나는 그것이 최적화될 수 있다는 것을 알고 있습니다.누구든지 cg 셰이더를 glsl 셰이더로 변환하는 데 도움을 줄 수 있나요?
편집하다: glsl을 사용한 최신 OpenGL API 구현(C++ 소스 코드)에 관심이 있다면:Volume_Rendering_Using_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와 glsl 사이에는 약간의 차이가 있습니다. ...에 데모를 GLSL 버전으로 번역하는 가장 어려운 부분은 다음과 같은 OpenGL의 CG 기능입니다.
.
param = cgGetNamedParameter(program, par);
cgGLSetTextureParameter(param, tex);
cgGLEnableTextureParameter(param);
텍스처 유닛과 멀티 라인 덱 코드 (glActiveTexture
사용) 및 비활성화의 프로세스를 캡슐화하고 고정 된 파이프 라인뿐만 아니라 프로그래밍 가능한 파이프 라인을 사용 하므로이 데모에서 매우 중요합니다. 피터 트리 어 GPU RayCasting 자습서의 데모의 Main.cpp의 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);
}
.