Merge pull request #764 from ichi-23/ichi/add_mesh_export_func

MeshExporter に Renderer を必要としない Export 関数を追加

`v0.68.0`
This commit is contained in:
ousttrue
2021-03-01 17:35:36 +09:00
committed by GitHub

View File

@@ -23,6 +23,132 @@ namespace UniGLTF
public static class MeshExporter
{
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex, Mesh mesh, Material[] meshMaterials, BoneWeight[] boneWeights, int[] jointIndexMap,
List<Material> exportedMaterials)
{
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();
gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();
var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.normalized.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
#if GLTF_EXPORT_TANGENTS
var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
#endif
var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
var uvAccessorIndex1 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv2.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
var colorAccessorIndex = -1;
var vColorState = MeshExportInfo.DetectVertexColor(mesh, meshMaterials);
if (vColorState == MeshExportInfo.VertexColorState.ExistsAndIsUsed // VColor使っている
|| vColorState == MeshExportInfo.VertexColorState.ExistsAndMixed // VColorを使っているところと使っていないところが混在(とりあえずExportする)
)
{
// UniUnlit で Multiply 設定になっている
colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER);
}
var weightAccessorIndex = -1;
var jointsAccessorIndex = -1;
if (boneWeights != null && jointIndexMap != null)
{
weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneWeights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneWeights.Select(y =>
new UShort4(
(ushort)jointIndexMap[y.boneIndex0],
(ushort)jointIndexMap[y.boneIndex1],
(ushort)jointIndexMap[y.boneIndex2],
(ushort)jointIndexMap[y.boneIndex3])
).ToArray(), glBufferTarget.ARRAY_BUFFER);
}
var attributes = new glTFAttributes
{
POSITION = positionAccessorIndex,
};
if (normalAccessorIndex != -1)
{
attributes.NORMAL = normalAccessorIndex;
}
#if GLTF_EXPORT_TANGENTS
if (tangentAccessorIndex != -1)
{
attributes.TANGENT = tangentAccessorIndex;
}
#endif
if (uvAccessorIndex0 != -1)
{
attributes.TEXCOORD_0 = uvAccessorIndex0;
}
if (uvAccessorIndex1 != -1)
{
attributes.TEXCOORD_1 = uvAccessorIndex1;
}
if (colorAccessorIndex != -1)
{
attributes.COLOR_0 = colorAccessorIndex;
}
if (weightAccessorIndex != -1)
{
attributes.WEIGHTS_0 = weightAccessorIndex;
}
if (jointsAccessorIndex != -1)
{
attributes.JOINTS_0 = jointsAccessorIndex;
}
var gltfMesh = new glTFMesh(mesh.name);
var indices = new List<uint>();
for (var j = 0; j < mesh.subMeshCount; ++j)
{
indices.Clear();
var triangles = mesh.GetIndices(j);
if (triangles.Length == 0)
{
// https://github.com/vrm-c/UniVRM/issues/664
continue;
}
for (var i = 0; i < triangles.Length; i += 3)
{
var i0 = triangles[i];
var i1 = triangles[i + 1];
var i2 = triangles[i + 2];
// flip triangle
indices.Add((uint)i2);
indices.Add((uint)i1);
indices.Add((uint)i0);
}
var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER);
if (indicesAccessorIndex < 0)
{
// https://github.com/vrm-c/UniVRM/issues/664
throw new Exception();
}
var primitives = new glTFPrimitives
{
attributes = attributes,
indices = indicesAccessorIndex,
mode = 4, // triangles ?
};
if (meshMaterials != null)
{
primitives.material = exportedMaterials.IndexOf(meshMaterials[j]);
}
gltfMesh.primitives.Add(primitives);
}
return gltfMesh;
}
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex,
MeshWithRenderer unityMesh, List<Material> unityMaterials,
IAxisInverter axisInverter)
@@ -328,5 +454,64 @@ namespace UniGLTF
yield return (unityMesh.Mesh, gltfMesh, blendShapeIndexMap);
}
}
public static (glTFMesh gltfMesh, Dictionary<int, int> blendShapeIndexMap) ExportMesh(glTF gltf, int bufferIndex, Mesh mesh, Renderer renderer, List<Material> exportedMaterials, MeshExportSettings meshExportSettings, IAxisInverter axisInverter)
{
var meshMaterials = default(Material[]);
if (renderer != null)
{
meshMaterials = renderer.sharedMaterials;
}
var boneWeights = default(BoneWeight[]);
var jointIndexMap = default(int[]);
if (renderer is SkinnedMeshRenderer skin)
{
var bones = skin.bones;
var uniqueBones = bones.Distinct().ToArray();
jointIndexMap = new int[bones.Length];
for (var i = 0; i < bones.Length; i++)
{
jointIndexMap[i] = Array.IndexOf(uniqueBones, bones[i]);
}
boneWeights = mesh.boneWeights;
}
var gltfMesh = ExportPrimitives(gltf, bufferIndex, mesh, meshMaterials, boneWeights, jointIndexMap, exportedMaterials);
var targetNames = new List<string>();
var blendShapeIndexMap = new Dictionary<int, int>();
int exportBlendShapes = 0;
for (int j = 0; j < mesh.blendShapeCount; ++j)
{
var morphTarget = ExportMorphTarget(gltf, bufferIndex,
mesh, j,
meshExportSettings.UseSparseAccessorForMorphTarget,
meshExportSettings.ExportOnlyBlendShapePosition, axisInverter);
if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0)
{
continue;
}
// maybe skip
var blendShapeName = mesh.GetBlendShapeName(j);
blendShapeIndexMap.Add(j, exportBlendShapes++);
targetNames.Add(blendShapeName);
//
// all primitive has same blendShape
//
for (int k = 0; k < gltfMesh.primitives.Count; ++k)
{
gltfMesh.primitives[k].targets.Add(morphTarget);
}
}
gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);
return (gltfMesh, blendShapeIndexMap);
}
}
}