A First-Person Camera
A First-Person Camera
现在开始扩展Camera基类,实现一个第一人称的camera,这种类型的camera可以通过鼠标和键盘进行控制。通过W和S键可以沿着direction向量分别向前和向后移动camera。按键A和D沿着right向量“扫射”(水平移动camera)。使用鼠标控制camera的俯仰和偏航移动:垂直移动鼠标执行camera的俯仰操作,水平移动鼠标执行camera的偏航操作。其中,俯仰是指绕着camera的right向量进行旋转,而偏航则绕着坐标轴的y轴旋转。这是第一人称camera的惯例方式,但是这种camera并不能用于所有的情况,比如,某个游戏中需要camera能在空间中沿着z轴滚动(纵向旋转)。
列表13.3列出了FirstPersonCamera类的头文件。
列表13.3 The FirstPersonCamera.h Header File
#pragma once#include "Camera.h"namespace Library
{class Keyboard;class Mouse;class FirstPersonCamera : public Camera{RTTI_DECLARATIONS(FirstPersonCamera, Camera)public:FirstPersonCamera(Game& game);FirstPersonCamera(Game& game, float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance);virtual ~FirstPersonCamera();const Keyboard& GetKeyboard() const;void SetKeyboard(Keyboard& keyboard);const Mouse& GetMouse() const;void SetMouse(Mouse& mouse);float& MouseSensitivity();float& RotationRate();float& MovementRate(); virtual void Initialize() override;virtual void Update(const GameTime& gameTime) override;static const float DefaultMouseSensitivity;static const float DefaultRotationRate;static const float DefaultMovementRate; protected:float mMouseSensitivity;float mRotationRate;float mMovementRate; Keyboard* mKeyboard;Mouse* mMouse;private:FirstPersonCamera(const FirstPersonCamera& rhs);FirstPersonCamera& operator=(const FirstPersonCamera& rhs);};
}
FirstPersonCamera类中包含了表示鼠标和键盘的成员变量,并提供了访问和修改这些变量的公有成员函数。但是在FirstPersonCamera的Initialize()函数中,试图通过查询service container获取鼠标和键盘。用于修改鼠标和键盘变量的成员函数只是简单地重写这些设置,甚至通过指定NULL值禁用鼠标和键盘控制。
还包含了用于表示camera移动和旋转的速率,以及对鼠标控制的响应敏感度。变量“rate”表示在1秒内camera移动或旋转的单位长度。鼠标敏感度支持增强或抑制对鼠标输入的响应。
列表13.4列出FirstPersonCamera实现中最值得关注的部分代码。本书的配套网站上提供了完成的实现代码。
列表13.4 The FirstPersonCamera Class Implementation (Abbreviated)
#include "FirstPersonCamera.h"
#include "Game.h"
#include "GameTime.h"
#include "Keyboard.h"
#include "Mouse.h"
#include "VectorHelper.h"namespace Library
{RTTI_DEFINITIONS(FirstPersonCamera)const float FirstPersonCamera::DefaultRotationRate = XMConvertToRadians(1.0f);const float FirstPersonCamera::DefaultMovementRate = 10.0f;const float FirstPersonCamera::DefaultMouseSensitivity = 100.0f;FirstPersonCamera::FirstPersonCamera(Game& game): Camera(game), mKeyboard(nullptr), mMouse(nullptr), mMouseSensitivity(DefaultMouseSensitivity), mRotationRate(DefaultRotationRate), mMovementRate(DefaultMovementRate){}FirstPersonCamera::FirstPersonCamera(Game& game, float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance): Camera(game, fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance), mKeyboard(nullptr), mMouse(nullptr),mMouseSensitivity(DefaultMouseSensitivity), mRotationRate(DefaultRotationRate), mMovementRate(DefaultMovementRate){}FirstPersonCamera::~FirstPersonCamera(){mKeyboard = nullptr;mMouse = nullptr;}void FirstPersonCamera::Initialize(){mKeyboard = (Keyboard*)mGame->Services().GetService(Keyboard::TypeIdClass());mMouse = (Mouse*)mGame->Services().GetService(Mouse::TypeIdClass());Camera::Initialize();}void FirstPersonCamera::Update(const GameTime& gameTime){XMFLOAT2 movementAmount = Vector2Helper::Zero;if (mKeyboard != nullptr){if (mKeyboard->IsKeyDown(DIK_W)){movementAmount.y = 1.0f;}if (mKeyboard->IsKeyDown(DIK_S)){movementAmount.y = -1.0f;}if (mKeyboard->IsKeyDown(DIK_A)){movementAmount.x = -1.0f;}if (mKeyboard->IsKeyDown(DIK_D)){movementAmount.x = 1.0f;}}XMFLOAT2 rotationAmount = Vector2Helper::Zero;if ((mMouse != nullptr) && (mMouse->IsButtonHeldDown(MouseButtonsLeft))){LPDIMOUSESTATE mouseState = mMouse->CurrentState(); rotationAmount.x = -mouseState->lX * mMouseSensitivity;rotationAmount.y = -mouseState->lY * mMouseSensitivity;}float elapsedTime = (float)gameTime.ElapsedGameTime();XMVECTOR rotationVector = XMLoadFloat2(&rotationAmount) * mRotationRate * elapsedTime;XMVECTOR right = XMLoadFloat3(&mRight);XMMATRIX pitchMatrix = XMMatrixRotationAxis(right, XMVectorGetY(rotationVector));XMMATRIX yawMatrix = XMMatrixRotationY(XMVectorGetX(rotationVector));ApplyRotation(XMMatrixMultiply(pitchMatrix, yawMatrix));XMVECTOR position = XMLoadFloat3(&mPosition);XMVECTOR movement = XMLoadFloat2(&movementAmount) * mMovementRate * elapsedTime;XMVECTOR strafe = right * XMVectorGetX(movement);position += strafe;XMVECTOR forward = XMLoadFloat3(&mDirection) * XMVectorGetY(movement);position += forward;XMStoreFloat3(&mPosition, position);Camera::Update(gameTime);}
}
在列表13.4中,首先设置了rotation rate,movement rate,以及mouse sensitivity的默认值。其中使用了DiretXMath库的XMConvertToRadians()函数,用于把degress转换成radians。而XMConvertToDegrees()函数则radians转换成degrees。
在Initialize()函数中演示了从service container中获取mouse和keyboard services的方法。需要注意的是这两个services很可能不存在,在这种情况下返回值为NULL,意味着在该component中不需要键盘的鼠标的功能。否则你应该assert在service container中一定存在这些对象。
Update()函数中包含了FirstPersonCamera类实现代码中的主要部分。首先检查W,S,A和D按键是否按下;如果按下了,就保存值1或-1,用于表示移动的方向。键盘是是一种数字形式的,按键要么按下要么没有按下,因此无法表示一个变量,比如游戏手柄上的模拟触发器或者摇杆。因此,成员变量mMovementRate用于定义camera运动的幅度(尽管理论上可以根据按键被按下的时间缩放幅度值)。
接下来,从鼠标移动(如果鼠标左键被按住不放)过程中获取旋转量。这些数量由成员变量mRotationRate与每一帧的elapsed time相乘得到。在执行乘法运算之前,需要把rotationAmount变量加载到一个XMVECTOR对象中,以便利用SIMD运算的优势。使用elapsed time变量是为了与计算帧率相互独立。
有了旋转数量值之后,就可以构建用于camera的偏航和俯仰旋转矩阵。俯仰矩阵通过调用XMMatrixRotationAxis()函数进行创建,该函数可以构建一个绕任意轴旋转的矩阵。对于俯仰矩阵,是绕着camera的right向量旋转。XMMatrixRotationAxis()函数中使用了XMVectorGetY()函数的返回值作为第二个参数。调用XMVectorGetY()函数可以从一个无法访问内部成员的XMVECTOR对象中获取Y分量值。偏航矩阵则通过调用XMMatrixRotationY()函数进行创建,该函数创建了一个绕y轴旋转的矩阵。在DirectXMath库中还有类似的矩阵用于创建围绕x轴和z轴旋转的矩阵。偏航和俯仰矩阵在传送给Camera::ApplyRotation()函数之前,需要先通过乘法运算进行串联。
接下来,使用成员变量mMovementRate和elapsed time对movementAmount进行乘法运算,并把结果存储到一个XMVECTOR类型的movement向量中。然后把camera的right向量与movement向量的X分量进行乘法运算,得到strafe向量。再把该向量值加到camera的position中。对于forward movement,执行同样的操作过程,把最终的position再写回到成员变量Camera::mPosition中。
总结
本章首先创建了一个基类component用于支持一个虚拟camere的通用部分。然后扩展基类创建了一个支持使用鼠标和键盘控制的第一人称camera。在这个过程中,练习了上一章所讨论的component和services模块,并温习了一些3D camera原理和DirectXMath的使用方法。
到目前为止,所有的工作都已经准备就绪。在下一章,就可以正式开始在屏幕上渲染3D场景了。
Exercises
1. Create an orbit camera similar to the one found in NVIDIA FX Composer. Note: Visualizing
the output of your camera will be difficult without any 3D rendering (which the next chapter
covers). You can use the SpriteBatch/SpriteFont system to output your camera’s data or
employ the Grid component on the companion website. This component renders a
customizable reference grid at the world origin.
1.创建一个与NVIDIA FX Composer中类似的orbit camera。注意:在没有任何3D渲染(下一章才会讲到)的情况要显示camera的输出是很困难的。可以使用SpriteBatch/SpriteFont系统输出camera的相关数据,或者使用本书配套网站上提供的Grid component。这个component可以在渲染一个自定义的参考网格。
本章配套学习代码
http://download.csdn.net/detail/chenjinxian_3d/9584778
首先在FirstPersonCamera的基础上,增加了一个OrbitCamera,并添加了一个Grid组件用于演示各种Camera的操作结果。
A First-Person Camera相关推荐
- Camera ISP技术
Camera ISP技术 ISP图像信号处理 • 1,ISP图像信号处理介绍 • 2,ISP的目的是什么? • 3, ISP的处理流程以及算法 o 3.1镜头的几何变形 o 3.2 镜头渐晕 o 3. ...
- Camera系列规格参数
Camera系列规格参数 FH8858V200: 新一代8M高性能网络摄像机 SoC FH8858V200是新一代面向8M专业型网络摄像机应用的高性能H.265/H.264/JPEG SoC芯片.芯片 ...
- IP SOC与Camera ISP
IP SOC与Camera ISP FH8858V200: 新一代8M高性能网络摄像机 SoC FH8858V200是新一代面向8M专业型网络摄像机应用的高性能H.265/H.264/JPEG SoC ...
- 手机与Camera CCM技术发展趋势
手机与Camera CCM技术发展趋势 CCM是CMOS Camera Module 互补金属氧化物半导体摄像模组的英文缩写,用于各种新一代便携式摄像设备的核心器件,与传统摄像系统相比具有小型化,低功 ...
- camera数字降噪(DNR)
camera数字降噪(DNR) 闭路电视摄像机 无论多么出色和弱光,在黑暗中拍摄视频监控录像时都会不可避免地产生一些噪音.噪声是任何电子通信中不可避免的部分,无论是视频还是音频.本质上是静态的–视频信 ...
- Camera噪声问题
Camera噪声问题 Camera RGB 域的噪声 以上部分属于sensor processing,接下来的部分属于color.luminance processing. gamma gamma是在 ...
- camera中LENS和SENSOR的CRA是如何搭配的?
camera中LENS和SENSOR的CRA是如何搭配的? camera中,lens和sensor的搭配是非常关键的问题.但这两者是如何搭配的呢? 一般在Sensor data sheet中会附有全视 ...
- Camera Lens Coating
Camera Lens Coating Coating Progress 转换镜头,根据要求进行OEM和设计. 光学元件:望远镜.显微镜.相机和数码相机镜头.放大镜头和远摄镜头.定心镜头.投影镜头.投 ...
- 摄像头标定GML Camera Calibration
摄像头标定GML Camera Calibration GML Camera Calibration官方版是一款十分优秀出色的相机标定软件,GML Camera Calibration官方版界面友好, ...
- Camera Calibration 相机标定
Camera Calibration 相机标定 一.相机标定方法 在opencv中提供了一组函数用于实现相机的标定,标定返回的值包括:相机内参矩阵(fx fy xc yc).相机外参矩阵(R t)以及 ...
最新文章
- eventsource 服务器发送事件
- Java多线程闲聊(三):RxJava
- seaborn 教程_使用Seaborn进行数据可视化教程
- 深入理解Java虚拟机(第三版)-13.Java内存模型与线程
- java jsp公共异常页面_Java如何创建JSP错误页面以处理异常?
- Github开源之旅启程:GitHub 上部署网页
- HDU5855 Less Time, More profit(最大权闭合图)
- 刘元普双生贵子(但行好事,莫问前程)
- 【渝粤题库】国家开放大学2021春2721乡镇行政管理题目
- html中不显示竖线边框代码,DIV用CSS定义边框为实线,但为什么预览的时候不显示。...
- Jie Business Project
- 微信订阅号申请与使用
- endcap和welltap_ICC布局规划
- 安卓日志:拍照、文件读取的问题
- 分布式ID之snowflake
- 水生植物的Java莫斯
- 09-微服务版的单点登陆系统设计及实现(2105~2106)
- 安卓项目各文件夹的含义和用处
- LVS三种工作方式八种算法
- PointNet论文解读和代码解析
热门文章
- PHP打印九九乘法表(让输出内容能够完全对齐)
- python 计算标准差和平均值
- 轨道运营管理专业自荐书_单招面试自我介绍,我报的是:城市轨道交通运营管理,谁可以给我一篇自我介绍的范文啊?谢谢!...
- swaggerconfig.java下载_Spring Boot:整合Swagger文档
- Unity3d关于Particle System is trying to spawn on a mesh with zero surface area的警告
- 全国最全乡镇边界面矢量、中国最全乡镇、街道级行政区划边界矢量数据-shp面数据-wgs84坐标数据分享
- 这 14 个短代码,蕴含着丰富的 Python 编程思维
- GPS定位平台软件,GPS/UWB/WIFI融合定位,提供开发接口
- 关于layui不支持IE兼容模式导出问题
- python网络爬虫笔记05:request进阶