我正在手动跟踪3D图像。我注意到,离3D图像越远,混叠就越大。
此3D图像基本上是斯坦福巨龙的体素化表示。我将音量置于原点中心(对角线交叉于(0,0,0)),这意味着其中一个角位于(-cube_dim,-cube_dim,-cube_dim),另一个位于(cube_dim,cube_dim, cube_dim)。
在近距离下图像很好:
(您在此处看到的次要“别名”是由于我执行了光线行进算法,这不是我担心的别名,这是预期的并可以接受)
但是,如果我们走得足够远,就会出现一些混叠现象: (这是完全不同的别名)
用于生成图像的片段着色器是这样的:
#version 430
in vec2 f_coord;
out vec4 fragment_color;
uniform layout(binding=0, rgba8) image3D volume_data;
uniform vec3 camera_pos;
uniform float aspect_ratio;
uniform float cube_dim;
uniform int voxel_resolution;
#define EPSILON 0.01
// Check whether the position is inside of the specified box
bool inBoxBounds(vec3 corner, float size, vec3 position)
{
bool inside = true;
//Put the position in the coordinate frame of the box
position-=corner;
//The point is inside only if all of it's components are inside
for(int i=0; i<3; i++)
{
inside = inside && (position[i] > -EPSILON);
inside = inside && (position[i] < size+EPSILON);
}
return inside;
}
//Calculate the distance to the intersection to a box, or inifnity if the bos cannot be hit
float boxIntersection(vec3 origin, vec3 dir, vec3 corner0, float size)
{
//dir = normalize(dir);
//calculate opposite corner
vec3 corner1 = corner0 + vec3(size,size,size);
//Set the ray plane intersections
float coeffs[6];
coeffs[0] = (corner0.x - origin.x)/(dir.x);
coeffs[1] = (corner0.y - origin.y)/(dir.y);
coeffs[2] = (corner0.z - origin.z)/(dir.z);
coeffs[3] = (corner1.x - origin.x)/(dir.x);
coeffs[4] = (corner1.y - origin.y)/(dir.y);
coeffs[5] = (corner1.z - origin.z)/(dir.z);
float t = 1.f/0.f;
//Check for the smallest valid intersection distance
//We allow negative values up to -size to create correct sorting if the origin is
//inside the box
for(uint i=0; i<6; i++)
t = (coeffs[i]>=0) && inBoxBounds(corner0,size,origin+dir*coeffs[i])?
min(coeffs[i],t) : t;
return t;
}
void main()
{
float v_size = cube_dim/voxel_resolution;
vec3 r = (vec3(f_coord.xy,1.f/tan(radians(40))));
r.y /= aspect_ratio;
vec3 dir = normalize(r);//;*v_size*0.5;
r+= camera_pos;
float t = boxIntersection(r, dir, -vec3(cube_dim), cube_dim*2);
if(isinf(t))
discard;
if(!((r.x>=-cube_dim) && (r.x<=cube_dim) && (r.y>=-cube_dim) &&
(r.y<=cube_dim) && (r.z>=-cube_dim) && (r.z<=cube_dim)))
r += dir*t;
vec4 color = vec4(0);
int c=0;
while((r.x>=-cube_dim) && (r.x<=cube_dim) && (r.y>=-cube_dim) &&
(r.y<=cube_dim) && (r.z>=-cube_dim) && (r.z<=cube_dim))
{
r += dir*v_size*0.5;
vec4 val = imageLoad(volume_data, ivec3(((r)*0.5/cube_dim+vec3(0.5))*(voxel_resolution-1)));
if(val.w > 0)
{
color = val;
break;
}
c++;
}
fragment_color = color;
}
首先,我们基于屏幕坐标创建射线(我们使用标准射线跟踪技术,焦距为1 / tan(角度))。
然后我们在相机的当前位置开始光线
我们检查射线与包含对象的盒子的交集(我们基本上假设3D纹理在场景中是一个大立方体,然后检查是否击中了它)。
如果我们不击中它,我们将丢弃该碎片。如果我们确实击中它,而我们在外面,则沿着射线移动,直到到达盒子的表面。如果我们击中它并进入里面,我们将留在原处。
在这一点上,我们保证射线的位置在盒子内部。
现在,我们沿着射线沿小段移动,直到找到一个非零值或到达方框的末端为止。