Beispiel #1
0
        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);
        }
        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);
        }
Beispiel #3
0
        /// <summary>
        /// Loads the VMesh into our Objmesh
        /// </summary>
        /// <param name="objMesh">The objmesh to load into</param>
        /// <param name="mesh">The VMesh to load</param>
        private void LoadVMeshIntoMesh(ObjMesh objMesh, VMesh mesh)
        {
            var data = mesh.GetData();
            var vbib = mesh.VBIB;

            foreach (var sceneObject in data.GetArray("m_sceneObjects"))
            {
                foreach (var drawCall in sceneObject.GetArray("m_drawCalls"))
                {
                    var startingVertexCount = objMesh.Positions.Count;                 // Set this so we can offset the indicies for triangles correctly
                    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];

                    // Set vertex attributes
                    foreach (var attribute in vertexBuffer.Attributes)
                    {
                        var buffer        = ReadAttributeBuffer(vertexBuffer, attribute);
                        var numComponents = buffer.Length / vertexBuffer.Count;


                        if (attribute.Name == "BLENDINDICES")
                        {
                            var byteBuffer    = buffer.Select(f => (byte)f).ToArray();
                            var rawBufferData = new byte[buffer.Length];
                            System.Buffer.BlockCopy(byteBuffer, 0, rawBufferData, 0, rawBufferData.Length);

                            var blendIndices = rawBufferData.ChunkBy(4);

                            objMesh.BlendIndices.AddRange(blendIndices);

                            continue;
                        }

                        if (attribute.Name == "BLENDWEIGHT")
                        {
                            var vectors = ToVector4Array(buffer);
                            objMesh.BlendWeights.AddRange(vectors);
                        }

                        if (attribute.Name == "POSITION")
                        {
                            var vectors = ToVector3Array(buffer);
                            objMesh.Positions.AddRange(vectors);
                        }

                        if (attribute.Name == "NORMAL")
                        {
                            if (VMesh.IsCompressedNormalTangent(drawCall))
                            {
                                var vectors = ToVector4Array(buffer);
                                var(normals, tangents) = DecompressNormalTangents(vectors);
                                objMesh.Normals.AddRange(normals);
                            }
                            else
                            {
                                var vectors = ToVector3Array(buffer);
                                objMesh.Normals.AddRange(vectors);
                            }
                            continue;
                        }

                        if (attribute.Name == "TEXCOORD")
                        {
                            if (numComponents != 2)
                            {
                                // ignore textcoords that arent 2
                                continue;
                            }
                            var vectors = ToVector2Array(buffer);
                            objMesh.TextureCoords.AddRange(vectors);
                        }
                    }

                    // Set index buffer
                    var startIndex = (int)drawCall.GetIntegerProperty("m_nStartIndex");
                    var indexCount = (int)drawCall.GetIntegerProperty("m_nIndexCount");
                    var indices    = ReadIndices(indexBuffer, startIndex, indexCount);
                    var newFaces   = indices.ChunkBy(3).Select(idxList => idxList.Select(idx => new ObjFaceVertex(idx + startingVertexCount)).ToList()).ToList();
                    objMesh.Faces.AddRange(newFaces);

                    var materialPath     = drawCall.GetProperty <string>("m_material");
                    var materialResource = VpkLoader.LoadFile(materialPath + "_c");
                    var renderMaterial   = (VMaterial)materialResource.DataBlock;
                    var matName          = Path.GetFileNameWithoutExtension(materialPath);
                    if (objMesh.Material == null)
                    {
                        objMesh.Material = ObjMaterial.FromVMaterial(renderMaterial, Path.GetFileNameWithoutExtension(materialPath), VpkLoader);
                    }
                    else if (matName != objMesh.Material.Name)
                    {
                        // throw new Exception("2 different mats in same object");
                    }
                }
            }
        }