BlendShapeExporter を準備中

This commit is contained in:
ousttrue 2021-06-04 13:39:28 +09:00
parent d46819bc85
commit 7e42a8bd12
6 changed files with 113 additions and 47 deletions

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UniGLTF
{
public struct SparseBase
{
public readonly Vector3[] Positions;
public readonly Vector3[] Normals;
public SparseBase(Vector3[] positions, Vector3[] normals)
{
Positions = positions;
Normals = normals;
}
}
public static class BlendShapeExporter
{
public static gltfMorphTarget Export(glTF gltf, int gltfBuffer, Vector3[] positions, Vector3[] normals, SparseBase? sparseBase)
{
if (sparseBase.HasValue)
{
throw new NotImplementedException();
}
else
{
// position
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(gltfBuffer, 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();
// normal
var normalAccessorIndex = -1;
if (normals != null)
{
normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(gltfBuffer, normals, glBufferTarget.ARRAY_BUFFER);
}
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();
return new gltfMorphTarget
{
POSITION = positionAccessorIndex,
NORMAL = normalAccessorIndex,
};
}
}
}
}

View File

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

View File

@ -15,37 +15,27 @@ namespace UniGLTF
{
public class BlendShapeBuffer
{
readonly List<Vector3> m_positions;
readonly List<Vector3> m_normals;
readonly Vector3[] m_positions;
readonly Vector3[] m_normals;
public BlendShapeBuffer(int reserve)
{
m_positions = new List<Vector3>(reserve);
m_normals = new List<Vector3>(reserve);
m_positions = new Vector3[reserve];
m_normals = new Vector3[reserve];
}
public void Push(Vector3 position, Vector3 normal)
public void Set(int index, Vector3 position, Vector3 normal)
{
m_positions.Add(position);
m_normals.Add(normal);
m_positions[index] = position;
m_normals[index] = normal;
}
public gltfMorphTarget ToGltf(glTF gltf, int bufferIndex, bool useNormal)
public gltfMorphTarget ToGltf(glTF gltf, int gltfBuffer, bool useNormal, SparseBase? sparseBase)
{
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_positions.ToArray(), glBufferTarget.ARRAY_BUFFER);
gltf.accessors[positionAccessorIndex].min = m_positions.Aggregate(m_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 = m_positions.Aggregate(m_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 = -1;
if (useNormal)
{
normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_normals.ToArray(), glBufferTarget.ARRAY_BUFFER);
}
return new gltfMorphTarget
{
POSITION = positionAccessorIndex,
NORMAL = normalAccessorIndex,
};
return BlendShapeExporter.Export(gltf, gltfBuffer,
m_positions,
useNormal ? m_normals : null,
sparseBase);
}
}
@ -113,11 +103,12 @@ namespace UniGLTF
m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3));
}
public glTFPrimitives ToGltfPrimitive(glTF gltf, int bufferIndex, int materialIndex, IEnumerable<int> indices)
public (glTFPrimitives, SparseBase) ToGltfPrimitive(glTF gltf, int bufferIndex, int materialIndex, IEnumerable<int> indices)
{
var sparseBase = new SparseBase(m_positions.ToArray(), m_normals.ToArray());
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 positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, sparseBase.Positions, glBufferTarget.ARRAY_BUFFER);
var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, sparseBase.Normals, glBufferTarget.ARRAY_BUFFER);
var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_uv.ToArray(), glBufferTarget.ARRAY_BUFFER);
int? jointsAccessorIndex = default;
@ -146,7 +137,7 @@ namespace UniGLTF
mode = 4,
};
return primitive;
return (primitive, sparseBase);
}
}
}

View File

