unity3d由多个部分组成一个角色

摘自http://forum.unity3d.com/threads/16485-quot-stitch-multiple-body-parts-into-one-character-quot

So I have many many models.  Each has a skeleton, material, etc.

I want to take some of these and combine them into one so I can apply animation commands to one rather than many (and so they stay in sync).

I have one mesh, say MeshA with the following hierarchy:

MeshA
-AllJoint
-AllTrans1
-Take 001
-MeshA

Take 001 being a sample animation clip
MeshA being the mesh

MeshB is similar in hierarchy however has the same bone structure (down to every detail).  MeshA is a body, and MeshB is arms.

I want to "stich" MeshB into MeshA so that I can apply animations to MeshA and have MeshB work....

Currently, I just create a base object, put MeshA and MeshB under it, and apply animations to them individually (it gets really tedious with more than just these 2, specially when the animations get out of sync or I want to do blending).

How do I "stich" these 2 together as it says in the Unity2.1 features?

Ok, here we go, finally got around to jotting a bit down!
Bones - Just a hierarchy of GameObjects.  The transforms are what the system uses Animation Clips - Collection of vectors to modify transforms.  Animation clips reference the bone by name I believe (although I haven't tested this fully, it works in my scripts).
So, you want to stitch some models together to share the bones and share an animation component.  Took me a bit to figure this out, then again I'm a bit slow
Where does the information in a model object go in Unity GameObjects? Answer is, quite simply, in the components!
When an object is updated in the Unity engine it's components interact with Unity in different ways.  If it has a MeshRenderer component, then it has geometry data to send to the rendering system.  A rigid body component would send geometry data to the physics system for simulation.  And so on......
We all know a static mesh is easier to render than a dynamic one (one where the vertices are changing all the time) as the dynamic one causes the graphics card to do more state changes and thus slows down rendering.  Although today's technology is very capable of doing this without slowing down, developers tend to take that as a queue to overload the system with regards to dynamic objects.
With that I introduce you to MeshFilters, MeshRenderers and SkinnedMeshRenderers! These are the bread and butter of the models in unity!
A static Model (procedural), which requires no animation (bone animation), would need a MeshFilter to hold the Model Geometry and a MeshRenderer to render the geometry.  Being new to Unity from 2.0 and on I can only assume this was kept this way, meaning 2 separate components, to A. Stay backwards compatible in the engine and B. Allow for compiled geometry to quickly be accessed in an organized fashion.  I believe the MeshFilter stores the geometry source whereas it sends a compiled version to the MeshRenderer upon creation.  The MeshRenderer merely adds materials, shadows, and so on based on your configuration of the MeshRenderer.
A dynamic model (non-procedural) has the combination of the MeshFilter and MeshRenderer all built into one.  It stores the source mesh, does lookups for bone structures, compiles the geometry and then stores it in it's own renderer for when Unity requires it to be rendered.
That's all great, and probably somewhat inaccurate (Hey, I didn't promise you an insiders look into the Unity engine, just a compilation of all the testing I have been doing to get my own projects off the ground in addition to my decades of experience with creating engines in C++ and so on), but how do I add one model to another in code?  Alright, enough Unity Component Theory and on to application......
Adding objects to a Static GameObject: Simply add a MeshFilter, and set the sharedMesh variable to the mesh you want.  If you want a texture on that mesh, just add a MeshRenderer and set materials of that MeshRenderer to whatever materials you want displayed (some meshes have multiple UV layers, or multi-texturing, this is set in the MeshRenderer on which material is pointing to which UV set). A link to the MeshFilter Docs: http://unity3d.com/support/documenta...eshFilter.html A link to the MeshRenderer Docs: http://unity3d.com/support/documenta...hRenderer.html
Adding objects to a Dynamic GameObject: Yeay, get ready to get dirty!  First thing of great note is that the MeshFilter and MeshRenderer of the Static Object have been combined into one great SkinnedMeshRenderer.  I will talk more about that later but for now, lets talk about bones!  So, we have a bone structure in an existing GameObject, how do we identify it?  I mean in my models I see (in some cases, but I will get to exceptions later) the following objects under the root object after I import it:
RootImportedObject -AllTrans1 -AllJoint -InfoObject (named the same as the rootImportedObject)
When I look at the AllJoint I will see more children, something like this:
AllJoint -JNT_C1_Hip01 --JNT_C1_Leg_R01 --JNT_C1_Leg_L01 -JNT_C1_Spine01 --JNT_C1_Head01 ---JNT_C1_Head02
Each one of them is named.  Ok, so that's the bone structure, I need to keep that AllJoint intact!  The AllTrans1?  Not sure what that is, it has a control object, and then all the same bone names below it in the same structure as the AllJoint.  I deleted this from my model and noticed no change in animation, so I am not sure what it is for, although I can say it is merely a hierarchy of transforms just like the AllJoint is.
The InfoObject in the above hierarchy holds the components for my SkinnedMeshRenderer and any materials used. 
Exceptions: Now I feel it important to mention exceptions to what I have found above.  The importer does it's best to create the same structure for animated assets however based on how it was exported (and from what asset creation tool, or modeler), it might slip up from time to time.  Although it doesn't affect how the animation works, or looks, it affects how the information is kept in the hierarchy.   I HAVE found the InfoObject to actually be one of the bones; where a bone, one of the children bones deep down in the hierarchy, had the SkinnedMeshRenderer and Materials components.  So in a Script, I had to do a search on the game object for ALL Components in children for SkinnedMeshRenderers in order to locate them and copy them over to the target object.
So how do the animations actually work? The answer is, as it would seem, by name.  You call the clip by name, the clip calls the bones by name, and so on.  When you run an animation in the Animation Component it does a search (when you add the component the first time) through the Object it's attached to and through all it's children to find all the bones it needs to move/rotate/transform by name.  If I remove the JNT_C1_Leg_R01 object from my hierarchy above and try to run the animations associated with this model Unity will error out with a reference somewhere along the lines of "bone differences" or something (I forget the error).  BUT I can move JNT_C1_Leg_R01 somewhere else in the hierarchy, like parent it to the spine or head, and the animation will still work (although the visual outcome will be very funky as the original hierarchy is now different than intended, and a guy that is supposed to be running might look like he's doing some funky dance instead).
Ok, so the Animation works with the bones by name, how does that correlate to the actual mesh? By a predetermined array pointing to each bone of course.  The SkinnedMeshRenderer has a Bones array built into it, you simply create an array of those transforms (the bones above) and set that bone array to it.  The skinned mesh renderer looks at the bones and their transforms and then modifies the geometry of it's internal MeshFilter.  It then compiles the geometry and sends it to it's internal MeshRenderer (remember I told you that the SkinnedMeshRenderer combined the MeshRenderer and the MeshFilter).  The Internal MeshRenderer does it's magic on it and sends it to Unity's renderer for display.
Link to the SkinnedMeshRenderer: http://unity3d.com/support/documenta...hRenderer.html
Wonderful, you told me exactly what 36 hours of reading the documentation can tell me, how do i do it already? Ok ok....  We will take MyTorso and MyArm, both animated model assets I just imported into Unity and we will go through the scripting necessary to stitch the two together.  Now remember that their bones have to be the same setup; meaning they have to have bones by the same name or the same skeleton when they are exported.
So, Drag MyTorso and MyArm on to the scene of Unity.  Lets create a script that stitches MyArm INTO MyTorso leaving us with just MyTorso to animate and what not in other scripts.

Code:  
  1. var objPlayer : GameObject;
  2. var objLimb : GameObject;

Ahhhh, that fresh code smell!  We have two Editor Refferenceable objects   Add this script to any game object (even player), and drag MyTorso onto objPlayer and drag MyArm onto objLimb.  The first thing we will need to do is to look through objLimb for our SkinnedMeshRenderer, once we find it (or them, hehe, remember we can have multiple meshes and what not on them) we will then begin the construction on objPlayer.

Code:  
  1. AddLimb( objLimb, objPlayer );
  2. function AddLimb( BonedObj : GameObject, RootObj : GameObject )
  3. {
  4. var BonedObjects = BonedObj.gameObject.GetComponentsInChildren( SkinnedMeshRenderer );
  5. for (var SkinnedRenderer : SkinnedMeshRenderer in BonedObjects)
  6. ProcessBonedObject( SkinnedRenderer, RootObj );
  7. }

YEAY our first function!  I like to write independent functions so that I can easily move code from one project to another as much as possible.  So if your curious why somethings are in there that probably wont pertain to this tutorial, bare with me.
So above we send our objPlayer in as a root object (or destination object) and the objLimb's SkinenedMeshRenderer in as the target object (or our object we need to copy over).  I pass the Renderer in instead of the GameObject because we will need to re-find it to get it's info anyhow.  And since we can reference a gameObject from a component, it just seems best to pass what we are actually looking for.  You'll see that I do a search for all SkinnedMeshRenderers in the object, then iterate through each one passing it to a processbone function.  It is in that function where we will actually do the stitching, so on we go:

Code:  
  1. private function ProcessBonedObject( ThisRenderer : SkinnedMeshRenderer, RootObj : GameObject )
  2. {
  3. /*      Create the SubObject        */
  4. var NewObj = new GameObject( ThisRenderer.gameObject.name );
  5. NewObj.transform.parent = RootObj.transform;
  6. /*      Add the renderer        */
  7. NewObj.AddComponent( SkinnedMeshRenderer );
  8. var NewRenderer = NewObj.GetComponent( SkinnedMeshRenderer );
  9. /*      Assemble Bone Structure     */
  10. var MyBones = new Transform[ ThisRenderer.bones.Length ];
  11. for ( var i=0; i<ThisRenderer.bones.Length; i++ )
  12. MyBones[ i ] = FindChildByName( ThisRenderer.bones[ i ].name, RootObj.transform );
  13. /*      Assemble Renderer       */
  14. NewRenderer.bones = MyBones;
  15. NewRenderer.sharedMesh = ThisRenderer.sharedMesh;
  16. NewRenderer.materials = ThisRenderer.materials;
  17. }
  18. private function FindChildByName( ThisName : String, ThisGObj : Transform ) : Transform
  19. {
  20. var ReturnObj : Transform;
  21. if( ThisGObj.name==ThisName )
  22. return ThisGObj.transform;
  23. for (var child : Transform in ThisGObj )
  24. {
  25. ReturnObj = FindChildByName( ThisName, child );
  26. if( ReturnObj )
  27. return ReturnObj;
  28. }
  29. return null;
  30. }

Whoa, busy busy busy!  Two functions for the price of one!  Ok, enough cheesy references....... So what are we doing above?  We passed in the RoobObject and our SkinnedMeshRenderer from the object we want to stitch into the root. First, and because I like organization, we create an object to hold all this info in the root object.  Remember it doesnt matter where in the rootobject this info resides as long as the bones it refferences stay the same (or stay the same name/heirarchy).  K, so I create it, name it what our limb object was named (so we know what it is), and parent it to the root object (or our torso in this case). Next we add the SkinnedMeshRenderer component to our new subobject.  This will hold the same stuff our arm has with the exception of the bones being referenced from the torso object. Now we need to find the bones, by name, from the old limb object and create an array of them to insert into the new renderer.  This uses the second function above.  You can see we look through the bones of the arm, get the name of each, find them by name in the torso, and create an array based on that info.  Lastly we set the bones of the new renderer to our new bones reference array.  Set the mesh, and the materials, and BAMMMM!!!!
After this, we can run animations, move the bones around manually, or what have you and you will see the limb follow along as if it were the same mesh as the torso.
This is all I have time for now, and feel free to make any corrections to this as I don't assume this to be accurate.  I only know it works from all the testing I have done from my own projects [/quote]

转载于:https://www.cnblogs.com/qzzlw/p/3580817.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/421153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

求质数的个数

/我买了一本书&#xff0c;意大利作家 保罗.乔尔达诺 得奖的一本小说&#xff0c;好奇这本书有多少页。但它每页页码都是质数&#xff0c;需求如下&#xff0c;1907页书&#xff0c;每个页数以质数命名&#xff0c;求有多少页。/ package funJoy;public class calBook {public…

leetcode 701 二叉搜索树的插入操作 C++ 递归和迭代

迭代 class Solution { public:TreeNode* insertIntoBST(TreeNode* root, int val) {if(!root) return new TreeNode(val);TreeNode*curroot;while(cur){if(val<cur->val){if(cur->left)curcur->left;else{cur->leftnew TreeNode(val);break;}}else if(val>…

1062. 最简分数(20)

1062. 最简分数(20) 时间限制400 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者CHEN, Yue一个分数一般写成两个整数相除的形式&#xff1a;N/M&#xff0c;其中M不为0。最简分数是指分子和分母没有公约数的分数表示形式。 现给定两个不相等的正分数 N1/M1 和 N2/M…

解决ListView 缓存机制带来的显示不正常问题

ListView加载数据原理:系统绘制ListView时&#xff0c;首先会用getCount&#xff08;&#xff09;函数得到要绘制的这个列表的长度&#xff0c;然后开始逐行绘制。然后调用getView()函数&#xff0c;在这个函数里面首先获得一个View&#xff08;简单item&#xff0c;如字符串或…

Java里面static, final, this, super, 代码块, 单例模式

static关键字 package csdn;public class staticWord {public static void main(String[] args) {funStatic fs1 new funStatic();funStatic.showA();fs1.b 2;fs1.showB(); // 2System.out.println("----------");funStatic fs2 new funStatic();funStatic.a 3…

1063. 计算谱半径(20)

1063. 计算谱半径(20) 时间限制200 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者CHEN, Yue在数学中&#xff0c;矩阵的“谱半径”是指其特征值的模集合的上确界。换言之&#xff0c;对于给定的n个复数空间的特征值{a1b1i, ..., anbni}&#xff0c;它们的模为实部…

用了vscode和clion我都裂开了

vscode看着挺牛逼&#xff0c;经常遇到问题&#xff0c;每次运行还得f5调试&#xff0c;你如果想便捷一点&#xff0c;你可以去下插件&#xff0c;比如ccmopiler&#xff0c;code runner啥的。我自己用c但是这两个玩意都不支持c11想要支持还得自己配你看4S店上很多文章&#xf…

windows phone (12) 小试自定义样式

windows phone (12) 小试自定义样式 原文:windows phone (12) 小试自定义样式样式在BS开发中经常用到&#xff0c;在wp中系统也提供了解决办法&#xff0c;就是对设置的样式的一种资源共享&#xff0c;首先是共享资源的位置&#xff0c;它是在App类中&#xff0c;之前我们已经有…

xdoj判断堆栈出栈序列是否有效c++

我在leetcode上写过类似的题&#xff0c;这个代码在xdoj上只能得***50***分&#xff0c;跪求各位大佬挑挑毛病。 #include<stack> #include<iostream> #include<vector> using namespace std; int main(){vector<int>poped;stack<int>s;int n,t;…

1064. 朋友数(20)

1064. 朋友数(20) 时间限制400 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者CHEN, Yue如果两个整数各位数字的和是一样的&#xff0c;则被称为是“朋友数”&#xff0c;而那个公共的和就是它们的“朋友证号”。例如123和51就是朋友数&#xff0c;因为123 51 6&…

Java StringBuffer

最近在学Java API 做的简单笔记 package C12_17;public class testBuffer {public static void main(String[] args) {//StringBuffer 属于java.lang包&#xff0c;属于基础包&#xff0c;jdk api 里面有其运用方式。StringBuffer sb new StringBuffer("Hello");//…

XDOJ 363 输出快速排序递归算法隐含递归树的后序遍历序列 AC

像我这样的菜鸡也没有什么能输出的&#xff0c;好像我写题解也不算输出。 最近期末了&#xff0c;写数据结构实验的时候&#xff0c;这个题写了挺久的&#xff0c;搞出来记录一下。 输出快速排序递归算法隐含递归树的后序遍历序列 描述&#xff1a; 快速排序递归算法隐含一棵由…

uilabel 自适应

有时一个UILable的text内容是变化的&#xff0c;而且差异有很大&#xff0c; 需求上要求UILabel的大小高宽能够自适应text的内容。代码例子&#xff1a; myLable[[UILabel alloc] initWithFrame:CGRectMake(0, 23, 175, 33)]; [myLable setFont:[UIFont fontWithName:&qu…

1065. 单身狗(25)

1065. 单身狗(25) 时间限制300 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者CHEN, Yue“单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人&#xff0c;以便给予特殊关爱。 输入格式&#xff1a; 输入第一行给出一个正整数N&am…

ArrayList的remove方法(重写equals方法) 与LinkedList的常用操作

package C12_18;import java.util.ArrayList;public class joy {public static void main(String[] args) {show();//重写equals方法&#xff0c;移除集合里面的元素。public static void show() {ArrayList<dog> al new ArrayList<dog>();al.add(new dog("j…

期末寒假绝对好好学

期末考试考7门&#xff0c;距离最近的一门还有7天&#xff0c;我保证我这几天绝对好好复习&#xff0c;好好过一个寒假。我的寒假从来都是浪完的&#xff0c;我发誓我这一次绝对好好学习٩( •̀㉨•́ )و &#xff0c;我不好好学&#xff0c;我这辈子都单身

android学习日记13--数据存储之ContentProvide

3、ContentProvider  数据在Android当中是私有的&#xff0c;当然这些数据包括文件数据和数据库数据以及一些其他类型的数据。ContentProvider实现多应用程序间的数据共享类一般利用ContentProvider为需要共享的数据定义一个URI(统一资源定位符)然后其他程序通过Context获得C…

cin,cin.get(),getline()

我势必扫清我对c的各种疑惑&#xff0c;重拾csdn水文之任 结论&#xff1a;cin在获得需要接受的东西之前&#xff0c;对缓冲区里的空格和换行符不会理睬(但是会把它们从缓冲区删去)&#xff0c;但如果达到了可以结束接受的时候&#xff0c;空格和换行符都会让cin不再接 收,并且…

1067. 试密码(20)

1067. 试密码(20) 时间限制400 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者CHEN, Yue当你试图登录某个系统却忘了密码时&#xff0c;系统一般只会允许你尝试有限多次&#xff0c;当超出允许次数时&#xff0c;账号就会被锁死。本题就请你实现这个小功能。 输入格…

Map接口的实现类HashMap的操作

3中遍历HashMap方式 package C12_21;import java.util.Collection; import java.util.HashMap; import java.util.Set; import java.util.Map.Entry;public class testHashMap {public static void main(String[] args) {//定义两个HashMap 集合HashMap<Integer, Integer&g…