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)。相机操纵器的本质是通过用户交互动态修改视图矩阵,从而改变模型在视口中的显示效果。下章将详细分析相机操纵器的工作原理及其实现方式,以更好地理解如何通过交互控制相机状态。

相关推荐
byte轻骑兵2 分钟前
【C++高级主题】命令空间(五):类、命名空间和作用域
开发语言·c++
忘梓.40 分钟前
从二叉树到 STL:揭开 set 容器的本质与用法
开发语言·c++
Alan3161 小时前
qt network 整体框架
c++
byte轻骑兵2 小时前
【C++高级主题】虚基类的声明
开发语言·c++
落羽的落羽2 小时前
【C++】二叉搜索树
开发语言·数据结构·c++·学习
胡译胡说2 小时前
C语言的”代码化石“出土:1979年的英文文本判别器
c++·unix
偷懒下载原神2 小时前
《C++ 模板》
开发语言·c++
小明同学012 小时前
[C++入门]简化的艺术---对模版的初步探索
开发语言·c++·算法
Rachelhi2 小时前
C++.异常处理(1.9w字)
开发语言·c++
溟洵2 小时前
【C++ Qt】窗口(Qt窗口框架、菜单栏QMenuBar)
c++·qt