游戏人生
首页
(current)
GameDevTools
登陆
|
注册
个人中心
注销
游戏引擎 浅入浅出
Introduction
Introduction
前言
前言
1. 游戏引擎框架介绍
1. 游戏引擎框架介绍
1.1 Unity的组成
1.2 游戏引擎组成
2. Opengl开发环境搭建
2. Opengl开发环境搭建
2.1 Opengl到底是什么
2.2 搭建Opengl开发环境
2.3 使用VisualStudio开发
3. 绘制多边形
3. 绘制多边形
3.1 画个三角形
3.2 画个正方形
3.3 画个立方体
4. 着色器
4. 着色器
4.1 Unity Shader和OpenGL Shader
4.2 顶点着色器
4.3 片段着色器
5. 绘制贴图
5. 绘制贴图
5.1 颜色和贴图
5.2 贴图文件介绍
5.3 CPU与GPU的通信方式
5.4 使用stb_image解析图片
5.5 绘制带贴图的立方体盒子
5.6 压缩纹理
5.7 图片压缩工具
5.8 使用压缩纹理
5.9 DXT压缩纹理扩展
6. 索引与缓冲区对象
6. 索引与缓冲区对象
6.1 顶点索引
6.2 缓冲区对象
6.3 OpenGL Core Profile
6.4 顶点数组对象
7. 绘制Mesh和材质
7. 绘制Mesh和材质
7.1 导出Mesh文件
7.2 使用Mesh文件
7.3 Shader文件创建与使用
7.4 创建材质
7.5 使用材质
7.6 MeshRenderer
8. 绘制静态模型
8. 绘制静态模型
8.1 Blender安装与配置
8.2 Blender制作模型
8.3 Blender Python设置开发环境
8.4 Blender Python创建物体
8.5 Blender Python导出顶点数据
8.6 加载导出的Mesh
9. 基于组件开发
9. 基于组件开发
9.1 基于RTTR实现反射
9.2 实现GameObject-Component
10. 相机
10. 相机
10.1 最简单的相机
10.2 多相机渲染
10.3 相机排序
10.4 CullingMask
11. 控制系统
11. 控制系统
11.1 键盘控制
11.2 鼠标控制
12. 拆分引擎和项目
12. 拆分引擎和项目
13. 绘制文字
13. 绘制文字
13.1 TrueType简介
13.2 绘制单个字符
13.3 绘制多个文字
13.4 彩色字
14. GUI
14. GUI
14.1 正交相机
14.2 UIImage
14.3 UIMask
14.4 UIText
14.5 UIButton
15. 播放音效
15. 播放音效
15.1 播放2D音效
15.2 播放3D音效
15.3 使用FMOD Studio音频引擎
16. Profiler
16. Profiler
16.1 初识easy_profiler
16.2 集成easy_profiler
17. 嵌入Lua
17. 嵌入Lua
17.1 Sol2与C++交互
17.2 更加友好的Lua框架设计
17.3 引擎集成sol2
17.4 调试Lua
18. 骨骼动画
18. 骨骼动画
18.1 Blender制作骨骼动画
18.2 Blender导出骨骼动画
18.3 解析骨骼动画
18.4 矩阵的主序
19. 骨骼蒙皮动画
19. 骨骼蒙皮动画
19.1 骨骼蒙皮动画实现
19.2 骨骼权重
19.3 Blender蒙皮刷权重
19.4 Blender导出蒙皮权重
19.5 加载权重文件
20. 解析FBX文件
20. 解析FBX文件
20.1 导出Mesh
20.2 导出骨骼动画
20.3 导出权重
20.4 渲染骨骼蒙皮动画
21. 多线程渲染
21. 多线程渲染
21.1 GLFW多线程渲染
21.2 基于任务队列的多线程渲染
21.3 完全异步的多线程模型
21.4 引擎支持多线程渲染
22. Physx物理引擎
22. Physx物理引擎
22.1 Physx实例-小球掉落
22.2 物理材质
22.3 碰撞检测
22.4 连续碰撞检测
22.5 场景查询
22.6 引擎集成Physx
23. 经典光照
23. 经典光照
23.1 环境光
23.2 漫反射光照模型
23.3 镜面高光光照模型
23.4 高光贴图
23.5 Shader结构体
23.6 Uniform Buffer Object
23.7 方向光
23.8 点光源
23.9 多光源
24. 引擎编辑器的实现
24. 引擎编辑器的实现
24.1 分析Godot引擎编辑器
24.2 FBO RenderTexture GameTurbo DLSS
24.3 ImGui介绍与使用
24.4 分离引擎核心层和应用层
24.5 使用ImGui实现引擎编辑器
24.6 Hierarchy与Inspector面板
24.7 Geometry Buffer
25. Shadow Mapping
25. Shadow Mapping
25.1 深度图
25.2 简单阴影
88. VSCode扩展开发与定制
88. VSCode扩展开发与定制
88.1 第一个VSCode扩展程序
88.2 从源码编译VSCode
88.3 打包VSCode内置扩展
88.4 打包LuaHelper到Code-OSS
89. Doxygen生成API文档
89. Doxygen生成API文档
90. GPU分析工具
90. GPU分析工具
90.1 RenderDoc分析不显示bug
98. SubstancePainter插件开发
98. SubstancePainter插件开发
98.1 SP插件开发环境
98.2 开发SP功能性插件
98.3 开发SP渲染插件
99. Toolbag插件开发
99. Toolbag插件开发
99.1 插件开发环境
99.2 API介绍
99.3 命令行调用Toolbag
99.4 更多实现
99.5 代码参考
附录1. Wwise音频引擎
附录1. Wwise音频引擎
1.1 Wwise名词概念
1.2 Wwise制作音效导出SoundBank
1.3 集成Wwise
1.4 封装Wwise播放3D音效
1.5 Wwise性能分析器介绍
1.6 猎人开发后记
代码资源下载
点我下载
Github
点赞、收藏、关注
目录
<< 20.1 导出Mesh
20.3 导出权重 >>
## 20.2 导出骨骼动画 ```text 「游戏引擎 浅入浅出」是一本开源电子书,PDF/随书代码/资源下载: https://github.com/ThisisGame/cpp-game-engine-book ``` ```bash CLion项目文件位于 samples\load_fbx\extra_skeleton_animation ``` ### 1.名词介绍 FBX是AutoDesk家的私有格式,一般在项目中都是用3dsmax制作模型和动画,有必要了解一下3dsmax的基本操作。 这里简单介绍一些名词概念,便于理解。 * 节点:每个物体看做一个节点,节点之间有层级关系。 * 属性:节点可以是不同的类别,可以是Mesh、也可以是Camera、Light等。 * 修改器:为了实现不同效果,就需要挂上不同的修改器。要对一个Mesh进行编辑,就要添加可编辑Mesh修改器。要实现蒙皮动画,就要添加蒙皮修改器才能绘制权重。 * Cluster:受到某个骨骼影响的多个顶点,被称为Cluster,就是一组顶点的意思。一般Cluster是对应骨骼。这组顶点跟随这个Cluster移动旋转。  从FBX中导出骨骼动画,就是导出每一帧所有Cluster的移动旋转矩阵数据。 拿到矩阵后,就可以作用到顶点,让顶点动起来,这就是骨骼蒙皮动画。 按照下面的顺序: 1. 初始化FBX SDK。 2. 遍历节点,找到Mesh节点。 3. 从Mesh节点获取蒙皮修改器,获取所有Cluster。 4. 遍历帧数,获取每一帧每个Cluster的移动旋转矩阵数据。 前面2点上一节已经介绍过了,来看获取Cluster以及对应数据。<a id="antiCollectorAdTxt" href="https://github.com/ThisisGame/cpp-game-engine-book">「游戏引擎 浅入浅出」是一本开源电子书,PDF/随书代码/资源下载: https://github.com/ThisisGame/cpp-game-engine-book</a> ### 2.导出数据 ```c++ //file:example/main.cpp line:153 /// 从Mesh节点获取蒙皮修改器,获取所有Cluster。遍历帧数,获取每一帧每个Cluster的移动旋转矩阵数据。 /// \param pNode Mesh节点 void ParseNodeRecursive(FbxNode* pNode){ auto name=pNode->GetName(); DEBUG_LOG_INFO("node name: {}", name); FbxNodeAttribute* lNodeAttribute = pNode->GetNodeAttribute(); if (lNodeAttribute) { // 获取pNode相对于锚点的offset const FbxVector4 lT = pNode->GetGeometricTranslation(FbxNode::eSourcePivot); const FbxVector4 lR = pNode->GetGeometricRotation(FbxNode::eSourcePivot); const FbxVector4 lS = pNode->GetGeometricScaling(FbxNode::eSourcePivot); FbxAMatrix lGeometryOffset = FbxAMatrix(lT, lR, lS); DEBUG_LOG_INFO(" node translation: ({},{},{},{})", lT[0], lT[1], lT[2], lT[3]); DEBUG_LOG_INFO(" node rotation: ({},{},{},{})", lR[0], lR[1], lR[2], lR[3]); DEBUG_LOG_INFO(" node scaling: ({},{},{},{})", lS[0], lS[1], lS[2], lS[3]); if (lNodeAttribute->GetAttributeType() == FbxNodeAttribute::eMesh) { FbxMesh* pMesh = pNode->GetMesh(); // 获取蒙皮数量,一般来说一个Mesh对应一个蒙皮修改器。 // int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin); Engine::Animation animation; animation.name_=mCurrentAnimationStack->GetName(); FbxTime::EMode lTimeMode = mScene->GetGlobalSettings().GetTimeMode(); animation.frame_per_second_=fbxsdk::FbxTime::GetFrameRate(lTimeMode); // 获取蒙皮修改器 int lSkinIndex=0; FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin); // 获取蒙皮修改器上的顶点组数量,一般来说就是骨骼数量,绑定的时候,一般是以一个骨骼作为一个顶点组。 int lClusterCount = lSkinDeformer->GetClusterCount(); // 遍历骨骼 for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) { // 获取骨骼的顶点组 FbxCluster *lCluster = lSkinDeformer->GetCluster(lClusterIndex); animation.bone_name_vec_.push_back(lCluster->GetName()); } // 每一帧的时间 FbxTime mFrameTime; mFrameTime.SetTime(0, 0, 0, 1, 0, mScene->GetGlobalSettings().GetTimeMode()); for(FbxTime pTime=mStart;pTime<mStop;pTime+=mFrameTime){ // 首先获取当前节点的全局坐标 FbxAMatrix lGlobalPosition = pNode->EvaluateGlobalTransform(pTime); FbxAMatrix lGlobalOffPosition = lGlobalPosition * lGeometryOffset;//相乘获得pNode在当前时间相对原点的坐标。 std::vector<glm::mat4> one_frame_bone_matrix_vec;//一帧的所有骨骼变换矩阵 for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) { // 获取骨骼的顶点组 FbxCluster *lCluster = lSkinDeformer->GetCluster(lClusterIndex); // 计算这个骨骼的形变,前面pNode是指计算到Mesh节点的形变,而这是是计算骨骼节点,后面会作用到顶点。 FbxAMatrix lVertexTransformMatrix; ComputeClusterDeformation(lGlobalOffPosition, pMesh, lCluster, lVertexTransformMatrix, pTime); glm::mat4 bone_matrix= FbxMatrixToGlmMat4(lVertexTransformMatrix); one_frame_bone_matrix_vec.push_back(bone_matrix); } animation.frame_bones_matrix_vec_.push_back(one_frame_bone_matrix_vec); }//lClusterCount animation.frame_count_=animation.frame_bones_matrix_vec_.size(); animation.Write(fmt::format("../data/animation/fbx_extra_{}.skeleton_anim", animation.name_).c_str()); } } // 遍历子节点,递归 const int lChildCount = pNode->GetChildCount(); for (int lChildIndex = 0; lChildIndex < lChildCount; ++lChildIndex) { ParseNodeRecursive(pNode->GetChild(lChildIndex)); } } ``` 核心代码其实就是下面这句,获取了当前Cluster在当前帧的形变。 ```c++ //file:example/main.cpp line:204 // 计算这个骨骼的形变,前面pNode是指计算到Mesh节点的形变,而这是是计算骨骼节点,后面会作用到顶点。 FbxAMatrix lVertexTransformMatrix; ComputeClusterDeformation(lGlobalOffPosition, pMesh, lCluster, lVertexTransformMatrix, pTime); ``` 这个函数是从`ViewScene`里原样搬过来的,函数里面挺复杂,不用管它,我知道了这个函数返回的矩阵是最终作用到顶点上,那么这个矩阵就是我所需要的,用它就能作用到顶点上形成蒙皮动画。 ```diff +对其他建模软件或者模型格式也可以用这个套路,找到最后作用到顶点的矩阵导出即可。 ``` ### 3.文件结构 还记得在前面Blender导出时,需要导出T-POS矩阵,以及每一帧Bone的相对位移矩阵,然后在运行时,加载文件后,首先进行Bake计算出最终的矩阵。 而这里导出的矩阵是最终作用到顶点上,这和之前Blender导出骨骼动画数据有点差异,少了Bake阶段。 就是说导出的矩阵是全局的,而不是局部的,那么相比较就少了T-POS矩阵数据,文件结构修改为如下:  较之前版本,红色框内不需要了。
<< 20.1 导出Mesh
20.3 导出权重 >>
12
代码资源下载
点我下载
Github
点赞、收藏、关注
目录
Introduction
Introduction
前言
前言
1. 游戏引擎框架介绍
1. 游戏引擎框架介绍
1.1 Unity的组成
1.2 游戏引擎组成
2. Opengl开发环境搭建
2. Opengl开发环境搭建
2.1 Opengl到底是什么
2.2 搭建Opengl开发环境
2.3 使用VisualStudio开发
3. 绘制多边形
3. 绘制多边形
3.1 画个三角形
3.2 画个正方形
3.3 画个立方体
4. 着色器
4. 着色器
4.1 Unity Shader和OpenGL Shader
4.2 顶点着色器
4.3 片段着色器
5. 绘制贴图
5. 绘制贴图
5.1 颜色和贴图
5.2 贴图文件介绍
5.3 CPU与GPU的通信方式
5.4 使用stb_image解析图片
5.5 绘制带贴图的立方体盒子
5.6 压缩纹理
5.7 图片压缩工具
5.8 使用压缩纹理
5.9 DXT压缩纹理扩展
6. 索引与缓冲区对象
6. 索引与缓冲区对象
6.1 顶点索引
6.2 缓冲区对象
6.3 OpenGL Core Profile
6.4 顶点数组对象
7. 绘制Mesh和材质
7. 绘制Mesh和材质
7.1 导出Mesh文件
7.2 使用Mesh文件
7.3 Shader文件创建与使用
7.4 创建材质
7.5 使用材质
7.6 MeshRenderer
8. 绘制静态模型
8. 绘制静态模型
8.1 Blender安装与配置
8.2 Blender制作模型
8.3 Blender Python设置开发环境
8.4 Blender Python创建物体
8.5 Blender Python导出顶点数据
8.6 加载导出的Mesh
9. 基于组件开发
9. 基于组件开发
9.1 基于RTTR实现反射
9.2 实现GameObject-Component
10. 相机
10. 相机
10.1 最简单的相机
10.2 多相机渲染
10.3 相机排序
10.4 CullingMask
11. 控制系统
11. 控制系统
11.1 键盘控制
11.2 鼠标控制
12. 拆分引擎和项目
12. 拆分引擎和项目
13. 绘制文字
13. 绘制文字
13.1 TrueType简介
13.2 绘制单个字符
13.3 绘制多个文字
13.4 彩色字
14. GUI
14. GUI
14.1 正交相机
14.2 UIImage
14.3 UIMask
14.4 UIText
14.5 UIButton
15. 播放音效
15. 播放音效
15.1 播放2D音效
15.2 播放3D音效
15.3 使用FMOD Studio音频引擎
16. Profiler
16. Profiler
16.1 初识easy_profiler
16.2 集成easy_profiler
17. 嵌入Lua
17. 嵌入Lua
17.1 Sol2与C++交互
17.2 更加友好的Lua框架设计
17.3 引擎集成sol2
17.4 调试Lua
18. 骨骼动画
18. 骨骼动画
18.1 Blender制作骨骼动画
18.2 Blender导出骨骼动画
18.3 解析骨骼动画
18.4 矩阵的主序
19. 骨骼蒙皮动画
19. 骨骼蒙皮动画
19.1 骨骼蒙皮动画实现
19.2 骨骼权重
19.3 Blender蒙皮刷权重
19.4 Blender导出蒙皮权重
19.5 加载权重文件
20. 解析FBX文件
20. 解析FBX文件
20.1 导出Mesh
20.2 导出骨骼动画
20.3 导出权重
20.4 渲染骨骼蒙皮动画
21. 多线程渲染
21. 多线程渲染
21.1 GLFW多线程渲染
21.2 基于任务队列的多线程渲染
21.3 完全异步的多线程模型
21.4 引擎支持多线程渲染
22. Physx物理引擎
22. Physx物理引擎
22.1 Physx实例-小球掉落
22.2 物理材质
22.3 碰撞检测
22.4 连续碰撞检测
22.5 场景查询
22.6 引擎集成Physx
23. 经典光照
23. 经典光照
23.1 环境光
23.2 漫反射光照模型
23.3 镜面高光光照模型
23.4 高光贴图
23.5 Shader结构体
23.6 Uniform Buffer Object
23.7 方向光
23.8 点光源
23.9 多光源
24. 引擎编辑器的实现
24. 引擎编辑器的实现
24.1 分析Godot引擎编辑器
24.2 FBO RenderTexture GameTurbo DLSS
24.3 ImGui介绍与使用
24.4 分离引擎核心层和应用层
24.5 使用ImGui实现引擎编辑器
24.6 Hierarchy与Inspector面板
24.7 Geometry Buffer
25. Shadow Mapping
25. Shadow Mapping
25.1 深度图
25.2 简单阴影
88. VSCode扩展开发与定制
88. VSCode扩展开发与定制
88.1 第一个VSCode扩展程序
88.2 从源码编译VSCode
88.3 打包VSCode内置扩展
88.4 打包LuaHelper到Code-OSS
89. Doxygen生成API文档
89. Doxygen生成API文档
90. GPU分析工具
90. GPU分析工具
90.1 RenderDoc分析不显示bug
98. SubstancePainter插件开发
98. SubstancePainter插件开发
98.1 SP插件开发环境
98.2 开发SP功能性插件
98.3 开发SP渲染插件
99. Toolbag插件开发
99. Toolbag插件开发
99.1 插件开发环境
99.2 API介绍
99.3 命令行调用Toolbag
99.4 更多实现
99.5 代码参考
附录1. Wwise音频引擎
附录1. Wwise音频引擎
1.1 Wwise名词概念
1.2 Wwise制作音效导出SoundBank
1.3 集成Wwise
1.4 封装Wwise播放3D音效
1.5 Wwise性能分析器介绍
1.6 猎人开发后记