突出3D点到2D屏幕坐标 [英] Projecting a 3D point to a 2D screen coordinate
问题描述
根据在 3D编程的第7章的Windows(查尔斯Petzold的)的信息,我已经试图写入作为帮手功能投射一个三维点到一个标准的2D点是包含对应屏幕坐标(x,y)的
公共点Point3DToScreen2D(三维点三维点,Viewport3D视口)
{
双screenX = 0D,screenY = 0D;
//相机在XAML定义为:
//< Viewport3D.Camera>
//< PerspectiveCamera位置=0,0,800LookDirection =0,0,-1/>
//< /Viewport3D.Camera>
PerspectiveCamera凸轮= viewPort.Camera为PerspectiveCamera;
//使用相机位置翻译输入点
双inputX = point3D.X - cam.Position.X;
双inputY = point3D.Y - cam.Position.Y;
双inputZ = point3D.Z - cam.Position.Z;
双的aspectRatio = viewPort.ActualWidth / viewPort.ActualHeight;
//应用投影到X和Y
screenX = inputX /(-inputZ * Math.Tan(cam.FieldOfView / 2));
screenY =(inputY *的aspectRatio)/(-inputZ * Math.Tan(cam.FieldOfView / 2));
//转换为屏幕坐标
screenX = screenX * viewPort.ActualWidth;
screenY = screenY * viewPort.ActualHeight;
//另外,当前未使用,投影比例因子
/ *
双xScale等= 1 / Math.Tan(Math.PI * cam.FieldOfView / 360);
双yScale =的aspectRatio * xScale等;
双zFar = cam.FarPlaneDistance;
双zNear = cam.NearPlaneDistance;
双zScale = zFar == Double.PositiveInfinity? -1:zFar /(zNear - zFar);
双zOffset = zNear * zScale;
* /
返回新的点(screenX,screenY);
}
在测试但这个函数返回不正确的屏幕坐标(通过比较2D鼠标坐标检查对一个简单的3D形状)。由于我缺乏3D编程经验,我很困惑,为什么。
块评论部分包含缩放计算,可能是必要的,但我不知道怎么了,这本书继续与MatrixCamera使用XAML。起初我只是想获得一个基本的计算多么的低效它可以比作矩阵工作不管。
谁能告知什么需要添加或更改?
由于Windows坐标为Z到屏幕(x横Y),我会使用类似
screenY = viewPort.ActualHeight *(1 - screenY);
而不是
screenY = screenY * viewPort.ActualHeight;
要纠正screenY以适应Windows操作系统。
另外,您可以使用OpenGL。当您设置了视区X / Y / Z系列,你可以将它留在本机单位,让OpenGL的转换为屏幕坐标。
编辑: 由于您的起源是中心。我会尝试
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]的乘法。为了说明的WindowsŸ从笛卡尔Y是翻转,从[1.0,0.0](左上方左下)转换到[0.0,1.0](上降低)从1.0减去previous屏幕。然后,您可以扩展到的ActualHeight。
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);
}
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.
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?
Since Windows coordinates are z into the screen (x cross y), I would use something like
screenY = viewPort.ActualHeight * (1 - screenY);
instead of
screenY = screenY * viewPort.ActualHeight;
to correct screenY to accomodate Windows.
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.
Edit: 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))
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屋!