- Home /
AssetPostprocessor - Can't change Mesh Data
Hello again,
For the past couple hours I've been trying to solve the old: "Blender Axis is different to Unity's" problem by writing an AssetPostprocessor
.
In the Unity Documentation for AssetPostprocessor.OnPostprocessModel
it states: "This lets you modify the imported Game Object, Meshes, AnimationClips referenced by it", however after multiple attempts and a ton of google searches, I have not been able to change any mesh data and have it saved to disk:
import System.IO;
//Fix the ignorance of the standard Blender Importer!!!
class BlenderAssetProcessor extends AssetPostprocessor {
public function OnPostprocessModel(object:GameObject) {
var importer : ModelImporter = assetImporter as ModelImporter;
//Only rotate with blender files
if (Path.GetExtension(importer.assetPath) == ".blend") {
RotateObject(object);
}
}
private function RotateObject(object:GameObject) {
object.transform.rotation *= Quaternion.Euler(90, 0, 0); //This works and is saved
var meshFilter:MeshFilter = object.GetComponent(MeshFilter);
if (meshFilter) {
//Use proven methods to manipulate the mesh data
ChangeMesh(meshFilter.sharedMesh); //This changes the mesh, but nothing is saved???
}
//--some code that calls this recursively for children I left out
}
}
I get no errors and everything works absolutely fine, except for the fact that no mesh data is saved.
Has anyone been able to achieve something similar?
Is this even possible, because it definitely should be?!?
Thanks for your help,
Benproductions1
I'm afraid I don't know, but +1 for a well-written, relevant question. Let's hope for the sake of the community here that someone can write an equally eloquent answer :)
This looks like it could be a life-saver. Could you post your Change$$anonymous$$esh() function?
Answer by Benproductions1 · Nov 21, 2013 at 09:27 AM
Hello again again,
It turns out that mesh data is not passed by reference but via copy.
For instance:
Vector3[] verts = mesh.vertices;
verts[0] = Vector3.zero;
will not set the first vertex to Vector3.zero
What you need to do is set the vertex array of the mesh
Vector3[] verts = mesh.vertices;
verts[0] = Vector3.zero;
mesh.vertices = verts;
I find this to be counter-intuitive, but what can you do?
Hope this helps anyone else,
Benproductions1
This may reflect the underlying opengl implementation where the vertices are written to the graphics card memory. This way you are forced to batch your vertex writes (just a theory).
I've read a bit more and this does seem to be the case. http://answers.unity3d.com/questions/334473/can-i-move-just-some-of-the-verts-on-a-mesh.html
http://answers.unity3d.com/questions/352162/optimized-vertex-manipulation.html
It's bad api design if you ask me.. having the .vertices return a copy when the syntax implies you're getting a reference is not good design.
Answer by AubreyH · Aug 04, 2020 at 07:37 PM
Hope this helps. Tested in v 2020.2.
Make a script file anywhere sub an "Editor" directory in your Project folder. Copy the below. Save it. Reimport your blender folder full of .blend files.
Note, this is for just the meshes. I have not had a stab at skinning data or animation. Only use this for non animated meshes.
using UnityEngine;
using UnityEditor;
public class BlenderModelImporter : AssetPostprocessor
{
void OnPostprocessModel (GameObject g)
{
// Only operate on blender files
if (assetPath.IndexOf(".blend") == -1)
{
return;
}
MeshFilter[] meshf = g.GetComponentsInChildren<MeshFilter>();
foreach (MeshFilter meshFilter in meshf)
{
FixBlenderRotation(meshFilter);
}
AssetDatabase.Refresh();
}
private void FixBlenderRotation(MeshFilter meshFilter)
{
Mesh mesh = meshFilter.sharedMesh;
Matrix4x4 matRot = Matrix4x4.Rotate( Quaternion.Euler(-90,0,0));
Vector3[] rotatedVers = new Vector3[mesh.vertexCount];
Vector3[] rotatedNormies = new Vector3[mesh.vertexCount];
for (int i = 0; i < mesh.vertexCount; i++)
{
rotatedVers[i] = matRot * mesh.vertices[i];
rotatedNormies[i] = matRot * mesh.normals[i];
}
mesh.vertices = rotatedVers;
mesh.normals = rotatedNormies;
mesh.RecalculateBounds();//This makes sure that bounds culling has updated data so that the camera doesn't stop drawing based on the pre-rotation bounds
//Also bring back the transform rotation to identity so that there's no weird counter orientation in the game object itself.
meshFilter.transform.localRotation = Quaternion.identity;
}
}