unity中一件衣服如何穿到人物身上

unity中一件衣服如何穿到人物身上,第1张

在unity里面,情况也是如此,不过再复杂一点展开。

1、骨架就是transform。不像maya和理论那样,是一种实体的单独的存在。在unity里,骨架就是transform的层次关系。一个骨头就是一个transform。这个人体的骨架(Transform)组织结构一般是abdome(spine,LeftUpLeg,RightUpLeg),abdome是根(有时用hip),向上是spine(neck,LeftUpArm,RightUpArm)。这个在哪里都差不多。关键是root,就是abdome。在unity里,引用骨架都是靠它。

2、Mesh。因为Unity里的Mesh有绑骨和未绑骨两种(在哪里都差不多)。在导入资源的时候,unity会为绑骨的Mesh自动生成一个SkinnedMeshRenderer,为未绑骨的生成一个MeshFilter和一个MeshRenderer。不精细的人物,头盔、手、武器(甚至靴子)等都不用绑骨,像骑马与砍杀,只需要把armor绑骨就好。

不绑骨情况:MeshFilter负责从文件中取出真实的Mesh(这里用的是Script里的类来表示,具体可以查reference)。MeshRender负责显示。这种想要固定在人体上,其实很简单,把这个GameObject的tansform的parent设置为需要绑定的骨头的transform就好。(比如武器,transformparent=item_l,item_l是左手一个绑定武器骨头)所以,缺点也很明显,一个mesh只能绑定到一个骨头,也就是这个mesh不会变形。(这个可以作为绑骨和不绑骨的依据,看Mesh是否需要变形,所以头盔,武器都不需要绑骨(仅在unity中成立))

绑骨情况:SkinnedMeshRenderer有俩个重要成员,一个是Mesh,一个是Bones。当然,Mesh里有每一个顶点的绑骨数据,但这里存的是序号。就是第几个骨头,并没有指明是哪个骨头,但是如果给一个根骨头就能推测出所有的骨头了。这里的Bones把所有的骨头都列出来了,至于顺序,有点扯淡,没啥规律(调试结果)。问题出来了,那SkinnedMeshRenderer里的骨头这么没顺序,Mesh里的骨头序号怎么对应过来呢?好吧,仔细想想,其实没那么复杂。因为SkinnedMeshRenderer里包含Mesh和Bones两个成员,由于都是一起生成的,那么就一个坑埋一个人,正好就对应起来了。之所以要这么个Bones列表,是因为要把它画成transform树吧。

这样就再回答一个问题,如何换装备?原SkinnedMeshRender对应的骨骼已经存在,不可能销毁它(还有其他部分要用),所以就修改SkinnedMeshRenderer本身就好。要改的有两个值(加上材质三个):Mesh和Bones。其实,原Bones根本不用变,只需要把Mesh变了就好(除非你的绑骨不是一帮人做的)。详细代码看看Unity有个官方项目。另外,我觉得吧,连SkinnedMeshRender都不用 *** 纵,直接重新生成就好。看文章最后的代码。

动画部分最有爱。其实呢,layer这个玩意,用来分组比较合适。优先级这个特点也是可以用的,不过寄太大信心。一个layer可以设置同样的叠加方式(累加,混合),控制方式(只控制上半身)。一般不同动画都放在不同层,相同功能动画在同一层,比如向左砍人和向右砍人。另外,我们动画一般都是自己搞到的一个一个片段,如果你不是动画师,还是不要用啥累加和混合了。用一些独立的动画,让他控制身体的某些部位就好。

所以,综合看,人物控制,在unity 里,换装备,换武器都是可行的。不知道咋了,网上就是搜不到如何换装的,搞到我自己研究了好久。。。

另外,最近的新发现,升级到4后,有个mecanima模块,用来做动画重定位的,这个叫帅啊。我的以下代码没办法处理动画,因为动画之前无法重定位。但是可爱的unity的新功能来了,给每个armor和每个动画都创建一个对应的avatar,然后就直接可以用一套动画驱动所有人了(虽然表面上我们显示的是一个人,但是在内部,实现这种换装方法用的是好几个独立的人体骨骼,当然,这种方法要求每个独立的骨骼都是相同的)。

附上换装代码。

#pragma strict

public var O_body_r:GameObject;

public var O_hand_L_r:GameObject;

public var O_hand_R_r:GameObject;

public var O_helmet_r:GameObject;

public var O_calf_L_r:GameObject;

public var O_calf_R_r:GameObject;

public var O_weapon_R_r:GameObject;

public var body1_r:GameObject;

private var mBody:GameObject;

private var mHand_L:GameObject;

private var mHand_L_P:Transform;

private var mHand_R:GameObject;

private var mHand_R_P:Transform;

private var mHelmet:GameObject;

private var mHelmet_P:Transform;

private var mCalf_L:GameObject;

private var mCalf_L_P:Transform;

private var mCalf_R:GameObject;

private var mCalf_R_P:Transform;

