Java Open GL

Download Report

Transcript Java Open GL

Java Open GL
Taller práctico
Objetivos de aprendizaje







Conocer las clases de Java que sirven de
interfaz para acceder a la funcionalidad de
OpenGL
Crear una aplicación mínima que utilice JOGL.
Posición de cámara y dibujo de una figura
básica
Dibujo de figuras empleando GLU
Iluminación
Texturas
Movimiento
Espacios y puntos de visión

Una coordenada z positiva sale hacia la pantalla, una coordenada z negativa
va hacia dentro de la pantalla. La posición de la camara está determinada por
un punto, otro punto al cual se dirige la vision y un vector que define el
punto hacia donde se dirije la vista en el cielo (tambien un angulo de vision
pero ese se revisará posteriormente).
Integración de clases OpenGL
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
public MyJoglCanvas(int width,int height, GLCapabilities capabilities){}
public void init(GLAutoDrawable drawable) {}
public void reshape(GLAutoDrawable drawable,int x,int y,int,
width,int height) {}
public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged,
boolean deviceChanged) {}
public void display(GLAutoDrawable drawable) {}
}
Implementar métodos de GLEventListener

El constructor especifica el tamaño inicial (size) de la ventana
así como también el mínimo de capacidades (capabilities)
requeridas para OpenGL.

El método init() se invoca por el evento AWT tan pronto como
la ventana esté lista; se pueden hacer algunas configuraciones
globales aquí.

Toda vez que se redimensione el canvas, se invocará reshape()

Ingoraremos completamente el método displayChanged. Este
se usa cuando se manejan múltiples escenarios.

Finalmente display(), se invoca cada vez que se re-dibuja la
escena. Aquí es donde se desarrolla todo el dibujo.
Ventana en blanco
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public MyJoglCanvas(int width, int height, GLCapabilities capabilities)
{
super(capabilities);
setSize(width, height);
}
. . .
}
// En main se define el modo de video
GLCapabilities capabilities = new GLCapabilities();
capabilities.setRedBits(8);
capabilities.setBlueBits(8);
capabilities.setGreenBits(8);
capabilities.setAlphaBits(8);
Inicialización del Canvas (GLCanvas)
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
drawable.setGL(new DebugGL(gl));
// Configuracion global.
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glShadeModel(GL.GL_SMOOTH);
gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
gl.glClearColor(0f, 0f, 0f, 1f);
// Iniciar animador
animator = new FPSAnimator(this, 60);
animator.start();
}
. . .
}
Métodos y configuraciones de inicialización



Las primeras dos habilitan los buffers Z (siempre
necesarios para el dibujo en 3D) con la ultima
configuración (dibujar un rectangulo, una linea
será visible).
Se selecciona un modelo de sombra (GL_SMOOTH),
y hace la corrección necesaria (GL_NICEST).
El color de borrado es el color: negro (Black) sin ser
traslucido (alpha es 1), especificado para RGBA
como numeros flotantes.
Redimension y despliegue
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void reshape(GLAutoDrawable drawable, int x, int y,
int width, int height) {
GL gl = drawable.getGL();
gl.glViewport(0, 0, width, height);
}
// El metodo display se invocará en cada ciclo de animación
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
. . .
}
. . .
}
Colocación de cámara
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void init(GLAutoDrawable drawable) {
glu = new GLU();
}
public void display(GLAutoDrawable drawable) {
setCamera(gl, glu, 100);
}
private void setCamera(GL gl, GLU glu, float distance) {
// Cambiar a matriz de proyeccion.
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
// Perspectiva.
float widthHeightRatio = (float) getWidth() / (float) getHeight();
glu.gluPerspective(45, widthHeightRatio, 1, 1000);
glu.gluLookAt(0, 0, distance, 0, 0, 0, 0, 1, 0);
// Regresar a la matriz de modelo de vista
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
}
Parámetros de cámara y punto de visión



OpenGL calcula las coordenadas utilizando
matrices. Para la cámara, cambiamos a la
matriz PROJECTION, y para todo lo demás
usamos la matriz MODELVIEW.
El método glLoadIdentity(), reinicializa todas las
configuraciones de matriz previas que se hayan
hecho.
GLU se hace cargo de la propia perspectiva. Se
especifica un ángulo de 45° con respecto a la
proporción de ancho y alto de la ventana.
Dirección de la vista gluLookAt()

