Ya deben estar al tanto de estas novedades, pero por las dudas les comento que dos grandiosos nuevos ejemplos están disponibles en el sitio web de XNA Creators Club:
Ahora bien, ¿qué hay de grandioso en ellos? Me alegro que hayan preguntado.
(I) Muestra de Extensión de Modelos Con Piel
El primer ejemplo muestra cómo extender el proyecto original de modelos con piel ("skinned models”) de forma que:
- Puedan “mover” una parte del modelo con piel de manera independiente a la secuencia de la animación (como en este caso, un brazo y la cabeza),
- Puedan posicionar objetos en relación a un hueso específico (en este caso, un bate), y
- Puedan anexar una geometría de cobertura al modelo animado (en este caso, esferas).
El código es una gran fuente de conocimiento técnico para programadores respecto a la técnica de “pelaje” pero, debido a unos pocos problemas en el modelo con piel en sí, ellos también pueden aprender cuan engorrosos y puntillozos pueden llegar a ser los procesos de (no sólo modelado y desenvoltura sino también) de inclusión de un esqueleto, pelaje y animación al modelo 3D, tal que se vea ok en todas y cada una de las situaciones (esperadas) antes de salir al mercado.
Primera captura de pantalla:
Como pueden ver aquí, cuando muevan la cabeza uno de los vértices permanece (casi) inmóvil, lo cual significa que o bien no fue asignado al hueso del cuello o, si lo fue, entonces sus “proporciones” deberían reajustarse.
Segunda foto:
Parece que la parte del cinto marcada arriba con anaranjado se mueve junto con la cadera mientras que el resto del cinto se mueve con el torso. Y por ende, la animación de caminar, incluso si se está comportando como se espera, parece algo rara.
Es posible que, s¡endo la parte de programación el único/principal propósito del ejemplo en sí, ello no sea relevante para programadores, pero para independientes (“indies”) como yo que tienden a desarrollar todas las partes del juego “por sí mismos”, es un ejemplo fabuloso de algúnos de los dolores de cabeza que van a encontrar cuando traten con el lado artístico del tema.
(II) Muestra de Primitivos 3D
El segundo presenta un conjuento de clases que necesitarán para crear cubos, esferas, cilindros, roscas y la famosa tetera!
Estos primitivos se encuentran usualmente en los más famosos aplicaciones de modelado, entre otras, como 3D Studio Max o Maya.
Se pueden preguntar: ¿por qué la tetera se la considera un primitivo? Bueno, gracias al tipo de operaciones poderasas que se utilizan para crearla de manera procedural: calculos de curvas bezier! Buenísimo, realmente …
Una sugerencia para el cilindro:
En el caso que algunos de Uds. quieran crear los triángulos que conforman cada tapa del cilindro tal que se distribuyan uniformemente en torno a un vértice central, en vez de hacia un lado (como se ve arriba), entonces tendrán que reemplazar el siguiente método en la clase “CylinderPrimitive”:/// <summary>
/// Helper method creates a triangle fan to close the ends of the cylinder.
/// </summary>
void CreateCap( int tessellation, float height, float radius, Vector3 normal )
{
// Create cap indices.
for ( int i = 0; i < tessellation - 2; i++ )
{
if ( normal.Y > 0 )
{
AddIndex( CurrentVertex );
AddIndex( CurrentVertex + ( i + 1 ) % tessellation );
AddIndex( CurrentVertex + ( i + 2 ) % tessellation );
}
else
{
AddIndex( CurrentVertex );
AddIndex( CurrentVertex + ( i + 2 ) % tessellation );
AddIndex( CurrentVertex + ( i + 1 ) % tessellation );
}
}
// Create cap vertices.
for ( int i = 0; i < tessellation; i++ )
{
Vector3 position = GetCircleVector( i, tessellation ) * radius +
normal * height;
AddVertex( position, normal );
}
}
De forma que, en cambio, se parezca a:
/// <summary>
/// Helper method that creates a cap laying out triangles around a centered vertex.
/// </summary>
void CreateCap( int tessellation, float height, float radius, Vector3 normal )
{
// Add a vertex in the center of the cap.
AddVertex( normal * height, normal );
// Create cap indices, taking into account the centered vertex (that is why
// we use "CurrentVertex - 1" as the first element of the corresponding index).
for ( int i = 0; i < tessellation; i++ )
{
if ( normal.Y > 0 )
{
AddIndex( CurrentVertex - 1 );
AddIndex( CurrentVertex + ( i + 1 ) % tessellation );
AddIndex( CurrentVertex + ( i + 2 ) % tessellation );
}
else
{
AddIndex( CurrentVertex - 1 );
AddIndex( CurrentVertex + ( i + 2 ) % tessellation );
AddIndex( CurrentVertex + ( i + 1 ) % tessellation );
}
}
// Create cap vertices.
for ( int i = 0; i < tessellation; i++ )
{
Vector3 position = GetCircleVector( i, tessellation ) * radius +
normal * height;
AddVertex( position, normal );
}
}
Siendo el resultado:
Esto no es para nada crítico, pero por cuestiones de (una mejor) desenvoltura -e incluso de crear más “secciones” (anillos) sobre cada tapa, vía programación- 2 vértices centrales y unos pocos triángulos adicionales son útiles sin dañar a la performance.
> Vínculo a la versión en inglés.