Dx11矩阵变换
物理模拟需要物体在一个虚拟的“物理世界”中记录位置,大小,方向,速度等等物理量并进行模拟,如何将“物理世界”中物体借助dx11渲染到屏幕中呢。这里不得不提dx11的矩阵变换。
世界矩阵
这里抛开繁杂的数学推导,网上有很多很好的文章,简单学过线性代数都能看懂。
注意,定义物体在“物理世界”中的位置,采用的是矩阵变换,也就是并不是直接定义物体的位置,而是定义物体“局部坐标系”的位置。即每个物体有一个属于自己的坐标系,也防止了单一物体旋转缩放影响其他物体的问题。
另外,矩阵的变换顺序也很重要,遵循缩放->旋转->平移,具体原理参考:为什么坐标变换的顺序必须是: 缩放->旋转->平移
// 世界矩阵
DirectX::XMMATRIX size = DirectX::XMMatrixScaling(this->m_data->size.x, this->m_data->size.y, this->m_data->size.z);
DirectX::XMMATRIX rotation = DirectX::XMMatrixRotationRollPitchYaw(this->m_data->rotation.x, this->m_data->rotation.y, this->m_data->rotation.z);
DirectX::XMMATRIX pos = DirectX::XMMatrixTranslation(this->m_data->pos.x, this->m_data->pos.y, this->m_data->pos.z);
DirectX::XMMATRIX word = size * rotation * pos;
现在,我们定义出了物体在“物理世界”中的位置,如何将这个物体显示到屏幕中呢。
视图矩阵与投影矩阵
我们可以把渲染类比为拍照。在拍照时,首先需要被拍照的物体,现在我们已经定义了一个物体。接下来需要一个“相机”,它本质也是一个物体,因此具有位置等信息,同时它还具有一个focus,也就是相机的“朝向”。本来还想解释更多的,但词汇量有限-.-,再推荐一篇文章吧(感谢大佬):视图变换和投影变换矩阵的原理及推导,以及OpenGL,DirectX和Unity的对应矩阵
归根结底,创建一个物体并通过dx11渲染需要经过:世界矩阵->视图矩阵->投影矩阵,三个变换。
void ZDSJ::Camera::calculateProjectionMatrix(float _window_rate)
{
std::unique_lock<std::shared_mutex> lock(this->m_shared_mutex);
delete this->m_projection_matrix;
// 投影矩阵
this->m_projection_matrix = new DirectX::XMMATRIX(DirectX::XMMatrixPerspectiveFovLH(this->m_fov / 180.0f * DirectX::XM_PI, _window_rate, this->m_near_plane, this->m_far_plane));
}
void ZDSJ::Camera::calsulateViewMatrix()
{
std::unique_lock<std::shared_mutex> lock(this->m_shared_mutex);
delete this->view_matrix;
// 视图矩阵
this->view_matrix = new DirectX::XMMATRIX(DirectX::XMMatrixLookAtLH(DirectX::XMVectorSet(this->m_pos.x, this->m_pos.y, this->m_pos.z, this->m_pos.w), // 摄像机位置
DirectX::XMVectorSet(this->m_pos.x, this->m_pos.y, 0.0f, 1.0f), // 目标点(世界空间原点)
DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f) // 上方向(y轴));
));
}
这里目标点与相机位置的横纵坐标相同,其原因是当前模拟的世界是2维的,如果相机位置与目标位置不同,则相机“观察”到的物体将发生“畸变”,上面那篇文章如果看懂了这里就很好理解了。
DirectX::XMMATRIX matrix = word * ZDSJ::Context::getInstance()->camera()->getCarmeraMatrix();
// return DirectX::XMMatrixTranspose(matrix * pro);
return DirectX::XMMatrixTranspose(matrix);
最终矩阵为:世界矩阵*视图矩阵*投影矩阵。
记得矩阵绑定到管线前需要进行转置,将行存储变为列存储。
相机类位于include/Mydx11/Camera.h
控制台
借用imgui库做了个控制台系统
控制台显示部分通过一个环形队列存储需要显示的内容,每次显示时将文本存入环形队列。
控制台命令单独出一个类,每个在控制台中可以控制的数据由数据所有者注册。
例如控制台调整相机位置,由相机类注册。
这种做法虽然将注册分散到各个类中,但相对来说逻辑更清晰。
using HandlerFunc = std::function<bool(std::string& _data)>;
std::unordered_map<std::string, std::unordered_map<std::string, std::pair<std::string, HandlerFunc>>> m_command_handlers;
控制台回调存储方式见上述代码。即<分类(类),操作(类中可操作数据), 描述(对操作的描述), 回调>
控制台类位于include/ImGuiManager/command.h
快捷键
快捷键处理与控制台处理相似,不再赘述,快捷键类位于include/Mydx11/Keybord.h
源码放在github,develop分支