计算光线跟踪器中的阴影时出现意外结果

时间:2016-03-28 02:36:27

标签: c++ raytracing

我正在使用C ++开发光线跟踪器,到目前为止,我已经能够基于漫反射,镜面反射和环境光学组件计算光照模型。当我试图为我的场景添加阴影时出现了我的问题:场景变得非常混乱:

enter image description here

我的代码分为以下几部分:

  • 我有一个基类“SceneObject”,它有一个虚方法intersect(),它接受一条光线(由原点和方向定义)并输出一个布尔值,以及为计算出的t值返回一个参数,一个命中点和对象的法线。
  • “Material”类包含镜面反射和漫反射颜色(矢量)以及phong指数(int)的值。
  • 我有来自上面SceneObject的3个派生类:plane,triangle和sphere类,每个类都有自己在基类中定义的相交版本。
  • 我有一个函数,使用对象的法线,命中点,光源和对象材料计算给定像素的输出颜色。
  • 我要渲染的所有对象都存储在矢量中。

这是我的派生类之一,Triangle:

class Triangle: public SceneObject{
public:
    Triangle (vec3 a, vec3 b, vec3 c, Material mat){
        name = "Triangle";
        p0 = a;
        p1 = b;
        p2 = c;
        objectMaterial = mat;
        normal = normalize(cross(p0-p1, p0-p2));
    }

    //Möller-Trumbore algorithm
    bool intersect(Ray aRay, float &t, vec3 &hitPoint, vec3 &n){//we will use ray-plane intersection and barycentric coords:

        bool returnValue = false;
        //first we need to get a t of intersection between the passed ray and the triangle
        vec3 v0v1 = p1-p0;
        vec3 v0v2 = p2-p0;
        vec3 pvec = cross(aRay.getDirection(), v0v2);

        float det = dot(v0v1, pvec);

        if ( det >= 1e-6 ){ // Only draw if not backfacing

            float invDet = 1/det;

            float u = dot(-p0, pvec) * invDet;
            // No intersection if u < 0 or u > 1
            if (u >=0 && u <= 1) {
                vec3 qvec = cross(-p0, v0v1);
                float v = dot(aRay.getDirection(), qvec) * invDet;

                // No intersection if v < 0 or u + v > 1
                if (v >=0 && (u + v) <= 1){
                    t = dot(v0v2, qvec) * invDet;
                    returnValue = true;

                    hitPoint = aRay.getOrigin() + (t*aRay.getDirection());
                    n = normal;
                    //calculated_Out_Colour = calculateOutputColour(normal, aRay, lightSource, objectMaterial, t, hitPoint);

                }
            }
        }

        return returnValue; 
    }

private:
    vec3 p0;
    vec3 p1;
    vec3 p2;
    vec3 normal;
};

这是我的主循环,我为窗口的每个像素生成所有光线,并确定颜色以及当前位置是否在阴影中:

for(int i=0;i<imageBuffer.Height();i++){
for(int j=0;j<imageBuffer.Width();j++){
    float currentX = ((float)i-256);
            float currentY = ((float)j-256);
            //cout << currentX << ", " << currentY << ", " << currentZ << endl;
            //make a ray for this pixel (i,j)
            glm::vec3 rayDirection = glm::normalize(glm::vec3(currentX, currentY, -d));
    //make a ray for this pixel (i,j)
    Ray currentRay(vec3(0,0,0), rayDirection);

    vec3 hitPoint;
    vec3 normalAtHit;
    float tnear = 999; // closest intersection, set to INFINITY to start with
    SceneObject* object = NULL;
    for (int k = 0; k < objects.size(); k++) {
        float t; // intersection to the current object if any
        if (objects[k]->intersect(currentRay, t, hitPoint, normalAtHit) && t < tnear) {
            object = objects[k].get();
            tnear = t;

            vec3 shadowRayDirection = normalize(light1.getLightOrigin()-hitPoint);
            Ray shadowRay(hitPoint+vec3(0.03, 0.03,0.03), shadowRayDirection);
            float shadowT;
            vec3 shadowHitPoint;
            vec3 shadowN;
            for (int m = 0; m < objects.size(); ++m) {
                if (objects[m]->intersect(shadowRay, shadowT, shadowHitPoint, shadowN)) {
                    imageBuffer.SetPixel(i, j, ambientColour*ambientIntensity); 
                    break;
                } else {
                    imageBuffer.SetPixel(i, j, calculateOutputColour(normalAtHit, currentRay, light1, objects[k]->getMaterial(), hitPoint));
                }
            }
            }
        }
    }
}

我真的在这里不知所措,我不知道为什么会这样。我尝试过使用here描述的算法,但它会产生图像中显示的相同结果。作为参考,如果我采取循环并检查阴影,我的场景看起来像这样:

enter image description here

我很感激在尝试调试这个东西方面有任何帮助。感谢。

1 个答案:

答案 0 :(得分:0)

Cornstalks是正确的,但如果你使用的是hitPoint + 0.03 * normalAtHit,那么你需要确保正常是与事件光线相匹配的正常光线,我们在你的代码中看到的只是正常的你的原始但每个面有2个法线(一个与另一个相反)。

根据您的不同,您的光线可能从错误的一侧开始,因此可能会导致无效的阴影。

要执行此操作,您可以使用正常情况检查您的incidentRay的点积,具体取决于结果(大于0或小于0),您将知道是否需要反转正常。