Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Mar 1, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,132 @@ public struct MeshExportSettings

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)
Expand Down Expand Up @@ -328,5 +454,64 @@ static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex,
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)
{
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);
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);
}
}
}