Viewports e Interacción con el Mouse

Anuncio
Viewports e Interacción
con el Mouse
CG 2014.
Introducción
Los vértices sufren transformaciones para
pasar del mundo a la pantalla.
Estas transformaciones, las especificamos
mediante matrices.
Ventana del mundo
● Luego de modelar los objetos y la escena
2D (mediante transformaciones, con más
matrices!!)
● Debemos seleccionar qué área de este
mundo queremos mostrar.
● Esto lo hacemos especificando una matriz
de proyección.
○ Esta matriz también va a determinar la forma en la
que veremos la escena (proyección).
En OpenGL
● Para especificar esa matriz de proyección,
se utiliza(ba):
glOrtho(left, right, bottom, top, near, far);
gluPerspective(fovy, aspect, near, far);
● Ahora, nosotros debemos ocuparnos de
crear la matriz.
● Pero OpenTK provee clases y estructuras
para trabajar con matrices y vectores.
○ Estas clases poseen operadores sobrecargados
para que podamos utilizarlos más fácilmente. (+, -, *,
/)
En OpenTK
Matrix4 projMat;
projMat = Matrix4.CreateOrthographicOffCenter(
left, right, bottom, top, zNear, zFar);
projMat = Matrix4.CreatePerspective(
fovy, aspect, zNear, zFar);
Con esto creamos una matriz. Resta hacer que
nuestro shader (de vértices) las utilice.
● Usar variables “uniform”:
Ventana (En 2D)
Ventana (En 3D)
Viewport
● La última de las transformaciones es la de
Viewport.
● La transformación de viewport especifica en
qué región de la pantalla será dibujada la
escena. (en nuestro caso, en qué región del
GLControl)
● Al trabajar sobre la pantalla, las
coordenadas son números enteros (pixels).
(A diferencia de las coordenadas de la
ventana, que son números reales).
En OpenGL
En OpenGL especificamos la información del
viewport mediante:
glViewport(x, y, width, height);
OpenTK sobrecarga este método:
GL.Viewport(x, y, width, height);
GL.Viewport(rectangle);
GL.Viewport(point, size);
GL.Viewport(size);
Viewport
Coordenadas de la ventana (mi glControl),
según OpenGL
y
w
h
(x,y)
x
Relación de aspecto
● Relación de aspecto = ancho / alto
○ Si la región del mundo que queremos dibujar tiene
una relación de aspecto distinta a la del viewport,
veremos nuestra escena deformada.
Relación de aspecto
● Podemos:
○ Calcular las dimensiones del viewport en función de
la relación de aspecto de la ventana.
○ Ajustar la ventana en función de las dimensiones
del viewport.
● ¿Que diferencia hay?
○
Ejemplo: ex Laboratorio 3
¿Cómo lo logramos?
Tenemos que dibujar la misma figura 2 veces:
Primero:
● Una ventana 2D que abarque a toda la
figura.
● Un viewport a la izquierda.
Luego:
● Una ventana que abarque sólo una parte
de la figura (zoom).
● Un viewport a la derecha.
Pseudocódigo
void On_Paint(){
...
SetearViewport(viewport1);
SetearVentana(projMatrix1);
figura.Dibujar();
SetearViewport(viewport2);
SetearVentana(projMatrix2);
figura.Dibujar();
...
}
Pseudocódigo
● Podemos utilizar dos variables de tipo
Rectangle (System.Drawing) para guardar
información de los viewports.
● Y dos variables de tipo OpenTK.Matrix4
para las matrices de proyección.
Rectangle viewport1 = new ...;
Rectangle viewport2 = new ...;
Matrix4 projMat1 = Matrix4.CreateOrthog..;
Matrix4 projMat2 = Matrix4.CreateOrthog...;
Pseudocódigo
¿Dónde actualizamos los valores de los
viewports?
void glControl1_Resize(..){
//Sacar las cuentas en función de glControl1.Width
//glControl1.Height y el aspectRatio de la ventana
viewport1.X = ...;
// 2D
viewport1.Y = ...;
viewport1.Width = ...;
viewport1.Height = ...;
viewport2.X = ...;
...
glControl1.Invalidate();
};
Interacción con el mouse
● Aparte de la interacción mediante controles
(botones, sliders, checkboxes, etc),
podemos interactuar con el glControl
utilizando el mouse.
● ¿Qué interacciones serán posibles?
○
○
○
○
Manejar la cámara.
Seleccionar un área para hacer zoom.
Seleccionar un objeto de la escena. (Picker).
Etc...
Interacción con el Mouse
● El componente GLControl (al igual que
todos los componentes de Windows) tiene el
evento Click(...) que se dispara cuando se
realiza un click de mouse sobre el
componente.
OpenGL vs Windows
x
y
y
x
Usan el eje Y distinto!
Picker 3D
● Existen varias formas de implementar un
picker 3D:
○ Utilizando el buffer de stencil.
○ Utilizando el buffer de profundidad.
○ Revertir las transformaciones.(Unproject)
● Veremos la última, que es la más elegante,
aunque presenta sus ventajas y
desventajas.
○ http://myweb.lmu.edu/dondi/share/cg/unprojectexplained.pdf
Picker 3D - El problema
● Cuanto windows nos reporta (mediante un
evento) que se realizó un click en la posición
(x, y) del glControl, ¿A qué posición de la
escena 3D corresponde?
● ¿En qué espacio de coordenadas vemos la
información del framebuffer?
Unproject
● Los vértices se fueron transformando, hasta
llegar a coordenadas de pantalla.
● Ahora quiero el camino inverso, es decir, a
partir de una posición en pantalla,
determinar a qué posición en el mundo
corresponde.
Unproject
● De eso se encarga(ba) la función
gluUnproject(...);
● Esta función no está disponible en OpenTK.
La tenemos que implementar!
● Consultar la documentación de esta
función, para comprender bien el
significado de los parámetros.
Unproject
Vector3 UnProject(Vector3 win,
Matrix4 mViewMat,
Matrix4 projMat,
Rectangle viewport)
{
Vector3 resul = Vector3.Zero;
Vector4 _in = Vector4.Zero;
Vector4 _out = Vector4.Zero;
Matrix4 oneMatrix;
//Combinamos las dos matrices y las invertimos.
oneMatrix = Matrix4.Multiply(mViewMat, projMat);
oneMatrix.Invert();
Unproject (cont.)
_in.X = win.X;
_in.Y = win.Y;
_in.Z = win.Z;
_in.W = 1.0f;
//Map x and y from window coordinates.
_in.X = (_in.X - viewport.X) / viewport.Width;
_in.Y = (_in.Y - viewport.Y) / viewport.Height;
//Map to range -1 to 1.
_in.X = _in.X * 2 - 1;
_in.Y = _in.Y * 2 - 1;
_in.Z = _in.Z * 2 - 1;
Unproject (cont.)
//Antitransformamos.
_out = Vector4.Transform(_in, oneMatrix);
if ((_out.W > float.Epsilon) ||
(_out.W < -float.Epsilon))
{
_out.X = _out.X / _out.W;
_out.Y = _out.Y / _out.W;
_out.Z = _out.Z / _out.W;
}else{
throw new Exception("UnProject: No pudo
antitransformar.");
}
Unproject (cont.)
resul.X = _out.X;
resul.Y = _out.Y;
resul.Z = _out.Z;
return resul;
};
Este método lo vamos a utilizar en el
manejador del evento Click();
Unproject
● La posición en coordenadas de ventana,
(window) tiene 3 componentes (x, y, z).
○ La “ventana” es tridimensional.
● Nosotros solamente tenemos las
coordenadas bidimensionales (x, y), que nos
reporta el componente.
○ Un “punto” en la pantalla, corresponde a toda una
línea en la ventana 3D.
Pantalla vs. Ventana
Unproject
● ¿Cómo determinamos las coordenadas de
este segmento de línea (o rayo)?
● Utilizamos:
○ zwin = 0.0, para el plano near;
○ zwin = 1.0, para el plano far.
● Entonces debemos llamar dos veces a esta
función, una para calcular la posición en el
plano near, y otra en el far.
Secuencia de pasos
● Dada una posición (xpant, ypant):
○ Invertir la coordenada ypant.
○ Obtener los valores de las matrices de modelView,
Projection y el Viewport utilizado.
○ Llamar 2 veces al Unproject(...),
■ una vez con: (xpant, ypant, 0.0)
■ y la segunda con (xpant, ypant, 1.0)
○ Con los dos puntos obtenidos, tenemos la ecuación
de la recta.
○ Recorrer cada objeto de la escena y ver si intersecta
a alguno (usar Bounding Box)
Observaciones
● Si en la matriz modelView, utilizamos
solamente la de view (model = Identidad):
○ La ecuación de la recta, estará en coordenadas del
mundo.
○ Al comparar la recta con cada objeto, pasar las
coordenadas de los mismos a coordendas del
mundo.
● Si usamos la view y la model (de cada obj):
○ La ecuación de la recta estará en coord. del objeto
(comparación directa)
○ Pero, hay que repetir el proceso por cada objeto
(cada uno tiene su matriz de modelado).
Observaciones
● Desventajas:
○ Intersección de los objetos con una recta (se puede
utilizar bounding-box)
○ Si hay varios objetos que intersectan el rayo ¿Cuál
elegimos?
■ Podemos parametrizar la recta como:
L(u) = nearPoint + u * (farPoint - nearPoint);
u en el intervalo [0..1]
u = 0, el plano near
u = 1, el plano far.
Descargar