CombineSkinnedMeshes

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Removing all content from page)
m (Reverted edits by Joseph05408 (Talk); changed back to last version by Gabrielmsantos)
Line 1: Line 1:
 +
Author: Gabriel Santos
 +
== Description ==
  
 +
 +
Class Model that allows you combine multiple skinned meshes at runtime.
 +
IMPORTANT: The number of vertices and bones is very particular, you must set it up according to your own model.
 +
 +
This Class uses the SkinMeshCombineUtility !
 +
 +
Feel free to clean up the code and add to it. :D
 +
 +
== C# Code ==
 +
<csharp>
 +
/*IMPORTANT: READ !!!!!!
 +
@Autor: Gabriel Santos
 +
@Description Class that Combine Multilple SkinnedMeshes in just one Skinned Mesh Renderer
 +
@Usage: Just AddComponent("CombineSkinnedMeshes") to your root component;
 +
@IMPORTANT: This script uses the SkinMeshCombineUtility Script!
 +
 +
PS: It was tested with FBX files exported from 3D MAX
 +
This Vertex Number and Bone Number must be configured according to your own AVATAR...
 +
You can make a Counter to get the Number of Vertices from your imported character, I choice not do it since
 +
this is script is just executed one time... */
 +
 +
using UnityEngine;
 +
using System.Collections;
 +
 +
 +