El método gluLookAt(), toma tres grupos de
coordenadas 3D:

(0,0,distance): Donde estamos parados (“eye”)


(0,0,0) : Hacia donde dirigimos la vista (“at”)


Aquí solo se modifica la coordenada Z
Directamente al centro de las coordenadas del sistema
(0,1,0) : Hacia donde apunta nuestra cabeza en el
cielo (“up”)

Directamente erguidos, sobre la coordenada Y.
Despliegue de un triangulo
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void display(GLAutoDrawable drawable) {
setCamera(gl, glu, 100);
// Definir el triangulo.
gl.glColor3f(0.9f, 0.5f, 0.2f);
gl.glBegin(GL.GL_TRIANGLE_FAN);
gl.glVertex3f(-20, -20, 0);
gl.glVertex3f(+20, -20, 0);
gl.glVertex3f(0, 20, 0);
gl.glEnd();
}
}
Despliegue de una esfera
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void display(GLAutoDrawable drawable) {
setCamera(gl, glu, 100);
// Dibujar una esfera (estilos elegibles: FILL, LINE, POINT).
gl.glColor3f(0.3f, 0.5f, 1f);
GLUquadric earth = glu.gluNewQuadric();
glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL);
glu.gluQuadricNormals(earth, GLU.GLU_FLAT);
glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
final float radius = 6.378f;
final int slices = 16;
final int stacks = 16;
glu.gluSphere(earth, radius, slices, stacks);
glu.gluDeleteQuadric(earth);
}
}
Iuminación
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void display(GLAutoDrawable drawable) {
// Preparar los parametros de luz.
float SHINE_ALL_DIRECTIONS = 1;
float[] lightPos = {-30, 0, 0, SHINE_ALL_DIRECTIONS};
float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1f};
float[] lightColorSpecular = {0.8f, 0.8f, 0.8f, 1f};
// Establecer los parametros de luz.
gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPos, 0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightColorAmbient, 0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, lightColorSpecular, 0);
// Habilizar iluminacion en GL.
gl.glEnable(GL.GL_LIGHT1);
gl.glEnable(GL.GL_LIGHTING);
// Establecer las propiedades de los materiales.
float[] rgba = {0.3f, 0.5f, 1f};
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.5f);
// Dibujar la esfera (possible styles: FILL, LINE, POINT).
GLUquadric earth = glu.gluNewQuadric();
...
}
}
Parámetros para iluminación


La iluminación es donde se intercambia todo el modelo
de color. Se especifica la forma de una superficie y como
reacciona a la luz en su espectro RGB y añadimos las
fuentes de luz con su propio espectro RGB (también
como en el mundo real).
Existen dos tipos de luz, AMBIENT y ESPECULAR, y
nuestra superficie de material reaccionará en esta luz.


La luz ambiental (AMBIENT) está en todas partes, sin una
fuente particular. Típicamente se utiliza una intensidad de 0.2
(valores entre 0 y 1).
La luz ESPECULAR, es la que proviene de una lámpara y que
se refleja en las superficies. Esta es la que da típico efecto 3D.
Normalmente se utiliza una intensidad de 0.8 (valores entre 0 y
1).
Posición y color de la luz


Primero, se definen los parámetros de la luz: la
posición de la luz en el ejemplo en las
coordenadas (-30,0,0), ligeramente a la
izquierda, con un cuarto elemento establecido
en uno. Esto es necesario para iluminar en
todas las direcciones.
Siguiendo, se establece el valor RGBA de la luz
AMBIENT y ESPECULAR. El valor alpha es
siempre 1, significa opacidad completa (“sin
efecto de cristal”)
Encendiendo cada luz y todo el sistema


Las siguientes tres líneas, asociamos éstos
parámetros a una luz específica, denominada
LIGHT1, especificando los parámetros a
establecer, los arreglos apropiados y un índice
donde iniciar en el arreglo. Finalmente se
habilita la luz LIGHT1 y lo más importante,
habilitar la iluminación “LIGHTING”.
Cabe mencionar, que si no se cambia la luz
entre frames, se puede colocar todo en el
método init() en lugar del método display().
Esto podría brindar un poco más de eficiencia.
Características del material


