unity code之GPUSkinning

梳理:

整体的执行包括skinning的创建,更新,删除。

指令驱动:

所有相关skinning的驱动都是通过void GfxDeviceWorker::RunCommand(ThreadedStreamBuffer& stream)俩执行的。其实包括动态合批,静态合批,其他所有操作都是可以通过这个指令列表来做的。

启动skinning(kGfxCmd_BeginSkinning):

也就是新建一个线程组准备执行skinning。

结束skinning(kGfxCmd_EndSkinning):

等待线程完成后移除skinning的数据。WaitForGroup这里是会会循环等待这个线程完成了才结束。

移除skinning的数据信息(kGfxCmd_DeleteGPUSkinningInfo):

这里是通过gfx的接口来对不同平台执行deleta,也就是直接deleta掉数据info。

读取每帧的数据渲染skinning(kGfxCmd_SkinOnGPU):

dx11:

这里从stream里面读取出info和destVBO信息,并让vbo信息设置进info中。然后执行gfx的SkinOnGPU。然后每个平台执行到SkinMesh,比如dx11的话是:

在里面通过channel,GetBonesPerVertex每个顶点的骨骼数,还有DeBruijn编码来组成三维数组的下标。通过GetMemExShader来获取到顶点和几何变化信息赋值。

特别说明在dx11下拿到的数据是已经编好码的一串关联数字

这些编码是一个汇编码

然后dx通过接口填充shader的数据,当然dx11是通过接口给汇编数据

在最后vbo要解绑

opengles3:

gles3会在TransformFeedbackSkinnedMesh中执行TransformFeedbackSkinningInfo::SkinMesh。还是传统的绑定vbo,绑定shaderprogram,设置shader的数据

根据条件启动shader属性

通过glDrawArrays的方式顺序执行顶点:

其他渲染器:

其他渲染器直接执行GfxDevice::SkinMesh,看上去和普通的skinmesh一样,直接走skinmesh正常的渲染,也就是不会由skinning。正常的skinmesh是建立线程来执行vbo渲染。

更新vbo

骨骼数据(kGfxCmd_UpdateSkinSourceData):

这里很明显就是更新正在执行的skinng的数据了。

更新骨骼数量以及骨骼矩阵(kGfxCmd_UpdateSkinBonePoses):

这里很明显就是更新正在执行的skinng的数据了。

更新数据:

以opengles3为例,像前面两种更新都会TransformFeedbackSkinningInfo::UpdateSourceData或者TransformFeedbackSkinningInfo::UpdateSourceBones。UpdateSourceData是更新蒙皮顶点变化后的索引和权重最终更新到vboData(unity中支持1,2,4个骨骼权重)。然后通过ubo的方式更新。

UpdateSourceBones则是更新骨骼矩阵,也就是影响顶点变化的信息。并放到m_CachedPose。然后在TransformFeedbackSkinningInfo::SkinMesh中执行ubo绑定。

skinmesh的数据:

提交数据到线程组并执行线程(kGfxCmd_SkinMesh):

最终执行到skinmesh。

其他记录:

GPUSkinning启动与更新:

GPUSkinning的启动是在SkinedMeshFilter中的SkinMesh开始的。他会分为xbox和dx11和其他架构的区别。

GPUSkinning也可以通过GfxDeviceWorker的RunCommand更新。

如果是更新骨骼信息则通过GfxDeviceWorker的kGfxCmd_UpdateSkinBonePoses指令来更新。他会拿到gpuskinninginfo以及骨骼数量以及骨骼矩阵来给到UpdateSkinBonePoses。

如果是直接驱动会走SkinnedMeshFilter的SkinMesh。

也就是说unity会初始化skinmesh,然后又骨骼更新不会直接走skinmesh而是走GfxDeviceWorker的指令更新。

接下来主要介绍opengl3.0和dx11的区别。

opengl3.0:

数据准备:

如果是在opengl3.0的话会执行到GfxDeviceGLES30中的UpdateSkinBonePoses。强制转换为TransformFeedbackSkinningInfo,然后更新骨骼信息UpdateSourceBones。

