Programación Open GL ES en iPhone e iPod touch

53
Gráficos 3D para iPhone con OpenGL ES Manuel R. Freire Interactive Fan

description

Fundamentos sobre programación OpenGL dirigida a la creación de juegos para el iPhone e iPod touch.

Transcript of Programación Open GL ES en iPhone e iPod touch

Gráficos 3D para iPhone con OpenGL ES

Manuel R. FreireInteractive Fan

© Electronic A

rts, Inc.

© D

igital Chocolate, Inc.

© Electronic A

rts, Inc.

© Firem

int

© ngm

oco, Inc.

© C

hillingo Ltd.

© ngm

oco, Inc.

© D

igital Legends©

SGN

Índice

• Introducción a OpenGL ES para iPhone

• Operaciones básicas

• El mundo 3D

• Texturas

• Shaders (sólo OpenGL ES 2.0)

Introducción a OpenGL ES para iPhone

OpenGL ES

• OpenGL for Embedded Systems

• API de gráficos 3D de bajo nivel

• Permite especificar la geometría y propiedades de objetos (color, iluminación, texturas)

• Subconjunto de OpenGL

Versiones de OpenGL ES

Hardware Dispositivos OpenGL

OpenGL ES 1.1

OpenGL ES 2.0

Función fijaiPhone

iPhone 3GiPod touch

1.5

Programable (shaders)

iPhone 3G S 2.0

Un mundo de vértices

• Los objetos se definen mediante conjuntos de vértices

• Cada vértice puede tener asociada información de color y textura

• Los vértices se agrupan en primitivas: triángulos, puntos, líneas, tiras de triángulos, etc.

PrimitivasPrimitiva Descripción

GL_POINTS Conjunto de puntos(N vértices → N puntos)

GL_LINE_STRIP Conjunto de segmentos conectados(N vértices → N-1 segmentos)

GL_LINE_LOOP Conjunto cíclico de segmentos conectados(N vértices → N segmentos)

GL_LINES Conjunto de segmentos desconectados(N vértices → N/2 segmentos)

GL_TRIANGLE_STRIP Tira de triángulos(N vértices → N-2 triángulos)

GL_TRIANGLE_FAN Abanico de triángulos(N vértices → N-2 triángulos)

GL_TRIANGLES Conjunto de triángulos(N vértices → N/3 triángulos)

Ejemplo: Cuadrado

• 4 vértices

• Primitivas:

➡ Opción 1: dos triángulos

➡ Opción 2: abanico de triángulos

➡ Opción 3: tira de triángulos

v3 = (0, 1, 0) v2 = (1, 1, 0)

v0 = (0, 0, 0) v1 = (1, 0, 0)

T1: (v0, v2, v3)T2: (v0, v1, v2)

Anatomía de una aplicación 3D (simplificada)

1. Inicializar OpenGL ES

1.1. Crear un contexto OpenGL ES (EAGLContext)

1.2. Asociar el contexto a una vista (EAGLView)

2. Bucle (cada frame):

2.1. Actualizar estado de la aplicación

2.2. Dibujar

Plantilla “OpenGL ES Application” de XCode

Operaciones básicas

Borrar la pantalla• Pinta todo el buffer de un único color

• Se hace (al menos) al inicio de cada frame

Borrar la pantalla• Pinta todo el buffer de un único color

• Se hace (al menos) al inicio de cada frame

glClearColor(0.0f, 1.0f, 0.0f, 1.0f);

Borrar la pantalla• Pinta todo el buffer de un único color

• Se hace (al menos) al inicio de cada frame

glClearColor(0.0f, 1.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);

Dibujar primitivas

• Los vértices se almacenan en un array y se dibujan con glDrawArrays

Dibujar primitivas

glEnableClientState(GL_VERTEX_ARRAY);

• Los vértices se almacenan en un array y se dibujan con glDrawArrays

Dibujar primitivas

glEnableClientState(GL_VERTEX_ARRAY);const GLfloat vertices[] = {

-0.5f, -0.5f,0.5f, -0.5f,-0.5f, 0.5f,0.5f, 0.5f,

};glVertexPointer(2, GL_FLOAT, 0, vertices);

• Los vértices se almacenan en un array y se dibujan con glDrawArrays

Dibujar primitivas

glEnableClientState(GL_VERTEX_ARRAY);const GLfloat vertices[] = {

-0.5f, -0.5f,0.5f, -0.5f,-0.5f, 0.5f,0.5f, 0.5f,

};glVertexPointer(2, GL_FLOAT, 0, vertices);glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

• Los vértices se almacenan en un array y se dibujan con glDrawArrays

Seleccionar un color

• El color se define en RGBA

• Por defecto, las operaciones que utilizan color utilizan el último color seleccionado

Seleccionar un color

• El color se define en RGBA

• Por defecto, las operaciones que utilizan color utilizan el último color seleccionado

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

Seleccionar un color

• El color se define en RGBA

