【问题标题】:Implementation of Orthogonal Camera in C#C#中正交相机的实现
【发布时间】:2026-01-31 11:55:02
【问题描述】:

我正在制作一个简单的光线追踪器,现在我正在尝试制作一个显示球体的简单正交视图,但我得到一个红色矩形而不是黑色背景上的红色圆圈......

在我的球体类中,我有一个方法可以检查光线是否击中球体:

    public bool IntersectsRay(Ray ray) //c -> origin, R -> radius, o - origin ray, 
    //d - direction ray 
    {
        Vector3 d = ray.direction;
        Vector3 o = ray.origin;
        Vector3 c = origin;
        double R = radius;

        double A = d.DotVector(d); //d^2
        double B = 2 * d.DotVector(o.MinusVector(c)); //2d(o - c)
        double C = (o.MinusVector(c)).DotVector(o.MinusVector(c)) - radius * radius; //(o - c)(o - c) - R^2

        double delta = B * B - 4 * A * C;

        if (delta < 0)
        {
            Console.WriteLine("There are no intersection points");
            return false;
        }
        else
        {
            Console.WriteLine("delta is equal to: {0}", delta);

            double t1 = (-B + Math.Sqrt(delta)) / 2 * A;
            double t2 = (-B - Math.Sqrt(delta)) / 2 * A;

            if (t1.Equals(t2))
            {
                Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));

                Console.WriteLine("P0: ({0}, {1}, {2})", P1.x, P1.y, P1.z);
                return true;
            }
            else
            {
                Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));
                Vector3 P2 = o.PlusVector(d.MultiplyByScalar((float)t2));

                Console.WriteLine("P1: ({0}, {1}, {2}), P2: ({3}, {4}, {5})", P1.x, P1.y, P1.z, P2.x, P2.y, P2.z);
                return true;
            }
        }
    }

正交相机类:

public class CamOrthogonal
{
    public Bitmap BM;
    private float pixelWidth;
    private float pixelHeight;
    private float centerPixelX;
    private float centerPixelY;
    private bool intersection;

    public CamOrthogonal()
    {
        this.BM = new Bitmap(240, 240, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    }

    public CamOrthogonal(Img IMG)
    {
        this.BM = IMG.BM;
    }

    public void render(Sphere S)
    {
        pixelWidth = 2.0f / BM.Width;
        pixelHeight = 2.0f / BM.Height;

        for (int i = 0; i < BM.Width; i++)
        {
            for (int j = 0; j < BM.Height; j++)
            {
                centerPixelX = -1.0f + (i + 0.5f) * pixelWidth;
                centerPixelY = 1.0f - (j + 0.5f) * pixelHeight;

                //Ray ray = new Ray(new Vector3(0, 0, 1), new Vector3(centerPixelX, centerPixelX, 0));
                Ray ray = new Ray(new Vector3(centerPixelX, centerPixelX, 0), new Vector3(0, 0, 1));

                /* if (Plane_or_Sphere is Plane)
                {
                    intersection = ((Plane)Plane_or_Sphere).IntersectsRay(ray);
                }
                else if (Plane_or_Sphere is Sphere)
                {
                    intersection = ((Sphere)Plane_or_Sphere).IntersectsRay(ray);
                } */

                intersection = S.IntersectsRay(ray);

                if (intersection == true)
                {
                    this.BM.SetPixel(i, j, Color.Red);
                }
                else 
                {
                    this.BM.SetPixel(i, j, Color.Black);
                }
            }
        }
        this.BM.Save("/Users/Aleksy/Desktop/RT_IMG.jpg");
    }
}

然后,在我的主要课程中,我有:

CamOrthogonal CAM = new CamOrthogonal();
Sphere S = new Sphere(0, 0, -10, (float)0.1); //origin - x,y,z & radius
CAM.render(S);

我得到的是那个红色矩形。我在哪里做错了?

【问题讨论】:

    标签: c# raytracing


    【解决方案1】:

    在您的代码中,您有:

    double t1 = (-B + Math.Sqrt(delta)) / 2 * A;

    在 C# 中,这是根据 operator precedence rules 评估的,其中指出 */ 是乘法运算符。它还说:

    每个部分中的运算符共享相同的优先级。

    因此,*/ 具有相同的优先级;它们从左到右进行评估。因此,您的陈述被这样评估:

    double t1 = (((-B + Math.Sqrt(delta)) / 2) * A);

    然而,你真正想要解的二次方程是这样的:

    double t1 = (-B + Math.Sqrt(delta)) / (2 * A);

    ...t2 也是如此。

    编辑

    另外,你的命中条件不正确:

    if (t1.Equals(t2))
    {
       Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));
       Console.WriteLine("P0: ({0}, {1}, {2})", P1.x, P1.y, P1.z);
       return true;
    }
    else
    {
       Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));
       Vector3 P2 = o.PlusVector(d.MultiplyByScalar((float)t2));
       Console.WriteLine("P1: ({0}, {1}, {2}), P2: ({3}, {4}, {5})", P1.x, P1.y, P1.z, P2.x, P2.y, P2.z);
       return true;
    }
    

    如果t1 &gt;= 0t2 &gt;= 0,射线实际命中。在这种情况下,交点由最小的t 给出(但仍然是&gt;= 0)。

    【讨论】: