I have a Blender file. In it, lies a mesh. I want to take this mesh, and manipulate it. Doing so directly doesn't work. How do I get a copy, then? If I use the == operator on a Mesh variable, I get a pointer to the data, instead of a copy.
You actually have to copy the vertices and triangles over and not the mesh, as the mesh counts as an asset and all you get are references when you pass it around. What I did was create a function to manually copy over the following: Vertices Triangles UV, uv2 normal tangent colors then save it to a new asset using AssetDatabase.
That sounds terrible. I'm trying out using Object.Instantiate, which seems to work, aside from the undesired suffix (Clone). Nevermind. Not having any success there, either, though that did fix some sort of wacky naming problem I was having. I hate this.
Okay, now I'm doing that. Why is this vertex color change not having any effect? Code (csharp): using UnityEngine; using UnityEditor; class VertexRGB2A { [ MenuItem("Assets/Copy RGB Vertex Colors to Alpha") ] static void VertexRGB2AMenuItem () { Mesh rgbMesh = Selection.activeObject as Mesh; Mesh rgbaMesh = new Mesh(); rgbaMesh.vertices = rgbMesh.vertices; rgbaMesh.colors = rgbMesh.colors; rgbaMesh.triangles = rgbMesh.triangles; for (int i = 0; i < rgbaMesh.colors.Length; ++i) rgbaMesh.colors[i].a = rgbaMesh.colors[i].grayscale; // Get the path of the enclosing folder. string path = AssetDatabase.GetAssetPath(Selection.activeObject); path = path.Substring(0, path.LastIndexOf('/') ); AssetDatabase.CreateAsset(rgbaMesh, path + '/' + rgbMesh.name + " (VertRGB->A)" + ".asset"); } [ MenuItem("Assets/Copy RGB Vertex Colors to Alpha", true) ] static bool ValidateSyncFBXToHierarchy () { return Selection.activeObject.GetType() == typeof(Mesh); } }
Here's a quick script I just hacked up, since I thought it would be useful in a couple of places. Code (csharp): [MenuItem("Assets/CopyMesh")] static void CopyMesh() { Mesh mesh = Selection.activeObject as Mesh; Mesh newmesh = new Mesh(); newmesh.vertices = mesh.vertices; newmesh.triangles = mesh.triangles; newmesh.uv = mesh.uv; newmesh.normals = mesh.normals; newmesh.colors = mesh.colors; newmesh.tangents = mesh.tangents; AssetDatabase.CreateAsset(newmesh, AssetDatabase.GetAssetPath(mesh) + " copy.asset"); } You can also do this at runtime instead of in-editor.
Oh, simul-post... Anyway, you have to reassign your RGB color array back to your mesh, otherwise you're just editing a copy: Color[] colors = rgbaMesh.colors; // Edit colors here for( i=0 to <blah>) colors.a = <random alpha> // <SNIP> // now reassign it back rgbaMesh.colors = colors;
Hooray for posting in the same minute! I don't like that kind of stuff! I don't understand this, but I would like to. Regardless, this works. Thanks a bunch! Code (csharp): Mesh rgbMesh = Selection.activeObject as Mesh; Color[] colors = rgbMesh.colors; for (int i = 0; i < rgbMesh.colors.Length; ++i) colors[i].a = colors[i].grayscale; Mesh rgbaMesh = new Mesh(); rgbaMesh.vertices = rgbMesh.vertices; rgbaMesh.triangles = rgbMesh.triangles; rgbaMesh.colors = colors;
Hey there, I'm trying to do the same, but for a whole GameObject. First, I Object.Instantiate() an FBX asset, and then I try to create a new asset from this GameObject. Lastly, I use SaveAssets(). But the new asset loses its components each time I restart Unity ... Does this mean I have to recreate all the components from the old to the new asset ? Or is the instanciated GameObject reference is sufficient to include all its components with CreateAsset ? Thank you in advance. P.S : There is a lack of examples and docs about how to handle prefabs and assets without messing everything up.
I got curious enough to see if it would work. Here's what I did: 1. Instantiate an FBX through the editor. 2. Added a component, changed some of the default settings. 3. Used an editor script to save it to an asset file. Observations: If the object is active, Unity complains and sets it to inactive, and then saves it. If I set the object and script to inactive, there are no errors, and the prefab seems to be created and retains the settings of the components. However; deleting the created prefab always crashes Unity on my machine in either case. I'm not quite ready to risk a full reimport on my current project so I'm stopping the experiments here for now 8). After a little bit more dangerous experimenting, (because I'm too lazy to open up a blank project), CreateAsset using a GameObject does not create a Prefab, but instead tries to create an invalid asset file that has a reference to the GameObject in the scene hierarchy. Personally, if you needed that facility, unless anyone has a better suggestion I would highly recommend just using reflection to store the game object's components and settings and just recreate them. :?
Well, I'm running into the exact same crashes and weird things than you decribe. It's turning me mad I really don't understand, it's like every single bit of attribution is not a new instance but just a reference... Here is where I'm at actually : 0) I instantiate the original asset into a GameObject, and it will be the object I'll work with in further steps 1) I create a new GameObject 2) I create a new Animation component 3) I build its curves by copying the old asset's ones, like NewCurve = OldAssetCurve 4) I export this new GameObject into a new asset with CreateAsset(). Here, everyting is fine, it contain my clips, and my Transform. 5) SetDirty() + SaveAssets() + Save Project 6) restart Unity 7) Then I receive that damn message "Component could not be loaded. Cleaning up!" And my New Asset is empty. Please don't tell me that in order to manipulate an FBX file, we have to recreate manually every single bit of it into a new asset ? :cry: I tried the CopyAsset approach in point 0), but the created asset is unreadable, not containing any component at all. I also tried the approach of creating every component with new, and then EditorUtility.CopySerialized the old ones, but still it wouldn't save to disk. Finally I even tried EditorUtility.CloneComponent(), but GameObject.animation is read only, so it was useless. How could it be so complicated to just manipulate a Unity resource file ? Anyway, thanks for the tips. What do you mean by using Reflection ? (sorry I'm not fully used to C# :roll: )
I don't have the patience to go sorting through my logged bugs right now, but I have encountered several related problems, over the past couple of months, and tried to log a bug about each one. As I see it, Unity really doesn't seem to want me to manipulate any assets in the Editor, and prefers for me to work in Start(). Which I don't want to do, because as a gamer, I am impatient with any sort of loading, and don't want that in my own products. 2.5 brought improvements to this area with improved ability to take control of the Editor, but the foundation needs to become more sound for procedural creation and manipulation of content in the Editor.
Seconded, it's simply impossible to do some generation stuff at runtime as it would take ages to launch the game. Now after an ultimate experiment, I feel something is seriously wrong : I recreated a brand new Animation(), and then recreated each of its curves by the use of new Keyframe(). each of these keyframes were set to the values of another asset's animation keyframes. In short, I just can't go deeper to the data source. Then I saved the Animation into a new .ANIM extension asset, to ensure that nothing else would interfere. As usual, everything looks ok after operation. Restarting Unity --> "Component could not be loaded. Cleaning up!" And my new .ANIM asset is empty. Depressing.
Ok, after ten centuries of trials and errors, I finally found why the data wouldn't persist after restarting Unity. We have to do an AssetDatabase.AddObjectToAsset() for each animationClip referenced in the Animation component of the new asset. Docs should have specified this key step ... Anyway, this makes me do the relative with what the Editor shows when we select a component member of a FBX file : a visual white line to the child element in the inspector. So I guess we have to do AssetDatabase.AddObjectToAsset() for Meshes too. Simple reflection of vertices, etc wouldn't work. edit : haha now I'm screwed, as we can't tell AssetDatabase.AddObjectToAsset() to write at the root, every components that are in the root of the new asset are lost at restart ... Well, let's go ahead of ten more centuries of trials and errors. :? edit 2 : ok I found how to tell AssetDatabase.AddObjectToAsset() to write at where we want : AddObjectToAsset (objectToAdd : Object, assetObject : Object) instead of AddObjectToAsset (objectToAdd : Object, assetPath : string). Everything is persistent now. Oooookaaaaaaaay, now I can work. Fine.
I've never used AssetDatabase.AddObjectToAsset before now, but I'm glad of that. All it does is turn Unity into a crashing machine. Very disappointing, but completely in-line with what I'm used to, from the editor classes.
Yep, it seems to be fragile ... Anyway, adding new animationClip now just works fine. I'll soon publish a clean script where we can do stuff in a FBX (like procedural stuff) and then copy it to a new safe asset.
For creating prefabs from scratch, Fer laid out the calls in this thread: http://forum.unity3d.com/viewtopic.php?p=286965#286965
Old thread I know, but I came across this when looking to see if Mesh had a copy constructor, thought I'd share this method to copy across the properties via reflection. Edit: Updated to extension method (see http://msdn.microsoft.com/en-us//library/bb383977.aspx). Code (csharp): using UnityEngine; namespace UnityExtensions { public static class MeshExtensions { public static Mesh Copy(this Mesh mesh) { var copy = new Mesh(); foreach(var property in typeof(Mesh).GetProperties()) { if(property.GetSetMethod() != null property.GetGetMethod() != null) { property.SetValue(copy, property.GetValue(mesh, null), null); } } return copy; } } }
Calling setter/getter (or any other method) by reflection is generally a bad idea, at least for the code's performance. You would better write the assignments line by line and make direct calls. I guess your code will run about ~400% faster!
For me, the best and simple way to clone a mesh is to use Instantiate. Like this: Code (CSharp): if (Selection.activeGameObject != null && Selection.activeGameObject.TryGetComponent(out MeshFilter meshFilter)) { GameObject obj = new GameObject("obj"); obj.AddComponent<MeshRenderer>().sharedMaterials = meshFilter.GetComponent<MeshRenderer>().sharedMaterials; obj.AddComponent<MeshFilter>().sharedMesh = Instantiate(meshFilter.sharedMesh); }
That's not a copy, that's the same mesh it references. The easiest way to copy a mesh is simply to call MeshFilter.mesh, but for some stupid reason Unity logs an error when you do that in an editor script. I've been trying to make an exact copy of a mesh by manually copying everything, and it's easy enough, unless the mesh has blendshapes, I can't get these to copy correctly
For future me and others, I found a simple script that copies the full mesh data, including submeshes, without dealing of manually copying the mesh data itself. I didn't check if it works with bindposes etc. but it's a nice shortcut anyway. Code (CSharp): public static Mesh CloneMesh(Mesh source) { Mesh mesh = new Mesh(); // Using unity combine mesh to combine a single mesh into another one, making a full copy. CombineInstance[] instancesToCombine = new CombineInstance[source.subMeshCount]; for (int i = 0; i < source.subMeshCount; i++) { instancesToCombine[i] = new CombineInstance() { mesh = source, subMeshIndex = i, lightmapScaleOffset = new Vector4(1, 1, 0, 0), realtimeLightmapScaleOffset = new Vector4(1, 1, 0, 0), transform = Matrix4x4.identity }; } mesh.CombineMeshes(instancesToCombine, false, false, false); mesh.name = source.name; return mesh; }
I saw this thread started in 2009 and was just about to whine about necro-posting, but this is a pretty neat little future-proofing solution. Theoretically, if Mesh grows new features in the future, then the CombineMeshes API will grow to cover them automatically, instead of you needing to revisit your code here. https://docs.unity3d.com/ScriptReference/CombineInstance.html
Nice trick. I want to point out a little gotcha I found for a weird edge case: if you ever are saving Mesh *ASSETS* to disk and want to modify the mesh data in place without breaking prefabs that reference that mesh asset, you can't use this method - you have to load the mesh asset, then individually replace its vertices, colors, etc fields. In my case I have prefabs that reference certain mesh assets in order to handle vertex color palette swaps.