
中级OpenGL教程 010Object 类设计与模型矩阵完全实现Bilibili 同步视频一、Object 类3D 物体的「空间管理者」1.1 文件结构与基础配置二、成员变量设计protected 权限的精妙选择2.1 三大核心变换变量三、旋转逻辑本地坐标系 Unity 标准顺序3.1 本地坐标系旋转3.2 旋转顺序严格遵循 Unity 引擎标准四、接口封装简洁易用的变换 API4.1 核心接口声明4.2 接口实现object.cpp五、模型矩阵计算渲染管线的「核心输出」5.1 矩阵计算完整实现5.2 关键细节勘误必看六、Object 类的价值与扩展方向6.1 核心价值6.2 扩展方向结语Bilibili 同步视频中级OpenGL教程 010Object 类设计与模型矩阵完全实现在 3D 图形渲染的世界里一切可见元素都可被抽象为「物体」—— 无论是场景中的模型、角色、道具还是粒子特效都需要一套统一的框架来管理其空间变换。Object 类正是这套框架的核心它封装了物体的位移、旋转、缩放三大基础变换最终输出渲染管线必需的模型矩阵Model Matrix为后续 MVP 矩阵计算与片元着色打下坚实基础。本文将从零拆解 Object 类的设计思路、成员变量定义、接口封装与模型矩阵计算逻辑搭配可直接落地的 C 代码实现帮你快速搭建 3D 引擎的物体管理模块✨。一、Object 类3D 物体的「空间管理者」Object 类的核心使命只有一个管理物体的空间变换输出标准模型矩阵。它是所有可渲染物体的基类场景中的模型、相机、灯光等实体都可继承此类复用变换逻辑。因此在设计时权限控制、变量封装、接口易用性是三大关键原则。1.1 文件结构与基础配置我们将 Object 类置于GL framework核心模块方便全工程复用创建两个核心文件object.h类定义、变量声明、接口声明object.cpp函数实现、矩阵计算逻辑头文件必须添加#pragma once预编译指令杜绝头文件二次编译避免重复定义报错同时引入核心依赖库GLM 数学库、框架核心文件为矩阵运算、向量操作提供支撑。// object.h 基础配置#pragmaonce#includecore.h// 包含 GLM 数学库、框架核心工具二、成员变量设计protected 权限的精妙选择物体的空间变换本质是位置、旋转、缩放三组数据的组合。在权限设计上我们放弃private选择protected修饰所有成员变量 —— 这是为了让子类能直接访问父类变换数据保证继承体系的灵活性比如模型类、角色类可直接修改位置、旋转角度。2.1 三大核心变换变量位置变量m_position记录物体在世界坐标系中的坐标用glm::vec3存储初始化为(0.0f, 0.0f, 0.0f)代表物体默认位于世界原点。旋转变量m_angle_x /m_angle_y/m_angle_z采用欧拉角旋转方案分别记录物体绕 X、Y、Z 本地轴的旋转角度这是游戏 / 引擎中最通用的旋转方式Pitch绕 X 轴上下俯仰类比「点头」Yaw绕 Y 轴左右转向类比「摇头」Roll绕 Z 轴滚筒旋转类比「滚床单」缩放变量m_scale用glm::vec3存储物体在 X、Y、Z 轴的缩放比例默认值必须为 1.0f代表无缩放若设为 0 会导致物体完全消失。// object.h 成员变量定义classObject{protected:// 1. 位置世界坐标系坐标glm::vec3 m_position{0.0f,0.0f,0.0f};// 2. 旋转欧拉角绕本地X/Y/Z轴floatm_angle_x{0.0f};floatm_angle_y{0.0f};floatm_angle_z{0.0f};// 3. 缩放三轴缩放比例glm::vec3 m_scale{1.0f,1.0f,1.0f};public:// 后续接口声明...};三、旋转逻辑本地坐标系 Unity 标准顺序旋转是 3D 变换中最易出错的环节核心要解决两个问题基于什么坐标系旋转旋转的先后顺序是什么3.1 本地坐标系旋转我们采用本地坐标系局部坐标系旋转规则物体的旋转始终围绕自身当前的坐标轴而非世界坐标系坐标轴。比如物体先绕 X 轴旋转 30°再绕 Z 轴旋转时Z 轴是物体旋转后的本地 Z 轴而非世界 Z 轴 —— 这符合现实中物体的运动直觉如飞机、汽车的运动。3.2 旋转顺序严格遵循 Unity 引擎标准为保证旋转结果可预期固定旋转顺序至关重要我们直接沿用工业级标准Unity 引擎先 PitchX 轴→ 再 YawY 轴→ 最后 RollZ 轴此顺序能最大程度避免万向锁问题适配绝大多数 3D 场景需求。四、接口封装简洁易用的变换 APIObject 类对外提供极简接口支持设置位置、增量旋转、设置缩放三大操作区分「赋值式设置」与「增量式修改」符合引擎开发习惯。4.1 核心接口声明// object.h 公共接口public:Object()default;~Object()default;// 1. 设置位置赋值式直接覆盖世界坐标voidsetPosition(constglm::vec3position);// 2. 增量旋转在原有角度基础上累加voidrotateX(floatangle);voidrotateY(floatangle);voidrotateZ(floatangle);// 3. 设置缩放赋值式直接覆盖三轴缩放voidsetScale(constglm::vec3scale);// 4. 核心计算并返回模型矩阵glm::mat4getModelMatrix();4.2 接口实现object.cpp旋转接口采用增量累加逻辑每调用一次rotateX就在原有角度上叠加新角度适配帧更新的旋转逻辑位置与缩放为直接赋值保证精准控制。// object.cpp 接口实现#includeobject.h// 设置位置voidObject::setPosition(constglm::vec3position){m_positionposition;}// 增量旋转 X 轴voidObject::rotateX(floatangle){m_angle_xangle;}// 增量旋转 Y 轴voidObject::rotateY(floatangle){m_angle_yangle;}// 增量旋转 Z 轴voidObject::rotateZ(floatangle){m_angle_zangle;}// 设置缩放voidObject::setScale(constglm::vec3scale){m_scalescale;}五、模型矩阵计算渲染管线的「核心输出」getModelMatrix()是 Object 类的灵魂函数它将位移、旋转、缩放三组离散数据组合为渲染管线必需的模型矩阵变换顺序严格遵循 Unity 标准先缩放 → 再旋转 → 最后平移⚠️ 关键规则平移必须在最后且基于世界坐标系执行保证物体最终定位到指定世界坐标。5.1 矩阵计算完整实现// object.cpp 模型矩阵计算glm::mat4Object::getModelMatrix(){// 1. 初始化单位矩阵glm::mat4 transformglm::mat4(1.0f);// 2. 第一步缩放变换本地坐标系transformglm::scale(transform,m_scale);// 3. 第二步旋转变换本地坐标系严格按 X→Y→Z 顺序// 旋转需转弧度GLM 仅支持弧度运算角度必须转换transformglm::rotate(transform,glm::radians(m_angle_x),glm::vec3(1.0f,0.0f,0.0f));transformglm::rotate(transform,glm::radians(m_angle_y),glm::vec3(0.0f,1.0f,0.0f));transformglm::rotate(transform,glm::radians(m_angle_z),glm::vec3(0.0f,0.0f,1.0f));// 4. 第三步平移变换世界坐标系单独计算后相乘transformglm::translate(glm::mat4(1.0f),m_position)*transform;// 返回最终模型矩阵returntransform;}5.2 关键细节勘误必看GLM 数学库的旋转函数仅支持弧度值但我们设计的m_angle_x/y/z是角度值必须用glm::radians()转换否则旋转结果完全错误这是 3D 开发高频踩坑点❗六、Object 类的价值与扩展方向6.1 核心价值统一抽象将所有 3D 物体的变换逻辑收敛到一个基类减少重复代码标准输出输出合规模型矩阵无缝对接渲染管线易于继承子类可快速扩展如 Model 类添加网格数据、Light 类添加光照参数6.2 扩展方向新增resetTransform()重置所有变换添加欧拉角转四元数解决万向锁问题支持父物体 / 子物体的父子坐标系变换结语Object 类是 3D 渲染框架的「最小可用单元」它没有复杂的逻辑却承载了物体空间变换的核心能力。从变量权限设计、旋转规则制定到模型矩阵计算每一步都遵循工业级引擎标准代码简洁、可直接落地到 OpenGL/ES 3D 项目中。掌握 Object 类你就掌握了 3D 场景中物体运动的底层逻辑后续再扩展相机、光照、材质等模块都会变得水到渠成。