17 Renderizaci�n de pol�gonos


void polygon3d(BITMAP *bmp, int type, BITMAP *texture, int vc, V3D *vtx[]);
void polygon3d_f(BITMAP *bmp, int type, BITMAP *texture, int vc, V3D_f *vtx[]);
Dibuja pol�gonos 3d en el bitmap especificado, usando el modo de render especificado. A diferencia de la funci�n polygon(), estas rutinas no soportan figuras c�ncavas o con intersecciones, y no pueden dibujar sobre bitmaps de pantalla en modo-X ( si quiere escribir c�digo en modo-X, dibuja en un bitmap de memoria y c�pialo a la pantalla). El ancho y alto del bitmap de la textura debe ser un m�ltiplo de dos, pero puede ser diferente, ejemplo: una textura 64x16 est� bien, pero una de 17x3 no. El par�metro que cuenta los v�rtices (vc) debe ser seguido por un array que contiene el n�mero apropiado de punteros a estructuras vertex: polygon3d() usa la estructura de punto fijo V3D, mientras que polygon3d_f() usa la estructura coma flotante V3D_f. Estas son definidas as�:

      typedef struct V3D
      {
         fixed x, y, z;       - posici�n
         fixed u, v;          - coordenadas de la textura
         int c;               - color
      } V3D;
   
      typedef struct V3D_f
      {
         float x, y, z;       - posici�n
         float u, v;          - coordenadas de la textura
         int c;               - color
      } V3D_f;
El c�mo se almacenan los datos de los v�rtices depende del modo de render:

Los valores x e y especifican la posici�n del v�rtice en coordenadas de pantalla 2d.

El valor z s�lo es necesario cuando use correcci�n de perspectiva en las texturas, y especifica la profundidad del punto usando coordenadas del mundo 3d.

Las coordenadas u y v s�lo son necesarias cuando use texturas, y especifican la posici�n del punto en el bitmap de la textura que se corresponde con el v�rtice indicado. El plano de la textura es un plano infinito con el bitmap repetido sobre toda la superficie, y la imagen del pol�gono resultante en este plano rellenar� el pol�gono cuando se dibuje en pantalla.

Nos referimos a pixels en el plano de la textura como texels. Cada texel es un bloque, n� s�lo un punto, y los n�meros enteros de u y v se refieren a la esquina superior izquierda del texel. Esto tiene varias implicaciones. Si quiere dibujar un pol�gono rectangular y aplicar una textura de 32x32 sobre �l, debe usar las coordenadas de textura (0,0), (0,32), (32,32) y (32,0), asumiendo que los v�rtices son especificados en �rden antihorario. La textura ser� aplicada perfectamente sobre el pol�gono. No obstante, note que si ajustamos u=32, la �ltima columna de texels que se ver�n en la pantalla ser�n los que est�n en u=31, y lo mismo ocurre para v. Esto es porque las coordenadas se refieren a la esquina superior izquierda de los texels. En efecto, las coordenadas de textura por la derecha y por abajo son exclusivas.

Aqu� hay otro punto interesante. Si tiene dos pol�gonos juntos que comparten dos v�rtices (como las dos partes de una pieza de cart�n doblada), y quiere aplicar sobre ellos una textura cont�nua, los valores u y v de los v�rtices que est�n en la junta ser�n iguales para ambos pol�gonos. Por ejemplo, si ambos son rectangulares, un pol�gono usar� (0,0), (0,32), (32,32) y (32,0), y el otro usar� (32,0), (32,32), (64,32) y (64,0). Esto aplicar� la textura perfectamente.

Por supuesto puede usar n�meros con decimales para u y v indicando puntos que est�n parcialmente en un texel. Adem�s, dado que el plano de la textura es infinito, puede especificar valores mayores que el tama�o de la textura. Esto puede ser usado para repetir la textura varias veces sobre el pol�gono.

El valor c especifica el color del v�rtice, y es interpretado de forma diferente por los modos de render.

El par�metro type especifica el modo de render, y puede ser cualquiera de los siguientes:

POLYTYPE_FLAT:
Un simple pol�gono con sombreado plano, que toma el color del valor c del primer v�rtice. Este tipo de pol�gono es afectado por la funci�n drawing_mode(), por lo que puede ser usado para renderizar pol�gonos transparentes o XOR.

POLYTYPE_GCOL:
Un pol�gono con un color de sombreado goraud. Los colores de cada v�rtice son tomados del valor c, e interpolados a trav�s del pol�gono. Esto es muy r�pido, pero s�lo funcionar� en modos de 256 colores si su paleta tiene un suave gradiente de colores. En modos truecolor interpreta el color como valor empaquetado en formato directo de hardware producido por la funci�n makecol().

