当前位置: 首页 > 编程语言 > C#

Projecting3DPointsto2DScreenCoordinatesSharing

时间:2023-04-10 23:14:43 C#

Projecting3DPointsto2DScreenCoordinates根据3DProgrammingforWindows(CharlesPetzold)第7章的信息,我正在尝试编写一个辅助函数,它将投影Point3D到包含相应屏幕坐标(x,y)的标准2D点:publicPointPoint3DToScreen2D(Point3Dpoint3D,Viewport3DviewPort){doublescreenX=0d,screenY=0d;//相机在XAML中定义为://////PerspectiveCameracam=viewPort.CameraasPerspectiveCamera;//使用相机位置平移输入点doubleinputX=point3D.X-cam.Position.X;双输入Y=point3D.Y-cam.Position.Y;双输入Z=point3D.Z-cam.Position.Z;双纵横比=viewPort.ActualWidth/viewPort.ActualHeight;//将投影应用于X和YscreenX=inputX/(-inputZ*Math.Tan(cam.FieldOfView/2));screenY=(inputY*aspectRatio)/(-inputZ*Math.Tan(cam.FieldOfView/2));//转换为屏幕坐标screenX=screenX*viewPort.ActualWidth;screenY=screenY*viewPort.ActualHeight;//额外的,当前未使用的投影比例因子/*doublexScale=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;*/returnnewPoint(screenX,screenY);然而,在测试时,此函数返回不正确的屏幕坐标(通过将2D鼠标坐标与简单的3D形状进行比较来检查)由于我缺乏3D编程经验,我很困惑为什么。块注释部分包含可能必不可少的缩放计算,但我不确定如何计算,并且本书继续使用XAML的MatrixCamera。最初我只是希望能够进行基本计算,无论它与矩阵相比有多高效。谁能建议需要添加或更改的内容?由于窗口坐标是z进入屏幕(x穿过y),我会使用类似screenY=viewPort.ActualHeight*(1-screenY);而不是screenY=screenY*viewPort.ActualHeight;更正screenY以适应窗口。或者,您可以使用OpenGL。设置视口x/y/z范围时,您可以将它们保留为“本机”单位,让OpenGL转换为屏幕坐标。编辑:因为你的起源是居中的。我会尝试screenX=viewPort.ActualWidth*(screenX+1.0)/2.0screenY=viewPort.ActualHeight*(1.0-((screenY+1.0)/2.0))screen+1.0从[-1.0,1.0]转换为[0.0,2.0]。此时,除以2.0得到[0.0,1.0]用于乘法。为了考虑从笛卡尔y翻转的窗口y,通过从1.0减去前一个屏幕,将[1.0,0.0](左上角到左下角)转换为[0.0,1.0](大到小)。然后您可以缩放到ActualHeight。我已经使用3DUtilsCodeplex源库创建并成功测试了一种工作方法。真正的工作是在3DUtils的TryWorldToViewportTransform()方法中执行的。没有它,此方法将不起作用(请参阅上面的链接)。在EricSink的文章:Autoscaling中也找到了非常有用的信息。注意。可能有更可靠/有效的方法,如果有,请将它们添加为答案。与此同时,它足以满足我的需求。//////获取一个3D点并返回视口内相应的2D点(X,Y)。///需要http://www.codeplex.com/Wiki/View.aspx提供的3DUtils项目?ProjectName=3DTools//////3D空间中的一个点///Viewport3D的一个实例///对应的2D点,如果无法计算publicPoint?Point3DToScreen2D(Point3Dpoint3D,Viewport3DviewPort){boolbOK=false;//我们需要一个Viewport3DVisual,但我们只有一个Viewport3D。Viewport3DVisualvpv=VisualTreeHelper.GetParent(viewPort.Children[0])asViewport3DVisual;//获取世界到视口的变换矩阵Matrix3Dm=MathUtils.TryWorldToViewportTransform(vpv,outbOK);if(bOK){//将3D点转换为2DPoint3DtransformedPoint=m.Transform(point3D);Pointscreen2DPoint=newPoint(transformedPoint.X,transformedPoint.Y);返回新的Nullable(screen2DPoint);}else{返回空值;这并没有解决有问题的算法,但它可能对遇到这个问题很有用(就像我所做的那样)。在.NET3.5中,您可以使用Visual3D.TransformToAncestor(视觉祖先)。我用它在我的3D视口上的画布上绘制线框:voidCompositionTarget_Rendering(objectsender,EventArgse){}voidUpdateWireframe(){GeometryModel3Dmodel=cube.ContentasGeometryModel3D;canvas.Children.Clear();如果(模型!=null){GeneralTransform3DTo2Dtransform=cube.TransformToAncestor(viewport);MeshGeometry3Dgeometry=model.GeometryasMeshGeometry3D;for(inti=0;i这也考虑了模型上的任何转换等。否则请参阅:http://blogs.msdn.com/wpf3d/archive/2009/05/13/transforming-bounds.aspx这是不清楚你想用aspectRatiocoeff实现什么。如果点在视野的边缘,那么它应该在屏幕的边缘,但如果aspectRatio!=1则不会。尝试设置aspectRatio=1并使窗口平方.坐标还不对吗?ActualWidth和ActualHeight好像真的是窗口大小的一半,所以screenX应该是[-ActualWidth;ActualWidth],而不是[0;ActualWidth。是你想要的吗?screenX和screenY应该是相对于屏幕中心计算...我没有看到使用WindowsAPI绘图时原点位于屏幕左上角的事实。我假设你的坐标系是y||+------x此外,根据Scott的问题,您的坐标系是在中心还是左下角?但是,Windows屏幕API是+--------x|||y并且您需要将坐标从经典笛卡尔坐标转换为Windows。以上就是C#学习教程的全部内容:投影3D点到2D屏幕坐标分享。如果对你有用,需要了解更多C#学习教程,希望大家多加关注---本文收集自网络,不代表立场,如涉及侵权,请右击联系管理员删除。如需转载请注明出处: