因此,我受命创建一个康奈尔盒子的模型。我已经设法做完了一切,直到投射阴影为止,在这种情况下,当不应有阴影时,会投射一些阴影。以下是现在的外观图片和应该的外观图片:



我发现由于某种原因,箱壁也蒙上阴影。

快速了解其工作原理:我们有一个针孔相机,可以将光线投射出并找到最近的碰撞点,这就是您所看到的一切。它将这些点以及从某个起始点(在这种情况下为摄像机)到碰撞点的距离保存在一个称为“相交”的预定义数据结构中。然后,它使用此数据来计算与光的距离,从而创建照明强度。用于查找最近碰撞点的方法与使用原始碰撞点作为起点并使用光源作为射线矢量的方向的方法相同,该方法用于查找阴影的最近对象。

我已将问题缩小为射线追踪;当检查是否有任何物体要从后灰墙的右上区域投射阴影时,青绿色的天花板是从光源同一侧的一点拾取的。例如。说光源在中间,原始点在我们的右侧。当向量应直接穿过光源并在我们左侧的某个位置结束时,该方法会以某种方式拾取光的同一点。

这是我的源代码有问题的功能:

bool ClosestIntersection( vec3 start, vec3 dir, const vector<Triangle>& triangles, Intersection& it ) {

    vec3 least;
    vec3 e1, e2, b, v0;
    mat3 A;

    least[0] = m;

    int index = triangles.size()-1;

    for(int i = 0; i < int(triangles.size()); i++) {

        v0 = triangles[i].v0;
        e1 = triangles[i].v1 - v0;
        e2 = triangles[i].v2 - v0;
        b = start - v0;

        A = mat3( -dir, e1, e2);

        if(!getInverse(A,b)) {continue;}

        vec3 x = A * b;

        if(x[0] <= least[0] && x[1] + x[2] <= 1.f && x[1] >= 0.f && x[2] >= 0.f && x[0] >= 0.00001f) {
            least = x;
            index = i;
        }
    }

    if (least[0] == m) {
        return false;
    }
    else {
        it.position = least[0] * dir + start;
        const vec3 t = it.position-start;
        it.distance = sqrt(t[0]*t[0] + t[1]*t[1] + t[2]*t[2]);
        it.triangleIndex = index;
        return true;
    }
}

vec3 DirectLight( const Intersection& i ){
    const Triangle T = triangles[i.triangleIndex];
    const vec3 r = lightPos - i.position;
    const float dist = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);

    Intersection t;
    t.distance = dist;
    t.position = i.position;
    t.triangleIndex = i.triangleIndex; 

    //ClosestIntersection( i.position, lightPos, triangles, t);

    /*
    if(!ClosestIntersection( lightPos, i.position, triangles, t)) {return vec3(1,0,0);}
    else { return vec3(0,0,0); } */

    if(ClosestIntersection( i.position, lightPos, triangles, t) && (dist-t.distance > 1.f)) {

        return vec3(0,0,0);
    } else {
        const vec3 B = 14.f * T.color * (float(max(dot(r,T.normal),float(0)) / float(4*3.14 * dist* dist)));

        return B; 
    }


}

我花了十二个小时来尝试发现此问题。甚至我的讲师也无法解决问题。任何帮助将不胜感激!

#1 楼

您确定在检查光遮挡器时没有在同一表面上重新相交吗?这是一个经典的精度问题。有很多解决方法:


首先,对交叉点进行良好的条件处理,方法是第二次相交:将您的第一个碰撞距离d视为近似值,创建点E '=眼睛+(d-eps)*射线,从此处重新计算交点。 (变体:对于第一个交点,只需使用边界框即可。)
其次,对于掠射角,这取决于您的形状表示,存储和计算精度以及比例,细分,在这里您也可能存在危险的不精确度,并且必须仍然确保您不会重新相交同一表面。如果是平坦的,凸起的或镶嵌的,则可以将其标记为不可相交以进行阴影射线测试。
一个更简单的技巧(更近似)是用epsilon在正常方向上移动阴影射线的起点。


#2 楼

实际上有很多技巧可以让您完全避开该问题*。场景和要进行光线追踪的事物集不必相同。大多数光线跟踪器允许对象不参与阴影投射,反射等。

在您的情况下,您可以仅从阴影投射中取出外墙,因此它们不会自阴影,因此您不能放置阴影

无论如何,您都可以为采样增加一些偏差,并比计算结果所考虑的稍微考虑对象,因为阴影投射可以避免各种问题。
/>
*是的,您应该解决此问题。但是有时候,所有这些都需要快速而完成的事情