摘自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.
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.
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:
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]
unity3d由多个部分组成一个角色,布布扣,bubuko.com
原文:http://www.cnblogs.com/qzzlw/p/3580817.html