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

相关推荐
DK2215116 分钟前
计算机网络基础科普
c++·计算机网络
无畏烧风34 分钟前
[C++] 一个线程打印奇数一个线程打印偶数
c++
I AM_SUN36 分钟前
994. 腐烂的橘子
数据结构·c++·算法·leetcode·职场和发展
DARLING Zero two♡1 小时前
C++色彩博弈的史诗:红黑树
c++·红黑树
龙湾开发1 小时前
计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 09.天空和背景
c++·笔记·学习·3d·图形渲染
kyle~1 小时前
C++匿名函数
开发语言·c++·人工智能
李匠20241 小时前
C++GO语言微服务之Dockerfile && docker-compose
c++·docker·微服务·架构
code bean1 小时前
【Qt/C++】深入理解 Lambda 表达式与 `mutable` 关键字的使用
开发语言·c++·qt
Cuit小唐1 小时前
C++ 模板方法模式详解
java·c++·模板方法模式
序属秋秋秋2 小时前
《数据结构初阶》【堆 + 堆排序 + TOP-K】
c语言·数据结构·c++·笔记