我想在opengl和glsl中实现光线跟踪来渲染从.obj文件加载的模型,但我不明白这是怎么做到的。我之前使用过obj文件,但是我使用栅格化来渲染它们。到目前为止,我已经使用片段着色器实现了简单的光线跟踪器,渲染了一些简单的形状(平面,球体,盒子)。问题在于光线追踪我计算与物体的交点,但这些也是在片段着色器中定义的。
这就是我使用光栅化进行渲染的方式: 加载顶点数据(位置,正常,uvs)后,我将它们存储到VBO中并将它们绑定到VAO。这些我发送到顶点着色器并通过将它们与MVP矩阵相乘来对它们进行变换。然后我将变换后的顶点发送到片段着色器。但这是我不了解如何通过光线跟踪实现的部分,因为现在我已经将顶点转换为片段着色器的输入,这意味着我不知道如何使用网格三角形计算光线交点。那么,怎么做呢?
答案 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);
}