2011-09-29 8 views
5

Estoy tratando de crear un motor de gráficos 3D simple y he encontrado y utilizado las ecuaciones que encontré aquí: http://en.wikipedia.org/wiki/3D_projection#cite_note-0. (Tengo cálculos para Dx, Dy, Dz y Bx, By)Matriz de clip para proyección en perspectiva 3D

Funciono, pero cuando giro la cámara, las líneas comienzan a volar por todas partes y eventualmente ves que los polígonos que se apagaron comienzan a volver. en el lado opuesto de la pantalla (se puede ir aquí: http://mobile.sheridanc.on.ca/~claassen/3d.html y utilizar las teclas W, a, S y D para girar la cámara para ver lo que estoy hablando)

leí esta discusión: How to convert a 3D point into 2D perspective projection? donde hablamos sobre el uso de una matriz de clip, pero todavía estoy un poco confundido sobre cómo usar exactamente uno. Además, no estoy seguro de si estoy usando 'coordenadas homogéneas' como se describe en la discusión.

Respuesta

18

Después de multiplicar por la matriz de proyección en perspectiva (también conocida como matriz de clip) se termina con un vector homogéneo de 4 vectores [x, y, z, w]. Esto se llama npc (coordenadas de proyección normalizadas) y también se llama coordenadas de clip. Para obtener coordenadas 2D en la pantalla se suele usar algo así como

xscreen = (x/w) * screen_width 
yscreen = (y/w) * screen_width 

Para los puntos en frente de la cámara esto le da lo que quiere. Pero los puntos detrás de la cámara tendrán w < 0 y obtendrá valores que se correlacionan con coordenadas de pantalla válidas aunque el punto esté detrás de la cámara. Para evitar esto, necesitas cortar. Cualquier vértice que tenga un w < 0 debe recortarse.

Una cosa rápida para intentar es simplemente no dibujar ninguna línea si cualquiera de los vértices tiene w < 0. Esto debería corregir los extraños polígonos que aparecen en su escena. Pero también eliminará algunas líneas que deberían ser visibles.

Para solucionar por completo el problema que necesita para recortar todas las líneas que tienen un vértice en frente de la cámara y un vértice detrás de la cámara. Recortar significa cortar la línea por la mitad y tirar la mitad que está detrás de la cámara. La línea es "recortada" por un plano que atraviesa la cámara y es paralelo a la pantalla de visualización. El problema es encontrar el punto en la línea que corresponde a este plano (es decir, donde la línea se cruza con el plano). Esto ocurrirá en el punto en la línea donde w == 0.Puede encontrar este punto, pero luego, cuando se intenta encontrar la pantalla coordina

xscreen = (x/w) * screen_width 
yscreen = (y/w) * screen_width 

se termina dividiendo por 0 (w == 0). Esta es la razón del "plano de recorte cercano". El plano de recorte cercano también es paralelo a la pantalla de visualización pero está en frente de la cámara (entre la cámara y la escena). La distancia entre la cámara y el plano de delimitación cercano es el parámetro de "cerca" de la matriz de proyección:

[ near/width ][  0  ][   0    ][  0  ] 
[  0  ][ near/height ][   0    ][  0  ] 
[  0  ][  0  ][(far+near)/(far-near) ][  1  ] 
[  0  ][  0  ][-(2*near*far)/(far-near)][  0  ] 

para recortar al plano cerca de usted tiene que encontrar el punto de la línea que corta el plano de delimitación cercano. Este es el punto donde w == cerca. Así que si usted tiene una línea con vértices v1, v2, donde

v1 = [x1, y1, z1, w1] 
v2 = [x2, y2, z2, w2] 

es necesario comprobar si cada vértice está por delante o por detrás del plano de recorte cercano. V1 está al frente si w1> = cerca y detrás si w1 < cerca. Si v1 y v2 están ambos al frente, dibuja la línea. Si v1 y v2 están detrás, no dibuje la línea. Si v1 es delante y detrás v2 es entonces usted necesita para encontrar vc donde la línea se cruza con el plano de recorte cerca de:

n = (w1 - near)/(w1 - w2) 
xc = (n * x1) + ((1-n) * x2) 
yc = (n * y1) + ((1-n) * y2) 
zc = (n * z1) + ((1-n) * z2) 
vc = [xc, yc, zc, wc] 

Ahora trazar la línea entre v1 y VC.

+0

No puedo agradecerle lo suficiente por la respuesta bien escrita. Esto me ha ayudado tremendamente ... no puedo votar lo suficiente tampoco. – shbi

+0

Esta es una gran respuesta, pero hay algunas cosas que no tengo claras. Primero, ¿te falta la línea 'wc = (n * w1) + ((1 - n) * w2)'? Además, ¿su matriz de proyección P se multiplica a la derecha, es decir, v_e * P? Lo que es más importante, ningún renderizador que haya utilizado me obliga a especificar el plano cercano en el momento del sorteo. ¿Cómo se puede realizar este recorte cuando se desconoce el valor cercano? – Qualia

+0

Probablemente haya encontrado una respuesta. Claramente, recorte z, constriñe w, ya que son linealmente dependientes. El problema que tuve es que si está interpolando w, está interpolando el valor del clip con el que prueba z. De hecho, las ecuaciones no son tan difíciles como pensaba. Para un vértice v_3 dado por v_1 y v_2, cuya línea interseca el plano del clip, 'w_3 = w_1 + r * (w_2-w_1)' y 'a_3 = a_1 + r * (a_2-a_3)', donde 'a_n = dot (avión, v_n) '. Pero a_3 es igual al valor del clip, w_3, entonces 'a_1 + r * (a_2-a_1) = w_1 + r * (w_2-w_1)'. Resuelve para r, y listo. (Espero). – Qualia

4

Esto podría ser un malentendido de la terminología. La matriz de clip se conoce más apropiadamente como una matriz de proyección. En OpenGL al menos, la matriz de proyección transforma coordenadas homogéneas 4D en ver espacio de coordenadas (VCS) en espacio de coordenadas de recorte (CCS). La proyección desde el CCS al espacio de coodinación del dispositivo normalizado (NDCS) requiere la división de perspectiva, es decir, dividir cada componente por el componente W. El recorte se realiza correctamente antes de este paso. Entonces, una 'matriz de recorte' no elimina la necesidad de recortar la geometría antes de la proyección. Espero haberte entendido, y esto no suena condescendiente.

Dicho esto, creo que obviamente tienes la matriz de proyección correcta, funciona. Sospecho que los vértices que pasan detrás del ojo tienen W negativo, lo que significa que deben recortarse; pero también sospecho que tienen Z negativa, por lo que la división está dando un valor Z positivo. Si realmente desea recortar la geometría, en lugar de descartar triángulos enteros, realice una búsqueda de "recorte homogéneo". Si realmente no está trabajando en un espacio homogéneo 4D, puede comenzar mirando el recorte 3D 'Sutherland-Hodgman'.

Cuestiones relacionadas