• Por defecto, las operaciones que utilizan color utilizan el último color seleccionado

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);dibujaObjeto1(); 1

Seleccionar un color

• El color se define en RGBA

• Por defecto, las operaciones que utilizan color utilizan el último color seleccionado

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);dibujaObjeto1();glColor4f(1.0f, 0.0f, 0.0f, 1.0f);

1

Seleccionar un color

• El color se define en RGBA

• Por defecto, las operaciones que utilizan color utilizan el último color seleccionado

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);dibujaObjeto1();glColor4f(1.0f, 0.0f, 0.0f, 1.0f);dibujaObjeto2();

1

2

Seleccionar un color

• El color se define en RGBA

• Por defecto, las operaciones que utilizan color utilizan el último color seleccionado

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);dibujaObjeto1();glColor4f(1.0f, 0.0f, 0.0f, 1.0f);dibujaObjeto2();dibujaObjeto3(); 3

1

2

El mundo 3D

El mundo 3D en OpenGL

• OpenGL representa el mundo 3D a través de matrices a las que se aplican transformaciones (multiplicaciones)

• Dos matrices fundamentales:

‣ Modelo-vista (GL_MODELVIEW)

‣ Proyección (GL_PROJECTION)

• Las transformaciones se aplican sobre la matriz activa

Analogía cámara fotográfica

• Elección de la posición de la cámara

• Elección de la disposición de los objetos

• Elección de la lente

Matriz modelo-vista

Matriz de proyección

La matriz modelo-vista

• Define la posición y orientación de los objetos

• Tres operaciones: traslación, rotación y escalado

Traslación Rotación Escalado

Ejemplo: Traslación

glMatrixMode(GL_MODELVIEW);glLoadIdentity();glTranslatef(10.0f, 20.0f, 0.0f);dibujaObjeto(); /* posición: (10.0, 20.0, 0.0) */

void glTranslatef(GLfloat x, GLfloat y, GLfloat z)void glTranslatex(GLfixed x, GLfixed y, GLfixed z)

Ejemplo: Rotación

glMatrixMode(GL_MODELVIEW);glLoadIdentity();glRotatef(90.0f, 0.0f, 0.0f, 1.0f);dibujaObjeto(); /* objeto girado 90º respecto a Z */

void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) void glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z)

Ejemplo: Escalado

glMatrixMode(GL_MODELVIEW);glLoadIdentity();glTranslatef(10.0f, 10.0f, -10.0f);glScalef(2.0f, 2.0f, 2.0f);dibujaObjeto1(); /* objeto x2 en (10.0, 10.0, -10.0) */

glLoadIdentity();glScalef(2.0f, 2.0f, 2.0f);glTranslatef(10.0f, 10.0f, -10.0f);dibujaObjeto2(); /* OJO: objeto x2 en (20.0, 20.0, -20.0) */

void glScalef(GLfloat x, GLfloat y, GLfloat z)void glScalex(GLfixed x, GLfixed y, GLfixed z)

Ejemplo: Múltiples objetos

glMatrixMode(GL_MODELVIEW);glLoadIdentity();glTranslatef(0.0f, 0.0f, -10.0f);

glPushMatrix();glTranslatef(5.0f, 5.0f, 0.0f);dibujaObjeto1(); /* posición: (5.0, 5.0, -10.0) */glPopMatrix();

glPushMatrix();dibujaObjeto2(); /* posición: (0.0, 0.0, -10.0) */glPopMatrix();

void glPushMatrix()void glPopMatrix()

La matriz de proyección• Determina cómo se va a proyectar la geometría 3D sobre la pantalla 2D

• Planos de corte (clipping)

Ortográfica Perspectiva

Ejemplo: Ortográfica

glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);

void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)

void glOrthox(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed near, GLfixed far)

Ejemplo: Perspectiva

glMatrixMode(GL_PROJECTION);glLoadIdentity();float aspect = width / height;float fov = 50.0f;float near = 0.5f;float far = 20.0f;float top = near * tan(fov * PI / 360.0f);float bottom = -top;float left = bottom * aspect;float right = top * aspect;glFrustumf(left, right, bottom, top, near far);

void glFrustumf(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)

void glFrustumx(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed near, GLfixed far)

Anatomía de una aplicación 3D (actualizada)

1. Inicializar OpenGL ES

1.1. Crear un contexto OpenGL ES (EAGLContext)

1.2. Asociar el contexto a una vista (EAGLView)

1.3. Inicializar la matriz de proyección con glOrtho o glFrustum

2. Bucle (cada frame):

2.1. Actualizar estado de la aplicación

2.2. Dibujar utilizando OpenGL

- Borrar la pantalla con glClear

- Situar la cámara transformando la matriz modelo-vista

- Para cada objeto:

Situar el objeto transformando la matriz modelo-vista

Dibujar las primitivas del objeto

Texturas

Texturas

• Imágenes 2D que se dibujan sobre las primitivas

