Ejemplo n.º 1
0
        public static LoadedModels <RealtimeMaterial> LoadRealtimeModelsFromFile(string baseDirectory, string localPath, PostProcessSteps flags = DefaultPostProcessSteps)
        {
            string filePath = Path.Combine(baseDirectory, localPath);

            string[] directoryStructure = localPath.Split('/');
            string   modelDir           = directoryStructure[0];

            AssimpContext assimpContext = new AssimpContext();

            Assimp.Scene pScene = assimpContext.ImportFile(filePath, flags);

            //TODO: Identify meshcount for each vertex type. Have to preprocess
            int meshCount = pScene.MeshCount;

            var loadedMeshCounts = pScene.GetHenzaiMeshCounts();
            int meshCountP       = loadedMeshCounts.meshCountP;
            int meshCountPC      = loadedMeshCounts.meshCountPC;
            int meshCountPN      = loadedMeshCounts.meshCountPN;
            int meshCountPT      = loadedMeshCounts.meshCountPT;
            int meshCountPNT     = loadedMeshCounts.meshCountPNT;
            int meshCountPNTTB   = loadedMeshCounts.meshCountPNTTB;

            Mesh <VertexPosition>[]              meshesP   = new Mesh <VertexPosition> [meshCountP];
            Mesh <VertexPositionColor>[]         meshesPC  = new Mesh <VertexPositionColor> [meshCountPC];
            Mesh <VertexPositionNormal>[]        meshesPN  = new Mesh <VertexPositionNormal> [meshCountPN];
            Mesh <VertexPositionTexture>[]       meshesPT  = new Mesh <VertexPositionTexture> [meshCountPT];
            Mesh <VertexPositionNormalTexture>[] meshesPNT = new Mesh <VertexPositionNormalTexture> [meshCountPNT];
            Mesh <VertexPositionNormalTextureTangentBitangent>[] meshesPNTTB = new Mesh <VertexPositionNormalTextureTangentBitangent> [meshCountPNTTB];

            RealtimeMaterial[] materialsP     = new RealtimeMaterial[meshCountP];
            RealtimeMaterial[] materialsPC    = new RealtimeMaterial[meshCountPC];
            RealtimeMaterial[] materialsPN    = new RealtimeMaterial[meshCountPN];
            RealtimeMaterial[] materialsPT    = new RealtimeMaterial[meshCountPT];
            RealtimeMaterial[] materialsPNT   = new RealtimeMaterial[meshCountPNT];
            RealtimeMaterial[] materialsPNTTB = new RealtimeMaterial[meshCountPNTTB];

            ushort[][] meshIndiciesP     = new ushort[meshCountP][];
            ushort[][] meshIndiciesPC    = new ushort[meshCountPC][];
            ushort[][] meshIndiciesPN    = new ushort[meshCountPN][];
            ushort[][] meshIndiciesPT    = new ushort[meshCountPT][];
            ushort[][] meshIndiciesPNT   = new ushort[meshCountPNT][];
            ushort[][] meshIndiciesPNTTB = new ushort[meshCountPNTTB][];

            int meshIndiciesP_Counter     = 0;
            int meshIndiciesPC_Counter    = 0;
            int meshIndiciesPN_Counter    = 0;
            int meshIndiciesPT_Counter    = 0;
            int meshIndiciesPNT_Counter   = 0;
            int meshIndiciesPNTTB_Counter = 0;

            var loadedModels = new LoadedModels <RealtimeMaterial>();

            VertexPosition[]              meshDefinitionP   = new VertexPosition[0];
            VertexPositionColor[]         meshDefinitionPC  = new VertexPositionColor[0];
            VertexPositionNormal[]        meshDefinitionPN  = new VertexPositionNormal[0];
            VertexPositionTexture[]       meshDefinitionPT  = new VertexPositionTexture[0];
            VertexPositionNormalTexture[] meshDefinitionPNT = new VertexPositionNormalTexture[0];
            VertexPositionNormalTextureTangentBitangent[] meshDefinitionPNTTB = new VertexPositionNormalTextureTangentBitangent[0];

            for (int i = 0; i < meshCount; i++)
            {
                var aiMesh      = pScene.Meshes[i];
                var vertexCount = aiMesh.VertexCount;
                if (vertexCount == 0)
                {
                    Console.Error.WriteLine("Mesh has no verticies");
                    continue;
                }

                Assimp.Material aiMaterial = pScene.Materials[aiMesh.MaterialIndex];
                Core.Materials.RealtimeMaterial material = aiMaterial.ToRealtimeMaterial();
                VertexRuntimeTypes henzaiVertexType      = aiMaterial.ToHenzaiVertexType();
                switch (henzaiVertexType)
                {
                case VertexRuntimeTypes.VertexPosition:
                    meshDefinitionP = new VertexPosition[vertexCount];
                    break;

                case VertexRuntimeTypes.VertexPositionColor:
                    meshDefinitionPC = new VertexPositionColor[vertexCount];
                    break;

                case VertexRuntimeTypes.VertexPositionTexture:
                    meshDefinitionPT = new VertexPositionTexture[vertexCount];
                    break;

                case VertexRuntimeTypes.VertexPositionNormalTexture:
                    meshDefinitionPNT = new VertexPositionNormalTexture[vertexCount];
                    break;

                case VertexRuntimeTypes.VertexPositionNormal:
                    meshDefinitionPN = new VertexPositionNormal[vertexCount];
                    break;

                case VertexRuntimeTypes.VertexPositionNormalTextureTangentBitangent:
                    meshDefinitionPNTTB = new VertexPositionNormalTextureTangentBitangent[vertexCount];
                    break;

                default:
                    throw new NotImplementedException($"{henzaiVertexType.ToString("g")} not implemented");
                }

                for (int j = 0; j < vertexCount; j++)
                {
                    byte[] bytes = GenerateVertexBytesArrayFromAssimp(henzaiVertexType, aiMesh, j);

                    switch (henzaiVertexType)
                    {
                    case VertexRuntimeTypes.VertexPosition:
                        meshDefinitionP[j] = ByteMarshal.ByteArrayToStructure <VertexPosition>(bytes);
                        break;

                    case VertexRuntimeTypes.VertexPositionColor:
                        meshDefinitionPC[j] = ByteMarshal.ByteArrayToStructure <VertexPositionColor>(bytes);
                        break;

                    case VertexRuntimeTypes.VertexPositionTexture:
                        meshDefinitionPT[j] = ByteMarshal.ByteArrayToStructure <VertexPositionTexture>(bytes);
                        break;

                    case VertexRuntimeTypes.VertexPositionNormalTexture:
                        meshDefinitionPNT[j] = ByteMarshal.ByteArrayToStructure <VertexPositionNormalTexture>(bytes);
                        break;

                    case VertexRuntimeTypes.VertexPositionNormal:
                        meshDefinitionPN[j] = ByteMarshal.ByteArrayToStructure <VertexPositionNormal>(bytes);
                        break;

                    case VertexRuntimeTypes.VertexPositionNormalTextureTangentBitangent:
                        meshDefinitionPNTTB[j] = ByteMarshal.ByteArrayToStructure <VertexPositionNormalTextureTangentBitangent>(bytes);
                        break;

                    default:
                        throw new NotImplementedException($"{henzaiVertexType.ToString("g")} not implemented");
                    }
                }

                var faceCount = aiMesh.FaceCount;
                switch (henzaiVertexType)
                {
                case VertexRuntimeTypes.VertexPosition:
                    materialsP[meshIndiciesP_Counter]    = material;
                    meshIndiciesP[meshIndiciesP_Counter] = new ushort[3 * faceCount];

                    for (int j = 0; j < faceCount; j++)
                    {
                        var face = aiMesh.Faces[j];

                        if (face.IndexCount != 3)
                        {
                            Console.Error.WriteLine("Loading Assimp: Face index count != 3!");
                            continue;
                        }

                        meshIndiciesP[meshIndiciesP_Counter][3 * j + 0] = face.Indices[0].ToUnsignedShort();
                        meshIndiciesP[meshIndiciesP_Counter][3 * j + 1] = face.Indices[1].ToUnsignedShort();
                        meshIndiciesP[meshIndiciesP_Counter][3 * j + 2] = face.Indices[2].ToUnsignedShort();
                    }
                    meshesP[meshIndiciesP_Counter] = new Mesh <VertexPosition>(meshDefinitionP, meshIndiciesP[meshIndiciesP_Counter]);
                    meshIndiciesP_Counter++;
                    break;

                case VertexRuntimeTypes.VertexPositionColor:
                    materialsPC[meshIndiciesPC_Counter]    = material;
                    meshIndiciesPC[meshIndiciesPC_Counter] = new ushort[3 * faceCount];

                    for (int j = 0; j < faceCount; j++)
                    {
                        var face = aiMesh.Faces[j];

                        if (face.IndexCount != 3)
                        {
                            Console.Error.WriteLine("Loading Assimp: Face index count != 3!");
                            continue;
                        }

                        meshIndiciesPC[meshIndiciesPC_Counter][3 * j + 0] = face.Indices[0].ToUnsignedShort();
                        meshIndiciesPC[meshIndiciesPC_Counter][3 * j + 1] = face.Indices[1].ToUnsignedShort();
                        meshIndiciesPC[meshIndiciesPC_Counter][3 * j + 2] = face.Indices[2].ToUnsignedShort();
                    }
                    meshesPC[meshIndiciesPC_Counter] = new Mesh <VertexPositionColor>(meshDefinitionPC, meshIndiciesPC[meshIndiciesPC_Counter]);
                    meshIndiciesPC_Counter++;
                    break;

                case VertexRuntimeTypes.VertexPositionTexture:
                    materialsPT[meshIndiciesPT_Counter]    = material;
                    meshIndiciesPT[meshIndiciesPT_Counter] = new ushort[3 * faceCount];

                    for (int j = 0; j < faceCount; j++)
                    {
                        var face = aiMesh.Faces[j];

                        if (face.IndexCount != 3)
                        {
                            Console.Error.WriteLine("Loading Assimp: Face index count != 3!");
                            continue;
                        }

                        meshIndiciesPT[meshIndiciesPT_Counter][3 * j + 0] = face.Indices[0].ToUnsignedShort();
                        meshIndiciesPT[meshIndiciesPT_Counter][3 * j + 1] = face.Indices[1].ToUnsignedShort();
                        meshIndiciesPT[meshIndiciesPT_Counter][3 * j + 2] = face.Indices[2].ToUnsignedShort();
                    }
                    meshesPT[meshIndiciesPT_Counter] = new Mesh <VertexPositionTexture>(meshDefinitionPT, meshIndiciesPT[meshIndiciesPT_Counter]);
                    meshIndiciesPT_Counter++;
                    break;

                case VertexRuntimeTypes.VertexPositionNormalTexture:
                    materialsPNT[meshIndiciesPNT_Counter]    = material;
                    meshIndiciesPNT[meshIndiciesPNT_Counter] = new ushort[3 * faceCount];

                    for (int j = 0; j < faceCount; j++)
                    {
                        var face = aiMesh.Faces[j];

                        if (face.IndexCount != 3)
                        {
                            Console.Error.WriteLine("Loading Assimp: Face index count != 3!");
                            continue;
                        }

                        meshIndiciesPNT[meshIndiciesPNT_Counter][3 * j + 0] = face.Indices[0].ToUnsignedShort();
                        meshIndiciesPNT[meshIndiciesPNT_Counter][3 * j + 1] = face.Indices[1].ToUnsignedShort();
                        meshIndiciesPNT[meshIndiciesPNT_Counter][3 * j + 2] = face.Indices[2].ToUnsignedShort();
                    }
                    meshesPNT[meshIndiciesPNT_Counter] = new Mesh <VertexPositionNormalTexture>(meshDefinitionPNT, meshIndiciesPNT[meshIndiciesPNT_Counter]);
                    meshIndiciesPNT_Counter++;
                    break;

                case VertexRuntimeTypes.VertexPositionNormal:
                    materialsPN[meshIndiciesPN_Counter]    = material;
                    meshIndiciesPN[meshIndiciesPN_Counter] = new ushort[3 * faceCount];

                    for (int j = 0; j < faceCount; j++)
                    {
                        var face = aiMesh.Faces[j];

                        if (face.IndexCount != 3)
                        {
                            Console.Error.WriteLine("Loading Assimp: Face index count != 3!");
                            continue;
                        }

                        meshIndiciesPN[meshIndiciesPN_Counter][3 * j + 0] = face.Indices[0].ToUnsignedShort();
                        meshIndiciesPN[meshIndiciesPN_Counter][3 * j + 1] = face.Indices[1].ToUnsignedShort();
                        meshIndiciesPN[meshIndiciesPN_Counter][3 * j + 2] = face.Indices[2].ToUnsignedShort();
                    }
                    meshesPN[meshIndiciesPN_Counter] = new Mesh <VertexPositionNormal>(meshDefinitionPN, meshIndiciesPN[meshIndiciesPN_Counter]);
                    meshIndiciesPN_Counter++;
                    break;

                case VertexRuntimeTypes.VertexPositionNormalTextureTangentBitangent:
                    materialsPNTTB[meshIndiciesPNTTB_Counter]    = material;
                    meshIndiciesPNTTB[meshIndiciesPNTTB_Counter] = new ushort[3 * faceCount];

                    for (int j = 0; j < faceCount; j++)
                    {
                        var face = aiMesh.Faces[j];

                        if (face.IndexCount != 3)
                        {
                            Console.Error.WriteLine("Loading Assimp: Face index count != 3!");
                            continue;
                        }

                        meshIndiciesPNTTB[meshIndiciesPNTTB_Counter][3 * j + 0] = face.Indices[0].ToUnsignedShort();
                        meshIndiciesPNTTB[meshIndiciesPNTTB_Counter][3 * j + 1] = face.Indices[1].ToUnsignedShort();
                        meshIndiciesPNTTB[meshIndiciesPNTTB_Counter][3 * j + 2] = face.Indices[2].ToUnsignedShort();
                    }
                    meshesPNTTB[meshIndiciesPNTTB_Counter] = new Mesh <VertexPositionNormalTextureTangentBitangent>(meshDefinitionPNTTB, meshIndiciesPNTTB[meshIndiciesPNTTB_Counter]);
                    meshIndiciesPNTTB_Counter++;
                    break;

                default:
                    throw new NotImplementedException($"{henzaiVertexType.ToString("g")} not implemented");
                }
            }

            if (meshCountP > 0)
            {
                loadedModels.modelP = new Model <VertexPosition, RealtimeMaterial>(modelDir, meshesP, materialsP);
            }
            if (meshCountPC > 0)
            {
                loadedModels.modelPC = new Model <VertexPositionColor, RealtimeMaterial>(modelDir, meshesPC, materialsPC);
            }
            if (meshCountPN > 0)
            {
                loadedModels.modelPN = new Model <VertexPositionNormal, RealtimeMaterial>(modelDir, meshesPN, materialsPN);
            }
            if (meshCountPT > 0)
            {
                loadedModels.modelPT = new Model <VertexPositionTexture, RealtimeMaterial>(modelDir, meshesPT, materialsPT);
            }
            if (meshCountPNT > 0)
            {
                loadedModels.modelPNT = new Model <VertexPositionNormalTexture, RealtimeMaterial>(modelDir, meshesPNT, materialsPNT);
            }
            if (meshCountPNTTB > 0)
            {
                loadedModels.modelPNTTB = new Model <VertexPositionNormalTextureTangentBitangent, RealtimeMaterial>(modelDir, meshesPNTTB, materialsPNTTB);
            }

            return(loadedModels);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Returns a Sphere Mesh with the corresponing vertex struct.
        /// </summary>
        public static Mesh <VertexPositionNormalTextureTangentBitangent> GenerateSphereTangentBitangent(int numLatitudeLines, int numLongitudeLines, float radius)
        {
            // One vertex at every latitude-longitude intersection,
            // plus one for the north pole and one for the south.
            // One meridian serves as a UV seam, so we double the vertices there.
            int numVertices = numLatitudeLines * (numLongitudeLines + 1) + 2;

            VertexPositionNormalTextureTangentBitangent[] vertices = new VertexPositionNormalTextureTangentBitangent[numVertices];
            List <ushort> indices = new List <ushort>();

            // North pole.
            vertices[0].Position           = new Vector3(0, radius, 0);
            vertices[0].TextureCoordinates = new Vector2(0, 0);

            // South pole.
            vertices[numVertices - 1].Position           = new Vector3(0, -radius, 0);
            vertices[numVertices - 1].TextureCoordinates = new Vector2(0, 1);

            // +1.0f because there's a gap between the poles and the first parallel.
            float latitudeSpacing  = 1.0f / (numLatitudeLines + 1.0f);
            float longitudeSpacing = 1.0f / (numLongitudeLines);

            // start writing new vertices at position 1
            int v = 1;

            for (int latitude = 0; latitude < numLatitudeLines; latitude++)
            {
                for (int longitude = 0; longitude <= numLongitudeLines; longitude++)
                {
                    // Scale coordinates into the 0...1 texture coordinate range,
                    // with north at the top (y = 0).
                    vertices[v].TextureCoordinates = new Vector2(
                        longitude.ToFloat() * longitudeSpacing,
                        (latitude.ToFloat() + 1.0f) * latitudeSpacing
                        );

                    // Convert to spherical coordinates:
                    // theta is a longitude angle (around the equator) in radians.
                    // phi is a latitude angle (north or south of the equator).
                    float theta = vertices[v].TextureCoordinates.X * 2.0f * Math.PI.ToFloat();
                    float phi   = vertices[v].TextureCoordinates.Y * Math.PI.ToFloat();

                    // This determines the radius of the ring of this line of latitude.
                    // It's widest at the equator, and narrows as phi increases/decreases.
                    // float c = Math.Sin(phi).ToFloat();

                    // Usual formula for a vector in spherical coordinates.
                    // You can exchange x & z to wind the opposite way around the sphere.
                    vertices[v].Position = new Vector3(
                        Math.Sin(phi).ToFloat() * Math.Sin(theta).ToFloat(),
                        Math.Cos(phi).ToFloat(),
                        Math.Sin(phi).ToFloat() * Math.Cos(theta).ToFloat()
                        ) * radius;

                    vertices[v].Normal = Vector3.Normalize(vertices[v].Position);

                    if (latitude < numLatitudeLines - 1)
                    {
                        indices.Add(v.ToUnsignedShort());
                        indices.Add((v + 1).ToUnsignedShort());
                        indices.Add((v + 1 + numLongitudeLines).ToUnsignedShort());

                        indices.Add((v + 1).ToUnsignedShort());
                        indices.Add((v + 2 + numLongitudeLines).ToUnsignedShort());
                        indices.Add((v + numLongitudeLines + 1).ToUnsignedShort());
                    }


                    var position = vertices[v].Position;
                    var normal   = vertices[v].Normal;

                    // derivative wrt. phi
                    vertices[v].Tangent = Vector3.Normalize(new Vector3(
                                                                Math.Cos(phi).ToFloat() * Math.Sin(theta).ToFloat(),
                                                                -Math.Sin(phi).ToFloat(),
                                                                Math.Cos(phi).ToFloat() * Math.Cos(theta).ToFloat()
                                                                ));

                    // theta
                    vertices[v].Bitangent = Vector3.Normalize(new Vector3(
                                                                  Math.Cos(phi).ToFloat() * Math.Cos(theta).ToFloat(),
                                                                  0,
                                                                  Math.Sin(phi).ToFloat() * -Math.Sin(theta).ToFloat()
                                                                  ));

                    if (vertices[v].Tangent.Length() == 0)
                    {
                        Console.WriteLine("Warning, Tagent is 0");
                    }

                    if (vertices[v].Bitangent.Length() == 0)
                    {
                        Console.WriteLine("Warning, Bitangent is 0");
                    }

                    // Proceed to the next vertex.
                    v++;
                }
            }

            // North pole indices
            for (int longitude = 1; longitude < numLongitudeLines; longitude++)
            {
                indices.Add(0);
                indices.Add((longitude + 1).ToUnsignedShort());
                indices.Add(longitude.ToUnsignedShort());
            }
            indices.Add(0);
            indices.Add(1);
            indices.Add(numLongitudeLines.ToUnsignedShort());

            v -= numLongitudeLines + 1;
            // southpole
            for (int longitude = 0; longitude <= numLongitudeLines; longitude++)
            {
                indices.Add((v + longitude).ToUnsignedShort());
                indices.Add((v + longitude + 1).ToUnsignedShort());
                indices.Add((numVertices - 1).ToUnsignedShort());
            }
            indices.Add((numVertices - 2).ToUnsignedShort());
            indices.Add((v + 1).ToUnsignedShort());
            indices.Add((numVertices - 1).ToUnsignedShort());
            return(new Mesh <VertexPositionNormalTextureTangentBitangent>(vertices, indices.ToArray()));
        }