Thursday, 8 March 2007

XNA Collision Detection (Part III). Content Processing (code fixed)

[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;


}


}




When VisualStudio passes every model through our ContentProcessor, it will write the model´s data to an XNB file. When it finds a MeshData object, will search for a writer that is able to serialize it, so we have to write our custom ContentTypeWriter for the MeshData class:



[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";


}


}




In a similar way, when the ContentPipeline tries to read back the XNB file, it will search for a deserializer for the type MeshData, so we have to write our own ContentTypeReader:



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 !




6 comments:

Péter said...

The text is confused. Can you fix it?

Iñaki Ayucar said...

Yes, blogspot is a crap to post source code. Will try to fix it.

Karl said...

Nice blog you got. Your series on collision detection is exactly what I'm looking for. I'm really excited about your next part in the series.

Keep up the good work!
Karl

Martijn said...

Hey, very good article, but where is part IV??

Anonymous said...

Yes, very good. But I want the part IV also. ;)

reyt said...

Buy archlord money and flyff goldand flyff moneyorflyff power leveling or2moons dilI be to aoc gold go to age of conan gold