美文网首页
Unity 分块Skin Combine

Unity 分块Skin Combine

作者: superowner | 来源:发表于2019-03-08 21:09 被阅读0次
    03c9564fd238b517702e084162a59682.jpg

    这里的分块Skin Combine指的是,把零散的skin mesh renderer组建,合并为若干块
    比如我有15块skin,现在想合并为头和body两块,当然,网上的教程一般是无法实现的,
    目前网上的都是合并为一块,但是对于低模可能不错,中模以上外加Blendshaps就完全GG了,这里需要一点骚操作;

    我们合并的目的是,把含表情(Blendshaps)的skin独立,这里就是头,包含眼睛,舌头等等
    把Blendshaps独立出,在一个相对顶点数较少的skin里的意义非常重大,因为,Unity的Blendshaps是非常呆笨的,他会在Blendshaps更新的时候,更新Blendshaps所在skin的mesh的所有顶点偏移,即使是这个顶点没有移动也会计算!这里性能开销很大!重复三遍。所以,聪明的任天堂公司,就没有使用fbx自带的Blendshaps功能,而是自定义Blendshaps功能,也非常简单,就是获取目标mesh的pose,然后对原版的mesh进行插值到目标mesh,这样可以有效减少顶点的计算!!因为,老任只需要计算部分需要更新的顶点即可,在初始化的时候安排一下即可!甚至还不需要用skin,用mesh即可,甚至这个都不需要,初始化取得Vector3[]数组后,直接Destroy都可以
    性能大大提高!
    如下:


    ffggfg.PNG

    表情这里我们一般来说,只取最后一帧数据,也就是说,从0-100是靠liner插值实现,所以你可以用Vector3[]
    读取保存,之后重建Blendshaps也so easy,也可以通过bakedmesh函数实现mesh拷贝,第二个参数写ture

        public SkinnedMeshRenderer[] SMR1, SMR2;
        public Transform RootBone;
        private HumanBone[] humanBones;
    
        // Start is called before the first frame update
        void Start()
        {
            humanBones= CreateHumanBone(out Dictionary<HumanBodyBones, Transform> boneMap);
           
            CombineSkin(SMR1,this.gameObject,0);
            CombineSkin(SMR2, this.gameObject,1);
            //CombineSkin(this.gameObject);
            GenericAvatar(humanBones, boneMap,out Avatar avatar,out Animator ani);
        }
    

    详细的代码不解释,GenericAvatar的代码可以git搜mmd for unity查看里面的实现,一模一样,这里SMR1, SMR2两个数组就是我们需要合并的内容,拉进去,注意需要把所有的skin都拉到这两个或多个SMRX里,否则后面会skin丢失!
    然后这个CombineSkin()函数就是网上的普通的合并mesh的函数,只是,我们这里合并部分mesh而已
    当然CombineSkin的多少取决于你,你也可以遍历判断表情在哪个skin,动态解析
    或者,以65k顶点数为一组进行合并,在Unity2017.3及以后,单mesh 65k的限制没有了,大概支持65x2k的顶点数应该够用了吧
    你可以这样:

    #if UNITY_2017_3_OR_NEWER
                //print("vertexCounter:"+ vertexCounter);
                if (vertexCounter> 65535)
                    r.sharedMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
    #else
                    throw new NotImplementedException(String.Format("exceed 65535 vertices: {0}", integrator.Positions.Count.ToString()));
    #endif
    

    最后一步GenericAvatar,顾名思义,就是重建Avatar,这个需要huomanoid bone,我们可以合并前,通过anim.GetBoneTransform(h_bone)获取,最后重新对Animator的Avatar赋值即可实现
    还有一些技术细节比如T-POSE这些你们就自己解决吧,不难
    合并前:


    fsdsdf.PNG

    合并后:


    dfsdfsdg.PNG

    这里,怎么说,其实你有单独的骨架fbx,那么你不必做一步GenericAvatar,这一步并不是必须的,但是对于没有单独骨架的模型,就是需要的,或许是我代码结构不对,另外,还有一种技术可以不必GenericAvatar,就是把所有的骨骼名字通过GetBoneTransform这个函数,映射到标准人形骨骼名字,Unity会自动识别

    相关文章

      网友评论

          本文标题:Unity 分块Skin Combine

          本文链接:https://www.haomeiwen.com/subject/nnmdpqtx.html