POLYTYPE_GRGB:
Un pol�gono con sombreado goraud que interpola tripletes RGB en vez de un solo color. En modos de 256 colores usa la tabla global rgb_map para convertir el resultado a color de 8 bits, por lo que s�lo puede ser usado despu�s de que haya creado una tabla de mapa de colores. Los colores para cada v�rtice son tomados del valor c, que es interpretado como un triplete RGB de 24 bits (0xFF0000 es rojo, 0x00FF00 es verde y 0x0000FF es azul).

POLYTYPE_ATEX:
Un pol�gono con textura af�n. Esto dibuja la textura a trav�s del pol�gono con una simple interpolaci�n 2d lineal, que es r�pida pero matem�ticamente incorrecta. Puede estar bien si el pol�gono es peque�o o plano hacia la c�mara, pero como no cuenta con la acortaci�n de perspectiva, puede producir extra�os artefactos movidos en la textura. Para ver lo que quiero decir, ejecuta test.exe y mire lo que pasa con el test polygon3d() cuando hace un zoom muy cerca del cubo.

POLYTYPE_PTEX:
Un pol�gono texturizado con correcci�n de perspectiva. Esto usa el valor z de la estructura del v�rtice as� como las coordenadas u/v, por lo que las texturas se ven correctamente independientemente del �ngulo de visualizaci�n. Ya que esto envuelve c�lculos de divisi�n en al bucle interior de la texturizaci�n, este modo es mucho m�s lento que POLYTYPE_ATEX, y usa coma flotante, por lo que ser� muy lento en cualquier cosa peor que un Pentium (incluso con una FPU, un 486 no es capaz de mezclar divisi�n de coma flotante con otras operaciones de enteros tal y como puede hacer un Pentium).

POLYTYPE_ATEX_MASK:
POLYTYPE_PTEX_MASK:
Como POLYTYPE_ATEX and POLYTYPE_PTEX, pero los pixels a cero de la textura son ignorados, permitiendo que la textura sea transparente.

POLYTYPE_ATEX_LIT:
POLYTYPE_PTEX_LIT:
Como POLYTYPE_ATEX y POLYTYPE_PTEX, pero la tabla global color_map (para modos de 256 colores) o la funci�n de fundido (para modos truecolor no-MMX) es usada para fundir la textura con el nivel de luz tomado del valor c en la estructura del v�rtice. �Esto s�lo puede ser usado despu�s de que haya creado una tabla de mapa de color o funciones de fundido!

POLYTYPE_ATEX_MASK_LIT:
POLYTYPE_PTEX_MASK_LIT:
Como POLYTYPE_ATEX_LIT y POLYTYPE_PTEX_LIT, pero los pixels a cero de la textura son ignorados, permitiendo que la textura sea transparente.

POLYTYPE_ATEX_TRANS:
POLYTYPE_PTEX_TRANS:
Renderiza texturas transl�cidas. Son aplicables todas las reglas generales de dibujado transl�cido. No obstante, estos modos tienen una limitaci�n: s�lo funcionan con bitmaps en memoria o con memoria de v�deo lineal (no con video por bancos). Ni si quiera lo intente en estos casos, ya que las funciones no realizan chequeos y su programa morir� horriblemente (o como m�nimo dibujar� mal las cosas).

POLYTYPE_ATEX_MASK_TRANS:
POLYTYPE_PTEX_MASK_TRANS:
Como POLYTYPE_ATEX_TRANS y POLYTYPE_PTEX_TRANS, pero los pixels a cero de la textura son ignorados.

Si el bit CPU_MMX de la variable global cpu_capabilities est� activado, las rutinas GRGB y *LIT truecolor ser�n optimizadas usando instrucciones MMX. Si el bit CPU_3DNOW est� activado, las rutinas truecolor PTEX*LIT tomar�n ventaja de la extensi�n de CPU 3DNow!.

Usar rutinas MMX para *LIT tiene un efecto secundario: normalmente (sin MMX), estas rutinas usan las funciones de fundido y otras funciones de luz, creadas con set_trans_blender() o set_blender_mode(). Las versiones MMX s�lo usan el valor RGB que se pasa a set_trans_blender() y hacen la interpolaci�n lineal internamente. Por esta raz�n, un nuevo conjundo de funciones de fundido que se pasa a set_blender_mode() es ignorado.

