30 Rutinas matem�ticas 3D

Allegro tambi�n contiene algunas funciones de ayuda de 3d para manipular vectores, construir o usar matrices de transformaci�n, y hacer proyecciones de perspectiva de un espacio 3d en la pantalla. Estas funciones no son, y nunca ser�n, una librer�a 3d total (mi objetivo es dar rutinas de soporte gen�ricas, y no c�digo gr�fico muy especializado :-) pero estas funciones pueden serle �tiles para desarrollar su propio c�digo 3d.

Allegro usa el sistema de coordenadas de mano derecha, es decir, si apunta con el dedo gordo de su mano derecha al eje positivo x, y con el �ndice al eje positivo y, su dedo coraz�n apuntar� en la direcci�n positiva del eje z. Esto tambi�n significa que para las rotaciones, si hace que el dedo gordo de su mano derecha siga el eje de rotaci�n, sus dedos se curvar�n en la direcci�n positiva de la rotaci�n.

Hay dos versiones de todas las funciones matem�ticas de 3d: una usando aritm�tica de punto fijo, y la otra usando coma flotante. La sintaxis para ambas es id�ntica, pero las funciones y estructuras de coma flotante tienen el sufijo '_f'. Ejemplo: la funci�n cross_product() de punto fijo tiene el equivalente de coma flotante en cross_product_f(). Si est� programando en C++, Allegro tambi�n sobrecarga estas funciones para que las use con la clase "fija".

La transformaci�n 3d se realiza modelando una matriz. Esta es un array de 4x4 n�meros que pueden ser multiplicados con un punto 3d para producir otro punto 3d. Si ponemos los valores correctos en la matriz, podemos usarla para varias operaciones como translaci�n, rotaci�n y escalado. El truco consiste en que puede multiplicar dos matrices para producir una tercera, y esta tendr� el mismo efecto en los puntos 3d que aplicando las dos matrices originales una despu�s de la otra. Por ejemplo, si tiene una matriz que rota un punto, y otra que lo mueve en una direcci�n, puede combinarlas para producir una matriz que realizara la rotaci�n y translaci�n en un paso. Puede crear transformaciones extremadamente complejas de este modo, teniendo que multiplicar cada punto 3d por una sola matriz.

Allegro hace trampa al implementar la estructura de la matriz. La rotaci�n y el escalado de un punto 3d puede ser realizado con una matriz simple de 3x3, pero para trasladar el punto y proyectarlo en la pantalla, la matriz tiene que ser extendida a 4x4, y el punto extendido a una cuarta dimensi�n, al a�adir una coordenada extra: w=1. Esto es algo malo en t�rminos de eficiencia, pero afortunadamente, es posible realizar una optimizaci�n. Dada la siguiente matriz 4x4:

   ( a, b, c, d )
   ( e, f, g, h )
   ( i, j, k, l )
   ( m, n, o, p )
se puede observar un patr�n de qu� partes hacen qu�. La rejilla 3x3 de arriba a la izquierda implementa la rotaci�n y el escalado. Los tres valores de arriba de la cuarta columna (d, h y l) implementan la translaci�n, y siempre y cuando la matriz sea usada s�lo para transformaciones afines, m, n y o ser�n siempre cero y p siempre ser� 1. Si no sabe que significa 'af�n', lea a Foley & Van Damme: b�sicamente cubre el escalado, la translaci�n y rotaci�n del objeto pero no la proyecci�n. Ya que Allegro usa una funci�n aparte para la proyecci�n, las funciones de matriz s�lo tienen que servir para la transformaci�n af�n, lo que significa que no hay que guardar la fila inferior de la matriz. Allegro asume que esta contiene (0,0,0,1), y por eso optimiza las funciones de manipulaci�n de matrices.

