【问题标题】:GLSL : Why are my calculated normals not working properlyGLSL:为什么我计算的法线不能正常工作
【发布时间】:2022-01-24 09:40:52
【问题描述】:

我正在尝试关注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 是为了更明显地发现色差。 这就是我的法线的样子。

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

是什么错误或监督问题导致了这种情况。

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

【问题讨论】:

    标签: glsl fragment-shader raytracing


    【解决方案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 &gt; 0 与 p 为 -1 时,您绘制法线向量。实际上你总是计算normalize(at(r, -1) - sphere.center)。这是错误的,因为 p 需要是从原点到光线撞击球体的球体上品脱的距离。

    当光线击中球体时,p >= 0。在这种情况下,您要绘制法线向量:

    if (p &lt; 0.0)

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

    discriminant &gt; 0

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

    【讨论】:

    • 为什么是if(p &lt; 0.0)
    • @ExtorcProductions 你的代码搞砸了。当discriminant &gt; 0p 为-1 时,您绘制法线向量。实际上你总是计算normalize(at(r, -1) - sphere.center)。这绝对是错误的,因为p 需要是从orgin 到射线击中球体的球体上的品脱的距离。
    • 好的,我会努力改正的。
    • 我对我的代码做了一些更正,imgur.com/a/Lmu1fLG如果这张图片是正确的,那么你可以按照你在上一条评论中所说的写答案。
    • @ExtorcProductions 我已经更改了答案。这是正确的图像。您没有蓝色分量,因为 z 轴是倒置的。试试FragColor = vec4(-N.xyz * 0.5 + 0.5, 1);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多