VrmLib.Coordinates.Vrm1

https://github.com/vrm-c/vrm-specification/issues/205
This commit is contained in:
ousttrue 2021-02-05 16:22:51 +09:00
parent 96c01397ce
commit 5f86ffe842
11 changed files with 147 additions and 52 deletions

View File

@ -313,7 +313,7 @@ namespace UniVRM10
// 右手系に変換
m_logLabel += $"convert to right handed coordinate...\n";
model.ConvertCoordinate(VrmLib.Coordinates.Gltf, ignoreVrm: false);
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
var exportedBytes = GetGlb(model);
m_logLabel += $"write to {path}...\n";

View File

@ -37,7 +37,7 @@ public class Sample : MonoBehaviour
var exporter = new UniVRM10.RuntimeVrmConverter();
var model = exporter.ToModelFrom10(vrm0x.Root);
// 右手系に変換
model.ConvertCoordinate(VrmLib.Coordinates.Gltf);
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1);
var exportedBytes = model.ToGlb();
// Import 1.0

View File

@ -62,7 +62,7 @@ namespace UniVRM10.Test
var exporter = new UniVRM10.RuntimeVrmConverter();
var model = exporter.ToModelFrom10(root, root.GetComponent<VRM10Controller>().Meta);
model.ConvertCoordinate(VrmLib.Coordinates.Gltf, ignoreVrm: false);
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
return model;
}

View File

@ -39,7 +39,7 @@ namespace UniVRM10.Test
byte[] ToVrm10(VrmLib.Model model)
{
// 右手系に変換
VrmLib.ModelExtensionsForCoordinates.ConvertCoordinate(model, VrmLib.Coordinates.Gltf);
VrmLib.ModelExtensionsForCoordinates.ConvertCoordinate(model, VrmLib.Coordinates.Vrm1);
var bytes = UniVRM10.ModelExtensions.ToGlb(model);
return bytes;
}

View File