public class CombineSkinnedMeshes : MonoBehaviour {
 +
 +
/// Usually rendering with triangle strips is faster.
 +
/// However when combining objects with very low triangle counts, it can be faster to use triangles.
 +
/// Best is to try out which value is faster in practice.
 +
public bool castShadows = true;
 +
public bool receiveShadows = true;
 +
 +
/* This is for very particular use, you must set it regarding to your Character */
 +
public static int VERTEX_NUMBER= [Your Vertices Number]; //The number of vertices total of the character
 +
public static int BONE_NUMBER =[Your Bones Number]; //The number of bones total
 +
 +
// Use this for initialization
 +
void Start () {
 +
 +
//Getting all Skinned Renderer from Children
 +
Component[] allsmr = GetComponentsInChildren(typeof(SkinnedMeshRenderer));
 +
Matrix4x4 myTransform = transform.worldToLocalMatrix;
 +
 +
//The hash with the all bones references: it will be used for set up the BoneWeight Indexes
 +
Hashtable boneHash =new Hashtable();
 +
 +
/* If you want make a counter in order to get the total of Vertices and Bones do it here ... */
 +
 +
//The Sum of All Child Bones
 +
Transform[] totalBones = new Transform[BONE_NUMBER];//Total of Bones for my Example
 +
//The Sum of the BindPoses
 +
Matrix4x4[] totalBindPoses = new Matrix4x4[BONE_NUMBER];//Total of BindPoses
 +
//The Sum of BoneWeights
 +
BoneWeight[] totalBoneWeight = new BoneWeight[VERTEX_NUMBER];//total of Vertices for my Example
 +
 +
int offset=0;
 +
int b_offset=0;
 +
Transform[] usedBones= new Transform[totalBones.Length];
 +
 +
ArrayList myInstances = new ArrayList();
 +
 +
//Setting my Arrays for copies
 +
ArrayList myMaterials=new ArrayList();
 +
 +
for(int i=0;i<allsmr.Length;i++)
 +
{
 +
//Getting one by one
 +
SkinnedMeshRenderer smrenderer  =  (SkinnedMeshRenderer)allsmr[i];
 +
//Making changes to the Skinned Renderer
 +
SkinMeshCombineUtility.MeshInstance instance = new SkinMeshCombineUtility.MeshInstance ();
 +
 +
//Setting the Mesh for the instance
 +
instance.mesh = smrenderer.sharedMesh;
 +
 +
//Getting All Materials
 +
for(int t=0;t<smrenderer.sharedMaterials.Length;t++)
 +
{
 +
myMaterials.Add(smrenderer.sharedMaterials[t]);
 +
}
 +
 +
if (smrenderer != null && smrenderer.enabled && instance.mesh != null) {
 +
 +
instance.transform = myTransform * smrenderer.transform.localToWorldMatrix;
 +
 +
//Material == null
 +
smrenderer.sharedMaterials =new  Material[1];
 +
 +
//Getting  subMesh
 +
for(int t=0;t<smrenderer.sharedMesh.subMeshCount;t++)
 +
{
 +
instance.subMeshIndex = t;
 +
myInstances.Add(instance);
 +
}
 +
 +
//Copying Bones
 +
for(int x=0;x<smrenderer.bones.Length;x++)
 +
{
 +
 +
bool flag = false;
 +
for(int j=0;j<totalBones.Length;j++)
 +
{
 +
if(usedBones[j]!=null)
 +
//If the bone was already inserted
 +
if((smrenderer.bones[x]==usedBones[j]))
 +
{
 +
flag = true;
 +
break;
 +
}
 +
}
 +
 +
//If Bone is New ...
 +
if(!flag)
 +
{
 +
//Debug.Log("Inserted bone:"+smrenderer.bones[x].name);
 +
for(int f=0;f<totalBones.Length;f++)
 +
{
 +
//Insert bone at the firs free position
 +
if(usedBones[f]==null)
 +
{
 +
usedBones[f] = smrenderer.bones[x];
 +
break;
 +
}
 +
}
 +
//inserting bones in totalBones
 +
totalBones[offset]=smrenderer.bones[x];
 +
//Reference HashTable
 +
boneHash.Add(smrenderer.bones[x].name,offset);
 +
 +
//Recalculating BindPoses
 +
//totalBindPoses[offset] = smrenderer.sharedMesh.bindposes[x] ;
 +
totalBindPoses[offset] = smrenderer.bones[x].worldToLocalMatrix * transform.localToWorldMatrix ;
 +
offset++;
 +
}
 +
}
 +
 +
//RecalculateBoneWeights
 +
for(int x=0;x<smrenderer.sharedMesh.boneWeights.Length ;x++)
 +
{
 +
//Just Copying and changing the Bones Indexes !!
 +
totalBoneWeight[b_offset] =  recalculateIndexes(smrenderer.sharedMesh.boneWeights[x],boneHash,smrenderer.bones);
 +
b_offset++;
 +
}
 +
//Disabling current SkinnedMeshRenderer
 +
((SkinnedMeshRenderer)allsmr[i]).enabled = false;
 +
}
 +
}
 +
 +
SkinMeshCombineUtility.MeshInstance[] instances = (SkinMeshCombineUtility.MeshInstance[])myInstances.ToArray(typeof(SkinMeshCombineUtility.MeshInstance));
 +
 +
// Make sure we have a SkinnedMeshRenderer
 +
if (GetComponent(typeof(SkinnedMeshRenderer)) == null)
 +
{
 +
gameObject.AddComponent(typeof(SkinnedMeshRenderer));
 +
}
 +
 +
//Setting Skinned Renderer
 +
SkinnedMeshRenderer objRenderer = (SkinnedMeshRenderer)GetComponent(typeof(SkinnedMeshRenderer));
 +
//Setting Mesh
 +
objRenderer.sharedMesh = SkinMeshCombineUtility.Combine(instances);
 +
 +
objRenderer.castShadows = castShadows;
 +
objRenderer.receiveShadows = receiveShadows;
 +
 +
//Setting Bindposes
 +
objRenderer.sharedMesh.bindposes = totalBindPoses;
 +
 +
//Setting BoneWeights
 +
objRenderer.sharedMesh.boneWeights = totalBoneWeight;
 +
 +
//Setting bones
 +
objRenderer.bones =totalBones;
 +
 +
//Setting Materials
 +
objRenderer.sharedMaterials = (Material[])myMaterials.ToArray(typeof(Material));
 +
 +
objRenderer.sharedMesh.RecalculateNormals();
 +
objRenderer.sharedMesh.RecalculateBounds();
 +
 +
//Enable Mesh
 +
objRenderer.enabled = true;
 +
 +
/* Debug.Log("############################################");
 +
Debug.Log("M Materials "+myMaterials.Count);
 +
Debug.Log("bindPoses "+objRenderer.sharedMesh.bindposes.Length);
 +
Debug.Log("boneWeights "+objRenderer.sharedMesh.boneWeights.Length);
 +
Debug.Log("Bones "+objRenderer.bones.Length);
 +
Debug.Log("Vertices "+objRenderer.sharedMesh.vertices.Length); */
 +
 +
}
 +
 +
/*
 +
@Description: Revert the order of an array of components
 +
(NOT USED)
 +
*/
 +
static Component[] revertComponent(Component[] comp )
 +
{
 +
Component[] result = new Component[comp.Length];
 +
int x=0;
 +
for(int i=comp.Length-1;i>=0;i--)
 +
{
 +
result[x++]=comp[i];
 +
}
 +
 +
return result;
 +
}
 +
 +
/*
 +
@Description: Setting the Indexes for the new bones
 +
*/
 +
static BoneWeight recalculateIndexes(BoneWeight bw,Hashtable boneHash,Transform[] meshBones )
 +
{
 +
BoneWeight retBw = bw;
 +
retBw.boneIndex0 = (int)boneHash[meshBones[bw.boneIndex0].name];
 +
retBw.boneIndex1 = (int)boneHash[meshBones[bw.boneIndex1].name];
 +
retBw.boneIndex2 = (int)boneHash[meshBones[bw.boneIndex2].name];
 +
retBw.boneIndex3 = (int)boneHash[meshBones[bw.boneIndex3].name];
 +
return retBw;
 +
}
 +
}
 +
