虽然我认为我做得对,但Pathtracing Code无效

时间:2014-12-11 07:43:26

标签: c# bitmap

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

这是我的班级“renderScene”。它创建了Bitmap,遍历每个像素,根据像素计算光线。创建光线后,我会递归遍历世界,最后返回像素的颜色。

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;
    }
}

1 个答案:

答案 0 :(得分:0)

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

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