Merge pull request #668 from ousttrue/feature/unique_joints

Feature/unique joints
This commit is contained in:
ousttrue
2021-01-14 19:55:34 +09:00
committed by GitHub
6 changed files with 154 additions and 59 deletions

View File

@@ -17,13 +17,17 @@ namespace MeshUtility.Validators
[LangMsg(Languages.en, "ExportRoot must be topmost parent")]
NO_PARENT,
[LangMsg(Languages.ja, "ヒエラルキーに active なメッシュが含まれていない")]
[LangMsg(Languages.ja, "ヒエラルキーに active なメッシュが含まれていません")]
[LangMsg(Languages.en, "No active mesh")]
NO_ACTIVE_MESH,
[LangMsg(Languages.ja, "ヒエラルキーの中に同じ名前のGameObjectが含まれている。 エクスポートした場合に自動でリネームす")]
[LangMsg(Languages.ja, "ヒエラルキーの中に同じ名前のGameObjectが含まれている。 エクスポートした場合に自動でリネームします")]
[LangMsg(Languages.en, "There are bones with the same name in the hierarchy. They will be automatically renamed after export")]
DUPLICATE_BONE_NAME_EXISTS,
[LangMsg(Languages.ja, "SkinnedMeshRenderer.bones に重複する内容がある。エクスポートした場合に、bones の重複を取り除き、boneweights, bindposes を調整します")]
[LangMsg(Languages.en, "There are same bone in bones the SkinnedMeshRenderer. They will be automatically uniqued")]
NO_UNIQUE_JOINTS,
}
/// <summary>
@@ -45,6 +49,19 @@ namespace MeshUtility.Validators
return (duplicates.Any());
}
static bool HasNoUniqueJoints(Renderer r)
{
if (r is SkinnedMeshRenderer skin)
{
if (skin.bones != null && skin.bones.Length != skin.bones.Distinct().Count())
{
return true;
}
}
return false;
}
public static IEnumerable<Validation> Validate(GameObject ExportRoot)
{
if (ExportRoot == null)
@@ -66,6 +83,11 @@ namespace MeshUtility.Validators
yield break;
}
if (renderers.Any(x => HasNoUniqueJoints(x)))
{
yield return Validation.Warning(ExportValidatorMessages.NO_UNIQUE_JOINTS.Msg());
}
if (DuplicateNodeNameExists(ExportRoot))
{
yield return Validation.Warning(ExportValidatorMessages.DUPLICATE_BONE_NAME_EXISTS.Msg());

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UniJSON;
using UnityEngine;
namespace UniGLTF
@@ -24,10 +23,10 @@ namespace UniGLTF
public static class MeshExporter
{
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex,
string rendererName,
Mesh mesh, Material[] materials,
List<Material> unityMaterials)
MeshWithRenderer unityMesh, List<Material> unityMaterials)
{
var mesh = unityMesh.Mesh;
var materials = unityMesh.Renderer.sharedMaterials;
var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray();
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER);
gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
@@ -53,7 +52,13 @@ namespace UniGLTF
var boneweights = mesh.boneWeights;
var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y =>
new UShort4(
(ushort)unityMesh.GetJointIndex(y.boneIndex0),
(ushort)unityMesh.GetJointIndex(y.boneIndex1),
(ushort)unityMesh.GetJointIndex(y.boneIndex2),
(ushort)unityMesh.GetJointIndex(y.boneIndex3))
).ToArray(), glBufferTarget.ARRAY_BUFFER);
var attributes = new glTFAttributes
{
@@ -124,7 +129,7 @@ namespace UniGLTF
if (j >= materials.Length)
{
Debug.LogWarningFormat("{0}.materials is not enough", rendererName);
Debug.LogWarningFormat("{0}.materials is not enough", unityMesh.Renderer.name);
break;
}
@@ -277,36 +282,23 @@ namespace UniGLTF
};
}
public struct MeshWithRenderer
{
public Mesh Mesh;
[Obsolete("Use Renderer")]
public Renderer Rendererer { get { return Renderer; } set { Renderer = value; } }
public Renderer Renderer;
}
public static IEnumerable<(Mesh, glTFMesh, Dictionary<int, int>)> ExportMeshes(glTF gltf, int bufferIndex,
List<MeshWithRenderer> unityMeshes, List<Material> unityMaterials,
MeshExportSettings settings)
{
for (int i = 0; i < unityMeshes.Count; ++i)
foreach (var unityMesh in unityMeshes)
{
var x = unityMeshes[i];
var mesh = x.Mesh;
var materials = x.Renderer.sharedMaterials;
var gltfMesh = ExportPrimitives(gltf, bufferIndex,
x.Renderer.name,
mesh, materials, unityMaterials);
unityMesh, unityMaterials);
var targetNames = new List<string>();
var blendShapeIndexMap = new Dictionary<int, int>();
int exportBlendShapes = 0;
for (int j = 0; j < mesh.blendShapeCount; ++j)
for (int j = 0; j < unityMesh.Mesh.blendShapeCount; ++j)
{
var morphTarget = ExportMorphTarget(gltf, bufferIndex,
mesh, j,
unityMesh.Mesh, j,
settings.UseSparseAccessorForMorphTarget,
settings.ExportOnlyBlendShapePosition);
if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0)
@@ -315,7 +307,7 @@ namespace UniGLTF
}
// maybe skip
var blendShapeName = mesh.GetBlendShapeName(j);
var blendShapeName = unityMesh.Mesh.GetBlendShapeName(j);
blendShapeIndexMap.Add(j, exportBlendShapes++);
targetNames.Add(blendShapeName);
@@ -330,7 +322,7 @@ namespace UniGLTF
gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);
yield return (mesh, gltfMesh, blendShapeIndexMap);
yield return (unityMesh.Mesh, gltfMesh, blendShapeIndexMap);
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UniGLTF
{
public struct MeshWithRenderer
{
public readonly Mesh Mesh;
public readonly Renderer Renderer;
public readonly Transform[] UniqueBones;
readonly int[] JointIndexMap;
public MeshWithRenderer(Transform x)
{
Mesh = x.GetSharedMesh();
Renderer = x.GetComponent<Renderer>();
if (Renderer is SkinnedMeshRenderer skin && skin.bones != null && skin.bones.Length > 0)
{
// has joints
var uniqueBones = skin.bones.Distinct().ToArray();
UniqueBones = uniqueBones;
JointIndexMap = new int[skin.bones.Length];
var bones = skin.bones;
for (int i = 0; i < bones.Length; ++i)
{
JointIndexMap[i] = Array.IndexOf(uniqueBones, bones[i]);
}
}
else
{
UniqueBones = null;
JointIndexMap = null;
}
}
public int GetJointIndex(int index)
{
if (index < 0)
{
return index;
}
if (JointIndexMap != null)
{
return JointIndexMap[index];
}
else
{
return index;
}
}
public IEnumerable<Matrix4x4> GetBindPoses()
{
var used = new HashSet<int>();
for (int i = 0; i < JointIndexMap.Length; ++i)
{
var index = JointIndexMap[i];
if (used.Add(index))
{
yield return Mesh.bindposes[i];
}
}
}
public static IEnumerable<MeshWithRenderer> FromNodes(IEnumerable<Transform> nodes)
{
foreach (var node in nodes)
{
var x = new MeshWithRenderer(node);
if (x.Mesh == null)
{
continue; ;
}
if (x.Renderer.sharedMaterials == null
|| x.Renderer.sharedMaterials.Length == 0)
{
continue;
}
yield return x;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6f745ee7743b23243bf6adcb740dab82
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -252,27 +252,7 @@ namespace UniGLTF
#endregion
#region Meshes
var unityMeshes = Nodes
.Select(x => new MeshExporter.MeshWithRenderer
{
Mesh = x.GetSharedMesh(),
Renderer = x.GetComponent<Renderer>(),
})
.Where(x =>
{
if (x.Mesh == null)
{
return false;
}
if (x.Renderer.sharedMaterials == null
|| x.Renderer.sharedMaterials.Length == 0)
{
return false;
}
return true;
})
.ToList();
var unityMeshes = MeshWithRenderer.FromNodes(Nodes).ToList();
MeshBlendShapeIndexMap = new Dictionary<Mesh, Dictionary<int, int>>();
foreach (var (mesh, gltfMesh, blendShapeIndexMap) in MeshExporter.ExportMeshes(
@@ -289,13 +269,10 @@ namespace UniGLTF
#endregion
#region Nodes and Skins
var unitySkins = Nodes
.Select(x => x.GetComponent<SkinnedMeshRenderer>()).Where(x =>
x != null
&& x.bones != null
&& x.bones.Length > 0)
var unitySkins = unityMeshes
.Where(x => x.UniqueBones != null)
.ToList();
glTF.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Renderer).ToList(), unitySkins)).ToList();
glTF.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Renderer).ToList(), unitySkins.Select(y => y.Renderer as SkinnedMeshRenderer).ToList())).ToList();
glTF.scenes = new List<gltfScene>
{
new gltfScene
@@ -306,19 +283,20 @@ namespace UniGLTF
foreach (var x in unitySkins)
{
var matrices = x.sharedMesh.bindposes.Select(y => y.ReverseZ()).ToArray();
var matrices = x.GetBindPoses().Select(y => y.ReverseZ()).ToArray();
var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE);
var renderer = x.Renderer as SkinnedMeshRenderer;
var skin = new glTFSkin
{
inverseBindMatrices = accessor,
joints = x.bones.Select(y => Nodes.IndexOf(y)).ToArray(),
skeleton = Nodes.IndexOf(x.rootBone),
joints = x.UniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(),
skeleton = Nodes.IndexOf(renderer.rootBone),
};
var skinIndex = glTF.skins.Count;
glTF.skins.Add(skin);
foreach (var z in Nodes.Where(y => y.Has(x)))
foreach (var z in Nodes.Where(y => y.Has(x.Renderer)))
{
var nodeIndex = Nodes.IndexOf(z);
var node = glTF.nodes[nodeIndex];

View File

@@ -83,7 +83,10 @@ namespace VRM
.ToDictionary(x => x.Key, x => boneMap[x.Value])
;
var animator = dst.AddComponent<Animator>();
if (dst.GetComponent<Animator>() == null)
{
var animator = dst.AddComponent<Animator>();
}
var vrmHuman = go.GetComponent<VRMHumanoidDescription>();
var avatarDescription = AvatarDescription.Create();
if (vrmHuman != null && vrmHuman.Description != null)