UpdateSourceBones是更新骨骼相关信息的。

他会先删除以前的vao,重新设置uniformtfmethod,uniformbuffertfmothod,texturetfmethod。

DoBoneMatrixUpload来绑定骨骼缓存。他是获取到我们的buffer的指针地址,然后把cachedPose的矩阵写入到指针中,其实他是用了一个float的数组来存储。最后用UnmapBoneBuffer来调用opengl接口来存储,比如针对texture,他会绑定texture,设置texture的参数,最终提交。

然后PrepareVAOAndShader来准备vao以及shader。首先通过GetTransformFeedbackShaderProgram来获取shader,如果有缓存就从缓存中取,如果没有则通过opengl接口创建并缓存。接下来就是创建顶点属性数组,根据顶点,法线,切线以及蒙皮的权重数量来确定顶点属性数组。

驱动:

然后会通过SkinnedMeshFilter的SkinMesh的下一步执行到TransformFeedbackSkinningInfo的SkinMesh。他会把shader插入到s_currTFQueue中,Flush后开始每个s_currTFQueue的对象执行doTFSkinning。他会拿去每个TransformFeedbackSkinningInfo的数据执行vbo的缓存,vao的绑定,渲染目标相关内容。渲染完成后就清空opengl对象的数据。

这里要注意shader上是通过GetTransformFeedbackShaderProgram来设置的,他主要更改的是顶点着色器,通过std::string shadercode = buildTFVertexShaderCode(shaderChannelsMap, bonesPerVertex, maxBoneCount, method);这句来改变。buildTFVertexShaderCode里是对应的顶点着色的信息。

在buildTFVertexShaderCode里会存在一些默认的gpuskinning顶点变换的方法。关键在于坐标矩阵的变化,他会拿骨骼索引与骨骼权重来变换顶点的坐标矩阵,最后给到输出的顶点变换。

然后无论是dx还是opengl都会通过device.GetFrameStats().AddDrawCall添加drawcall,三角形等的显示数据。

opengl的shader执行流程:

vao上就是先绑定确定的顶点数据,然后包括法线切线也绑定,之后就是蒙皮的信息确定顶点跟骨骼的关系。

shader是直接走gl的流程,创建着色器glCreateShader,替换着色器中的源代码glShaderSource,glCompileShader编译一个着色器对象,glGetShaderiv()检测着色器编译是否成功,glCreateProgram创建一个空program并返回一个可以被引用的非零值,program对象是可以附加着色器对象的对象。glAttachShader将着色器对象附加到program对象,glTransformFeedbackVaryings配置要从着色器返回的变量。glLinkProgram连接一个program对象。

dx11:

SkinOnGPU会执行到StreamOutSkinnedMesh中的SkinMesh。这里的操作是:

汇编执行:

如果是dx11,他会有个流输出缓冲区(streaming output buffers).在GetMemExShader中获取指定的shader代码到code里(GetMemExShaderCode),在GetMemExShaderCode里需要通过三维数组来获取指定的shader,这个三维数组决定是否要获取位置,法线,切线信息和他们的排列组合,然后从流输出缓冲区输出数据。然后他用code来实现顶点着色和几何着色和输入信息。这个code是一个byte流,里面是用一个cbuffer存储bones的数据。然后直接汇编上直接计算骨骼权重与顶点的关系来偏移顶点。比如g_StreamOutSkinVS_Position_Tangent_1_128这个类型就是一个128的bones的4x3的矩阵数组,然后通过骨骼的信息与权重在汇编中完成偏移。

vbo绑定:

然后在SkinMesh中通过vbo绑定流输出缓冲区,然后获取指定的顶点着色偏远着色以及几何着色。最后再解绑流输出缓冲区。

获取到代码数据后,通过d3d11的接口指定顶点着色CreateVertexShader,几何着色CreateGeometryShaderWithStreamOutput。最终给到外部的ID3D11DeviceContext来设置顶点,几何,片元着色。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值