Viewports e Interacción con el Mousecs.uns.edu.ar/cg/practicos/viewports_ y_click_3D.pdfPero OpenTK...

Post on 09-Mar-2021

1 views 0 download

Transcript of Viewports e Interacción con el Mousecs.uns.edu.ar/cg/practicos/viewports_ y_click_3D.pdfPero OpenTK...

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 OpenTKMatrix4 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

x

y

(x,y)

h

w

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

yx

y

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/unproject-

explained.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óngluUnproject(...);

● 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.

UnprojectVector3 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 nearu = 1, el plano far.