Step 13: Sky box |
In this step we will add a sky box for rendering the background.
Select Sky2.dds and click Add.
(No special content processore required. Texture can use the default XNA importers and processors.)
Add a new game object called SkyObject.cs:
using DigitalRune.Game; using DigitalRune.Graphics.SceneGraph; using Microsoft.Practices.ServiceLocation; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace MyGame { public class SkyObject : GameObject { private SkyboxNode _skyboxNode; protected override void OnLoad() { var game = ServiceLocator.Current.GetInstance<Game>(); var scene = ServiceLocator.Current.GetInstance<IScene>(); var cubeMap = game.Content.Load<TextureCube>("Sky2"); _skyboxNode = new SkyboxNode(cubeMap); scene.Children.Add(_skyboxNode); } protected override void OnUnload() { _skyboxNode.Parent.Children.Remove(_skyboxNode); _skyboxNode.Dispose(false); _skyboxNode = null; } } }
In MyGameComponent.cs add a sky object to the game object service:
… namespace MyGame { public class MyGameComponent : Microsoft.Xna.Framework.GameComponent { … public MyGameComponent(Game game) : base(game) { … gameObjectService.Objects.Add(new GroundObject()); gameObjectService.Objects.Add(new LightsObject()); gameObjectService.Objects.Add(new DudeObject()); gameObjectService.Objects.Add(new CrateObject()); gameObjectService.Objects.Add(new SmokeObject()); gameObjectService.Objects.Add(new SkyObject()); // NEW _myGraphicsScreen.DebugRenderer.DrawText("MyGame"); _myGraphicsScreen.DebugRenderer.DrawAxes(Pose.Identity, 1, false); } …
The SkyRenderer can handle SkyBoxNodes. Let's use it in MyGraphicsScreen:
… namespace MyGame { public class MyGraphicsScreen : GraphicsScreen { private MeshRenderer _meshRenderer; private BillboardRenderer _billboardRenderer; private SkyRenderer _skyRenderer; // NEW … public MyGraphicsScreen(IGraphicsService graphicsService) : base(graphicsService) { _meshRenderer = new MeshRenderer(); _billboardRenderer = new BillboardRenderer(graphicsService, 2048); _skyRenderer = new SkyRenderer(graphicsService); // NEW var spriteFont = graphicsService.Content.Load<SpriteFont>("SpriteFont1"); DebugRenderer = new DebugRenderer(graphicsService, spriteFont); Scene = new Scene(); } … protected override void OnRender(RenderContext context) { var graphicsDevice = GraphicsService.GraphicsDevice; graphicsDevice.Clear(Color.CornflowerBlue); context.CameraNode = CameraNode; context.Scene = Scene; // Frustum Culling: Get all the scene nodes that intersect the camera frustum. var query = Scene.Query<CameraFrustumQuery>(context.CameraNode, context); // Render opaque meshes that are visible from the camera graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; graphicsDevice.SamplerStates[0] = SamplerState.AnisotropicWrap; context.RenderPass = "Default"; _meshRenderer.Render(query.SceneNodes, context); context.RenderPass = null; _skyRenderer.Render(query.SceneNodes, context); // NEW graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; _billboardRenderer.Render(query.SceneNodes, context, RenderOrder.BackToFront); DebugRenderer.Render(context); context.Scene = null; context.CameraNode = null; } } }
Here is our sky: