viernes, 12 de octubre de 2012

Derivar la Matriz de Proyeccion

Hay que eliminar una dimension.

Para poder dibujar en la pantalla de una computadora un mundo en 3d es necesario de alguna manera transformar los puntos del espacio real en 3 dimensiones, al llamado espacio de la pantalla, que logicamente tiene 2 dimensiones.
Este proceso de eliminar una dimension en algebra se llama proyeccion.
Por ejemplo, si defino

P:R3-->R2 / P(x,y,z) = (x,y)

es una proyeccion.

El problema con esta proyeccion es que no brinda demasiada informacion acerca del mundo 3d real. Eso es debido a que la dimension z simplemente desaparecio. Seria bueno de alguna manera que parte de la informacion que esta en esa coordenada aparezca en la funcion.

Proyeccion en perspectiva.

La perspectiva es un efecto visual, por el cual los objetos que estan cerca se ven mas grandes que los que estan lejos.

Para entender como funciona la perspectiva, es util el siguiente esquema:


En el esquema el near plane corresponde a la pantalla de la computadora, que esta a una cierta distancia "d" del ojo. El origen de coordenadas (0,0,0) esta en el ojo, que tambien podria ser un camara, por lo cual se lo llama camera space usualmente.
En la imagen solo esta la coordenada y, (y la z que es la distancia al ojo), para simplificar el esquema, pero la coordenada x funciona de la misma manera.

Volviendo a la perspectiva, si quisieramos que lo que esta mas lejos se viera mas pequeño, podriamos dividir por z y listo:

P:R3-->R2 / P(x,y,z) = (x/z,y/z)

Esta nueva proyeccion si bien esta bastante cerca de lo que queremos lograr, todavia tiene algunos problemas: en la medida que la z se hace cada vez mas pequeña, el valor de la proyeccion tiende a infinito. Por otra parte no podemos permitir que la z sea infinitamente grande, debido a la precision limitada de la computadora.

Clipping.

Entonces, lo primero que tenemos que hacer es acotar los valores de z entre ciertos limites que aseguren que exista la proyeccion y que se pueda mapear con una determinada precision.
Clipping es el proceso por el cual se elimina o se descartan los valores que estan fuera de cierto rango. En nuestro caso, la variable z tiene que ir entre el near plane y el far plane. (Si bien el far plane lo podriamos ubicar arbitrariamente lejos del near plane, dentro de los parametros logicos)

Volviendo a la imagen, el punto p = (x,y,z) que esta en el mundo real, y expresado en camera space (o coordenadas del ojo) , y lo queremos proyectar en la plantalla de la computadora, que es el near plane, y en el esquema esta representado por ps = (xs,ys) (que seria la coordenada en screen space).

Por triangulos semejantes, se tiene que
y/z = ys/d

con lo cual
ys = d * y/z

Ahora, queremos "normalizar" estos valores, para que vayan entre -1 y 1, de esta forma se pueden adaptar a cualquier resolusion de pantalla (800x600, 1024x768 etc)

Entonces:

H = Alto de la pantalla, y d = znear (como se puede ver en el esquema)
ys = y * (2 * znear ) / ( z * H)

Notar que la formula sigue siendo ys = y/z * K

de la misma forma
xs = x * (2 * znear ) / ( z * W)
donde W = ancho de la pantalla

Como cualquier cosa que se vaya de pantalla no se va a ver,
resulta que -1<=xs<=1 ; -1<=ys<=1

Que hacemos con la z?

La z se comporta diferente de las otras 2. Primero porque como no se puede ver nada que este detras de la pantalla, y por convencion zs va entre cero y 1, y no entre -1 y 1 como xs e ys.
El otro motivo tiene que ver con las:

Coordenadas Homogeneas.

Como todas estas ecuaciones tienen que ir a parar a una matriz de 4x4 para poder utilizar el hardware de la placa de video, que tiene implementadas multiplicaciones de matrices. Y como tenemos que dividir tanto la x como la y, por el valor z (constante mas, constante menos), aca entran en juego las coordenadas homogeneas.

En las coordenadas homogeneas todo punto en espacio real (x,y,z) esta definido por 4 coordenadas

(x * w ,y * w ,z * w , w) con w !=0

dichas coordenadas se llaman homogeneas y transforman el espacio R3 en el espacio proyectivo, pero eso es otro tema (de topologia)

Para obtener las coordenadas reales hay que dividir por w, es decir si (X,Y,Z,W) son homogeneas, para obtener x real, se hace x = X/W y = Y/W z = Z/W
En concreto es un artificio algebraico para poder introducir una division en una multiplicacion de matrices.

Nota: agregar una dimension adicional permite introducir traslaciones junto con rotaciones y escalados en la misma matriz.

Poniendo X e Y en la matriz de Proyeccion.

Antes de seguir con Z, vamos a ver que forma va tomando la matriz de proyeccion:

            | 2*Zn/W         0         0     0 | 
(x,y,z,1) x | 0             2*Zn/H     0     0 | 
            | 0             0         A?     1 | 
            | 0             0         B?     0 | 


Vemos que hasta aca se verifican:

X = 2*x*Zn/W
Y = 2*y*Zn/H
Z = Az + B
W = z

Haciendo la division por W, nos queda
xs = x * (2 * Zn ) / ( z * W)
ys = y * (2 * Zn ) / ( z * H)

Tal como queriamos, hasta aca estamos bien.
Ahora, para la Z podemos tocar las constantes A y/o B en la matriz, sin romper nada de lo que estaba.

Z = Az + B

Y luego de dividir por W=z, nos quedaria:

Zs = A + B/z

Pero sabemos que si
 z = Zn implica que  Zs = 0 y si
 z = Zf  impplica que Zs = 1, luego

0 = A +B/Zn
1 = A +B/Zf

Se trata de 2 ecuaciones con 2 incognitas (A y B), que despejando se resuelven asi:

A = Zf / (Zf-Zn)
B = Zf*Zn / (Zn-Zf)

Entonces, la Zs nos quedaria asi:

Zs = Zf/(Zf-Zn) + Zf*Zn / (z * (Zn-Zf))

Poniendo todo junto.

        | 2*Zn/W         0         0             0 | 
MProj = | 0             2*Zn/H     0             0 | 
        | 0             0         Zf/(Zf-Zn)     1 | 
        | 0             0         Zf*Zn/(Zn-Zf)  0 | 

Semi-Interactive Rendering

Entre el real time rendering dibujando a mas de 30 fps y las imagenes casi fotograficas generadas con los raytracer modernos, que llegan a tardar mas de 30min en una maquina de ultima generacion, se habre una brecha no muy explotada de aplicaciones que precisan crear graficas de la mayor calidad posible en un tiempo razonable que van desde uno pocos segundos hasta algunos minutos. Sin las limitaciones del realtime, se puede aprovechar la gpu para lograr efectos de sombras, reflexiones, perceptualmente correctas.