http://stage6.divx.com/user/graphicdna/video/1403012/Simax-DS--Practica-con-ABS---ABS-Braking-practice
you can find the latest Simax Project video. An exercise practicing braking with and without Anti-lock Braking System.
cheers!
Take a look at the newest Simax Project video. It shows a high speed ride with the Porsche 911 Carrera through a highway, closed to traffic.
http://stage6.divx.com/user/graphicdna/video/1351013/Simax-DS--Porsche-911-highway-ride--HD
More info at: www.simax.esFinally, I also have to thank Daniel Romano, Carlos Ibarra and Fernando Lacunza for their help with the shipment to the CodeCamp. It was hard, but you made it... Thanks !!
Thanks a lot to everyone !!!!!
[Please NOTE: This article is OBSOLETE. It has been re-written and completed in this newer posts: part 1 and part 2]
Put in the Mesh class all the info wee need
Very much like we did in the Custom Content Processing post, we are going to use the “Tag” property of a mesh to store what we want, which in this case is something like this:
public class MeshData
{
public VertexPositionNormalTexture[] Vertices;
public int[] Indices;
public Vector3[] FaceNormals;
public MeshData(VertexPositionNormalTexture[] Vertices,
int[] Indices,
Vector3[] pFaceNormals)
{
this.Vertices = Vertices;
this.Indices = Indices;
this.FaceNormals = pFaceNormals;
}
}
[ContentTypeWriter]
public class ModelVertexDataWriter : ContentTypeWriter<MeshData>
{
protected override void Write(
ContentWriter output, MeshData value)
{
output.Write((int)value.Vertices.Length);
for (int x = 0; x < value.Vertices.Length; x++)
{
output.Write(value.Vertices[x].Position);
output.Write(value.Vertices[x].Normal);
output.Write(value.Vertices[x].TextureCoordinate);
}
output.Write(value.Indices.Length);
for (int x = 0; x < value.Indices.Length; x++)
output.Write(value.Indices[x]);
output.Write(value.FaceNormals.Length);
for (int x = 0; x < value.FaceNormals.Length; x++)
output.Write(value.FaceNormals[x]);
}
public override string GetRuntimeType(
TargetPlatform targetPlatform)
{
return typeof(MeshData).AssemblyQualifiedName;
}
public override string GetRuntimeReader(
TargetPlatform targetPlatform)
{
return "ContentProcessors.ModelVertexDataReader, ContentProcessors, Version=1.0.0.0, Culture=neutral";
}
}
public class ModelVertexDataReader : ContentTypeReader<MeshData>
{
protected override MeshData Read(
ContentReader input, MeshData existingInstance)
{
int i;
i = input.ReadInt32();
VertexPositionNormalTexture[] vb = new VertexPositionNormalTexture[i];
for (int x = 0; x < i; x++)
{
vb[x].Position = input.ReadVector3();
vb[x].Normal = input.ReadVector3();
vb[x].TextureCoordinate = input.ReadVector2();
}
i = input.ReadInt32();
int[] ib = new int[i];
for (int x = 0; x < i; x++)
ib[x] = input.ReadInt32();
i = input.ReadInt32();
Vector3[] normals = new Vector3[i];
for (int x = 0; x < i; x++)
normals[x] = input.ReadVector3();
return new MeshData(vb, ib, normals);
}
}
Finally, our Custom Content Processor that fills up the MeshData objects for each model goes through it:
Note: some parts taken from ZiggyWare:
http://www.ziggyware.com/readarticle.php?article_id=74
[ContentProcessor(DisplayName = "Custom Mesh Processor")]
public class PositionNormalTexture : ModelProcessor
{
public override ModelContent Process(
NodeContent input, ContentProcessorContext context)
{
ModelContent model = base.Process(input, context);
foreach (ModelMeshContent mesh in model.Meshes)
{
// Put the data in the tag.
VertexPositionNormalTexture[] vb;
MemoryStream ms =
new MemoryStream(mesh.VertexBuffer.VertexData);
BinaryReader reader = new BinaryReader(ms);
VertexElement[] elems = mesh.MeshParts[0].GetVertexDeclaration();
int num = mesh.VertexBuffer.VertexData.Length /
VertexDeclaration.GetVertexStrideSize(elems, 0);
vb = new VertexPositionNormalTexture[num];
for (int i = 0; i < num; i++)
{
foreach (VertexElement e in elems)
{
switch (e.VertexElementUsage)
{
case VertexElementUsage.Position:
{
vb[i].Position.X =
reader.ReadSingle();
vb[i].Position.Y =
reader.ReadSingle();
vb[i].Position.Z =
reader.ReadSingle();
}
break;
case VertexElementUsage.Normal:
{
vb[i].Normal.X =
reader.ReadSingle();
vb[i].Normal.Y =
reader.ReadSingle();
vb[i].Normal.Z =
reader.ReadSingle();
}
break;
case
VertexElementUsage.TextureCoordinate:
{
if (e.UsageIndex != 0)
continue;
vb[i].TextureCoordinate.X =
reader.ReadSingle();
vb[i].TextureCoordinate.Y =
reader.ReadSingle();
}
break;
default:
{
Console.WriteLine(e.VertexElementFormat.ToString());
switch (e.VertexElementFormat)
{
case VertexElementFormat.Color:
{
reader.ReadUInt32();
}
break;
case VertexElementFormat.Vector3:
{
reader.ReadSingle();
reader.ReadSingle();
reader.ReadSingle();
}
break;
case VertexElementFormat.Vector2:
{
reader.ReadSingle();
reader.ReadSingle();
}
break;
}
}
break;
}
}
} // for i < num
reader.Close();
int[] ib = new int[mesh.IndexBuffer.Count];
mesh.IndexBuffer.CopyTo(ib, 0);
Vector3[] normals = new Vector3[mesh.IndexBuffer.Count / 3];
for (int i = 0, conta = 0; i < mesh.IndexBuffer.Count; i += 3, conta++)
{
Vector3 v0 = vb[mesh.IndexBuffer[i]].Position;
Vector3 v1 = vb[mesh.IndexBuffer[i+1]].Position;
Vector3 v2 = vb[mesh.IndexBuffer[i+2]].Position;
Vector3 edge1 = v1 - v0;
Vector3 edge2 = v2 - v0;
Vector3 normal = Vector3.Cross(edge1, edge2);
normal.Normalize();
normals[conta] = normal;
}
mesh.Tag = new MeshData(vb, ib, normals);
} // foreach mesh
return model;
}
}
In the next chapter will focus on the Collision Detection implementation using all this info. Cheers !
[Please NOTE: This article is OBSOLETE. It has been re-written and completed in this newer posts: part 1 and part 2]
Accurate collision detection
( I assume here that you´ve read my post about Custom Content Processing: http://graphicdna.blogspot.com/2007/02/xna-customizing-content-processing.html )
A more accurate collision model is sometimes needed. The best is to develop a library of methods to test between meshes and rays, spheres, boxes, etc. How we do that?
Probably, you already incluye in your engine a system memory copy of your geometry. The problem is that there´s no direct access to content created with the WriteOnly flag in XNA, so you cannot create that sysmem copy at load time.
The solution is to make a custom content processor that stores that copy of the geometry at build time, where there´s still access to it. We made a simple example of something similar in the post mentioned above, but now we need more...
In the next post, I´ll show how to create a Custom Content Processor designed to store all the info needed for collision detection.
Cheers !
[Please NOTE: This article is OBSOLETE. It has been re-written and completed in this newer posts: part 1 and part 2]
Preface:
If you want to see an introductory post to Collision Detection, check out this one: http://graphicdna.blogspot.com/2007/02/3d-intersection-concepts-and.html
XNA collision detection
In D3D there´s a method called Mesh.Intersect that performs a Mesh-Ray intersection test. Many people thinks this method does some kind of optimized "magic" to test for intersection, but in fact it just loops throught all the triangles of the mesh doing a triangle-ray intersect, keeping track of the closest collision point. In XNA, there´s not such a method, and we will have to do it on our own. To do so, we will also have to deal with Custom Content Processing.
Simple Collision Detection
Before we go into a Mesh.Intersect() method, it´s a good idea to point out that XNA does include simple intersection tests for simplification shapes like: Bounding Spheres, AABB (Axis Aligned Bound Box), Planes, Rays, and any combination of them.
Using those tests, almost any kind of game-like intersection can be achieved. You must remember that a Mesh-Whatever intersection is expensive (depending in the number of polygons, of course), and should be left for special cases in which a very high intersection accuracy is needed. So, its usually preferred to aproximate a complex geometry by a bunch of spheres or boxes, than using the real triangles.
There´s a very good post at Sharky´s blog about XNA collisions, specially focused in approximating generic shapes with bounding spheres.
You can find it here: http://sharky.bluecog.co.nz/?p=119
Will continue tomorrow.
Cheers !