Merge pull request #912 from ousttrue/fix/mesh_export_divided

Fix/mesh export divided
This commit is contained in:
PoChang007 2021-04-26 19:08:33 +09:00 committed by GitHub
commit a98c028f39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 151 additions and 25 deletions

View File

@ -7,7 +7,7 @@ namespace UniGLTF
{
public static class MeshExporterDivided
{
class BlendShapeBuffer
public class BlendShapeBuffer
{
readonly List<Vector3> m_positions;
readonly List<Vector3> m_normals;
@ -40,8 +40,32 @@ namespace UniGLTF
}
}
class VertexBuffer
public class VertexBuffer
{
/// <summary>
/// SubMeshで分割するので index が変わる。対応表
/// </summary>
/// <typeparam name="int"></typeparam>
/// <typeparam name="int"></typeparam>
/// <returns></returns>
readonly Dictionary<int, int> m_vertexIndexMap = new Dictionary<int, int>();
public bool ContainsTriangle(int v0, int v1, int v2)
{
if (!m_vertexIndexMap.ContainsKey(v0))
{
return false;
}
if (!m_vertexIndexMap.ContainsKey(v1))
{
return false;
}
if (!m_vertexIndexMap.ContainsKey(v2))
{
return false;
}
return true;
}
readonly List<Vector3> m_positions;
readonly List<Vector3> m_normals;
readonly List<Vector2> m_uv;
@ -50,22 +74,25 @@ namespace UniGLTF
readonly List<UShort4> m_joints;
readonly List<Vector4> m_weights;
public VertexBuffer(int reserve, Func<int, int> getJointIndex)
public VertexBuffer(int vertexCount, Func<int, int> getJointIndex)
{
m_positions = new List<Vector3>(reserve);
m_normals = new List<Vector3>(reserve);
m_positions = new List<Vector3>(vertexCount);
m_normals = new List<Vector3>(vertexCount);
m_uv = new List<Vector2>();
m_getJointIndex = getJointIndex;
if (m_getJointIndex != null)
{
m_joints = new List<UShort4>(reserve);
m_weights = new List<Vector4>(reserve);
m_joints = new List<UShort4>(vertexCount);
m_weights = new List<Vector4>(vertexCount);
}
}
public void Push(Vector3 position, Vector3 normal, Vector2 uv)
public void Push(int index, Vector3 position, Vector3 normal, Vector2 uv)
{
var newIndex = m_positions.Count;
m_vertexIndexMap.Add(index, newIndex);
m_positions.Add(position);
m_normals.Add(normal);
m_uv.Add(uv);
@ -77,9 +104,9 @@ namespace UniGLTF
m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3));
}
public glTFPrimitives ToGltf(glTF gltf, int bufferIndex, int materialIndex, IReadOnlyList<uint> indices)
public glTFPrimitives ToGltfPrimitive(glTF gltf, int bufferIndex, int materialIndex, IEnumerable<int> indices)
{
var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER);
var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.Select(x => (uint)m_vertexIndexMap[x]).ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER);
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_positions.ToArray(), glBufferTarget.ARRAY_BUFFER);
var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_normals.ToArray(), glBufferTarget.ARRAY_BUFFER);
var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_uv.ToArray(), glBufferTarget.ARRAY_BUFFER);
@ -109,6 +136,7 @@ namespace UniGLTF
material = materialIndex,
mode = 4,
};
return primitive;
}
}
@ -148,14 +176,6 @@ namespace UniGLTF
// mesh
// index の順に attributes を蓄える
var buffer = new VertexBuffer(indices.Length, getJointIndex);
// foreach (var k in indices)
// {
// buffer.Push(axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV());
// if (getJointIndex != null)
// {
// buffer.Push(boneWeights[k]);
// }
// }
// indices から参照される頂点だけを蓄える
usedIndices.Clear();
for (int k = 0; k < positions.Length; ++k)
@ -163,7 +183,7 @@ namespace UniGLTF
if (indices.Contains(k))
{
usedIndices.Add(k);
buffer.Push(axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV());
buffer.Push(k, axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV());
if (getJointIndex != null)
{
buffer.Push(boneWeights[k]);
@ -177,16 +197,25 @@ namespace UniGLTF
{
materialIndex = unityMaterials.IndexOf(material);
}
var indexMap = usedIndices.Select((used, index) => (used, index)).ToDictionary(x => x.used, x => (uint)x.index);
var flipped = new List<uint>();
var flipped = new List<int>();
for (int j = 0; j < indices.Length; j += 3)
{
flipped.Add((uint)indexMap[indices[j + 2]]);
flipped.Add((uint)indexMap[indices[j + 1]]);
flipped.Add((uint)indexMap[indices[j]]);
var t0 = indices[j];
var t1 = indices[j + 1];
var t2 = indices[j + 2];
if (buffer.ContainsTriangle(t0, t1, t2))
{
flipped.Add(t2);
flipped.Add(t1);
flipped.Add(t0);
}
else
{
Debug.LogWarning($"triangle not contains [{t0}, {t1}, {t2}]");
}
}
var gltfPrimitive = buffer.ToGltf(gltf, bufferIndex, materialIndex, flipped);
var gltfPrimitive = buffer.ToGltfPrimitive(gltf, bufferIndex, materialIndex, flipped);
// blendShape
for (int j = 0; j < mesh.blendShapeCount; ++j)

View File

@ -0,0 +1,86 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NUnit.Framework;
using UniGLTF;
using UnityEngine;
using VRMShaders;
namespace VRM
{
public class DividedMeshTests
{
static string AliciaPath
{
get
{
return Path.GetFullPath(Application.dataPath + "/../Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm")
.Replace("\\", "/");
}
}
static GameObject Load(byte[] bytes, string path)
{
var parser = new GltfParser();
parser.Parse(path, bytes);
using (var loader = new VRMImporterContext(parser))
{
loader.Load();
loader.ShowMeshes();
return loader.DisposeOnGameObjectDestroyed().gameObject;
}
}
static IEnumerable<Mesh> GetMeshes(GameObject gameObject)
{
foreach (var r in gameObject.GetComponentsInChildren<Renderer>())
{
if (r is SkinnedMeshRenderer smr)
{
yield return smr.sharedMesh;
}
else if (r is MeshRenderer mr)
{
yield return r.GetComponent<MeshFilter>().sharedMesh;
}
}
}
/// <summary>
/// positions: [
/// {1, 1, 0}
/// {1, 1, 1}
/// {1, 1, 2}
/// {1, 1, 3}
/// {1, 1, 4}
/// {1, 1, 5}
/// ]
/// submesh
/// 0 1 2
/// submesh
/// 3 4 5
/// </summary>
[Test]
public void ExportDividedMeshTest()
{
var path = AliciaPath;
var loaded = Load(File.ReadAllBytes(path), path);
var exported = VRMExporter.Export(new UniGLTF.MeshExportSettings
{
DivideVertexBuffer = true, // test this
ExportOnlyBlendShapePosition = true,
ExportTangents = false,
UseSparseAccessorForMorphTarget = true,
}, loaded, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime);
var bytes = exported.ToGlbBytes();
var divided = Load(bytes, path);
var src = GetMeshes(loaded).ToArray();
var div = GetMeshes(divided).ToArray();
Assert.AreEqual(src[0].triangles.Length, div[0].triangles.Length);
}
}
}

View File

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