mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-07 03:17:25 -05:00
MeshExporterDivided
This commit is contained in:
36
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs
Normal file
36
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public struct MeshExportSettings
|
||||
{
|
||||
//
|
||||
// https://github.com/vrm-c/UniVRM/issues/800
|
||||
//
|
||||
// VertexBuffer を共有バッファ方式にする
|
||||
// UniVRM-0.71.0 までの挙動
|
||||
//
|
||||
public bool UseSharingVertexBuffer;
|
||||
|
||||
// MorphTarget に Sparse Accessor を使う
|
||||
public bool UseSparseAccessorForMorphTarget;
|
||||
|
||||
// MorphTarget を Position だけにする(normal とか捨てる)
|
||||
public bool ExportOnlyBlendShapePosition;
|
||||
|
||||
// tangent を出力する
|
||||
public bool ExportTangents;
|
||||
|
||||
public static MeshExportSettings Default => new MeshExportSettings
|
||||
{
|
||||
UseSparseAccessorForMorphTarget = false,
|
||||
ExportOnlyBlendShapePosition = false,
|
||||
// WIP
|
||||
UseSharingVertexBuffer = true,
|
||||
#if GLTF_EXPORT_TANGENTS
|
||||
ExportTangents = true,
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26b97430e1698e94e9a27ab322f3eee5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,187 +6,8 @@ using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public struct MeshExportSettings
|
||||
{
|
||||
//
|
||||
// https://github.com/vrm-c/UniVRM/issues/800
|
||||
//
|
||||
// VertexBuffer を共有バッファ方式にする
|
||||
// UniVRM-0.71.0 までの挙動
|
||||
//
|
||||
public bool UseSharingVertexBuffer;
|
||||
|
||||
// MorphTarget に Sparse Accessor を使う
|
||||
public bool UseSparseAccessorForMorphTarget;
|
||||
|
||||
// MorphTarget を Position だけにする(normal とか捨てる)
|
||||
public bool ExportOnlyBlendShapePosition;
|
||||
|
||||
// tangent を出力する
|
||||
public bool ExportTangents;
|
||||
|
||||
public static MeshExportSettings Default => new MeshExportSettings
|
||||
{
|
||||
UseSparseAccessorForMorphTarget = false,
|
||||
ExportOnlyBlendShapePosition = false,
|
||||
#if GLTF_EXPORT_TANGENTS
|
||||
ExportTangents = true,
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
class MorphTarget
|
||||
{
|
||||
readonly string m_name;
|
||||
readonly List<Vector3> m_positions;
|
||||
readonly List<Vector3> m_normals;
|
||||
|
||||
public MorphTarget(string name, int reserve)
|
||||
{
|
||||
m_name = name;
|
||||
m_positions = new List<Vector3>(reserve);
|
||||
m_normals = new List<Vector3>(reserve);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class VertexBuffer
|
||||
{
|
||||
readonly IAxisInverter m_inverter;
|
||||
readonly int m_indexCount;
|
||||
readonly List<Vector3> m_positions;
|
||||
readonly List<Vector3> m_normals;
|
||||
readonly List<Vector2> m_uv;
|
||||
|
||||
readonly Func<int, int> m_getJointIndex;
|
||||
readonly List<UShort4> m_joints;
|
||||
readonly List<Vector4> m_weights;
|
||||
|
||||
readonly List<MorphTarget> m_morphs = new List<MorphTarget>();
|
||||
|
||||
|
||||
public VertexBuffer(IAxisInverter inverter, int reserve, Func<int, int> getJointIndex)
|
||||
{
|
||||
m_inverter = inverter;
|
||||
m_indexCount = reserve;
|
||||
m_positions = new List<Vector3>(reserve);
|
||||
m_normals = new List<Vector3>(reserve);
|
||||
m_uv = new List<Vector2>();
|
||||
|
||||
m_getJointIndex = getJointIndex;
|
||||
if (m_getJointIndex != null)
|
||||
{
|
||||
m_joints = new List<UShort4>(reserve);
|
||||
m_weights = new List<Vector4>(reserve);
|
||||
}
|
||||
}
|
||||
|
||||
public void Push(Vector3 position, Vector3 normal, Vector2 uv)
|
||||
{
|
||||
m_positions.Add(m_inverter.InvertVector3(position));
|
||||
m_normals.Add(m_inverter.InvertVector3(normal));
|
||||
m_uv.Add(uv.ReverseUV());
|
||||
}
|
||||
|
||||
public void Push(BoneWeight boneWeight)
|
||||
{
|
||||
m_joints.Add(new UShort4((ushort)boneWeight.boneIndex0, (ushort)boneWeight.boneIndex1, (ushort)boneWeight.boneIndex2, (ushort)boneWeight.boneIndex3));
|
||||
m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3));
|
||||
}
|
||||
|
||||
public glTFPrimitives ToGltf(glTF gltf, int bufferIndex, int materialIndex)
|
||||
{
|
||||
var indices = new List<uint>(m_indexCount);
|
||||
// flip triangles
|
||||
for (int i = 0; i < m_indexCount; i += 3)
|
||||
{
|
||||
// 2, 1, 0, 5, 4, 3, ...
|
||||
indices.Add((uint)(i + 2));
|
||||
indices.Add((uint)(i + 1));
|
||||
indices.Add((uint)(i + 0));
|
||||
}
|
||||
|
||||
var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.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);
|
||||
var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_joints.ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_weights.ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
|
||||
var primitive = new glTFPrimitives
|
||||
{
|
||||
indices = indicesAccessorIndex,
|
||||
attributes = new glTFAttributes
|
||||
{
|
||||
POSITION = positionAccessorIndex,
|
||||
NORMAL = normalAccessorIndex,
|
||||
TEXCOORD_0 = uvAccessorIndex0,
|
||||
JOINTS_0 = jointsAccessorIndex,
|
||||
WEIGHTS_0 = weightAccessorIndex,
|
||||
},
|
||||
material = materialIndex,
|
||||
mode = 4,
|
||||
targets = null,
|
||||
};
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MeshExporter
|
||||
{
|
||||
static glTFMesh ExportDividedVertexBuffer(glTF gltf, int bufferIndex,
|
||||
MeshWithRenderer unityMesh, List<Material> unityMaterials,
|
||||
IAxisInverter axisInverter, MeshExportSettings settings)
|
||||
{
|
||||
var mesh = unityMesh.Mesh;
|
||||
var gltfMesh = new glTFMesh(mesh.name);
|
||||
|
||||
if (settings.ExportTangents)
|
||||
{
|
||||
// support しない
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var positions = mesh.vertices;
|
||||
var normals = mesh.normals;
|
||||
var uv = mesh.uv;
|
||||
var boneWeights = mesh.boneWeights;
|
||||
|
||||
Func<int, int> getJointIndex = null;
|
||||
if (boneWeights != null && boneWeights.Length == positions.Length)
|
||||
{
|
||||
getJointIndex = unityMesh.GetJointIndex;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh.subMeshCount; ++i)
|
||||
{
|
||||
var indices = mesh.GetIndices(i);
|
||||
|
||||
// index の順に attributes を蓄える
|
||||
var buffer = new VertexBuffer(axisInverter, indices.Length, getJointIndex);
|
||||
foreach (var j in indices)
|
||||
{
|
||||
buffer.Push(positions[j], normals[j], uv[j]);
|
||||
if (getJointIndex != null)
|
||||
{
|
||||
buffer.Push(boneWeights[j]);
|
||||
}
|
||||
}
|
||||
|
||||
var material = unityMesh.Renderer.sharedMaterials[i];
|
||||
var materialIndex = -1;
|
||||
if (material != null)
|
||||
{
|
||||
materialIndex = unityMaterials.IndexOf(material);
|
||||
}
|
||||
gltfMesh.primitives.Add(buffer.ToGltf(gltf, bufferIndex, materialIndex));
|
||||
}
|
||||
|
||||
// morphTarget
|
||||
|
||||
return gltfMesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// primitive 間で vertex を共有する形で Export する。
|
||||
@@ -520,7 +341,7 @@ namespace UniGLTF
|
||||
}
|
||||
else
|
||||
{
|
||||
gltfMesh = ExportDividedVertexBuffer(gltf, bufferIndex, unityMesh, unityMaterials, axisInverter, settings);
|
||||
gltfMesh = MeshExporterDivided.Export(gltf, bufferIndex, unityMesh, unityMaterials, axisInverter, settings);
|
||||
}
|
||||
|
||||
return (gltfMesh, blendShapeIndexMap);
|
||||
|
||||
196
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs
Normal file
196
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class MeshExporterDivided
|
||||
{
|
||||
class BlendShapeBuffer
|
||||
{
|
||||
readonly List<Vector3> m_positions;
|
||||
readonly List<Vector3> m_normals;
|
||||
|
||||
public BlendShapeBuffer(int reserve)
|
||||
{
|
||||
m_positions = new List<Vector3>(reserve);
|
||||
m_normals = new List<Vector3>(reserve);
|
||||
}
|
||||
|
||||
public void Push(Vector3 position, Vector3 normal)
|
||||
{
|
||||
m_positions.Add(position);
|
||||
m_normals.Add(normal);
|
||||
}
|
||||
|
||||
public gltfMorphTarget ToGltf(glTF gltf, int bufferIndex, bool useNormal)
|
||||
{
|
||||
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_positions.ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
var normalAccessorIndex = -1;
|
||||
if (useNormal)
|
||||
{
|
||||
normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_normals.ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
return new gltfMorphTarget
|
||||
{
|
||||
POSITION = positionAccessorIndex,
|
||||
NORMAL = normalAccessorIndex,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class VertexBuffer
|
||||
{
|
||||
readonly int m_indexCount;
|
||||
readonly List<Vector3> m_positions;
|
||||
readonly List<Vector3> m_normals;
|
||||
readonly List<Vector2> m_uv;
|
||||
|
||||
readonly Func<int, int> m_getJointIndex;
|
||||
readonly List<UShort4> m_joints;
|
||||
readonly List<Vector4> m_weights;
|
||||
|
||||
public VertexBuffer(int reserve, Func<int, int> getJointIndex)
|
||||
{
|
||||
m_indexCount = reserve;
|
||||
m_positions = new List<Vector3>(reserve);
|
||||
m_normals = new List<Vector3>(reserve);
|
||||
m_uv = new List<Vector2>();
|
||||
|
||||
m_getJointIndex = getJointIndex;
|
||||
if (m_getJointIndex != null)
|
||||
{
|
||||
m_joints = new List<UShort4>(reserve);
|
||||
m_weights = new List<Vector4>(reserve);
|
||||
}
|
||||
}
|
||||
|
||||
public void Push(Vector3 position, Vector3 normal, Vector2 uv)
|
||||
{
|
||||
m_positions.Add(position);
|
||||
m_normals.Add(normal);
|
||||
m_uv.Add(uv);
|
||||
}
|
||||
|
||||
public void Push(BoneWeight boneWeight)
|
||||
{
|
||||
m_joints.Add(new UShort4((ushort)boneWeight.boneIndex0, (ushort)boneWeight.boneIndex1, (ushort)boneWeight.boneIndex2, (ushort)boneWeight.boneIndex3));
|
||||
m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3));
|
||||
}
|
||||
|
||||
public glTFPrimitives ToGltf(glTF gltf, int bufferIndex, int materialIndex)
|
||||
{
|
||||
var indices = new List<uint>(m_indexCount);
|
||||
// flip triangles
|
||||
for (int i = 0; i < m_indexCount; i += 3)
|
||||
{
|
||||
// 2, 1, 0, 5, 4, 3, ...
|
||||
indices.Add((uint)(i + 2));
|
||||
indices.Add((uint)(i + 1));
|
||||
indices.Add((uint)(i + 0));
|
||||
}
|
||||
|
||||
var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.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);
|
||||
var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_joints.ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_weights.ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
|
||||
var primitive = new glTFPrimitives
|
||||
{
|
||||
indices = indicesAccessorIndex,
|
||||
attributes = new glTFAttributes
|
||||
{
|
||||
POSITION = positionAccessorIndex,
|
||||
NORMAL = normalAccessorIndex,
|
||||
TEXCOORD_0 = uvAccessorIndex0,
|
||||
JOINTS_0 = jointsAccessorIndex,
|
||||
WEIGHTS_0 = weightAccessorIndex,
|
||||
},
|
||||
material = materialIndex,
|
||||
mode = 4,
|
||||
};
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
|
||||
public static glTFMesh Export(glTF gltf, int bufferIndex,
|
||||
MeshWithRenderer unityMesh, List<Material> unityMaterials,
|
||||
IAxisInverter axisInverter, MeshExportSettings settings)
|
||||
{
|
||||
var mesh = unityMesh.Mesh;
|
||||
var gltfMesh = new glTFMesh(mesh.name);
|
||||
|
||||
if (settings.ExportTangents)
|
||||
{
|
||||
// support しない
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var positions = mesh.vertices;
|
||||
var normals = mesh.normals;
|
||||
var uv = mesh.uv;
|
||||
var boneWeights = mesh.boneWeights;
|
||||
|
||||
Func<int, int> getJointIndex = null;
|
||||
if (boneWeights != null && boneWeights.Length == positions.Length)
|
||||
{
|
||||
getJointIndex = unityMesh.GetJointIndex;
|
||||
}
|
||||
|
||||
Vector3[] blendShapePositions = new Vector3[mesh.vertexCount];
|
||||
Vector3[] blendShapeNormals = new Vector3[mesh.vertexCount];
|
||||
|
||||
for (int i = 0; i < mesh.subMeshCount; ++i)
|
||||
{
|
||||
var indices = mesh.GetIndices(i);
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
var material = unityMesh.Renderer.sharedMaterials[i];
|
||||
var materialIndex = -1;
|
||||
if (material != null)
|
||||
{
|
||||
materialIndex = unityMaterials.IndexOf(material);
|
||||
}
|
||||
var gltfPrimitive = buffer.ToGltf(gltf, bufferIndex, materialIndex);
|
||||
|
||||
// blendShape
|
||||
for (int j = 0; j < mesh.blendShapeCount; ++j)
|
||||
{
|
||||
var blendShape = new BlendShapeBuffer(indices.Length);
|
||||
|
||||
// index の順に attributes を蓄える
|
||||
mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null);
|
||||
foreach (var k in indices)
|
||||
{
|
||||
blendShape.Push(
|
||||
axisInverter.InvertVector3(blendShapePositions[k]),
|
||||
axisInverter.InvertVector3(blendShapeNormals[k]));
|
||||
}
|
||||
|
||||
gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, bufferIndex, !settings.ExportOnlyBlendShapePosition));
|
||||
}
|
||||
|
||||
gltfMesh.primitives.Add(gltfPrimitive);
|
||||
}
|
||||
|
||||
var targetNames = Enumerable.Range(0, mesh.blendShapeCount).Select(x => mesh.GetBlendShapeName(x)).ToArray();
|
||||
gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);
|
||||
|
||||
return gltfMesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92bc82be5ead84a429346379590f6d7d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user