diff --git a/Assets/VRM/UniGLTF/Editor/Serialization/FieldSerializationInfo.cs b/Assets/VRM/UniGLTF/Editor/Serialization/FieldSerializationInfo.cs index 3ca000776f..f0236d6d46 100644 --- a/Assets/VRM/UniGLTF/Editor/Serialization/FieldSerializationInfo.cs +++ b/Assets/VRM/UniGLTF/Editor/Serialization/FieldSerializationInfo.cs @@ -51,26 +51,26 @@ public FieldSerializationInfo(FieldInfo fi, string path) Path = path + "/" + fi.Name; m_attr = fi.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(JsonSchemaAttribute)) as JsonSchemaAttribute; - Serialization = GetSerialization(m_fi.FieldType, Path); + Serialization = GetSerialization(m_fi.FieldType, Path, m_attr); } - static IValueSerialization GetSerialization(Type t, string path) + static IValueSerialization GetSerialization(Type t, string path, JsonSchemaAttribute attr) { if (t.IsArray) { return new ArraySerialization(t, - GetSerialization(t.GetElementType(), path + "[]")); + GetSerialization(t.GetElementType(), path + "[]", attr)); } else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>)) { return new ListSerialization(t, - GetSerialization(t.GetGenericArguments()[0], path + "[]")); + GetSerialization(t.GetGenericArguments()[0], path + "[]", attr)); } else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dictionary<,>) && t.GetGenericArguments()[0] == typeof(string)) { - return new StringKeyDictionarySerialization(t, - GetSerialization(t.GetGenericArguments()[1], path)); + return new StringKeyDictionarySerialization(t, + GetSerialization(t.GetGenericArguments()[1], path, attr)); } // GetCollectionType(fi.FieldType, out suffix, out t); @@ -124,7 +124,7 @@ static IValueSerialization GetSerialization(Type t, string path) } else if (t.IsEnum) { - return new EnumIntSerialization(t); + return new EnumIntSerialization(t, attr.EnumSerializationType); } return new ObjectSerialization(t, path); diff --git a/Assets/VRM/UniGLTF/Editor/Serialization/PrimitiveSerialization.cs b/Assets/VRM/UniGLTF/Editor/Serialization/PrimitiveSerialization.cs index 396aa483f0..33d879a954 100644 --- a/Assets/VRM/UniGLTF/Editor/Serialization/PrimitiveSerialization.cs +++ b/Assets/VRM/UniGLTF/Editor/Serialization/PrimitiveSerialization.cs @@ -179,20 +179,33 @@ public override string GenerateDeserializerCall(string callName, string argName) public class EnumIntSerialization : PrimitiveSerializationBase { Type m_type; + UniJSON.EnumSerializationType m_serializationType; public override Type ValueType { get { return m_type; } } - public EnumIntSerialization(Type t) + public EnumIntSerialization(Type t, UniJSON.EnumSerializationType serializationType) { m_type = t; + m_serializationType = serializationType; } public override string GenerateDeserializerCall(string callName, string argName) { - return string.Format("({0}){1}.GetInt32()", m_type.Name, argName); + switch (m_serializationType) + { + case UniJSON.EnumSerializationType.AsInt: + return string.Format("({0}){1}.GetInt32()", m_type.Name, argName); + + case UniJSON.EnumSerializationType.AsLowerString: + // (ProjectionType)Enum.Parse(typeof(ProjectionType), kv.Value.GetString(), true) + return $"({m_type.Name})Enum.Parse(typeof({m_type.Name}), {argName}.GetString(), true)"; + + default: + throw new NotImplementedException(); + } } } } \ No newline at end of file diff --git a/Assets/VRM/UniGLTF/Editor/Serialization/SerializerGenerator.cs b/Assets/VRM/UniGLTF/Editor/Serialization/SerializerGenerator.cs index 783afcec86..25237cfd40 100644 --- a/Assets/VRM/UniGLTF/Editor/Serialization/SerializerGenerator.cs +++ b/Assets/VRM/UniGLTF/Editor/Serialization/SerializerGenerator.cs @@ -76,6 +76,7 @@ class Generator : IDisposable {"gltf/meshes[]/primitives[]/attributes/NORMAL", "if(value.NORMAL!=-1)"}, {"gltf/meshes[]/primitives[]/attributes/TANGENT", "if(value.TANGENT!=-1)"}, {"gltf/meshes[]/primitives[]/attributes/TEXCOORD_0", "if(value.TEXCOORD_0!=-1)"}, + {"gltf/meshes[]/primitives[]/attributes/TEXCOORD_1", "if(value.TEXCOORD_1!=-1)"}, {"gltf/meshes[]/primitives[]/attributes/COLOR_0", "if(value.COLOR_0!=-1)"}, {"gltf/meshes[]/primitives[]/attributes/JOINTS_0", "if(value.JOINTS_0!=-1)"}, {"gltf/meshes[]/primitives[]/attributes/WEIGHTS_0", "if(value.WEIGHTS_0!=-1)"}, diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs index c2d11a4666..14de38978b 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs @@ -19,6 +19,9 @@ public class glTFAttributes : JsonSerializableBase [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int TEXCOORD_0 = -1; + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] + public int TEXCOORD_1 = -1; + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int COLOR_0 = -1; @@ -45,6 +48,7 @@ public override bool Equals(object obj) && NORMAL == rhs.NORMAL && TANGENT == rhs.TANGENT && TEXCOORD_0 == rhs.TEXCOORD_0 + && TEXCOORD_1 == rhs.TEXCOORD_1 && COLOR_0 == rhs.COLOR_0 && JOINTS_0 == rhs.JOINTS_0 && WEIGHTS_0 == rhs.WEIGHTS_0 @@ -57,6 +61,7 @@ protected override void SerializeMembers(GLTFJsonFormatter f) if (NORMAL != -1) f.KeyValue(() => NORMAL); if (TANGENT != -1) f.KeyValue(() => TANGENT); if (TEXCOORD_0 != -1) f.KeyValue(() => TEXCOORD_0); + if (TEXCOORD_1 != -1) f.KeyValue(() => TEXCOORD_1); if (COLOR_0 != -1) f.KeyValue(() => COLOR_0); if (JOINTS_0 != -1) f.KeyValue(() => JOINTS_0); if (WEIGHTS_0 != -1) f.KeyValue(() => WEIGHTS_0); diff --git a/Assets/VRM/UniGLTF/Scripts/IO/GltfDeserializer.g.cs b/Assets/VRM/UniGLTF/Scripts/IO/GltfDeserializer.g.cs index a2bf59bb81..2912ba9b10 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/GltfDeserializer.g.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/GltfDeserializer.g.cs @@ -1861,7 +1861,7 @@ public static glTFCamera Deserialize_gltf_cameras_LIST(ListTreeNode p } if(key=="type"){ - value.type = (ProjectionType)kv.Value.GetInt32(); + value.type = (ProjectionType)Enum.Parse(typeof(ProjectionType), kv.Value.GetString(), true); continue; } diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs index de44ec80a3..a0720b96d7 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs @@ -158,7 +158,8 @@ static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex, #if GLTF_EXPORT_TANGENTS var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); #endif - var uvAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); + 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; @@ -189,9 +190,13 @@ static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex, attributes.TANGENT = tangentAccessorIndex; } #endif - if (uvAccessorIndex != -1) + if (uvAccessorIndex0 != -1) { - attributes.TEXCOORD_0 = uvAccessorIndex; + attributes.TEXCOORD_0 = uvAccessorIndex0; + } + if (uvAccessorIndex1 != -1) + { + attributes.TEXCOORD_1 = uvAccessorIndex1; } if (colorAccessorIndex != -1) { diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index ad73e58297..bd92613b7d 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -20,10 +20,11 @@ private static MeshContext _ImportMeshSharingMorphTarget(ImporterContext ctx, gl var normals = new List(); var tangents = new List(); var uv = new List(); + var uv2 = new List(); var colors = new List(); var blendShapes = new List(); var meshContext = new MeshContext(); - + // blendshapes var targetNames = gltfMesh.extras.targetNames; for (int i = 1; i < gltfMesh.primitives.Count; ++i) @@ -39,7 +40,7 @@ private static MeshContext _ImportMeshSharingMorphTarget(ImporterContext ctx, gl var blendShape = new BlendShape(!string.IsNullOrEmpty(targetNames[i]) ? targetNames[i] : i.ToString()); blendShapes.Add(blendShape); } - + foreach (var prim in gltfMesh.primitives) { var indexOffset = positions.Count; @@ -81,6 +82,17 @@ private static MeshContext _ImportMeshSharingMorphTarget(ImporterContext ctx, gl uv.AddRange(new Vector2[positionCount]); } + // uv1 + if (prim.attributes.TEXCOORD_1 != -1) + { + uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); + } + else + { + // for inconsistent attributes in primitives + uv2.AddRange(new Vector2[positionCount]); + } + // color if (prim.attributes.COLOR_0 != -1) { @@ -112,7 +124,7 @@ private static MeshContext _ImportMeshSharingMorphTarget(ImporterContext ctx, gl meshContext.boneWeights.Add(bw); } } - + // blendshape if (prim.targets != null && prim.targets.Count > 0) { @@ -183,6 +195,7 @@ private static MeshContext _ImportMeshIndependentVertexBuffer(ImporterContext ct var normals = new List(); var tangents = new List(); var uv = new List(); + var uv2 = new List(); var colors = new List(); var meshContext = new MeshContext(); foreach (var prim in gltfMesh.primitives) @@ -226,6 +239,17 @@ private static MeshContext _ImportMeshIndependentVertexBuffer(ImporterContext ct uv.AddRange(new Vector2[positionCount]); } + // uv2 + if (prim.attributes.TEXCOORD_1 != -1) + { + uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); + } + else + { + // for inconsistent attributes in primitives + uv2.AddRange(new Vector2[positionCount]); + } + // color if (prim.attributes.COLOR_0 != -1) { @@ -355,6 +379,17 @@ private static MeshContext _ImportMeshSharingVertexBuffer(ImporterContext ctx, g context.uv = new Vector2[context.positions.Length]; } + // uv2 + if (prim.attributes.TEXCOORD_1 != -1) + { + context.uv2 = ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).SelectInplace(x => x.ReverseUV()); + } + else + { + // for inconsistent attributes in primitives + context.uv2 = new Vector2[context.positions.Length]; + } + // color if (prim.attributes.COLOR_0 != -1) { @@ -491,6 +526,7 @@ public class MeshContext public Vector3[] normals; public Vector4[] tangents; public Vector2[] uv; + public Vector2[] uv2; public Color[] colors; public List boneWeights = new List(); public List subMeshes = new List(); @@ -575,6 +611,10 @@ public static MeshWithMaterials BuildMesh(ImporterContext ctx, MeshImporter.Mesh { mesh.uv = meshContext.uv; } + if (meshContext.uv2 != null && meshContext.uv2.Length > 0) + { + mesh.uv2 = meshContext.uv2; + } bool recalculateTangents = true; #if UNIGLTF_IMPORT_TANGENTS @@ -657,7 +697,7 @@ public static MeshWithMaterials BuildMesh(ImporterContext ctx, MeshImporter.Mesh return result; } - + public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.MeshContext meshContext) { if (!meshContext.materialIndices.Any()) @@ -678,12 +718,12 @@ public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.M #endif } - + mesh.vertices = meshContext.positions; bool recalculateNormals = false; if (meshContext.normals != null && meshContext.normals.Length > 0) { - + mesh.normals = meshContext.normals; } else @@ -693,7 +733,7 @@ public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.M if (meshContext.uv != null && meshContext.uv.Length > 0) { - + mesh.uv = meshContext.uv; } @@ -708,7 +748,7 @@ public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.M if (meshContext.colors != null && meshContext.colors.Length > 0) { - + mesh.colors = meshContext.colors; } if (meshContext.boneWeights != null && meshContext.boneWeights.Count > 0) @@ -746,7 +786,7 @@ public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.M if (meshContext.blendShapes != null) { Vector3[] emptyVertices = null; - + foreach (var blendShape in meshContext.blendShapes) { if (blendShape.Positions.Count > 0)