diff --git a/Geometry/Mesh.cs b/Geometry/Mesh.cs index 3d23b44..32c7afc 100644 --- a/Geometry/Mesh.cs +++ b/Geometry/Mesh.cs @@ -1,12 +1,23 @@ +using Microsoft.Xna.Framework; + namespace Kav { public class Mesh { public MeshPart[] MeshParts { get; } + public BoundingBox BoundingBox { get; } public Mesh(MeshPart[] meshParts) { MeshParts = meshParts; + + BoundingBox boundingBox = new BoundingBox(); + foreach (var meshPart in MeshParts) + { + boundingBox = BoundingBox.CreateMerged(boundingBox, meshPart.BoundingBox); + } + + BoundingBox = boundingBox; } } } diff --git a/Geometry/MeshPart.cs b/Geometry/MeshPart.cs index 248fb1a..25cb93c 100644 --- a/Geometry/MeshPart.cs +++ b/Geometry/MeshPart.cs @@ -9,6 +9,8 @@ namespace Kav public VertexBuffer VertexBuffer { get; } public Triangle[] Triangles { get; } public Vector3[] Positions { get; } + + public BoundingBox BoundingBox { get; } private Texture2D albedoTexture = null; private Texture2D normalTexture = null; @@ -50,6 +52,8 @@ namespace Kav IndexBuffer = indexBuffer; Positions = positions; Triangles = triangles; + + BoundingBox = BoundingBox.CreateFromPoints(Positions); } } } diff --git a/Geometry/Model.cs b/Geometry/Model.cs index 9ab1dc0..6ffe912 100644 --- a/Geometry/Model.cs +++ b/Geometry/Model.cs @@ -5,6 +5,7 @@ namespace Kav public class Model { public Mesh[] Meshes { get; } + public BoundingBox BoundingBox { get; } public Color Albedo { @@ -51,6 +52,14 @@ namespace Kav public Model(Mesh[] meshes) { Meshes = meshes; + + BoundingBox boundingBox = new BoundingBox(); + foreach (var mesh in Meshes) + { + boundingBox = BoundingBox.CreateMerged(boundingBox, mesh.BoundingBox); + } + + BoundingBox = boundingBox; } public void DisableAlbedoMaps() diff --git a/README.md b/README.md index 29c7615..ee54072 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Essential - [x] Cascading shadow maps - [x] Tone map shader - [x] Poisson soft shadowing -- [ ] Frustum culling +- [x] Frustum culling - [x] Shadow-casting point lights - [ ] Parabolic lights - [x] Skyboxes diff --git a/Renderer.cs b/Renderer.cs index 3eb2440..2ad0ceb 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -240,7 +240,9 @@ namespace Kav PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms ) { - foreach (var (model, transform) in modelTransforms) + var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); + + foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) { foreach (var modelMesh in model.Meshes) { @@ -312,7 +314,9 @@ namespace Kav GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; - foreach (var (model, transform) in modelTransforms) + var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); + + foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) { foreach (var modelMesh in model.Meshes) { @@ -581,7 +585,9 @@ namespace Kav effect.LightSpaceMatrixFour = lightSpaceMatrix; } - foreach (var (model, transform) in modelTransforms) + var boundingFrustum = new BoundingFrustum(lightSpaceMatrix); + + foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) { foreach (var modelMesh in model.Meshes) { @@ -677,7 +683,9 @@ namespace Kav targetUpDirection ); - foreach (var (model, transform) in modelTransforms) + var boundingFrustum = new BoundingFrustum(LinearDepthEffect.View * LinearDepthEffect.Projection); + + foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) { foreach (var modelMesh in model.Meshes) { @@ -706,5 +714,41 @@ namespace Kav } } } + + private static IEnumerable<(Model, Matrix)> FrustumCull( + BoundingFrustum boundingFrustum, + IEnumerable<(Model, Matrix)> modelTransforms + ) { + foreach (var modelTransform in modelTransforms) + { + var boundingBox = TransformedBoundingBox(modelTransform.Item1.BoundingBox, modelTransform.Item2); + var containment = boundingFrustum.Contains(boundingBox); + if (containment != ContainmentType.Disjoint) + { + yield return modelTransform; + } + } + } + + private static BoundingBox TransformedBoundingBox(BoundingBox boundingBox, Matrix matrix) + { + var center = (boundingBox.Min + boundingBox.Max) / 2f; + var extent = (boundingBox.Max - boundingBox.Min) / 2f; + + var newCenter = Vector3.Transform(center, matrix); + var newExtent = Vector3.TransformNormal(extent, AbsoluteMatrix(matrix)); + + return new BoundingBox(newCenter - newExtent, newCenter + newExtent); + } + + private static Matrix AbsoluteMatrix(Matrix matrix) + { + return new Matrix( + Math.Abs(matrix.M11), Math.Abs(matrix.M12), Math.Abs(matrix.M13), Math.Abs(matrix.M14), + Math.Abs(matrix.M21), Math.Abs(matrix.M22), Math.Abs(matrix.M23), Math.Abs(matrix.M24), + Math.Abs(matrix.M31), Math.Abs(matrix.M32), Math.Abs(matrix.M33), Math.Abs(matrix.M34), + Math.Abs(matrix.M41), Math.Abs(matrix.M42), Math.Abs(matrix.M43), Math.Abs(matrix.M44) + ); + } } }