Matrices

Saturday, April 07, 2012

12:37 PM

Applied Order

Matrix multiplication is right to left (i.e. the right most matrix is applied to the model first). So typically the 'do everything in one go' matrix we generate for a model will be doEverything = scaling * rotation * transformation

Well Known Matrixes

·         View Matrix
Transforms world space into view space. The world as seen by a camera. Matrix.CreateLookAt(cameraPostionXYZ, subjectPositionXYZ, up) create a view matrix with the camera at cameraPositionXYZ pointed to something interesting at subjectPositionXYZ. up controls the rotation of the camera around the line joining the two.

·         Projection Matrix
Transforms 3D space into 2D space Matrix.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance) Only Items between the near plane and the far plan are rendered. A typical field of view is 45-60 degrees. 180 = fish eye lens.   The enclosed area between the near plane and far plane is known as the Frustum (and is very useful for clipping) A good default projection is matrix is Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), GraphicsDevice.Viewport.AspectRatio, 0.1f, 10000.0f); A bounding frustrum can be created from the view and projection matrixes: new BoundingFrustum(viewMatrix * projectMatrix);

·         World Matrix
Transforms a local object to a world space. Used to place models in the world space. This is typically the last matrix applied to the model.

Helpers

·         Matrix m = Matrix.CreateFromYawPitchRoll(yaw, pitch, row)
Creates a matrix that applies a rotation

·         Vector3 v = Vector3.Transform(vector, rotation)
Applies a rotation to a vector.

·         Vector3.Up, .XUnit, YUnit, Zunit

·         Vector3 v = vector.Normalize()
Creates a vector with the same orientation as the original, but with a length of 1.

·         Angle between two vectors (say the direction the playing is facing (f) and the direction to the of monster (m))

a.       The dot product (f.m) is |F||Q|cos(angle), so

b.      Normalize all vectors (so |F| and |Q| are one)

c.       double angle = Vector3.dot(f,q);

Content

Saturday, April 07, 2012

12:44 PM

Overview

Models (and other assets) are added to the Content project rather than the runtime project. The Content project takes care of converting the various assets into common XNA format. The content project is about conversion ??and is a build time thing rather than run-time??

So good we reference it twice

Content dependencies (e.g. textures for models) are automatically detected. Adding the texture to Content directly will cause the file to be included twice.

At runtime the Content assets are exposed via the ContentManager class. In simple games (where all assets are simply loaded at start up)  the programmer can simply load each asset individual in their override of Game::LoadContent(). When the model is loaded, a copy is usually take of the model's bones so that they can be manipulated later.

Model model;

Matrix[] transforms;

/// <summary>LoadContent will be called once per game and is the place to load

/// all of your content.</summary>

{

// …

// TODO: use this.Content to load your game content here

// The mesh

// Make a copy of where the bones of the model are

Matrix[] transforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);
}

Common types for Content.Load<T> are Model, Effect, TODO

By default, the loader assigns the BasicEffect shader to the model's mesh parts.

Minimum to Display a Model

In addition to the snippet above:

/// <summary>/// This is called when the game should draw itself.</summary>

/// <param name="gameTime">Provides a snapshot of timing values.</param>

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(
Color.CornflowerBlue);

float ang45 = (floatMath.PI / 4.0f;

Matrix view = Matrix.CreateLookAt(new Vector3(333, 333, 1000), new Vector3(0, 50, 0),

Vector3.Up);

Matrix projection = Matrix.CreatePerspectiveFieldOfView(ang45,
GraphicsDevice.Viewport.AspectRatio, 0.1f, 10000.0f);

Matrix world = Matrix.CreateScale(0.5f) * Matrix.CreateRotationY(ang45);

foreach (ModelMesh mesh in model.Meshes)
{

foreach (ModelMeshPart part in mesh.MeshParts)
{

BasicEffect e = (BasicEffect)part.Effect;
e.EnableDefaultLighting();
e.View = view;
e.Projection = projection;

// Matrix math go right to left, so apply the world transform, then

// the mesh's relative-to-the-other-meshes-model-transform
e.World = transforms[mesh.ParentBone.Index] * world; ;
}
mesh.Draw();
}

base.Draw(gameTime);
}

Cameras

Saturday, April 07, 2012

2:05 PM

Target Camera

Should be trival: Matrix.CreateLookAt(c=camera, s=subject, u=Vector3.Up), but...

When the vector (v) representing the line from camera (c) to subject (s) is exactly the same as the camera's up direction (u), XNA can't calculate a plane from which to 'up' should apply.

·         If your camera flips over when it crosses an axis or nothing renders when you exactly align to an axis, it is likely this problem is the cause.

·         When we use (for example) u=(0,1,0) for the third parameter, what we're really saying is 'the final up vector must have a positive Y'.

The work around for this is to calculate 'up' as being perpendicular to v (imaging a plane in 3d space defined by c & s. u would be up from that).

The cross product of two vectors is a new vector that is perpendicular to those vectors*. This can be used to calculate the Up vector for the camera.

