GLSL计算着色器中的射线投射(磁盘射线交汇)。

问题描述 投票:0回答:1

我想做什么

我有一些表面元素("surfel"),它们是三维空间中具有位置、法线和半径的圆盘。对于一组射线,我需要找到被该射线击中的最近的曲面元素。

我经常进行这种计算,所以速度是个问题。在多次调用之间,只有射线集会改变,但曲面元素列表不会改变。然而,曲面元素的列表并不是一成不变的,也会经常变化。

曲面元素的数量通常是1000或10000的数量,而射线的数量是10000的数量。

我现在的做法是

我写了一个GLSL计算着色器,是我从各种在线资源中Frankensteined出来的,似乎可以工作,但它比我想要的要慢一些。

它的输入是一个 顶点图 是一个指定每个像素的射线方向的图像,以及一个冲浪点的列表。

输出的图像大小与顶点图相同,但有两个部分:最接近击中的surfel的索引和与它的距离。

我将工作组的数量设置为 nx = width / kxny = height / ky 哪儿 widthheight 是顶点图尺寸,而 kx = local_size_xky = 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));
        }
    }
}

问题

  • 我可以对我的代码进行改进吗?鉴于我对OpenGL着色器的经验不足,可能会有一些常见的陷阱,我已经跳进了这些陷阱。
  • 是否有其他(更好的)方法值得我尝试?

局限性

  • 由于我已经有了一些OpenGL代码,我更喜欢使用OpenGL着色器的解决方案,而不是CUDA或OpenCL。不过,我很乐意听取转换的合理理由。
  • 顶点图上的像素坐标实际上代表了一个球面坐标框架(俯仰和偏航),这意味着我不能简单地使用普通的顶点和帧着色器(例如带透明度的四边形)来渲染曲面。
opengl glsl raycasting
1个回答
© www.soinside.com 2019 - 2024. All rights reserved.