fix blendshape bake.

簡単になるように処理順をみなおし。

            var mesh = src.sharedMesh.Copy(false, ".baked");
            src.BakeMesh(mesh);
            CopyBlendShapes(src, mesh);

            var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one);
            mesh.ApplyMatrixAlsoBlendShapes(m); // 最後の一回だけまとめて matrix を適用する
This commit is contained in:
ousttrue
2024-06-24 17:39:27 +09:00
parent 3104b4c755
commit 85bfe4bcd1
2 changed files with 138 additions and 66 deletions

View File

@@ -1,6 +1,8 @@
using UnityEngine;
using System.Linq;
using VRMShaders;
using System;
using System.Collections.Generic;
namespace UniGLTF.MeshUtility
@@ -23,10 +25,10 @@ namespace UniGLTF.MeshUtility
return null;
}
public static Mesh Copy(this Mesh src, bool copyBlendShape)
public static Mesh Copy(this Mesh src, bool copyBlendShape, string nameSuffix = "(copy)")
{
var dst = new Mesh();
dst.name = src.name + "(copy)";
dst.name = src.name + nameSuffix;
#if UNITY_2017_3_OR_NEWER
dst.indexFormat = src.indexFormat;
#endif
@@ -108,5 +110,67 @@ namespace UniGLTF.MeshUtility
}).ToArray();
}
}
class BlendShape
{
public readonly string Name;
public readonly float FrameWeight;
public readonly Vector3[] Vertices;
public readonly Vector3[] Normals;
public readonly Vector3[] Tangents;
public BlendShape(string name, float frameweight,
IEnumerable<Vector3> vertices,
IEnumerable<Vector3> normals,
IEnumerable<Vector3> tangents)
{
Name = name;
FrameWeight = frameweight;
Vertices = vertices.ToArray();
Normals = normals.ToArray();
Tangents = tangents.ToArray();
}
public static BlendShape FromMesh(Mesh mesh, int i, Matrix4x4 m)
{
var blendShapePositions = new Vector3[mesh.vertexCount];
var blendShapeNormals = new Vector3[mesh.vertexCount];
var blendShapeTangents = new Vector3[mesh.vertexCount];
mesh.GetBlendShapeFrameVertices(i, 0, blendShapePositions, blendShapeNormals, blendShapeTangents);
return new BlendShape(
mesh.GetBlendShapeName(i), mesh.GetBlendShapeFrameWeight(i, 0),
blendShapePositions.Select(x => m.MultiplyPoint(x)),
blendShapeNormals.Select(x => m.MultiplyPoint(x)),
blendShapeTangents.Select(x => m.MultiplyPoint(x)));
}
}
public static void ApplyMatrixAlsoBlendShapes(this Mesh src, Matrix4x4 m)
{
src.vertices = src.vertices.Select(x => m.MultiplyPoint(x)).ToArray();
if (src.normals != null && src.normals.Length > 0)
{
src.normals = src.normals.Select(x => m.MultiplyVector(x.normalized)).ToArray();
}
if (src.tangents != null && src.tangents.Length > 0)
{
src.tangents = src.tangents.Select(x =>
{
var t = m.MultiplyVector((Vector3)x);
return new Vector4(t.x, t.y, t.z, x.w);
}).ToArray();
}
var blendshapes = new List<BlendShape>();
for (int i = 0; i < src.blendShapeCount; ++i)
{
blendshapes.Add(BlendShape.FromMesh(src, i, m));
}
src.ClearBlendShapes();
foreach (var blendshape in blendshapes)
{
src.AddBlendShapeFrame(blendshape.Name, blendshape.FrameWeight,
blendshape.Vertices, null, null);
}
}
}
}

View File

