El tutor de nuestro curso online de Desarrollo de Aplicaciones para Android, Víctor Ramírez Las,…
OpenGL: Primitivas, Proyección e Iluminación de objetos 3D
2.
OpenGL: Primitivas, Proyección e Iluminación de objetos 3D
Tipos de Primitivas de OpenGL
Comentamos los tipos de primitivas existentes en OpenGL ES y visualizaremos un cubo utilizando cada una de ellas.
Primitiva | Descripción |
GL_POINTS | Dibuja los vértices como puntos individuales. |
GL_LINES | Cada par de vértices formaría una línea individual. |
GL_LINE_STRIP | Cada vértice está unido con el anterior formando segmentos conectados. |
GL_LINE_LOOP | Al igual que GL_LINE_STRIP, pero implementando un segmento más entre el primer y último vértice. |
GL_TRIANGLES | Tres vértices son interpretados como tres triángulos |
GL_TRIANGLE_STRIP | Cada vértice se une con los dos anteriores para formar un triángulo. |
GL_TRIANGLE_FAN | Cada vértice se une con los dos primeros para formar un triángulo. |
Resultado de las primitivas utilizadas para un cubo.
La proyección: Objetos 3D en superficie 2D.
La proyección de una escena, es aquella que permite representar objetos definidos en 3D en una superficie 2D. Esta proyección, se consigue trazando líneas imaginarias, desde un punto fijo llamado foco, a cada uno de los puntos del objetos 3D que se representa.
Tipos de proyección:
- Paralela: El foco se sitúa en el infinito, siendo las líneas de proyección trazadas paralelas. Si el plano de proyección se sitúa perpendicular a las líneas de proyección se denomina proyección ortogonal.
- Perspectiva: El foco se sitúa en un punto concreto, por lo que las líneas de proyección trazadas no serán paralelas. Si el objeto está cercano al foco se representará más grande, dando una sensación de profundidad. Esta opción es una de las más usadas en gráficos 3D.
OpenGL se encarga de realizar todos los cálculos necesarios para la realización de dicha proyección, con lo que nos evita realizarla manualmente.
Iluminación en objetos 3D
En el siguiente punto, nos centraremos en entender como iluminar una escena, estableciendo un foco, para reflejar luz sobre un objeto 3D, mostrando los diferentes efectos de sombra.
En cualquier objeto 3D representado, lo habitual es que alguna de las caras que forman el objeto, queden a la sombra, y por lo tanto se vean más oscuras. Para ello OpenGL divide el proceso de iluminación en tres partes bien diferenciadas, para dar mucho más realismos a las formas construidas:
- Definir los vectores normales de cada cara: En este punto será necesario calcular la luz reflejada con respecto al ángulo que se forme con el foco de luz. Para ello es necesario definir un vector normal (perpendicular a la superficie apuntando hacia fuera de la parte visible) por cada uno de los vértices de nuestra representación. Por lo tanto es necesarios definir 6 vectores normales por cada una de las caras de un cubo.
- Situar las luces: Para iluminar una escena será necesario situar las luces. OpenGL maneja dos tipos de iluminación:
- Luz ambiental: ilumina toda la escena por igual, ya que esta no proviene de una dirección predeterminada.
- Luz difusa: Viene de una dirección específica, y depende de su ángulo de incidencia para iluminar una superficie en mayor o menor medida.
- Definiendo materiales: OpenGL permite controlar la forma en que la luz se refleja sobre nuestros objetos, que es lo que se conoce como definición de materiales.
Implementación de luz difusa
En nuestra clase encargada de construir la vista (implementa la interfaz GLSurfaceView.Renderer), dentro del método onSurfaceCreated(GL10 gl, EGLConfig config)se deben añadir las siguientes instrucciones:
- En primer lugar habilitamos la iluminación:
gl.glEnable(GL10.GL_LIGHTING); - Y habilitamos la primera luz individualmente: gl.glEnable(GL10.GL_LIGHT0);
- Con el método
glLightfv(int luz,int propiedad,float[] parámetros,int inicio), nos permite introducir las características de la luz, a través de las coordenadas indicadas en los tres primeros parámetros recibidos:
12345678private float[] luzAmbiente = {0.5f, 0.5f, 0.5f, 1.0f};private float[] luzDifusa = {1.0f, 1.0f, 1.0f, 1.0f};private float[] luzPosicion = {0.0f, 0.0f, 2.0f, 1.0f};[...]gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, luzAmbiente,0);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, luzDifusa,0);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, luzPosicion,0); - Y por último se especifica el modo en que OpenGL realizará el sombreado sobre el objeto:
gl.glShadeModel(GL10.GL_SMOOTH);
Implementación de materiales
En nuestra clase encargada de definir los parámetros de representación del objeto, dentro del método draw(GL10 gl) se deben añadir las siguientes instrucciones:
- En primer lugar habilitamos la definición de materiales: gl.glEnable(GL10.GL_COLOR_MATERIAL);
- Y posteriormente, mediante el método
glMaterialfv(int face,int pname, float[] params,int offset) definimos las propiedades de los materiales (estos cambios afectarán al resto de operaciones que estén definidas):
123456private float[] luzAmbiente = {0.5f, 0.5f, 0.5f, 1.0f};private float[] luzDifusa = {1.0f, 1.0f, 1.0f, 1.0f};[...]gl.glMaterialfv(GL10.GL_FRONT, GL10.GL_DIFFUSE, luzDifusa,0);gl.glMaterialfv(GL10.GL_FRONT, GL10.GL_AMBIENT, luzAmbiente,0);
Aquí puedes consultar la documentación oficial de la interfaz GL10
Continuaremos en el siguiente tutorial desarrollando un proyecto ejemplo para mostrar como iluminar objetos 3D e implementar eventos de interacción como pantalla táctil o acelerómetro.
Contenidos elaborados por Academia Android – José Antonio Gázquez