How do I implement SkyBox in xna 4.0 Reach Profile (for Windows Phone 7)?
- by Biny
I'm trying to Implement SkyBox in my phone game. Most of the samples in the web are for HiDef profile, and they are using custom effects (that not supported on Windows Phone). I've tried to follow this guide. But for some reason my SkyBox is not rendered.
This is my SkyBox class:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Rocuna.Core;
using Rocuna.GameEngine.Graphics;
using Rocuna.GameEngine.Graphics.Components;
namespace Rocuna.GameEngine.Extension.WP7.Graphics
{
/// <summary>
/// Sky box element for phone games.
/// </summary>
public class SkyBox : SkyBoxBase
{
/// <summary>
/// Initializes a new instance of the <see cref="SkyBoxBase"/> class.
/// </summary>
/// <param name="game">The Game that the game component should be attached to.</param>
public SkyBox(TextureCube cube, Game game)
: base(game)
{
Cube = cube;
CubeFaces = new Texture2D[6];
PositionOffset = new Vector3(20, 20, 20);
CreateGraphic(512);
StripTexturesFromCube();
InitializeData(Game.GraphicsDevice);
}
#region Properties
/// <summary>
/// Gets or sets the position offset.
/// </summary>
/// <value>
/// The position offset.
/// </value>
public Vector3 PositionOffset { get; set; }
/// <summary>
/// Gets or sets the position.
/// </summary>
/// <value>
/// The position.
/// </value>
public Vector3 Position { get; set; }
/// <summary>
/// Gets or sets the cube.
/// </summary>
/// <value>
/// The cube.
/// </value>
public TextureCube Cube { get; set; }
/// <summary>
/// Gets or sets the pixel array.
/// </summary>
/// <value>
/// The pixel array.
/// </value>
public Color[] PixelArray { get; set; }
/// <summary>
/// Gets or sets the cube faces.
/// </summary>
/// <value>
/// The cube faces.
/// </value>
public Texture2D[] CubeFaces { get; set; }
/// <summary>
/// Gets or sets the vertex buffer.
/// </summary>
/// <value>
/// The vertex buffer.
/// </value>
public VertexBuffer VertexBuffer { get; set; }
/// <summary>
/// Gets or sets the index buffer.
/// </summary>
/// <value>
/// The index buffer.
/// </value>
public IndexBuffer IndexBuffer { get; set; }
/// <summary>
/// Gets or sets the effect.
/// </summary>
/// <value>
/// The effect.
/// </value>
public BasicEffect Effect { get; set; }
#endregion
protected override void LoadContent()
{
}
public override void Update(GameTime gameTime)
{
var camera = Game.GetService<GraphicManager>().CurrentCamera;
this.Position = camera.Position + PositionOffset;
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
DrawOrder = int.MaxValue;
var graphics = Effect.GraphicsDevice;
graphics.DepthStencilState = new DepthStencilState() { DepthBufferEnable = false };
graphics.RasterizerState = new RasterizerState() { CullMode = CullMode.None };
graphics.BlendState = new BlendState();
graphics.SamplerStates[0] = SamplerState.AnisotropicClamp;
graphics.SetVertexBuffer(VertexBuffer);
graphics.Indices = IndexBuffer;
Effect.Texture = CubeFaces[0];
Effect.CurrentTechnique.Passes[0].Apply();
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _vertices.Count, 0, 2);
Effect.Texture = CubeFaces[1];
Effect.CurrentTechnique.Passes[0].Apply();
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _vertices.Count, 6, 2);
Effect.Texture = CubeFaces[2];
Effect.CurrentTechnique.Passes[0].Apply();
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _vertices.Count, 12, 2);
Effect.Texture = CubeFaces[3];
Effect.CurrentTechnique.Passes[0].Apply();
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _vertices.Count, 18, 2);
Effect.Texture = CubeFaces[4];
Effect.CurrentTechnique.Passes[0].Apply();
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _vertices.Count, 24, 2);
Effect.Texture = CubeFaces[5];
Effect.CurrentTechnique.Passes[0].Apply();
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _vertices.Count, 30, 2);
base.Draw(gameTime);
}
#region Fields
private List<VertexPositionNormalTexture> _vertices = new List<VertexPositionNormalTexture>();
private List<ushort> _indices = new List<ushort>();
#endregion
#region Private methods
private void InitializeData(GraphicsDevice graphicsDevice)
{
VertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionNormalTexture), _vertices.Count,
BufferUsage.None);
VertexBuffer.SetData<VertexPositionNormalTexture>(_vertices.ToArray());
// Create an index buffer, and copy our index data into it.
IndexBuffer = new IndexBuffer(graphicsDevice, typeof(ushort),
_indices.Count, BufferUsage.None);
IndexBuffer.SetData<ushort>(_indices.ToArray());
// Create a BasicEffect, which will be used to render the primitive.
Effect = new BasicEffect(graphicsDevice);
Effect.TextureEnabled = true;
Effect.EnableDefaultLighting();
}
private void CreateGraphic(float size)
{
Vector3[] normals = {
Vector3.Right,
Vector3.Left,
Vector3.Up,
Vector3.Down,
Vector3.Backward,
Vector3.Forward,
};
Vector2[] textureCoordinates = {
Vector2.One, Vector2.UnitY, Vector2.Zero, Vector2.UnitX,
Vector2.Zero, Vector2.UnitX, Vector2.One, Vector2.UnitY,
Vector2.Zero, Vector2.UnitX, Vector2.One, Vector2.UnitY,
Vector2.Zero, Vector2.UnitX, Vector2.One, Vector2.UnitY,
Vector2.UnitY, Vector2.Zero, Vector2.UnitX, Vector2.One,
Vector2.UnitY, Vector2.Zero, Vector2.UnitX, Vector2.One,
};
var index = 0;
foreach (var normal in normals)
{
var side1 = new Vector3(normal.Z, normal.X, normal.Y);
var side2 = Vector3.Cross(normal, side1);
AddIndex(CurrentVertex + 0);
AddIndex(CurrentVertex + 1);
AddIndex(CurrentVertex + 2);
AddIndex(CurrentVertex + 0);
AddIndex(CurrentVertex + 2);
AddIndex(CurrentVertex + 3);
AddVertex((normal - side1 - side2) * size / 2, normal, textureCoordinates[index++]);
AddVertex((normal - side1 + side2) * size / 2, normal, textureCoordinates[index++]);
AddVertex((normal + side1 + side2) * size / 2, normal, textureCoordinates[index++]);
AddVertex((normal + side1 - side2) * size / 2, normal, textureCoordinates[index++]);
}
}
protected void StripTexturesFromCube()
{
PixelArray = new Color[Cube.Size * Cube.Size];
for (int s = 0; s < CubeFaces.Length; s++)
{
CubeFaces[s] = new Texture2D(Game.GraphicsDevice, Cube.Size, Cube.Size, false, SurfaceFormat.Color);
switch (s)
{
case 0:
Cube.GetData<Color>(CubeMapFace.PositiveX, PixelArray);
CubeFaces[s].SetData<Color>(PixelArray);
break;
case 1:
Cube.GetData(CubeMapFace.NegativeX, PixelArray);
CubeFaces[s].SetData(PixelArray);
break;
case 2:
Cube.GetData(CubeMapFace.PositiveY, PixelArray);
CubeFaces[s].SetData(PixelArray);
break;
case 3:
Cube.GetData(CubeMapFace.NegativeY, PixelArray);
CubeFaces[s].SetData(PixelArray);
break;
case 4:
Cube.GetData(CubeMapFace.PositiveZ, PixelArray);
CubeFaces[s].SetData(PixelArray);
break;
case 5:
Cube.GetData(CubeMapFace.NegativeZ, PixelArray);
CubeFaces[s].SetData(PixelArray);
break;
}
}
}
protected void AddVertex(Vector3 position, Vector3 normal, Vector2 textureCoordinates)
{
_vertices.Add(new VertexPositionNormalTexture(position, normal, textureCoordinates));
}
protected void AddIndex(int index)
{
if (index > ushort.MaxValue)
throw new ArgumentOutOfRangeException("index");
_indices.Add((ushort)index);
}
protected int CurrentVertex
{
get { return _vertices.Count; }
}
#endregion
}
}