Antes de empezar

como dije en el punto anterior, los dos puntos claves de estos ficheros son "como almacenar los objetos" y "como reacionarlos entre si". Esto es comun a la mayoria de los formatos de almacenamiento de objetos 3D. Asi es como lo resuelve el formato .X:

- Tipos de datos definidos por el usuario:

Los ficheros .X estan compues de plantillas, que pueden ser definidas por el usuario. Una plantilla es una "definicion de como quiere el usuario que se almacene la informacion".

Existen unas plantillas por defecto quese encuentran en rmxftmpl.h (d3dfile.cpp ) y rmxftmpl.x en c:\mssdk\include. Las firmas de identificacion en rmxfgguid.h (tambien incluido en 3d3file.cpp, uno de los Common files)

- Relaciones jerarquicas:

Los tipos de datos consentidos por un plantilla se lllaman "miembros opcionales". Estos miembros opcionales se almacenan como hijos del objeto. Los hijos pueden ser a su vez objetos, referencias a un objeto anterior, o datos binarios.

>Vale, esto a sido muy teorico, pero no me he entereado de nada

Pues vamos a comenzar con un pequeño ejemplo, un cuadrado. Este cuadrado lo vamos a guardar en un fichero llamado cuadrado.x

Puedes escribir tu mismo un fichero .x y luego ver el resultado con la herramienta que trae el SDK de DirextX "Optimized Mesh Example".

Ejemplo sencillo

compuesto de un cuadrado, con 2 caras. Si el cuadrado solo tuviese una cara, solo veriamos el cuadrado de frente, y cuando lo rotasemos no veriamos nada. Te recuerdo que DirectX solo dibuja las caras que estan definida en sentido de las agujas de reloj, cuando giramos el cuadrado se invierte el orden de los puntos y por lo tanto no se dibuja nada. Para solucionarlo dibujamos dos caras, una frontal y la otra trasera. Otra solucion seria dejar una cara y desactivar el "BackFace Cullling".

xof 0302txt 0064
//cuadrado
Mesh Cuadrado {						//cara frontal y trasera (2 caras)


	 8;								//numero de vertices
	 1.0;  1.0;  0.0;,				//vertice 0
	-1.0;  1.0;  0.0;,				//vertice 1
	-1.0; -1.0;  0.0;,				//vertice 2
	 1.0; -1.0;  0.0;,				//vertice 3
	 1.0;  1.0;  0.0;,				//vertice 4
	 1.0; -1.0;  0.0;,				//vertice 5
	-1.0; -1.0;  0.0;,				//vertice 6
	-1.0;  1.0;  0.0;;				//vertice 7
	 4;								//numero de triangulos
	 3; 0,1,2;,						//triangulo 1
	 3; 0,2,3;,						//triangulo 2
	 3; 4,5,6;,						//triangulo 3
	 3; 4,6,7;;						//triangulo 4
	
	MeshMaterialList {
		1;							// un material
		4;							// una cara
		0,							// cara 0 usa material 0
		0,							// cara 1 usa material 0
		0,							// cara 2 usa material 0
		0;;							// cara 3 usa material 0


		Material {					// material 0
			0.0; 1.0; 0.0; 1.0;;	// color de la cara
			0.0;					// intensidad
			0.0; 0.0; 0.0;;			// color "specular"
			0.0; 0.0; 0.0;;			// color "emmisive"
		}
	}
}



Cabecera

xof 0302txt 0064

Se comienza el fichero con un numero de 4 bytes llamado xof. Este numero nos indica que version de formato se trata, la version mayor es 03 y la menor es 02. Y que el formato del fichero es txt.

Puedes convertir entre txt y bin con la herramienta c:\mssdk\DXUtils\Xfiles\conv.exe

Otros formatos posibles son tzip y bzip, que significan texto-comprimido y binario-comprimido.

Por ultimo tenenemos que el tipo de coma flotante es 0064 (otro valor posible es 0032)

como ves, los comentarios se ponen como en C++ con // , o tambien con #

Mesh

La mayor parte del ejemplo se trata de una plantilla de malla.

template Mesh {
	<3D82AB44-62DA-11cf-AB39-0020AF71E433>
	DWORD nVertices;
	array Vector vertices[nVertices];
	DWORD nFaces;
	array MeshFace faces[nFaces];
	[...]
}

Esta plantilla hace uso a su vez de otras plantillas como son Vector y MeshFace

template Vector {
	<3D82AB5E-62DA-11cf-AB39-0020AF71E433>
	FLOAT x;;
	FLOAT y;
	FLOAT z;
}


template MeshFace {
	<3D82AB5F-62DA-11cf-AB39-0020AF71E433>
	DWORD nFaceVertexIndex;
	array DWORD faceVertexIndices[nFaceVertexIIndices];
}

