protected virtual void BuildMeshAttributes(GLTF.Schema.MeshPrimitive primitive, int meshID, int primitiveIndex) { if (_assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes.Count == 0) { Dictionary <string, AttributeAccessor> attributeAccessors = new Dictionary <string, AttributeAccessor>(primitive.Attributes.Count + 1); foreach (var attributePair in primitive.Attributes) { AttributeAccessor AttributeAccessor = new AttributeAccessor() { AccessorId = attributePair.Value, Buffer = _assetCache.BufferCache[attributePair.Value.Value.BufferView.Value.Buffer.Id] }; attributeAccessors[attributePair.Key] = AttributeAccessor; } if (primitive.Indices != null) { AttributeAccessor indexBuilder = new AttributeAccessor() { AccessorId = primitive.Indices, Buffer = _assetCache.BufferCache[primitive.Indices.Value.BufferView.Value.Buffer.Id] }; attributeAccessors[GLTF.Schema.SemanticProperties.INDICES] = indexBuilder; } GLTFHelpers.BuildMeshAttributes(ref attributeAccessors); _assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes = attributeAccessors; } }
private void parseAttribute(ref GLTF.Schema.MeshPrimitive prim, string property, ref Vector4[] values) { byte[] bufferData = _assetCache.BufferCache[prim.Attributes[property].Value.BufferView.Value.Buffer.Id]; NumericArray num = new NumericArray(); GLTF.Math.Vector4[] gltfValues = prim.Attributes[property].Value.AsVector4Array(ref num, bufferData); values = new Vector4[gltfValues.Length]; for (int i = 0; i < gltfValues.Length; ++i) { values[i] = gltfValues[i].ToUnityVector4(); } }
protected virtual void LoadSkinnedMeshAttributes(int meshIndex, int primitiveIndex, ref Vector4[] boneIndexes, ref Vector4[] weights) { GLTF.Schema.MeshPrimitive prim = _root.Meshes[meshIndex].Primitives[primitiveIndex]; if (!prim.Attributes.ContainsKey(SemanticProperties.JOINT) || !prim.Attributes.ContainsKey(SemanticProperties.WEIGHT)) { return; } parseAttribute(ref prim, SemanticProperties.JOINT, ref boneIndexes); parseAttribute(ref prim, SemanticProperties.WEIGHT, ref weights); foreach (Vector4 wei in weights) { wei.Normalize(); } }
// Taken from: http://answers.unity3d.com/comments/190515/view.html // Official support for Mesh.RecalculateTangents should be coming in 5.6 // https://feedback.unity3d.com/suggestions/recalculatetangents /*private MeshPrimitiveAttributes CalculateAndSetTangents(MeshPrimitiveAttributes attributes) * { * var triangleCount = attributes.Triangles.Length; * var vertexCount = attributes.Vertices.Length; * * var tan1 = new Vector3[vertexCount]; * var tan2 = new Vector3[vertexCount]; * * attributes.Tangents = new Vector4[vertexCount]; * * for (long a = 0; a < triangleCount; a += 3) * { * long i1 = attributes.Triangles[a + 0]; * long i2 = attributes.Triangles[a + 1]; * long i3 = attributes.Triangles[a + 2]; * * var v1 = attributes.Vertices[i1]; * var v2 = attributes.Vertices[i2]; * var v3 = attributes.Vertices[i3]; * * var w1 = attributes.Uv[i1]; * var w2 = attributes.Uv[i2]; * var w3 = attributes.Uv[i3]; * * var x1 = v2.X - v1.X; * var x2 = v3.X - v1.X; * var y1 = v2.Y - v1.Y; * var y2 = v3.Y - v1.Y; * var z1 = v2.Z - v1.Z; * var z2 = v3.Z - v1.Z; * * var s1 = w2.X - w1.X; * var s2 = w3.X - w1.X; * var t1 = w2.Y - w1.Y; * var t2 = w3.Y - w1.Y; * * var r = 1.0f / (s1 * t2 - s2 * t1); * * var sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); * var tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); * * tan1[i1] += sdir; * tan1[i2] += sdir; * tan1[i3] += sdir; * * tan2[i1] += tdir; * tan2[i2] += tdir; * tan2[i3] += tdir; * } * * * for (long a = 0; a < vertexCount; ++a) * { * var n = attributes.Normals[a]; * var t = tan1[a]; * * Vector3.OrthoNormalize(ref n, ref t); * * attributes.Tangents[a].X = t.X; * attributes.Tangents[a].Y = t.Y; * attributes.Tangents[a].Z = t.Z; * * attributes.Tangents[a].W = (Vector3.Dot(Vector3.Cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f; * } * * return attributes; * }*/ public static MeshPrimitive Deserialize(GLTFRoot root, JsonReader reader) { var primitive = new MeshPrimitive(); while (reader.Read() && reader.TokenType == JsonToken.PropertyName) { var curProp = reader.Value.ToString(); switch (curProp) { case "attributes": primitive.Attributes = reader.ReadAsDictionary(() => new AccessorId { Id = reader.ReadAsInt32().Value, Root = root }); break; case "indices": primitive.Indices = AccessorId.Deserialize(root, reader); break; case "material": primitive.Material = MaterialId.Deserialize(root, reader); break; case "mode": primitive.Mode = (DrawMode)reader.ReadAsInt32().Value; break; case "targets": primitive.Targets = reader.ReadList(() => { return(reader.ReadAsDictionary(() => new AccessorId { Id = reader.ReadAsInt32().Value, Root = root }, skipStartObjectRead: true)); }); break; case "extras": // GLTF does not support morph target names, serialize in extras for now // https://github.com/KhronosGroup/glTF/issues/1036 if (reader.Read() && reader.TokenType == JsonToken.StartObject) { while (reader.Read() && reader.TokenType == JsonToken.PropertyName) { var extraProperty = reader.Value.ToString(); switch (extraProperty) { case "targetNames": primitive.TargetNames = reader.ReadStringList(); break; } } } break; default: primitive.DefaultPropertyDeserializer(root, reader); break; } } return(primitive); }
protected virtual GameObject CreateMeshPrimitive(GLTF.Schema.MeshPrimitive primitive, int meshID, int primitiveIndex) { var primitiveObj = new GameObject("Primitive"); var meshFilter = primitiveObj.AddComponent <MeshFilter>(); if (_assetCache.MeshCache[meshID][primitiveIndex] == null) { _assetCache.MeshCache[meshID][primitiveIndex] = new MeshCacheData(); } if (_assetCache.MeshCache[meshID][primitiveIndex].LoadedMesh == null) { if (_assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes.Count == 0) { BuildMeshAttributes(primitive, meshID, primitiveIndex); } var meshAttributes = _assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes; var vertexCount = primitive.Attributes[GLTF.Schema.SemanticProperties.POSITION].Value.Count; // todo optimize: There are multiple copies being performed to turn the buffer data into mesh data. Look into reducing them UnityEngine.Mesh mesh = new UnityEngine.Mesh { vertices = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.POSITION) ? meshAttributes[GLTF.Schema.SemanticProperties.POSITION].AccessorContent.AsVertices.ToUnityVector3() : null, normals = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.NORMAL) ? meshAttributes[GLTF.Schema.SemanticProperties.NORMAL].AccessorContent.AsNormals.ToUnityVector3() : null, uv = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.TexCoord(0)) ? meshAttributes[GLTF.Schema.SemanticProperties.TexCoord(0)].AccessorContent.AsTexcoords.ToUnityVector2() : null, uv2 = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.TexCoord(1)) ? meshAttributes[GLTF.Schema.SemanticProperties.TexCoord(1)].AccessorContent.AsTexcoords.ToUnityVector2() : null, uv3 = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.TexCoord(2)) ? meshAttributes[GLTF.Schema.SemanticProperties.TexCoord(2)].AccessorContent.AsTexcoords.ToUnityVector2() : null, uv4 = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.TexCoord(3)) ? meshAttributes[GLTF.Schema.SemanticProperties.TexCoord(3)].AccessorContent.AsTexcoords.ToUnityVector2() : null, colors = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.Color(0)) ? meshAttributes[GLTF.Schema.SemanticProperties.Color(0)].AccessorContent.AsColors.ToUnityColor() : null, triangles = primitive.Indices != null ? meshAttributes[GLTF.Schema.SemanticProperties.INDICES].AccessorContent.AsTriangles : GLTF.Schema.MeshPrimitive.GenerateTriangles(vertexCount), tangents = primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.TANGENT) ? meshAttributes[GLTF.Schema.SemanticProperties.TANGENT].AccessorContent.AsTangents.ToUnityVector4() : null }; _assetCache.MeshCache[meshID][primitiveIndex].LoadedMesh = mesh; } meshFilter.sharedMesh = _assetCache.MeshCache[meshID][primitiveIndex].LoadedMesh; var materialWrapper = CreateMaterial( primitive.Material != null ? primitive.Material.Value : DefaultMaterial, primitive.Material != null ? primitive.Material.Id : -1 ); var meshRenderer = primitiveObj.AddComponent <MeshRenderer>(); meshRenderer.material = materialWrapper.GetContents(primitive.Attributes.ContainsKey(GLTF.Schema.SemanticProperties.Color(0))); if (_addColliders) { var meshCollider = primitiveObj.AddComponent <MeshCollider>(); meshCollider.sharedMesh = meshFilter.mesh; } return(primitiveObj); }