Vector3 subjectPosition, cameraPosition;

// Calculate the vector from camera to subject

Vector3 forward = subjectPosition - cameraPosition;

// Ensure the camera's up is up

Vector3 side = Vector3.Cross(forward, Vector3.up);

Vector3 cameraUp = Vector3.Cross(forward, side);

Matrix view = Matrix.CreateLookAt(camera, subject, cameraUp)

[*Since two vectors fulfill the requirement (one pointing 'up' the other pointing 'down') which one the cross product returns depends on whether you are using left or right handiness. XMA is right handed (-Z goes into the screen). Interestingly Direct3D is right handed.]

Over the Shoulder, Chase, Arc Cameras

These are created by applying a relative offset to the model and applying the models transformation to the camera as well. However, when following (for example) a banking plane it is often desired that the camera bank as well.

Collision Detection & Clipping

Saturday, April 07, 2012

2:39 PM

Bounding Sphere

Quickest way to check for collision. Also doesn't need rotation :-)

Models have built in bounding spheres (model.Meshes.BoundingSphere), which can be added together to create one big sphere for the whole model:

BoundingSphere sphere = new BoundingSphere(Vector3.Zero, 0);

foreach(ModelMesh mesh in model.Meshes) {

sphere = BoundingShere.CreateMerged(sphere, mesh.BoundingSphere.Transform(transforms[mesh.ParentBone.Index]);

}

[Note that if the model is animated, a sphere based on the original bone positions may not be appropriate]

Bounding Frustrum

A bounding frustrum can be created from the view and projection matrixes:

new BoundingFrustum(viewMatrix * projectMatrix);

Bounding Tests

instanceOfBoundingType1.Contains(instanceOfBoundingType2) == ContainmentType.[Contains|Disjoint|Intersects]

 ContainmentType Meaning Disjoint No overlap Contains Completely contains (?? But which is the bigger ??) Intersects Partial overlap

Bones

Saturday, April 07, 2012

3:25 PM

Animation

Model model = …

Model.Bones["boneName"].Transform = ...

Controller IO

Saturday, April 07, 2012

4:17 PM

Keyboard

KeyboardState k = Keyboard.GetState();

If (keyState.IsKeyDown(Keys.W)) {…

Tuesday, April 10, 2012

8:29 PM

BasicEffect

Each ModelMeshPart can have its own shader. By default, the content pipeline assigns a new instance of BasicEffect shader to each part.

Useful information loaded by the pipeline can be extracted via the shader:

foreach (ModelMesh mesh in model.Meshes) {

foreach(ModelMeshPart part in mesh) {

(BasicEffect) part.Effect ->

 DiffuseColor RGB color that is applied if the part has no texture ?? May tint texture if has texture? ?? SpecularPower Texture

Custom Effects

Custom effect classes are generated via .fx files added to the Content project (Content project -> Add new -> Effect File), loaded through Content.Load<Effect>("myEffect"), and applied through assign the effect (or more likely a .Clone() of the affect) to each model.Meshes[].MeshParts[].Effect.

See subpages for example code.

Ambient Lighting

Applying a float3 coefficient to the return value returned PixelShaderFunction provides ambient lighting that illuminates the model evenly. The magnitude of the coefficient represents the intensity of the ambient lighting.

Point Lighting

Point lighting (such as a light bulb) is just ambient lighting whose coefficient is reduced by the distance between the light source and the model. Curved drop off (i.e. 1/distance) works better than straight distance.

Directional (Lambertian) Lighting

A face (triangle) in the model that is flat on to a light source should reflect more light (i.e. appear brighter) than a face that is at an angle to the light source. We can use the dot product to calculate the angle between a normal to the face (i.e. which way the face is pointing) and a vector drawn from the face to the light source. The closer the angle is to zero, the brighter (in relative terms) that face should be.

Dot product is fine here since we don't care only about the magnitude of the angle and not which direction the angle is in.  The math is pretty straightforward, but expressing it in the effects language requires some magic I'm too lazy to repeat / reinvent here.

A coefficient applied the returned brightness can be used to simulate how 'shiny' the object is, but this works much better with Phong shading.

Spot Light

Lambertian lighting that has a cut off point for the angle.

Shiny Lighting (Phong Shading aka Phong Specular Highlighting)

Makes bright spots on (say) a kettle. Similar in theory to Lambertian lighting except that brightness is determined by the angle between the reflected light and the camera rather than between the light source and the model.

Since at the triangle level we are flat, calculating the vector of the reflected light is simple a case of calculating (as before) the angle between the face and the light source, then applying the old truism that the angle of incidence is equal to the angle of reflection. The dot product trick can then be applied to this vector and one drawn from the face to the observer and again, the closer to zero the angle is the brighter the face should be drawn.

As mentioned above, a coefficient can be applied to make the surface appear more shiny or dull.

Prelighting

A way of having many light sources cheaply. Logic makes my head hurt, so at this point I recommend using a pre-rolled shader. This is where depth and normal maps come in.

SimpleEffect.cs

Tuesday, April 10, 2012

9:59 PM

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Minimal
{

/// <summary>This is the main type for your game</summary>

public class Game1 : Microsoft.Xna.Framework.Game
{

private GraphicsDeviceManager graphics;

private SpriteBatch spriteBatch;

private Model model;

public Game1()
{
graphics =
new GraphicsDeviceManager(this);
Content.RootDirectory =
"Content";
}

/// <summary>

/// Allows the game to perform any initialization it needs to before starting to run.

/// This is where it can query for any required services and load any non-graphic

/// related content.  Calling base.Initialize will enumerate through any components

/// and initialize them as well.

/// </summary>

protected override void Initialize()
{

// TODO: Add your initialization logic here

base.Initialize();
}

/// <summary>LoadContent will be called once per game and is the place to load all of your content.</summary>

{

// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch =
new SpriteBatch(GraphicsDevice);

// TODO: use this.Content to load your game content here

// Apply custom effect

foreach (ModelMesh mesh in this.model.Meshes)
{

foreach (ModelMeshPart part in mesh.MeshParts)
{

Effect effect = simpleEffect.Clone();

Texture meshPartTexture = ((BasicEffect)part.Effect).Texture;
effect.Parameters[
"MyTexture"].SetValue(meshPartTexture);
part.Effect = effect;
}
}
}

/// <summary>UnloadContent will be called once per game and is the place to unload all content.</summary>

{

// TODO: Unload any non ContentManager content here
}

/// <summary>Allows the game to run logic such as updating the world, checking for collisions, gathering input, and playing audio.</summary>

/// <param name="gameTime">Provides a snapshot of timing values.</param>

protected override void Update(GameTime gameTime)
{

// Allows the game to exit

this.Exit();

// TODO: Add your update logic here

base.Update(gameTime);
}

/// <summary>This is called when the game should draw itself.</summary>

/// <param name="gameTime">Provides a snapshot of timing values.</param>

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(
Color.CornflowerBlue);

float ang45 = (float)Math.PI / 4.0f;

Matrix view = Matrix.CreateLookAt(new Vector3(333, 333, 1000), new Vector3(0, 50, 0), Vector3.Up);

Matrix projection = Matrix.CreatePerspectiveFieldOfView(ang45, GraphicsDevice.Viewport.AspectRatio, 0.1f, 10000.0f);

Matrix world = Matrix.CreateScale(0.5f) * Matrix.CreateRotationY(ang45);

foreach (ModelMesh mesh in model.Meshes)
{

foreach (ModelMeshPart part in mesh.MeshParts)
{
part.Effect.Parameters[
"View"].SetValue(view);
part.Effect.Parameters[
"Projection"].SetValue(projection);
part.Effect.Parameters[
"World"].SetValue(world);
}
mesh.Draw();
}

base.Draw(gameTime);
}
}
}

SimpleEffect.fx

Tuesday, April 10, 2012

10:01 PM

// SimpleEffect.fx - Apply a red tinge to the model's textures

// Properties are exposed at run time through model.Meshes[].MeshParts[].Effect.Parameters[name]
// These three are standard
float4x4 World;                        // World Matrix public property
float4x4 View;                        // View Matrix public property
float4x4 Projection;        // Projection Matrix public property

// My custom texture
texture MyTexture;                // MyTexture public property

sampler MyTextureSampler = sampler_state {
texture = <MyTexture>;

// This class has additional properties that can be set for better (and more expensive)

// pixel sampling options such as anisotropic filtering and mip-mapping.

};

{
// This is standard
float4 Position : POSITION0;

// TODO: add input channels such as texture
// coordinates and vertex colors here.
float2 UV : TEXCOORD0;
};

{
// This is standard
float4 Position : POSITION0;

// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
float2 UV : TEXCOORD0;
};

{

// This is standard

float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);

// Passthrough
output.UV = input.UV;

return output;
}

{
// Make the entire image grey
// return float4(.5, .5, .5, 1);

// Dim the green & blue channels, leaving red as is
float3 output = tex2D(MyTextureSampler, input.UV) * float3(1, 0.3, 0.3);
return float4(output, 1);
}

technique Technique1
{
pass Pass1
{
}
}

Definitions

Saturday, April 07, 2012

12:33 PM

Axis

 Axis -ve +ve X Left Right Y Down Up Z In Out

HLSL

ModelMeshPart

A piece of a mesh. Each mesh part can have its own shader (for example, shiny metal verses dull skin).

Mesh

A piece of a model. A mesh can be attached to 0 or 1 bones. When the bone is manipulated, the mesh moves with it.

Model

A model is made up of one or more meshes. Meshes can have transformations of their own relative to the model, allowing (for example) a tank turret to rotate. For meshes to be manipulated this way, they require bones. The collection of bones for all the meshes in a model is called the skeleton.

Quaternion

A matrix storing only a rotation.

Rotation

·         Pitch
Rotation around the X-Axis

·         Yaw
Rotation around the Y-Axis

·         Roll
Rotation around the Z-Axis