Using a SkyBOx

Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla tempor libero leo, nec condimentum massa. Sed elementum nisi in velit lobortis varius. Mauris pulvinar ullamcorper metus eget rhoncus. Curabitur venenatis dui eu quam bibendum lobortis. Maecenas mattis ligula eget lacus dignissim pulvinar. In et congue justo. Duis at mauris elit. Proin in ante quis turpis pretium vulputate. Suspendisse at erat ut ipsum porta imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi pulvinar ullamcorper dui et euismod. Donec at enim ante. Integer volutpat purus vitae metus adipiscing id hendrerit tortor pretium. Cras ligula odio, congue quis sagittis mattis, malesuada quis tortor. Morbi scelerisque nunc quis orci ultrices interdum porttitor orci interdum. Vivamus enim sapien, hendrerit et tincidunt in, ultrices quis metus. Etiam at sollicitudin lacus. Aliquam eu metus eros. Morbi volutpat ullamcorper enim, nec convallis nunc bibendum a. Duis arcu nunc, fringilla nec porttitor non, vulputate sed tortor. Mauris imperdiet massa sit amet urna pharetra vel tempus massa sagittis. Nulla facilisi. Sed sodales nisi a leo lobortis accumsan. Mauris et mi tellus. Nam vel interdum lectus. Suspendisse ac dui dui. Nunc at diam lacus. Vivamus vel odio eleifend lacus ultrices gravida. Etiam ullamcorper urna nec libero fermentum dictum. Vestibulum faucibus erat justo, in facilisis nisi. Aliquam massa nibh, pretium ut hendrerit eget, ultrices eu ipsum.

SkyBoxes

Back to Tutorials

