我有一些表面元素("surfel"),它们是三维空间中具有位置、法线和半径的圆盘。对于一组射线,我需要找到被该射线击中的最近的曲面元素。
我经常进行这种计算,所以速度是个问题。在多次调用之间,只有射线集会改变,但曲面元素列表不会改变。然而,曲面元素的列表并不是一成不变的,也会经常变化。
曲面元素的数量通常是1000或10000的数量,而射线的数量是10000的数量。
我写了一个GLSL计算着色器,是我从各种在线资源中Frankensteined出来的,似乎可以工作,但它比我想要的要慢一些。
它的输入是一个 顶点图 是一个指定每个像素的射线方向的图像,以及一个冲浪点的列表。
输出的图像大小与顶点图相同,但有两个部分:最接近击中的surfel的索引和与它的距离。
我将工作组的数量设置为 nx = width / kx
和 ny = height / ky
哪儿 width
和 height
是顶点图尺寸,而 kx = local_size_x
和 ky = local_size_y
在计算着色器中设置。
#version 430 core
layout (local_size_x = 8, local_size_y = 8) in;
struct Surfel {
vec4 position;
vec4 normal_radius;
};
// Inputs
layout(rgba32f, location=0) readonly uniform restrict image2D vertex_map;
layout(std430, binding=1) buffer surfels_in
{
Surfel surfels[];
} In;
// Outputs
layout(rg32f, location=2) writeonly uniform restrict image2D index_map;
bool intersectPlane(vec3 n, vec3 p0, vec3 l0, vec3 l, out float t)
{
// assuming vectors are all normalized
float denom = dot(n, l);
if (abs(denom) > 1e-6) {
vec3 p0l0 = p0 - l0;
t = dot(p0l0, n) / denom;
return (t >= 0);
}
return false;
}
bool intersectDisk(vec3 n, vec3 p0, float radius, vec3 l0, vec3 l, out vec3 p, out float t)
{
t = 0;
if (intersectPlane(n, p0, l0, l, t)) {
vec3 p = l0 + l * t;
vec3 v = p - p0;
float d2 = dot(v, v);
return (d2 <= (radius * radius));
}
return false;
}
void main() {
ivec2 pos = ivec2(gl_GlobalInvocationID.xy); // image coordinate
ivec2 dims = imageSize(vertex_map);
if ((pos.x < dims.x) && (pos.y < dims.y)) {
// Get the ray direction from the vertexmap
vec4 v = imageLoad(vertex_map, pos);
vec3 ray = v.xyz / length(v.xyz);
vec3 origin = vec3(0); // Note: This will be set by user later
bool intersected = false;
int best_index = 0;
float best_t = 1e6; // Best distance, start huge
vec3 best_p; // Best intersection point (really just ray * best_t)
const int num_surfels = In.surfels.length();
for (int surfel_index=0; surfel_index < num_surfels; ++surfel_index) {
Surfel s = In.surfels[surfel_index];
vec3 p;
float t;
if (intersectDisk(s.normal_radius.xyz, s.position.xyz, s.normal_radius.w, origin, ray, p, t)) {
if (t < best_t) {
intersected = true;
best_p = p;
best_t = t;
best_index = surfel_index;
}
}
}// end for
if (intersected) {
imageStore(index_map, pos, vec4(best_index, best_t, 0, 0));
}
else {
imageStore(index_map, pos, vec4(-1));
}
}
}