Relacionado con: triangle3d, quad3d, polygon, clip3d, cpu_capabilities.
void triangle3d(BITMAP *bmp, int type, BITMAP *tex, V3D *v1, *v2, *v3);
void triangle3d_f(BITMAP *bmp, int type, BITMAP *tex, V3D_f *v1, *v2, *v3);
Dibuja tri�ngulos en 3d, usando las estructuras de v�rtices de punto fijo o coma flotante. A diferencia de quad3d[_f], las funciones triangle3d[_f] no envuelven polygon3d[_f]. Las funciones triangle3d[_f] usan sus propias rutinas para determinar los grados del gradiente. Por esto, triangle3d[_f](bmp, type, tex, v1, v2, v3) es m�s r�pido que polygon3d[_f](bmp, type, tex, 3, v[]).
Relacionado con: polygon3d, quad3d, triangle.
void quad3d(BITMAP *bmp, int type, BITMAP *tex, V3D *v1, *v2, *v3, *v4);
void quad3d_f(BITMAP *bmp, int type, BITMAP *tex, V3D_f *v1, *v2, *v3, *v4);
Dibuja cuadril�teros en 3d, usando las estructuras de v�rtices de punto fijo o coma flotante. Esto es equivalente a llamar polygon3d(bmp, type, tex, 4, v[]); o polygon3d_f(bmp, type, tex, 4, v[]);
Relacionado con: polygon3d, triangle3d.
int clip3d_f(int type, float min_z, float max_z, int vc, V3D_f *vtx[], V3D_f *vout[], V3D_f *vtmp[], int out[]);
Recorta el pol�gono dado en vtx. vc es el n�mero de v�rtices, el resultado va en vout, y vtmp y out son necesarios para uso interno. Los punteros en vtx, vout y vtmp deben apuntar a estructuras V3D_f v�lidas. Como en el proceso de recorte pueden aparecer nuevos v�rtices, el tama�o de vout, vtmp y out deber�a ser al menos vc * (1.5 ^ n), donde n es el n�mero de planos de corte (5 o 6), y '^' denota "elevado a la". El frustum (vol�men visualizado) est� definido por -z<x<z, -z<y<z, 0<min_z<z<max_z. Si max_z<=min_z, el recorte z<max_z no se hace. Como puede ver, el recorte se realiza en el espacio de la c�mara, con la perspectiva en mente, por lo que esta rutina deber�a ser llamada despues de aplicar la matriz de c�mara, pero antes de la proyecci�n de perspectiva. La rutina interpolar� correctamente u, v, y c en la estructura de v�rtices. Sin embargo, esto no est� previsto para GCOL en profundidades de color high/truecolor.
Relacionado con: polygon3d, clip3d.
int clip3d(int type, fixed min_z, fixed max_z, int vc, V3D *vtx[], V3D *vout[], V3D *vtmp[], int out[]);
Versi�n de punto fijo de clip3d_f(). Esta funci�n se deber�a usar con cuidado, dad la precisi�n limitada de la aritm�tica de punto fijo, y las altas posibilidades de errores por redondeo: el c�digo de punto flotante es mejor en la mayor�a de situaciones.
Relacionado con: polygon3d, clip3d_f.

Render con zbuffer

Un Z-buffer almacena la profundidad de cada pixel dibujado en una pantalla. Cuando un objeto 3d es renderizado, la profundidad de cada pixel es comparada con el valor ya almacenado en el Z-buffer: si el pixel es m�s cercano se dibuja, en caso contrario se ignora.

No hace falta ordenar los pol�gonos. No obstante, sigue siendo �til ignorar los pol�gonos que no est�n de cara a la c�mara, ya que as� se previene la comparaci�n de muchos pol�gonos ocultos contra el Z-buffer. El render mediante Z-buffer es el �nico algoritmo soportado por Allegro que resuelve directamente la intersecci�n entre figuras (mire por ejemplo exzbuf.c). El precio que hay que pagar son unas rutinas m�s complejas (y m�s lentas).

Los pol�gonos con Z-buffer son por dise�o una extensi�n de los estilos de render normales POLYTYPE_*. S�lo hay que hacer una OR entre POLYTYPE y el valor POLYTYPE_ZBUF, y las rutinas normales como polygon3d(), polygon3d_f(), quad3d(), etc, renderizar�n pol�gonos con Z-buffer.

Ejemplo:

   polygon3d(bmp, POLYTYPE_ATEX | POLYTYPE_ZBUF, tex, vc, vtx);

Por supuesto, las coordenadas z deben ser v�lidas sin importar el estilo de render.

