当前位置: 首页 > news >正文

Metal - 9. 深入剖析 3D 场景

一个 3D 场景通常由一个或多个摄影机、光源和模型构成。随着项目的复杂性增加,如果在 Renderer 类中处理所有这些对象的添加和复杂的游戏逻辑,将变得越来越不切实际。更优的选择是将**场景设置(scene setup)游戏逻辑(game logic)**从渲染代码中分离出来,进行抽象化处理。

本章的核心目标是创建一个抽象的场景结构来容纳模型,并引入一个摄影机结构,使得开发者可以在一个新的文件中设置和更新场景,而无需涉足复杂的渲染器细节。


一、 启动项目 (The Starter Project)

Navigating a 3d Scene

1. 场景抽象(Scene Abstraction)

项目设置了一个 GameScene 类,其主要职责是封装场景代码和设置 (abstract game code and scene setup away from the rendering code)

  • GameScene 结构体持有场景中需要渲染的所有模型(例如 houseground),这些模型被存储在一个 models: [Model] 数组中。
  • 模型通常采用 惰性初始化(lazy var) 的方式创建,例如初始化房屋模型 (Model(name: "lowpoly-house.obj")) 或地面模型 (plane.obj),并在初始化时设置模型的属性(如 tilingscale)。
  • 通过将场景逻辑封装在 GameScene 中,Renderer 类的工作被简化为只负责实例化 GameScene,并迭代调用数组中的模型进行渲染。

2. 摄影机结构(Camera Structure)

相机是移动和导航场景的必备元素。一个相机需要位置(position)旋转(rotation)信息,因此相机结构体必须遵守可变换协议(Transformable protocol)

  • 所有的相机都拥有投影矩阵 (Projection Matrix)视图矩阵 (View Matrix)
  • 相机结构体必须实现方法来处理窗口大小变化(例如更新宽高比)以及每帧的更新。
  • 本章首先创建一个名为 FPCamera(第一人称相机,First-Person Camera)的结构体,它包含一个 Transform 属性,并遵守 Camera 协议。最终,该相机将支持使用键盘控制在 3D 场景中移动。

二、 输入处理(Input)

为了实现场景导航,需要处理来自用户的输入。输入可以来自各种形式,包括游戏控制器、键盘、鼠标和触控板。

1. GCController API

在 macOS 和 iPadOS 上,Apple 提供了 GCController API 来处理这些类型的输入。

2. 事件与轮询(Events or Polling)

GCController API 支持两种输入处理模式:

  • 事件或中断 (Events or Interrupts):当用户按下或释放按键时触发动作。可以通过设置代理方法或闭包(closures)在事件发生时运行代码。
  • 轮询 (Polling):在每一帧中处理所有当前被按下的按键状态。

本章采用轮询模式进行处理:

  • 代码通过添加观察者(observer)来设置 keyChangedHandler,该处理器在键盘首次连接到应用时运行。
  • 当玩家按下或抬起按键时,keyChangedHandler 会运行,并将对应的按键代码(keyCode)添加到 keysPressed 集合中,或从中移除。
  • 这种方法使得在渲染循环的更新阶段可以随时检查当前按下了哪些键。

3. 设置参数(Settings)

为了让相机和鼠标移动平滑,项目引入了 Settings 结构体来存储关键参数。这些参数通过与**时间增量(Delta Time)**结合,用于计算每帧的精确运动量:

  • rotationSpeed:相机每秒应旋转的弧度。
  • translationSpeed:相机每秒应移动的距离。
  • mouseScrollSensitivitymousePanSensitivity:用于调整鼠标追踪和滚动的敏感度。

三、 相机移动(Camera Movement)

本节实现 WASD 键控制的第一人称相机移动:W(前进)、A(向左平移)、S(后退)、D(向右平移)。

1. 移动原理

  • 相机的移动发生在 X 轴和 Z 轴上。
  • 相机需要一个方向向量 (direction vector)。当按下 W 键时,相机将沿着 Z 轴的正方向移动。
  • 如果同时按下 W 和 D 键,相机将斜向移动 (move diagonally)
  • 按下左右箭头键会改变相机的旋转,从而改变相机的前进方向向量 (forward direction vector)

2. 前进向量的计算

forwardVector 是一个关键的计算属性,用于确定相机在世界空间中的朝向。

  • 计算公式:基于当前的 Y Y Y 轴旋转值 (rotation.y),前进向量被计算为 normalize([sin(rotation.y), 0, cos(rotation.y)])
  • 右侧向量 (rightVector):用于实现平移(strafing)的右侧向量是与前进向量垂直的向量。
  • 应用移动:在处理所有按下的按键后,会生成一个最终的 direction 向量(例如,按下 W 和 A 会产生 [-1, 0, 1])。然后,计算出的 translationAmount(等于 deltaTime * Settings.translationSpeed)被用于缩放前进向量和右侧向量,并将结果加到相机的位置上 (transform.position)。

四、 轨道球摄影机(Arcball Camera)

轨道球摄影机是一种特殊的相机类型,用于环绕一个目标点 (orbits a target point) 进行观察,而不是像 FPCamera 那样自由移动。

1. 关键属性

Arcball Camera 由以下三个属性定义:

  • Target (目标点):相机围绕其轨道运行的点。
  • Distance (距离):相机与目标点之间的距离。玩家通过鼠标滚轮控制缩放。
  • Rotation (旋转):相机围绕目标点进行的旋转。玩家通过左键点击鼠标并拖拽来控制。