@ -4,9 +4,12 @@ namespace VrmLib
{
Unknown,
/// OpenGL standard
/// VRM-0
XYZ_RightUpBack_RH,
/// VRM-1
XYZ_RightUpForward_RH,
/// D3D standard(Unity)
XYZ_RightUpForward_LH,
}
@ -27,13 +30,19 @@ namespace VrmLib
public GeometryCoordinates Geometry;
public TextureOrigin Texture;
public static Coordinates Gltf => new Coordinates
public static Coordinates Vrm0 => new Coordinates
{
Geometry = GeometryCoordinates.XYZ_RightUpBack_RH,
Texture = TextureOrigin.LeftTop,
};
public bool IsVrm0 => this.Equals(Vrm0);
public bool IsGltf => this.Equals(Gltf);
public static Coordinates Vrm1 => new Coordinates
{
Geometry = GeometryCoordinates.XYZ_RightUpForward_RH,
Texture = TextureOrigin.LeftTop,
};
public bool IsVrm1 => this.Equals(Vrm1);
public static Coordinates Unity => new Coordinates
{

View File

@ -12,7 +12,7 @@ namespace VrmLib
return null;
}
var model = new Model(Coordinates.Gltf)
var model = new Model(Coordinates.Vrm1)
{
AssetVersion = storage.AssetVersion,
AssetGenerator = storage.AssetGenerator,

View File

@ -36,7 +36,7 @@ namespace VrmLib
public static Model CreateFromBvh(BvhNode node)
{
// add nodes
var model = new Model(Coordinates.Gltf);
var model = new Model(Coordinates.Vrm1);
model.Root.Name = "__bvh_root__";
AddBvhNodeRecursive(model, model.Root, node);

View File

@ -6,6 +6,83 @@ 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>
@ -16,14 +93,24 @@ namespace VrmLib
return;
}
if (model.Coordinates.IsGltf && coordinates.IsUnity)
if (model.Coordinates.IsVrm0 && coordinates.IsUnity)
{
model.ReverseZAndFlipTriangle(ignoreVrm);
model.ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm);
model.UVVerticalFlip();
}
else if (model.Coordinates.IsUnity && coordinates.IsGltf)
else if (model.Coordinates.IsUnity && coordinates.IsVrm0)
{
model.ReverseZAndFlipTriangle(ignoreVrm);
model.ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm);
model.UVVerticalFlip();
}
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
@ -59,7 +146,7 @@ namespace VrmLib
/// * Rotation => Axis Angle に分解 => Axis の Z座標に -1 を乗算。Angle に -1 を乗算
/// * Triangle の index を 0, 1, 2 から 2, 1, 0 に反転する
/// </summary>
static void ReverseZAndFlipTriangle(this Model model, bool ignoreVrm)
static void ReverseAxisAndFlipTriangle(this Model model, Reverser reverser, bool ignoreVrm)
{
foreach (var g in model.MeshGroups)
{
@ -69,7 +156,7 @@ namespace VrmLib
{
if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
{
ReverseZ(v);
reverser.ReverseBuffer(v);
}
if (k == VertexBuffer.TangentKey)
{
@ -98,7 +185,7 @@ namespace VrmLib
{
if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
{
ReverseZ(v);
reverser.ReverseBuffer(v);
}
if (k == VertexBuffer.TangentKey)
{
@ -113,7 +200,7 @@ namespace VrmLib
// Rootは原点決め打ちのード(GLTFに含まれない)
foreach (var n in model.Root.Traverse().Skip(1))
{
n.SetMatrix(n.Matrix.ReverseZ(), false);
n.SetMatrix(reverser.ReverseMatrix(n.Matrix), false);
}
// 親から順に処理したので不要
// model.Root.CalcWorldMatrix();
@ -122,7 +209,7 @@ namespace VrmLib
{
if (s.InverseMatrices != null)
{
ReverseZ(s.InverseMatrices);
reverser.ReverseBuffer(s.InverseMatrices);
}
}
@ -138,7 +225,7 @@ namespace VrmLib
// LookAt
if (model.Vrm.LookAt != null)
{
model.Vrm.LookAt.OffsetFromHeadBone = model.Vrm.LookAt.OffsetFromHeadBone.ReverseZ();
model.Vrm.LookAt.OffsetFromHeadBone = reverser.ReverseVector3(model.Vrm.LookAt.OffsetFromHeadBone);
}
// SpringBone
@ -154,11 +241,11 @@ namespace VrmLib
switch (s.ColliderType)
{
case VrmSpringBoneColliderTypes.Sphere:
c.Colliders[i] = VrmSpringBoneCollider.CreateSphere(s.Offset.ReverseZ(), s.Radius);
c.Colliders[i] = VrmSpringBoneCollider.CreateSphere(reverser.ReverseVector3(s.Offset), s.Radius);
break;
case VrmSpringBoneColliderTypes.Capsule:
c.Colliders[i] = VrmSpringBoneCollider.CreateCapsule(s.Offset.ReverseZ(), s.Radius, s.CapsuleTail.ReverseZ());
c.Colliders[i] = VrmSpringBoneCollider.CreateCapsule(reverser.ReverseVector3(s.Offset), s.Radius, reverser.ReverseVector3(s.CapsuleTail));
break;
default:
@ -169,7 +256,7 @@ namespace VrmLib
foreach (var j in b.Joints)
{
j.GravityDir = j.GravityDir.ReverseZ();
j.GravityDir = reverser.ReverseVector3(j.GravityDir);
}
}
}
@ -177,34 +264,6 @@ namespace VrmLib
}
}
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();
}
}
static void FlipTriangle(SpanLike<byte> indices)
{
for (int i = 0; i < indices.Length; i += 3)

View File

@ -36,6 +36,11 @@ namespace VrmLib
return new Vector2(src.X, 1.0f - src.Y);
}
public static Vector3 ReverseX(this Vector3 src)
{
return new Vector3(-src.X, src.Y, src.Z);
}
public static Vector3 ReverseZ(this Vector3 src)
{
return new Vector3(src.X, src.Y, -src.Z);
@ -51,6 +56,12 @@ namespace VrmLib
return (new Vector3((float)x, (float)y, (float)z), (float)angle);
}
public static Quaternion ReverseX(this Quaternion src)
{
var (axis, angle) = src.GetAxisAngle();
return Quaternion.CreateFromAxisAngle(axis.ReverseX(), -angle);
}
public static Quaternion ReverseZ(this Quaternion src)
{
var (axis, angle) = src.GetAxisAngle();
@ -131,5 +142,21 @@ namespace VrmLib
return FromTRS(t.ReverseZ(), r.ReverseZ(), s);
}
}
public static Matrix4x4 ReverseX(this Matrix4x4 m)
{
if (m.IsOnlyTranslation())
{
var ret = m;
ret.M43 = -ret.M43;
return ret;
}
else
{
var (t, r, s) = m.Decompose();
return FromTRS(t.ReverseX(), r.ReverseX(), s);
}
}
}
}

View File

@ -10,7 +10,7 @@ namespace VrmLibTests
[Test]
public void ModifierTest()
{
var model = new Model(Coordinates.Gltf);
var model = new Model(Coordinates.Vrm1);
var modifier = new ModelModifier(model);
var node0 = new Node("node0");

View File

@ -47,7 +47,7 @@ PlayerSettings:
defaultScreenWidthWeb: 960
defaultScreenHeightWeb: 600
m_StereoRenderingPath: 0
m_ActiveColorSpace: 0
m_ActiveColorSpace: 1
m_MTRendering: 1
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
iosShowActivityIndicatorOnLoading: -1