GLSL:为什么我计算的法线不能正常工作

GLSL : Why are my calculated normals not working properly

我正在尝试遵循 Ray Tracing in one Weekend tutorial 但我的法线看起来不像我期望的那样。

float hit_sphere(Sphere sphere, Ray r){
    vec3 oc = r.origin - sphere.center;
    float a = dot(r.direction,r.direction);
    float b = 2.0 * dot(oc, r.direction);
    float c = dot(oc, oc) - sphere.radius * sphere.radius;
    float discriminant = b * b - 4 * a * c;
    if(discriminant > 0){
        return -1;
    }
    else{
        return (-b -sqrt(discriminant))/(2.0 * a);
    }
}

vec3 at(Ray ray, float p){
    return ray.origin + p * ray.direction;
}

void main()
{
    vec3 camera_origin = vec3(0,0,2);
    vec2 st = gl_FragCoord.xy/vec2(x, y);
    Ray r = Ray(camera_origin, normalize(vec3(st.x - 0.5, st.y - 0.5, 1.0)));

    Sphere sphere = {vec3(0,0,0),0.5};
    float p = hit_sphere(sphere, r);
    
if(p < 0.0){
    vec3 N = normalize(at(r, p) - sphere.center);
    FragColor = vec4(N.x + 1, N.y + 1, N.z + 1, 1);
}
else{
    // FragColor = vec4(st.xy, 1.0, 1.0);
    FragColor = vec4(1 - st.y+0.7, 1 - st.y+0.7,1 - st.y+0.9, 1.0);
}
}

请注意,每个正常颜色通道中的 + 1 是为了更明显地发现色差。 这就是我的法线的样子。

尽管这不是我所期望的这些法线的样子。 它们应该是这样的(不完全像这样但是很接近)

是什么错误或疏忽的问题导致的。

注意:来回移动不会改变情况

表达式

FragColor = vec4(N.x + 1, N.y + 1, N.z + 1, 1);

创建 [0, 2] 范围内的颜色。但是,颜色通道必须在 [0, 1]:

范围内
FragColor = vec4(N.xyz * 0.5 + 0.5, 1);

注意你也可以用abs表示法线:

FragColor = vec4(abs(N.xyz), 1);

甚至用倒数最大颜色通道缩放:

vec3 nv_color = abs(N.xyz); 
nv_color     /= max(nv_color.x, max(nv_color.y, nv_color.z));
FragColor     = vec4(nv_color, 1.0); 

discriminant > 0 p 为-1 时绘制法向量。其实你总是计算normalize(at(r, -1) - sphere.center)。这是错误的,因为 p 需要是从原点到射线撞击球体的球体上的 pint 的距离。

当光线射到球体上时,p >= 0。此时你要绘制法向量:

if (p < 0.0)

if (p >= 0.0) {
    vec3 N = normalize(at(r, p) - sphere.center);
    FragColor = vec4(N.xyz * 0.5 + 0.5, 1);
}

discriminant > 0

if (discriminant < 0){
    return -1;
}
else {
    return (-b -sqrt(discriminant))/(2.0 * a);
}