Buenas, llegamos a la recta final para programar 3D en la NDS, en esta ocasión aprenderemos a usar el Toon Shading y los Cube Maps, las cuales son las únicas cosas que nos faltan para haberlo dado todo. Luego en el siguiente tutorial daré unas funciones de control y optimización y de regalo un juego 3D (simple) para asimilar todo lo aprendido.
Bueno, sin más preámbulos, empezamos!
1- Otra forma de sombrear: Toon Shading
En el tutorial anterior vimos cómo usar la niebla para dar sombreados a nuestros terrenos en 3D, pues en esta ocasión veremos otro tipo llamado Toon Shading, el cual se basa en sombrear los vértices del modelo/objeto 3D usando para ello las luces y materiales. Todo esto puede que os suene a rollo, pero este efecto se usa en muchos juegos, como los de The Legend of Zelda para NDS, ahora veréis un ejemplo de toon shading:
Aquí podemos ver una imagen a la izquierda con "plastic shading" (otro sombreado no soportado por el hardware de NDS), y a la derecha el mismo modelo de la izquierda solo que aplicándole el efecto Toon Shading, con esto conseguimos que las partes no iluminadas e iluminadas se distingan rápidamente. Esto puede sonar muy bien para nuestros juegos 3D pero tiene una serie de inconvenientes:
- Debemos usar las luces 0 y 1 para que surta efecto, las luces 2 y 3 no podemos usarla ya que el Hardware las ignora
- No podemos usar colores para el modelo, esto se suele suplir usando materiales o texturas directamente
- Debemos dar el color de toon shading a cada uno de los 32 slots que tiene (lo veremos más adelante)
Bien, ahora que sabemos los inconvenientes, aquí expondré un pequeño pseudocódigo de cómo vamos a usar el Toon Shading, aquí va:
int main(){ Iniciar3D(); INICIAR LUCES 0 Y 1 CONFIGURAR LOS 32 SLOTS DE TOON SHADING while(1){ Empezar3D(); DIBUJAR OBJETOS CON MATERIALES O TEXTURAS (NO USAR COLORES) Actualiza3D(); } return 0; }
Bien, lo primero que hay que hacer es iniciar las luces 0 y 1 para que se vea el efecto Toon Shading, para el que no se acuerde las luces se configuran con esta función:
void glLight(int luz, u16 color, v10 x, v10 y, v10 z); Configura una luz para ser usada luz ---> Numero de luz (0, 1, 2 o 3) (Toon Shading solo soporta 0 y 1) color --> Color de la luz de la macro RGB15() x, y, z --> Posicion de la luz Para usar la luz tenemos que decirlo al glPolyFmt() glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE | POLY_FORMAT_LIGHT0 | POLY_FORMAT_LIGHT1); Con esto mostramos las luces 0 y 1 Estos conceptos se vieron con más detalle en el tutorial 3 sobre iluminación
Digo también que para que salga el Toon Shading tenemos que decírselo al glPolyFmt(), añadiendo el parámetro POLY_TOON_HIGHLIGHT, si no se especifica esto el efecto no se verá.
Bueno, después de configurar las luces 0 y 1 (repito: no podemos usar las luces 2 y 3 paa esto), tenemos que saber que, como la niebla, el Toon Shading tiene 32 slots para aplicarle el color del sombreado, el slot 0 es usado por los vértices completamente oscuros y va subiendo hasta el 31 donde los vértices son completamente luminosos, todo esto y más con esta función:
void glSetToonTableRange(int slot_inicial, int slot_final, u16 color); Configura varios slots de Toon Shading slot_inicial --> Slot inicial de configuración slot_final --> Slot donde termina la configuración colo ---> Color en RGB15() de los slots Ejemplo: glSetToonTableRange(0, 15, RGB15(31, 31, 31)); Los slots del 0 al 15 tienen el color blanco (el modelo se verá blanco en las zonas no iluminadas)
Fácil no? Con esto ya podemos usar el Toon Shading, ahora sólo tenemos que dibujar el objeto afectado, teniendo en cuenta que no podemos usar colores (en teoría si, pero por razones de Hardware el canal R del color no se ve), así que para ello tenemos 2 alternativas, usar materiales o texturas, los cuales se vieron con detalle en tutoriales anteriores.
Bien, terminamos con esto con el código completo:
// Configuramos las luces 0 y 1 glLight(0, RGB15(31, 31, 31), floattov10(-1), floattov10(1), floattov10(0)); glLight(1, RGB15(31, 31, 31), floattov10(1), floattov10(-1), floattov10(0)); // Configuramos los Slots de Toon Shading (0-31) glSetToonTableRange(0, 15, RGB15(15, 15, 15)); // Los slots del 0 al 15 son grises glSetToonTableRange(15, 31, RGB15(31, 31, 31)); // Los otros más iluminados son blancos while(1){ // Aplicamos el Toon Shading glPoylFmt(POLY_ALPHA(31) | POLY_ID(0) | POLY_CULL_NONE | POLY_TOON_HIGHLIGHT); // Definimos un material para el objeto glMaterialf(GL_AMBIENT, RGB15(8,8,8)); glMaterialf(GL_DIFFUSE, RGB15(24,24,24)); glMaterialf(GL_SPECULAR, RGB15(0,0,0)); glMaterialf(GL_EMISSION, RGB15(0,0,0)); // Dibujamos objeto con toon shading glCallList(modelo); }
Solo con hacer esto ya tendremos el modelo 3D con este efecto, primero configuramos las luces, los slots del efecto, lo ponemos con el glPolyFmt(), y finalmente dibujamos el objeto...
2- Usando Cube Maps, otra manera de texturizar
Bien, el siguiente apartado, el miy mencionado, va a tratar sobre los entornos o cube maps. En tutoriales anteriores vimos cómo texturizar objetos mediante las coordenadas de textura, pero si dijera que los podemos hacer de otra forma, ésta sería mediante los normales de iluminación, este efecto trata de calcular las normales de iluminación convirtiéndolas en coordenadas de textura, por ejemplo: si quisiéremos hacer que un objeto refleje lo que hay a su alrededor (como un espejo), pues usamos esto, para asimilarlo nada mejor que una imagen:
En la imagen anterior podemos ver una esfera 3D la cual, mediante una textura, aplicamos el efecto Cube Map, y ésa textura envuelve el objeto (todo esto pasando las normales de iluminación a la matriz de texturas).
Bien, ahora que hemos aprendido lo que es, vamos a aprender a usarla, al hacerlo no vamos a perder nada, así que con este código lo explico en un momento:
INICIAR EL SISTEMA DE TEXTURAS CARGAR LA TEXTURA EN VRAM EN EL MODO CUBE MAP while(1){ CALCULAR LA MATRIZ DE TEXTURA (CONVERTIR NORMALES EN COORDENADAS DE TEXTURA) SELECCIONAR TEXTURA USADA COMO CUBE MAP DIBUJAR OBJETO CON EL CUBE MAP }
Bien, primero y fundamental es iniciar las texturas, es decir, iniciar los bancos A y B de VRAM para texturas y activarlas con glEnable(), se vió en el otro tutorial.
Luego las cargamos en VRAM, usando el mismo método, solo que en el glTexImage2D() tenemos que decirle que la textura se va a generar mediante normales de iluminación, no como coordenadas de textura, todo esto con esta función:
glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_32, TEXTURE_SIZE_32, 0, opciones_generacion, datos_textura); Todos los parámetros se explicaron en el tutorial 4 Lo que cambia aquí es que el en argumento "opciones generacion", en vez de poner TEXGEN_TEXCOORD tenemos que poner lo siguiente: (TEXGEN_NORMAL | GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T). Poniendo eso la textura se cargará en el modo Cube Map y podremos usarla.
Bien, ya hemos iniciado las texturas y hemos cargado en VRAM una en el modo Cube Map (calcular normales + repetir coordenada S + repetir coordenada T), lo siguiente que tenemos que hacer es configurar en el bucle while() la matriz de texturas, todo con este código:
// Selecciona la matriz de texturas glMatrixMode(GL_TEXTURE); // Reseteala glLoadIdentity(); // Escala la matriz de textura para los cube maps // Los datos recomiendo ponerlos a INT o en FLOAT glScalei(-64 << 16, 64 << 16, 0 << 16); // NOTA: El valor a escalar hay que moverlo 16 bits a la izquierda para que se vean los cambios entre valor y valor // NOTA: Si hacemos transformaciones a los objetos, debemos ponerla también en la matriz de textura, p.e: si rotamos 60º, aquí habría que poner también glRotateX(60); // Una vez configurada, reinicia el modelado glMatrixMode(GL_MODELVIEW); glLoadIdentity();
Una vez configurada la matriz de texturas tenemos que seleccionar la textura que usaremos como Cube Map (obvio), lo hacemos con glBindTexture(0, slot);
Después de esto, dibujamos el objeto normalmente, definiendo sus normales de iluminación y se calcularán en la matriz de textura con el código de antes, como no tenemos que aplicarle un material para que los normales tengan efecto.
Termino con un ejemplo final de cómo usamos los cube maps:
// Iniciamos las texturas vramSetBankA(VRAM_A_TEXTURE); vramSetBankB(VRA_B_TEXTURE); // Cargamos la textura en VRAM glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_128, TEXTURE_SIZE_128, (TEXGEN_NORMAL | GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T), datos); // Dibujar objetos con el cube map... while(1){ // Configura la matriz de texturas glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalei(-64 << 16, 64 << 16, 0 << 16); // Una vez configurada, reinicia el modelado glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Dibuja el objeto con el cube map (las normales y el material deben estar definidos) glMaterialf(GL_EMISSION, RGB15(31,31,31)); glMaterialf(GL_DIFFUSE, RGB15(31,31,31)); glCallList(modelo); }
Bien, con esto tendremos nuestro objeto con la textura en modo cube map, repasad bien todo el código, y si hay alguna duda ponedla en los comentarios. Pondré ahora un par de ejercicios para practicar lo aprendido y termino:
Ejercicios
Ejercicio 10
En este ejercicio usaremos el Toon Shading aprendido anteriormente, tendremos 2 modelos rotando con el Toon Shading y veremos cómo cambia su aspecto, le aplicaremos texturas a los objetos (recordad que no deberíamos poner colores):
Descarga: http://www.mediafire.com/?1uqzosrf3dl6g7d
Ejercicio 11
Ya vimos que con el Toon Shading podemos sombrear los objetos sin apenas esfuerzo, pero y si los texturizamos usando los Cube Maps?, el resultado sería sorprendente, solo hay que ver la imagen para notarlo, tendremos los 2 modelos otra vez, solo que esta vez, aplicando Cube Maps podemos darle apariencia a madera, cristal etc... Todo ello usando una sola textura.
Con Arriba-Abajo cambias la textura de cube map seleccionada
Descarga: http://www.mediafire.com/?sh851txsvrhyolf
Bueno, este ha sido el fin de este sexto tutorial, el siguiente desgraciadamente será el último, ya que hemos dado casi todo lo que nos puede ofrecer la NDS de 3D, daremos una clase rápida de optimización y un ejemplo final de un juego (simple) en 3D, usando la "librería" que hemos estado acumulando en estos tutoriales.
Bien, hasta entonces, saludos!
~Actualmente estudiando Ingeniería de las Tecnologías de la Telecomunicación en la Escuela de Ingenieros~
Hola IndexAlpha9 Y vas a
Hola IndexAlpha9
Y vas a poder terminar el tutorial?
Ups...
Tengo hecha la parte de las funciones, pero como acaba de empezar el instituto y todo, no me ha dado tiempo de terminar el juego final xD
En cuanto pueda lo publico entero, saludos!
~Actualmente estudiando Ingeniería de las Tecnologías de la Telecomunicación en la Escuela de Ingenieros~