位置: 编程技术 - 正文

Unity3D游戏开发之换装方法(Unity3D游戏开发pdf)

编辑:rootadmin

推荐整理分享Unity3D游戏开发之换装方法(Unity3D游戏开发pdf),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:Unity3D游戏开发毕业论文,Unity3D游戏开发基础,Unity3D游戏开发毕业论文,Unity3D游戏开发引擎,unity3D游戏开发,unity3D游戏开发,unity3D游戏开发,unity3D游戏开发,内容如对您有帮助,希望把文章链接给更多的朋友!

游戏内的角色,能够像纸娃娃换装那样子让玩家可以为自己的角色改变外观,一直是相当受欢迎的功能;一般而言,我们建好的 3D 模型,如果要将其中一个部位换成另外一个形状,最直接的就是将该物件部位的 Mesh 替换掉,那么外观就改变了,但这种方法如果运用在需要做动作的模型上,将发现被置换掉的部位不会正常动作,更糟的状况可能连模型显示的位置及方向都是错误的,所以,直接变更 Mesh 的方法只适用于静态模型物件,为此,我们必须找出更深入的方法来做换装的功能,幸好,此部份 Unity 已经有提供相关范例可以参考。

Unity 提供的人物换装范例可以从官网下载 Character Customization,或是开启 Unity 编辑器的 Window > Asset Store 在 Complete Projects > Tutorials 找到 Character Customization 下载并汇入到自己的专案中。这个范例提供相当完整的示范,而且考虑到实作于游戏中时,不可能一次把全部的资源都载入,所以将模型、材质、纹理等资源都包成 Asset bundle,只在要使用到时才载入需要的部份;也因为如此,对於不了解 Asset bundle 的情况下,要透过这个范例来直接学习换装也相对变得困难;另外,范例中也对资源规范了特定形式的命名规则,主要也是为了建立 Asset bundle 内容资料及从 Asset bundle 取出资源而设计,在不了解这些规则之前,想要透过此范例学习换装,有一定程度的难度;当然,如果愿意使用与范例中 characters 目录中两个人物的模型、材质、纹理完全相同的命名规则及档案配置方式,几乎可以直接套用到自己的游戏中,而不太需要了解内部的运作方式。

在 Unity 开启 Asset store,在Asset store 中找出 Character Customization 范例。

虽然,官方这个范例能够直接套用,但制作游戏常会有不同的客制化需求,如果不了解相关原理和流程的话,可能就无法自由灵活的运用,所以,以下将利用这个范例并排除掉 Asset bundle 的部份,直接在场景中完成纸娃娃换装的方法。

首先,先来看看模型的结构,从 Projects 视窗将 CharacterCustomization > characters > Female > Female 拉到场景中,在 Hierarchy 视窗将物件展开来,会发现几个名称相同并使用数字区别的物件,它们分别代表人物各部位的模型,由此可知,整个人物模型档包含多个相同部位的模型,而 Famale_Hips 则是整个人物的骨架结构,人物的动作则是设置在顶层物件(Female)的 Animation,所以这个模型档是个模型资源,而不是实际上要放到在场景中的目标物件。

每个部位有多个模型物件

了解模型档内容後,接下来先建立一个名为 TestChar 的 C# 程式档用来控制换装,为了方便测试,在 Projects 视窗将 CharacterCustomization > characters > Female > Female@walk 的 Animation Wrap Mode 改为 Loop,并在程式档的 Start() 内加入 animation.Play(“walk”),如此在执行状态将会使人物不断的做走路的动作。文章出处【狗刨学习网】

选择 Female@walk

Animation Wrap Mode 选择 Loop

Unity 官方这个范例,说穿了就是将模型档做为来源模型资源,然後再依照需求将各部位重新组合成一个新的目标模型,所以我们直接将人物模型 Female 拉两个到场景中,分别为它们命名为 Source 及 Target,依照以下步骤做些准备动作:

从 Projects 视窗将 CharacterCustomization > characters > Female > Per Texture Materials 依照名称把适当的材质球(Material) 拉给 Source 的每个部位(不包含 Female_Hips 及其子物件)。

Unity3D游戏开发之换装方法(Unity3D游戏开发pdf)

Source 物件是做为来源资源使用,实际在场景中不需要运作,所以直接点选 Source 物件并将 Inspector 视窗中 Source 名称栏位前的方框取消勾选来将它关闭。

Source 前面的方框取消勾选,取消勾选后会弹出对话视窗询问是否希望关闭全部的子物件,点击 Deactivate Chidren。把 Target 物件中除了 Famale_Hips 以外的子物件全部删除。把 TestChar 程式档拉给 Target 物件。Source 中的各部位名称应该都要有编号(例如 face-1 ),如果没有的话,加上编号。