El procedimiento de render con Z-buffer parece un render con doble buffer. Deber�a seguir los siguientes pasos: crear el Z-buffer al comienzo de su programa y hacer que la librer�a lo use mediante set_zbuffer(). Entonces, por cada frame, borre el Z-buffer y dibuje pol�gonos con POLYTYPE_* | POLYTYPE_ZBUF para finalmente destruir el Z-buffer al finalizar su programa.

Notas sobre los renders con Z-buffer:

ZBUFFER *create_zbuffer(BITMAP *bmp);
Crea el Z-buffer usando el tama�o del BITMAP que est� planeando usar para dibujar sus pol�gonos. Se pueden definir varios Z-buffers, pero s�lo se puede usar uno a la vez, por lo que debe usar set_zbuffer() para elegir cu�l ser� activo.
Relacionado con: create_sub_zbuffer, set_zbuffer, clear_zbuffer, destroy_zbuffer.
ZBUFFER *create_sub_zbuffer(ZBUFFER *parent, int x, int y, int width, int height);
Crea un sub-z-buffer, es decir, un z-buffer que comparte memoria de dibujado con un z-buffer ya existente, pero posiblemente con un tama�o diferente. Son aplicables las mismas reglas que con los sub-bitmaps: la anchura y altura pueden extenderse fuera de los bordes del z-buffer padre (ser�n recortados), pero el punto de origen debe estar en una regi�n del padre.

Cuando dibuje con z-buffer en un bitmap, la esquina superior izquierda del bitmap siempre est� alineada con la esquina superior izquierda del z-buffer actual. Por lo que esta funci�n es �til principalmente si quiere dibujar en un sub-bitmap y usar el �rea correspondiente del z-buffer. En otros casos, ej, si quiere dibujar en un sub-bitmap de la pantalla (y no en otras partes de la pantalla), normalmente querr� crear un z-buffer normal (no un sub-z-buffer) del tama�o de la pantalla. No necesita crear un z-buffer del tama�o de la pantalla virtual y entonces un sub-z-buffer de �ste.

Relacionado con: create_zbuffer, create_sub_bitmap, destroy_zbuffer.
void set_zbuffer(ZBUFFER *zbuf);
Hace que un Z-buffer sea el activo. Este deber� haber sido creado previamente mediante create_zbuffer().
Relacionado con: create_zbuffer, clear_zbuffer, destroy_zbuffer.
void clear_zbuffer(ZBUFFER *zbuf, float z);
Escribe z en el Z-buffer (0 significa muy lejos). Esta funci�n debe ser usada para iniciar el Z-buffer antes de cada frame. Realmente, las rutinas de bajo nivel comparan la profundidad del pixel actual con 1/z: por ejemplo, si quiere recortar pol�gonos m�s lejanos de 10, debe usar: clear_zbuffer(zbuf, 0.1);
Relacionado con: create_zbuffer, set_zbuffer, destroy_zbuffer.
void destroy_zbuffer(ZBUFFER *zbuf);
Destruye el Z-buffer cuando haya finalizado.
Relacionado con: create_zbuffer, set_zbuffer, clear_zbuffer.

Render de escenas

Allegro provee dos m�todos simples para quitar caras ocultas:

El render de escenas sigue los siguientes pasos aproxim�damente:

Por cada linea horizontal del �rea de visualizaci�n se usa una lista ordenada de bordes para saber qu� pol�gonos "est�n dentro" y cu�les est�n cerca. Se usa coherencia vertical - la lista de bordes es ordenada a partir de la anterior - no cambiar� mucho. Las rutinas de render de escenas usan las mismas rutinas de bajo nivel que polygon3d().

Notas del render de escena:

Usar muchos pol�gonos con m�scara reduce el rendimiento, porque cuando se encuentra un pol�gono con m�scara en primera linea de visi�n, los pol�gonos que est�n detr�s deben ser dibujados tambi�n. Lo mismo es aplicable a pol�gonos FLAT dibujados con DRAW_MODE_TRANS.

El render con Z-buffer tambi�n funciona con el render de escenas. Puede ser �til si tiene algunos pol�gonos que se interseccionan, pero la mayor�a de los pol�gonos pueden ser renderizados sin problemas usando el algoritmo normal de ordenado de scanlines. Igual que antes: simplemente haga una OR del POLYTIPE con POLYTYPE_ZBUF. Adem�s, tiene que limpiar el z-buffer al comienzo del frame. Ejemplo:

   clear_scene(buffer);
   if (some_polys_are_zbuf) clear_zbuffer(0.);
   while (polygons) {
      ...
      if (this_poly_is_zbuf) type |= POLYTYPE_ZBUF;
      scene_polygon3d(type, tex, vc, vtx);
   }
   render_scene();


