UniVRM/Assets/VRM10/vrmlib/Runtime/ModelExtensionsForCoordinates.cs
2021-02-19 18:30:12 +09:00

301 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Linq;
using System.Numerics;
namespace VrmLib
{
public static class ModelExtensionsForCoordinates
{
static void ReverseX(BufferAccessor ba)
{
if (ba.ComponentType != AccessorValueType.FLOAT)
{
throw new Exception();
}
if (ba.AccessorType == AccessorVectorType.VEC3)
{
var span = SpanLike.Wrap<Vector3>(ba.Bytes);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseX();
}
}
else if (ba.AccessorType == AccessorVectorType.MAT4)
{
var span = SpanLike.Wrap<Matrix4x4>(ba.Bytes);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseX();
}
}
else
{
throw new NotImplementedException();
}
}
static void ReverseZ(BufferAccessor ba)
{
if (ba.ComponentType != AccessorValueType.FLOAT)
{
throw new Exception();
}
if (ba.AccessorType == AccessorVectorType.VEC3)
{
var span = SpanLike.Wrap<Vector3>(ba.Bytes);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseZ();
}
}
else if (ba.AccessorType == AccessorVectorType.MAT4)
{
var span = SpanLike.Wrap<Matrix4x4>(ba.Bytes);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseZ();
}
}
else
{
throw new NotImplementedException();
}
}
struct Reverser
{
public Action<BufferAccessor> ReverseBuffer;
public Func<Vector3, Vector3> ReverseVector3;
public Func<Matrix4x4, Matrix4x4> ReverseMatrix;
}
static Reverser ZReverser => new Reverser
{
ReverseBuffer = ReverseZ,
ReverseVector3 = v => v.ReverseZ(),
ReverseMatrix = m => m.ReverseZ(),
};
static Reverser XReverser => new Reverser
{
ReverseBuffer = ReverseX,
ReverseVector3 = v => v.ReverseX(),
ReverseMatrix = m => m.ReverseX(),
};
/// <summary>
/// ignoreVrm: VRM-0.XX では無変換で入出力してた。VRM-1.0 では変換する。
/// </summary>
public static void ConvertCoordinate(this Model model, Coordinates coordinates, bool ignoreVrm = false)
{
if (model.Coordinates.Equals(coordinates))
{
return;
}
if (model.Coordinates.IsVrm0 && coordinates.IsUnity)
{
model.ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm);
model.UVVerticalFlip();
}
else if (model.Coordinates.IsUnity && coordinates.IsVrm0)
{
model.ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm);
model.UVVerticalFlip();
}
else if (model.Coordinates.IsVrm1 && coordinates.IsUnity)
{
model.ReverseAxisAndFlipTriangle(XReverser, ignoreVrm);
model.UVVerticalFlip();
}
else if (model.Coordinates.IsUnity && coordinates.IsVrm1)
{
model.ReverseAxisAndFlipTriangle(XReverser, ignoreVrm);
model.UVVerticalFlip();
}
else
{
throw new NotImplementedException();
}
}
/// <summary>
/// UVのVを反転する。 => V = 1.0 - V
/// </summary>
static void UVVerticalFlip(this Model model)
{
foreach (var g in model.MeshGroups)
{
foreach (var m in g.Meshes)
{
var uv = m.VertexBuffer.TexCoords;
if (uv != null)
{
var span = SpanLike.Wrap<Vector2>(uv.Bytes);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].UVVerticalFlip();
}
}
}
}
}
/// <summary>
/// * Position, Normal の Z座標に -1 を乗算する
/// * Rotation => Axis Angle に分解 => Axis の Z座標に -1 を乗算。Angle に -1 を乗算
/// * Triangle の index を 0, 1, 2 から 2, 1, 0 に反転する
/// </summary>
static void ReverseAxisAndFlipTriangle(this Model model, Reverser reverser, bool ignoreVrm)
{
foreach (var g in model.MeshGroups)
{
foreach (var m in g.Meshes)
{
foreach (var (k, v) in m.VertexBuffer)
{
if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
{
reverser.ReverseBuffer(v);
}
else if (k == VertexBuffer.TangentKey)
{
// I don't know
}
}
switch (m.IndexBuffer.ComponentType)
{
case AccessorValueType.UNSIGNED_BYTE:
FlipTriangle(SpanLike.Wrap<Byte>(m.IndexBuffer.Bytes));
break;
case AccessorValueType.UNSIGNED_SHORT:
FlipTriangle(SpanLike.Wrap<UInt16>(m.IndexBuffer.Bytes));
break;
case AccessorValueType.UNSIGNED_INT:
FlipTriangle(SpanLike.Wrap<UInt32>(m.IndexBuffer.Bytes));
break;
default:
throw new NotImplementedException();
}
foreach (var mt in m.MorphTargets)
{
foreach (var (k, v) in mt.VertexBuffer)
{
if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
{
reverser.ReverseBuffer(v);
}
if (k == VertexBuffer.TangentKey)
{
// I don't know
}
}
}
}
}
// 親から順に処理する
// Rootは原点決め打ちのード(GLTFに含まれない)
foreach (var n in model.Root.Traverse().Skip(1))
{
n.SetMatrix(reverser.ReverseMatrix(n.Matrix), false);
}
// 親から順に処理したので不要
// model.Root.CalcWorldMatrix();
foreach (var s in model.Skins)
{
if (s.InverseMatrices != null)
{
reverser.ReverseBuffer(s.InverseMatrices);
}
}
foreach (var a in model.Animations)
{
// TODO:
}
if (model.Vrm != null)
{
if (!ignoreVrm)
{
// LookAt
if (model.Vrm.LookAt != null)
{
model.Vrm.LookAt.OffsetFromHeadBone = reverser.ReverseVector3(model.Vrm.LookAt.OffsetFromHeadBone);
}
// SpringBone
if (model.Vrm.SpringBone != null)
{
foreach (var b in model.Vrm.SpringBone.Springs)
{
foreach (var c in b.Colliders)
{
for (int i = 0; i < c.Colliders.Count; ++i)
{
var s = c.Colliders[i];
switch (s.ColliderType)
{
case VrmSpringBoneColliderTypes.Sphere:
c.Colliders[i] = VrmSpringBoneCollider.CreateSphere(reverser.ReverseVector3(s.Offset), s.Radius);
break;
case VrmSpringBoneColliderTypes.Capsule:
c.Colliders[i] = VrmSpringBoneCollider.CreateCapsule(reverser.ReverseVector3(s.Offset), s.Radius, reverser.ReverseVector3(s.CapsuleTail));
break;
default:
throw new NotImplementedException();
}
}
}
foreach (var j in b.Joints)
{
j.GravityDir = reverser.ReverseVector3(j.GravityDir);
}
}
}
}
}
}
static void FlipTriangle(SpanLike<byte> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{
// 0, 1, 2 to 2, 1, 0
var tmp = indices[i + 2];
indices[i + 2] = indices[i];
indices[i] = tmp;
}
}
static void FlipTriangle(SpanLike<ushort> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{
// 0, 1, 2 to 2, 1, 0
var tmp = indices[i + 2];
indices[i + 2] = indices[i];
indices[i] = tmp;
}
}
static void FlipTriangle(SpanLike<uint> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{
// 0, 1, 2 to 2, 1, 0
var tmp = indices[i + 2];
indices[i + 2] = indices[i];
indices[i] = tmp;
}
}
}
}