光线跟踪三角形的问题(方向和着色)

时间:2016-11-14 23:48:48

标签: java colors raytracing lighting

编辑:我发现所有像素都是颠倒的,因为屏幕和世界坐标之间存在差异,所以这不再是问题。
编辑:根据@TheVee的建议(使用绝对值)后,我的图片变得更好了,但我仍然看到颜色问题。

我对光线跟踪三角形有点麻烦。这是我previous question关于同一主题的后续内容。这个问题的答案让我意识到我需要采取不同的方法。我采用的新方法效果更好,但我现在看到了我的光线跟踪器的几个问题:

  1. 有一个三角形永远不会呈现颜色(它总是黑色,即使它的颜色应该是黄色)。
  2. 以下是我期待看到的内容:
    Expected

    但这就是我实际看到的内容:
    Actual

    1. 解决调试第一个问题,即使我删除所有其他对象(包括蓝色三角​​形),黄色三角形总是呈现黑色,所以我不相信这是我发送的阴影光线的问题出。我怀疑它与三角形/平面相对于相机的角度有关。
    2. 以下是基于this website中的过程的光线跟踪三角形的过程。

      1. 确定光线是否与平面相交。
      2. 如果是,请确定光线是否与三角形内部相交(使用参数坐标)。
      3. 以下是确定光线是否到达平面的代码:

        private Vector getPlaneIntersectionVector(Ray ray)
        {
            double epsilon = 0.00000001;
            Vector w0 = ray.getOrigin().subtract(getB());
            double numerator = -(getPlaneNormal().dotProduct(w0));
            double denominator = getPlaneNormal().dotProduct(ray.getDirection());
            //ray is parallel to triangle plane
            if (Math.abs(denominator) < epsilon)
            {
                //ray lies in triangle plane
                if (numerator == 0)
                {
                    return null;
                }
                //ray is disjoint from plane
                else
                {
                    return null;
                }
            }
            double intersectionDistance = numerator / denominator;
        
            //intersectionDistance < 0 means the "intersection" is behind the ray (pointing away from plane), so not a real intersection
            return (intersectionDistance >= 0) ? ray.getLocationWithMagnitude(intersectionDistance) : null;
        }
        

        一旦我确定光线与平面相交,这里就是确定光线是否在三角形内的代码:

        private boolean isIntersectionVectorInsideTriangle(Vector planeIntersectionVector)
        {
            //Get edges of triangle
            Vector u = getU(); 
            Vector v = getV();
        
            //Pre-compute unique five dot-products
            double uu = u.dotProduct(u);
            double uv = u.dotProduct(v);
            double vv = v.dotProduct(v);
            Vector w = planeIntersectionVector.subtract(getB());
            double wu = w.dotProduct(u);
            double wv = w.dotProduct(v);
            double denominator = (uv * uv) - (uu * vv);
        
            //get and test parametric coordinates
            double s = ((uv * wv) - (vv * wu)) / denominator;
            if (s < 0 || s > 1)
            {
                return false;
            }
            double t = ((uv * wu) - (uu * wv)) / denominator;
            if (t < 0 || (s + t) > 1)
            {
                return false;
            }
        
            return true;
        }
        

        认为我的着色有问题。我认为它与各种三角形的法线有关。这是我在为球体和三角形构建照明模型时正在考虑的等式:
        Lighting model

        现在,这是执行此操作的代码:

        public Color calculateIlluminationModel(Vector normal, boolean isInShadow, Scene scene, Ray ray, Vector intersectionPoint)
        {
            //c = cr * ca + cr * cl * max(0, n \dot l)) + cl * cp * max(0, e \dot r)^p
            Vector lightSourceColor = getColorVector(scene.getLightColor()); //cl
            Vector diffuseReflectanceColor = getColorVector(getMaterialColor()); //cr
            Vector ambientColor = getColorVector(scene.getAmbientLightColor()); //ca
            Vector specularHighlightColor = getColorVector(getSpecularHighlight()); //cp
            Vector directionToLight = scene.getDirectionToLight().normalize(); //l
            double angleBetweenLightAndNormal = directionToLight.dotProduct(normal);
            Vector reflectionVector = normal.multiply(2).multiply(angleBetweenLightAndNormal).subtract(directionToLight).normalize(); //r
        
            double visibilityTerm = isInShadow ? 0 : 1;
            Vector ambientTerm = diffuseReflectanceColor.multiply(ambientColor);
        
            double lambertianComponent = Math.max(0, angleBetweenLightAndNormal);
            Vector diffuseTerm = diffuseReflectanceColor.multiply(lightSourceColor).multiply(lambertianComponent).multiply(visibilityTerm);
        
            double angleBetweenEyeAndReflection = scene.getLookFrom().dotProduct(reflectionVector);
            angleBetweenEyeAndReflection = Math.max(0, angleBetweenEyeAndReflection);
            double phongComponent = Math.pow(angleBetweenEyeAndReflection, getPhongConstant());
            Vector phongTerm = lightSourceColor.multiply(specularHighlightColor).multiply(phongComponent).multiply(visibilityTerm);
        
            return getVectorColor(ambientTerm.add(diffuseTerm).add(phongTerm));
        }
        

        我看到正常光源和光源之间的点积为黄色三角形为-1,蓝色三角形为-707左右,所以我不确定正常是错误的方式是问题。无论如何,当我添加确保光线和法线之间的角度为正(Math.abs(directionToLight.dotProduct(normal));)时,它会导致相反的问题:
        Absolute value of dot products

        我怀疑这将是一个小错字/错误,但我需要另一双眼睛来发现我不能。

        注意:我的三角形有顶点(a,b,c),边(u,v)分别使用a-bc-b计算(同样,这些是用于计算平面/三角形法线)。 Vector(x,y,z)点组成,Ray由来源Vector和标准化方向Vector组成。

        以下是我计算所有三角形法线的方法:

        private Vector getPlaneNormal()
        {
            Vector v1 = getU();
            Vector v2 = getV();
            return v1.crossProduct(v2).normalize();
        }
        

        如果我遗漏了您认为对解决这些问题很重要的任何事情,请告诉我。

        编辑:在@TheVee的帮助下,这就是我当时所拥有的: "Working" image

        z-buffering仍然存在问题,而且三角形的phong突出显示,但我试图在这里解决的问题是固定的。

