在opengl / glsl中进行光线跟踪obj文件

时间:2014-11-29 13:03:51

标签: opengl glsl raytracing wavefront

我想在opengl和glsl中实现光线跟踪来渲染从.obj文件加载的模型,但我不明白这是怎么做到的。我之前使用过obj文件,但是我使用栅格化来渲染它们。到目前为止,我已经使用片段着色器实现了简单的光线跟踪器,渲染了一些简单的形状(平面,球体,盒子)。问题在于光线追踪我计算与物体的交点,但这些也是在片段着色器中定义的。

这就是我使用光栅化进行渲染的方式: 加载顶点数据(位置,正常,uvs)后,我将它们存储到VBO中并将它们绑定到VAO。这些我发送到顶点着色器并通过将它们与MVP矩阵相乘来对它们进行变换。然后我将变换后的顶点发送到片段着色器。但这是我不了解如何通过光线跟踪实现的部分,因为现在我已经将顶点转换为片段着色器的输入,这意味着我不知道如何使用网格三角形计算光线交点。那么,怎么做呢?

2 个答案:

答案 0 :(得分:1)

嗯,基本上对于每个片段,您都要对整个场景进行光线交叉测试。因此,挑战在于将场景编码在某些数据结构中,这些数据结构可以从片段着色器访问并为其提供足够的空间。一个直接的选择是三个1D纹理具有相同大小的3个组件,其中对于每个纹素指数,三个纹理的三倍表示三角形。然后对于投射到场景中的每条光线(即每个片段)迭代三角形。

如果你想要更加漂亮,你可以使用三个3D纹理,将三角形数据放入纹理的右侧区域以限制纹素迭代,使用它们的mipmap级别进行LOD并使用稀疏纹理存储来减少内存占用。

答案 1 :(得分:0)

最近,我正在为此做确切的工作。我使用Assimp库导入obj文件,并将顶点和索引获取到单独的数组中。我通过着色器存储缓冲区将顶点和索引发送到片段着色器。不幸的是,当我要绘制100多个三角形的面并检查相交时,我的计算机崩溃了。我想这就是为什么现在存在专用于光线追踪的GPU(我的GPU是gtx750 ti)的原因
在我的片段着色器中,有一个Möller-Trumbore相交算法,用于检查三角形和射线之间的相交。

这是我的片段着色器(正在构建中,所以不完整):

#version 460 core

layout(std140, binding=2) buffer primitives{
    vec3 primitiveCoordinates[];
};

layout(std140, binding=3) buffer indices{
    vec3 indicesC[];
};

in       vec2       TexCoords;
out      vec4       FragColor;
in       vec3 p;
uniform vec3 wEye;
uniform  sampler2D  texture_diffuse1;


struct Light{
    vec3 Le, La;
    vec3 direction;
    vec3 position;

};

uniform Light lights[2];

struct Ray{
    vec3 orig, dir;
};

struct Hit{
    vec3 orig, dir, normal;
    float t;
};

struct IntersectionPoint{
    float t;

};

vec3 outIntersectionPoint;

Hit rayTriangleIntersect(Ray ray, vec3 v0, vec3 v1, vec3 v2){

    Hit hit;
    float t; float u; float v;
    vec3 v0v1 = v1 - v0;
    vec3 v0v2 = v2 - v0;
    vec3 pvec = cross(ray.dir, v0v2);
    float det = dot(v0v1, pvec);


    if (abs(det) < 0.008){
        hit.t=-1;
        return hit;// Culling is off
    }
    float invDet = 1 / det;

    vec3 tvec = ray.orig - v0;
    u = dot(tvec, pvec) * invDet;
    if (u < 0 || u > 1){
        hit.t=-1;
        return hit;
    }

    vec3 qvec = cross(tvec, v0v1);
    v = dot(ray.dir, qvec) * invDet;
    if (v < 0 || u + v > 1) {
        hit.t=-1;
        return hit;
    }

    hit.t = dot(v0v2, qvec) * invDet;
    hit.normal= cross(v0v1, v0v2);
    return hit;
}


vec3 getCoordinatefromIndices(float index){
    vec3 back;
    for (int i=0; i < primitiveCoordinates.length();i++){
        if (i==index){
            back=primitiveCoordinates[i];
            break;
        }
    }
    return back;
}


Hit firstIntersect(Ray ray){
    Hit besthit;
    besthit.t=-1;
    for (int i=0;i<indicesC.length();i++){
        vec3 TrianglePointA=getCoordinatefromIndices(indicesC[i].x);
        vec3 TrianglePointB=getCoordinatefromIndices(indicesC[i].y);
        vec3 TrianglePointC=getCoordinatefromIndices(indicesC[i].z);
        Hit hit=rayTriangleIntersect(ray, TrianglePointA, TrianglePointB, TrianglePointC);

        if (hit.t>0 && (besthit.t>hit.t|| besthit.t<0)){
            besthit=hit;
        }

    }
    return besthit;
}

vec3 trace(Ray ray){
    vec3 color;
    vec3 ka=vec3(0.5215, 0.1745, 0.0215);

    Hit hit;
    hit=firstIntersect(ray);
    if (hit.t==-1){
        return lights[0].La;
    }
    color=lights[0].La*ka;

    for (int i=0;i<lights.length();i++){
    Ray shadowRay;
    shadowRay.orig=hit.orig+hit.normal*0.0001f;
    shadowRay.dir=lights[i].direction;

        Hit shadowHit=firstIntersect(shadowRay);
        if (shadowHit.t<0){
            color+=lights[i].Le;
        }
    }
    return color;
}

void main()
{
    Ray ray;
    ray.orig = wEye;
    ray.dir = normalize(p - wEye);
    FragColor = vec4(trace(ray), 1);
}