示例#1
0
        private static List <Mesh> CreateMeshesFromAiNode(Ai.Node aiNode, Ai.Scene aiScene, Object obj,
                                                          ref AxisAlignedBoundingBox objectAABB, ObjectSet objectSet, string texturesDirectoryPath)
        {
            var aiMeshes = aiNode.MeshIndices.Select(x => aiScene.Meshes[x]).Where(x => x.PrimitiveType == Ai.PrimitiveType.Triangle)
                           .OrderBy(x => x.VertexCount).ThenBy(x => x.FaceCount).ToList();

            if (aiMeshes.Count == 0)
            {
                return(null);
            }

            var meshes    = new List <Mesh>();
            var transform = GetWorldTransform(aiNode);

            int subIndex = 0;

            for (int index = 0; index < aiMeshes.Count;)
            {
                int begin = index;
                int end   = index + 1;

                int vertexCount = aiMeshes[index].VertexCount;

                // Collect meshes till we hit the vertex count limit.
                while (end < aiMeshes.Count)
                {
                    if (vertexCount + aiMeshes[end].VertexCount > 32768)
                    {
                        break;
                    }

                    vertexCount += aiMeshes[end++].VertexCount;
                }

                var mesh = new Mesh {
                    Name = aiNode.Name
                };
                if (index != 0)
                {
                    mesh.Name += "." + (++subIndex).ToString("D3");
                }

                var aabbMesh = new AxisAlignedBoundingBox();

                int vertexOffset = 0;

                for (int it = begin; it < end; it++)   // we goin C++
                {
                    var aiMesh      = aiMeshes[it];
                    var aabbSubMesh = new AxisAlignedBoundingBox();

                    if (aiMesh.HasVertices)
                    {
                        if (mesh.Positions == null)
                        {
                            mesh.Positions = new Vector3[vertexCount];
                        }

                        for (int i = 0; i < aiMesh.VertexCount; i++)
                        {
                            var position = Vector3.Transform(aiMesh.Vertices[i].ToNumerics(), transform);

                            mesh.Positions[vertexOffset + i] = position;

                            aabbSubMesh.AddPoint(position);
                        }
                    }

                    if (aiMesh.HasNormals)
                    {
                        if (mesh.Normals == null)
                        {
                            mesh.Normals = new Vector3[vertexCount];
                        }

                        for (int i = 0; i < aiMesh.VertexCount; i++)
                        {
                            mesh.Normals[vertexOffset + i] = Vector3.Normalize(Vector3.TransformNormal(aiMesh.Normals[i].ToNumerics(), transform));
                        }
                    }

                    for (int i = 0; i < 4; i++)
                    {
                        if (!aiMesh.HasTextureCoords(i))
                        {
                            continue;
                        }

                        var texCoords = mesh.GetTexCoordsChannel(i);

                        if (texCoords == null)
                        {
                            texCoords = new Vector2[vertexCount];
                            mesh.SetTexCoordsChannel(i, texCoords);
                        }

                        for (int j = 0; j < aiMesh.VertexCount; j++)
                        {
                            var texCoord = new Vector2(
                                aiMesh.TextureCoordinateChannels[i][j].X,
                                aiMesh.TextureCoordinateChannels[i][j].Y);

                            texCoords[vertexOffset + j] = texCoord;
                        }
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        if (!aiMesh.HasVertexColors(i))
                        {
                            continue;
                        }

                        var colors = mesh.GetColorsChannel(i);

                        if (colors == null)
                        {
                            colors = new Color[vertexCount];
                            for (int j = 0; j < vertexCount; j++)
                            {
                                colors[j] = Color.White;
                            }

                            mesh.SetColorsChannel(i, colors);
                        }

                        for (int j = 0; j < aiMesh.VertexCount; j++)
                        {
                            colors[vertexOffset + j] = aiMesh.VertexColorChannels[i][j].ToMML();
                        }
                    }

                    var subMesh = new SubMesh();

                    if (aiMesh.HasBones)
                    {
                        if (mesh.BoneWeights == null)
                        {
                            mesh.BoneWeights = new BoneWeight[vertexCount];
                            for (int i = 0; i < mesh.BoneWeights.Length; i++)
                            {
                                mesh.BoneWeights[i] = BoneWeight.Empty;
                            }
                        }

                        subMesh.BoneIndices = new ushort[aiMesh.BoneCount];

                        for (int i = 0; i < aiMesh.BoneCount; i++)
                        {
                            var aiBone = aiMesh.Bones[i];

                            int boneIndex = obj.Skin.Bones.FindIndex(
                                x => x.Name == aiBone.Name);

                            if (boneIndex == -1)
                            {
                                boneIndex = obj.Skin.Bones.Count;

                                var aiBoneNode = aiScene.RootNode.FindNode(aiBone.Name);

                                // This is not right, but I'm not sure how to transform the bind pose matrix
                                // while not having duplicate bones.
                                Matrix4x4.Invert(GetWorldTransform(aiBoneNode), out var inverseBindPoseMatrix);

                                obj.Skin.Bones.Add(new BoneInfo
                                {
                                    Name = aiBoneNode.Name,
                                    InverseBindPoseMatrix = inverseBindPoseMatrix
                                });
                            }

                            foreach (var boneWeight in aiBone.VertexWeights)
                            {
                                mesh.BoneWeights[vertexOffset + boneWeight.VertexID].AddWeight(i, boneWeight.Weight);
                            }

                            subMesh.BoneIndices[i] = ( ushort )boneIndex;
                        }

                        subMesh.BonesPerVertex = 4;
                    }

                    subMesh.Indices = aiMesh.Faces.Where(x => x.IndexCount == 3).SelectMany(x => x.Indices)
                                      .Select(x => ( uint )(vertexOffset + x)).ToArray();

                    subMesh.PrimitiveType = PrimitiveType.Triangles;
                    subMesh.IndexFormat   = IndexFormat.UInt16;

                    var aiMaterial = aiScene.Materials[aiMesh.MaterialIndex];

                    int materialIndex = obj.Materials.FindIndex(x => x.Name == aiMaterial.Name);

                    if (materialIndex == -1)
                    {
                        materialIndex = obj.Materials.Count;
                        obj.Materials.Add(CreateMaterialFromAiMaterial(aiMaterial, objectSet.TextureSet, texturesDirectoryPath));
                    }

                    subMesh.MaterialIndex = ( uint )materialIndex;

                    subMesh.BoundingSphere = aabbSubMesh.ToBoundingSphere();
                    subMesh.BoundingBox    = aabbSubMesh.ToBoundingBox();

                    mesh.SubMeshes.Add(subMesh);

                    vertexOffset += aiMesh.VertexCount;

                    aabbMesh.Merge(aabbSubMesh);
                }

                if (mesh.BoneWeights != null)
                {
                    for (int i = 0; i < mesh.BoneWeights.Length; i++)
                    {
                        mesh.BoneWeights[i].Validate();
                    }
                }

                mesh.GenerateTangents();

                mesh.BoundingSphere = aabbMesh.ToBoundingSphere();
                meshes.Add(mesh);

                objectAABB.Merge(aabbMesh);

                // Go to the next mesh
                index = end;
            }

            return(meshes);
        }