Math 三维点到二维功能工作不正常

Math 三维点到二维功能工作不正常,math,matrix,3d,2d,point,c#,Math,Matrix,3d,2d,Point,C#,我已经研究这个话题一段时间了,现在我终于尝试自己去实现它了;但是,由于某些原因,3d点未正确转换为2d点,这意味着我的函数返回了错误的值。这可能来自两种不同的情况: 1) 我的数学不正确 2) 我的矩阵的值不正确 由于我正在反转和使用地址,我不确定矩阵。有没有可能有人检查我的数学,看看是不是数学不正确?在此功能上的任何帮助都将不胜感激。提前感谢您的建议 private bool ConvertToScreen(Vector3 position3D, ref Point screenPoint)

我已经研究这个话题一段时间了,现在我终于尝试自己去实现它了;但是,由于某些原因,3d点未正确转换为2d点,这意味着我的函数返回了错误的值。这可能来自两种不同的情况:

1) 我的数学不正确

2) 我的矩阵的值不正确

由于我正在反转和使用地址,我不确定矩阵。有没有可能有人检查我的数学,看看是不是数学不正确?在此功能上的任何帮助都将不胜感激。提前感谢您的建议

private bool ConvertToScreen(Vector3 position3D, ref Point screenPoint)
    {

    // r is the right rotation (x-axis)
    // u is the up rotation (y-axis)
    // f is the forward rotation (z-axis)
    // p is the position (transform)

        Point returnPoint = new Point(300, 400);

        // Set Values of Matrix
        Matrix matrix = GetMatrix();

        // Do the math calculations here
        float xPrime = matrix.rX * position3D.x + matrix.rY * position3D.y + matrix.rZ * position3D.z + matrix.rW;
        float yPrime = matrix.uX * position3D.x + matrix.uY * position3D.y + matrix.uZ * position3D.z + matrix.uW;
        // Dont need zPrime
        float wPrime = matrix.pX * position3D.x + matrix.pY * position3D.y + matrix.pZ * position3D.z + matrix.pW;

        // If wPrime > 0 we can see the point
        if (wPrime <= 0)
        {
            return false;
        }
        xPrime *= 1 / wPrime;
        yPrime *= 1 / wPrime;

        // Relative To Screen Center
        xPrime = rect.left + 0.5f * xPrime * (rect.right - rect.left) + 0.5f;
        yPrime = rect.top + 0.5f * yPrime * (rect.bottom - rect.top) + 0.5f;

        returnPoint = new Point((int)xPrime, (int)yPrime);

        screenPoint = returnPoint;

        return true;
    }