Las plantillas constan de 4 partes: Un numero "UNICO", que consiste en una mezcla de numeros, caracteres y el simbolo _. La segunda parte que se llama UUID (identificador unico universal). Y la tercera parte consiste en el tipo de datos de las entradas.

La ultima parte regula el grado de restriccion: una plantilla pude ser abierta, cerrada o restringida. Esto es: las abiertas pueden contener cualquier otro tipo de dato, las cerradas no pueden tener otro tipo diferente de datos, y las restringidas que solo puede contener aquellos tipos de datos que se especifiquen como tales.

En nuestro ejemplo la plantilla Mesh es abierta, porque usa los corchetes y los puntos suspensivos al finnal: [...] Asi que puede contener otros tipos de datos.

Materiales (MeshMaterialList)

La plantilla MeshMaterialList es hija de Mesh. Contiene el numero caras y materiales y relaciona una cara con uno o varios materiales.

La plantilla tiene la siguiente definicion:

template MeshMaterialList {
+<f6f23f42-7686-11cf-8f52-0040333594a3>
	DWORD nMaterials:
	DWORD nFaceIndexes;
	array DWORD faceIndexes[nFaceIndexes];

	[Material]
}

La primera variable contiene el numero de materiales y la segunda el numero de caras. Nuestro ejemplo tiene dos caras, la cara frontal y la trasera. Adjuntamos los materiales a las caras en el array faceIndexes. Cada cara se concatena con el material nombrando el numero de material. Despues el programa que lea el fichero .X sabra la cara que se trata contando el numero de caras.

Al final aparece [Material] , lo que significa que esta plantilla es una plantilla restringida y que solo puede contener objetos de tipo Material

template Material {
	<3D82AB4D-62DA-11cf-AB39-0020AF1E433>
	ColorRGBA faceColor;
	FLOAT power;
	ColorRGB specularColor;
	ColorRGB emissiveColor;
	[...]
}

Esta plantilla hace uso de ColorRGBA y ColorRGB

template ColorRGBA {
	<35FF44E0-6C7C-11cf-8F52-0040333594A3>
	FLOAT red;
	FLOAT green;
	FLOAT blue;
	FLOAT alpha;
}


template ColorRGB {
	FLOAT red;
	FLOAT green;
	FLOAT blue;
}

Normales

Se suele incluir las normales de todos los verticecs mediante la plantilla MeshNormals.

El vector normal del vertice se usa en el sombreado Gouraud (por defecto en Direct3D) para controlar la iluminacion y crear algunos efectos con las texturas.

MeshTextureCoords {
	 8;				// 4 coordenadas de textura
	 1.0;  1.0;,	// coord 0
	 1.0;  0.0;,	// coord 1
	 0.0;  0.0;,	// coord 2
	 0.0;  1.0;,	// coord 3
	 1.0;  1.0;,	// coord 4
	 1.0; -1.0;,	// coord 5
	-1.0; -1.0;,	// coord 6
	-1.0;  1.0;,	// coord 7
}


template MeshNormals {
	<f6f23f43-7686-11cf-8f52-0043333594a3>
	DWORD nNormals;
	array Vector normals[nNormals];
	DWORD nFaceNormals;
	aray MeshFace fafceNormals[nFaceNormals];
}

Texturas

Las texturas se pueden referenciar por medio de TextureFilename, un objeto hijo de Material:

template TextureFilename {
	STRING filename;
}

La referencia ha de ser incluida en el objeto Material, de esta manera por ejemplo:

Material MuroVerde {		// Material numero 0
	0.0; 1.0; 0.0; 1.0;;
	0.0;
	0.0; 0.0; 0.0;;
	0.0; 0.0; 0.0;;
	TextureFileName{"wall.bmp";}
}

Ademas necesitas especificar las coordenadas de la textura

template MeshTextureCoords {
	<f6f23f40-7686-11cf-8f52-0040333594a3>
	DWORD nTextureCoords;
	array Coords2d textureCoords[nTextureCoords];
}
template Coords2d {
	<f6ff23f44-7686-11cf-8f52-0040333594a3>
	FLOAT u;
	FLOAT v;
}

La primera variable contiene el numero de vertices que tienen que ser usados junto con las coordenadas de textura. El siguiente array contiene los pares tu/tv de las texturas.

Matrices

A veces queremos transformar partes de un objeto independientemente de las otras. Por ejemplo un tanque puede mover el cañon arriba y abajo, la cabina rotaria sobre si misma a la izuierda y a la derecha. Las cadenas y las ruedas se moverian cuando el conjunto avanzase, etc. Para ello debemos dividir el objeto en partes, y especificar una matriz para cada parte. Un objeto para guardar cada "frame" seria como sigue:

