【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机

这篇具有很好参考价值的文章主要介绍了【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文只罗列公式,不做具体的推导。

OpenGL本身没有摄像机(Camera)的概念,但我们为了产品上的需求与编程上的方便,一般会抽象一个摄像机组件。摄像机类似于人眼,可以建立一个本地坐标系。相机的位置是坐标原点,摄像机的朝向Forward是摄像机看的方向,再给定向上的Up轴即可建立本地坐标系。然后,可以通过矩阵将世界坐标系的物体变换到摄像机坐标系中,这个矩阵称为视图矩阵。通过改变摄像机的本地坐标系,可以产生场景漫游的效果。
【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机,Overload游戏引擎细节分析,游戏引擎,矩阵,线性代数

1. 视图矩阵公式

视图矩阵是将物体坐标从世界空间坐标变换到相机本地坐标系中。计算视图矩阵需给定摄像机的位置 e y e \mathbf{eye} eye,焦点位置 t o \mathbf{to} to, Forward与Up所在平面的内的矢量 Y Y Y ,注意Y可以不与Forward垂直,我们可以通过叉乘获得摄像机的本地坐标系:
f w d = n o r m a l i z e ( e y e − t o ) r i g h t = n o r m a l i z e ( Y × f w d ) u p = n o r m a l i z e ( f w d × r i g h t ) \begin{aligned} & \mathbf{fwd} = normalize(\mathbf{eye}-\mathbf{to}) \\& \mathbf{right}=normalize(Y\times \mathbf{fwd}) \\& \mathbf{up} = normalize(\mathbf{fwd}\times\mathbf{right})\end{aligned} fwd=normalize(eyeto)right=normalize(Y×fwd)up=normalize(fwd×right)
【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机,Overload游戏引擎细节分析,游戏引擎,矩阵,线性代数
LookAt矩阵等于:

L o o k A t = [ s i d e x s i d e y s i d e z − s i d e ⋅ e y e u p x u p y u p z − u p ⋅ e y e f w d x f w d y f w d z − f w d ⋅ e y e 0 0 0 1 ] LookAt= \begin{bmatrix} \mathbf{side}_x & \mathbf{side}_y & \mathbf{side}_z & -\mathbf{side}\cdot \mathbf{eye}\\ \mathbf{up}_x & \mathbf{up}_y & \mathbf{up}_z & -\mathbf{up}\cdot \mathbf{eye}\\ \mathbf{fwd}_x & \mathbf{fwd}_y & \mathbf{fwd}_z & -\mathbf{fwd}\cdot \mathbf{eye}\\ 0& 0 & 0 & 1 \end{bmatrix} LookAt= sidexupxfwdx0sideyupyfwdy0sidezupzfwdz0sideeyeupeyefwdeye1

Overload中计算视图矩阵代码:

OvMaths::FMatrix4 OvMaths::FMatrix4::CreateView(const float p_eyeX, const float p_eyeY, const float p_eyeZ, const float p_lookX, const float p_lookY, const float p_lookZ, const float p_upX, const float p_upY, const float p_upZ)
{
	const OvMaths::FVector3 eye(p_eyeX, p_eyeY, p_eyeZ); // 摄像机位置
	const OvMaths::FVector3 look(p_lookX, p_lookY, p_lookZ); // 摄像机焦点
	const OvMaths::FVector3 up(p_upX, p_upY, p_upZ); // 摄像机up

	const OvMaths::FVector3 forward(eye - look); // 摄像机的Z轴
	FVector3::Normalize(forward);
	
	// cross得到right轴
	const OvMaths::FVector3 upXForward(OvMaths::FVector3::Cross(up, forward));
	FVector3::Normalize(upXForward);
	
	// cross得到Up轴,等价于Y轴
	const OvMaths::FVector3 v(OvMaths::FVector3::Cross(forward, upXForward));

	OvMaths::FMatrix4 View;

	View.data[0] = upXForward.x;
	View.data[1] = upXForward.y;
	View.data[2] = upXForward.z;
	View.data[3] = -OvMaths::FVector3::Dot(eye, upXForward);
	
	View.data[4] = v.x;
	View.data[5] = v.y;
	View.data[6] = v.z;
	View.data[7] = -OvMaths::FVector3::Dot(eye, v);

	View.data[8] = forward.x;
	View.data[9] = forward.y;
	View.data[10] = forward.z;
	View.data[11] = -OvMaths::FVector3::Dot(eye, forward);

	return View;
}

2. 投影矩阵

