奇数光线追踪神器 - 错误的彩色像素

时间:2011-08-08 16:51:17

标签: c# graphics 3d raytracing

所以我试图用C#重写我的光线跟踪器,我一直在收到这些奇怪的文物。 起初我可能认为它们是由于没有将Epsilon添加到阴影射线as described here而导致的黑点伪影。

但是我添加了一个epsilon并且斑点不是黑色(但我添加了环境)。 这是一个示例图片(我将背景设为黄色,因此它突出了一点)

Artifact Image

这是我的照明代码:

private Vector4 CalculateBlinnPhongLight(Ray ray, Intersection its)
    {
        Vector4 blinnPhongColor = Color.Blue.ToVector4();
        //Step 1: Calculate intersection point. Since our direction was never normalized we need to do it here.
        Microsoft.Xna.Framework.Vector3 itsPoint = ray.Origin + ray.Direction*its.TimeInterval.StartTime;
        //Step 2: Calculate half vector h - bisector of angle of v (from intersection to eye) and l (intersection to light)
        Microsoft.Xna.Framework.Vector3 v = -1 * ray.Direction; v.Normalize();
        //Step 3: For ecah light in the scene grab it's contribution
        foreach (Light light in Lights)
        {
            //Step 4: Setup unit vectors for Blinn Phong Lighting model: pg.84
            Microsoft.Xna.Framework.Vector3 l = light.Position - itsPoint; l.Normalize();
            Microsoft.Xna.Framework.Vector3 h = v + l; h.Normalize();
            Microsoft.Xna.Framework.Vector3 n = its.Normal;
            //Step 5: Shadow-Check - send shadow ray and see if it intersects with anything
            if  (IsInShadow(l, itsPoint) )
            {
                continue;
                //TO DO: Check if the material is dielectric (see through)
            }
            //Step 6: Calculate light attenuation
            //TODO:

            //Step 7: Perform Blinn Phong calculation
            //color = color + diffuse * I * max(0, n.l)
            //color = color + specular * I * max(0, n.h)^phong
            blinnPhongColor += its.ClosestNode.Material.DiffuseColor.ToVector4() * light.Color.ToVector4() * Math.Max(0, Microsoft.Xna.Framework.Vector3.Dot(n, l));
            blinnPhongColor += its.ClosestNode.Material.SpecularColor.ToVector4() * light.Color.ToVector4() * (float)Math.Pow(Math.Max(0, Vector3.Dot(n, h)), its.ClosestNode.Material.PhongExponent);
        }
        //Step 8: Add ambient Color
        blinnPhongColor += its.ClosestNode.Material.AmbientColor.ToVector4() * AmbientColor.ToVector4();
        return blinnPhongColor;
    }

    private bool IsInShadow(Microsoft.Xna.Framework.Vector3 dirToLight, Microsoft.Xna.Framework.Vector3 itsPoint)
    {
        //Step 1: Need to add epsilon go itsPoint otherwise we might intersect ourselves
        Microsoft.Xna.Framework.Vector3 epsItsPoint = itsPoint + 0.000001f*dirToLight;
        Ray shadowRay = new Ray(epsItsPoint, dirToLight);
        return ! this.Root.IntersectRay(shadowRay).Hit;
    }

或许值得注意的是,我的光线方向不是单位矢量。我根据我正在阅读的书中的说明有目的地完成了这一点,这样当我可以通过变换矩阵变换光线时,我会给每个原语提供简单的实例化。

1 个答案:

答案 0 :(得分:4)

由于这些神器正在获得环境光的贡献,但既没有接收镜面也没有接收漫反射,几乎可以肯定是IsInShadow计算。根据您定义球体的方式,您应该遇到各种精度误差。

要验证它是您的阴影计算,请使用单个常量贡献替换漫反射和镜面反射贡献。如果文物消失了,那就是你的问题。如果它们没有消失,那么两个光贡献都会出错(不太可能),您可以通过重新定位场景中的灯来验证这一点。

此外,您实际上不需要对阴影线进行标准化处理,并且不这样做会使您无法进行除法计算,通常会发生这种精度错误。