• Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By RoKabium Games
      While looking out for that pesky Terrator, our little alien is doing a bit of relaxed mining down on the new gas planet "Lelantos" this weekend.... 
      #gamedev #indiedev #madewithunity #screenshotsaturday
    • By vividgamer
      I have a native iOS game (objective c, XCode build) which I am considering to port to other platforms.
      Core gameplay is based on solely on geographical maps, and custom drawing over maps. It also has Core Data. This part is complete in development.
      What is not done yet is: monetization, gamification (leaderboards, challenges) and multiplayer functionality.
      As I think more about it, I am tempted to think if this is the right time to move to a cross platform tool such as Unity. But before dedicating time to port my 5 years side-project effort in Objective C, I really want to know if its worth it.
      - Does Unity support such plugins / assets that will fulfill all my above requirements?
      - Unity Personal seems to have only 20 concurrent users - is it too costly scaling if I decide for extending to web and android platforms?
      - What is the general workflow involved in publishing to iOS, Android, PC, and web platforms while using Unity? I mean to ask about various points of signing stuff, paying fees and getting certified.
      - How long will it really take to port my entire Objective C project into Unity? I am somewhat familiar with C# but I am finding it hard fidgeting with Unity IDE as lot of things are focused around FPS and 3D while my game is still 2d - not much action involved. I seem bit overwhelmed by the list of features I see there. All in all, I do not want to lose my momentum while still making sure its portable to everywhere.
      - Any assets I could use (for free to try basis in debug) that are relevant for my game?
      - Last but not the least, are there any costs that I need to be paying upfront to Unity, for using it (apart from their monthly subscription model)? I don't understand their costing for multiplayer in conjunction with their subscription fees - if someone could kindly elaborate.
      Thanks in advance for your time reading a newbie
    • By GytisDev
      me and few friends are developing simple city building game with unity for a school project, think something like Banished but much simpler. I was tasked to create the path-finding for the game so I mostly followed this tutorial series up to episode 5. Then we created simple working system for cutting trees. The problem is that the path-finding is working like 90% of the time, then it get stuck randomly then there's clearly a way to the objective (tree). I tried looking for some pattern when it happens but can't find anything. So basically I need any tips for how I should approach this problem.
      Use this image to visualize the problem.
    • By aymen
      please any know how can i' calculate the centroid from any number vertices
    • By Henry Fernandez
      Good day sir/maam. I am developing a game for my thesis and im done with multiplayer and plan to start the implementation of AI but i dont know how/where to start. Please give an advice. I am developing it in C# using UNITY. 
      Im am now collected all pieces that has possible moves but i am stuck on which best move to select. I hope you will help me. This is link explained the game https://en.wikipedia.org/wiki/Game_of_the_Generals 

  • Advertisement
  • Advertisement
Sign in to follow this  

Unity Copying Skinned Mesh Renderer and bones from one GO to another in unity

This topic is 1040 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Im trying to implement a modular character system in Unity3d 5, which seems to be quite poorly documented. So far, what I have underestood from several sources is that I have to split the character mesh in the required parts, export each one separately including the skeleton, and export the skeleton without geometry. Then each part must be instantiated, but just to copy its Skinned Mesh Renderer component to a new GameObject, which is child of a parent game object that holds the asembled character mesh plus the skeleton. Also, each Skinned Mesh Renderer must have its bones overwriten with the ones from the skeleton.

I have tried to implement this, but I have only  managed to make an script that runs and has no syntax errors, but it does nothing:

using UnityEngine;
using System.Collections;

public class assemble : MonoBehaviour {
	Transform me;
	Animator anim;
	private Vector3 position;
	NavMeshAgent agent;

	GameObject head;
	GameObject torso;
	GameObject hands;
	GameObject legs;
	GameObject feet;	

