private void SetCameraPose() { var vehiclePose = _vehicle.Pose; if (_useSpectatorView) { // Spectator Mode: // Camera is looking at the car from a fixed location in the level. Vector3F position = new Vector3F(10, 8, 10); Vector3F target = vehiclePose.Position; Vector3F up = Vector3F.UnitY; // Set the new camera view matrix. (Setting the View matrix changes the Pose. // The pose is simply the inverse of the view matrix). CameraNode.View = Matrix44F.CreateLookAt(position, target, up); } else { // Player Camera: // Camera moves with the car. The look direction can be changed by moving the mouse. Matrix33F yaw = Matrix33F.CreateRotationY(_yaw); Matrix33F pitch = Matrix33F.CreateRotationX(_pitch); Matrix33F orientation = vehiclePose.Orientation * yaw * pitch; Vector3F forward = orientation * -Vector3F.UnitZ; Vector3F up = Vector3F.UnitY; Vector3F position = vehiclePose.Position - 10 * forward + 5 * up; Vector3F target = vehiclePose.Position + 1 * up; CameraNode.View = Matrix44F.CreateLookAt(position, target, up); } }
public override void Update(GameTime gameTime) { // Move the directional light in a circle. float deltaTimeF = (float)gameTime.ElapsedGameTime.TotalSeconds; _lightAngle += 0.3f * deltaTimeF; var position = QuaternionF.CreateRotationY(_lightAngle).Rotate(new Vector3F(6, 6, 0)); // Make the light look at the world space origin. var lightTarget = Vector3F.Zero; var lookAtMatrix = Matrix44F.CreateLookAt(position, lightTarget, Vector3F.Up); // A look-at matrix is the inverse of a normal world or pose matrix. _mainDirectionalLightNode.PoseWorld = new Pose(lookAtMatrix.Translation, lookAtMatrix.Minor).Inverse; // Compute shadow matrix for the new light direction. var lightRayDirection = (lightTarget - position); _shadowMatrix = ProjectedShadowRenderer.CreateShadowMatrix( new Plane(new Vector3F(0, 1, 0), 0.01f), new Vector4F(-lightRayDirection, 0)); // Update the scene - this must be called once per frame. _scene.Update(gameTime.ElapsedGameTime); base.Update(gameTime); }
public void GetBoundsOrthographic() { // Get bounds of AABB in clip space. (Used in OcclusionCulling.fx.) Vector3F cameraPosition = new Vector3F(100, -200, 345); Vector3F cameraForward = new Vector3F(1, 2, 3).Normalized; Vector3F cameraUp = new Vector3F(-1, 0.5f, -2).Normalized; Matrix44F view = Matrix44F.CreateLookAt(cameraPosition, cameraPosition + cameraForward, cameraUp); Matrix44F proj = Matrix44F.CreateOrthographic(16, 9, -10, 100); Matrix44F viewProj = proj * view; Vector3F center = new Vector3F(); Vector3F halfExtent = new Vector3F(); Aabb aabb = new Aabb(center - halfExtent, center + halfExtent); Aabb aabb0, aabb1; GetBoundsOrtho(aabb, viewProj, out aabb0); GetBoundsOrthoSmart(aabb, viewProj, out aabb1); Assert.IsTrue(Aabb.AreNumericallyEqual(aabb0, aabb1)); center = new Vector3F(-9, 20, -110); halfExtent = new Vector3F(5, 2, 10); aabb = new Aabb(center - halfExtent, center + halfExtent); GetBoundsOrtho(aabb, viewProj, out aabb0); GetBoundsOrthoSmart(aabb, viewProj, out aabb1); Assert.IsTrue(Aabb.AreNumericallyEqual(aabb0, aabb1)); }
public MyGraphicsScreen(IGraphicsService graphicsService) : base(graphicsService) { _meshRenderer = new MeshRenderer(); var contentManager = ServiceLocator.Current.GetInstance <ContentManager>(); var spriteFont = contentManager.Load <SpriteFont>("SpriteFont1"); _debugRenderer = new DebugRenderer(graphicsService, spriteFont); Scene = new Scene(); // Add a camera with a perspective projection. var projection = new PerspectiveProjection(); projection.SetFieldOfView( ConstantsF.PiOver4, graphicsService.GraphicsDevice.Viewport.AspectRatio, 0.1f, 100.0f); CameraNode = new CameraNode(new Camera(projection)) { Name = "CameraPerspective", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(10, 5, 10), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)).Inverse), }; Scene.Children.Add(CameraNode); }
public WpRagdollSample(Microsoft.Xna.Framework.Game game) : base(game) { GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.CornflowerBlue; // Set a fixed camera. var projection = new PerspectiveProjection(); projection.SetFieldOfView( MathHelper.ToRadians(30), GraphicsService.GraphicsDevice.Viewport.AspectRatio, 1f, 100.0f); Vector3F cameraTarget = new Vector3F(0, 1, 0); Vector3F cameraPosition = new Vector3F(0, 12, 0); Vector3F cameraUpVector = new Vector3F(0, 0, -1); GraphicsScreen.CameraNode = new CameraNode(new Camera(projection)) { View = Matrix44F.CreateLookAt(cameraPosition, cameraTarget, cameraUpVector), }; InitializePhysics(); }
/// <summary> /// Changes the camera based on the tilt of the Windows Phone. /// </summary> /// <param name="deltaTime">The elapsed time since the last call of <see cref="Update"/>.</param> private void TiltCamera(TimeSpan deltaTime) { // (Note: We use DigitalRune Mathematics instead of the XNA math types - mainly because // DigitalRune Mathematics provides a 3x3 matrix to describe rotations and the QuaternionF // provides a nice helper function to create a rotation from two given vectors. // // Please note that DigitalRune Mathematics uses column vectors whereas XNA uses row vectors. // When using Vector3F and Matrix33F we need to multiple them in this order: v' = M * v. // When using Vector3 and Matrix we need to multiple them in this order: v' = v * M.) // Get accelerometer value transformed into world space. Vector3F accelerometerVector = new Vector3F( -InputService.AccelerometerValue.Y, InputService.AccelerometerValue.Z, -InputService.AccelerometerValue.X); // Run the accelerometer signal through a low-pass filter to remove noise and jitter. Vector3F currentGravityDirection = _lowPassFilter.Filter(accelerometerVector, (float)deltaTime.TotalSeconds); Matrix33F cameraTilt; if (!currentGravityDirection.IsNumericallyZero) { // We have some valid sensor readings. // Let's compute the tilt of the camera. When the phone is lying flat on a table the camera // looks down onto the scene. When the phone is tilted we want to rotate the position of // the camera. QuaternionF contains a useful helper function that creates a rotation from // two given directions - exactly what we need here. cameraTilt = QuaternionF.CreateRotation(currentGravityDirection, new Vector3F(0, -1, 0)).ToRotationMatrix33(); } else { // Current acceleration is nearly (0, 0, 0). We cannot infer any useful direction from // this vector. Reset the camera tilt. cameraTilt = Matrix33F.Identity; } // ----- Set up the view matrix (= the position and orientation of the camera). Vector3F cameraTarget = new Vector3F(0, 2, 0); // That's were the camera is looking at. Vector3F cameraPosition = new Vector3F(0, _cameraDistance, 0); // That's the default position of the camera. Vector3F cameraUpVector = new Vector3F(0, 0, -1); // That's the up-vector of the camera. // Apply the camera tilt to the position and orientation. cameraPosition = cameraTilt * cameraPosition; cameraUpVector = cameraTilt * cameraUpVector; // Keep the camera above the ground. cameraPosition.Y = Math.Max(0.5f, cameraPosition.Y); // Create the view matrix from these points. GraphicsScreen.CameraNode.View = Matrix44F.CreateLookAt(cameraPosition, cameraTarget, cameraUpVector); // Save the camera position because it is required for hit-testing in DragBodies(). _cameraPosition = cameraPosition; }
public override void Update(GameTime gameTime) { // This sample clears the debug renderer each frame. _graphicsScreen.DebugRenderer.Clear(); // A second camera for player B. var totalTime = (float)gameTime.TotalGameTime.TotalSeconds; var position = Matrix33F.CreateRotationY(totalTime * 0.1f) * new Vector3F(4, 2, 4); _cameraNodeB.View = Matrix44F.CreateLookAt(position, new Vector3F(0, 0, 0), new Vector3F(0, 1, 0)); }
/// <summary> /// Positions the camera so that it sees the whole model and is not to near or to far away. /// </summary> private void ResetCameraPose() { if (ModelNode == null && Document.Model == null) { var lookAtMatrix = Matrix44F.CreateLookAt(new Vector3F(10, 10, 10), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)); _cameraNode.PoseWorld = Pose.FromMatrix(lookAtMatrix).Inverse; ModelCenter = new Vector3F(0, 1, 0); MoveSpeed = 5; ZoomSpeed = MoveSpeed / 10; return; } // Get combined AABB of scene nodes. Aabb aabb = new Aabb(); if (ModelNode != null) { foreach (var meshNode in ModelNode.GetSubtree().OfType <MeshNode>()) { aabb.Grow(meshNode.Aabb); } } else { Matrix[] boneTransforms = new Matrix[Document.Model.Bones.Count]; Document.Model.CopyAbsoluteBoneTransformsTo(boneTransforms); foreach (var mesh in Document.Model.Meshes) { var sphere = mesh.BoundingSphere; sphere = sphere.Transform(boneTransforms[mesh.ParentBone.Index]); var partCenter = (Vector3F)sphere.Center; var partRadius = new Vector3F(sphere.Radius); aabb.Grow(new Aabb(partCenter - partRadius, partCenter + partRadius)); } } // Set camera position. var center = aabb.Center; var radius = aabb.Extent.Length / 2; var gamma = _cameraNode.Camera.Projection.FieldOfViewY / 2; var distance = Math.Max((float)(radius / Math.Tan(gamma)) * 0.7f, 1); // * 0.x to move a bit closer otherwise distance is usually to large. _cameraNode.PoseWorld = Pose.FromMatrix( Matrix44F.CreateLookAt(center + new Vector3F(distance), center, Vector3F.Up)).Inverse; // Center for camera orbiting. ModelCenter = center; // Make navigation speed relative to model size. MoveSpeed = Math.Max(radius * 4, 1); ZoomSpeed = MoveSpeed / 10; }
protected override void OnUpdate(TimeSpan deltaTime) { // Rotate camera around origin. _cameraRotation += 0.1f * (float)deltaTime.TotalSeconds; var cameraPosition = Matrix33F.CreateRotationY(_cameraRotation) * new Vector3F(10, 5, 10); var targetPosition = new Vector3F(0, 1, 0); var up = new Vector3F(0, 1, 0); var viewMatrix = Matrix44F.CreateLookAt(cameraPosition, targetPosition, up); CameraNode.PoseWorld = Pose.FromMatrix(viewMatrix.Inverse); Scene.Update(deltaTime); }
/// <summary> /// Moves and rotates the scene node so that it faces a certain direction (in world space). /// </summary> /// <param name="node">The scene node.</param> /// <param name="position">The new position in world space.</param> /// <param name="target"> /// The target coordinates in world space at which the scene node is "looking". /// </param> /// <param name="upVector"> /// The direction that is "up" from the scene node's point of view given in world space. (Does /// not need to be normalized.) /// </param> /// <remarks> /// A scene node uses the same coordinate system as the <strong>XNA Framework</strong>: /// By default, the positive x-axis points to the right, the positive y-axis points up, and the /// positive z-axis points towards the viewer. This method moves the scene node to /// <paramref name="position"/> and rotates it so that its local forward direction (0, 0, -1) is /// pointing towards <paramref name="target"/>. /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="node"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="position"/> is the same as <paramref name="target"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="upVector"/> is (0, 0, 0). /// </exception> /// <exception cref="DivideByZeroException"> /// The camera direction (<paramref name="target"/> - <paramref name="position"/>) is probably /// pointing in the same or opposite direction as <paramref name="upVector"/>. (The two vectors /// must not be parallel.) /// </exception> public static void LookAt(this SceneNode node, Vector3F position, Vector3F target, Vector3F upVector) { if (node == null) { throw new ArgumentNullException("node"); } Matrix44F view = Matrix44F.CreateLookAt(position, target, upVector); Matrix44F viewInverse = view.Inverse; QuaternionF orientation = QuaternionF.CreateRotation(viewInverse.Minor); node.PoseWorld = new Pose(position, orientation); }
public void GetBoundsPerspective() { // Get bounds of AABB in clip space. (Used in OcclusionCulling.fx.) // Note: Z = 0 or negative is handled conservatively. Point (0, 0, 0) is returned. Vector3F cameraPosition = new Vector3F(100, -200, 345); Vector3F cameraForward = new Vector3F(1, 2, 3).Normalized; Vector3F cameraUp = new Vector3F(-1, 0.5f, -2).Normalized; Matrix44F view = Matrix44F.CreateLookAt(cameraPosition, cameraPosition + cameraForward, cameraUp); Matrix44F proj = Matrix44F.CreatePerspectiveFieldOfView(MathHelper.ToRadians(90), 16.0f / 9.0f, 1, 100); Matrix44F viewProj = proj * view; // Empty AABB at center of near plane. Vector3F center = cameraPosition + cameraForward; Vector3F halfExtent = new Vector3F(); Aabb aabb = new Aabb(center - halfExtent, center + halfExtent); Aabb aabb0, aabb1; GetBoundsPersp(aabb, viewProj, out aabb0); GetBoundsPerspSmart(aabb, viewProj, out aabb1); Assert.IsTrue(Aabb.AreNumericallyEqual(aabb0, aabb1)); // AABB inside frustum. center = view.Inverse.TransformPosition(new Vector3F(2, -3, -50)); halfExtent = new Vector3F(1, 6, 10); aabb = new Aabb(center - halfExtent, center + halfExtent); GetBoundsPersp(aabb, viewProj, out aabb0); GetBoundsPerspSmart(aabb, viewProj, out aabb1); Assert.IsTrue(Aabb.AreNumericallyEqual(aabb0, aabb1)); // Behind camera. center = view.Inverse.TransformPosition(new Vector3F(2, -3, 50)); halfExtent = new Vector3F(1, 6, 10); aabb = new Aabb(center - halfExtent, center + halfExtent); GetBoundsPersp(aabb, viewProj, out aabb0); GetBoundsPerspSmart(aabb, viewProj, out aabb1); Assert.IsTrue(Aabb.AreNumericallyEqual(aabb0, aabb1)); // Camera inside AABB. center = view.Inverse.TransformPosition(new Vector3F(2, -3, -50)); halfExtent = new Vector3F(100, 100, 100); aabb = new Aabb(center - halfExtent, center + halfExtent); GetBoundsPersp(aabb, viewProj, out aabb0); GetBoundsPerspSmart(aabb, viewProj, out aabb1); Assert.IsTrue(Aabb.AreNumericallyEqual(aabb0, aabb1)); }
public void InverseViewTest() { CameraInstance cameraInstance = new CameraInstance(new Camera(new PerspectiveProjection())); Assert.AreEqual(Matrix44F.Identity, cameraInstance.View); Assert.AreEqual(Matrix44F.Identity, cameraInstance.ViewInverse); Vector3F position = new Vector3F(1, 2, 3); Vector3F target = new Vector3F(2, 5, 4); Vector3F upVector = new Vector3F(1, 1, 1); Matrix44F view = Matrix44F.CreateLookAt(position, target, upVector); cameraInstance.ViewInverse = view.Inverse; Assert.IsTrue(Matrix44F.AreNumericallyEqual(view, cameraInstance.View)); Assert.IsTrue(Matrix44F.AreNumericallyEqual(view.Inverse, cameraInstance.ViewInverse)); Assert.IsTrue(Matrix44F.AreNumericallyEqual(view.Inverse, cameraInstance.PoseWorld.ToMatrix44F())); }
public WindowsPhoneSample(Microsoft.Xna.Framework.Game game) : base(game) { GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.CornflowerBlue; // Set a fixed camera. var projection = new PerspectiveProjection(); projection.SetFieldOfView( MathHelper.ToRadians(30), GraphicsService.GraphicsDevice.Viewport.AspectRatio, 1f, 1000.0f); Vector3F cameraTarget = new Vector3F(0, 1, 0); Vector3F cameraPosition = new Vector3F(0, 12, 0); Vector3F cameraUpVector = new Vector3F(0, 0, -1); GraphicsScreen.CameraNode = new CameraNode(new Camera(projection)) { View = Matrix44F.CreateLookAt(cameraPosition, cameraTarget, cameraUpVector), }; // We use the accelerometer to control the camera view. The accelerometer registers every // little change, but we do not want a shaky camera. We can use a low-pass filter to smooth // the sensor signal. _lowPassFilter = new LowPassFilter(new Vector3F(0, -1, 0)) { TimeConstant = 0.15f, // Let's try a time constant of 0.15 seconds. // When increasing the time constant the camera becomes more stable, // but also slower. }; // Enable touch gestures _originalEnabledGestures = TouchPanel.EnabledGestures; TouchPanel.EnabledGestures = GestureType.Tap // Tap is used to drop new bodies. | GestureType.Flick // Flick creates an explosion. | GestureType.Hold // Hold to clear the scene. | GestureType.Pinch; // Pinch can be used to zoom in or out. InitializePhysics(); }
public void LookAtTest() { CameraInstance cameraInstance = new CameraInstance(new Camera(new PerspectiveProjection())); Vector3F position = new Vector3F(1, 2, 3); Vector3F target = new Vector3F(2, 5, 4); Vector3F upVector = new Vector3F(1, 1, 1); cameraInstance.PoseWorld = new Pose(new Vector3F(1, 2, 3)); Matrix44F expected = Matrix44F.CreateLookAt(position, target, upVector); cameraInstance.LookAt(target, upVector); Assert.That(Matrix44F.AreNumericallyEqual(expected, cameraInstance.View)); position = new Vector3F(-2, 3, -7.5f); expected = Matrix44F.CreateLookAt(position, target, upVector); cameraInstance.LookAt(position, target, upVector); Assert.That(Vector3F.AreNumericallyEqual(position, cameraInstance.PoseWorld.Position)); Assert.That(Matrix44F.AreNumericallyEqual(expected, cameraInstance.View)); }
public void UnprojectTest() { Viewport viewport = new Viewport(0, 0, 640, 480); PerspectiveProjection projection = new PerspectiveProjection(); projection.SetFieldOfView(MathHelper.ToRadians(60), viewport.AspectRatio, 10, 1000); Matrix44F view = Matrix44F.CreateLookAt(new Vector3F(0, 0, 0), new Vector3F(0, 0, -1), Vector3F.Up); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 0, -10), viewport.Unproject(new Vector3F(320, 240, 0), projection, view))); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(projection.Left, projection.Top, -10), viewport.Unproject(new Vector3F(0, 0, 0), projection, view))); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(projection.Right, projection.Top, -10), viewport.Unproject(new Vector3F(640, 0, 0), projection, view))); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(projection.Left, projection.Bottom, -10), viewport.Unproject(new Vector3F(0, 480, 0), projection, view))); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(projection.Right, projection.Bottom, -10), viewport.Unproject(new Vector3F(640, 480, 0), projection, view))); Vector3[] farCorners = new Vector3[4]; GraphicsHelper.GetFrustumFarCorners(projection, farCorners); Assert.IsTrue(Vector3F.AreNumericallyEqual((Vector3F)farCorners[0], viewport.Unproject(new Vector3F(0, 0, 1), projection, view))); Assert.IsTrue(Vector3F.AreNumericallyEqual((Vector3F)farCorners[1], viewport.Unproject(new Vector3F(640, 0, 1), projection, view))); Assert.IsTrue(Vector3F.AreNumericallyEqual((Vector3F)farCorners[2], viewport.Unproject(new Vector3F(0, 480, 1), projection, view))); Assert.IsTrue(Vector3F.AreNumericallyEqual((Vector3F)farCorners[3], viewport.Unproject(new Vector3F(640, 480, 1), projection, view))); }
public void ViewTest() { CameraInstance cameraInstance = new CameraInstance(new Camera(new PerspectiveProjection())); Assert.AreEqual(Matrix44F.Identity, cameraInstance.View); Assert.AreEqual(Matrix44F.Identity, cameraInstance.ViewInverse); Vector3F position = new Vector3F(1, 2, 3); Vector3F target = new Vector3F(2, 5, 4); Vector3F upVector = new Vector3F(1, 1, 1); Matrix44F view = Matrix44F.CreateLookAt(position, target, upVector); cameraInstance.View = view; Assert.AreEqual(view, cameraInstance.View); Assert.AreEqual(view.Inverse, cameraInstance.ViewInverse); Vector3F originOfCamera = cameraInstance.PoseWorld.Position; originOfCamera = cameraInstance.View.TransformPosition(originOfCamera); Assert.IsTrue(Vector3F.AreNumericallyEqual(Vector3F.Zero, originOfCamera)); Vector4F positionView = new Vector4F(0, 0, -1, 1); Vector4F positionView2; // Transform a point from view space to world space. Vector4F positionWorld = cameraInstance.PoseWorld * positionView; Vector4F positionWorld2 = cameraInstance.ViewInverse * positionView; Assert.IsTrue(Vector4F.AreNumericallyEqual(positionWorld, positionWorld2)); // Transform a point from world space to view space. positionView = cameraInstance.PoseWorld.Inverse * positionWorld; positionView2 = cameraInstance.View * positionWorld; Assert.IsTrue(Vector4F.AreNumericallyEqual(positionView, positionView2)); cameraInstance.View = Matrix44F.Identity; Assert.AreEqual(Vector3F.Zero, cameraInstance.PoseWorld.Position); Assert.AreEqual(Matrix33F.Identity, cameraInstance.PoseWorld.Orientation); }
public override void Update(GameTime gameTime) { // Move the directional light in a circle. float deltaTimeF = (float)gameTime.ElapsedGameTime.TotalSeconds; _lightAngle += 0.3f * deltaTimeF; var position = QuaternionF.CreateRotationY(_lightAngle).Rotate(new Vector3F(6, 6, 0)); // Make the light look at the world space origin. var lightTarget = Vector3F.Zero; var lookAtMatrix = Matrix44F.CreateLookAt(position, lightTarget, Vector3F.Up); // A look-at matrix is the inverse of a normal world or pose matrix. _mainDirectionalLightNode.PoseWorld = new Pose(lookAtMatrix.Translation, lookAtMatrix.Minor).Inverse; // Update the light position of the renderer. // To create a local light shadow (light rays are not parallel), we have to set the light // position and a 4th component of 1. //_projectedShadowRenderer.LightPosition = new Vector4F(position, 1); // To create a directional light shadow (light rays are parallel), we have to set the inverse // light direction and 0. var lightRayDirection = (lightTarget - position); _projectedShadowRenderer.LightPosition = new Vector4F(-lightRayDirection, 0); // For debugging: Draw coordinate axes at (0, 0, 0). _debugRenderer.Clear(); _debugRenderer.DrawAxes(Pose.Identity, 1, true); // Draw light node. (Will be drawn as a coordinate cross.) _debugRenderer.DrawObject(_mainDirectionalLightNode, Color.Yellow, false, true); // Update the scene - this must be called once per frame. _scene.Update(gameTime.ElapsedGameTime); base.Update(gameTime); }
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 top-down camera. GraphicsScreen.CameraNode = _topDownCameraNode; // 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."); }
protected override void OnLoad() { var contentManager = _services.GetInstance <ContentManager>(); _lights.Add(new LightNode(new AmbientLight { Color = new Vector3F(0.9f, 0.9f, 1f), Intensity = 0.05f, HemisphericAttenuation = 1, }) { Name = "AmbientLight", // This ambient light is "infinite", the pose is irrelevant for the lighting. It is only // used for the debug rendering below. PoseWorld = new Pose(new Vector3F(0, 4, 0)), }); _lights.Add(new LightNode(new DirectionalLight { Color = new Vector3F(0.6f, 0.8f, 1f), DiffuseIntensity = 0.1f, SpecularIntensity = 0.1f, }) { Name = "DirectionalLightWithShadow", Priority = 10, // This is the most important light. PoseWorld = new Pose(new Vector3F(0, 5, 0), Matrix33F.CreateRotationY(-1.4f) * Matrix33F.CreateRotationX(-0.6f)), Shadow = new CascadedShadow { PreferredSize = 1024, DepthBiasScale = new Vector4F(0.99f), DepthBiasOffset = new Vector4F(0), FadeOutDistance = 20, MaxDistance = 30, MinLightDistance = 5, ShadowFog = 0.5f, JitterResolution = 3000, SplitDistribution = 0.7f } }); _lights.Add(new LightNode(new DirectionalLight { Color = new Vector3F(0.8f, 0.4f, 0.0f), DiffuseIntensity = 0.1f, SpecularIntensity = 0.0f, }) { Name = "DirectionalLight", PoseWorld = new Pose(new Vector3F(0, 6, 0), Matrix33F.CreateRotationY(-1.4f) * Matrix33F.CreateRotationX(-0.6f) * Matrix33F.CreateRotationX(ConstantsF.Pi)), }); _lights.Add(new LightNode(new PointLight { Color = new Vector3F(0, 1, 0), DiffuseIntensity = 2, SpecularIntensity = 2, Range = 3, Attenuation = 1f, }) { Name = "PointLight", PoseWorld = new Pose(new Vector3F(-7, 1, 0)) }); _lights.Add(new LightNode(new PointLight { DiffuseIntensity = 4, SpecularIntensity = 4, Range = 3, Attenuation = 1f, Texture = contentManager.Load <TextureCube>("LavaBall/LavaCubeMap"), }) { Name = "PointLightWithTexture", PoseWorld = new Pose(new Vector3F(-2, 1, 0)) }); _lights.Add(new LightNode(new PointLight { Color = new Vector3F(1, 1, 1), DiffuseIntensity = 2, SpecularIntensity = 2, Range = 3, Attenuation = 1f, }) { Name = "PointLightWithShadow", PoseWorld = new Pose(new Vector3F(2, 1, 0)), Shadow = new CubeMapShadow { PreferredSize = 128, DepthBiasScale = 0.9f, DepthBiasOffset = -0.01f, } }); _lights.Add(new LightNode(new PointLight { Color = new Vector3F(1, 1, 1), DiffuseIntensity = 4, SpecularIntensity = 4, Range = 3, Attenuation = 1f, Texture = contentManager.Load <TextureCube>("MagicSphere/ColorCube"), }) { Name = "PointLightWithTextureAndShadow", PoseWorld = new Pose(new Vector3F(7, 1, 0)), Shadow = new CubeMapShadow { PreferredSize = 128, DepthBiasScale = 0.9f, DepthBiasOffset = -0.01f, } }); _lights.Add(new LightNode(new ProjectorLight { Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "ProjectorLight", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(-1, 1, -6), new Vector3F(-5, 0, -6), new Vector3F(0, 1, 0))).Inverse, }); _lights.Add(new LightNode(new ProjectorLight { Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "ProjectorLightWithShadow", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(5, 1, -6), new Vector3F(1, 0, -6), new Vector3F(0, 1, 0))).Inverse, Shadow = new StandardShadow { PreferredSize = 128, } }); _lights.Add(new LightNode(new Spotlight { Color = new Vector3F(0, 1, 0), DiffuseIntensity = 2, SpecularIntensity = 2, }) { Name = "Spotlight", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(-7, 1, -12), new Vector3F(-10, 0, -12), new Vector3F(0, 1, 0))).Inverse, }); _lights.Add(new LightNode(new Spotlight { DiffuseIntensity = 2, SpecularIntensity = 2, Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "SpotlightWithTexture", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(-1, 1, -12), new Vector3F(-5, 0, -12), new Vector3F(0, 1, 0))).Inverse, }); _lights.Add(new LightNode(new Spotlight { DiffuseIntensity = 2, SpecularIntensity = 2, }) { Name = "SpotlightWithShadow", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(5, 1, -12), new Vector3F(1, 0, -12), new Vector3F(0, 1, 0))).Inverse, Shadow = new StandardShadow { PreferredSize = 128, } }); _lights.Add(new LightNode(new Spotlight { Color = new Vector3F(1, 1, 0), DiffuseIntensity = 2, SpecularIntensity = 2, Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "SpotlightWithTextureAndShadow", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(11, 1, -12), new Vector3F(5, 0, -12), new Vector3F(0, 1, 0))).Inverse, Shadow = new StandardShadow { PreferredSize = 128, } }); var scene = _services.GetInstance <IScene>(); _debugRenderer = _services.GetInstance <DebugRenderer>(); foreach (var lightNode in _lights) { scene.Children.Add(lightNode); } }
protected override void OnUpdate(TimeSpan deltaTime) { // Mouse centering (controlled by the MenuComponent) is disabled if the game // is inactive or if the GUI is active. In these cases, we do not want to move // the player. if (!_inputService.EnableMouseCentering) { return; } if (_inputService.IsPressed(Keys.Enter, true)) { // Toggle between player camera and spectator view. _useSpectatorView = !_useSpectatorView; } else { float deltaTimeF = (float)deltaTime.TotalSeconds; // Compute new yaw and pitch from mouse movement. float deltaYaw = 0; deltaYaw -= _inputService.MousePositionDelta.X; deltaYaw -= _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.X * 10; _yaw += deltaYaw * deltaTimeF * 0.1f; float deltaPitch = 0; deltaPitch -= _inputService.MousePositionDelta.Y; deltaPitch += _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.Y * 10; _pitch += deltaPitch * deltaTimeF * 0.1f; // Limit the pitch angle to less than +/- 90°. float limit = ConstantsF.PiOver2 - 0.01f; _pitch = MathHelper.Clamp(_pitch, -limit, limit); } // Update SceneNode.LastPoseWorld - this is required for some effects, like // camera motion blur. CameraNode.LastPoseWorld = CameraNode.PoseWorld; var vehiclePose = _vehicle.Pose; if (_useSpectatorView) { // Spectator Mode: // Camera is looking at the car from a fixed location in the level. Vector3F position = new Vector3F(10, 8, 10); Vector3F target = vehiclePose.Position; Vector3F up = Vector3F.UnitY; // Set the new camera view matrix. (Setting the View matrix changes the Pose. // The pose is simply the inverse of the view matrix). CameraNode.View = Matrix44F.CreateLookAt(position, target, up); } else { // Player Camera: // Camera moves with the car. The look direction can be changed by moving the mouse. Matrix33F yaw = Matrix33F.CreateRotationY(_yaw); Matrix33F pitch = Matrix33F.CreateRotationX(_pitch); Matrix33F orientation = vehiclePose.Orientation * yaw * pitch; Vector3F forward = orientation * -Vector3F.UnitZ; Vector3F up = Vector3F.UnitY; Vector3F position = vehiclePose.Position - 10 * forward + 5 * up; Vector3F target = vehiclePose.Position + 1 * up; CameraNode.View = Matrix44F.CreateLookAt(position, target, up); } }
public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order) { if (nodes == null) { throw new ArgumentNullException("nodes"); } if (context == null) { throw new ArgumentNullException("context"); } int numberOfNodes = nodes.Count; if (numberOfNodes == 0) { return; } context.ThrowIfCameraMissing(); context.ThrowIfSceneMissing(); var originalRenderTarget = context.RenderTarget; var originalViewport = context.Viewport; var originalReferenceNode = context.ReferenceNode; var cameraNode = context.CameraNode; // Update SceneNode.LastFrame for all visible nodes. int frame = context.Frame; cameraNode.LastFrame = frame; // The scene node renderer should use the light camera instead of the player camera. context.CameraNode = _perspectiveCameraNode; context.Technique = "Omnidirectional"; var graphicsService = context.GraphicsService; var graphicsDevice = graphicsService.GraphicsDevice; var renderTargetPool = graphicsService.RenderTargetPool; var savedRenderState = new RenderStateSnapshot(graphicsDevice); for (int i = 0; i < numberOfNodes; i++) { var lightNode = nodes[i] as LightNode; if (lightNode == null) { continue; } var shadow = lightNode.Shadow as CubeMapShadow; if (shadow == null) { continue; } var light = lightNode.Light as PointLight; if (light == null) { throw new GraphicsException("CubeMapShadow can only be used with a PointLight."); } // LightNode is visible in current frame. lightNode.LastFrame = frame; if (shadow.ShadowMap == null) { shadow.ShadowMap = renderTargetPool.ObtainCube( new RenderTargetFormat( shadow.PreferredSize, null, false, shadow.Prefer16Bit ? SurfaceFormat.HalfSingle : SurfaceFormat.Single, DepthFormat.Depth24)); } ((PerspectiveProjection)_perspectiveCameraNode.Camera.Projection).SetFieldOfView( ConstantsF.PiOver2, 1, shadow.Near, light.Range); // World units per texel at a planar distance of 1 world unit. float unitsPerTexel = _perspectiveCameraNode.Camera.Projection.Width / (shadow.ShadowMap.Size * shadow.Near); // Convert depth bias from "texel" to world space. // Minus to move receiver closer to light. shadow.EffectiveDepthBias = -shadow.DepthBias * unitsPerTexel; // Convert normal offset from "texel" to world space. shadow.EffectiveNormalOffset = shadow.NormalOffset * unitsPerTexel; var pose = lightNode.PoseWorld; context.ReferenceNode = lightNode; context.Object = shadow; bool shadowMapContainsSomething = false; for (int side = 0; side < 6; side++) { context.Data[RenderContextKeys.ShadowTileIndex] = BoxedIntegers[side]; graphicsDevice.SetRenderTarget(shadow.ShadowMap, CubeMapFaces[side]); // context.RenderTarget = shadow.ShadowMap; // TODO: Support cube maps targets in the render context. context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(Color.White); _perspectiveCameraNode.View = Matrix44F.CreateLookAt( pose.Position, pose.ToWorldPosition(CubeMapForwardVectors[side]), pose.ToWorldDirection(CubeMapUpVectors[side])); // Abort if this cube map frustum does not touch the camera frustum. if (!context.Scene.HaveContact(cameraNode, _perspectiveCameraNode)) { continue; } graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; shadowMapContainsSomething |= RenderCallback(context); } // Recycle shadow map if empty. if (!shadowMapContainsSomething) { renderTargetPool.Recycle(shadow.ShadowMap); shadow.ShadowMap = null; } } graphicsDevice.SetRenderTarget(null); savedRenderState.Restore(); context.CameraNode = cameraNode; context.Technique = null; context.RenderTarget = originalRenderTarget; context.Viewport = originalViewport; context.ReferenceNode = originalReferenceNode; context.Object = null; context.Data[RenderContextKeys.ShadowTileIndex] = null; }
private void Render(RenderContext context) { var originalRenderTarget = context.RenderTarget; var originalViewport = context.Viewport; var graphicsDevice = context.GraphicsService.GraphicsDevice; if (_updateCubeMap) { _updateCubeMap = false; _cloudMapRenderer.Render(_skyNodes, context); // Create a camera with 45° FOV for a single cube map face. var perspectiveProjection = new PerspectiveProjection(); perspectiveProjection.SetFieldOfView(ConstantsF.PiOver2, 1, 1, 100); context.CameraNode = new CameraNode(new Camera(perspectiveProjection)); var size = _skybox.Texture.Size; var hdrFormat = new RenderTargetFormat(size, size, false, SurfaceFormat.HdrBlendable, DepthFormat.None); var hdrTarget = context.GraphicsService.RenderTargetPool.Obtain2D(hdrFormat); var ldrFormat = new RenderTargetFormat(size, size, false, SurfaceFormat.Color, DepthFormat.None); var ldrTarget = context.GraphicsService.RenderTargetPool.Obtain2D(ldrFormat); var spriteBatch = GraphicsService.GetSpriteBatch(); for (int side = 0; side < 6; side++) { // Rotate camera to face the current cube map face. var cubeMapFace = (CubeMapFace)side; context.CameraNode.View = Matrix44F.CreateLookAt( new Vector3F(), GraphicsHelper.GetCubeMapForwardDirection(cubeMapFace), GraphicsHelper.GetCubeMapUpDirection(cubeMapFace)); // Render sky into HDR render target. graphicsDevice.SetRenderTarget(hdrTarget); context.RenderTarget = hdrTarget; context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(Color.Black); _skyRenderer.Render(_skyNodes, context); graphicsDevice.BlendState = BlendState.Opaque; // Convert HDR to RGBM. context.SourceTexture = hdrTarget; context.RenderTarget = ldrTarget; _colorEncoder.Process(context); context.SourceTexture = null; // Copy RGBM texture into cube map face. graphicsDevice.SetRenderTarget((RenderTargetCube)_skybox.Texture, cubeMapFace); spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, null, null, null); spriteBatch.Draw(ldrTarget, new Vector2(0, 0), Color.White); spriteBatch.End(); } context.GraphicsService.RenderTargetPool.Recycle(ldrTarget); context.GraphicsService.RenderTargetPool.Recycle(hdrTarget); } graphicsDevice.BlendState = BlendState.Opaque; graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; context.CameraNode = _cameraObject.CameraNode; var tempFormat = new RenderTargetFormat(originalRenderTarget); tempFormat.SurfaceFormat = SurfaceFormat.HdrBlendable; var tempTarget = context.GraphicsService.RenderTargetPool.Obtain2D(tempFormat); graphicsDevice.SetRenderTarget(tempTarget); graphicsDevice.Viewport = originalViewport; context.RenderTarget = tempTarget; context.Viewport = originalViewport; _skyRenderer.Render(_skybox, context); context.SourceTexture = tempTarget; context.RenderTarget = originalRenderTarget; _hdrFilter.Process(context); context.SourceTexture = null; context.GraphicsService.RenderTargetPool.Recycle(tempTarget); RenderDebugInfo(context); context.CameraNode = null; }
public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order) { if (nodes == null) { throw new ArgumentNullException("nodes"); } if (context == null) { throw new ArgumentNullException("context"); } int numberOfNodes = nodes.Count; if (numberOfNodes == 0) { return; } var graphicsService = context.GraphicsService; var graphicsDevice = graphicsService.GraphicsDevice; var renderTargetPool = graphicsService.RenderTargetPool; int frame = context.Frame; var savedRenderState = new RenderStateSnapshot(graphicsDevice); var originalRenderTarget = context.RenderTarget; var originalViewport = context.Viewport; var originalCameraNode = context.CameraNode; var originalLodCameraNode = context.LodCameraNode; var originalReferenceNode = context.ReferenceNode; try { // Use foreach instead of for-loop to catch InvalidOperationExceptions in // case the collection is modified. for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i] as SceneCaptureNode; if (node == null) { continue; } // Update each node only once per frame. if (node.LastFrame == frame) { continue; } node.LastFrame = frame; var cameraNode = node.CameraNode; if (cameraNode == null) { continue; } var texture = node.RenderToTexture.Texture; if (texture == null) { continue; } // RenderToTexture instances can be shared. --> Update them only once per frame. if (node.RenderToTexture.LastFrame == frame) { continue; } context.CameraNode = cameraNode; context.LodCameraNode = cameraNode; context.ReferenceNode = node; var renderTarget2D = texture as RenderTarget2D; var projection = cameraNode.Camera.Projection; if (renderTarget2D != null) { context.RenderTarget = renderTarget2D; context.Viewport = new Viewport(0, 0, renderTarget2D.Width, renderTarget2D.Height); RenderCallback(context); // Update other properties of RenderToTexture. node.RenderToTexture.LastFrame = frame; node.RenderToTexture.TextureMatrix = GraphicsHelper.ProjectorBiasMatrix * projection * cameraNode.PoseWorld.Inverse; continue; } var renderTargetCube = texture as RenderTargetCube; if (renderTargetCube != null) { var format = new RenderTargetFormat(renderTargetCube) { Mipmap = false }; renderTarget2D = renderTargetPool.Obtain2D(format); context.RenderTarget = renderTarget2D; context.Viewport = new Viewport(0, 0, renderTarget2D.Width, renderTarget2D.Height); if (_spriteBatch == null) { _spriteBatch = graphicsService.GetSpriteBatch(); } var perspectiveProjection = projection as PerspectiveProjection; if (perspectiveProjection == null) { throw new GraphicsException("The camera of the SceneCaptureNode must use a perspective projection."); } // ReSharper disable CompareOfFloatsByEqualityOperator if (perspectiveProjection.FieldOfViewX != ConstantsF.PiOver2 || perspectiveProjection.FieldOfViewY != ConstantsF.PiOver2) { perspectiveProjection.SetFieldOfView(ConstantsF.PiOver2, 1, projection.Near, projection.Far); } // ReSharper restore CompareOfFloatsByEqualityOperator var originalCameraPose = cameraNode.PoseWorld; for (int side = 0; side < 6; side++) { // Rotate camera to face the current cube map face. //var cubeMapFace = (CubeMapFace)side; // AMD problem: If we generate in normal order, the last cube map face contains // garbage when mipmaps are created. var cubeMapFace = (CubeMapFace)(5 - side); var position = cameraNode.PoseWorld.Position; cameraNode.View = Matrix44F.CreateLookAt( position, position + originalCameraPose.ToWorldDirection(GraphicsHelper.GetCubeMapForwardDirection(cubeMapFace)), originalCameraPose.ToWorldDirection(GraphicsHelper.GetCubeMapUpDirection(cubeMapFace))); RenderCallback(context); // Copy RGBM texture into cube map face. graphicsDevice.SetRenderTarget(renderTargetCube, cubeMapFace); _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, null, null, null); _spriteBatch.Draw(renderTarget2D, new Vector2(0, 0), Color.White); _spriteBatch.End(); } cameraNode.PoseWorld = originalCameraPose; renderTargetPool.Recycle(renderTarget2D); // Update other properties of RenderToTexture. node.RenderToTexture.LastFrame = frame; node.RenderToTexture.TextureMatrix = GraphicsHelper.ProjectorBiasMatrix * projection * cameraNode.PoseWorld.Inverse; continue; } throw new GraphicsException( "SceneCaptureNode.RenderToTexture.Texture is invalid. The texture must be a RenderTarget2D or RenderTargetCube."); } } catch (InvalidOperationException exception) { throw new GraphicsException( "InvalidOperationException was raised in SceneCaptureRenderer.Render(). " + "This can happen if a SceneQuery instance that is currently in use is modified in the " + "RenderCallback. --> Use different SceneQuery types in the method which calls " + "SceneCaptureRenderer.Render() and in the RenderCallback method.", exception); } graphicsDevice.SetRenderTarget(null); savedRenderState.Restore(); context.RenderTarget = originalRenderTarget; context.Viewport = originalViewport; context.CameraNode = originalCameraNode; context.LodCameraNode = originalLodCameraNode; context.ReferenceNode = originalReferenceNode; }