@ -7,7 +7,17 @@ namespace UniGLTF
{
public static class MeshExporter_DividedVertexBuffer
{
public static (glTFMesh, Dictionary<int, int>) Export(glTF gltf, int bufferIndex,
/// <summary>
/// Divide vertex buffer(Position, Normal, UV, VertexColor, Skinning and BlendShapes) by submesh usage, then export
/// </summary>
/// <param name="gltf"></param>
/// <param name="gltfBuffer"></param>
/// <param name="unityMesh"></param>
/// <param name="unityMaterials"></param>
/// <param name="axisInverter"></param>
/// <param name="settings"></param>
/// <returns></returns>
public static (glTFMesh, Dictionary<int, int>) Export(glTF gltf, int gltfBuffer,
MeshExportInfo unityMesh, List<Material> unityMaterials,
IAxisInverter axisInverter, MeshExportSettings settings)
{
@ -16,7 +26,7 @@ namespace UniGLTF
if (settings.ExportTangents)
{
// support しない
// no support
throw new NotImplementedException();
}
@ -40,15 +50,14 @@ namespace UniGLTF
var indices = mesh.GetIndices(i);
var hash = new HashSet<int>(indices);
// mesh
// index の順に attributes を蓄える
// aggrigate vertex attributes
var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex);
usedIndices.Clear();
for (int k = 0; k < positions.Length; ++k)
{
if (hash.Contains(k))
{
// indices から参照される頂点だけを蓄える
// aggrigate indices
usedIndices.Add(k);
buffer.Push(k, axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV());
if (getJointIndex != null)
@ -75,23 +84,25 @@ namespace UniGLTF
flipped.Add(t1);
flipped.Add(t0);
}
var gltfPrimitive = buffer.ToGltfPrimitive(gltf, bufferIndex, materialIndex, flipped);
var (gltfPrimitive, sparseBase) = buffer.ToGltfPrimitive(gltf, gltfBuffer, materialIndex, flipped);
// blendShape
// blendShape(morph target)
for (int j = 0; j < mesh.blendShapeCount; ++j)
{
var blendShape = new MeshExportUtil.BlendShapeBuffer(indices.Length);
// index の順に attributes を蓄える
// aggriage morph target
mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null);
int l = 0;
foreach (var k in usedIndices)
{
blendShape.Push(
blendShape.Set(l++,
axisInverter.InvertVector3(blendShapePositions[k]),
axisInverter.InvertVector3(blendShapeNormals[k]));
}
gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, bufferIndex, !settings.ExportOnlyBlendShapePosition));
gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, gltfBuffer, !settings.ExportOnlyBlendShapePosition,
settings.UseSparseAccessorForMorphTarget ? sparseBase : default));
}
gltfMesh.primitives.Add(gltfPrimitive);

View File

@ -10,11 +10,12 @@ namespace UniGLTF
{
/// <summary>
/// primitive 間で vertex を共有する形で Export する。
/// UniVRM-0.71.0 以降は、MeshExporterDivided.Export もある。
///
/// UniVRM-0.71.0 までの挙動
/// * GLB/GLTF は shared(default) と divided を選択可能
/// * VRM0 は shared 仕様
/// * VRM1 は divided 仕様
///
/// UniVRM-0.71.0 以降は、MeshExporterDivided.Export もある
///
/// /// </summary>
/// <param name="gltf"></param>
/// <param name="bufferIndex"></param>
@ -159,12 +160,13 @@ namespace UniGLTF
unityMesh.Mesh, j,
settings.UseSparseAccessorForMorphTarget,
settings.ExportOnlyBlendShapePosition, axisInverter);
if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0)
if (morphTarget.POSITION < 0)
{
// Skip empty blendShape.
// Shift blendShape's index.
continue;
}
// maybe skip
var blendShapeName = unityMesh.Mesh.GetBlendShapeName(j);
blendShapeIndexMap.Add(j, exportBlendShapes++);
targetNames.Add(blendShapeName);
@ -199,7 +201,7 @@ namespace UniGLTF
}
static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex,
Mesh mesh, int j,
Mesh mesh, int blendShapeIndex,
bool useSparseAccessorForMorphTarget,
bool exportOnlyBlendShapePosition,
IAxisInverter axisInverter)
@ -215,8 +217,8 @@ namespace UniGLTF
//var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length;
var useTangent = false;
var frameCount = mesh.GetBlendShapeFrameCount(j);
mesh.GetBlendShapeFrameVertices(j, frameCount - 1, blendShapeVertices, blendShapeNormals, null);
var frameCount = mesh.GetBlendShapeFrameCount(blendShapeIndex);
mesh.GetBlendShapeFrameVertices(blendShapeIndex, frameCount - 1, blendShapeVertices, blendShapeNormals, null);
var blendShapePositionAccessorIndex = -1;
var blendShapeNormalAccessorIndex = -1;

View File

@ -121,7 +121,7 @@ namespace UniVRM10
}
}
var materialIndex = submesh.Material;
var gltfPrimitive = buffer.ToGltfPrimitive(storage.Gltf, bufferIndex, materialIndex, indices);
var (gltfPrimitive, sparseBase) = buffer.ToGltfPrimitive(storage.Gltf, bufferIndex, materialIndex, indices);
// blendShape
for (int j = 0; j < mesh.MorphTargets.Count; ++j)
@ -136,15 +136,16 @@ namespace UniVRM10
{
blendShapeNormals = morph.VertexBuffer.Normals.GetSpan<UnityEngine.Vector3>();
}
int l = 0;
foreach (var k in usedIndices)
{
blendShape.Push(
blendShape.Set(l++,
blendShapePositions[k],
blendShapeNormals.HasValue ? blendShapeNormals.Value[k] : UnityEngine.Vector3.zero
);
}
gltfPrimitive.targets.Add(blendShape.ToGltf(storage.Gltf, bufferIndex, !option.removeMorphNormal));
gltfPrimitive.targets.Add(blendShape.ToGltf(storage.Gltf, bufferIndex, !option.removeMorphNormal, option.sparse ? sparseBase : default));
}
yield return gltfPrimitive;