专用布尔变换器屏幕(矢量3位置3D,参考点屏幕点)
{
//r是右旋转(x轴)
//u是向上旋转(y轴)
//f为正向旋转(z轴)
//p是位置(变换)
点返回点=新点(300400);
//矩阵的集值
矩阵=GetMatrix();
//在这里做数学计算
float xPrime=matrix.rX*position3D.x+matrix.rY*position3D.y+matrix.rZ*position3D.z+matrix.rW;
float yPrime=matrix.uX*position3D.x+matrix.uY*position3D.y+matrix.uZ*position3D.z+matrix.uW;
//不需要zPrime
float wPrime=matrix.pX*position3D.x+matrix.pY*position3D.y+matrix.pZ*position3D.z+matrix.pW;
//如果wPrime>0,我们就可以看出这一点

如果(wPrime这个计算有几个步骤,我建议将它分成相应的部分,并对每个部分进行测试

  • 模型到摄像机坐标-这是
    位置=(x,y,z)
    点从模型坐标到摄像机坐标的旋转。这里我们假设摄像机的目标位于原点

    local = rot * (position - target)
    
    | x' |   | rx ry rz |   | x |   | rx*x + ry*y + rz*z |
    | y' | = | ux uy yz | * | y | = | ux*x + uy*y + uz*z |
    | z' |   | fx fy fz |   | z |   | fx*x + fy*y + fz*z |
    
  • 透视投影-您需要定义目标和相机之间的距离,以及覆盖视图的模型大小。我们将其称为
    距离
    大小
    。结果是视图坐标在x和y方向上都在
    0..1
    之间变化

    | vx |    | (distance/size)*(x'/(distance+z')) |
    |    | =  |                         |          |
    | vy |    | (distance/size)*(y'/(distance+z')) |
    
    这来自类似的三角形。如果
    x'=size
    z'=0
    ,则
    vx=1
    。越大的
    z'
    越小

  • 像素坐标

    在这里,您可以将视图坐标映射为像素。您的视口具有
    宽度和
    高度,您希望
    [0,0]
    像素位于左上角,而
    [width-1,height-1]
    位于右下角

           width
    +-------------------+
    |(-1,1)   :    (1,1)|
    |         :         |
    |         : (0,0)   |
    +- - - - -+- - - - -+ height
    |         :         |
    |         :         |
    |(-1,-1)  :   (1,-1)| 
    +-------------------+
    
    px = (width-1)*(vx+1.0)/2.0
    py = (height-1)*(1.0-vy)/2.0
    
  • 最后,我建议使用OOP编程(如果可能的话)将向量/矩阵数学分解为意图。
    通过摄像机的公共静态矢量3(矢量3点、矢量3目标、矩阵3摄像机)
    {
    返回camera.Transpose()*(点目标);
    }
    公共静态矢量2透视图(矢量3点,双距离,双尺寸=1)
    {
    返回新矢量2(
    (距离/大小)*(点X/(距离+点Z)),
    (距离/大小)*(点Y/(距离+点Z));
    }
    公共静态点F像素(矢量2点、整数宽度、整数高度)
    {
    返回新的点F(
    (浮动)((宽度-1)*(点X+1)/2),
    (浮动)((高度-1)*(1点Y)/2));
    }
    静态无效dlg_Paint(对象发送器、PaintEventArgs e)
    {
    表格dlg=作为表格的发件人;
    //设置摄影机旋转
    Matrix3摄像机=Matrix3.Ry(0.67);
    双倍距离=25;
    双倍尺寸=20;
    
    对于(int i=0;i您确定绘制2D点
    (0,0)
    会在视口的中心创建一个点吗?此代码会转换为2D点,而不是像素。我以为我正在转换为像素坐标。您能给我指出正确的方向吗
    返回视图投影矩阵?是
    r,u,f
    方向向量吗?你称它们为旋转。我想,它们代表矩阵的各个列或行?相对于屏幕中心
    //下最后的
    +0.5f
    看起来是错误的。相反,你应该用替换
    xPrime
    yPrime
    ode>(xPrime+1)
    (yPrime+1)
    。谢谢。所以我相信我得到的是二维坐标,这意味着我需要将二维坐标转换为像素坐标。谢谢你的详细回答。
        public static Vector3 ThroughCamera(Vector3 point, Vector3 target, Matrix3 camera)
        {
            return camera.Transpose()*(point-target);
        }
    
        public static Vector2 Perspective(Vector3 point, double distance, double size=1)
        {
            return new Vector2(
                (distance/size)*(point.X/(distance+point.Z)),
                (distance/size)*(point.Y/(distance+point.Z)) );
        }
        public static PointF Pixel(Vector2 point, int width, int height)
        {
            return new PointF(
                (float) ((width-1)*(point.X+1)/2),
                (float) ((height-1)*(1-point.Y)/2) );
        }
    
        static void dlg_Paint(object sender, PaintEventArgs e)
        {
            Form dlg=sender as Form;
            // Set camera rotation
            Matrix3 camera=Matrix3.Ry(0.67);
            double distance=25;
            double size=20;
    
            for(int i=0; i<10; i++)
            {
                for(int j=0; j<10; j++)
                {
                    // this is the model points
                    Vector3 pt=new Vector3(5*(i-5), 5*(j-5), 0);
                    // these are the points through the camera
                    Vector3 pt_local=ThroughCamera(pt, Vector3.O, camera);
                    // these are the view coordinates
                    Vector2 pt_view=Perspective(pt_local, distance, size);
                    // these are the pixel coordinates
                    PointF px=Pixel(pt_view, dlg.ClientSize.Width, dlg.ClientSize.Height);
    
                    e.Graphics.DrawRectangle(Pens.Blue, px.X, px.Y, 1f, 1f);
                }
            }            
        }