viernes, 23 de abril de 2010

Introducción a Motores 3D (parte 3)

Projection Transformation y Perspective Division

En el post anterior mencionaba un poco acerca de la Modelview Transformation. Como resultado de esta transformación se obtienen las coordenadas de vista, estas son las coordenadas desde el punto de vista del observador. El siguiente paso es la Projection Transformation y Perspective Division, donde se determina que objetos y/o partes de estos serán mostrados en la pantalla. Además hace un calculo del eje z ya que como nuestro monitor es en 2D debe hacer una transformación para representar objetos 3D, y así poder simular aquellas caras de los objetos que se encuentran más lejos del observador.





En la figura, los objetos contenidos dentro del plano a y b son los que se proyectarán en pantalla. Estos planos se determinan a través de la función glFrustum o glPerspective. También puede generarse una proyección paralela, con todos los objetos contenidos en un paralelogramo, esto se logra a través de la función glOrtho. Pero para producir proyecciones en perspectiva se utilizan las mencionadas primero.


Viewport Transformation

La última transformación por la que pasan cada uno de los puntos es la Viewport Transformation. Ésta básicamente consiste en transformar las coordenadas normalizadas de los puntos en coordenadas de la ventana donde se mostrarán. Se utiliza la función glViewport para indicarle a OpenGL los parámetros que deberá utilizar para realizar la transformación.

Un ejemplo de la configuración del OpenGL para estas transformaciones podría ser así:

const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity() ;

glViewport establece las medidas de la pantalla y glFrustum establece la perspectiva para la representación de los objetos. Nótese que se establece GL_PROJECTION como la matriz de trabajo para estas transformaciones, luego se cambia a GL_MODELVIEW donde más adelante en el programa se añadírían los puntos de los objetos como se mostró en el post anterior, utilizando la matriz de cada uno de éstos para colocarlos en la posición que les corresponde en el mundo 3D.

Conociendo estas transformaciones, y aprovechando que OpenGL nos facilita el cálculo de todas ellas; el programador puede concentrarse en cuestiones como el movimiento de la cámara, movimiento de los objetos, reglas del juego, etc. para crear su motor 3D.

Hay que tomar en cuenta también otro montón de cosas como ser la iluminación, sombras, efectos especiales, detección de colisiones, etc. algunas de las cuales requerirán de cálculos matemáticos complejos o del ingenio del programador para simularlos. Estas las expondré en los siguientes posts.

lunes, 1 de febrero de 2010

Enorme Log

La unidad C en un Windows SBS 2003, se me estaba quedando sin espacio; lo cual me generaba una diversa variedad de errores: no funcionaban las impresoras, se perdía la conexión con el Exchange Server, y en el peor de los casos todas las licencias CAL del Windows parecían desaparecer, lo que ocasionaba que ningún usuario pudiera conectarse.

Me tocaba estar borrando archivos temporales, sucesos de evento, vaciando la papelera, etc. para poder evitar estos problemas. No podía desinstalar ninguno de los programas que tenía y no deseaba formatear el servidor para hacer una partición más grande.

Encontré algo que me ayudará a resolver el problema por lo menos durante un buen tiempo, y es que el Symantec Server cuenta con un servicio llamado Reporting Agents que crea un log en el directorio "C:\Archivos de Programa\Archivos comunes\Symantec Shared\Reporting Agents\Win32" en un archivo llamado ReportsSVC.log. Este archivo va creciendo y creciendo hasta hacerse enorme!, el mío tenía mas de 700MB.

No encontré la forma de configurar la carpeta donde se crea este archivo para poder moverlo de mi disco C, pero si pude moverlo y hacer que comenzara con 1 KB de nuevo :). Solamente hay que detener el servicio Reporting Agents y mover o eliminar el archivo. No encontré mucho de importancia en él, pero por cualquier cosa lo salvé en otra partición :p

lunes, 18 de enero de 2010

MindManager 6 con MS Word 2007

MindManager es una fabulosa herramienta para la organización de ideas e incluso para realizar presentaciones. Tiene varias funcionalidades muy buenas, entre ellas la posibilidad de exportar los documentos a PowerPoint, Excel, Visio o Word, entre otros.

Tengo la versión Professional 6, y todo funcionaba muy bien hasta que decidí actualizarme a Office 2007. La versión 6 del MindManager trabaja con Office 2003, pero al intentar exportar los documentos si tenemos instalado el Office 2007 en vez del 2003, probablemente el programa se quede trabado o nos tire un error.

La nueva versión del MindManager se encuentra integrado con el Office 2007 y trae algunas características al parecer muy interesantes; pero yo necesitaba poder exportar documentos sin necesidad de desinstalar mi Office 2003 ni actualizar mi MindManager.

Bajé una actualización del sitio de Mindjet (el fabricante) que aseguraba resolver el problema y permitir exportar a Office 2007. Instalé la actualización y al entrar a mi MindManager las opciones de exportar a Word y otras habían desaparecido, solamente quedó la opción de exportar a Powerpoint y a rangos de Excel. Esto definitivamente era peor que el estado inicial...