完成以上的准备动作,接下来就要开始来写程式了,程式主要工作是先将 Source 中每个物件的 SkinnedMeshRenderer 资料取出储存在 data 变数中,data 的内容则是依照部位分类 接下来在 Target 加SkinnedMeshRenderer ,然后每个部位取出一个指定的资料,利用 CombineInstance class 及 Mesh.CombineMeshes() 将各部位模型合并,同时也重新排列材质,然後依照取出的 SkinnedMeshRenderer 的 bone 的名称,找到与 Target 的 Female_Hips 子物件内名称相对应的物件重建骨架列表,最后将这些重新组合建立的资料给 Target 的 SkinnedMeshRenderer,如此就可完成换装的动作,以下为程式说明:

//来源模型资源的物件public Transform source;//目标物件public Transform target;//模型资源资料private Dictionary<string , Dictionary<string,SkinnedMeshRenderer>> data = new Dictionary<string, Dictionary<string,SkinnedMeshRenderer>>();void Start () {//从来源模型资源取出各部位的 SkinnedMeshRendererSkinnedMeshRenderer[] parts = source.GetComponentsInChildren<SkinnedMeshRenderer>(true);foreach(SkinnedMeshRenderer part in parts){//利用 ? 字元分隔档名做为资料结构的 key,档名为 部位?编号 储存为 [部位][编号]=SkinnedMeshRenderer资料string[] partName = part.name.Split('?');// 在 data 加入资料if(!data.ContainsKey(partName[0])) data.Add(partName[0] , new Dictionary<string,SkinnedMeshRenderer>());data[partName[0]].Add(partName[1],part);}//目标物件加入 SkinnedMeshRendererSkinnedMeshRenderer targetSmr = target.gameObject.AddComponent<SkinnedMeshRenderer>();//从目标物件取得骨架资料 (Female_Hips 的全部物件)Transform[] hips = target.GetComponentsInChildren<Transform>();/** 开始 重组模型 *///初始化资料列表List<CombineInstance> combineInstances = new List<CombineInstance>();List<Material> materials = new List<Material>();List<Transform> bones = new List<Transform>();foreach(KeyValuePair<string , Dictionary<string,SkinnedMeshRenderer>> _part in data){//从资料中取得各部位指定编号的 SkinnedMeshRendererSkinnedMeshRenderer smr = new SkinnedMeshRenderer();switch(_part.Key){case “eyes”:smr = _part.Value[“1”];break;case “face”:smr = _part.Value[“1”];break;case “hair”:smr = _part.Value[“1”];break;case “pants”:smr = _part.Value[“1”];break;case “shoes”:smr = _part.Value[“1”];break;case “top”:smr = _part.Value[“1”];break;}//准备要组合的 MeshCombineInstance ci = new CombineInstance();ci.mesh = smr.sharedMesh;combineInstances.Add(ci);//排列新的材质列表materials.AddRange(smr.materials);//取得相对应名称的骨架物件来建立新的骨架列表foreach(Transform bone in smr.bones){foreach(Transform hip in hips){if(hip.name != bone.name) continue;bones.Add(hip);break;}}}//合并 Mesh 并写入至 Target 的 SkinnedMeshRenderertargetSmr.sharedMesh = new Mesh();targetSmr.sharedMesh.CombineMeshes(combineInstances.ToArray() , false , false);// Target 的 SkinnedMeshRenderer 写入新骨架列表targetSmr.bones = bones.ToArray();// Target 的 SkinnedMeshRenderer 写入新材质列表targetSmr.materials = materials.ToArray();/** 重组模型 结束 *///指定播放走路动作animation.Play(“walk”);}复制代码

写完程式后,记得把场景中的 Source 及 Target 两个物件分别拉给附属在 Target 物件上的 TestChar script 的 source 及 target 栏位;

程式动作都在 Start() 内进行,是因为最初目标物件并没有模型等资料,所以要先依照指定的各部位资料把人物建立出来并使它动作,而 smr = _part.Value[“1”]; 的 “1” 则是表示指定此部位的 “1” 模型资料,所以只要改变各部位的这个&#;,就能为人物配置不同的造型,当然,前题是来源模型资源必须要有这个编号的物件才行;以上程式码主要是测试及解说流程用,在实作上应该把标示 /** 重组模型 */ 这一段程式独立出来,在需要换装时,给予各部位指定编号来执行。

以上是 Unity 官方范例中处理换装的方法,它把各部位模型、材质等资料重新组合合并成单一的模型并重建骨架列表,如此即使看起来人物身上有其中一个部位被置换了,仍能持续正常动作;当查看 Target 物件时会发现它的子物件仍然维持不变,只有 Target 物件本身在 Inspector 视窗中的 Component 多出了 Skinned Mesh Renderer 及各部位的 Material,如果查看 SkinnedMeshRenderer 的 Mesh 栏位 也会发现看不到任何的 Mesh。

