// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#meshes int ExportIndices(int[] indices) { // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#primitiveindices indices = CoordUtils.FlipIndices(indices).ToArray(); // Scalar | UNSIGNED_BYTE // | UNSIGNED_SHORT // | UNSIGNED_INT! (TODO: optimize kind...) byte[] buffer = PrimitiveExporter.Marshal(indices); var viewIndex = BufferBuilder.AddView( new ArraySegment <byte>(buffer), null, Types.BufferView.TargetEnum.ELEMENT_ARRAY_BUFFER); var viewComponentType = Types.Accessor.ComponentTypeEnum.UNSIGNED_INT; var accessor = new Types.Accessor { BufferView = viewIndex, ByteOffset = 0, ComponentType = viewComponentType, Count = indices.Length, Type = Types.Accessor.TypeEnum.Scalar, }; return(Types.GltfExtensions.AddAccessor(Gltf, accessor)); }
IndexedResource <Skin> ForceExportSkin(SkinnedMeshRenderer smr, Mesh mesh) { var rootBone = smr.rootBone != null ? (int?)Export(smr.rootBone).Index : null; var boneIndices = smr.bones.Select(bt => Export(bt).Index).ToArray(); var primitiveExporter = new PrimitiveExporter(this); int?matricesAccIndex = null; if (mesh.bindposes.Length > 0) { matricesAccIndex = ExportInverseBindMatrices(mesh.bindposes); } var gltfSkin = new Types.Skin { InverseBindMatrices = matricesAccIndex, Skeleton = rootBone, Joints = boneIndices, }; return(new IndexedResource <Skin> { Index = Types.GltfExtensions.AddSkin(Gltf, gltfSkin), Value = new Skin(), }); }
int ExportPositionsBuffer(ref Vector3[] vec3, out Types.Accessor.ComponentTypeEnum componentType) { vec3 = vec3.Select(CoordUtils.ConvertSpace).ToArray(); // VEC3! | FLOAT! byte[] buffer = PrimitiveExporter.Marshal(vec3); var viewIndex = BufferBuilder.AddView(new ArraySegment <byte>(buffer)); componentType = Types.Accessor.ComponentTypeEnum.FLOAT; return(viewIndex); }
int ExportSparseIndicesBuffer(ref int[] indices, out Types.Accessor.SparseType.IndicesType.ComponentTypeEnum componentType) { // Scalar | UNSIGNED_BYTE // | UNSIGNED_SHORT // | UNSIGNED_INT! (TODO: optimize kind...) byte[] buffer = PrimitiveExporter.Marshal(indices); var viewIndex = BufferBuilder.AddView(new ArraySegment <byte>(buffer)); componentType = Types.Accessor.SparseType.IndicesType.ComponentTypeEnum.UNSIGNED_INT; return(viewIndex); }
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skin int ExportInverseBindMatrices(Matrix4x4[] matrices) { matrices = matrices.Select(CoordUtils.ConvertSpace).ToArray(); // MAT4! | FLOAT! byte[] buffer = PrimitiveExporter.Marshal(matrices); var viewIndex = BufferBuilder.AddView(new ArraySegment <byte>(buffer)); var accessor = new Types.Accessor { BufferView = viewIndex, ByteOffset = 0, ComponentType = Types.Accessor.ComponentTypeEnum.FLOAT, Count = matrices.Length, Type = Types.Accessor.TypeEnum.Mat4, }; return(Types.GltfExtensions.AddAccessor(Gltf, accessor)); }
int ExportWeights(Vector4[] weights) { // VEC4! | FLOAT! // | UNSIGNED_BYTE (normalized) // | UNSIGNED_SHORT (normalized) byte[] buffer = PrimitiveExporter.Marshal(weights); var viewIndex = BufferBuilder.AddView(new ArraySegment <byte>(buffer)); var accessor = new Types.Accessor { BufferView = viewIndex, ByteOffset = 0, ComponentType = Types.Accessor.ComponentTypeEnum.FLOAT, Count = weights.Length, Type = Types.Accessor.TypeEnum.Vec4, }; return(Types.GltfExtensions.AddAccessor(Gltf, accessor)); }
int ExportTangents(Vector4[] vec4) { vec4 = vec4.Select(CoordUtils.ConvertSpace).ToArray(); // VEC4! | FLOAT! byte[] buffer = PrimitiveExporter.Marshal(vec4); var viewIndex = BufferBuilder.AddView(new ArraySegment <byte>(buffer)); var accessor = new Types.Accessor { BufferView = viewIndex, ByteOffset = 0, ComponentType = Types.Accessor.ComponentTypeEnum.FLOAT, Count = vec4.Length, Type = Types.Accessor.TypeEnum.Vec4, }; return(Types.GltfExtensions.AddAccessor(Gltf, accessor)); }
int ExportUV(Vector2[] uv) { uv = uv.Select(CoordUtils.ConvertUV).ToArray(); // VEC2! | FLOAT! // | UNSIGNED_BYTE (normalized) // | UNSIGNED_SHORT (normalized) byte[] buffer = PrimitiveExporter.Marshal(uv); var viewIndex = BufferBuilder.AddView(new ArraySegment <byte>(buffer)); var accessor = new Types.Accessor { BufferView = viewIndex, ByteOffset = 0, ComponentType = Types.Accessor.ComponentTypeEnum.FLOAT, Count = uv.Length, Type = Types.Accessor.TypeEnum.Vec2, }; return(Types.GltfExtensions.AddAccessor(Gltf, accessor)); }
int ExportJoints(Vec4 <int>[] joints) { // VEC4! | UNSIGNED_BYTE // | UNSIGNED_SHORT! byte[] buffer = PrimitiveExporter.Marshal( joints .Select(v => new Vec4 <ushort>((ushort)v.x, (ushort)v.y, (ushort)v.z, (ushort)v.w)) .ToArray() ); var viewIndex = BufferBuilder.AddView(new ArraySegment <byte>(buffer)); var accessor = new Types.Accessor { BufferView = viewIndex, ByteOffset = 0, ComponentType = Types.Accessor.ComponentTypeEnum.UNSIGNED_SHORT, Count = joints.Length, Type = Types.Accessor.TypeEnum.Vec4, }; return(Types.GltfExtensions.AddAccessor(Gltf, accessor)); }
public IndexedResource <Mesh> ForceExport(Renderer r, Mesh mesh) { var materialIndices = new List <int>(); foreach (var m in r.sharedMaterials) { var materialResource = Materials.Export(m); materialIndices.Add(materialResource.Index); } var primitiveExporter = new PrimitiveExporter(this); // Convert to right-handed coordinate system var positionAccIndex = ExportPositions(mesh.vertices); int?normalAccIndex = null; if (mesh.normals.Length > 0) { normalAccIndex = ExportNormals(mesh.normals); } int?tangentAccIndex = null; //if (mesh.tangents.Length > 0) //{ // tangentAccIndex = ExportTangents(mesh.tangents); //} int?texcoord0AccIndex = null; if (mesh.uv.Length > 0) { texcoord0AccIndex = ExportUV(mesh.uv); } int?texcoord1AccIndex = null; if (mesh.uv2.Length > 0) { texcoord1AccIndex = ExportUV(mesh.uv2); } int?color0AccIndex = null; if (mesh.colors.Length > 0) { color0AccIndex = ExportColors(mesh.colors); } int?joints0AccIndex = null; int?weights0AccIndex = null; if (mesh.boneWeights.Length > 0) { var joints = mesh.boneWeights .Select(w => new Vec4 <int>( w.boneIndex0, w.boneIndex1, w.boneIndex2, w.boneIndex3) ).ToArray(); var weights = mesh.boneWeights .Select(w => new Vector4( w.weight0, w.weight1, w.weight2, w.weight3) ).ToArray(); joints0AccIndex = ExportJoints(joints); weights0AccIndex = ExportWeights(weights); } #region blendSpace List <Target> targets = null; if (mesh.blendShapeCount > 0) { targets = new List <Target>(); for (int i = 0; i < mesh.blendShapeCount; ++i) { var name = mesh.GetBlendShapeName(i); var deltaVertices = new Vector3[mesh.vertexCount]; var deltaNormals = new Vector3[mesh.vertexCount]; var deltaTangents = new Vector3[mesh.vertexCount]; var frameCount = mesh.GetBlendShapeFrameCount(i); mesh.GetBlendShapeFrameVertices( i, frameCount - 1 /* get last frame */, deltaVertices, deltaNormals, deltaTangents); // TODO: Export as sparse accessors var mPositionAccIndex = ExportPositions(deltaVertices); var mNormalsAccIndex = ExportNormals(deltaNormals); //var mTangentsAccIndex = ExportPositions(deltaTangents); var mTangentsAccIndex = (int?)null; var weight = mesh.GetBlendShapeFrameWeight( i, frameCount - 1 /* get last frame */); targets.Add(new Target { Name = name, Position = mPositionAccIndex, Normal = mNormalsAccIndex, Tangent = mTangentsAccIndex, Weight = weight, }); } } List <Dictionary <string, int> > primTargets = null; if (targets != null) { primTargets = new List <Dictionary <string, int> >(); foreach (var t in targets) { var primTarget = new Dictionary <string, int>(); primTarget[TMPA.POSITION] = t.Position; if (t.Normal != null) { primTarget[TMPA.NORMAL] = t.Normal.Value; } if (t.Tangent != null) { primTarget[TMPA.TANGENT] = t.Tangent.Value; } primTargets.Add(primTarget); } } #endregion var primitives = new List <Types.Mesh.PrimitiveType>(); for (var i = 0; i < mesh.subMeshCount; ++i) { var indices = mesh.GetIndices(i); var positionindicesAccIndex = ExportIndices(indices); var attrs = new Dictionary <string, int>(); attrs[TMPA.POSITION] = positionAccIndex; if (normalAccIndex != null) { attrs[TMPA.NORMAL] = normalAccIndex.Value; } if (tangentAccIndex != null) { attrs[TMPA.TANGENT] = tangentAccIndex.Value; } if (texcoord0AccIndex != null) { attrs[TMPA.TEXCOORD_0] = texcoord0AccIndex.Value; } if (texcoord1AccIndex != null) { attrs[TMPA.TEXCOORD_1] = texcoord1AccIndex.Value; } if (color0AccIndex != null) { attrs[TMPA.COLOR_0] = color0AccIndex.Value; } if (joints0AccIndex != null) { attrs[TMPA.JOINTS_0] = joints0AccIndex.Value; } if (weights0AccIndex != null) { attrs[TMPA.WEIGHTS_0] = weights0AccIndex.Value; } var primitive = new Types.Mesh.PrimitiveType { Attributes = attrs, Indices = positionindicesAccIndex, Material = materialIndices[i < materialIndices.Count ? i : materialIndices.Count - 1], Targets = primTargets, }; primitives.Add(primitive); } var gltfMesh = new Types.Mesh { Name = mesh.name, Primitives = primitives, // Weights = Should support default morph target weights? }; if (targets != null) { var targetNames = targets.Select(t => t.Name).ToArray(); // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#morph-targets gltfMesh.Extras = new Dictionary <string, object> { { "targetNames", targetNames }, }; } return(new IndexedResource <Mesh> { Index = Types.GltfExtensions.AddMesh(Gltf, gltfMesh), Value = mesh, }); }