public static ModelRoot ToGLTF(this Papa papa) { ModelRoot root = ModelRoot.CreateModel(); Scene scene = root.UseScene("default"); Node rootNode = scene .CreateNode() .WithLocalRotation(Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), (float)(-90 * (Math.PI / 180)))); foreach (PapaModel papaModel in papa.Models) { Node modelNode = rootNode .CreateNode(); // Skinned model if (papaModel.Skeleton != null) { List <(Node, Matrix4x4)> skeleton = CreateSkeleton(modelNode, papaModel.Skeleton); foreach (PapaMeshBinding meshBinding in papaModel.MeshBindings) { modelNode .CreateNode(papaModel.Name) .WithSkinnedMesh(root.CreateMesh(BuildSkinnedMesh(meshBinding)), skeleton.ToArray()); } if (papa.Animations.Count != 0) { CreateAnimations(root, skeleton, papa.Animations); } } else { foreach (PapaMeshBinding meshBinding in papaModel.MeshBindings) { var meshBuilder = BuildMesh(meshBinding); modelNode .CreateNode(meshBinding.Name) .WithMesh(root.CreateMesh(meshBuilder)); } } } return(root); }
public Mesh CreateSchema2Mesh(ModelRoot root, Func <TMaterial, Material> materialEvaluator) { var dstMesh = root.CreateMesh(_MeshName); foreach (var p in _Primitives) { p.CopyToMesh(dstMesh, materialEvaluator); } return(dstMesh); }
public Mesh CreateSchema2Mesh(ModelRoot root, Func <TMaterial, Material> materialEvaluator) { if (_Primitives.Count == 0) { return(null); } var dstMesh = root.CreateMesh(_MeshName); foreach (var p in _Primitives) { p.CopyToMesh(dstMesh, materialEvaluator); } dstMesh.SetMorphWeights(default);
public Mesh CreateSchema2Mesh(ModelRoot root, Converter <TMaterial, Material> materialEvaluator) { if (_Primitives.Count == 0) { return(null); } var dstMesh = root.CreateMesh(); this.TryCopyNameAndExtrasTo(dstMesh); foreach (var p in _Primitives) { p.CopyToMesh(dstMesh, materialEvaluator); } dstMesh.SetMorphWeights(default);
public static ModelRoot ToGLTF(this MapGeometry mgeo) { ModelRoot root = ModelRoot.CreateModel(); Scene scene = root.UseScene("Map"); Node rootNode = scene.CreateNode("Map"); // Find all layer combinations used in the Map // so we can group the meshes var layerModelMap = new Dictionary <MapGeometryLayer, List <MapGeometryModel> >(); foreach (MapGeometryModel model in mgeo.Models) { if (!layerModelMap.ContainsKey(model.Layer)) { layerModelMap.Add(model.Layer, new List <MapGeometryModel>()); } layerModelMap[model.Layer].Add(model); } // Create node for each layer combination var layerNodeMap = new Dictionary <MapGeometryLayer, Node>(); foreach (var layerModelPair in layerModelMap) { layerNodeMap.Add(layerModelPair.Key, rootNode.CreateNode(DeriveLayerCombinationName(layerModelPair.Key))); } foreach (MapGeometryModel model in mgeo.Models) { IMeshBuilder <MaterialBuilder> meshBuilder = BuildMapGeometryMeshStatic(model); layerNodeMap[model.Layer] .CreateNode() .WithMesh(root.CreateMesh(meshBuilder)) .WithLocalTransform(new AffineTransform(model.Transformation)); } return(root); }
public static ModelRoot ToGltf(this StaticObject staticObject) { ModelRoot root = ModelRoot.CreateModel(); Scene scene = root.UseScene("default"); var mesh = VERTEX.CreateCompatibleMesh(); foreach (StaticObjectSubmesh submesh in staticObject.Submeshes) { MaterialBuilder material = new MaterialBuilder(submesh.Name); var primitive = mesh.UsePrimitive(material); List <VERTEX> vertices = new List <VERTEX>(); foreach (StaticObjectVertex vertex in submesh.Vertices) { vertices.Add(new VERTEX() .WithGeometry(vertex.Position) .WithMaterial(vertex.UV)); } for (int i = 0; i < submesh.Indices.Count; i += 3) { VERTEX v1 = vertices[(int)submesh.Indices[i + 0]]; VERTEX v2 = vertices[(int)submesh.Indices[i + 1]]; VERTEX v3 = vertices[(int)submesh.Indices[i + 2]]; primitive.AddTriangle(v1, v2, v3); } } scene .CreateNode() .WithMesh(root.CreateMesh(mesh)); return(root); }
public Mesh FindOrCreateMesh(ModelRoot model, string meshName) { var mesh = model.LogicalMeshes.FirstOrDefault(m => m.Name == meshName) ?? model.CreateMesh(meshName); return(mesh); }
private Mesh CreateGltfMesh(string meshName, VMesh vmesh, ModelRoot model, bool includeJoints) { ProgressDialog.SetProgress($"Creating mesh: {meshName}"); var data = vmesh.GetData(); var vbib = vmesh.VBIB; var mesh = model.CreateMesh(meshName); mesh.Name = meshName; foreach (var sceneObject in data.GetArray("m_sceneObjects")) { foreach (var drawCall in sceneObject.GetArray("m_drawCalls")) { var vertexBufferInfo = drawCall.GetArray("m_vertexBuffers")[0]; // In what situation can we have more than 1 vertex buffer per draw call? var vertexBufferIndex = (int)vertexBufferInfo.GetIntegerProperty("m_hBuffer"); var vertexBuffer = vbib.VertexBuffers[vertexBufferIndex]; var indexBufferInfo = drawCall.GetSubCollection("m_indexBuffer"); var indexBufferIndex = (int)indexBufferInfo.GetIntegerProperty("m_hBuffer"); var indexBuffer = vbib.IndexBuffers[indexBufferIndex]; // Create one primitive per draw call var primitive = mesh.CreatePrimitive(); // Avoid duplicate attribute names var attributeCounters = new Dictionary <string, int>(); // Set vertex attributes foreach (var attribute in vertexBuffer.Attributes) { attributeCounters.TryGetValue(attribute.Name, out var attributeCounter); attributeCounters[attribute.Name] = attributeCounter + 1; var accessorName = GetAccessorName(attribute.Name, attributeCounter); var buffer = ReadAttributeBuffer(vertexBuffer, attribute); var numComponents = buffer.Length / vertexBuffer.Count; if (attribute.Name == "BLENDINDICES") { if (!includeJoints) { continue; } var byteBuffer = buffer.Select(f => (byte)f).ToArray(); var rawBufferData = new byte[buffer.Length]; System.Buffer.BlockCopy(byteBuffer, 0, rawBufferData, 0, rawBufferData.Length); var bufferView = mesh.LogicalParent.UseBufferView(rawBufferData); var accessor = mesh.LogicalParent.CreateAccessor(); accessor.SetVertexData(bufferView, 0, buffer.Length / 4, DimensionType.VEC4, EncodingType.UNSIGNED_BYTE); primitive.SetVertexAccessor(accessorName, accessor); continue; } if (attribute.Name == "NORMAL" && DrawCall.IsCompressedNormalTangent(drawCall)) { var vectors = ToVector4Array(buffer); var(normals, tangents) = DecompressNormalTangents(vectors); primitive.WithVertexAccessor("NORMAL", normals); primitive.WithVertexAccessor("TANGENT", tangents); continue; } if (attribute.Name == "BLENDINDICES") { var byteBuffer = buffer.Select(f => (byte)f).ToArray(); var bufferView = mesh.LogicalParent.UseBufferView(byteBuffer); var accessor = mesh.LogicalParent.CreateAccessor(); accessor.SetVertexData(bufferView, 0, buffer.Length / 4, DimensionType.VEC4, EncodingType.UNSIGNED_BYTE); primitive.SetVertexAccessor(accessorName, accessor); continue; } if (attribute.Name == "TEXCOORD" && numComponents != 2) { // We are ignoring some data, but non-2-component UVs cause failures in gltf consumers continue; } switch (numComponents) { case 4: { var vectors = ToVector4Array(buffer); primitive.WithVertexAccessor(accessorName, vectors); break; } case 3: { var vectors = ToVector3Array(buffer); primitive.WithVertexAccessor(accessorName, vectors); break; } case 2: { var vectors = ToVector2Array(buffer); primitive.WithVertexAccessor(accessorName, vectors); break; } case 1: { primitive.WithVertexAccessor(accessorName, buffer); break; } default: throw new NotImplementedException($"Attribute \"{attribute.Name}\" has {numComponents} components"); } } // For some reason soruce models can have joints but no weights, check if that is the case var jointAccessor = primitive.GetVertexAccessor("JOINTS_0"); if (jointAccessor != null && primitive.GetVertexAccessor("WEIGHTS_0") == null) { // If this occurs, give default weights var defaultWeights = Enumerable.Repeat(Vector4.UnitX, jointAccessor.Count).ToList(); primitive.WithVertexAccessor("WEIGHTS_0", defaultWeights); } // Set index buffer var startIndex = (int)drawCall.GetIntegerProperty("m_nStartIndex"); var indexCount = (int)drawCall.GetIntegerProperty("m_nIndexCount"); var indices = ReadIndices(indexBuffer, startIndex, indexCount); primitive.WithIndicesAccessor(PrimitiveType.TRIANGLES, indices); // Add material var materialPath = drawCall.GetProperty <string>("m_material"); ProgressDialog.SetProgress($"Loading material: {materialPath}"); var materialResource = GuiContext.LoadFileByAnyMeansNecessary(materialPath + "_c"); if (materialResource == null) { continue; } var renderMaterial = (VMaterial)materialResource.DataBlock; var materialNameTrimmed = Path.GetFileNameWithoutExtension(materialPath); var bestMaterial = GenerateGLTFMaterialFromRenderMaterial(renderMaterial, model, materialNameTrimmed); primitive.WithMaterial(bestMaterial); } } return(mesh); }
private Mesh CreateGltfMesh(string meshName, VMesh vmesh, ModelRoot model) { ProgressDialog.SetProgress($"Creating mesh: {meshName}"); var data = vmesh.GetData(); var vbib = vmesh.VBIB; var mesh = model.CreateMesh(meshName); mesh.Name = meshName; foreach (var sceneObject in data.GetArray("m_sceneObjects")) { foreach (var drawCall in sceneObject.GetArray("m_drawCalls")) { var vertexBufferInfo = drawCall.GetArray("m_vertexBuffers")[0]; // In what situation can we have more than 1 vertex buffer per draw call? var vertexBufferIndex = (int)vertexBufferInfo.GetIntegerProperty("m_hBuffer"); var vertexBuffer = vbib.VertexBuffers[vertexBufferIndex]; var indexBufferInfo = drawCall.GetSubCollection("m_indexBuffer"); var indexBufferIndex = (int)indexBufferInfo.GetIntegerProperty("m_hBuffer"); var indexBuffer = vbib.IndexBuffers[indexBufferIndex]; // Create one primitive per draw call var primitive = mesh.CreatePrimitive(); // Avoid duplicate attribute names var uniqueAttributes = vertexBuffer.Attributes.GroupBy(a => a.Name).Select(g => g.First()); // Set vertex attributes foreach (var attribute in uniqueAttributes) { if (AccessorInfo.TryGetValue(attribute.Name, out var accessorInfo)) { var buffer = ReadAttributeBuffer(vbib, vertexBuffer, attribute); if (accessorInfo.NumComponents == 4) { var vectors = ToVector4Array(buffer); primitive.WithVertexAccessor(accessorInfo.GltfAccessorName, vectors); } else if (attribute.Name == "NORMAL" && DrawCall.IsCompressedNormalTangent(drawCall)) { var vectors = ToVector4Array(buffer); var(normals, tangents) = DecompressNormalTangents(vectors); primitive.WithVertexAccessor("NORMAL", normals); primitive.WithVertexAccessor("TANGENT", tangents); } else if (accessorInfo.NumComponents == 3) { var vectors = ToVector3Array(buffer, true, accessorInfo.Resize); primitive.WithVertexAccessor(accessorInfo.GltfAccessorName, vectors); } else if (accessorInfo.NumComponents == 2) { var vectors = ToVector2Array(buffer); primitive.WithVertexAccessor(accessorInfo.GltfAccessorName, vectors); } } } // Set index buffer var indices = ReadIndices(indexBuffer); // For triangle primitives, the front face has to be in counter-clockwise (CCW) winding order. for (var i = 0; i < indices.Length; i += 3) { var b = indices[i + 2]; indices[i + 2] = indices[i + 1]; indices[i + 1] = b; } primitive.WithIndicesAccessor(PrimitiveType.TRIANGLES, indices); // Add material var materialPath = drawCall.GetProperty <string>("m_material"); ProgressDialog.SetProgress($"Loading material: {materialPath}"); var materialResource = GuiContext.LoadFileByAnyMeansNecessary(materialPath + "_c"); if (materialResource == null) { continue; } var renderMaterial = (VMaterial)materialResource.DataBlock; var materialNameTrimmed = Path.GetFileNameWithoutExtension(materialPath); var bestMaterial = GenerateGLTFMaterialFromRenderMaterial(renderMaterial, model, materialNameTrimmed); primitive.WithMaterial(bestMaterial); } } return(mesh); }