Target 物件的内容

这种做法的来源模型与材质数量必须相对应,否则模型的贴图将会变得不正常,也就是说如果裤子的 material 有两个,其他部位的 materail 只有一个,那麽结果模型上的贴图将与预期的不同;为了使各部位的 material 使用上更为弹性,前面的程式将做些修改,使它的各部位都是独立的 GameObject,如下所示:

//来源模型资源的物件public Transform source;//目标物件public Transform target;//模型资源资料private Dictionary<string , Dictionary<string,Transform>> data = new Dictionary<string, Dictionary<string,Transform>>();//目标物件的骨架private Transform[] hips;//目标物件各部位的 SkinnedMeshRenderer 资料(参照)private Dictionary<string , SkinnedMeshRenderer> targetSmr = new Dictionary<string, SkinnedMeshRenderer>();void Start () {//从来源模型资源取出各部位的 SkinnedMeshRendererSkinnedMeshRenderer[] parts = source.GetComponentsInChildren<SkinnedMeshRenderer>(true);foreach(SkinnedMeshRenderer part in parts){//利用 ? 字元分隔档名做为资料结构的 key,档名为 部位?编号 储存为 [部位][编号]=Transform资料string[] partName = part.name.Split('?');// 在 data 加入资料if(!data.ContainsKey(partName[0])){data.Add(partName[0] , new Dictionary<string,Transform>());//建立新的 GameObject 并使用部位名称来命名,指定为目标物件的子物件GameObject partObj = new GameObject();partObj.name = partName[0];partObj.transform.parent = target;//为新建立的 GameObject 加入 SkinnedMeshRenderer,并将此 SkinnedMeshRenderer 存入 targetSmrtargetSmr.Add(partName[0] , partObj.AddComponent<SkinnedMeshRenderer>());}data[partName[0]].Add(partName[1],part.transform);}//从目标物件取得骨架资料 (Female_Hips 的全部物件)hips = target.GetComponentsInChildren<Transform>();/** 开始 重组模型 */foreach(KeyValuePair<string , Dictionary<string,Transform>> _part in data){switch(_part.Key){case “eyes”:ChangePart(“eyes” , “1”);break;case “face”:ChangePart(“face” , “1”);break;case “hair”:ChangePart(“hair” , “1”);break;case “pants”:ChangePart(“pants” , “1”);break;case “shoes”:ChangePart(“shoes” , “1”);break;case “top”:ChangePart(“top” , “1”);break;}}/** 重组模型 结束 *///指定播放走路动作target.animation.Play(“walk”);}private void ChangePart(string part , string item){//从资料中取得各部位指定编号的 SkinnedMeshRendererSkinnedMeshRenderer smr = data[part][item].GetComponent<SkinnedMeshRenderer>();//取得相对应名称的骨架物件来建立新的骨架列表List<Transform> bones = new List<Transform>();foreach(Transform bone in smr.bones){foreach(Transform hip in hips){if(hip.name != bone.name) continue;bones.Add(hip);break;}}// 更新指定部位 GameObject 的 SkinnedMeshRenderer 内容targetSmr[part].sharedMesh = smr.sharedMesh;targetSmr[part].bones = bones.ToArray();targetSmr[part].materials = smr.materials;}复制代码

在建立 data 变数内容时,同时为每个部位建立 GameObject,另外也把变更部位内容的程式码独立出来为 ChangePart 方法,如此在每次需要变更该部位时,只要指定部位名及编号就可以直接为该部位换装,而不需要将每个部位都重建;因为每个部位都是 GameObject 实体,我们在 Hierarchy 或 Scene 视窗中点选该部位也可以清楚的从 Inspector 视窗中看到此部位内容,正因如此,每个部位就可以自由配置 Material 的数量了。

从以上程式中会发现换装除了把 Mesh 和 Material 从来源取出给目标置换之外,有个关键的地方是重建骨架列表,为什麽要重建骨架列表呢?最主要是变更 Mesh 之後的

SkinnedMeshRenderer.bones 及SkinnedMeshRenderer.sharedMesh.bindposes 数量有可能会不同而产生错误讯息 Number of bind poses doesn't match number of bones in skinned mesh

即使数量相同而没有错误讯息

SkinnedMeshRenderer.sharedMesh.bindposes 内的 Matrix4x4[] 资料也会因为数&#;不正确而发生执行期模型扭曲成奇怪形状的问题;这部份可以将 Female 模型档汇入到 3DS Max 中查看,以鞋子为例,在 Modify 视窗中,可以很明显看出 shoes-1 和 shoes-2 的 Bones 列表内容是不同的,所以在为模型物件变更 Mesh 的同时必须重建骨架列表。

