图形学基础:屏幕坐标转世界坐标

三维图形学体系中,有两种类型的投影。透视投影(Perspective projection)和正交投影(Orthographic projection)。
在这里插入图片描述
对于透视投影(Perspective projection),有两个矩阵:透视变换矩阵和相机到世界坐标系变换。透视变换矩阵参考:https://zhuanlan.zhihu.com/p/463027517
在这里插入图片描述
在这里插入图片描述
相机到世界坐标系变换由相机的位置、朝向、向上的方向计算而来:

  gp_Dir        myUp;       //!< Camera up direction vector
  gp_Dir        myDirection;//!< Camera view direction (from eye)
  gp_Pnt        myEye;      //!< Camera eye position

OCCT 中的相机世界坐标系矩阵计算:

template <typename Elem_t>
void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
                                        const NCollection_Vec3<Elem_t>& theFwdDir,
                                        const NCollection_Vec3<Elem_t>& theUpDir,
                                        const NCollection_Vec3<Elem_t>& theAxialScale,
                                        NCollection_Mat4<Elem_t>& theOutMx)
{
  NCollection_Vec3<Elem_t> aForward = theFwdDir;
  aForward.Normalize();

  // side = forward x up
  NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
  aSide.Normalize();

  // recompute up as: up = side x forward
  NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);

  NCollection_Mat4<Elem_t> aLookMx;
  aLookMx.SetRow (0, aSide);
  aLookMx.SetRow (1, anUp);
  aLookMx.SetRow (2, -aForward);

  theOutMx.InitIdentity();
  theOutMx.Multiply (aLookMx);
  theOutMx.Translate (-theEye);

  NCollection_Mat4<Elem_t> anAxialScaleMx;
  anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
  anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
  anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();

  theOutMx.Multiply (anAxialScaleMx);
}

也可参考:相机变换矩阵

由此,对于三维点World3dPoint到屏幕点Screen2dPoint的计算:
Screen2dPoint = 透视变换矩阵 X 相机到世界坐标系变换 X World3dPoint;
然而需要注意的是,屏幕上一个点到三维中实际是一条线,而非一个点。
正交投影想对透视投影更简单一些。

如果想要调试弄清楚原理,可以参考 OCCT 例子源码:

// OpenCASCADE-7.6.0-vc14-64\opencascade-7.6.0\samples\mfc\standard\04_Viewer3d\src\Viewer3dView.cpp
gp_Pnt ConvertClickToPoint(Standard_Real x, Standard_Real y, Handle(V3d_View) aView)
{
	Standard_Real XEye,YEye,ZEye,XAt,YAt,ZAt;
	aView->Eye(XEye,YEye,ZEye);
	aView->At(XAt,YAt,ZAt);
	gp_Pnt EyePoint(XEye,YEye,ZEye);
	gp_Pnt AtPoint(XAt,YAt,ZAt);

	gp_Vec EyeVector(EyePoint,AtPoint);
	gp_Dir EyeDir(EyeVector);

	gp_Pln PlaneOfTheView = gp_Pln(AtPoint,EyeDir);
	Standard_Real X,Y,Z;
	aView->Convert(int(x),int(y),X,Y,Z);
	gp_Pnt ConvertedPoint(X,Y,Z);
	gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project(PlaneOfTheView,ConvertedPoint);
	
	gp_Pnt ResultPoint = ElSLib::Value(ConvertedPointOnPlane.X(),
									ConvertedPointOnPlane.Y(),
									PlaneOfTheView);
	return ResultPoint;
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客BIM工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值