我尝试在 Chai3D 中使用直接体积渲染,但有一个伪影使托管边界网格的边缘始终可见,即使在其前面有另一个对象也是如此。有任何可能导致问题的线索吗?
完整代码可以在这里看到,无论是否连接了触觉设备,应用程序都会运行:
这是着色器代码:
uniform vec3 uMinCorner;
uniform vec3 uMaxCorner;
uniform vec3 uTextureScale;
uniform vec3 uGradientDelta;
uniform sampler3D uVolume;
uniform sampler1D uColorLUT;
uniform float uIsosurface;
uniform float uOpacityThreshold;
uniform float uOpticalDensityFactor;
uniform float uResolution;
varying vec4 vPosition;
vec3 dx = vec3(uGradientDelta.x, 0.0, 0.0);
vec3 dy = vec3(0.0, uGradientDelta.y, 0.0);
vec3 dz = vec3(0.0, 0.0, uGradientDelta.z);
float entry(vec3 e1, vec3 d)
{
float t = distance(uMinCorner, uMaxCorner);
vec3 a = (uMinCorner - e1) / d;
vec3 b = (uMaxCorner - e1) / d;
vec3 u = min(a, b);
return max(max(-t, u.x), max(u.y, u.z));
}
vec3 gradient(vec3 tc)
{
vec3 nabla = vec3(
texture3D(uVolume, tc + dx).r - texture3D(uVolume, tc - dx).r,
texture3D(uVolume, tc + dy).r - texture3D(uVolume, tc - dy).r,
texture3D(uVolume, tc + dz).r - texture3D(uVolume, tc - dz).r
);
return (nabla / uGradientDelta) * uTextureScale;
}
vec3 shade(vec3 p, vec3 v, vec3 n)
{
vec4 lp = gl_ModelViewMatrixInverse * gl_LightSource[0].position;
vec3 l = normalize(lp.xyz - p * lp.w);
vec3 h = normalize(l + v);
float cos_i = max(dot(n, l), 0.0);
float cos_h = max(dot(n, h), 0.0);
vec3 Ia = gl_FrontLightProduct[0].ambient.rgb;
vec3 Id = gl_FrontLightProduct[0].diffuse.rgb * cos_i;
vec3 Is = gl_FrontLightProduct[0].specular.rgb * pow(cos_h, gl_FrontMaterial.shininess);
return (Ia + Id + Is);
}
void main(void)
{
vec4 camera = gl_ModelViewMatrixInverse * vec4(0.0, 0.0, 0.0, 1.0);
vec3 raydir = normalize(vPosition.xyz - camera.xyz);
float t_entry = entry(vPosition.xyz, raydir);
t_entry = max(t_entry, -distance(camera.xyz, vPosition.xyz);
float t_step = distance(uMinCorner, uMaxCorner) / uResolution;
vec3 tc_step = uTextureScale * (t_step * raydir);
vec4 sum = vec4(0.0);
vec3 tc = gl_TexCoord[0].stp + t_entry * tc_step / t_step;
for (float t = t_entry; t < 0.0; t += t_step, tc += tc_step)
{
float intensity = texture3D(uVolume, tc).r;
vec4 colour = texture1D(uColorLUT, intensity);
if (colour.a < 0.001) continue;
vec3 nabla = gradient(tc);
vec3 position = vPosition.xyz + t * raydir;
vec3 normal = -normalize(nabla);
vec3 view = -raydir;
vec3 shaded = shade(position, view, normal);
colour.rgb *= shaded;
float Tr = exp(-colour.a * uOpticalDensityFactor);
colour.rgb *= 1.0 - Tr;
colour.a = 1.0 - Tr;
sum += (1.0 - sum.a) * colour;
if (sum.a > uOpacityThreshold)
{
vec4 clip = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
gl_FragDepth = (gl_DepthRange.diff * clip.z / clip.w + gl_DepthRange.near + gl_DepthRange.far) * 0.5;
break;
}
}
gl_FragColor = sum;
}
这是我的主要图形循环:
while (!glfwWindowShouldClose(window))
{
// get width and height of window
glfwGetWindowSize(window, &width, &height);
// render graphics
updateGraphics();
// swap buffers
glfwSwapBuffers(window);
// process events
glfwPollEvents();
// signal frequency counter
freqCounterGraphics.signal(1);
}
UpdateGraphics() 使用 Chai3D 函数:
// update shadow maps (if any)
world->updateShadowMaps(false, mirroredDisplay);
// render world
camera->renderView(width, height);
// wait until all GL commands are completed
glFinish();
这些伪影可能是由于体渲染针对其他对象的深度排序不正确造成的。确保首先渲染不透明对象,然后渲染体渲染以与背景正确混合。使用适当的深度测试和混合设置以避免与深度相关的伪影。
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
另一个原因可能是体数据的采样和插值。确保您正确地对体积数据进行采样,并且使用三线性或各向异性过滤来最大限度地减少伪影。
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
在着色器中,您应该考虑启用背面剔除以减少与渲染体积背面相关的伪影。
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);