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); }
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; }