以上的说明主要是用于了解换装所需要的做法,实作时,不太可能把游戏中的角色全身各部位的模型资料全部都载入做为来源资料,例如游戏中的武器有种,角色背包中有3种武器,但为了换装却把种武器都载入到游戏中,而实际上此角色最多也只能变换背包中的3种武器而已,这样无疑是浪费了种武器所占用的资源;所以在了解如何换装後,实作时应该尽量像官方范例那样把来源资源包装起来,只取出需要的资源来进行换装。

游戏开发学习方法概述 更多精彩:www.gopedu.com很多想自己尝试做游戏的同学,不知道从哪入手,经常是买本游戏引擎的书就开始看,看着看着就放弃了。因为路子不对,学游戏

Unity3d游戏开发之使用烘焙贴图教程(一) 关于灯光贴图,烘焙贴图如何在unity3d中导入及使用的基本教程。1,当您完成uvw保存到您的模型。uvw文件2,创建新uvw并将其更改为通道2。加载uvw前面创

狗刨学习网谈如何做好游戏制作人 作者声明:虽然我在狗刨学习网工作,但本文只代表我本人的观点,不代表狗刨学习网的任何形式的政策、行为等。引言我经常被问到的一个问题是:

标签: Unity3D游戏开发pdf

本文链接地址:https://www.jiuchutong.com/biancheng/372984.html 转载请保留说明!

上一篇:血条或者进度条(kui血条插件设置)

下一篇:游戏开发学习方法概述(游戏开发主要学什么)

  • 公司买房子可以贷款多少
  • 劳务报酬申报个税流程
  • 营业执照办理税务登记需要什么资料
  • 家具厂投入多少钱
  • 开淘宝店怎么做账
  • 交强险可以打折扣吗
  • 购入股票作为短期投资是什么凭证
  • 固定资产清理属于流动资产吗
  • 城市维护建设税免税
  • 印花税什么情况可以退
  • 捐赠的固定资产按什么计价
  • 公司进货可以计提折旧吗
  • 单位员工借款的认定
  • 公司购入房产账务处理
  • 办公室租赁合同需要交哪些税额?
  • 转售的物业
  • 二手房房产税税率
  • 一般纳税人适用税种及税率
  • 营改增的会计分录
  • 工会经费计税依据是应发还是实发
  • 贷款服务开票开具要求
  • 劳务外包收入公式是什么
  • 怎么限制路由器使用人数
  • 计提坏账准备的比例
  • 会计跨年业务的处理
  • 小规模开票运费怎么开
  • 锁定任务栏不管用
  • 加班车费报销计入什么科目
  • php二分查找算法两种方法
  • fg726p.exe
  • 材料采购计入资产负债表哪里
  • 购买加油卡能否抵扣
  • 结转已销售产品的实际生产成本会计分录
  • php 获取网页内容
  • thinkphp登录验证
  • vue自学
  • cynefin框架
  • 确认收入与结转成本会计分录怎么写
  • 航天金税税控盘运行环境
  • 2022年最新苹果平板电脑
  • mysql分库分表实践
  • 销售收入和销售收入净额的区别
  • 差旅费包括哪些费用
  • 商品进销差价在借方还是贷方
  • 货币资金的计税基础
  • 个人所得税计提会计分录怎么做
  • 外贸进项税额怎么算
  • 税务处理决定书撤销情形
  • 筹资现金流量净额
  • 房地产企业土地增值税清算
  • 绩效工资扣款违法么?
  • 甲供材的卸料由谁负责
  • 物流企业货损赔付标准
  • 中级会计实务主观题怎么给分
  • 暂估入账应该如何操作
  • 计提工资要附什么凭证
  • 销售商品发生的应收账款入账价值包括
  • 什么时候计提增值税发票
  • 其他业务支出的借贷方向
  • 基建待摊费用如何分摊
  • 支付宝如何支付医保费用
  • 增值税普通发票可以跨区域开吗
  • windows如何创建桌面快捷方式
  • centos5.4 安装
  • SpamSubtract.exe - SpamSubtract是什么进程
  • win10搜索功能不好用
  • win7word打开很慢怎么解决
  • Win10系统怎么添加字体
  • win7如何设置桌面背景图
  • unity的设置在哪里
  • vs2010配置opengl
  • 解决脱发的8个方法
  • javascriptweb
  • python event.pos
  • javascript基础笔记
  • 安卓中textview
  • linux查看shell脚本
  • 限售股转让如何交税
  • 地税逾期了怎么申报
  • 2020年山东录取人数
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设