• Son un aspecto crítico en aplicaciones 3D para iPhone por su tamaño en memoria y tiempo de carga

Cargar una textura

img = cargarImagen(“imagen.png”);GLuint texName;glGenTextures(1, &texName);glBindTexture(GL_TEXTURE_2D, texName);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgWidth, imgHeight, 0, GL_RGBA,

GL_UNSIGNED_BYTE, img);free(img);

1. Cargar la imagen con CGBitmapContextCreate (ver clase Texture2D, ejemplo “Crash Landing”)

2. Definir los parámetros de filtrado

3. Crear un objeto textura en OpenGL con glTexImage2D

Utilizar una textura1. Activar las texturas con glEnable(GL_TEXTURE_2D)

2. Definir las coordenadas de la textura, que afectan a cómo se acopla la textura a los vértices

3. Dibujar la primitiva

Utilizar una textura

glEnable(GL_TEXTURE_2D); /* sólo una vez */

1. Activar las texturas con glEnable(GL_TEXTURE_2D)

2. Definir las coordenadas de la textura, que afectan a cómo se acopla la textura a los vértices

3. Dibujar la primitiva

Utilizar una textura

glEnable(GL_TEXTURE_2D); /* sólo una vez */glBindTexture(GL_TEXTURE_2D, texName);

1. Activar las texturas con glEnable(GL_TEXTURE_2D)

2. Definir las coordenadas de la textura, que afectan a cómo se acopla la textura a los vértices

3. Dibujar la primitiva

Utilizar una textura

glEnable(GL_TEXTURE_2D); /* sólo una vez */glBindTexture(GL_TEXTURE_2D, texName);glVertexPointer(3, GL_FLOAT, 0, vertices);

1. Activar las texturas con glEnable(GL_TEXTURE_2D)

2. Definir las coordenadas de la textura, que afectan a cómo se acopla la textura a los vértices

3. Dibujar la primitiva

Utilizar una textura

glEnable(GL_TEXTURE_2D); /* sólo una vez */glBindTexture(GL_TEXTURE_2D, texName);glVertexPointer(3, GL_FLOAT, 0, vertices);GLfloat texCoordinates[] = {

0, 1.0f,0, 0,1.0f, 0,1.0f, 1.0f

};glTexCoordPointer(2, GL_FLOAT, 0, texCoordinates);

1. Activar las texturas con glEnable(GL_TEXTURE_2D)

2. Definir las coordenadas de la textura, que afectan a cómo se acopla la textura a los vértices

3. Dibujar la primitiva

Utilizar una textura

glEnable(GL_TEXTURE_2D); /* sólo una vez */glBindTexture(GL_TEXTURE_2D, texName);glVertexPointer(3, GL_FLOAT, 0, vertices);GLfloat texCoordinates[] = {

0, 1.0f,0, 0,1.0f, 0,1.0f, 1.0f

};glTexCoordPointer(2, GL_FLOAT, 0, texCoordinates);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

1. Activar las texturas con glEnable(GL_TEXTURE_2D)

2. Definir las coordenadas de la textura, que afectan a cómo se acopla la textura a los vértices

3. Dibujar la primitiva

Shaders (OpenGL 2.0)

Shaders

• Programas ejecutados por la GPU

• OpenGL ES 2.0 incluye dos tipos:

‣ Vertex shaders: manipulan vértices

‣ Fragment shaders: manipulan píxeles

• Se programan en OpenGL ES Shading Language

Vertex shaders• Procesan los vértices especificados con glDrawArrays

• El shader está formado por el conjunto de operaciones que se aplicarán a cada vértice

• Aplicaciones típicas:

- Deformación de superficies

- Suavizado de elementos articulados para animación de personajes

- Etc.

Fragment shaders

• Procesan el color de los píxeles (pixel shaders)

• Aplicaciones típicas:

- Bump mapping

- Reflejos

- Cartoon-shading

- Etc.

Creación de shaders

const char *shaderFiles[] = {“shader1.glsl”,“shader2.glsl”,

};const int shaderFilesLength[] = {

NULL,NULL,

};uint shader = CreateShader(VERTEX_SHADER); /* o FRAGMENT_SHADER */ShaderSource(shader, 2, shaderFiles, shaderFilesLength);CompileShader(shader);

• Se crea un nuevo objeto shader y se compila el código

• También se puede cargar el shader precompilado (ShaderBinary)

Utilización de shaders

uint program = CreateProgram();AttachShader(program, shader);LinkProgram(program);UseProgram(program);

• Los shaders se agrupan en una entidad común llamada programa

• Una vez se ha creado el programa y añadido los shaders, se ejecuta con UseProgram

Más información

• OpenGL ES Programming for iPhone, iPhone Reference Library, http://developer.apple.com/iphone

• OpenGL ES, http://www.khronos.org/opengles

• T. Akenine-Möller, E. Haines and N. Hoffman, Real-Time Rendering, A. K. Peters Ltd., 3rd edition