2. 鼠标输入集成

  • mouseMovedHandler 记录鼠标的 Δ X , Δ Y \Delta X, \Delta Y ΔX,ΔY 变化。
  • scroll.valueChangedHandler 记录滚动的 Δ X , Δ Y \Delta X, \Delta Y ΔX,ΔY 变化。
  • 如果玩家拖拽鼠标左键,相机旋转值会根据 mouseDelta 进行更新。

3. 位置计算

Arcball Camera 的世界位置通过以下序列计算:

  1. 根据相机旋转 (rotation),创建一个 rotateMatrix
  2. 创建一个 distanceVector,例如 float4(0, 0, -distance, 0)
  3. 将旋转矩阵与距离向量相乘,得到旋转后的向量 rotatedVector
  4. 最终位置是 目标位置 加上 旋转向量
    • 矩阵操作顺序float4x4(rotationYXZ:) 方法确保了旋转矩阵是按 Y 轴、X 轴、Z 轴的顺序进行组合的。

五、 正交摄影机(Orthographic Camera)

1. 概念与用途

正交摄影机 渲染时没有透视效果 (renders without perspective)。这意味着所有渲染到 2D 屏幕上的顶点,看起来与摄影机的距离都是相同的,远处物体不会显得更小

  • 投影矩阵:正交投影矩阵定义了一个立方体视椎体(orthographic frustum)
  • 应用场景:正交相机常用于创建俯视整个棋盘的 2D 游戏,或在实现定向光源的阴影贴图时(因为定向光的光线是平行的)。

2. 缩放与宽高比

  • 相机的 update(size:) 方法会设置 aspect(宽高比),用于正交投影矩阵。
  • 玩家可以通过鼠标滚动来改变 viewSize,进而实现缩放或放大场景。

六、 Metal 与 OpenGL 3D 导航对比

Metal 和 OpenGL 在实现 3D 场景导航时,都遵循通过矩阵模拟摄影机的图形学原理,但在 API、数学库和坐标约定上有所不同。

概念Metal (《Metal Tutorials》)OpenGL (《Learn OpenGL》)核心差异与相似点
相机模拟通过创建 Camera 结构体,计算 viewMatrix(通常是相机世界位置的逆矩阵)来实现场景的反向移动。OpenGL 本身不了解相机的概念,通过 view matrix 移动场景中的所有对象来产生相机移动的错觉。核心原理一致,都是通过矩阵变换实现。
视图空间Camera SpaceView Space通常称为 View SpaceCamera SpaceEye Space
输入处理依赖 Apple 平台的 GCController API 来处理键盘、鼠标和游戏控制器输入。依赖于外部库(如 GLFW)来创建窗口并处理输入事件。Metal 的输入处理与 Apple 生态系统深度集成。
数学库使用 Apple 的原生 SIMD 框架进行矩阵和向量操作 (float4x4, simd_float3)。依赖于 GLM (OpenGL Mathematics) 库 (glm::mat4) 来创建和操作变换矩阵。
正交投影使用 Orthographic Camera 实现无透视渲染,NDC 的 Z Z Z 轴范围是 0 0 0 1 1 1Orthographic Projection 常用于 2D 游戏或阴影贴图。 NDC 的 X , Y , Z X, Y, Z X,Y,Z 轴范围都是 − 1.0 -1.0 1.0 1.0 1.0 1.0投影后的 Z Z Z 轴范围不同。
变换组合顶点着色器接收组合矩阵 (uniforms.projectionMatrix * uniforms.viewMatrix * uniforms.modelMatrix) 并执行乘法。顶点着色器执行矩阵乘法,通常顺序是 projection * view * model
输出位置最终顶点位置输出到 [[position]] 属性。最终顶点位置写入内置变量 gl_Position
http://www.dtcms.com/a/414736.html

相关文章:

  • 3DVG的当前面临的挑战和问题
  • 无代码企业网站开发网站建设管理和维护
  • 【C++】string类的常见接口的使用
  • 网站建设制作设计营销公司杭州亚马逊雨林探险作文
  • 东莞圆心科技网站开发哪里有做网站系统
  • 网站定位要点 有哪些方面大航母网站建设费用
  • iServer 启动端口冲突
  • 大连网站建设佳熙科技湖南专业seo优化公司
  • 单词配对记忆游戏小程序V1.1.0-“太空霓虹“视觉升级版
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘onnxruntime’ 问题
  • 设备租赁结算软件有哪些
  • 全网首先 Docker Compose 启动Postgresql18
  • 公司网站非响应式模板网站建设包括内容
  • 180课时吃透Go语言游戏后端开发5:Go语言中的条件语句
  • 企业信息化建设总体规划设计方案
  • 淮北做网站的公司网站建设荣茂
  • Redis 核心知识体系总结
  • 网站图片速度临沂市经济开发区建设局网站
  • React第四天——hooks
  • 地方网站如何做网页版梦幻西游好玩吗
  • 无人机,无人车等机器人系统分布式集群技术难点
  • 企业网站硬件方面建设如何做移动端网站
  • 【代码随想录day 28】 力扣 1005. K次取反后最大化的数组和
  • Python 2025:云原生与容器化技术的新浪潮
  • 上网出现危险网站wordpress批量修改文章内链接
  • 速通ACM省铜第十六天 赋源码(Sigma Cubes和Find Permutation 2和Rotate and Sum Query)
  • 算法题(219):纪念品
  • Cybersecurity AI (CAI) - 轻量级网络安全AI框架
  • 接网站建设_网站设计交换链接的其它叫法是
  • 计算机视觉(opencv)——基于 dlib 的实时摄像头人脸检测