投影是将物体的光线投射到相机的近平面上,将3D物体变成2D图像,是将相机坐标空间转换到屏幕空间,类似于真实相机的曝光过程。投影有两种透视投影与正交投影。
透视投影:通过透视概念模仿我们看到的真实世界的方式,尝试让2D图像看起来像是3D的。物体近大远小,这样3D空间中有的平行线看起来就不再平行。
正投影:与透视投影相反,在视锥体中的物体不因其距离相机远近做任何调整,直接进行投影。正投影在CAD软件中使用广泛。

【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机,Overload游戏引擎细节分析,游戏引擎,矩阵,线性代数

透视投影矩阵:
[ 2 Z n e a r R − L 0 R + L R − L 0 0 2 Z n e a r T − B T + B T − B 0 0 0 − Z f a r + Z n e a r Z f a r − Z n e a r − 2 Z n e a r Z f a r Z f a r − Z n e a r 0 0 − 1 0 ] \begin{bmatrix} \frac{2Z_{near}}{R-L} & 0 & \frac{R+L}{R-L} & 0\\ 0 & \frac{2Z_{near}}{T-B} & \frac{T+B}{T-B} & 0\\ 0 & 0 & -\frac{Z_{far}+Z_{near}}{Z_{far}-Z_{near}} & -\frac{2Z_{near}Z_{far}}{Z_{far}-Z_{near}} \\ 0 & 0 & -1 & 0 \end{bmatrix} RL2Znear0000TB2Znear00RLR+LTBT+BZfarZnearZfar+Znear100ZfarZnear2ZnearZfar0
其中:
     Z n e a r 、 Z f a r 是相机位置到近平面、远平面的距离 Z_{near}、Z_{far}是相机位置到近平面、远平面的距离 ZnearZfar是相机位置到近平面、远平面的距离
     R、L–投影平面左右边界的X坐标
     T、B–投影平面上下边界的Y坐标

Overload中计算透视投影矩阵的代码:

OvMaths::FMatrix4 OvMaths::FMatrix4::CreateFrustum(const float p_left, const float p_right, const float p_bottom, const float p_top, const float p_zNear, const float p_zFar)
{
	const float maxView = 2.0f * p_zNear;
	const float width = p_right - p_left;
	const float height = p_top - p_bottom;
	const float zRange = p_zFar - p_zNear;

	FMatrix4 Frustum;

	Frustum.data[0] = maxView / width;
	Frustum.data[5] = maxView / height;
	Frustum.data[2] = (p_right + p_left) / width;
	Frustum.data[6] = (p_top + p_bottom) / height;
	Frustum.data[10] = (-p_zFar - p_zNear) / zRange;
	Frustum.data[14] = -1.0f;
	Frustum.data[11] = (-maxView * p_zFar) / zRange;
	Frustum.data[15] = 0.0f;

	return Frustum;
}

正投影矩阵:
[ 2 R − L 0 0 − R + L R − L 0 2 T − B 0 − T + B T − B 0 0 − 2 Z f a r − Z n e a r − Z f a r + Z n e a r Z f a r − Z n e a r 0 0 0 1 ] \begin{bmatrix} \frac{2}{R-L} & 0 & 0 & -\frac{R+L}{R-L} \\ 0 & \frac{2}{T-B} & 0 & -\frac{T+B}{T-B} \\ 0 & 0 & \frac{-2}{Z_{far}-Z_{near}} & -\frac{Z_{far} + Z_{near}}{Z_{far}-Z_{near}} \\ 0 & 0 & 0 & 1 \end{bmatrix} RL20000TB20000ZfarZnear20RLR+LTBT+BZfarZnearZfar+Znear1

Overload中计算正投影矩阵的代码:

OvMaths::FMatrix4 OvMaths::FMatrix4::CreateOrthographic(const float p_size, const float p_aspectRatio, const float p_zNear, const float p_zFar)
{
    auto ortho = OvMaths::FMatrix4::Identity;

    const auto right = p_size * p_aspectRatio;
    const auto left = -right;

    const auto top = p_size;
    const auto bottom = -top;

    ortho(0, 0) = 2.0f / (right - left);
    ortho(1, 1) = 2.0f / (top - bottom);
    ortho(2, 2) = -2.0f / (p_zFar - p_zNear);
    ortho(0, 3) = -(right + left) / (right - left);
    ortho(1, 3) = -(top + bottom) / (top - bottom);
    ortho(2, 3) = -(p_zFar + p_zNear) / (p_zFar - p_zNear);
    ortho(3, 3) = 1.0f;

    return ortho;
}

3. 摄像机封装

Overload中摄像机类比较简单,主要是对上面两个矩阵计算的封装。每次就是的时候需传入摄像机的位置及转动四元数,计算完视图投影矩阵后保存到自己的字段中。代码比较简单,不再分析了。文章来源地址https://www.toymoban.com/news/detail-723473.html

到了这里,关于【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Overload游戏引擎细节分析】PBR材质Shader---完结篇

    PBR基于物理的渲染可以实现更加真实的效果,其Shader值得分析一下。但PBR需要较多的基础知识,不适合不会OpenGL的朋友。 一、PBR理论 PBR指基于物理的渲染,其理论较多,需要的基础知识也较多,我在这就不再写一遍了,具体可以参看: LearnOpenGL PBR理论-英文 或者 LearnOpenGL

    2024年02月08日
    浏览(44)
  • 【Overload游戏引擎细节分析】UBO与SSBO的封装

    一、OpenGL的UBO   在OpenGL Shader中,如果逻辑比较复杂,使用的uniform变量较多。通常多个着色器使用同一个uniform变量。由于uniform变量的位置是着色器链接时候产生的,因此它在应用程序中获得的索引会有变化。Uniform Buffer Object(UBO)是一种优化uniform变量访问,不同着色器直接

    2024年02月07日
    浏览(37)
  • 【Overload游戏引擎细节分析】编辑器对象鼠标拾取原理

          Overload的场景视图区有拾取鼠标功能,单击拾取物体后会显示在Inspector面板中。本文来分析鼠标拾取这个功能背后的原理。 一、OpenGL的FrameBuffer 实现鼠标拾取常用的方式有两种:渲染id到纹理、光线投射求交。Overload使用的是渲染id到纹理,其实现需借助OpenGL的帧缓冲

    2024年02月04日
    浏览(50)
  • 【计算机图形学】三维图形投影和消隐(三视图构造)

    模块4-1 三维图形投影和消隐 一 实验目的 编写三维图形各种变换的投影算法 二 实验内容 1 :自行选择三维物体(不能选长方体),建立坐标系,给定点的三维坐标值,建立边表结构。完成三视图。 实验结果如下图所示: 左上显示为主视图,右上显示为侧视图,右下显示为

    2024年02月01日
    浏览(92)
  • 相机投影矩阵的计算

    摄像机标定(Camera calibration)中存在的一个关键问题:如何求解投影矩阵有了投影矩阵,我们便可以把世界坐标系变化到图像坐标系。 一、最小二乘法 已知条件 n个三维世界坐标点(保存在dat文件中) n个二维图像坐标点(保存在dat文件中) 使用工具: 环境:windows10+python3.7+pycharm2

    2023年04月23日
    浏览(33)
  • 计算相机投影矩阵(含代码)(Python)

    前几天处理点云时,需要使用到像片与3D点云的对应关系。在这边找了一圈没有发现直接可用的代码,于是去GitHub试了一下,以下是一个提炼后的矩阵计算代码。 下面展示 矩阵计算代码 。 代码源于 链接: AdityaNair111 最后感谢piong233的热心帮助

    2024年02月15日
    浏览(45)
  • GAMES101投影矩阵推导详解和分析

    之前推导过OpenGL的投影矩阵,学了GAMES101之后,发现老师的推导方式很有意思,且GAMES101的坐标系约定和OpenGL不一样。最近在填新坑URasterizer的过程中,发现了一些问题,比如透视投影在clip space做裁剪时为啥w必须取反,以及之前GAMES101作业中做深度测试时为啥z值要取反的问题

    2024年02月08日
    浏览(45)
  • 齐次裁剪矩阵(投影矩阵)ProjectionMatrix参数分析以及NDC坐标原理解释

    齐次裁剪矩阵(投影矩阵)ProjectionMatrix参数分析以及NDC坐标原理解释 在观察空间中,我们可以通过近平面(near plane)n,和远平面(far plane)f,垂直视场角 a 以及纵横比 r 这4个参数来表述一个以原点作为中心的视锥体。横纵比公式: r = width/height(宽除以高); 出于理解,我

    2024年03月16日
    浏览(57)
  • 图形学-(视图变换,投影变换)

    在 3 维物体变到二维平面的过程中,我们需要规定好相机的位置。对于相机所做的变换就是 视图变换 (Viewing/Camera transformation)。 我们需要对相机位置进行定义,对于一个相机我们要规定下面三个属性: 相机位置(视点)(Position) 相机拍摄方向(视线)(Look-at/Gaze direction) 相机

    2024年02月11日
    浏览(39)
  • Games101笔记-模型、视图、投影

    在旋转点,旋转矩阵的逆等于矩阵的转置 左边3*3是线性变换,右边一列是仿射变换(平移) 先线性再平移 x叉乘y得到z,y叉乘z得到x, xyz给任何两个可以得到另一个 (循环对称) z叉乘x得到y,所以y是反的 任意绕3d轴旋转可以分解为绕x,y,z轴旋转。三个角为欧拉角 罗德里格斯旋

    2024年03月19日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包