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

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

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

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)
在这里插入图片描述
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 x f w d x − 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}_x & \mathbf{fwd}_x & -\mathbf{fwd}\cdot \mathbf{eye}\\ 0& 0 & 0 & 1 \end{bmatrix} LookAt= sidexupxfwdx0sideyupyfwdx0sidezupzfwdx0sideeyeupeyefwdeye1

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); // 摄像机upconst 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软件中使用广泛。

在这里插入图片描述

透视投影矩阵:
[ 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 1 Z f a r − Z n e 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{1}{Z_{far}-Z_{near}} & -\frac{Z_{near}}{Z_{far}-Z_{near}} \\ 0 & 0 & 0 & 1 \end{bmatrix} RL20000TB20000ZfarZnear10RLR+LTBT+BZfarZnearZnear1

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中摄像机类比较简单,主要是对上面两个矩阵计算的封装。每次就是的时候需传入摄像机的位置及转动四元数,计算完视图投影矩阵后保存到自己的字段中。代码比较简单,不再分析了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/139620.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2020年下半年~2022下半年下午题易错总结

2020年下半年 试题一: 1.组播报文对无线网络空口的影响主要有(14) ,随着业务数据转发的方式不同, 组播报文的抑制分别在 (15)、(16) 配置。 答案: (14)无线空口拥塞 (15)直连AP的交换…

瑞芯微RK3568核心板在边缘服务器产品中的应用-迅为电子

迅为RK3568核心板在边缘服务器产品中可以发挥关键作用,为边缘计算应用提供高性能的计算和多媒体处理能力。边缘服务器通常用于处理和存储数据,执行本地计算任务,并支持与远程云服务的通信。以下是RK3568核心板在边缘服务器产品中的应用方案&a…

项目中 .env.development 与 .env.production 的区别

文章目录 一、项目中使用此两个文件的意义二、使用方式 一、项目中使用此两个文件的意义 我们在开发项目时,经常会有开发环境与生产环境,分别会对应不同的请求地址与各种不同的变量,这个时候我们就可以使用 process.env 去抓取这两个文件写的…

VS使用Visual Assist添加代码说明信息

写代码时,我们一般需要在代码的最前面添加一些说明信息,作者的联系方式等等。一些高级的 IDE 工具提供修改代码模板的功能,这样就能够在创建新代码时自动加上版权信息。Visual Studio 虽然没有提供这样的操作界面,但是我们可以通过…

Linux上如何部署SpringBoot项目——手把手教会你

目录 前言 1、准备操作 1.1、Linux上安装jdk 1.2、准备MySQL数据库 1.3、打开云服务器的防火墙 1.4、准备jar包 2、部署 前言 下面是教你部署SpringBoot项目,jar包形式的,不是war包!!! 1、准备操作 1.1、Linux…

echarts的markline警标线(一条/多条)的使用

echarts之markLine(可以设置特定阈值线(警戒线)) 一条线写法 series: [{name: Fake Data,type: line,showSymbol: false,data: data,markLine: {symbol: [none, none], // 去掉箭头label: {show: false,position: start,formatter: {b}},data: [{name: 阈值,yAxis: 200}],line…

ruoyi识别访问设备是pc端还是移动端跳转到对应的登录页面

背景需求 ruoyi框架,前后端分离。现在要在用户访问的时候根据不同的设备跳转到不同的登录页面。 教程 router/index.js 修改src/router/index.js,在这里增加自己的要跳转的页面 permission.js 在白名单中添加自己的登录页面 增加以下识别的代码 le…

一氧化碳单位换算 以及环保最低排放

换算单位: 1.0 % 10000 mg/m3 1.0 mg/m3 0.870 ppm 举例:CO表测数据 1.0 %,则10000 mg/m3,则10000*22.4/28 8700 ppm 参考:钢铁工业大气污染物超低排放标准 DB13

半导体测试方法主要有哪几种?

外观检测:对半导体外观质量的评估,包括检查芯片的平整度、颜色、镜面度等。 电性能测试:测量半导体的电导率、电阻率、电流和电压特性等,以评估其电性能。 温度测试:用于测量半导体在不同温度下的电性能表现&#xf…

Nginx基础学习

1. 引言 项目刚上线时,用户使用少,并发量小,在这种情况下,在这种情况下,一个jar包部署到一台服务器上启动就满足需求了。 随着,平台使用的用户量增多,并发量也慢慢增大,这种情况下一…

关于W5500网卡使用过程的部分问题记录

某个项目中用到了W5500这种自带网络协议栈的网卡芯片,由于该项目开发时间很紧,就临时网上买了一些模块拼凑到了一套系统,经过验证果真这种拼积木的方法只能用在学生实验开发中,真不能拿来做工程应用,硬件太不稳定很容易…

【力扣1528】重新排列字符串

👑专栏内容:力扣刷题⛪个人主页:子夜的星的主页💕座右铭:前路未远,步履不停 目录 一、题目描述二、题目分析1、Java代码2、C代码 一、题目描述 给你一个字符串 s 和一个长度相同的整数数组 indices。 请你…