Las matrices se almacenan en estructuras:

   typedef struct MATRIX     - matriz de punto fijo
   {
      fixed v[3][3];         - componente 3x3 de escalado y rotaci�n
      fixed t[3];            - componente x/y/z de translaci�n
   } MATRIX;
   
   typedef struct MATRIX_f   - matriz de coma flotante
   {
      float v[3][3];         - componente 3x3 de escalado y rotaci�n
      float t[3];            - componente x/y/z de translaci�n
   } MATRIX_f
extern MATRIX identity_matrix;
extern MATRIX_f identity_matrix_f;
Variable global que contiene la matriz con identidad 'vac�a'. Multiplicar por la matriz de identidad no tiene ning�n efecto.


void get_translation_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void get_translation_matrix_f(MATRIX_f *m, float x, float y, float z);
Construye una matriz de translaci�n, guard�ndola en m. Si se aplica a un punto (px, py, pz), esta matriz producir� el punto (px+x, py+y, pz+z). En otras palabras: mueve las cosas.

Relacionado con: apply_matrix, get_transformation_matrix, qtranslate_matrix.
void get_scaling_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void get_scaling_matrix_f(MATRIX_f *m, float x, float y, float z);
Construye una matriz de escalado, almacen�ndola en m. Cuando se aplica a un punto (px, py, pz), esta matriz produce un punto (px*x, py*y, pz*z). En otras palabras, agranda o empeque�ece las cosas.
Relacionado con: apply_matrix, get_transformation_matrix, qscale_matrix.
void get_x_rotate_matrix(MATRIX *m, fixed r);
void get_x_rotate_matrix_f(MATRIX_f *m, float r);
Construye las matrices de rotaci�n del eje X, almacen�ndolas en m. Cuando se aplican a un punto, estas matrices lo rotar�n sobre el eje X el �ngulo especificado (en binario, 256 grados hacen un c�rculo).
Relacionado con: apply_matrix, get_rotation_matrix, get_y_rotate_matrix, get_z_rotate_matrix.
void get_y_rotate_matrix(MATRIX *m, fixed r);
void get_y_rotate_matrix_f(MATRIX_f *m, float r);
Construye las matrices de rotaci�n del eje Y, almacen�ndolas en m. Cuando se aplican a un punto, estas matrices lo rotar�n sobre el eje Y el �ngulo especificado (en binario, 256 grados hacen un c�rculo).
Relacionado con: apply_matrix, get_rotation_matrix, get_x_rotate_matrix, get_z_rotate_matrix.
void get_z_rotate_matrix(MATRIX *m, fixed r);
void get_z_rotate_matrix_f(MATRIX_f *m, float r);
Construye las matrices de rotaci�n del eje Z, almacen�ndolas en m. Cuando se aplican a un punto, estas matrices lo rotar�n sobre el eje Z el �ngulo especificado (en binario, 256 grados hacen un c�rculo).
Relacionado con: apply_matrix, get_rotation_matrix, get_x_rotate_matrix, get_y_rotate_matrix.
void get_rotation_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void get_rotation_matrix_f(MATRIX_f *m, float x, float y, float z);
Construye una matriz de transformaci�n que rotar� puntos en todos los ejes los grados especificados. (en binario, 256 grados hacen un c�rculo).
Relacionado con: apply_matrix, get_transformation_matrix, get_vector_rotation_matrix, get_align_matrix, get_x_rotate_matrix, get_y_rotate_matrix, get_z_rotate_matrix.
void get_align_matrix(MATRIX *m, fixed xfront, yfront, zfront, fixed xup, fixed yup, fixed zup);
Rota la matriz de tal forma que la alinea sobre las coordenadas de los vectores especificados (estos no tienen que ser normalizados o perpendiculares, pero up y front no pueden ser iguales). Un vector front de 1,0,0 y un vector up de 0,1,0 devolver�n la matriz de identidad.
Relacionado con: apply_matrix, get_camera_matrix.
void get_align_matrix_f(MATRIX *m, float xfront, yfront, zfront, float xup, yup, zup);
Versi�n en coma flotante de get_align_matrix().
Relacionado con: get_align_matrix.
void get_vector_rotation_matrix(MATRIX *m, fixed x, y, z, fixed a);
void get_vector_rotation_matrix_f(MATRIX_f *m, float x, y, z, float a);
Construye una matriz de transformaci�n que rotar� puntos sobre todos los vectores x,y,z un �ngulo especificado (en binario, 256 grados hacen un c�rculo).
Relacionado con: apply_matrix, get_rotation_matrix, get_align_matrix.
void get_transformation_matrix(MATRIX *m, fixed scale, fixed xrot, yrot, zrot, x, y, z);
Construye una matriz de transformaci�n que rotar� puntos en todos los ejes los �ngulos especificados (en binario, 256 grados hacen un c�rculo), escalar� el resultado (pasa el valor 1 si no quiere cambiar la escala), y entonces los trasladar� a la posici�n x, y, z requerida.
Relacionado con: apply_matrix, get_rotation_matrix, get_scaling_matrix, get_translation_matrix.
void get_transformation_matrix_f(MATRIX_f *m, float scale, float xrot, yrot, zrot, x, y, z);
Versi�n en coma flotante de get_transformation_matrix().
Relacionado con: get_transformation_matrix.
void get_camera_matrix(MATRIX *m, fixed x, y, z, xfront, yfront, zfront, fixed xup, yup, zup, fov, aspect);
Construye la matriz de c�mara para trasladar objetos del espacio a una vista normalizada del espacio, preparada para la proyecci�n de perspectiva. Los par�metros x, y, z especifican la posici�n de la c�mara, xfront, yfront y zfront son los vectores 'de frente' que especifican hacia adonde apunta la c�mara (estos pueden ser de cualquier tama�o, no es necesaria la normalizaci�n), y xup, yup y zup son los vectores de la direcci�n 'arriba'. El par�metro fov especifica el campo de visi�n (el ancho del foco de la c�mara) en binario, haciendo 256 grados un c�rculo. Para proyecciones t�picas, un campo de visi�n de entre 32 a 48 trabajara bien. Finalmente, la raz�n de aspecto es usada para el escalado en la dimensi�n Y relativamente al eje X, para que pueda ajustar las proporciones de la imagen final (ponga a uno para no escalar).
Relacionado con: apply_matrix, get_align_matrix.
void get_camera_matrix_f(MATRIX_f *m, float x, y, z, xfront, yfront,zfront, float xup, yup, zup, fov, aspect);
Versi�n en coma flotante de get_camera_matrix().
Relacionado con: get_camera_matrix.
void qtranslate_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void qtranslate_matrix_f(MATRIX_f *m, float x, float y, float z);
Rutina optimizada para trasladar una matriz ya generada: esto simplemente a�ade el 'offset' de translaci�n, por lo que no hay que crear dos matrices temporales y multiplicarlas.
Relacionado con: get_translation_matrix.
void qscale_matrix(MATRIX *m, fixed scale);
void qscale_matrix_f(MATRIX_f *m, float scale);
Rutina optimizada para escalar una matriz ya generada: esto simplemente a�ade el factor de escalaci�n, por lo que no hay que crear dos matrices temporales y multiplicarlas.
Relacionado con: get_scaling_matrix.
void matrix_mul(const MATRIX *m1, MATRIX *m2, MATRIX *out);
void matrix_mul_f(const MATRIX_f *m1, MATRIX_f *m2, MATRIX_f *out);
Multiplica dos matrices, guardando el resultado en out (que puede ser un duplicado de una de las dos m�trices de entrada, pero es m�s r�pido cuando las entradas y la salida son todas distintas). La matriz resultante tendr� el mismo efecto que la combinaci�n de m1 y m2, p.ej cuando son aplicadas en un punto, (p * out) = ((p * m1) * m2). Cualquier n�mero de transformaciones se puede concatenar de esta forma. F�jese que la multiplicaci�n de matrices no es communtaiva, as� matrix_mul(m1,m2) != matrix_mul(m2,m1).
Relacionado con: apply_matrix.
fixed vector_length(fixed x, fixed y, fixed z);
float vector_length_f(float x, float y, float z);
Calcula la longitud del vector (x, y, z), usando ese buen teorema de Pit�goras.
Relacionado con: normalize_vector.
void normalize_vector(fixed *x, fixed *y, fixed *z);
void normalize_vector_f(float *x, float *y, float *z);
Convierte un vector (*x, *y, *z) a un vector normalizado. Este apunta en la misma direcci�n que el vector original, pero tiene una longitud de uno.
Relacionado con: vector_length, dot_product, cross_product.
fixed dot_product(fixed x1, y1, z1, x2, y2, z2);
float dot_product_f(float x1, y1, z1, x2, y2, z2);
Calcula el producto escalar (x1, y1, z1) . (x2, y2, z2), devolviendo el resultado.
Relacionado con: cross_product, normalize_vector.
void cross_product(fixed x1, y1, z1, x2, y2, z2, *xout, *yout, *zout);
void cross_product_f(float x1, y1, z1, x2, y2, z2, *xout, *yout, *zout);
Calcula el producto vectorial (x1, y1, z1) x (x2, y2, z2), almacenando el resultado en (*xout, *yout, *zout). El resultado es perpendicular a los dos vectores de entrada, para que pueda ser usado para generar las normales de los pol�gonos.
Relacionado con: dot_product, polygon_z_normal, normalize_vector.
fixed polygon_z_normal(const V3D *v1, V3D *v2, V3D *v3);
float polygon_z_normal_f(const V3D_f *v1, V3D_f *v2, V3D_f *v3);
Encuentra la componente Z de la normal de un vector de tres v�rtices especificados (que deben ser parte de un pol�gono convexo). Esto es usado principalmente en la ocultaci�n de caras. Las caras traseras de un poliedro cerrado nunca son visibles al espectador, y por tanto no necesitan ser dibujadas. Esto puede ocultar aproximadamente la mitad de los pol�gonos de una escena. Si la normal es negativa, el pol�gono se puede eliminar, si es cero, el pol�gono est� perpendicular a la pantalla.
Relacionado con: cross_product.
void apply_matrix(const MATRIX *m, fixed x, y, z, *xout, *yout, *zout);
void apply_matrix_f(const MATRIX_f *m, float x, y, z, *xout, *yout, *zout);
Multiplica el punto (x, y, z) por la transformaci�n de la matriz m, almacenando el resultado en el punto (*xout, *yout, *zout).
Relacionado con: matrix_mul.
void set_projection_viewport(int x, int y, int w, int h);
Ajusta el punto de visi�n usado para escalar la salida de la funci�n persp_project(). Pase las dimensiones de la pantalla y el �rea donde la quiere dibujar, que t�picamente ser� 0, 0, SCREEN_W, SCREEN_H.
Relacionado con: persp_project.
void persp_project(fixed x, y, z, *xout, *yout);
void persp_project_f(float x, y, z, *xout, *yout);
Proyecta el punto 3d (x, y, z) del espacio sobre una pantalla 2d, almacenando el resultado en (*xout, *yout) usando los par�metros anteriormente ajustados por set_projection_viewport(). Esta funci�n proyecta desde la pir�mide de vista normalizada, que tiene una c�mara en el origen apuntando al eje z positivo. El eje x va de izquierda a derecha, y va de arriba a abajo, y z se incrementa con la profundidad de la pantalla. La c�mara tiene un �ngulo de visi�n de 90 grados, es decir, los planos x=z y -x=z ser�n los bordes izquierdo y derecho de la pantalla, y los planos y=z y -y=z ser�n la parte superior e inferior de la pantalla. Si quiere un campo de visi�n diferente a la posici�n de la c�mara, deber�a transformar todos sus objetos con la matriz de visi�n apropiada. Ejemplo, para obtener el efecto de haber girado la c�mara 10 grados a la izquierda, rote todos sus objetos 10 grados a la derecha.
Relacionado con: set_projection_viewport.

Volver al Indice