	// Use this for initialization
	void Start () {
		me = transform;
		anim = GetComponent<Animator>();
		agent = GetComponent<NavMeshAgent> ();
		GameObject prefab = Resources.Load("vmale-head") as GameObject;
		GameObject tt2 = Instantiate (prefab);
		head = new GameObject("head");
		head.transform.SetParent( transform);
		head.transform.localPosition = Vector3.zero;
		head.transform.localRotation = Quaternion.Euler(Vector3.zero);
		head.transform.localScale = transform.localScale;
		var comp = head.AddComponent<SkinnedMeshRenderer>();
		SkinnedMeshRenderer[] t = tt2.GetComponentsInChildren<SkinnedMeshRenderer> ();
		if (t.Length > 0) {
			comp.sharedMesh = t [0].sharedMesh; //copy geometry
			comp.materials = t [0].materials; //and copy materials
		} else
			Debug.LogWarning("No components found!!");		
		Destroy (tt2);

		prefab = Resources.Load("vmale-torso") as GameObject;
		tt2 = Instantiate (prefab);
		torso = new GameObject("torso");
		torso.transform.SetParent( transform);
		torso.transform.localPosition = Vector3.zero;
		torso.transform.localRotation = Quaternion.Euler(Vector3.zero);
		comp = torso.AddComponent<SkinnedMeshRenderer>();
		t = tt2.GetComponentsInChildren<SkinnedMeshRenderer> ();
		if (t.Length > 0) {
			comp.sharedMesh = t [0].sharedMesh;
			comp.materials = t [0].materials;
		} else
			Debug.LogWarning("No components found!!");
		Destroy (tt2);

The parent gameobject  gets the 2 children Im creating, but they are empty, no actual geometry is copied (or at least, it is not visible) and the new gameobjects are placed at 0,0,0, in the corner of the map. Also, I cant find a way to attach the skeleton to the parent or copy its bones, because the exported file doesnt produces an Skinned Mesh Render, as it has no geometry.

Can somebody give me some directions about this?

Edited by rogerdv

Share this post

Link to post
Share on other sites

Here is the old script that I mentioned in the other thread (and was using it). Not the optimal one, just proof of the concept:

using UnityEngine;
using System.Collections.Generic;

using HierarchyDict = System.Collections.Generic.Dictionary<string, UnityEngine.Transform>;
using BoneTransformDict = System.Collections.Generic.Dictionary<string, utils.Tuple<UnityEngine.Transform, string>>;

namespace utils
	public class MeshCombiner
#region Operations
		//! Combine mesh.
			\return combined mesh instance.
		public static Mesh Combine(GameObject Object, GameObject NewObject)
			// Dummy parent holder
			GameObject dummy_parent = new GameObject("DummyParent");

			// Be sure new object is at same position as reference object, otherwise
			// combined mesh would be distored
			NewObject.transform.position = Object.transform.position;

			// All skin renderers in all children
			var skin_renderers = Object.GetComponentsInChildren<SkinnedMeshRenderer>();
			// All available bones
			var all_bones = new BoneTransformDict();
			// Traverse through all skinned mesh renderers
			foreach (var renderer in skin_renderers)
				var renderer_bones = renderer.bones;
				foreach (var bone in renderer_bones)
					// Bone doesn't exist, add it
					if (!all_bones.ContainsKey(bone.name))
						all_bones[bone.name] = new utils.Tuple<Transform, string>(bone, bone.parent.name);

			var combineInstanceArrays = new Dictionary<Material, List<CombineInstance>>();
			var bone_weights = new Dictionary<Mesh, BoneWeight[]>();
			// Map between bone name and index
			var added_bones = new Dictionary<string, int>();
			// List of child objects holding the skinned mesh renderers to be
			// destroyed when finished
			var child_objects_to_destroy = new List<GameObject>();

			int bone_index = 0;
			foreach (var renderer in skin_renderers)

				var renderer_bones = renderer.bones;
				// Add all bones as first and save the indices of them
				foreach (var bone in renderer_bones)
					// Bone not yet added
					if (!added_bones.ContainsKey(bone.name))
						added_bones[bone.name] = bone_index++;
				// Adjust bone weights indices based on real indices of bones
				var bone_weights_list = new BoneWeight[renderer.sharedMesh.boneWeights.Length];
				var renderer_bone_weights = renderer.sharedMesh.boneWeights;
				for (int i = 0; i < renderer_bone_weights.Length; ++i)

					BoneWeight current_bone_weight = renderer_bone_weights[i];

					current_bone_weight.boneIndex0 = added_bones[renderer_bones[current_bone_weight.boneIndex0].name];
					current_bone_weight.boneIndex2 = added_bones[renderer_bones[current_bone_weight.boneIndex2].name];
					current_bone_weight.boneIndex3 = added_bones[renderer_bones[current_bone_weight.boneIndex3].name];
					current_bone_weight.boneIndex1 = added_bones[renderer_bones[current_bone_weight.boneIndex1].name];

					bone_weights_list[i] = current_bone_weight;
				bone_weights[renderer.sharedMesh] = bone_weights_list;

				// Handle bad input
				if (renderer.sharedMaterials.Length != renderer.sharedMesh.subMeshCount)
					Debug.LogError("Mismatch between material count and submesh count. Is this the correct MeshRenderer?");

				// Prepare stuff for mesh combination with same materials
				for (int i = 0; i < renderer.sharedMesh.subMeshCount; i++)
					// Material not in dict, add it
					if (!combineInstanceArrays.ContainsKey(renderer.sharedMaterials[i]))
						combineInstanceArrays[renderer.sharedMaterials[i]] = new List<CombineInstance>();
					var actual_mat_list = combineInstanceArrays[renderer.sharedMaterials[i]];
					// Add new instance
					var combine_instance = new CombineInstance();
					combine_instance.transform = renderer.transform.localToWorldMatrix;
					combine_instance.subMeshIndex = i;
					combine_instance.mesh = renderer.sharedMesh;

				// No need to use it anymore
				renderer.enabled = false;
			var bones_hierarchy = new HierarchyDict();
			// Recreate bone structure
			foreach (var bone in all_bones)
				// Bone not processed, process it
				if (!bones_hierarchy.ContainsKey(bone.Key))
					AddParent(bone.Key, bones_hierarchy, all_bones, dummy_parent);

			// Create bone array from preprocessed dict
			var bones = new Transform[added_bones.Count];
			foreach (var bone in added_bones)
				bones[bone.Value] = bones_hierarchy[bone.Key];

			// Get the root bone
			Transform root_bone = bones[0];

			while (root_bone.parent != null)
				// Get parent
				if (bones_hierarchy.ContainsKey(root_bone.parent.name))
					root_bone = root_bone.parent;

			// Create skinned mesh renderer GO
			GameObject combined_mesh_go = new GameObject("Combined");
			combined_mesh_go.transform.parent = NewObject.transform;
			combined_mesh_go.transform.localPosition = Vector3.zero;

			// Fill bind poses
			var bind_poses = new Matrix4x4[bones.Length];
			for (int i = 0; i < bones.Length; ++i)
				bind_poses[i] = bones[i].worldToLocalMatrix * combined_mesh_go.transform.localToWorldMatrix;

			// Need to move it to new GO
			root_bone.parent = NewObject.transform;

			// Combine meshes into one
			var combined_new_mesh = new Mesh();
			var combined_vertices = new List<Vector3>();
			var combined_uvs = new List<Vector2>();
			var combined_indices = new List<int[]>();
			var combined_bone_weights = new List<BoneWeight>();
			var combined_materials = new Material[combineInstanceArrays.Count];

			var vertex_offset_map = new Dictionary<Mesh, int>();

			int vertex_index_offset = 0;
			int current_material_index = 0;

			foreach (var combine_instance in combineInstanceArrays)
				combined_materials[current_material_index++] = combine_instance.Key;
				var submesh_indices = new List<int>();
				// Process meshes for each material
				foreach (var combine in combine_instance.Value)
					// Update vertex offset for current mesh
					if (!vertex_offset_map.ContainsKey(combine.mesh))
						// Add vertices for mesh
						// Set uvs
						// Add weights

						vertex_offset_map[combine.mesh] = vertex_index_offset;
						vertex_index_offset += combine.mesh.vertexCount;
					int vertex_current_offset = vertex_offset_map[combine.mesh];

					var indices = combine.mesh.GetTriangles(combine.subMeshIndex);
					// Need to "shift" indices
					for (int k = 0; k < indices.Length; ++k)
						indices[k] += vertex_current_offset;

				// Push indices for given submesh

			combined_new_mesh.vertices = combined_vertices.ToArray();
			combined_new_mesh.uv = combined_uvs.ToArray();
			combined_new_mesh.boneWeights = combined_bone_weights.ToArray();

			combined_new_mesh.subMeshCount = combined_materials.Length;
			for (int i = 0; i < combined_indices.Count; ++i)
				combined_new_mesh.SetTriangles(combined_indices[i], i);

			// Create mesh renderer
			SkinnedMeshRenderer combined_skin_mesh_renderer = combined_mesh_go.AddComponent<SkinnedMeshRenderer>();
			combined_skin_mesh_renderer.sharedMesh = combined_new_mesh;
			combined_skin_mesh_renderer.bones = bones;
			combined_skin_mesh_renderer.rootBone = root_bone;
			combined_skin_mesh_renderer.sharedMesh.bindposes = bind_poses;

			combined_skin_mesh_renderer.sharedMaterials = combined_materials;

			// Destroy children
			foreach (var child in child_objects_to_destroy)
			// Destroy dummy parent

			return combined_skin_mesh_renderer.sharedMesh;

		static void AddParent(string BoneName, HierarchyDict BoneHierarchy, BoneTransformDict AllBones, GameObject DummyParent)
			Transform actual_bone = null;
			// Must be bone
			if (AllBones.ContainsKey(BoneName))
				var bone_tuple = AllBones[BoneName];
				// Add parent recursively if not added
				if (!BoneHierarchy.ContainsKey(bone_tuple._2))
					AddParent(bone_tuple._2, BoneHierarchy, AllBones, DummyParent);
					// Unparent all children of parents
					Unparent(BoneHierarchy[bone_tuple._2], DummyParent);

				bone_tuple._1.parent = BoneHierarchy[bone_tuple._2];
				actual_bone = bone_tuple._1;

			BoneHierarchy[BoneName] = actual_bone;

		static void Unparent(Transform Parent, GameObject DummyParent)
			if (Parent != null)
				var unparent_list = new List<Transform>();

				foreach (Transform child in Parent.transform)

				foreach (var child in unparent_list)
					child.parent = DummyParent.transform;

Share this post

Link to post
Share on other sites

I found the problem in my script: I was copying only the SkinnedMeshRenderer to see "if it worked", but it didnt.  I added bone copy and now I see the resulting character and it idle animation, but other animations give several errors: Quaternion To Matrix conversion failed because input Quaternion is invalid {-0.757474, 0.102703, -0.196973, 0.627736} l=1.017166

Here is the relevant (I think) code:

#region TransformCatalog
class TransformCatalog : Dictionary<string, Transform>
	#region Constructors
	public TransformCatalog(Transform transform)
	#region Catalog
	private void Catalog(Transform transform)
		Add(transform.name, transform);
		foreach (Transform child in transform)

#region DictionaryExtensions
class DictionaryExtensions
	public static TValue Find<TKey, TValue>(Dictionary<TKey, TValue> source, TKey key)
		TValue value;
		source.TryGetValue(key, out value);
		return value;

var boneCatalog = new TransformCatalog(me);
//repeat for each body part
GameObject prefab = Resources.Load("vmale-head") as GameObject;
GameObject tt2 = Instantiate (prefab);
head = new GameObject("head");
head.transform.SetParent( transform);
head.transform.localPosition = Vector3.zero;
head.transform.localRotation = Quaternion.Euler(Vector3.zero);
head.transform.localScale = transform.localScale;		
var skinnedMeshRenderers = tt2.GetComponentsInChildren<SkinnedMeshRenderer> ();
foreach (var sourceRenderer in skinnedMeshRenderers)
        var comp = head.AddComponent<SkinnedMeshRenderer>();
	comp.sharedMesh = sourceRenderer.sharedMesh;
	comp.materials = sourceRenderer.materials;
	comp.bones = TranslateTransforms(sourceRenderer.bones, boneCatalog);
Destroy (tt2);

I guess that Im missing more info that needs to be copied. The code is mostly based on the sample posted here.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement