I've been around for quite a long time reading stuff and asking a couple of questions and since I started really digging into Xen to develop my hobby game, I thought I could give a hand and share a few code to help some other people around.
It's nothing really big but for my busy brain, it still took me a while to get it done right :p
So here it goes. My goal here was to create a starfield composed of a randomized set of stars and a nebula stored in a Cubemap.
All the required code is contained in two files: a Starfield class and a Nebula shader.
We'll start by the Nebula shader that only takes care of rendering a Cubemap in a Sphere.
uniform extern float4x4 ViewMatrix : VIEW;
uniform extern float4x4 ProjectionMatrix : PROJECTION;
void NebulaeVertexShader( float3 pos : POSITION0,
out float4 NebulaePos : POSITION0,
out float3 NebulaeCoord : TEXCOORD0 )
// Calculate rotation. Using a float3 result, so translation is ignored
float3 rotatedPosition = mul(pos, ViewMatrix);
// Calculate projection, moving all vertices to the far clip plane
// (w and z both 1.0)
NebulaePos = mul(float4(rotatedPosition, 1), ProjectionMatrix).xyww;
NebulaeCoord = pos;
uniform extern texture NebulaeTexture;
sampler NebulaeS = sampler_state
Texture = ;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
float4 NebulaePixelShader( float3 NebulaeCoord : TEXCOORD0 ) : COLOR
// grab the pixel color value from the skybox cube map
return texCUBE(NebulaeS, NebulaeCoord);
VertexShader = compile vs_2_0 NebulaeVertexShader();
PixelShader = compile ps_2_0 NebulaePixelShader();
The great thing with Xen is that you don't have to do anything in the code to make that work except creating a Sphere and loading the right resource as Xen takes care of putting the right values in the Vertex and Pixel methods ;)
And now the Starfield class.
First, I setup some using statements that will become useful:
// This last one is where the Xen Shader tool created and compiled the above shader.
The Starfield class implements 2 interfaces provided by Xen: IDraw for rendering calls support and IContenOwner for dynamic content loading support.
public class Starfield : IDraw, IContentOwner
First, I add a constant to define the number of stars to create and render.
/// Defines the maximum number of stars used in the Starfield generation.
private const int NUMBER_OF_STARS = 10000;
I then add a set of private members to store the Geometry used by the stars a generic collection of Vertices kindly provided by Xen, a Sphere for the Cubemap rendering and the shaders: MaterialShader from the Xen.Ex library for stars and our newly created
private IVertices p_SmallStarVertices;
private MaterialShader p_SmallStarsMaterial;
private Sphere p_NebulaSphere;
private NebulaeTechnique p_NebulaShader;
Now, all the initialization code.
public Starfield(ContentRegister contentRegister)
// The ContentRegister class is the class in Xen that allows you to simply get your class LoadContent and UnloadContent called whenever it needs to be done.
if (contentRegister == null)
throw new ArgumentNullException();
// The starfield material shader.
// We simply create a Xen MaterialShader instance...
p_SmallStarsMaterial = new MaterialShader();
// ... then create a new MaterialLightCollection...
p_SmallStarsMaterial.Lights = new MaterialLightCollection();
// ... which we setup the way we want.
p_SmallStarsMaterial.Lights.AmbientLightColour = Color.White.ToVector3();
p_SmallStarsMaterial.TextureMapSampler = TextureSamplerState.AnisotropicHighFiltering;
// This one is important as it will allow Xen to pass the Color you passed in the MaterialShader to the Vertex method.
p_SmallStarsMaterial.UseVertexColour = true;
// We generate stars (I'll come to this method later)
// The Nebula cubemap shader.
// We create a new instance of our Nebula class generated automatically by the Xen shader tool in Visual Studio
p_NebulaShader = new NebulaeTechnique();
// The Nebula sphere we will use to render the cubemap. The Sphere is provided by Xen.Ex library too.
p_NebulaSphere = new Sphere(new Vector3(5f), 32);
// And finally we tell Xen to add this class instance to the list of instances to get their LoadContent method call.
Until here, we haven't done anything really tedious. But now, we'll get into some maths.
Remember, I wanted to create a set of stars directly using Vertexes which means that I need to get all of them positioned in a sphere and that implies some coordinates that I need to calculate from the center of a sphere and uniformously distribute.
In order to achieve this, all you really need to do is randomize the two angles that compose any point distributed on a sphere (you could see these angles as the Latitude and Longitude coordinates on our Earth somehow).
private void GenerateSmallStars()
// We'll need some randomisation so I create a simple Random class instance from the .Net framework.
Random rand = new Random();
// I also create an array of the Xna VertexPositionColor class that will give me the ability to define a Vertex based on its position in 3d space and the associated color.
VertexPositionColor verts = new VertexPositionColor[NUMBER_OF_STARS];
// Now I loop through the number of stars I need to generate.
for (int i = 0; i < NUMBER_OF_STARS; i++)
// x, y, z for the final coordinates of the vertex.
// w and t are used for the angles.
double x, y, z, w, t;
// And now the Maths. I won't get into these for now but believe me: it makes the job ;)
z = 2.0 * rand.NextDouble() - 1.0;
t = 2.0 * MathHelper.Pi * rand.NextDouble();
w = Math.Sqrt(1 - z * z);
x = w * Math.Cos(t);
y = w * Math.Sin(t);
// I also define a random float to create the Color I'll use for the Vertex. I only need one as I want to get grayscaled stars.
float color = (float)rand.NextDouble();
// And finally, I add to my array of Vertexes a new one with the position and given color.
// You probably noticed that I multiply all x, y and z by 100000; that's because I didn't get another way (yet) to manage my scene sorting (I get all Vertexes rendered in front of all other meshes otherwise).
verts[i] = new VertexPositionColor(new Vector3((float)x * 100000, (float)y * 100000, (float)z * 100000), new Color(color, color, color, 1.0f));
// And the magic of Xen in action: by using the simple Vertices<T> generic class, I just create my own set of Vertices from my array.
p_SmallStarVertices = new Vertices<VertexPositionColor>(verts);
I'll go now to the easiest part of the code which needs no explanations if you know about Xna:
public void LoadContent(ContentRegister content, DrawState state, Microsoft.Xna.Framework.Content.ContentManager manager)
p_NebulaShader.NebulaeTexture = manager.Load<TextureCube>("nebula");
public void UnloadContent(ContentRegister content, DrawState state)
And finally, the rendering code:
public void Draw(DrawState state)
// Retrieves the camera position and forces the rendering to occur whatever the real game position is.
// Using Xen DrawState instance, I store the current RenderState so that I can reset back to it after my nebula rendering.
// I set the Cullmode to None and DepthWriteEnabled to false so that it doesn't occlude anything on my scene and I don't care about the Sphere normals.
state.RenderState.DepthColourCull.CullMode = CullMode.None;
state.RenderState.DepthColourCull.DepthWriteEnabled = false;
// We then simply bind the Cubemap shader to the current state and call the Sphere Draw method.
// I reset the RenderState.
// I also have to do some RenderState management with my Starfield rendering so that it blends correctly with the nebula.
// And once again, the magic of Xen in action: simply bind the MaterialShader and call the Vertices Draw method. I don't need any indices and I simple set it to use PointList.
p_SmallStarVertices.Draw(state, null, PrimitiveType.PointList);
// I don't need to cull anything here so I always return true
public bool CullTest(ICuller culler)
And you get the end result something similar to this: