avatar/Assets/VRCFury/Scripts/Editor/VF/Builder/MeshBaker.cs

57 lines
2.3 KiB
C#

using System.Linq;
using UnityEngine;
namespace VF.Builder {
public static class MeshBaker {
/**
* Returns a baked mesh, where the vertices are in local space in relation to the renderer's transform.
* This is true even for skinned meshes (where in other places, the offsets are commonly in relation to the root bone)
*/
public static BakedMesh BakeMesh(Renderer renderer, Transform origin = null) {
Mesh mesh;
if (renderer is SkinnedMeshRenderer skin) {
// If the skinned mesh doesn't have any bones attached, it's treated like a regular mesh and BakeMesh applies no transforms
// So we have to skip calling BakeMesh, because otherwise we'd apply the inverse scale inappropriately and it would be too small.
var actuallySkinned = skin.sharedMesh && skin.sharedMesh.boneWeights.Length > 0;
if (actuallySkinned) {
var temporaryMesh = new Mesh();
skin.BakeMesh(temporaryMesh);
var verts = temporaryMesh.vertices;
var scale = skin.transform.lossyScale;
var inverseScale = new Vector3(1 / scale.x, 1 / scale.y, 1 / scale.z);
for (var i = 0; i < verts.Length; i++) {
verts[i].Scale(inverseScale);
}
temporaryMesh.vertices = verts;
mesh = temporaryMesh;
} else {
mesh = skin.sharedMesh;
}
} else {
var meshFilter = renderer.GetComponent<MeshFilter>();
mesh = meshFilter ? meshFilter.sharedMesh : null;
}
if (!mesh) return null;
Vector3[] vertices;
if (origin) {
vertices = mesh.vertices
.Select(v => origin.InverseTransformPoint(renderer.transform.TransformPoint(v))).ToArray();
} else {
vertices = mesh.vertices;
}
return new BakedMesh() {
vertices = vertices,
normals = mesh.normals
};
}
public class BakedMesh {
public Vector3[] vertices;
public Vector3[] normals;
}
}
}