将 3D 点投影到 2D 屏幕坐标 [英] Projecting a 3D point to a 2D screen coordinate

查看:89
本文介绍了将 3D 点投影到 2D 屏幕坐标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 Windows 3D 编程 (Charles Petzold) 第 7 章中的信息,我已经尝试编写将 Point3D 投影到包含相应屏幕坐标 (x,y) 的标准 2D Point 的辅助函数:

Based on information in Chapter 7 of 3D Programming For Windows (Charles Petzold), I've attempted to write as helper function that projects a Point3D to a standard 2D Point that contains the corresponding screen coordinates (x,y):

public Point Point3DToScreen2D(Point3D point3D,Viewport3D viewPort )
{
    double screenX = 0d, screenY = 0d;

    // Camera is defined in XAML as:
    //        <Viewport3D.Camera>
    //             <PerspectiveCamera Position="0,0,800" LookDirection="0,0,-1" />
    //        </Viewport3D.Camera>

    PerspectiveCamera cam = viewPort.Camera as PerspectiveCamera;

    // Translate input point using camera position
    double inputX = point3D.X - cam.Position.X;
    double inputY = point3D.Y - cam.Position.Y;
    double inputZ = point3D.Z - cam.Position.Z;

    double aspectRatio = viewPort.ActualWidth / viewPort.ActualHeight;

    // Apply projection to X and Y
    screenX = inputX / (-inputZ * Math.Tan(cam.FieldOfView / 2));

    screenY = (inputY * aspectRatio) / (-inputZ * Math.Tan(cam.FieldOfView / 2));

    // Convert to screen coordinates
    screenX = screenX * viewPort.ActualWidth;

    screenY = screenY * viewPort.ActualHeight;


    // Additional, currently unused, projection scaling factors
    /*
    double xScale = 1 / Math.Tan(Math.PI * cam.FieldOfView / 360);
    double yScale = aspectRatio * xScale;

    double zFar = cam.FarPlaneDistance;
    double zNear = cam.NearPlaneDistance;

    double zScale = zFar == Double.PositiveInfinity ? -1 : zFar / (zNear - zFar);
    double zOffset = zNear * zScale;

    */

    return new Point(screenX, screenY);
}

然而,在测试中,此函数返回错误的屏幕坐标(通过将 2D 鼠标坐标与简单的 3D 形状进行比较来检查).由于我缺乏 3D 编程经验,我不知道为什么.

On testing however this function returns incorrect screen coordinates (checked by comparing 2D mouse coordinates against a simple 3D shape). Due to my lack of 3D programming experience I am confused as to why.

块注释部分包含可能必不可少的缩放计算,但是我不确定如何,本书继续使用 XAML 使用 MatrixCamera.最初,我只想让基本计算工作,而不管它与矩阵相比效率有多低.

The block commented section contains scaling calculations that may be essential, however I am not sure how, and the book continues with the MatrixCamera using XAML. Initially I just want to get a basic calculation working regardless of how inefficient it may be compared to Matrices.

谁能建议需要添加或更改的内容?

Can anyone advise what needs to be added or changed?

推荐答案

由于 Windows 坐标是 z 进入屏幕(x cross y),我会使用类似

Since Windows coordinates are z into the screen (x cross y), I would use something like

screenY = viewPort.ActualHeight * (1 - screenY);

代替

screenY = screenY * viewPort.ActualHeight;

更正 screenY 以适应 Windows.

to correct screenY to accomodate Windows.

或者,您可以使用 OpenGL.当您设置视口 x/y/z 范围时,您可以将其保留为原生"单位,并让 OpenGL 转换为屏幕坐标.

Alternately, you could use OpenGL. When you set the viewport x/y/z range, you could leave it in "native" units, and let OpenGL convert to screen coordinates.

因为你的原点是中心.我会试试

Since your origin is the center. I would try

screenX = viewPort.ActualWidth * (screenX + 1.0) / 2.0
screenY = viewPort.ActualHeight * (1.0 - ((screenY + 1.0) / 2.0))

屏幕+1.0从[-1.0, 1.0]转换为[0.0, 2.0].此时,您除以 2.0 得到 [0.0, 1.0] 的乘法.为了解决从笛卡尔 y 翻转的 Windows y,您可以通过从 1.0 中减去前一个屏幕来将 [1.0, 0.0](左上到左下)转换为 [0.0, 1.0](从上到下).然后,您可以缩放到 ActualHeight.

The screen + 1.0 converts from [-1.0, 1.0] to [0.0, 2.0]. At which point, you divide by 2.0 to get [0.0, 1.0] for the multiply. To account for Windows y being flipped from Cartesian y, you convert from [1.0, 0.0] (upper left to lower left), to [0.0, 1.0] (upper to lower) by subtracting the previous screen from 1.0. Then, you can scale to the ActualHeight.

这篇关于将 3D 点投影到 2D 屏幕坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