private var mWeapon_R:GameObject;

private var mWeapon_R_P:Transform;

function Start () {

}

private var ifIs:boolean=true;

function Update () {

if(InputGetButtonDown("Fire1")){

Generate(ifIs);

ifIs=!ifIs;

}

}

function Generate(num:boolean){

if(mBody){

Destroy(mBody);

}

if(num==true){

mBody=Instantiate(O_body_r,transformposition,Quaternionidentity);

}else{

mBody=Instantiate(body1_r,transformposition,Quaternionidentity);

}

mHand_L_P=mBodytransformFind("abdomen/spine/thorax/shoulderL/upperarmL/forearmL/handL");

mHand_L=Instantiate(O_hand_L_r,mHand_L_Pposition,Quaternionidentity);

mHand_Ltransformparent=mHand_L_P;

mHand_LtransformlocalRotation=QuaternionEuler(0,270,90);

mHand_R_P=mBodytransformFind("abdomen/spine/thorax/shoulderR/upperarmR/forearmR/handR");

mHand_R=Instantiate(O_hand_R_r,mHand_R_Pposition,Quaternionidentity);

mHand_Rtransformparent=mHand_R_P;

mHand_RtransformlocalRotation=QuaternionEuler(0,270,90);

mWeapon_R_P=mBodytransformFind("abdomen/spine/thorax/shoulderR/upperarmR/forearmR/handR/itemR");

mWeapon_R=Instantiate(O_weapon_R_r,mWeapon_R_Pposition,Quaternionidentity);

mWeapon_Rtransformparent=mWeapon_R_P;

mWeapon_RtransformlocalRotation=QuaternionEuler(0,270,90);

mCalf_L_P=mBodytransformFind("abdomen/thighL/calfL");

mCalf_L=Instantiate(O_calf_L_r,mCalf_L_Pposition,Quaternionidentity);

mCalf_Ltransformparent=mCalf_L_P;

mCalf_LtransformlocalRotation=QuaternionEuler(0,270,90);

mCalf_R_P=mBodytransformFind("abdomen/thighR/calfR");

mCalf_R=Instantiate(O_calf_R_r,mCalf_R_Pposition,Quaternionidentity);

mCalf_Rtransformparent=mCalf_R_P;

mCalf_RtransformlocalRotation=QuaternionEuler(0,270,90);

mHelmet_P=mBodytransformFind("abdomen/spine/thorax/head");

mHelmet=Instantiate(O_helmet_r,mHelmet_Pposition,Quaternionidentity);

mHelmettransformparent=mHelmet_P;

mHelmettransformlocalRotation=QuaternionEuler(0,270,90);

}

T是组件类型

比如mesh就是

transformgameObjectGetComponent<Mesh>()

我举个别的例子

curObjtransformFind ("mesh_body")GetComponentsInChildren<SkinnedMeshRenderer> (true) [0]sharedMaterials[0]color; 这个例子里color是main color,要是获取tinycolor啥的话就是sharedMaterials[0]GetColor("_TintColor");

简化模型

最小化模型网格中的顶点和面的数量,避免复杂的网格。

使用纹理贴图代替复杂的网格

考虑用法线贴图对比高度贴图。法线贴图适用于伪造模型表面凸起和凹陷光照的简单纹理贴图。

高度贴图使用一张纹理来制作一种非常传统的3D表面几何图形。高度贴图比法线贴图优越是因为它们不仅定义了表面凸起和凹陷,而且提供了平行视差。作为一个着色器,它们的计算开销很大,只是没有网格的开销那么大。

限制需要绘制的对象

遮挡剔除(occlusion culling),在摄像机看不见对象时禁用对它们的渲染,因为它们被其他对象遮挡了。

Global Fog(迷雾限制),减少场景中细节渲染,其基于距离,比迷雾限制更远的对象将不会被绘制。

对细节分级或LOD分组,近处的物体用细节模型渲染,远处的模型则用简化的模型渲染,是一种简化几何对象的好方法。

光照和阴影的性能

节约使用实时光影,当某个对象投射阴影时会生成一个阴影贴图,它会被用于渲染其他可能接受阴影的对象。阴影有很高的渲染开销而且通常需要高端的GPU硬件。

其他技术如灯光探测器(实时或烘焙)和着色器的选择。

优化脚本

Update()回调函数每一帧都会被调用。移除不用的更新,使用一个状态变量和if语句在它们不需要时停止计算。内存管理,数学与物理。

批量处理

Unity是将不同的网格归类到一个单独的批处理中,这个批处理会被立即放进图形硬件。这比单独发送网格快很多。网格实际上先被编译进一个OpenGL顶点缓存对象或一个VBO,这是渲染流水线的低层细节。

每一个批处理调用一次绘制,在一个场景中减少调用绘制次数的比减少顶点或三角形的实际数量的效果更有意义。

共有两种类型的批处理——静态批处理和动态批处理

首先,确认在Player Settings中启用Static Batching和Dynamic Batching。

