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);
        }
Beispiel #2
0
        public void Update()
        {
            Matrix4 viewMatrix, projectionMatrix;

            if (UseExperimental)
            {
                // Calculate corners of the active camera's frustum
                OldFrustum f = new OldFrustum(Camera.Active, true);

                Vector3[] shadowFrustum = new Vector3[8];
                shadowFrustum[0] = f.FBL;
                shadowFrustum[1] = f.FBR;
                shadowFrustum[2] = f.FTL;
                shadowFrustum[3] = f.FTR;
                shadowFrustum[4] = f.NBL;
                shadowFrustum[5] = f.NBR;
                shadowFrustum[6] = f.NTL;
                shadowFrustum[7] = f.NTR;

                int   shadowRes   = MasterRenderer.Instance.GFXSettings.ShadowResolution;
                float shadowTexel = 1f / shadowRes;

                // Transform each frustum corner into light space
                Vector3 position = new Vector3(
                    (int)(Position.X / shadowTexel) * shadowTexel,
                    (int)(Position.Y / shadowTexel) * shadowTexel,
                    (int)(Position.Z / shadowTexel) * shadowTexel);
                Vector3 target = new Vector3(
                    (int)(Target.X / shadowTexel) * shadowTexel,
                    (int)(Target.Y / shadowTexel) * shadowTexel,
                    (int)(Target.Z / shadowTexel) * shadowTexel);
                viewMatrix = Matrix4.LookAt(position, target, Vector3.UnitY);
                Matrix4 invLightviewMatrix = viewMatrix.Inverse();

                for (int i = 0; i < shadowFrustum.Length; i++)
                {
                    Vector3 transformedVertex = Vector3.Transform(shadowFrustum[i], invLightviewMatrix);
                    transformedVertex.X = (int)(transformedVertex.X / shadowTexel) * shadowTexel;
                    transformedVertex.Y = (int)(transformedVertex.Y / shadowTexel) * shadowTexel;
                    transformedVertex.Z = (int)(transformedVertex.Z / shadowTexel) * shadowTexel;
                    shadowFrustum[i]    = transformedVertex;
                }

                // Calculate the boundingbox of the frustum
                AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox();
                for (int i = 0; i < shadowFrustum.Length; i++)
                {
                    aabb.AddPoint(shadowFrustum[i]);
                }

                float maxX = (aabb.Max.X - aabb.Min.X) / 2f;
                maxX = (int)(maxX / shadowTexel) * shadowTexel;
                float minX = -maxX;
                float maxY = (aabb.Max.Y - aabb.Min.Y) / 2f;
                maxY = (int)(maxY / shadowTexel) * shadowTexel;
                float minY = -maxY;
                float maxZ = (aabb.Max.Z - aabb.Min.Z) / 2f;
                maxZ = (int)(maxZ / shadowTexel) * shadowTexel;
                float minZ = -maxZ;

                //FinalAABB = new AxisAlignedBoundingBox(new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ));

                // Create the projection matrix of the light from the boundingbox
                projectionMatrix = Matrix4.CreateOrthographicOffCenter(minX, maxX, minY, maxY, minZ, maxZ);
                // Matrix4 projectionMatrix = Matrix4.CreateOrthographicOffCenter(minExtent, maxExtent, minExtent, maxExtent, minExtent, maxExtent);
            }
            else
            {
                viewMatrix       = Matrix4.LookAt(Position, Target, Vector3.UnitY);
                projectionMatrix = Matrix4.CreateOrthographicOffCenter(-1600, 1600, -1600, 1600, 10, 3000);
            }

            // And finally, calculate the light space matrix
            LightSpaceMatrix = viewMatrix * projectionMatrix;
        }