路径跟踪代码不起作用,尽管我认为我做对了

本文关键字:管我 代码 跟踪 不起作用 路径 | 更新日期: 2023-09-27 18:33:59

所以我想写一个小的路径追踪器来熟悉所有的向量数学和交集计算。因此,我用 C# 创建了一个 Windows 窗体应用程序,并使用 PictureBox 来显示位图。

这是我的类"渲染场景"。它创建位图,遍历每个像素,计算与像素相关的光线。创建光线后,我递归地跟踪它在整个世界中,最后返回像素的颜色。

public void renderScene()
    {
        Bitmap drawArea = new Bitmap(pB_Result.Size.Width, pB_Result.Size.Height);
        pB_Result.Image = drawArea;
        int height = pB_Result.Size.Height;
        int width = pB_Result.Size.Width;
        float fov = 160 * (float)Math.PI / 180;
        float zdir = 1.0f / (float)Math.Tan(fov);
        float aspect = (float)height / (float)width;
        //BWorker.RunWorkerAsync(new Tuple<int, int, Bitmap, float, float, float>(height, width, drawArea, fov, zdir, aspect));
        for (int y = 0; y < pB_Result.Height; y++)
        {
            for (int x = 0; x < pB_Result.Width; x++)
            {
                float xdir = (x / (float)width) * 2.0f - 1.0f;
                float ydir = ((y / (float)height) * 2.0f - 1.0f) * aspect;
                Ray ray = new Ray(Camera, new Vector3D(xdir, ydir, zdir).normalize());
                float r = 0, g = 0, b = 0;
                System.Threading.Tasks.Parallel.For(0, RAYS_PER_PIXEL, i =>
                {
                    Color c = Trace(ray, 0);
                    r += c.R;
                    g += c.G;
                    b += c.B;
                });
                //for (int i = 0; i < RAYS_PER_PIXEL; i++)
                //{
                //    Color c = Trace(ray, 0);
                //    r += c.R;
                //    g += c.G;
                //    b += c.B;
                //}
                drawArea.SetPixel(x, y, Color.FromArgb(255, (int)r / RAYS_PER_PIXEL, (int)g / RAYS_PER_PIXEL, (int)b / RAYS_PER_PIXEL));
            }
        }
        pB_Result.Image = drawArea;
    }

这是我的跟踪函数,它递归地将光线与场景相交:

public Color Trace(Ray ray, int depth, BaseObject missObject = null)
    {
        float distance = 5000.0f;
        BaseObject lastHitObject = null;
        Vector3D HitPoint = null;
        foreach (BaseObject obj in this.scene.Objects)
        {
            if (obj == missObject)
                continue;
            float currentDistance = obj.Intersect(ray);
            if (currentDistance < distance && currentDistance > 0)
            {
                distance = currentDistance;
                lastHitObject = obj;
            }
        }
        if (distance == 5000.0f) //Kein Objekt wurde getroffen
            return Color.Black;
        if (lastHitObject.isEmitter) //Eine Lichtquelle wurde getroffen
            return lastHitObject.surfaceColor;
        if (depth == MAX_DEPTH)
            return Color.Black;

        HitPoint = ray.origin.add(ray.direction.multiply(distance));
        Vector3D normal = lastHitObject.Normal(HitPoint);
        Ray reflectionRay = null;
        if (lastHitObject.mat == Material.Diffuse)
        {
            Vector3D randomVector = Vector3D.getRandomVectorInHemisphere();
            if (randomVector.Dotproduct(normal) < 0.0)
                randomVector = randomVector.negate();
            reflectionRay = new Ray(HitPoint, randomVector.normalize());
        }
        Color returnColor = Trace(reflectionRay, depth + 1, lastHitObject);
        float r = lastHitObject.surfaceColor.R * returnColor.R;
        float g = lastHitObject.surfaceColor.G * returnColor.G;
        float b = lastHitObject.surfaceColor.B * returnColor.B;
        r /= 255.0f;
        g /= 255.0f;
        b /= 255.0f;
        return Color.FromArgb(255, (int)r, (int)g, (int)b);
    }

我使用"missObject"参数来避免一些浮点数学不准确,所以我不会再次检查最后一个命中对象。

这是我的Vector3D类,它表示3D空间中的一个点。我还实现了一些操作向量的函数:

    public class Vector3D
{
    public float x { get; set; }
    public float y { get; set; }
    public float z { get; set; }
    public Vector3D()
    { 
    }
    public Vector3D(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    public float Dotproduct(Vector3D Dotvector)
    {
        return (Dotvector.x * this.x + Dotvector.y * this.y + Dotvector.z * this.z);
    }
    public float Length()
    {
        return (float)Math.Sqrt(x*x + y*y + z*z);
    }
    public Vector3D subtract(Vector3D subVec)
    {
        return new Vector3D(this.x - subVec.x, this.y - subVec.y, this.z - subVec.z);
    }
    public Vector3D add(Vector3D addVec)
    {
        return new Vector3D(this.x + addVec.x, this.y + addVec.y, this.z + addVec.z);
    }
    public Vector3D add(float value)
    {
        return add(new Vector3D(value, value, value));
    }
    public Vector3D multiply(Vector3D multVec)
    {
        return new Vector3D(this.x * multVec.x, this.y * multVec.y, this.z * multVec.z);
    }
    public Vector3D multiply(float value)
    {
        return multiply(new Vector3D(value, value, value));
    }
    public Vector3D divide(Vector3D divVec)
    {
        return new Vector3D(this.x / divVec.x, this.y / divVec.y, this.z / divVec.z);
    }
    public Vector3D divide(float value)
    {
        return divide(new Vector3D(value, value, value));
    }
    public Vector3D CrossProduct(Vector3D crossVec)
    {
        return new Vector3D
        {
            x = this.y * crossVec.z - this.z * crossVec.y,
            y = this.z * crossVec.x - this.x * crossVec.z,
            z = this.x * crossVec.y - this.y * crossVec.x
        };
    }
    public Vector3D negate()
    {
        return new Vector3D
        {
            x = -x,
            y = -y,
            z = -z
        };
    }
    public Vector3D normalize()
    { 
        float f = (float)(1.0f / Math.Sqrt(this.Dotproduct(this)));
        x *= f;
        y *= f;
        z *= f;
        return new Vector3D(x, y, z);
    }
    public static Vector3D getRandomVectorInHemisphere()
    {
        Random rnd = new Random(DateTime.Now.Millisecond);
        Vector3D v = new Vector3D
        {
            x = (float)rnd.NextDouble() * 2.0f - 1.0f,
            y = (float)rnd.NextDouble() * 2.0f - 1.0f,
            z = (float)rnd.NextDouble() * 2.0f - 1.0f
        };
        v = v.normalize();
        return v;
    }
}

路径跟踪代码不起作用,尽管我认为我做对了

问题似乎是System.Threading.Tasks.Parallel.For,如果我将其更改为正常的for循环,我会得到一个非常好的结果:

http://img5.fotos-hochladen.net/uploads/pathtracerv4i84onm23aiz.png

相关文章: