unity 以共享骨骼的形式实现换装功能

这篇具有很好参考价值的文章主要介绍了unity 以共享骨骼的形式实现换装功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、另一种思路

 另一种更换人物服饰模型的方式(合Mesh),参看此篇博客:https://blog.csdn.net/f_957995490/article/details/108985716

二、模型

 人物模型的显示所依靠的是骨骼与其上的蒙皮。就类似于我们人体组成部分,有骨头,有皮肤(当然还有器官、神经等等)。
 如果我们需要做出动作的话,就要控制自身各部位做出相应行为。那么模型也是如此,人物动画系统将会控制各关键骨骼的运动,引擎会为我们补全中间骨骼的运动轨迹,及骨骼上的蒙皮形变过程。
unity 换装,unity
 可以看到,所有的模型可以分为两个部分,骨骼树和模型。我们模型就是绑在自身的骨骼树上的,换句话说,骨骼树中包含了当前模型上所需要的所有骨骼结点。

三、SkinnedMeshRenderer

 在unity中将这骨骼与蒙皮整合成了一个组件——SkinnedMeshRenderer。
unity 换装,unity

 当然,SkinnedMeshRenderer的功能是非常强大的,本文只介绍换装所需用到的几项:
1、RootBone
 这是该模型绑定所对应骨骼的根骨骼这在Inspector视窗下是可以直观看到的,到然后也是允许通过拖动来改变参数
2、bones
 这是该模型所绑定的所有骨骼,这在Inspector视窗下是无法看见的,只能通过代码的形式进行获得,当然,它是允许通过代码对骨骼进行修改的。

gameObject.GetComponent<SkinnedMeshRenderer>().bones

 这里你所获得的就是由所有绑定的骨骼所组成的数组。数组数据以RootBone为根结点,深度优先进行遍历所得。

四、换装的实现思路(本文将人物拆分为了五个部位,头发,头,上身,下身,脚)

 把所有用到的服饰模型像拼积木一样全部绑到一套骨骼树上,哪个部位需要更换,就把对应的部位拆下来绑上替换的。
 首先在场景中加载六个部分,总骨骼树、头发模型、头模型、上身模型、下身模型和脚模型。分别遍历五个部位模型获取需要绑定的根骨骼(RootBone)及所有绑定的骨骼结点(bones),将之替换成总骨骼树上对应名称的骨骼结点。最后将各部位中已经没有用的骨骼树销毁。这样一个人物模型就拼好了,由于以这种形式生成的人物是由五个部位的子物体及骨骼树组成的,所以在换装,也就是替换服饰模型的时候,只需要找到对应的部位模型进行销毁和替换模型的骨骼绑定就行了。

五、模型准备

 准备一个包括了所有模型所需骨骼结点的骨骼树(下文称最全骨骼树)和所有替换用服饰模型。
 因为我们将最全骨骼树作为整个人物模型的父节点,所以在其上挂animator动画组件。如果你需要将动画模式设置为CullUpdateTransforms,那么还需要挂载一个空的MeshRenderer。具体原因可以参看:https://blog.csdn.net/xinzhilinger/article/details/110673046,此处不多赘述。
unity 换装,unity

六、实现过程

 将所有六个预制体生成(最全骨骼树、头发、头、上身、下身和脚),并将五个需要替换的服饰部件父物体设置成骨骼树。
 调用脚本拼接人物模型(传入最全骨骼树):
注意:最全骨骼树的根结点命名需要为“DM_ACTOR_BIND”

public class UCombineSkinnedMgr
    {
        //骨骼树下所有骨骼节点
        Dictionary<string, Transform> transforms = new Dictionary<string, Transform>();

        /// <summary>
        /// 使用共享骨骼的方法
        /// 只合骨骼信息
        /// </summary>
        /// <param name="skeleton">传入的骨骼</param>
        public void CombineObject(GameObject skeleton)
        {
            //遍历获取骨骼树下所有骨骼节点
            Transform tran = skeleton.transform;
            Transform rootBone = tran.Find("DM_ACTOR_BIND");
            Transform[] allbones = rootBone.GetComponentsInChildren<Transform>(true);
            for (int i = 0; i < allbones.Length; i++)
            {
                transforms[allbones[i].name] = allbones[i];
            }

            //共享骨骼
            SetBonesSharing(tran);
        }

        /// <summary>
        /// 设置Mesh骨骼节点
        /// 允许每个部件的骨骼根节点不同
        /// </summary>
        /// <param name="target">目标对象</param>
        private void SetBonesSharing(Transform target)
        {
            SkinnedMeshRenderer[] targetSkin = target.GetComponentsInChildren<SkinnedMeshRenderer>(true);
            for (int i = 0; i < targetSkin.Length; i++)
            {
                targetSkin[i].receiveShadows = false;
                if (null != targetSkin[i].rootBone)
                {
                    //替换骨骼根节点
                    Transform tf = GetBoneObject(targetSkin[i].rootBone.name);
                    if (targetSkin[i].rootBone == tf)
                    {
                        //增加效率,如果已经替换过骨骼节点,就不需要再次替换
                        continue;
                    }
                    else
                    {
                        targetSkin[i].rootBone = tf;
                    }
                }
                Transform[] tfs = new Transform[targetSkin[i].bones.Length];
                for (int j = 0; j < targetSkin[i].bones.Length; j++)
                {
                    //替换所有骨骼节点
                    if (null == targetSkin[i].bones[j])
                    {
                        //如果骨骼节点为null
                        Debug.LogWarning(targetSkin[i].name + "  " + j);
                    }
                    else
                    {
                        tfs[j] = GetBoneObject(targetSkin[i].bones[j].name);
                    }
                }
                targetSkin[i].bones = tfs;
            }

            //删除加载的原有的骨骼节点
            Transform tran;
            for (int i = 0; i < targetSkin.Length; i++)
            {
                tran = FindChildInTransfromAllChild(targetSkin[i].transform.parent, "DM_ACTOR_BIND");
                if (tran != null)
                {
                    Object.Destroy(tran.gameObject);
                }
            }
        }

        /// <summary>
        /// 获取共享骨骼节点
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private Transform GetBoneObject(string name)
        {
            if (transforms.ContainsKey(name))
            {
                return transforms[name];
            }

            Debug.LogWarning("bone: " + name + " is missing");
            return null;
        }

        /// <summary>
        /// 查找所有父物体下物体
        /// </summary>
        /// <param name="transform"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        private Transform FindChildInTransfromAllChild(Transform transform, string name)
        {
            if (transform == null)
            {
                return null;
            }
            Transform[] childArray = transform.GetComponentsInChildren<Transform>(true);
            List<Transform> childList = childArray.ToList();
            return childList.Find(value => value.name == name);
        }
    }