Frame TanqueBase {
	FrameTransformMatrix {
		1.000000,    0.000000,     0.000000,    0.000000,
		0.000000,    1.000000,     0.000000,    0.000000,
		0.000000,   -0.000000,     1.000000,    0.000000,
	  206.093353,   -6.400993,   -31.132195,    1.000000;;
	}
	Mesh TanqueBase {
		2470;
		41.310013; -26.219450; -113.602348;,
		...
	}
}


Frame Ruedas_Izq {
	FrameTransformMatrix { 
	...

Las plantilas usadas en este ejemplo son:

template Frame {
	<3D82AB46-62DA-11cf-AB39-0020AF71E433>
	[...]
}

template FrameTransformMatrix {

	Matrix4x4 frameMatrix;
}

template Matrix4x4 {
	array FLOAT matrix[16];
}

Animacion

Para animar un fichero .X necesitas especificar una serie de animaciones con referencia a las matrices frame correspondientes. Abajo aparece un ejemplo de nuestro cuadrado texturizado y animado.

Este ejmplo muestra el uso de los "frame keys", que consisten cada uno en una matriz 4 por 4. El unico valor que cambia es el primero de la cuarta fila, que es la posicion x del cuadrado.

{ SQUARE_ROOT } es la referencia a la matriz frame. El 4 indica que estamos usando "key" de tipo matrices. Existen diferentes tipos de "keys" (rotacion, escalado, , posicion, o matriz).

xof 0302txt 0064
   Frame SQUARE_Root {
   FrameTransformMatrix {
   1.000000, 0.000000, 0.000000, 0.000000,
   0.000000, 1.000000, 0.000000, 0.000000,
   0.000000, 0.000000, 1.000000, 0.000000,
   0.000000, 0.000000, 0.000000, 1.000000;;
   }
   Material GreenMat { // material #0
   0.0;1.0;0.0;1.0;;
   0.0;
   0.0;0.0;0.0;;
   0.0;0.0;0.0;;
 TextureFilename{"wall.bmp";}
   }
// square
   Mesh Square {
   // front face and back face
   8; // number of vertices
   1.0; 1.0; 0.0;, // vertice 0
   -1.0; 1.0; 0.0;, // vertice 1
   -1.0;-1.0; 0.0;, // vertice 2
   1.0;-1.0; 0.0; // vertice 3
 1.0; 1.0; 0.0;, // vertice 4
   1.0;-1.0; 0.0;, // vertice 5
   -1.0;-1.0; 0.0;, // vertice 6
   -1.0; 1.0; 0.0;; // vertice 7
 4; // number of triangles
   3;0,1,2;, // triangle #1
   3;0,2,3;, // triangle #2
   3;4,5,6;, // triangle #3
   3;4,6,7;; // triangle #4
 MeshMaterialList {
   1; // one material
   4; // one face
   0, // face #0 use material #0
   0, // face #1 use material #0
   0, // face #2 use material #0
   0;; // face #3 use material #0
 {GreenMat}
   }
 MeshTextureCoords {
   8; // 4 texture coords
   1.0; 1.0;, // coord 0
   1.0; 0.0;, // coord 1
   0.0; 0.0;, // coord 2
   0.0; 1.0;; // coord 3
 1.0; 1.0;, // coords 4
   1.0;-1.0;, // coords 5
   -1.0;-1.0;, // coords 6
   -1.0; 1.0;; // coords 7
   }
 MeshNormals {
   2; // 2 normals
   0.0; 0.0; 1.0;, // normal #1
   0.0; 0.0;-1.0;; // normal #2
 4; // 4 faces
   3;0,0,0;, 
   3;0,0,0;, 
   3;1,1,1;, 
   3;1,1,1;; 
   } 
   }
}
AnimationSet {
   Animation {
   AnimationKey {
   4; // Position keys
   5; // 5 keys
   0;16;1.0,0.0,0.0,0.0,
   0.0,1.0,0.0,0.0,
   0.0,0.0,1.0,0.0,
   0.1,0.0,0.0,1.0;;,
   80;16;1.0,0.0,0.0,0.0,
   0.0,1.0,0.0,0.0,
   0.0,0.0,1.0,0.0,
   0.2,0.0,0.0,1.0;;,
   160;16;1.0,0.0,0.0,0.0,
   0.0,1.0,0.0,0.0,
   0.0,0.0,1.0,0.0,
   0.3,0.0,0.0,1.0;;,
   240;16;1.0,0.0,0.0,0.0,
   0.0,1.0,0.0,0.0,
   0.0,0.0,1.0,0.0,
   0.2,0.0,0.0,1.0;;,
   320;16;1.0,0.0,0.0,0.0,
   0.0,1.0,0.0,0.0,
   0.0,0.0,1.0,0.0,
   0.1,0.0,0.0,1.0;;,
   }
   {SQUARE_Root} 
   }
   }
 

continuara....

(que tengo musho sueño ya hoy zzzzz z