private bool _cullingEnabled = true; // True to use frustum culling. False to disable frustum culling. public FrustumCullingSample(Microsoft.Xna.Framework.Game game) : base(game) { GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.CornflowerBlue; // The top-down camera. var orthographicProjection = new OrthographicProjection(); orthographicProjection.Set( LevelSize * 1.1f * GraphicsService.GraphicsDevice.Viewport.AspectRatio, LevelSize * 1.1f, 1, 10000f); var topDownCamera = new Camera(orthographicProjection); _topDownCameraNode = new CameraNode(topDownCamera) { View = Matrix44F.CreateLookAt(new Vector3F(0, 1000, 0), new Vector3F(0, 0, 0), -Vector3F.UnitZ), }; // The perspective camera moving through the scene. var perspectiveProjection = new PerspectiveProjection(); perspectiveProjection.SetFieldOfView( MathHelper.ToRadians(45), GraphicsService.GraphicsDevice.Viewport.AspectRatio, 1, 500); var sceneCamera = new Camera(perspectiveProjection); _sceneCameraNode = new CameraNode(sceneCamera); // Initialize collision detection. // We use one collision domain that manages all objects. _domain = new CollisionDomain(new CollisionDetection()) { // We exchange the default broad phase with a DualPartition. The DualPartition // has special support for frustum culling. BroadPhase = new DualPartition<CollisionObject>(), }; // Create a lot of random objects and add them to the collision domain. RandomHelper.Random = new Random(12345); for (int i = 0; i < NumberOfObjects; i++) { // A real scene consists of a lot of complex objects such as characters, vehicles, // buildings, lights, etc. When doing frustum culling we need to test each objects against // the viewing frustum. If it intersects with the viewing frustum, the object is visible // from the camera's point of view. However, in practice we do not test the exact object // against the viewing frustum. Each objects is approximated by a simpler shape. In our // example, we assume that each object is approximated with an oriented bounding box. // (We could also use an other shape, such as a bounding sphere.) // Create a random box. Shape randomShape = new BoxShape(RandomHelper.Random.NextVector3F(1, 10)); // Create a random position. Vector3F randomPosition; randomPosition.X = RandomHelper.Random.NextFloat(-LevelSize / 2, LevelSize / 2); randomPosition.Y = RandomHelper.Random.NextFloat(0, 2); randomPosition.Z = RandomHelper.Random.NextFloat(-LevelSize / 2, LevelSize / 2); // Create a random orientation. QuaternionF randomOrientation = RandomHelper.Random.NextQuaternionF(); // Create object and add it to collision domain. var geometricObject = new GeometricObject(randomShape, new Pose(randomPosition, randomOrientation)); var collisionObject = new CollisionObject(geometricObject) { CollisionGroup = 0, }; _domain.CollisionObjects.Add(collisionObject); } // Per default, the collision domain computes collision between all objects. // In this sample we do not need this information and disable it with a collision // filter. // In a real application, we would use this collision information for rendering, // for example, to find out which lights overlap with which meshes, etc. var filter = new CollisionFilter(); // Disable collision between objects in collision group 0. filter.Set(0, 0, false); _domain.CollisionDetection.CollisionFilter = filter; // Start with the scene camera. GraphicsScreen.CameraNode = _sceneCameraNode; // We will collect a few statistics for debugging. Profiler.SetFormat("NoCull", 1000, "Time in ms to submit DebugRenderer draw jobs without frustum culling."); Profiler.SetFormat("WithCull", 1000, "Time in ms to submit DebugRenderer draw jobs with frustum culling."); }
public CollisionFilterSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.Gray; GraphicsScreen.DrawReticle = true; SetCamera(new Vector3F(0, 0, 10), 0, 0); // ----- Initialize collision detection system. // We use one collision domain that manages all objects. var domain = new CollisionDomain(); // Let's set a filter which disables collision between object in the same collision group. // We can use a broad phase or a narrow phase filter: // Option A) Broad phase filter // The collision detection broad phase computes bounding box overlaps. // A broad phase filter is best used if the filtering rules are simple and do not change // during the runtime of your application. //domain.BroadPhase.Filter = new DelegatePairFilter<CollisionObject>( // pair => pair.First.CollisionGroup != pair.Second.CollisionGroup); // Option B) Narrow phase filter // The collision detection narrow phase computes contacts between objects where the broad // phase has detected a bounding box overlap. Use a narrow phase filter if the filtering rules // are complex or can change during the runtime of your application. var filter = new CollisionFilter(); // Disable collision between objects in the same groups. filter.Set(0, 0, false); filter.Set(1, 1, false); filter.Set(2, 2, false); filter.Set(3, 3, false); domain.CollisionDetection.CollisionFilter = filter; // Create a random list of points. var points = new List<Vector3F>(); for (int i = 0; i < 100; i++) points.Add(RandomHelper.Random.NextVector3F(-1.5f, 1.5f)); // Add lots of spheres to the collision domain. Assign spheres to different collision groups. var random = new Random(); var sphereShape = new SphereShape(0.7f); for (int i = 0; i < 20; i++) { var randomPosition = new Vector3F(random.NextFloat(-6, 6), random.NextFloat(-3, 3), 0); var geometricObject = new GeometricObject(sphereShape, new Pose(randomPosition)); var collisionObject = new CollisionObject(geometricObject) { // A collision group is simply an integer. We can assign collision objects to collision // groups to control the collision filtering. CollisionGroup = random.NextInteger(0, 3), }; domain.CollisionObjects.Add(collisionObject); } // Compute collisions. (The objects do not move in this sample. Therefore, we only have to // call Update once.) domain.Update(0); // Draw objects. The color depends on the collision group. var debugRenderer = GraphicsScreen.DebugRenderer; debugRenderer.Clear(); foreach (var collisionObject in domain.CollisionObjects) { Color color; switch (collisionObject.CollisionGroup) { case 0: color = Color.LightBlue; break; case 1: color = Color.Yellow; break; case 2: color = Color.Orange; break; default: color = Color.LightGreen; break; } debugRenderer.DrawObject(collisionObject.GeometricObject, color, false, false); } debugRenderer.DrawContacts(domain.ContactSets, 0.1f, Color.Red, true); }