int create_scene(int nedge, int npoly);
Reserva memoria para una escena, nedge y npoly son sus estimaciones de cu�ntas aristas y pol�gonos renderizar� (no puede salirse del l�mite que especifica aqu�). Si usa los mismos valores en llamadas sucesivas, el espacio ser� reusado (no nuevos malloc()).

La memoria reservada es algo menor que 150 * (nedge + npoly) bytes. Devuelve cero con �xito, o negativo si no se pudo reservar la memoria.

Relacionado con: create_zbuffer, scene_polygon3d, render_scene, clear_scene, destroy_scene, scene_gap.
void clear_scene(BITMAP *bmp);
Inicializa la escena. El bitmap es donde renderizar� sus gr�ficos.
Relacionado con: create_scene, scene_polygon3d, render_scene, destroy_scene, scene_gap.
void destroy_scene();
Libera la memoria previamente reservada por create_scene.
Relacionado con: create_scene, scene_polygon3d, clear_scene, render_scene, scene_gap.
int scene_polygon3d(int type, BITMAP *texture, int vc, V3D *vtx[]);
int scene_polygon3d_f(int type, BITMAP *texture, int vc, V3D_f *vtx[]);
Pone un pol�gono en la lista de render. Realmente no renderiza nada en este momento. Debe llamar esta funci�n entre clear_scene() y render_scene().

Los argumentos son iguales que para polygon3d(), excepto por el par�metro de bitmap que falta. Se usar� el que indic� mediante clear_scene().

A diferencia de polygon3d(), los pol�gonos pueden ser c�ncavos o estar interseccionados. Las figuras que penetran en otras pueden salir bien, pero no son manejadas realmente por este c�digo.

Note que s�lo se almacena un puntero a la textura, por lo que deber�a mantenerla en memoria hasta render_scene(), donde ser� usada.

Ya que el estilo FLAT es implementado con la funci�n de bajo nivel hline(), el estilo FLAT est� sujeto a DRAW_MODE. Todos los modos son v�lidos. Junto con el pol�gono, el modo ser� almacenado para el momento del render, y tambi�n otras variables relacionadas (puntero al mapa de color, puntero al patron, ancla, valores de blending).

El valor de los bits CPU_MMX y CPU_3DNOW de la variable global cpu_capabilities afectar� la elecci�n de la rutina de bajo nivel en ensamblador que ser� usada por render_scene() con este pol�gono.

Devuelve cero con �xito o negativo si no ser� renderizado debido a que falta la rutina de render apropiada.

Relacionado con: cpu_capabilities, create_scene, clear_scene, render_scene, destroy_scene, polygon3d.
void render_scene();
Renderiza toda la escena creada con scene_polygon3d() en el bitmap que pas� a clear_scene(). El render se realiza una linea a cada vez, sin procesar dos veces el mismo pixel.

Note que entre clear_scene() y render_scene() no deber�a modificar el rect�ngulo de recorte del bitmap destino. Por razones de velocidad, deber�a ajustar el rect�ngulo de recorte al m�nimo.

Tenga en cuenta tambi�n que las texturas pasadas a scene_polygon3d() son almacenadas como punteros y ser�n usadas en render_scene().

Relacionado con: create_scene, clear_scene, destroy_scene, scene_gap, scene_polygon3d.
extern float scene_gap;
Este n�mero (valor por defecto = 100.0) controla el comportamiento del algoritmo de ordenado en z. Cuando un borde est� muy cerca del plano de otro pol�gono, hay un intervalo de incertidumbre en el cual no se puede determinar qu� objeto es visible (qu� z es m�s peque�a). Esto es debido a errores num�ricos acumulativos para los bordes que han sufrido bastantes transformaciones e interpolaciones.

El valor por defecto significa que si los valores 1/z (en espacio proyectado) difieren s�lo en 1/100 (uno por ciento), ser�n considerados iguales y el eje x de los planos ser� usado para saber qu� plano est� acerc�ndose mientras nos movemos hacia la derecha.

Valores mayores significan m�rgenes menores, e incrementan la posibilidad de confundir planos/bordes realmente adyacentes. Valores menores significan m�rgenes mayores, e incrementan la posibilidad de confundir un pol�gono cercano con uno adyacejte. El valor de 100 est� cercano a lo m�s �ptimo. No obstante, el valor optimo oscila con diferentes resoluciones, y puede ser dependiente de la aplicaci�n. Est� aqu� para que lo pueda ajustar al m�ximo.

Relacionado con: create_scene, clear_scene, destroy_scene, render_scene, scene_polygon3d.

Volver al Indice