Pero encontré la forma de solucionarlo, es bastante sencilla: solamente hay que ir al Control Panel y en la opción de Agregar y/o Quitar Programas le decimos que queremos cambiar la instalación de MindManager y luego seleccionamos la opción reparar. Al terminarse este proceso, las opciones de exportar a Word y otros programas reaparecen y funcionarán con el Office 2007 sin problemas!!...eso si, si queremos exportar a un archivo de office de 2003, tendremos problemas, así que en este caso hay que exportarlo a Office 2007, abrirlo en la aplicación respectiva y salvarlo como archivo de Office 2003, asunto arreglado!.

viernes, 2 de octubre de 2009

Introducción a Motores 3D (parte 2)

Representación en pantalla

En el post anterior mencionaba que para crear nuestro mundo 3D encontraríamos dos grandes desafíos: la modelación de los objetos en estructuras de datos y la representación de estos en nuestra pantalla 2D.

Mostré un poco, de manera general, la modelación de los objetos; ahora hablaremos de la representación de estos.

La representación de objetos 3D no es un tema fácil, requiere que el programador, no solamente sea un buen programador y conocedor del lenguaje, sino que además debe tener bastantes conocimientos de vectores, albegra lineal, física, geometría analítica, trigonometría, análisis numérico, etc.

A pesar de que nuestro modelo almacena la información en tres dimensiones, debemos transformar esta información a dos dimensiones para representarlo en el monitor. Este cálculo matemático es demasiado complejo, y aunque es posible realizarlo, nos tomaría demasiado tiempo y además ya existen herramientas que lo hacen por nosotros. Una de estas herramientas es OpenGL, éste nos brinda las funciones necesarias para poder realizar estta transformación de nuestro modelo 3D al monitor 2D.

Los objetos pasan por una serie de transformaciones para poder llegar a la representación final, estas transformaciones son:
  • Modelview Transformation
  • Projection Transformation
  • Perspective Division
  • Viewport Transformation

Modelview Transformation

En este paso, las coordenadas locales de cada objeto son tomadas y transformadas para darles una posición en el mundo 3D. Como pudimos ver anteriormente, las coordenadas que tenemos almacenadas en nuestro modelo, son coordenadas relativas al objeto y no a su posición en el mundo. En este paso, el objeto es movido a la posición que debe tener en el mundo 3D, ya sea a través de rotaciones, traslaciones o escalamientos. Es importante apuntar que la apariencia final del objeto depende del orden en que se apliquen estas transformaciones. Ejemplo:




En el inciso a) aplicamos primero una rotación al objeto y luego una traslación sobre el eje x, dado que su eje x está rotado se mueve diagonalmente. En el inciso b) aplicamos las mismas transformaciones pero en orden inverso, obteniendo así un resultado diferente.

Además de estas operaciones, se debe tomar en cuenta también la posición de la cámara, lo que transformará entonces nuestras coordenadas anteriores a unas nuevas que dependen del punto de vista del observador.

Para lograr este tipo de transformaciones, OpenGL utiliza una matriz llamada la GL_MODELVIEW matrix. Cada vértice es multiplicado por los valores de esta matriz dándole así su posición real en el mundo. Es decir, que para cada objeto, debo almacenar información que me indique cómo ubicarlo en la posición q deseo. Aplico primero las transformaciones para modificar la matriz y luego voy calculando el valor de cada vértice. Para el ejemplo del inciso a) tendríamos un código similar a este:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(10, 0.0f, 0.0f, 1.0f);
glTranslatef(10.0f, 0.0f, 0.0f);

La primera instrucción le indica a OpenGL con qué matriz vamos a trabajar. Luego cargamos en ella la matriz identidad y luego aplicamos las operaciones de rotación y traslación. Una vez que hemos realizado todas las transformaciones que deseamos para el objeto, le decimos a OpenGL cuáles son los vértices que queremos representar:

glBegin(GL_TRIANGLES);
for (j=0; j<numPolygons;j++) {
//----------------- FIRST VERTEX -----------------
glColor3f(polygon[j].red,polygon[j].green,polygon[j].blue);
glVertex3f( vertex[ polygon[j].vertex[0] ].x, vertex[ polygon[j].vertex[0] ].y,vertex[ polygon[j].vertex[0] ].z);

//----------------- SECOND VERTEX -----------------
glColor3f(polygon[j].red,polygon[j].green,polygon[j].blue);
glVertex3f( vertex[ polygon[j].vertex[1] ].x, vertex[ polygon[j].vertex[1] ].y,vertex[ polygon[j].vertex[1] ].z);

//----------------- THIRD VERTEX -----------------
glColor3f(polygon[j].red,polygon[j].green,polygon[j].blue);
glVertex3f( vertex[ polygon[j].vertex[2] ].x, vertex[ polygon[j].vertex[2] ].y,vertex[ polygon[j].vertex[2] ].z);
}
glEnd();

glBegin le dice a OpenGL el tipo de polígono que vamos a utilizar para representar nuestro objeto. gl Color3f es para indicar el color y glVertex3f es para indicar las coordenadas de cada vértice.

Como podemos ver, se requiere entonces almacenar por cada objeto una matriz para ubicar el objeto en la posición correcta, por lo que en nuestra definición de la clase Object3D debemos añadir esta estructura de datos. La matriz es una matriz 4x4, la explicación del funcionamiento de esta matriz es un tema que esta fuera del objetivo de este post, pero que puede ser deducido a través de un breve análisis matemático. Puede consultarse el siguiente link: http://www.geocities.com/valcoey/intro3d.html