Javascript GLSL中阴影光线的平滑阴影无法正常工作

Javascript GLSL中阴影光线的平滑阴影无法正常工作,javascript,opengl-es,glsl,webgl,webgl2,Javascript,Opengl Es,Glsl,Webgl,Webgl2,我正在WebGL中使用网格点实现光线跟踪器。关于我的实现,我只说几句话 我在纹理中传递顶点值和顶点法线,并在执行光线跟踪算法的片段着色器中解压它们。由三角形组成的球体具有平坦的着色外观,然后我将三角形的顶点法线乘以重心坐标,在三角形球体中具有平滑外观。问题是,当我计算阴影时,它具有相同的前卫外观。我将提供一个打印屏幕的结果和代码,我目前如何计算阴影光线 如您所见,球体表面看起来平滑,但阴影不平滑 下面是我使用的calcShadow函数: vec3 calcShadow(Sphere lightS

我正在WebGL中使用网格点实现光线跟踪器。关于我的实现,我只说几句话

我在纹理中传递顶点值和顶点法线,并在执行光线跟踪算法的片段着色器中解压它们。由三角形组成的球体具有平坦的着色外观,然后我将三角形的顶点法线乘以重心坐标,在三角形球体中具有平滑外观。问题是,当我计算阴影时,它具有相同的前卫外观。我将提供一个打印屏幕的结果和代码,我目前如何计算阴影光线

如您所见,球体表面看起来平滑,但阴影不平滑

下面是我使用的calcShadow函数:

vec3 calcShadow(Sphere lightSource, vec3 hitPos){
    vec3 color;

    vec3 lightDir =  normalize(lightSource.center-hitPos);
    Ray shadowRay = Ray(hitPos, lightDir);

    float isHitLight = hitLightSource(shadowRay,lightSource);
    float isHitMesh = hitMesh(shadowRay);

    if (isHitMesh < isHitLight) {
        color = vec3(0.5,0.5,0.5);
    }else{
        color = vec3(1.,1.,1.);    
    }
    return color;
}
hitMesh:

float hitMesh(Ray R_){
    float mindist = 1000.;
    vec4 a = vec4(0.0), b = vec4(0.0), c = vec4(0.0);
    vec3 intersect = vec3(0.0,0.0,0.0);

    for (int i = 0; i < vertsCount; i += 3) {
        a = texelFetch(uMeshData, ivec2(i, 0), 0);
        b = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(1, 0));
        c = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(2, 0));

        vec3 triangleNormal;
        vec3 uvt;
        float z;

        bool isHit = hitTriangleSecond(R_.orig, R_.dir, a.xyz, b.xyz, c.xyz, uvt, triangleNormal, intersect, z);;
        if (isHit) {
            if (z<mindist && z > 0.001)  mindist = z;
        } 

    }
    return mindist;
}
这是Hittangleke第二种三角形相交测试方法:

bool hitTriangleSecond( vec3 orig, vec3 dir, vec3 a, vec3 b, vec3 c,
                        out vec3 uvt, out vec3 N, out vec3 x, out float dist) {

    float eps=1e-8;

    vec3 ab = b - a;
    vec3 ac = c - a;

    N = normalize(cross(ab, ac));

    dist = dot(a - orig, N) / dot(dir, N);
    x    = orig + dir * dist;

    vec3 ax = x - a;

    float d00 = dot(ab, ab);
    float d01 = dot(ab, ac);
    float d11 = dot(ac, ac);
    float d20 = dot(ax, ab);
    float d21 = dot(ax, ac);

    float denom = d00 * d11 - d01 * d01; // determinant

    // if the determinant is negative the triangle is backfacing
    // if the determinant is close to 0, the ray misses the triangl
    if ( denom <= eps )
        return false;

    uvt.y = (d11 * d20 - d01 * d21) / denom;
    if ( uvt.y < 0.0 || uvt.y > 1.0 )
        return false;

    uvt.z = (d00 * d21 - d01 * d20) / denom;
    if ( uvt.z < 0.0 || uvt.z > 1.0 )
        return false;

    uvt.x = 1.0 - uvt.y - uvt.z;
    if ( uvt.x < 0.0 || uvt.x > 1.0 )
        return false;

    return true;
}
我知道没有插值三角形法线的计算,但我的问题是,是否需要更新hitTriangle函数以返回基于顶点法线的插值法线?或者我需要计算重心坐标,然后把它插入命中三角形函数?我有点不明白如何实现平滑阴影

下面是我的跟踪循环,在这里我打开网格并计算命中的插值法线,这就是我获得平滑曲面外观的方式:

for (int i = 0; i < vertsCount; i += 3) {

            a = texelFetch(uMeshData, ivec2(i, 0), 0);
            b = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(1, 0));
            c = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(2, 0));

            aN = texelFetch(uNormData, ivec2(i, 0), 0);
            bN = texelFetchOffset(uNormData, ivec2(i, 0), 0, ivec2(1, 0));
            cN = texelFetchOffset(uNormData, ivec2(i, 0), 0, ivec2(2, 0));

            vec3 uvt;
            vec3 intersect;
            float z;
            bool isHit = hitTriangleSecond(R_.orig, R_.dir, a.xyz, b.xyz, c.xyz, uvt, triangleNormal, intersect, z);
            if (isHit) {

                if (z<mindist && z > 0.001) {
                    hitPos1 = intersect;

                    mindist = z;
                    weHitSomething = true;
                    material.type = DIEL;
                    material.albedo = vec3(.8, .3, .4);
                    normal = aN.xyz*uvt.x + bN.xyz*uvt.y + cN.xyz*uvt.z;

                    hitPos = hitPos1;            
                }
            }      
        } 

用于光线命中测试的网格仍然是低分辨率三角形网格,即使为了校正照明计算而使用法线,因此阴影中的锐角在某种程度上是意料之中的

光线投射依赖于三角形相交,因此对于平滑阴影,您需要阴影投射器中的平滑几何体,即更多三角形。法线贴图等技术适用于照明,因为您可以基于修改的方向伪造近似的灯光强度,但实际上没有任何曲面位移会改变物理几何体,因此这无助于纠正任何错误的命中测试


阴影真正需要的是更多的几何图形,以便使用真实的三角形准确地描述阴影投射轮廓边缘的形状。

无论我测试什么,我都无法理解它。。了解一下这个问题会很好。谢谢你为什么你不希望看到阴影?用于光线命中测试的网格仍然是低分辨率三角形网格,即使为了校正照明计算而乱弄法线也是如此。阴影真正需要的是剪影边缘的真实位移,但我不确定即使修正法线也能真正为您提供曲面方向!=表面位移。@solidpixel我知道阴影会这样显示,这就是我问的原因,但是你能解释一下你所说的轮廓边缘的真实位移是什么意思吗?我想知道是否有一种方法可以得到平滑的阴影。把这变成了一个答案…所以对于平滑的阴影,我需要有更详细的几何体?意思是更多的三角形?是的。对象的物理形状必须与要投射的阴影相匹配,因为物理形状的轮廓是光线跟踪投射的。