</csharp>

Revision as of 19:20, 19 October 2009

Author: Gabriel Santos

Description

Class Model that allows you combine multiple skinned meshes at runtime. IMPORTANT: The number of vertices and bones is very particular, you must set it up according to your own model.

This Class uses the SkinMeshCombineUtility !

Feel free to clean up the code and add to it. :D

C# Code

<csharp> /*IMPORTANT: READ !!!!!! @Autor: Gabriel Santos @Description Class that Combine Multilple SkinnedMeshes in just one Skinned Mesh Renderer @Usage: Just AddComponent("CombineSkinnedMeshes") to your root component; @IMPORTANT: This script uses the SkinMeshCombineUtility Script!

PS: It was tested with FBX files exported from 3D MAX This Vertex Number and Bone Number must be configured according to your own AVATAR... You can make a Counter to get the Number of Vertices from your imported character, I choice not do it since this is script is just executed one time... */

using UnityEngine; using System.Collections;


public class CombineSkinnedMeshes : MonoBehaviour {

/// Usually rendering with triangle strips is faster. /// However when combining objects with very low triangle counts, it can be faster to use triangles. /// Best is to try out which value is faster in practice. public bool castShadows = true; public bool receiveShadows = true;

/* This is for very particular use, you must set it regarding to your Character */ public static int VERTEX_NUMBER= [Your Vertices Number]; //The number of vertices total of the character public static int BONE_NUMBER =[Your Bones Number]; //The number of bones total

// Use this for initialization void Start () {

//Getting all Skinned Renderer from Children Component[] allsmr = GetComponentsInChildren(typeof(SkinnedMeshRenderer)); Matrix4x4 myTransform = transform.worldToLocalMatrix;

//The hash with the all bones references: it will be used for set up the BoneWeight Indexes Hashtable boneHash =new Hashtable();

/* If you want make a counter in order to get the total of Vertices and Bones do it here ... */

//The Sum of All Child Bones Transform[] totalBones = new Transform[BONE_NUMBER];//Total of Bones for my Example //The Sum of the BindPoses Matrix4x4[] totalBindPoses = new Matrix4x4[BONE_NUMBER];//Total of BindPoses //The Sum of BoneWeights BoneWeight[] totalBoneWeight = new BoneWeight[VERTEX_NUMBER];//total of Vertices for my Example

int offset=0; int b_offset=0; Transform[] usedBones= new Transform[totalBones.Length];

ArrayList myInstances = new ArrayList();

//Setting my Arrays for copies ArrayList myMaterials=new ArrayList();

for(int i=0;i<allsmr.Length;i++) { //Getting one by one SkinnedMeshRenderer smrenderer = (SkinnedMeshRenderer)allsmr[i]; //Making changes to the Skinned Renderer SkinMeshCombineUtility.MeshInstance instance = new SkinMeshCombineUtility.MeshInstance ();

//Setting the Mesh for the instance instance.mesh = smrenderer.sharedMesh;

//Getting All Materials for(int t=0;t<smrenderer.sharedMaterials.Length;t++) { myMaterials.Add(smrenderer.sharedMaterials[t]); }

if (smrenderer != null && smrenderer.enabled && instance.mesh != null) {

instance.transform = myTransform * smrenderer.transform.localToWorldMatrix;

//Material == null smrenderer.sharedMaterials =new Material[1];

//Getting subMesh for(int t=0;t<smrenderer.sharedMesh.subMeshCount;t++) { instance.subMeshIndex = t; myInstances.Add(instance); }

//Copying Bones for(int x=0;x<smrenderer.bones.Length;x++) {

bool flag = false; for(int j=0;j<totalBones.Length;j++) { if(usedBones[j]!=null) //If the bone was already inserted if((smrenderer.bones[x]==usedBones[j])) { flag = true; break; } }

//If Bone is New ... if(!flag) { //Debug.Log("Inserted bone:"+smrenderer.bones[x].name); for(int f=0;f<totalBones.Length;f++) { //Insert bone at the firs free position if(usedBones[f]==null) { usedBones[f] = smrenderer.bones[x]; break; } } //inserting bones in totalBones totalBones[offset]=smrenderer.bones[x]; //Reference HashTable boneHash.Add(smrenderer.bones[x].name,offset);

//Recalculating BindPoses //totalBindPoses[offset] = smrenderer.sharedMesh.bindposes[x] ; totalBindPoses[offset] = smrenderer.bones[x].worldToLocalMatrix * transform.localToWorldMatrix ; offset++; } }

//RecalculateBoneWeights for(int x=0;x<smrenderer.sharedMesh.boneWeights.Length ;x++) { //Just Copying and changing the Bones Indexes !! totalBoneWeight[b_offset] = recalculateIndexes(smrenderer.sharedMesh.boneWeights[x],boneHash,smrenderer.bones); b_offset++; } //Disabling current SkinnedMeshRenderer ((SkinnedMeshRenderer)allsmr[i]).enabled = false; } }

SkinMeshCombineUtility.MeshInstance[] instances = (SkinMeshCombineUtility.MeshInstance[])myInstances.ToArray(typeof(SkinMeshCombineUtility.MeshInstance));

// Make sure we have a SkinnedMeshRenderer if (GetComponent(typeof(SkinnedMeshRenderer)) == null) { gameObject.AddComponent(typeof(SkinnedMeshRenderer)); }

//Setting Skinned Renderer SkinnedMeshRenderer objRenderer = (SkinnedMeshRenderer)GetComponent(typeof(SkinnedMeshRenderer)); //Setting Mesh objRenderer.sharedMesh = SkinMeshCombineUtility.Combine(instances);

objRenderer.castShadows = castShadows; objRenderer.receiveShadows = receiveShadows;

//Setting Bindposes objRenderer.sharedMesh.bindposes = totalBindPoses;

//Setting BoneWeights objRenderer.sharedMesh.boneWeights = totalBoneWeight;

//Setting bones objRenderer.bones =totalBones;

//Setting Materials objRenderer.sharedMaterials = (Material[])myMaterials.ToArray(typeof(Material));

objRenderer.sharedMesh.RecalculateNormals(); objRenderer.sharedMesh.RecalculateBounds();

//Enable Mesh objRenderer.enabled = true;

/* Debug.Log("############################################"); Debug.Log("M Materials "+myMaterials.Count); Debug.Log("bindPoses "+objRenderer.sharedMesh.bindposes.Length); Debug.Log("boneWeights "+objRenderer.sharedMesh.boneWeights.Length); Debug.Log("Bones "+objRenderer.bones.Length); Debug.Log("Vertices "+objRenderer.sharedMesh.vertices.Length); */

}

/* @Description: Revert the order of an array of components (NOT USED) */ static Component[] revertComponent(Component[] comp ) { Component[] result = new Component[comp.Length]; int x=0; for(int i=comp.Length-1;i>=0;i--) { result[x++]=comp[i]; }

return result; }

/* @Description: Setting the Indexes for the new bones */ static BoneWeight recalculateIndexes(BoneWeight bw,Hashtable boneHash,Transform[] meshBones ) { BoneWeight retBw = bw; retBw.boneIndex0 = (int)boneHash[meshBones[bw.boneIndex0].name]; retBw.boneIndex1 = (int)boneHash[meshBones[bw.boneIndex1].name]; retBw.boneIndex2 = (int)boneHash[meshBones[bw.boneIndex2].name]; retBw.boneIndex3 = (int)boneHash[meshBones[bw.boneIndex3].name]; return retBw; } } </csharp>

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox