vulkanscenegraph显示倾斜模型(5.3)-相机

前言

在Vulkan中,相机的概念并非由API直接提供,而是由应用程序实现。相机的核心功能包括视图变换和投影变换:视图变换将世界坐标系中的物体转换到相机坐标系,投影变换则将相机坐标系中的物体转换到投影空间。在VSG(Vulkan Scene Graph)框架中,vsg::Camera类封装了视图矩阵和投影矩阵,并提供了便捷的接口来管理相机。本章将深入探讨Vulkan中的矩阵变换原理,以及VSG对相机功能的封装与实现。


目录

  • 1 vsg::Camera
  • 2 vsg中的视图变换
  • 3 vsg中的投影变换

1 vsg::Camera

本章将参照测试用例(写文章-CSDN创作中心)中的如下代码进行深入探讨。

cpp 复制代码
	vsg::ComputeBounds computeBounds;
	vsg_scene->accept(computeBounds);
	vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max)*0.5;
	double radius = vsg::length(computeBounds.bounds.max - computeBounds.bounds.min)*0.6;
	double nearFarRatio = 0.001;

	// set up the camera
	auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 3.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0));
	vsg::ref_ptr<vsg::ProjectionMatrix> perspective;
	if (vsg::ref_ptr<vsg::EllipsoidModel> ellipsoidModel(vsg_scene->getObject<vsg::EllipsoidModel>("EllipsoidModel")); ellipsoidModel)
	{
		perspective = vsg::EllipsoidPerspective::create(lookAt, ellipsoidModel, 30.0, static_cast<double>(vsg_window->extent2D().width) / static_cast<double>(vsg_window->extent2D().height), nearFarRatio, 0.0);
	}
	else
	{
		perspective = vsg::Perspective::create(30.0, static_cast<double>(vsg_window->extent2D().width) / static_cast<double>(vsg_window->extent2D().height), nearFarRatio*radius, radius * 4.5);
	}
	auto vsg_camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(vsg_window->extent2D()));

上述代码中1-5行,通过vsg::ComputeBounds计算得到场景的包围盒范围,进而计算得到场景中心点和半径,并设置远景裁剪面的比例。接着第7行,计算得到视图矩阵,第8-16行,计算得到投影矩阵。代码17行,由视图矩阵、投影矩阵、视口状态(Viewport)创建vsg::Camera。

cpp 复制代码
    class VSG_DECLSPEC Camera : public Inherit<Node, Camera>
    {
    public:
        Camera();

        Camera(ref_ptr<ProjectionMatrix> in_projectionMatrix, ref_ptr<ViewMatrix> in_viewMatrix, ref_ptr<ViewportState> in_viewportState = {});

        std::string name;
        ref_ptr<ProjectionMatrix> projectionMatrix;
        ref_ptr<ViewMatrix> viewMatrix;
        ref_ptr<ViewportState> viewportState;

        VkViewport getViewport() const { return viewportState ? viewportState->getViewport() : VkViewport{}; }
        VkRect2D getRenderArea() const { return viewportState ? viewportState->getScissor() : VkRect2D{}; }

        void read(Input& input) override;
        void write(Output& output) const override;
    };

vsg::Camera类提供了投影矩阵(ref_ptr<ProjectionMatrix>)、视图矩阵(ref_ptr<ViewMatrix>)以及视口设置(ref_otr<ViewportState>),这些共同控制着View在场景中所观察到的内容。

2 vsg中的视图变换

在vsg中视图相关的矩阵基类为vsg::ViewMatrix,子类有vsg::LookAt、vsg::LookDirection、vsg::RelativeViewMatrix、vsg::TrackingViewMatrix。

cpp 复制代码
auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 3.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0));
cpp 复制代码
          Z (Up)
          |
          |
          |
          +--------> Y
         /
        /
       X

其中vsg::LookAt,通过传入eyePosition、centerPositon、upDirection创建。上述代码,eyePosition位于负y轴上,centerPositon为上图的中心点、upDirection为Z轴。因此模型在视口中呈现的状态类似左视图的观察效果。

3 vsg中的投影变换

在vsg中投影相关的矩阵基类为vsg::ProjectionMatrix,相应的子类有vsg::EllipsoidPerspective、vsg::Orthographic、vsg::Perspective、vsg::RelativeProjection。

其中vsg::Perspective中的矩阵计算公式如下:

相比 OpenGL,Vulkan 在投影空间中,x 轴从左到右、y 轴从上向下(与 OpenGL 相反),同时 z 的取值范围为 0 到 1(其中近平面为 0、远平面为 1,而在 OpenGL 中,z 的取值范围为 -1 到 1)。

将(0,0,-zNear)、(0,0,-zFar)带入公式,分别计算得到的深度值为1和0,这与vulkan正好相反,这种深度值分布方式被称为 Reversed-Z,是一种常见的深度优化技术。 相应地,VKCompareOp默认取值为VK_COMPARE_OP_GREATER。

在Vulkan中,相机的概念并非由API直接提供,而是由应用程序实现,应用程序中的矩阵可通过vkCmdPushConstants将矩阵直接推送到命令缓冲区,对应的代码如下。

文末:本章在上一篇文章的基础上,进一步深入探讨 Vulkan 中的矩阵变换,重点分析了视图矩阵(View Matrix)和投影矩阵(Projection Matrix)的作用及其数学原理,并详细介绍了 VSG 框架对相机的封装实现------vsg::Camera 类。此外,本章还深入探讨了视图矩阵与投影矩阵的计算公式,对比了 Vulkan 与 OpenGL 在投影空间中的差异,并解释了 VSG 中投影矩阵计算公式的设计考量-ReverseZ。下一章将在本章的基础上,深入探讨 VSG 中的相机操纵器(Camera Manipulator)。相机操纵器的本质是通过用户交互动态修改视图矩阵,从而改变模型在视口中的显示效果。下章将详细分析相机操纵器的工作原理及其实现方式,以更好地理解如何通过交互控制相机状态。

相关推荐
myloveasuka几秒前
信号操作集函数
linux·运维·服务器·c语言·c++·vscode
山野万里__15 分钟前
C++与Java内存共享技术:跨平台与跨语言实现指南
android·java·c++·笔记
Mr_Xuhhh1 小时前
网络基础(1)
c语言·开发语言·网络·c++·qt·算法
醇醛酸醚酮酯2 小时前
std::promise和std::future的使用示例——单线程多链接、多线程单链接
网络·c++·算法
背影疾风2 小时前
C++之路:类基础、构造析构、拷贝构造函数
linux·开发语言·c++
程序员弘羽2 小时前
C++ 第四阶段 内存管理 - 第二节:避免内存泄漏的技巧
java·jvm·c++
DolphinDB4 小时前
如何在C++交易系统中集成高性能回测与模拟撮合
c++
筏.k4 小时前
C++ 网络编程(14) asio多线程模型IOThreadPool
网络·c++·架构
爱喝茶的小茶5 小时前
周赛98补题
开发语言·c++·算法
OpenC++5 小时前
【C++】备忘录模式
c++·设计模式·备忘录模式