DirectX12(D3D12)基础教程(十七)——让小姐姐翩翩起舞(3D骨骼动画渲染【1】)

1、前言

  经过了一系列比较枯燥的命令行式的“外篇”系列教程后,这一篇起回归主干,继续我们的D3D12之旅,本章就利用已经学习的assimp库导入3D模型及动画,并且实现3D骨骼动画渲染。需要注意的是本章重点在骨骼动画的加载解算以及相应基本Shader的编写上,并没有加入光照、材质等功能,这样也符合本系列教程一贯的宗旨,即尽力使每个例子都简单,主题集中,防止大家分散精力。并且本章主题“3D骨骼动画”本身就稍微有些难度,所以更需要大家集中精力搞懂骨骼动画的基本原理,这也是3D动画最核心的基础之一。当然也只有拥有了3D动画控制能力,才使得整个学习的旅程不再枯燥乏味,更会使大家信心满满继续努力朝全面掌握引擎级编程能力进发!

努力搬砖

  这里还要提醒大家的是,虽然本章集中在导入3D模型及骨骼动画渲染的学习上,但实质上,这里的方法几乎可以用于导入所有的模型并做渲染上,只有掌握了基本的导入模型能力,才使得创建更复杂的场景并渲染拥有了基础,所以这一章是比较重要的一章,请大家务必牢固掌握模型的导入能力以及骨骼动画的基础渲染能力上。
划重点

  另外,对于比较熟悉OpenGL的同学来说,使用Assimp导入并渲染模型可能更方便。但需要说明的是,这并不是说D3D12就比OpenGL弱。其实从编程的角度来说,OpenGL更像是具有一定封装的偏向引擎的接口,可以称之为“半引擎”,因此其功能更丰富强大一些,可以快速的进入动画渲染的学习掌握上。而D3D12是更偏向于驱动侧或者说硬件侧的一组比较纯粹的基础功能接口,几乎没什么封装,所有的完整功能级封装都需要自己动手设计实现,但是在性能上更具有优势,而且当显卡驱动更新或技术更新换代后,它可以快速的实现某些新特性的接口供开发者使用。

在这里插入图片描述

  这里提示大家,如果要掌握牢固的引擎封装基础能力,那么D3D12接口可能更合适一些。如果再考虑到跨平台特性,那么其实现代的Vulkan接口与D3D12接口更接近一些,所以如果完全掌握了D3D12接口,那么再去学习Vulkan和OpenGL接口就会更轻松,或者说学习曲线就会更平坦,但反过来可能会比较吃力。最终这种差别可以理解为在引擎与底层显卡驱动之间,“OpenGL向上”,而“D3D12向下”,如图:

在这里插入图片描述

  本章示例中,默认演示加载一个女侠舞剑(貌似叫李晓倩)的模型(lxq.x,在资源目录中,已上传Github),前一章的x文件也可以使用,或者可以自己再搜一些x文件或别的模型文件进行加载测试,程序运行开始时会弹出文件选择对话框,可以选择任一Assimp支持的类型的模型文件查看效果,甚至是FBX文件。需要注意的是,如果是没有添加基本纹理的模型,加载运行可能会出错。最终运行效果如下:
本章效果

  本章重要参考在:(第三十八课 用 Assimp 导入骨骼动画),注意这是一个OpenGL的教程,所以挪到D3D12中还是需要费点功夫的,当然这一系列文章都是非常重要的参考,建议大家认真从头学习一下理论知识,也可以顺道熟悉一下OpenGL。

2、本章代码简要说明

  上一章DirectX12(D3D12)基础教程(外篇四)——用Assimp载入模型基础操作(无渲染纯命令行版)_中,已经介绍了如何将3D模型数据通过Assimp库导入,除去为了遍历展示数据的代码外,其实用Assimp库导入3D模型的方法是很简单的。这一章就在导入的基础上,继续对重要的动画数据进行解算和动画渲染。

  同时这一章中,将导入和解析数据的部分接口封装在了GRS_Assimp_Loader.h和GRS_Assimp_Loader.cpp两个文件中,重点的就是两个函数,一个是LoadMesh用于加载模型文件,另一个是CalcAnimation用于解算动画数据,详细的后面会介绍到。

  如果你一开始就仔细的看过每一章教程,可能到这一章的时候,感觉会比较意外,为什么从一开始我说尽量不讲封装,而现在又搞起好像是封装了呢?

  这主要是因为:

  首先大家既然耐心的听我啰嗦的讲到这里了,那么我想大家对之前的内容应该已经有个基本的牢固的掌握了,尤其是D3D12的一些常用方法,应该都有了深刻的认识,这样适当的加些函数封装,我想大家也应该能接受,否则单个代码文件的体积就过于庞大了,反倒不利于进一步学习了。

  其次,这里的封装其实是一个暗示。大家可以明显的发现Assimp加载和初步解析数据的代码都在这两个文件中,而其中并没有牵扯到任何D3D12方法的调用,而最终加载数据并渲染的代码还是在项目的主文件中,这是暗示大家未来如果你要封装简单的demo,或简单的引擎,那么这里是可以方便的设计为一个“Build”模式的,而且这种分离,使得未来如果你使用其它的模型加载库,也可以方便的融入自己的体系中。另外这里明确分离了Assimp导入数据和D3D12加载及渲染的过程,也是使最终模块间的耦合度降到最低的程度,即只做数据耦合,本章示例中就是明确做到加载数据和使用数据功能明确解耦。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0X71rT2i-1626579190785)(17.assets/耦合度.png)]
  再次,对于骨骼动画的解算来说,都需要递归遍历骨骼结构,这个过程如果改成线性过程(经典做法就是用栈模拟递归)可能反倒不宜理解,因此必须要将遍历的过程函数化,所以就单独封装了函数,也是为了方便最终让大家理解和彻底掌握骨骼动画的核心原理。(提示:骨骼动画只是3D动画的一种,后续还会有表情动画、粒子动画等,这些都与骨骼动画不同。)

在这里插入图片描述
  另外,本章示例中,也将使用WIC库加载纹理的过程单独挪到了GRS_Texture_Loader.h、GRS_WIC_Utility.h文件中,因为这部分内容实在是太占用源码行数了,如果还放在项目主文件中再一遍遍重复,可能反倒会引起大家的不适。所以按照循序渐进的学习原则和低耦合高内聚的原则,就单独把加载纹理的数据定义及方法摆放到了单独的文件中,这样大家也可以方便的重用这部分代码,因为加载纹理也是一个重要基础的功能。这里要注意的是,D3D12默认的加载纹理的工具方法,只能加载DDS纹理,而使用WIC加载纹理可以加载多种类型的图片,甚至低压缩(BC3以下)或无压缩的DDS也可以使用WIC导入。
在这里插入图片描述

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片