Click or drag to resize
DigitalRuneStep 13: Sky box

In this step we will add a sky box for rendering the background.

Add sky cube map
  1. In the Solution Explorer right-click the MyGameContent content project.
  2. Select Add | Existing Item…
  3. Browse to this folder of the DigitalRune Engine:
    • <DigitalRune Engine Folder>\Samples\Content\
  4. Select Sky2.dds and click Add.

(No special content processore required. Texture can use the default XNA importers and processors.)

Add sky game object

Add a new game object called SkyObject.cs:

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:

MyGameComponent.cs
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);
        }
        …
Add sky renderer

The SkyRenderer can handle SkyBoxNodes. Let's use it in MyGraphicsScreen:

MyGraphicsScreen.cs
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:

Tutorial-01-21