mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-09 19:18:05 -05:00
Merge pull request #912 from ousttrue/fix/mesh_export_divided
Fix/mesh export divided
This commit is contained in:
commit
a98c028f39
|
|
@ -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)
|
||||
|
|
|
|||
86
Assets/VRM/Tests/VrmDividedMeshTests.cs
Normal file
86
Assets/VRM/Tests/VrmDividedMeshTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM/Tests/VrmDividedMeshTests.cs.meta
Normal file
11
Assets/VRM/Tests/VrmDividedMeshTests.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5739a74d19763bb498ed1a035e25daf7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user