unity gpu instance skin mesh骨骼动画

本文详细介绍了如何使用GPU驱动骨骼动画的实现过程,包括从Unity中记录和回放动画,计算并存储骨骼矩阵到纹理,以及在着色器中读取和应用这些矩阵。通过将动画数据转移到GPU,提高了动画的渲染效率。同时,提供了相应的Unity工程代码示例,展示了如何生成和更新动画矩阵纹理,并在Shader中进行实例化渲染。

 运行效果图如上

原理很简单,

1 先对动画进行采样(利用Animator StartRecording/Update/StopRecording这三个接口)

2 然后回放(利用Animator StartPlayback/Update/playbackTime这三个接口)

3 从SkinnedMeshRenderer里取出mesh数据(该mesh数据应该是包含bone index的)

对每个bone(就是transform)计算变换矩阵

4 将生成的矩阵数据存入纹理

5 将纹理传递给shader,根据当前动画播放到哪一帧,计算出纹理采样索引(利用shader参数BLENDINDICES,该参数在mesh有bone idx数据情况下,会由unity自动传递给shader)

如上图所示,观察mesh数据,有红框里这样的,就是包含bone idx的

计算骨骼矩阵:

原理很简单

骨骼有根节占, 每个骨骼节点有父子关系,子节点相对父节点有相对的旋转平移,记录为<矩阵M>

根据矩阵的结合律,把子节点依次按父节点回朔,对应的<矩阵M>依次相乘,就可以得到该节点

在世界空间中的新的变换矩阵

上代码,计算子节点的变换矩阵:

            for (int bone_idx = 0; bone_idx < bones.Length; ++bone_idx)
            {
                {
                    Transform tmp_bone = bones[bone_idx];
                    List<Transform> lst_parent = new List<Transform>();
                    lst_parent.Add(tmp_bone);
                    while (tmp_bone.name != gdata.root_name)
                    {
                        tmp_bone = tmp_bone.parent;
                        if (!tmp_bone)
                            break;
                        lst_parent.Add(tmp_bone);
                    }

                    Matrix4x4 tmp_mtx = bindposes[bone_idx];
                    foreach (var tnode in lst_parent)
                    {
                        Matrix4x4 mat = Matrix4x4.TRS(tnode.transform.localPosition, tnode.transform.localRotation, tnode.transform.localScale);
                        Matrix4x4 tm = tmp_mtx;
                        tmp_mtx = mat * tm;
                    }

                    for (int row_idx = 0; row_idx < 4; ++row_idx)
                    {
                        var row = tmp_mtx.GetRow(row_idx);

                        tex_clr_identity[texel_index_identity++] = new Color(row.x, row.y, row.z, row.w);
                    }
                    Debug.Log(bone_idx + ":" + bones[bone_idx].name + " " + tmp_mtx);
                }
            }

假设动画有10帧,骨骼有20个,那么生成的动画矩阵个数为200个,一个矩阵16个浮点数,占4个像素

要显示某一帧动画,在shader根据 帧数*(20*4) +(bone_idx*4)索引到该节点的矩阵

shader代码

Shader "lsc/gpu_instancing"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            //启用gpu instancing
            #pragma multi_compile_instancing 

            //开启主灯光的阴影
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile_fragment _ _SHADOWS_SOFT
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            //自定义数组,保存每个实例的颜色
            StructuredBuffer<float4> _instancing_color;
            StructuredBuffer<int> _ani_matrix_index;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                uint4 vBones : BLENDINDICES;
                float4 vWeights : BLENDWEIGHTS;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
               
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值