七、示例工程

 后续上传文章来源地址https://www.toymoban.com/news/detail-757833.html

到了这里,关于unity 以共享骨骼的形式实现换装功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • mysql实现if语句判断功能的六种使用形式

    在Mysql数据库中实现判断功能有很多方式,具体又分为函数和if语句形式,函数的好处是可以作为sql的一部分来运行,而if语句则需要在存储过程中使用。 语法: 解释: 判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值 参

    2024年02月15日
    浏览(54)
  • [Unity] 利用Mixamo进行人物骨骼绑定并导入Unity(搞定材质缺失+骨骼缺失)

    本文介绍了一种将自己人物模型(无绑骨)利用Mixamo平台自动绑骨,并且导入到Unity当中生成对应骨骼并进行动画播放的方法。 Mixamo是Adobe旗下的一个基于web版的在线3D人物动画制作平台,可以更轻易的创建出3D人物动画。其自身提供众多3D模型和动画文件。当然我们也可以上

    2024年02月07日
    浏览(53)
  • openAI 通过php方式 发送请求,流数据形式传输,php 实现chatGPT功能

    此处使用的框架是 symfony ,可自行根据自己框架开发,大同小异,框架无所谓,主要是功能! 先上代码 :

    2024年01月19日
    浏览(54)
  • Unity体感设备KinectV2虚拟换装解决方案

    Unity创建一个新工程(我使用的是2020.3.25),KinectFouUnity插件版本:Kinect v2 Examples with MS-SDK 2.13,Kinect插件示例3D换装Demo场景:更换模型,绑定模型,以及材质更换即能实现网上很多的3D换装功能。 (1):KinectFittingRoom1 (2):KinectFittingRoom2 以上两个场景为官方自带的3D换装功

    2024年02月02日
    浏览(32)
  • AI 绘画Stable Diffusion 研究(十一)sd图生图功能详解-美女换装

    免责声明: 本案例所用安装包免费提供,无任何盈利目的。 大家好,我是风雨无阻。 为了让大家更直观的了解图生图功能,明白图生图功能到底是干嘛的,能做什么事情?今天我们继续介绍图生图的实用案例-美女换装的制作。 对于新朋友,想详细了解Stable Diffusion 的话,请

    2024年02月12日
    浏览(50)
  • 第三十一章 Unity骨骼动画

    关于骨骼动画的原理,我们这里不再详细介绍,有不清楚的可以回去看DirectX课程和3dsMAX课程。接下来,我们来讲解一下Unity的骨骼动画系统。Unity 的动画系统基于动画剪辑(Animation Clip)的概念,它的本质就是一小段动画,代表了一个游戏角色的动作,例如:走路,跑步,攻

    2024年02月08日
    浏览(64)
  • 【Unity】2D骨骼绑定·一(学习笔记)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 在大三学习王乐然老师指导的可视媒体开发实践中,使用Unity在动画,视频,骨骼绑定等内容上的学习遇到了瓶颈期,通过一系列的学习,使我在Unity的使用上有了更进一步的了解。 ** 不同格式之间的图

    2024年01月17日
    浏览(36)
  • 15.Unity2D 横版 骨骼动画 之 单张切片图骨骼动画+Aseprite像素画软件

      主目录 https://blog.csdn.net/qq_54263076/category_11900070.html?spm=1001.2014.3001.5482 b站视频:骨骼动画 1.直接单图片   骨骼动画绑定(最简单,直接绑定就行) 2.部件分开切片图  骨骼动画绑定(本教程主要讲述) 3.部件多图层   骨骼动画绑定(Aseprite像素画绘图没有psd文件类型,本

    2024年02月10日
    浏览(44)
  • 在 Notepad++ 中,你可以使用正则表达式的替换功能来实现将 trade_status 转换为驼峰形式

    在 Notepad++ 中,你可以使用正则表达式的替换功能来实现将 trade_status 转换为驼峰形式的 tradeStatus。 请按照以下步骤进行操作: 打开 Notepad++,打开你要修改的文件。 点击菜单栏的 “搜索”(Search)- “替换”(Replace),或者使用快捷键 Ctrl + H 打开替换对话框。 在替换对话

    2024年02月16日
    浏览(56)
  • Unity学习笔记(7) Unity2D骨骼动画制作流程

    用骨骼动画最大的好处就是方便之后做换装系统。 无论对3Dor2D游戏都是这样的。 这篇博文记录一下2D骨骼动画的制作流程,参考b站麦扣的系列教程: https://space.bilibili.com/370283072/channel/seriesdetail?sid=211996 用PS做一个将人物各个部件(骨骼)都分解开来的人物模型。 导出时注意

    2023年04月09日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包