我正在尝试在一个立方体内进行球体光线追踪。该立方体由12个三角形构成,带有法向量。
该立方体具有单位坐标和单位法向量。因此,在其本地空间(介于-1和1之间),应该有半径为0.5的球体。
因此,我认为我应该在顶点着色器中计算光线:光线起点是插值的顶点位置,光线方向是顶点法线(或其相反方向,但我认为这不重要)。插值应该做剩下的事情。
然后,在片段着色器中,我应该计算光线-球体交点,如果有的话,改变片段的颜色。
在立方体的前面和后面,结果似乎是正确的,但在左侧、右侧、顶部和底部,结果似乎来自错误的角度。我应该一直看到中间的球体,但在这些侧面上并非如此。
有人能告诉我我做错了什么吗?
以下是着色器代码:
顶点着色器:
注意:因子t实际上并非必要,但它可以给出光线离球体边缘的距离,从而使其看起来阴影更深。使用步进函数step(0, d)来查看是否存在任何交点,使用max(0, d)来防止着色器在sqrt(<0)错误时停止运行,两者都是为了避免代码分支。
参考资料:我从https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection获取了计算结果。
编辑:这里有一个问题的视频:Video
该立方体具有单位坐标和单位法向量。因此,在其本地空间(介于-1和1之间),应该有半径为0.5的球体。
因此,我认为我应该在顶点着色器中计算光线:光线起点是插值的顶点位置,光线方向是顶点法线(或其相反方向,但我认为这不重要)。插值应该做剩下的事情。
然后,在片段着色器中,我应该计算光线-球体交点,如果有的话,改变片段的颜色。
在立方体的前面和后面,结果似乎是正确的,但在左侧、右侧、顶部和底部,结果似乎来自错误的角度。我应该一直看到中间的球体,但在这些侧面上并非如此。
有人能告诉我我做错了什么吗?
以下是着色器代码:
顶点着色器:
#version 400
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aNor;
uniform mat4 uProj;
uniform mat4 uView;
uniform mat4 uModel;
out vec3 vRayPos;
out vec3 vRayDir;
void main(void)
{
gl_Position = uProj * uView * uModel * vec4(aPos, 1);
vRayPos = aPos;
vRayDir = inverse(mat3(uModel)) * aNor;
}
片元着色器:
#version 400
in vec3 vRayPos;
in vec3 vRayDir;
out vec4 oFrag;
void main(void)
{
const vec3 sphereCenter = vec3(0, 0, 0);
const float sphereRadius = 0.5;
vec3 rayPos = vRayPos;
vec3 rayDir = normalize(vRayDir);
float a = dot(rayDir, rayDir); // TODO: rayDir is a unit vector, so: a = 1.0?
float b = 2 * dot(rayDir, (rayPos - sphereCenter));
float c = dot(rayPos - sphereCenter, rayPos - sphereCenter) - sphereRadius * sphereRadius;
float d = b * b - 4 * a * c;
float t = min(-b + sqrt(max(0, d)) / 2, -b - sqrt(max(0, d)) / 2);
vec3 color = (1.0 - step(0, d)) * vec3(0.554, 0.638, 0.447) + step(0, d) * abs(t) * vec3(0.800, 0.113, 0.053);
oFrag = vec4(color, 1);
}
注意:因子t实际上并非必要,但它可以给出光线离球体边缘的距离,从而使其看起来阴影更深。使用步进函数step(0, d)来查看是否存在任何交点,使用max(0, d)来防止着色器在sqrt(<0)错误时停止运行,两者都是为了避免代码分支。
参考资料:我从https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection获取了计算结果。
编辑:这里有一个问题的视频:Video
1.0
而不是0.5
。你可以通过这个ray and ellipsoid intersection accuracy improvement来交叉检查你的相交点。你有问题的截图吗?此外,你的射线方向/位置描述听起来有些奇怪,请参考第一个链接中的"How I do it (Quad covering whole screen,position is the Vertex position but direction is position-focus instead of normal !)"。 - SpektrevRayDir = inverse(mat3(uModel)) * aNor;
看起来很可疑。我会使用你的立方体中心,并将其沿法线方向平移半个大小加上焦距,以获得焦点,然后vRayDir = vRayPos - focal_point
... - Spektre