对于静态批处理,简单地通过在Unity的Inspector中为场景内的每个对象勾选Static复选框以标记对象为静态。把一个对象标记为静态是告诉它将永远不能移动,动画或缩放。Unity将自动把这些共享相同材质网格放在一起形成一个大网格。

共享相同材质的网格,所有这样的网格在一个批处理中必须有相同的材质设置——相同的纹理,着色器,着色参数及材质的指针对象。

对于动态批处理,那些没有标记为Static的对象,Unity将尝试把它们放进批处理,即使它会是一个更慢的过程,因为它需要考虑逐帧动画(CPU开销)。共享材质的需求依然存在,当然还有其他的限制,比如顶点个数(小于300个顶点)和统一的Transform Scale规则。只有Mesh Renderers和Particle Systems使用批处理,这意味着蒙皮网格,衣服,尾迹渲染以及其他一些类型的渲染组件并没有使用批处理。

多通道像素填充

多通道像素填充就是某些高级渲染器的工作方式。光照和材质效果,比如多光照,动态阴影及透明度(Trransparent和Fade Render模式)都是以这种方式实现的。

针对项目,可以选择优化并避免通道像素填充在一起,或者理解清楚什么样的场景需要高性能,什么样的场景需要高保真,需要仔细的策划这个场景。

使用Light Probes以很低的成本模拟动态对象的动态光照。

在Quality Settings中把同时发生的光照的全部数量设置为1。

其他渲染技巧

创建2048分辨率的纹理并导入到默认的1024的设置,这样可以加速渲染。

针对无阴影使用高质量的设置渲染到Android时,需要切换目标平台到PC,使用高分辨率烘焙光照并开启硬阴影和软阴影,再切换回Android。

针对低级设备的优化或将程序分为高低版本。

Unity内置的性能评估工具——Stats窗格和Profiler窗格

Game面板中可开启Stats窗格

CPU:获取到当前占用CPU进行计算的时间绝对值,或时间点,如果Unity主进程处于挂断或休眠状态时,CPU time将会保持不变。

Batches:即Batched Draw Calls,是Unity内置的Draw Call Batching技术。

什么叫做“Draw call”,CPU每次通知GPU发出一个 glDrawElements (OpenGl中的图元渲染函数)或者 DrawIndexedPrimitive (DirectX中的顶点绘制方法)的过程称为一次Draw call,一般来说,引擎每对一个物体进行一次DrawCall,就会产生一个Batch,这个Batch里包含着该物体所有的网格和顶点数据,当渲染另一个相同的物体时,引擎会直接调用Batch里的信息,将相关顶点数据直接送到GPU,从而让渲染过程更加高效,即Batching技术是将所有材质相近的物体进行合并渲染。

Tris:摄像机视野(field of view)内渲染的三角面总数量

Verts:摄像机视野(field of view)内渲染的顶点总数

Screen:当前Game屏幕的分辨率大小,58M表示总的内存使用数值

SetPass calls:描述渲染性能开销

Shadow casters:表示场景中有多少个可以投射阴影的物体,一般这些物体都作为场景中的光源。

visible skinned meshed:渲染皮肤网格的数量

Animations:正在播放动画的数量

Network:网络情况

Unity中的Profiler选项是一个性能探测工具,可以报告游戏中的哥哥区域花费的时长,包括渲染和脚本。它记录游戏中随着时间的统计数据并以时间线图表展现出来。点击可以逐帧查看细节

关键词

MeshRenderer m_meshrender = 通过任意方法找到药水的物体GetComponent<MeshRenderer> ();

m_meshrendermaterial=你的材质 ;

遮挡剔除 :在我们的场景中,如果物体1在Camera渲染中遮挡了另一个物体2,那物体2就不会再Camera中进行渲染,虽然物体2没有在Camera中进行渲染但是在整个游戏场景中这个物体同样存在。为了优化效率,这里就需要使用遮挡剔除。

   Lod : 如果一个物体离我们的Camera很远,我们自然就看不见这个物体(或者只能看见一个“小点”)。但是这个物体在场景中仍然会根据它的顶点结构进行渲染并消耗性能。这时候为了优化,如果它离我们的Camera距离很远,我们就不需要对它进行渲染,也就是Lod。

我们的LOD以及Occlusion,都是基于GameObject的MeshRender组件来实现的。只有掌握好核心点,不让它们进行渲染,这样减少了Draw Call自然就优化了性能。(主要为什么是让MeshRender组件失活,因为我们直接把整个游戏对象都失活了,那所有的碰撞信息也全部都会失效。)

用一个相机单独照射3D模型和粒子,把相机的图形映射到RenderTexture上,把RenderTexture的图形UITexture,就能通过NGUI的Clip对UITexture进行裁剪。

以上就是关于unity中一件衣服如何穿到人物身上全部的内容,包括:unity中一件衣服如何穿到人物身上、unity中GetComponent获取组件中的材质的颜色,用C#写、Unity对项目性能优化的实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9527625.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存