Además de definir las luces, es necesario
también que se especifique como reaccionará el
material a la luz en el espectro RGB: lo que
solía ser el color. Tomamos el mismo color azul
como anteriormente y se agrega un valor alfa de
uno (completamente opaco); entonces se
especifica la reacción tanto de la luz ambiente
como la especular.
La última característica antes de dibujar es el
grado de brillantez o SHININESS, el cual
especifica que tan fuerte es la reflexión en la
superficie (0..100). En el ejemplo se establece a
0.5, lo cual indica que no hay mucho efecto.
Texturas


Una textura brinda una forma mucho más real,
agregando un patrón mucho más agradable.
Se requieren dos pasos: primero, necesitamos
cargar la textura desde el archivo PNG y
ensamblarlo en una forma que JOGL lo pueda
manejar. Segundo, justo antes de realizar un
dibujo, se le tiene que indicar a JOGL que la
siguiente figura o forma a dibujar debe usar la
textura (“asociar o “bind”, la textura al contexto
GL”)
Carga de Texturas

Se utiliza TextureIO, TextureData y Texture
para leer, procesar y almacenar la textura.
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void init(GLAutoDrawable drawable) {
// Cargar los archivos de textura
try {
InputStream stream = getClass().getResourceAsStream("earth.png");
TextureData data = TextureIO.newTextureData(stream, false, "png");
earthTexture = TextureIO.newTexture(data);
} catch (IOException exc) {
exc.printStackTrace();
System.exit(1);
}
}
}
Aplicación de texturas
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void display(GLAutoDrawable drawable) {
// Establecer las propiedades del material.
float[] rgba = {1f, 1f, 1f};
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.5f);
// Aplicar textura
earthTexture.enable();
earthTexture.bind();
// Dibujar esfera.
GLUquadric earth = glu.gluNewQuadric();
glu.gluQuadricTexture(earth, true);
}
. . .
}
Movimiento
public class MyJoglCanvas extends GLCanvas implements GLEventListener {
. . .
public void display(GLAutoDrawable drawable) {
// Guardar el estado anterior.
gl.glPushMatrix();
// Calcular la posicion del satelite.
satelliteAngle = (satelliteAngle + 1f) % 360f;
final float distance = 10.000f;
final float x = (float) Math.sin(Math.toRadians(satelliteAngle)) * distance;
final float y = (float) Math.cos(Math.toRadians(satelliteAngle)) * distance;
final float z = 0;
gl.glTranslatef(x, y, z);
gl.glRotatef(satelliteAngle, 0, 0, -1);
gl.glRotatef(45f, 0, 1, 0);
// Establece el color plata y deshabilita el texturizado.
gl.glDisable(GL.GL_TEXTURE_2D);
float[] ambiColor = {0.3f, 0.3f, 0.3f, 1f};
float[] specColor = {0.8f, 0.8f, 0.8f, 1f};
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, ambiColor, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, specColor, 0);
gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 90f);
Movimiento
. . .
// Draw satellite body.
final float cylinderRadius = 1f;
final float cylinderHeight = 2f;
GLUquadric body = glu.gluNewQuadric();
glu.gluQuadricTexture(body, false);
glu.gluQuadricDrawStyle(body, GLU.GLU_FILL);
glu.gluQuadricNormals(body, GLU.GLU_FLAT);
glu.gluQuadricOrientation(body, GLU.GLU_OUTSIDE);
gl.glTranslatef(0, 0, -cylinderHeight / 2);
glu.gluDisk(body, 0, cylinderRadius, cylinderSlices, 2);
glu.gluCylinder(body, cylinderRadius, cylinderRadius, cylinderHeight,
slices, stacks);
gl.glTranslatef(0, 0, cylinderHeight);
glu.gluDisk(body, 0, cylinderRadius, cylinderSlices, 2);
glu.gluDeleteQuadric(body);
gl.glTranslatef(0, 0, -cylinderHeight / 2);
}
…
}