mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-08 03:48:19 -05:00
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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user