以下是需要翻译的内容:
这将看起来像:
为了提高效率,我决定实现以下查找函数:
似乎这种走样是因为某些坐标没有被设置为它们正确的体素。
例如,将截断部分修改如下:
创建:
正如您所看到的,对于一些点来说,第五个盒子的采样似乎被省略了。
以下是采样代码:
情况如下。我正在尝试在GLSL着色器中实现线性体素搜索,以实现高效的体素光线追踪。换句话说,我有一个3D纹理,我正在对其进行光线追踪,但我正在尝试进行光线追踪,以便仅检查光线只相交一次的体素。
为此,我编写了一个程序,具有以下结果:
不够高效,但正确:
上面的图像是通过多次添加小的epsilon射线并在每次迭代中从纹理中采样获得的。这样可以产生正确的结果,但效率非常低。这将看起来像:
loop{
start += direction*0.01;
sample(start);
}
为了提高效率,我决定实现以下查找函数:
float bound(float val)
{
if(val >= 0)
return voxel_size;
return 0;
}
float planeIntersection(vec3 ray, vec3 origin, vec3 n, vec3 q)
{
n = normalize(n);
if(dot(ray,n)!=0)
return (dot(q,n)-dot(n,origin))/dot(ray,n);
return -1;
}
vec3 get_voxel(vec3 start, vec3 direction)
{
direction = normalize(direction);
vec3 discretized_pos = ivec3((start*1.f/(voxel_size))) * voxel_size;
vec3 n_x = vec3(sign(direction.x), 0,0);
vec3 n_y = vec3(0, sign(direction.y),0);
vec3 n_z = vec3(0, 0,sign(direction.z));
float bound_x, bound_y, bound_z;
bound_x = bound(direction.x);
bound_y = bound(direction.y);
bound_z = bound(direction.z);
float t_x, t_y, t_z;
t_x = planeIntersection(direction, start, n_x,
discretized_pos+vec3(bound_x,0,0));
t_y = planeIntersection(direction, start, n_y,
discretized_pos+vec3(0,bound_y,0));
t_z = planeIntersection(direction, start, n_z,
discretized_pos+vec3(0,0,bound_z));
if(t_x < 0)
t_x = 1.f/0.f;
if(t_y < 0)
t_y = 1.f/0.f;
if(t_z < 0)
t_z = 1.f/0.f;
float t = min(t_x, t_y);
t = min(t, t_z);
return start + direction*t;
}
这将产生以下结果:
请注意一些表面左侧的三角形走样。似乎这种走样是因为某些坐标没有被设置为它们正确的体素。
例如,将截断部分修改如下:
vec3 discretized_pos = ivec3((start*1.f/(voxel_size)) - vec3(0.1)) * voxel_size;
创建:
因此,它已经解决了一些表面的问题,并引起了其他表面的问题。
我想知道是否有一种方法可以纠正这种截断,以便不会发生此错误。
更新:
我已经将问题缩小了一点。请观察以下图像:
这些数字代表着我期望盒子被访问的顺序。正如您所看到的,对于一些点来说,第五个盒子的采样似乎被省略了。
以下是采样代码:
vec4 grabVoxel(vec3 pos)
{
pos *= 1.f/base_voxel_size;
pos.x /= (width-1);
pos.y /= (depth-1);
pos.z /= (height-1);
vec4 voxelVal = texture(voxel_map, pos);
return voxelVal;
}
GL_CLAMP_TO_EDGE
或float
不足(如果使用double可以改善情况)。1.f/0.f;
是什么意思?它是除以零,而着色器不像CPU代码那样崩溃。是的,在GLSL中解码可能会让你发疯,这就是为什么我通常会编写一个C++代码(与着色器代码相同),当它工作正常时,只需将其用作着色器。 - Spektre(d/i)vec(2,3,4)
,并复制了GLSL的行为。这是一段疯狂的模板代码,需要正确处理getter/setter和模板递归,但它确实有效 :) CPU和Shader之间唯一的区别是纹理访问,这由#define
和调试渲染处理,因此我甚至不必更改代码。如果没有2D切片概述,我会在我的一些项目中陷入困境。我仍然相信,如果没有2D切片概述,您将无法像完整的3D渲染那样看到实际发生的情况。 - Spektre