@@ -140,62 +140,67 @@ namespace UniGLTF.MeshUtility
return default;
}
var srcMesh = src.sharedMesh;
var originalSrcMesh = srcMesh;
var hasBoneWeight = src.bones != null && src.bones.Length > 0;
if (!hasBoneWeight)
if (!HasBoneWeight(src))
{
// Before bake, bind no weight bones
srcMesh = srcMesh.Copy(true);
srcMesh.ApplyRotationAndScale(src.transform.localToWorldMatrix, false);
var bw = new BoneWeight
{
boneIndex0 = 0,
boneIndex1 = 0,
boneIndex2 = 0,
boneIndex3 = 0,
weight0 = 1.0f,
weight1 = 0.0f,
weight2 = 0.0f,
weight3 = 0.0f,
};
srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray();
src.bones = new[] { src.rootBone ?? src.transform };
srcMesh.bindposes = src.bones.Select(x => x.worldToLocalMatrix).ToArray();
src.sharedMesh = srcMesh;
//
// blendshape があって bone が無い SkinnedMeshRenderer と思われる。
// SkinnedMeshRenderer.transform に対する boneweight を付与する。
AssignSingleBoneWeight(src);
}
// BakeMesh
var mesh = srcMesh.Copy(false);
mesh.name = srcMesh.name + ".baked";
var mesh = src.sharedMesh.Copy(false, ".baked");
src.BakeMesh(mesh);
CopyBlendShapes(src, mesh);
mesh.boneWeights = srcMesh.boneWeights;
{
// apply SkinnedMesh.transform rotation
var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one);
mesh.ApplyMatrix(m);
}
// apply SkinnedMesh.transform rotation
var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one);
mesh.ApplyMatrixAlsoBlendShapes(m);
//
// BlendShapes
//
{
var m = src.localToWorldMatrix; // include scaling
m.SetColumn(3, new Vector4(0, 0, 0, 1)); // no translation
CopyBlendShapes(src, srcMesh, mesh, m);
}
// {
// var m = src.localToWorldMatrix; // include scaling
// m.SetColumn(3, new Vector4(0, 0, 0, 1)); // no translation
// CopyBlendShapes(src, srcMesh, mesh, m);
// }
return mesh;
}
private static void CopyBlendShapes(SkinnedMeshRenderer src, Mesh srcMesh, Mesh mesh, Matrix4x4 m)
public static bool HasBoneWeight(SkinnedMeshRenderer src)
{
return src.bones != null && src.bones.Length > 0;
}
public static void AssignSingleBoneWeight(SkinnedMeshRenderer src)
{
var srcMesh = src.sharedMesh.Copy(true);
srcMesh.ApplyRotationAndScale(src.transform.localToWorldMatrix, false);
var bw = new BoneWeight
{
boneIndex0 = 0,
boneIndex1 = 0,
boneIndex2 = 0,
boneIndex3 = 0,
weight0 = 1.0f,
weight1 = 0.0f,
weight2 = 0.0f,
weight3 = 0.0f,
};
srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray();
src.bones = new[] { src.rootBone ?? src.transform };
srcMesh.bindposes = src.bones.Select(x => x.worldToLocalMatrix).ToArray();
src.sharedMesh = srcMesh;
}
private static void CopyBlendShapes(SkinnedMeshRenderer src, Mesh mesh)
{
var srcMesh = src.sharedMesh;
var blendShapeValues = new Dictionary<int, float>();
for (int i = 0; i < srcMesh.blendShapeCount; i++)
{
@@ -258,28 +263,30 @@ namespace UniGLTF.MeshUtility
for (int j = 0; j < vertices.Length; ++j)
{
if (originalBlendShapePositions[j] == Vector3.zero)
{
vertices[j] = Vector3.zero;
}
else
{
vertices[j] = m.MultiplyPoint(vertices[j] - meshVertices[j]);
}
// if (originalBlendShapePositions[j] == Vector3.zero)
// {
// vertices[j] = Vector3.zero;
// }
// else
// {
// vertices[j] = m.MultiplyPoint(vertices[j] - meshVertices[j]);
// }
vertices[j] = vertices[j] - meshVertices[j];
}
Vector3[] normals = blendShapeMesh.normals;
for (int j = 0; j < normals.Length; ++j)
{
if (originalBlendShapeNormals[j] == Vector3.zero)
{
normals[j] = Vector3.zero;
// if (originalBlendShapeNormals[j] == Vector3.zero)
// {
// normals[j] = Vector3.zero;
}
else
{
normals[j] = m.MultiplyVector(normals[j].normalized) - meshNormals[j];
}
// }
// else
// {
// normals[j] = m.MultiplyVector(normals[j].normalized) - meshNormals[j];
// }
normals[j] = normals[j] - meshNormals[j];
}
Vector3[] tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray();
@@ -287,14 +294,15 @@ namespace UniGLTF.MeshUtility
{
for (int j = 0; j < tangents.Length; ++j)
{
if (originalBlendShapeTangents[j] == Vector3.zero)
{
tangents[j] = Vector3.zero;
}
else
{
tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j];
}
// if (originalBlendShapeTangents[j] == Vector3.zero)
// {
// tangents[j] = Vector3.zero;
// }
// else
// {
// tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j];
// }
tangents[j] = tangents[j] - meshTangents[j];
}
}