The Complete Source Code

      Game1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace SpaceSkyBox
{
    public class Game1 : Microsoft.Xna.Framework.Game
    //==========================================================================================================
    //  SpaceSkyBox
    //
    //  Purpose: 
    //      To demonstrate how to use a a skybox and the foundations of a space shooter and provide a 2D environment 
    //  to play around in.
    //
    //
    //  Notes:
    //      
    //
    //==========================================================================================================
    {
        GraphicsDeviceManager graphics;
        SpaceShipGameComponent SpaceShip;
        ProceduralSkyBox SkyBox;
        AsteroidFieldGameComponent AsteroidField;
        float ShipMovementChangeRate = 0.0001f;


        public Game1()
        //==========================================================================================================
        //  Constructor
        //
        //  Purpose: 
        //
        //  Parameters: None.
        //      
        //
        //  Notes:
        //      
        //
        //==========================================================================================================
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferWidth = 1280;   //Screen width horizontal
            graphics.PreferredBackBufferHeight = 720;   //Screen width vertical
            //graphics.PreferredBackBufferFormat = SurfaceFormat.Color;
            //graphics.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8;

            graphics.PreferMultiSampling = true;
            graphics.IsFullScreen = true;

        }
        //==========================================================================================================


        protected override void Initialize()
        //==========================================================================================================
        //  Initialize()
        //
        //  Purpose: Startup code.
        //
        //  Parameters: None.
        //      
        //
        //  Notes:
        //      I've split this program up using drawable game components. Some people may be unfamiliar with XNA's 
        //  game components but they're actually real easy once you figure out how they work. This code to add each
        //  one is the only code needed to add them to Game1.cs here. There is some additional code to facilitate
        //  communication between the components; the view matrix really belongs to the SpaceShip and therefore it 
        //  has to transfer that information to the other components so that they can draw with the same view matrix.
        //      
        //
        //==========================================================================================================
        {
            Window.Title = "SkyBoxes in Space!";

            SpaceShip = new SpaceShipGameComponent(this);   //XWing Drawable Game Component.
            Components.Add(SpaceShip);

            AsteroidField = new AsteroidFieldGameComponent(this);
            Components.Add(AsteroidField);

            SkyBox = new ProceduralSkyBox(this);    //Sky Box Drawable Game Component.
            Components.Add(SkyBox);

        
            base.Initialize();
        }
        //==========================================================================================================

        
        protected override void LoadContent()
        //==========================================================================================================
        //  LoadContent()
        //
        //  Purpose: 
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      Because I chose to go with drawable game components for everything. There's nothing to load here in
        //  the program. Each component load's its own content.
        //      
        //
        //==========================================================================================================
        {
                    
        }
        //==========================================================================================================

        
        protected override void UnloadContent()
        //==========================================================================================================
        //  UnloadContent()
        //
        //  Purpose: 
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      
        //
        //==========================================================================================================
        {
        
        }
        //==========================================================================================================

        
        protected override void Update(GameTime gameTime)
        //==========================================================================================================
        //  Update()
        //
        //  Purpose: To handle user input and update anything not updated in the components (which is nothing).
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      I have the arrow buttons setup to control the camera and wasd to control the ship. E and Q are 
        //  setup to add thrust. What I found was that the ship was very difficult to control once I got yaw, pitch,
        //  and roll all happening simultaneously, especially with forward movement. It can be very difficult to figure
        //  out exactly which controls you need to press to get out of the crazy spin especially to do it quickly enough
        //  to make it happen before running through an asteroid. So, I setup the X key to dampen everything except
        //  forward and backwards motion. The longer you hold down the dampening the more it will dampen the motion. So,
        //  you can tap on it to just get a little dampening perhaps slowing your yaw as the nose gets closer to pointing
        //  in the direction you want it in.
        //
        //      This ended up being extremely clean and straight forward code, partially because of the game components.
        //
        //      I should probably mention that I did little to nothing to immitate real physics here. You don't necessarily
        //  have to have real physics in your game. This might be a good model to try and implement more realistic physics
        //  on. But for the demo, I just want the ship to move around the scene in a semi-realistic fashion.
        //      
        //
        //==========================================================================================================
        {
            KeyboardState KBState;


            KBState = Keyboard.GetState();
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            if (KBState.IsKeyDown(Keys.Escape)) this.Exit();

            //Camera Controls.
            if (KBState.IsKeyDown(Keys.Up)) SpaceShip.ZoomCamera(0.99f);
            if (KBState.IsKeyDown(Keys.Down)) SpaceShip.ZoomCamera(1.01f);
            if (KBState.IsKeyDown(Keys.Right)) SpaceShip.OrbitCamera(0.02f);
            if (KBState.IsKeyDown(Keys.Left)) SpaceShip.OrbitCamera(-0.02f);
            if (KBState.IsKeyDown(Keys.PageUp)) SpaceShip.CameraBoom(0.05f);
            if (KBState.IsKeyDown(Keys.PageDown)) SpaceShip.CameraBoom(-0.05f);

            //Ship Controls.
            if (KBState.IsKeyDown(Keys.E)) SpaceShip.Velocity += ShipMovementChangeRate * 10;
            if (KBState.IsKeyDown(Keys.Q)) SpaceShip.Velocity -= ShipMovementChangeRate * 10;
            if (KBState.IsKeyDown(Keys.D)) SpaceShip.Yaw -= ShipMovementChangeRate;
            if (KBState.IsKeyDown(Keys.A)) SpaceShip.Yaw += ShipMovementChangeRate;
            if (KBState.IsKeyDown(Keys.W)) SpaceShip.Pitch -= ShipMovementChangeRate;
            if (KBState.IsKeyDown(Keys.S)) SpaceShip.Pitch += ShipMovementChangeRate;
            if (KBState.IsKeyDown(Keys.C)) SpaceShip.Roll -= ShipMovementChangeRate;
            if (KBState.IsKeyDown(Keys.Z)) SpaceShip.Roll += ShipMovementChangeRate;
            if (KBState.IsKeyDown(Keys.X))
            {
                //Dampen all turning.
                SpaceShip.Yaw *= 0.95f;
                SpaceShip.Pitch *= 0.95f;
                SpaceShip.Roll *= 0.95f;
            }
        
            base.Update(gameTime);
        }
        //==========================================================================================================

        
        protected override void Draw(GameTime gameTime)
        //==========================================================================================================
        //  Draw()
        //
        //  Purpose: Sets values between game components and calls the game components to draw themselves.
        //
        //  Parameters:
        //      gameTime - Standard XNA.
        //
        //  Notes:
        //      Basically, all this does is base.Draw() to call the draw methods of all the game components. Other than 
        //  that, it just sets the view matrix for each component (the ship controls the view matrix and thus already
        //  has it). And the position of the camera (maintained by the ship component) is passed to the SkyBox in
        //  order to keep the sky box moving with the camera. You want all sky boxes to move positionally with the 
        //  camera, because otherwise the illusion will be broken when you get closer and closer to the horizon and
        //  then pass through the sky box into nothingness. It should be impossible to reach the horizon no matter how
        //  far you travel. However, when the camera rotates the sky box still needs to rotate.
        //
        //==========================================================================================================
        {
            Matrix GameCamera;


            GraphicsDevice.Clear(Color.Black);  //Basically unnecessary, but if the skybox did not draw this would be the screen color.

            GameCamera = SpaceShip.ViewMatrix;  //The ship's view matrix is THE view matrix and so I get it's value once to set it for everything else.
            
            AsteroidField.View = GameCamera;    //The AsteroidField game component needs the view matrix to draw.

            SkyBox.View = GameCamera;   //The SkyBox game component needs the view matrix to draw.
            SkyBox.World = Matrix.CreateTranslation(SpaceShip.GetCameraPosition()); //Make the SkyBox follow the camera positionally, but not rotationally, so that the user never reaches the stars.

            base.Draw(gameTime);    //Calls the Draw() methods of the game components. Comment it out and you'll see that nothing draws.
        }
        //==========================================================================================================
    }
}
      ProceduralSkyBox.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace SpaceSkyBox
{
    public class ProceduralSkyBox : Microsoft.Xna.Framework.DrawableGameComponent   //Had to change this to .DrawableGameComponent from the template.
    //==========================================================================================================
    //  SpaceSkyBox
    //
    //  Purpose: To draw a sky box.
    //
    //  Notes:
    //      The class this inherits from has to be changed to DrawableGameComponent in order to make it "drawable".
    //  Even then you still have to add most of your methods, such as Draw() manually.
    //
    //      Originally, I was using other techniques to do a skybox. For the most part, I was creating a cube model
    //  and texturing it with the skybox texture. The problem there was that it severly limited the texture resolution
    //  that you could use for the sky texture. I'm not sure what the highest usable resolution is for a skybox or
    //  if it changes depending on the game. But I decided to make a skybox component that could be easily plugged 
    //  into any game that would use 6 seperate panels for the skybox allowing maximum resolution for each texture
    //  and also not wasting part of the texture as you do when using UV wrapping to texture a cube.
    //
    //      You could pop this into any game. The namespace would probably have to be changed, and you have to add this
    //  component in Game1.cs and update the world and view matrices from Game1.cs. Oh. And you would need to add
    //  your six sky textures to the Content project (SpaceSkyBoxContent here) and load them by name. But that's basically
    //  all it would take to copy this into your own game. You are more than welcome to do so by the way without giving
    //  me any credit even for commercial use.
    //
    //      The sky box textures that I am using here were created with a program called SpaceScape which is REALLY
    //  awesome! You can use it to create an infinate number of space skyboxes which could be used for different
    //  zones in a space game or possibly even a night sky in other games. I just found this website in a Google search.
    //  How lucky is that?
    //
    //  http://alexcpeterson.com/spacescape
    //
    //==========================================================================================================
    {
        private BasicEffect Effect;
        private Matrix ProjectionMatrix;
        private Matrix ViewMatrix;
        private Matrix WorldMatrix;
        private float SkyBoxScale;
        private Matrix Place;

        private VertexPositionTexture[] QuadVertices;
        private Texture2D SkyBoxFront;
        private Texture2D SkyBoxBack;
        private Texture2D SkyBoxLeft;
        private Texture2D SkyBoxRight;
        private Texture2D SkyBoxTop;
        private Texture2D SkyBoxBottom;
        private Matrix FrontPlacement;
        private Matrix BackPlacement;
        private Matrix LeftPlacement;
        private Matrix RightPlacement;
        private Matrix TopPlacement;
        private Matrix BottomPlacement;


        public ProceduralSkyBox(Game game) : base(game)
        //==========================================================================================================
        //  Constructor
        //
        //  Purpose: 
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      
        //
        //==========================================================================================================
        {
            
        }
        //==========================================================================================================


        public Matrix World     //We have to give external code the ability to move the skybox with the camera.
        {
            set { WorldMatrix = value; }
        }

        public Matrix View  //The camera, or view matrix, is defined externally and so we have to provide a way to import it since the skybox is actually drawn in this component and therefore needs a view matrix.
        {
            set { ViewMatrix = value; }
        }

        

        public override void Initialize()
        //==========================================================================================================
        //  Initialize()
        //
        //  Purpose: Startup code specific to this game component.
        //
        //  Parameters: None.
        //
        //  Notes:
        //            Really there are only 4 things going on in this method inspite of the fact that it looks a little busy.
        //  First, it sets up the projection matrix so that the far clipping plane doesn't clip out the skybox even at an angle. 
        //  Second, it creates a quad (square made out of two triangles) to be used to make a single side of our skybox. Third, 
        //  it creates world matrices that store the information to move and rotate this one quad to all 6 faces of our box
        //  so that the same quad can be used to draw all 6 cube faces of our skybox. Fourth, we define a BasicEffect shader to
        //  draw our skybox with later. 
        //
        //      The problem with the far clipping plane is that nothing will be drawn if it is further away than the
        //  far clipping plane. Our skybox, by definition, is supposed to be "way out there". Plus, we have the skybox's
        //  size set with what is basically a constant SkyBoxScale. I've set it to 10,000 units/meters. That's 10 kilometers
        //  or about 5 miles. But for space that's not very far. We wouldn't be able to see anything drawn outside of the 
        //  skybox. So you need the skybox to be big enough to enclose pretty much everything. I decided 10 kilometers was
        //  good enough for this demo anyway. Things can exist further away than that, they will just draw outside of the
        //  skybox and may "suddenly appear" as they get closer and come through the walls of the skybox.
        //
        //      So we want our skybox to be big, but our far clipping plane in our projection matrix has to be far
        //  enough away that it will not clip out the skybox. If the skybox is 10 kilometers, then it's walls are at 
        //  least 5 kilometers away. So, our far clipping plane has to be at least 5 kilometers or the skybox will 
        //  never be drawn. If you don't see the skybox, this is one of the first problems you check for. But notice
        //  that I said that it must be AT LEAST 5 kilometers. That's the distance straight to a face of the cube from
        //  it's center. But the distance from the center to a corner is considerably further.
        //
        //      That's where the Pythagorean theorum comes in. The Pythagoreans were a religious cult in ancient Greece
        //  who studied math, astronomy, geometry, and music in order to work "magic". The magic that they were attempting
        //  to work is what we know today as "science" (just imagine what someone in 400BC would have thought about
        //  computers and the space shuttle and you start getting the idea of what I mean by "magic"). Anyway, they
        //  figured out a whole lot of stuff that they basically considered magic but is actually some of the foundations
        //  of modern science. One of the big things that they figured out was that you can measure the long side of
        //  a right triangle as long as you know the length of the two other sides. Mathematically they wrote it as
        //
        //      C^2=A^2+B^2
        //
        //      The caret symbol ("^") is "square". So that reads "C square equals A square plus B square". Where
        //  C is the length of the long side that is opposite the right angle and A and B are the lengths of the
        //  other two sides. If you use algebra you can rewrite it to solve to get C by itself. So that would be
        //  "C equals the square root of quantity A squared plus B squared end quantity".
        //
        //      C=SQRRT(A^2 + B^2)
        //
        //  In XNA I wrote that like this:
        //  CornerToCornerIn2D = (float)Math.Sqrt((SkyBoxScale * SkyBoxScale) + (SkyBoxScale * SkyBoxScale));
        //
        //      That will give us the distance to the corner of a square. And we can set out far clipping plane to
        //  be bigger than that so that when we turn to face the corner the corner still gets drawn because it
        //  will certainly not draw half the cube face if half the cube face is further away than the far clipping
        //  plane even if that face is drawn with two triangles. It will cut a triangle in half and stop drawing
        //  any part of it that is further away than the far clipping plane. In the above formula we're actually
        //  calculating the distance between two corners of a square, not from the center to the corner.
        //
        //      Well, that's awesome except that we're in 3D and this is a cube and not a square. So, even if it's
        //  clipping far enough away to include the corner of a square, the corners of a cube are even futher 
        //  away than the corners of a square. So, then we need to apply the three dimensional Pythagorean theorum.
        //  Or we can do like we do here and take the distance from corner to corner on the square of the bottom 
        //  face as one side in a right triangle where we are looking to solve for the distance between opposite
        //  corners of the cube. The length of a cube face is the length of the other leg of the triangle. So that
        //  gives us the 3D distance of opposite corners in the cube as we apply the 2D Pythagorean theorum again.
        //  By dividing that answer in half we get the distance from the center of the cube out to a corner. So then
        //  no matter what size the cube of the skybox is, we will have the far clipping plane set large enough to
        //  not clip out the corners of the skybox. I added 2 meters just to make sure it was not right there on the
        //  clipping plane. We then setup the projection matrix of our camera to draw the skybox.
        //
        //      Next we create an instance of BasicEffect that will be used to draw the skybox. We do this once here
        //  in the Initialization() method because we do not need to build a new shader every time we Draw().
        //
        //      We then define an array of vertices and define those vertices to hold Position and Texture (UV
        //  coordinates) data. Next we set each quad vertex to form a square and UV map the square to a square texture.
        //
        //      Finally we create world matrices for each face of the skybox cube so that we can rotate and position
        //  this same quad (square) over and over again to draw all 6 faces.
        //
        //      I should also mention that I scaled each face to be slightly larger than the face of the skybox cube.
        //  This was because you could see the seams between each face and it destroyed the illusion when you can
        //  actually see the box of the skybox. I never did really work out mathematically how big this extra scaling
        //  needs to be. I just plugged in various numbers until I found that 16 worked pretty good for a cube 10,000
        //  units wide. When the cube was smaller a smaller amount worked. I created what is basically a constant in
        //  ExtraStretchToCoverTheSeams to hold this value and reuse it.
        //
        //      When you are positioning a face, the quad is created centered and so you move the quad out to half
        //  the width of the cube (from the center). Then you rotate it to face back towards the center. PiOver2, or
        //  Pi divided by two, is a quarter of a circle, or 90 degrees.
        //
        //==========================================================================================================
        {
            float CornerToCornerIn2D;   
            float CenterToCornerIn3D;
            float ExtraStretchToCoverTheSeams = 16f;    //Scaled 16 units wider to help hide the seams of the skybox. I experimented to get this number.


            SkyBoxScale = 10000f;
            CornerToCornerIn2D = (float)Math.Sqrt((SkyBoxScale * SkyBoxScale) + (SkyBoxScale * SkyBoxScale));   //Pythagorean Theorm.
            CenterToCornerIn3D = (float)Math.Sqrt((CornerToCornerIn2D * CornerToCornerIn2D) + (SkyBoxScale * SkyBoxScale))/2f;  //3D Pythagorean Theorm. Cut in half for center to corner.
            ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Game.GraphicsDevice.Viewport.AspectRatio, 1f, CenterToCornerIn3D +2f);

            Effect = new BasicEffect(Game.GraphicsDevice);  //Built in shader.

            QuadVertices = new VertexPositionTexture[6];
            QuadVertices[0] = new VertexPositionTexture(new Vector3(-0.5f, -0.5f, 0f), new Vector2(0f, 1f));    //Bottom Left
            QuadVertices[1] = new VertexPositionTexture(new Vector3(-0.5f, 0.5f, 0f), new Vector2(0f, 0f));    //Top Left
            QuadVertices[2] = new VertexPositionTexture(new Vector3(0.5f, 0.5f, 0f), new Vector2(1f, 0f));    //Top Right

            QuadVertices[3] = new VertexPositionTexture(new Vector3(0.5f, 0.5f, 0f), new Vector2(1f, 0f));    //Top Right
            QuadVertices[4] = new VertexPositionTexture(new Vector3(0.5f, -0.5f, 0f), new Vector2(1f, 1f));    //Bottom Right
            QuadVertices[5] = new VertexPositionTexture(new Vector3(-0.5f, -0.5f, 0f), new Vector2(0f, 1f));    //Bottom Left

            FrontPlacement = Matrix.CreateScale(SkyBoxScale + ExtraStretchToCoverTheSeams) * Matrix.CreateTranslation(0f, 0f, -SkyBoxScale / 2);  
            TopPlacement = Matrix.CreateScale(SkyBoxScale + ExtraStretchToCoverTheSeams) * Matrix.CreateRotationX(MathHelper.PiOver2) * Matrix.CreateTranslation(0f, SkyBoxScale / 2, 0f);
            LeftPlacement = Matrix.CreateScale(SkyBoxScale + ExtraStretchToCoverTheSeams) * Matrix.CreateRotationY(MathHelper.PiOver2) * Matrix.CreateTranslation(-SkyBoxScale / 2, 0f, 0f);
            RightPlacement = Matrix.CreateScale(SkyBoxScale + ExtraStretchToCoverTheSeams) * Matrix.CreateRotationY(-MathHelper.PiOver2) * Matrix.CreateTranslation(SkyBoxScale / 2, 0f, 0f);
            BottomPlacement = Matrix.CreateScale(SkyBoxScale + ExtraStretchToCoverTheSeams) * Matrix.CreateRotationX(-MathHelper.PiOver2) * Matrix.CreateTranslation(0f, -SkyBoxScale / 2, 0f);
            BackPlacement = Matrix.CreateScale(SkyBoxScale + ExtraStretchToCoverTheSeams) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateTranslation(0f, 0f, SkyBoxScale / 2);  

            base.Initialize();
        }
        //==========================================================================================================


        protected override void LoadContent()
        //==========================================================================================================
        //  LoadContent()
        //
        //  Purpose: To load the textures that will be drawn on the skybox.
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      We just load an image for each of the 6 faces of the skybox. We have to use Game.Content because this is
        //  a game component. Never spcify the file extension like .png because it's actually loading the .xnb file that
        //  was created from the .png file and not the .png file itself.
        //
        //==========================================================================================================
        {
            SkyBoxFront = Game.Content.Load<Texture2D>("BlueNebulaSkyBox_front5");
            SkyBoxTop = Game.Content.Load<Texture2D>("BlueNebulaSkyBox_top3");
            SkyBoxLeft = Game.Content.Load<Texture2D>("BlueNebulaSkyBox_left2");
            SkyBoxRight = Game.Content.Load<Texture2D>("BlueNebulaSkyBox_right1");
            SkyBoxBottom = Game.Content.Load<Texture2D>("BlueNebulaSkyBox_bottom4");
            SkyBoxBack = Game.Content.Load<Texture2D>("BlueNebulaSkyBox_back6");

            base.LoadContent();
        }
        //==========================================================================================================


        public override void Update(GameTime gameTime)
        //==========================================================================================================
        //  Update()
        //
        //  Purpose: 
        //
        //  Parameters:
        //      gameTime - XNA standard.
        //
        //  Notes:
        //      The only thing that updates with a skybox is it's position. And that's handled directly by setting its
        //  world matrix.
        //
        //==========================================================================================================
        {
        
            base.Update(gameTime);
        }
        //==========================================================================================================


        public override void Draw(GameTime gameTime)
        //==========================================================================================================
        //  Draw()
        //
        //  Purpose: To draw the skybox.
        //
        //  Parameters:
        //      gameTime - XNA standard.
        //
        //  Notes:
        //      Calls DrawBoxPanel() 6 times to draw every face of the cube.
        //
        //==========================================================================================================
        {
            DrawBoxPanel(FrontPlacement, SkyBoxFront);
            DrawBoxPanel(TopPlacement, SkyBoxTop);
            DrawBoxPanel(LeftPlacement, SkyBoxLeft);
            DrawBoxPanel(RightPlacement, SkyBoxRight);
            DrawBoxPanel(BackPlacement, SkyBoxBack);
            DrawBoxPanel(BottomPlacement, SkyBoxBottom);
            
            base.Draw(gameTime);
        }
        //==========================================================================================================


        private void DrawBoxPanel(Matrix Placement, Texture2D SkyBoxTexture)
        //==========================================================================================================
        //  DrawBoxPanel()
        //
        //  Purpose: To draw a single side of the skybox.
        //
        //  Parameters:
        //      Placement - this is a world matrix that defines the rotation and position of this panel.
        //      SkyBoxTexture - This is the texture that will be drawn on this panel.
        //
        //  Notes:
        //      
        //
        //==========================================================================================================
        {
            Effect.World = Placement * WorldMatrix;
            Effect.Projection = ProjectionMatrix;
            Effect.View = ViewMatrix;
            Effect.TextureEnabled = true;
            Effect.Texture = SkyBoxTexture;


            foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                Game.GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, QuadVertices, 0, 2, VertexPositionTexture.VertexDeclaration);
            }

        }
        //==========================================================================================================

    }
}
      SpaceShipGameComponent.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace SpaceSkyBox
{
    public class SpaceShipGameComponent : Microsoft.Xna.Framework.DrawableGameComponent //Had to change this to .DrawableGameComponent from the template.
    //==========================================================================================================
    //  SpaceShipGameComponent
    //
    //  Purpose: To handle all code related to the ship and camera.
    //
    //  Parameters:
    //      
    //
    //  Notes:
    //      I don't think there is a template to create a drawable game component in XNA. I just added a new standard
    //  game component to the project and then changed the object it inheriets from to Microsoft.Xna.Framework.DrawableGameComponent
    //  and this works except you still have to add all the override methods that it is missing manually.
    //
    //==========================================================================================================
    {
        private Model XWing;    //The data to draw the XWing model.
        private Matrix XWingWorldMatrix;    //Contains all the position and orientation data of the XWing model.
        private Matrix CameraViewMatrix;    //The view matrix. This is the camera.
        private Matrix BlenderCorrection;   //Blender likes to export models to XNA sideways.
        private Matrix CameraMount;     //Position above the XWing where the camera will be attached to.
        private Matrix CameraPosition;  //Position of the actual camera. We don't use this for camera facing, only position.
        private float CameraDistance;   //Distance of the camera away from the mount like the length of a "boom arm".
        private RasterizerState RS; //I needed this to turn backface culling on.
        private float ShipVelocity; //Current velocity (speed) of the ship.
        private float PitchPerFrame = 0f;   //Amount the ship is rotating during each frame.
        private float YawPerFrame = 0f;     //Amount the ship is rotating during each frame.
        private float RollPerFrame = 0f;    //Amount the ship is rotating during each frame.


        const float CameraMaxZoom = 100f;   //The furthest the camera can zoom out because if you don't stop it it will mess up the skybox.


        public SpaceShipGameComponent(Game game) : base(game)
        //==========================================================================================================
        //  Constructor
        //
        //  Purpose: 
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      
        //
        //==========================================================================================================
        {

        }
        //==========================================================================================================


        public Matrix WorldMatrix
        {
            get { return XWingWorldMatrix; }
            set { XWingWorldMatrix = value; }
        }


        public Matrix ViewMatrix
        {
            get { return CameraViewMatrix; }
        }

        
        public float Yaw
        {
            get { return YawPerFrame; }
            set { YawPerFrame = value; }
        }


        public float Pitch
        {
            get { return PitchPerFrame; }
            set { PitchPerFrame = value; }
        }


        public float Roll
        {
            get { return RollPerFrame; }
            set { RollPerFrame = value; }
        }


        public float Velocity
        {
            get { return ShipVelocity; }
            set { ShipVelocity = value; }
        }


        public Vector3 GetCameraPosition()
        //==========================================================================================================
        //  GetCameraPosition()
        //
        //  Purpose: To provide the camera position to external components, as a vector.
        //
        //  Parameters: None
        //      
        //
        //  Notes:
        //      Other components, like the skybox, need the camera position. The skybox needs to move with the camera
        //  and always keep the skybox centered at the camera's position. This is just the way skyboxes work. Since
        //  the camera is maintained here in this component, it must provide a way to get the camera position to external
        //  components.
        //
        //      Other components don't necessarily need the entire matrix because they don't need any rotational
        //  information in the matrix. So, I made the return result be a position/vector.
        //
        //      The Camera position actually has to be calculated here because CameraPosition is relative to the
        //  CameraMount which is relative to the XWingWorldMatrix. These matrices have to be combined in reverse order
        //  in order to find the camera position which is then turned into a vector/position. (It's not a true vector
        //  because we don't really care what direction the camera position is "pointing in". But XNA likes positions
        //  to be stored as vectors.)
        //      
        //
        //==========================================================================================================
        {
            Matrix CameraAt;

            CameraAt = CameraPosition * CameraMount * XWingWorldMatrix; 
            return CameraAt.Translation;
        }
        //==========================================================================================================


        public override void Initialize()
        //==========================================================================================================
        //  Initialize()
        //
        //  Purpose: Setup code specific to this component.
        //
        //  Parameters: None.
        //      
        //
        //  Notes:
        //      The rasterizer state is set to cull counter clockwise faces for faster performance. This reveals
        //  problems in the XWing model that I am using as I got some of the normals wrong. (R2D2 is drawn inside
        //  out because his normals are facing the wrong way.) It will draw correctly if you set CullMode to None,
        //  but a more appropriate fix would be to fix the normals in the model. I just don't want to take a couple
        //  of hours to do it for a demo.
        //
        //      I set the initial camera position here. CameraMount is basically a position above the XWing model
        //  that is used to revolve the camera around as well as look at for the view matrix. CameraPosition is the
        //  actual position of the camera which is relative to the CameraMount which is relative to the XWing's 
        //  world matrix. This is what makes the camera follow the XWing.
        //      
        //
        //==========================================================================================================
        {
            RS = new RasterizerState();
            RS.CullMode = CullMode.CullCounterClockwiseFace; //Model has it's indices wound backwards.
            //RS.CullMode = CullMode.None; //Model has it's indices wound backwards.
            RS.FillMode = FillMode.Solid;

            CameraDistance = 7f;
            CameraMount = Matrix.CreateTranslation(new Vector3(0f, 1.7f, 0f));
            CameraPosition = Matrix.CreateTranslation(new Vector3(0f, 0f, CameraDistance));


            base.Initialize();
        }
        //==========================================================================================================


        protected override void LoadContent()
        //==========================================================================================================
        //  LoadContent()
        //
        //  Purpose: To load any content specific to this component.
        //
        //  Parameters: None.
        //
        //  Notes:
        //      I had to add LoadContent manually when I created this Game Component.
        //
        //      Notice that it is Game.Content.Load<> and not just Content.Load<>. It has to be done that way for
        //  game components. But the cool thing is that it can see objects in Game which are external to this 
        //  component.
        //
        //      The XWing model was done by Angel David Guzman (PixelOz) and can be downloaded at       
        //  http://www.scifi-meshes.com/forums/showthread.php?79105-X-Wing-Fighter-Low-Poly-3D-Model-By-PixelOz
        //  The model was one of those rare finds that is basically exactly what we need. I needed a spaceship
        //  model that had a low polygon count and could be turned into a .fbx model. This model met all that
        //  criteria and still looks pretty sharp. I had to import it into Blender. And then because Blender
        //  does all of its normals inside out compared to XNA, I had to flip all of the normals. I missed some
        //  so the model looks a bit rough. I'm not a Blender guru, and so it was very difficult for me to get it
        //  even in the shape that I managed to get it in. But I managed to export it as a .fbx file and it works
        //  fine for this demo. You can download the model from the original source and do a better .fbx export if
        //  you like. You might even be able to set it up for animation.
        //
        //==========================================================================================================
        {
            XWing = Game.Content.Load<Model>("XWingFighter");   //This model is available at http://www.scifi-meshes.com/forums/showthread.php?79105-X-Wing-Fighter-Low-Poly-3D-Model-By-PixelOz
            BlenderCorrection = Matrix.CreateRotationX(-MathHelper.PiOver2); //Blender rotates the models funky compared to XNA. Fix it.
            XWingWorldMatrix = Matrix.CreateTranslation(new Vector3(0f, 0.0f, 0f)); // I want the model centered at its imaginary center of gravity
         
            base.LoadContent();
        }
        //==========================================================================================================


        public void CameraBoom(float DistanceChange)
        //==========================================================================================================
        //  CameraBoom()
        //
        //  Purpose: To change the height of the camera's "boom arm".
        //
        //  Parameters:
        //      DistanceChange - The distance to raise or lower the camera.
        //
        //  Notes:
        //      The camera is on an imaginary "boom arm" that is mounted to CameraMount. By raising and lowering
        //  CameraMount itself, you raise and lower the entire "boom arm" and the camera on it. So it just changes the
        //  "height" of the camera.
        //
        //==========================================================================================================
        {
            CameraMount *= Matrix.CreateTranslation(0f, DistanceChange, 0f);
        }
        //==========================================================================================================


        public void OrbitCamera(float TurnAngleInRadians)
        //==========================================================================================================
        //  OrbitCamera()
        //
        //  Purpose: To move the camera around the ship.
        //
        //  Parameters:
        //      TurnAngleInRadians - The angle in radians to orbit the camera through this frame.
        //
        //  Notes:
        //      The CameraPosition is attached to the CameraMount and so it essentially rotates around that point.
        //
        //==========================================================================================================
        {
            CameraPosition *= Matrix.CreateRotationY(TurnAngleInRadians);
        }
        //==========================================================================================================


        public void ZoomCamera(float DistanceChangePercentage)
        //==========================================================================================================
        //  ZoomCamera()
        //
        //  Purpose: To move the camera in or out from the CameraMount point.
        //
        //  Parameters:
        //      DistanceChangePercentage - Used to modify the distance by a percentage.
        //
        //  Notes:
        //      This method turns the position inside the CameraPosition matrix into a vector which represents the
        //  "boom arm" between the CameraMount and the CameraPosition. By normalizing this vector and multiplying
        //  by the length of the "boom arm" we want, we control the distance of the camera from CameraMount, zooming
        //  it in and out. Of course, CameraPosition is a matrix; so we have to put the position of the camera, as a
        //  vector, back into a matrix to be stored as CameraPosition. We also force the length of the "boom arm" to
        //  stay within a range of 1 to CameraMaxZoom.
        //
        //==========================================================================================================
        {
            Vector3 PathBetweenCameraAndMount;


            PathBetweenCameraAndMount = CameraPosition.Translation; //The camera's position vector is an arrow the length from CameraMount to the camera position. 
            PathBetweenCameraAndMount *= DistanceChangePercentage;  //Multiply it by a percentage (1=100 percent) to change the distance/length of the "boom arm".

            if (PathBetweenCameraAndMount.Length() > CameraMaxZoom) //Don't let it zoom out to far.
            {
                PathBetweenCameraAndMount.Normalize();  //Normalize to set it to 1 so that we can reset the vector's length.
                PathBetweenCameraAndMount *= CameraMaxZoom; //Set the vector's length to CameraMaxZoom.
            }
            if (PathBetweenCameraAndMount.Length() < 1) PathBetweenCameraAndMount.Normalize();  //The minimum zoom distance is 1.

            CameraPosition = Matrix.CreateTranslation(PathBetweenCameraAndMount);   //Reset the localy stored camera position which is a matrix. No rotational information is used in this matrix.
        }
        //==========================================================================================================

        
        public override void Update(GameTime gameTime)
        //==========================================================================================================
        //  Update()
        //
        //  Purpose: To do any updates each frame specific to this component.
        //
        //  Parameters:
        //      gameTime - XNA standard.
        //
        //  Notes:
        //      This is actually pretty straight forward. The rotations are stored as angle per frame and the object
        //  will rotate at that rate infinately unless a new rate of rotation is set. That is actually the way it 
        //  would work in the real world; so I at least got one thing correct in terms of physics. Of course there is
        //  no angular momentum, but still. 
        //
        //      Anyway, we start by creating rotation matrices out of the rotations. We then record the ship's current
        //  position for later. We move the ship to the world origin, apply all 3 rotations basically at once (notice
        //  that the order that they are combined in here is important), and then move the ship back to where it was
        //  with the position we recorded. Finally, we move the ship forward by the amount of the ship's current
        //  velocity per frame. I'm assuming 60 frames per second, which is a dangerous assumption. A more robust 
        //  program would calculate the frame rate to keep things applied at the same rate regardless of the actual
        //  framerate. But this is a demo, so I'll let you worry about that on your own. That's what gameTime is for.
        //
        //==========================================================================================================
        {
            Matrix PitchThisFrame;
            Matrix YawThisFrame;
            Matrix RollThisFrame;
            Vector3 XWingsOffsetFromWorldOrigin;


            PitchThisFrame = Matrix.CreateRotationX(PitchPerFrame);
            YawThisFrame = Matrix.CreateRotationY(YawPerFrame);
            RollThisFrame = Matrix.CreateRotationZ(RollPerFrame);

            XWingsOffsetFromWorldOrigin = XWingWorldMatrix.Translation;

            XWingWorldMatrix *= Matrix.CreateTranslation(-XWingsOffsetFromWorldOrigin); //Move ship to the center of the world to rotate it.
            XWingWorldMatrix = PitchThisFrame * YawThisFrame * RollThisFrame * XWingWorldMatrix;
            XWingWorldMatrix *= Matrix.CreateTranslation(XWingsOffsetFromWorldOrigin);  //Put the ship back where it was.

            XWingWorldMatrix *= Matrix.CreateTranslation( (XWingWorldMatrix.Forward * ShipVelocity));

            base.Update(gameTime);
        }
        //==========================================================================================================


        public override void Draw(GameTime gameTime)
        //==========================================================================================================
        //  Draw()
        //
        //  Purpose: To draw the ship.
        //
        //  Parameters:
        //      gameTime - XNA standard.
        //
        //  Notes:
        //      We start by setting the rasterizer state. We can get the rasterizer state through the Game object from inside
        //  a game component. We create the rasterizer state once in initialization and then set it to the one we created
        //  whenever needed. This is because creating a rasterizer state is said to have extremely high overhead.
        //
        //      Next we setup our camera by defining a view matrix. These three lines of code are essentially the camera.
        //  This view matrix is passed to the other components so that they draw from the same camera.
        //
        //      Then we loop through all one meshes in this model, setting the parameters for its shader, and tell the
        //  mesh to draw itself.
        //
        //==========================================================================================================
        {
            Matrix Camera;
            Matrix CameraMountPosition;
            Game.GraphicsDevice.RasterizerState = RS;

            Camera = CameraPosition * CameraMount * XWingWorldMatrix;   //Define the point where the camera is relative to the ship.
            CameraMountPosition = CameraMount * XWingWorldMatrix;  //This position is where the camera "boom" is attached and is always where the camera looks.

            CameraViewMatrix = Matrix.CreateLookAt(Camera.Translation, CameraMountPosition.Translation, Camera.Up);
            
            foreach (ModelMesh Mesh in XWing.Meshes)
            {
                foreach (BasicEffect e in Mesh.Effects)
                {
                    e.EnableDefaultLighting();
                    e.AmbientLightColor = Color.DarkSlateBlue.ToVector3();
                    e.PreferPerPixelLighting = true;
                    e.TextureEnabled = false;   //The XWing is not actually textured.
                    e.LightingEnabled = true;
                    e.World = BlenderCorrection * XWingWorldMatrix; //The order here is critical.
                    e.View = CameraViewMatrix;
                    e.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1f, 1000f);
                }

                Mesh.Draw();
            }

            base.Draw(gameTime);
        }
        //==========================================================================================================

    }
}
      AsteroidFieldGameComponent.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace SpaceSkyBox
{
    public class AsteroidFieldGameComponent : Microsoft.Xna.Framework.DrawableGameComponent //Changed after adding a standard game component to the project to make it drawable.
    //==========================================================================================================
    //  AsteroidFieldGameComponent
    //
    //  Purpose: To draw an asteroid field.
    //
    //  Notes:
    //      An interesting thing is that when you have no other objects around, you can't tell if an object is
    //  moving or what size it is. Even with a skybox in the scene you still have the same problem except that
    //  you can then, at least, see rotations. But the skybox moves with the camera; so lateral movement still
    //  cannot be detected.
    //
    //      I created this asteroid field to have objects in the scene with the ship so that you could actually 
    //  see the ship move. I created this drawable game component in order to manage the asteroid field.
    //
    //==========================================================================================================
    {
        private Model Asteroid; //We use a single model for all of the asteroids.
        private List<Matrix> AsteroidField; //We use a list to manage all of the asteroids.
        private Matrix ViewMatrix;  //The camera (view matrix) is external to this component, and so we have to provide a way to get that data in here before drawing.
        private Matrix ProjectionMatrix;    

        const int NumberOfAsteroidsInField = 2000;  //Set the number of asteroids you want in the field.
        const float FieldWidth = 8000f; //The asteroids are randomly distributed in a cubical field of this width.

        
        public AsteroidFieldGameComponent(Game game) : base(game)
        //==========================================================================================================
        //  Constructor
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      
        //
        //==========================================================================================================
        {
 
        }
        //==========================================================================================================


        public Matrix View  //Provide a way to import the view matrix since it is externally managed but needed for drawing.
        {
            set { ViewMatrix = value; }
        }


        public override void Initialize()
        //==========================================================================================================
        //  Initialize()
        //
        //  Purpose: To do anything at startup that is specific to this game component.
        //
        //  Parameters:
        //      
        //
        //  Notes:
        //      
        //
        //==========================================================================================================
        {
            Random RandomObject = new Random(); //Create a random number generator.
            Matrix SingleAsteroidsWorldMatrix;  //Used to position asteroids.

            AsteroidField = new List<Matrix>(NumberOfAsteroidsInField); //Create a list to store the asteroid data in.
            
            for (int Index = 0; Index < NumberOfAsteroidsInField; Index++)  //Create the given number of asteroids.
            {
                //Set asteroid to random orientation, size, and position
                SingleAsteroidsWorldMatrix = Matrix.CreateRotationX((float)RandomObject.NextDouble() * MathHelper.Pi * 2f);
                SingleAsteroidsWorldMatrix *= Matrix.CreateRotationY((float)RandomObject.NextDouble() * MathHelper.Pi * 2f);
                SingleAsteroidsWorldMatrix *= Matrix.CreateRotationZ((float)RandomObject.NextDouble() * MathHelper.Pi * 2f);
                SingleAsteroidsWorldMatrix *= Matrix.CreateScale((float) RandomObject.NextDouble() * 100); //Randomize Asteroid size.
                SingleAsteroidsWorldMatrix *= Matrix.CreateTranslation(new Vector3(((float)RandomObject.NextDouble() * FieldWidth) - (FieldWidth / 2), ((float)RandomObject.NextDouble() * FieldWidth) - (FieldWidth / 2), ((float)RandomObject.NextDouble() * FieldWidth) - (FieldWidth / 2)));

                AsteroidField.Add(SingleAsteroidsWorldMatrix);
            }

            //Create our camera's projection matrix for drawing just the asteroids. I just set the far clipping plane to a distance that's certainly large enough to draw the whole field.
            ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Game.GraphicsDevice.Viewport.AspectRatio, 1f, FieldWidth * 4);
 
            base.Initialize();
        }
        //==========================================================================================================


        protected override void LoadContent()
        //==========================================================================================================
        //  LoadContent()
        //
        //  Purpose: To load the asteroid model that was created in Blender.
        //
        //  Parameters: None.
        //      
        //
        //  Notes:
        //      This uses Game.Content.Load<> instead of Content.Load<> because this is a game component. For drawable
        //  game components like this you will probably even have to create this LoadContent() method override yourself
        //  manually as well as the other methods.
        //
        //==========================================================================================================
        {
            Asteroid = Game.Content.Load<Model>("AsteroidOne");

            base.LoadContent();
        }
        //==========================================================================================================


        public override void Update(GameTime gameTime)
        //==========================================================================================================
        //  Update()
        //
        //  Purpose: Not needed because the asteroids don't change.
        //
        //  Parameters:
        //      gameTime - XNA standard.
        //
        //  Notes:
        //      You could modify this to make the asteroids rotate in place, but that might be pretty processor
        //  intensive to go through the list of asteroids every frame and update them.
        //
        //==========================================================================================================
        {
            base.Update(gameTime);
        }
        //==========================================================================================================


        public override void Draw(GameTime gameTime)
        //==========================================================================================================
        //  Draw()
        //
        //  Purpose: To draw the asteroids.
        //
        //  Parameters:
        //      gameTime - XNA standard.
        //
        //  Notes:
        //      Iterates through the entire list of asteroids and draws them with their correct size, position, and
        //  orientation/rotation.
        //
        //==========================================================================================================
        {
            foreach (Matrix AsteroidMatrix in AsteroidField)
            {
                DrawAsteroid(AsteroidMatrix);
            }
            
            base.Draw(gameTime);
        }
        //==========================================================================================================


        private void DrawAsteroid(Matrix WorldMatrix)
        //==========================================================================================================
        //  DrawAsteroid()
        //
        //  Purpose: To draw an asteroid and to encapsulate some very repetitive code.
        //
        //  Parameters:
        //      WorldMatrix - the world matrix of the asteroid, which contains it's position, scale, and orientation.
        //
        //  Notes:
        //      I mostly tried to duplicate the lighting for everything in the scene.
        //
        //==========================================================================================================
        {
            foreach (ModelMesh Mesh in Asteroid.Meshes)
            {
                foreach (BasicEffect e in Mesh.Effects)
                {
                    e.EnableDefaultLighting();
                    e.AmbientLightColor = Color.DarkSlateBlue.ToVector3();
                    e.DiffuseColor = Color.SlateGray.ToVector3();
                    e.PreferPerPixelLighting = true;
                    e.TextureEnabled = true;    //These asteroids are textured.
                    e.LightingEnabled = true;
                    e.FogEnabled = true;    //Not sure if fog is helpful or not.
                    e.FogColor = Color.DarkSlateBlue.ToVector3() * 0.1f;
                    e.FogStart = 4200f;
                    e.FogEnd = 10000f;

                    e.World = WorldMatrix;
                    e.View = ViewMatrix;
                    e.Projection = ProjectionMatrix;
                }
                Mesh.Draw();
            }

        }
        //==========================================================================================================

    }
}

 

 

 







Summary...

Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla tempor libero leo, nec condimentum massa. Sed elementum nisi in velit lobortis varius. Mauris pulvinar ullamcorper metus eget rhoncus. Curabitur venenatis dui eu quam bibendum lobortis.

Source Code





Tutorials

The Holodeck

Subsites

Blog

Files


Future Use