1 个答案:

答案 0 :(得分:1)

在我们从错误的一侧击中它们的场景(包括平面物体)的光线追踪中,这是一个常见的问题。包含点积的公式具有固有的假设,即光从面向外的法线指向的方向入射到物体上。 这可能只适用于三角形的一半可能方向并且你运气不好以正常背离光线定向它。

从技术上讲,在物理世界中,你的三角形不会有零音量。它由一些薄薄的材料层组成。在任何一方,它都有一个指向外面的正常法线。分配单个法线是一种公平的简化,因为两者只有不同的符号。

但是,如果我们进行了简化,我们需要考虑到它。从技术上来说,在我们的公式中,内向正常会产生负点产品,在这种情况下它们不是为了制造的。这就像光从物体内部传来,或者它撞到一个表面是不可能的。这就是他们给出错误结果的原因。负值将减去来自其他来源的光,并且取决于幅度和实施可能导致变暗,全黑或数值下溢。

但是因为我们知道正确的正常是我们正在使用的还是负面的,我们可以通过采取预防性绝对值来立即修复案例,其中隐含地假定正点积(在您的代码中,即{ {1}})。像OpenGL这样的一些库会为您做这些,并且最好使用附加信息(符号)在您需要的two different materials(正面和背面)之间进行选择。或者,它们可以设置为根本不绘制实体对象的背面,因为无论如何它们都会被实体对象的前面透支(称为face culling),从而节省了大约一半的数值工作。