Boxes

Hoy toca un poco de 3D, vamos a dibujar unas cuantas cajitas, no deberia suponer ninguna dificultad, para esto nos hará faclta activar el cull_face y el depth_test (que si me ha supuesto algun quebradero de cabeza que aun no comprendo porque).

Proyecto + FrameWork

Como siempre empezamos por crear un proyecto vacio, agregamos el framework CoreGraphics como siempre siguiendo nuestro tutorial de Sprites en OGL, que ademas ahora tiene los sources para descargar.

Box

A continuación vamos a crear una clase Box para dibujar cada caja … seguro que mi método os va a asustar horrores, pero tiene su lógica: no me interesa dibujar la caja como un objeto solido a base de una lista de vértices y una definición de caras. Yo quiero dibujar un plano cuadrado, y luego rotarlo para formar cada lado del cubo. Esto me permitirá en un futuro (espero no muy lejano) añadir métodos a esta clase para dibujar los lados con mas control

 C |  copy code |? 
01
 
02
 @interface Box : NSObject { 
03
 GLfloat px,py,pz; 
04
 GLfloat spriteTexcoords[8]; // coordenadas para la textura 
05
 GLfloat spriteVertices[12]; // coordenadas para los vertices 
06
 GLfloat spriteNormals[12];  // normales 
07
 } 
08
 
09
 - (void)init:(GLfloat)x y:(GLfloat)y z:(GLfloat)z; 
10
 - (void)Render; 
11
 - (void)drawPlane:(int)rx ry:(int)ry rz:(int)rz; 
12
 

Por ahora solo nos interesa ver el método Init para darle una posición a la caja y el Render.

 C |  copy code |? 
01
 
02
 
03
 @implementation Box 
04
 
05
 - (void)init:(GLfloat)x y:(GLfloat)y z:(GLfloat)z 
06
 { 
07
 px = x; py = y; pz = z; 
08
 
09
 // coordenadas 
10
 spriteVertices[0]=-1.0f; spriteVertices[1]= -1.0f;spriteVertices[2]= -1.0f; 
11
 spriteVertices[3]= 1.0f; spriteVertices[4]= -1.0f; spriteVertices[5]=-1.0f; 
12
 spriteVertices[6]=-1.0f; spriteVertices[7]= -1.0f; spriteVertices[8]= 1.0f; 
13
 spriteVertices[9]= 1.0f; spriteVertices[10]=-1.0f;spriteVertices[11]= 1.0f; 
14
 
15
 // texturas 
16
 spriteTexcoords[0] = 0.0f; spriteTexcoords[1] = 0.0f; 
17
 spriteTexcoords[2] = 1.0f; spriteTexcoords[3] = 0.0f; 
18
 spriteTexcoords[4] = 0.0f; spriteTexcoords[5] = 1.0f; 
19
 spriteTexcoords[6] = 1.0f; spriteTexcoords[7] = 1.0f; 
20
 
21
 // normales 
22
 spriteNormals[0] = 0.0f; spriteNormals[1]  = 1.0f; spriteNormals[2]  = 0.0; 
23
 spriteNormals[3] = 0.0f; spriteNormals[4]  = 1.0f; spriteNormals[5]  = 0.0; 
24
 spriteNormals[6] = 0.0f; spriteNormals[7]  = 1.0f; spriteNormals[8]  = 0.0; 
25
 spriteNormals[9] = 0.0f; spriteNormals[10] = 1.0f; spriteNormals[11] = 0.0; 
26
 
27
 } 
28
 
29
 - (void)Render 
30
 { 
31
 
32
 glPushMatrix(); 
33
 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 
34
 
35
 GLfloat sep = 2.50f; 
36
 glTranslatef(px * sep, py * sep, pz * sep); 
37
 
38
 [self drawPlane:3 ry:0 rz:0]; 
39
 [self drawPlane:3 ry:1 rz:0]; 
40
 [self drawPlane:3 ry:2 rz:0]; 
41
 [self drawPlane:3 ry:3 rz:0]; 
42
 [self drawPlane:0 ry:0 rz:0]; 
43
 [self drawPlane:2 ry:0 rz:0]; 
44
 
45
 glPopMatrix(); 
46
 } 
47
 
48
 - (void)drawPlane:(int)rx ry:(int)ry rz:(int)rz 
49
 { 
50
 glPushMatrix(); 
51
 glRotatef(90 * rz, 0, 0, 1); 
52
 glRotatef(90 * ry, 0, 1, 0); 
53
 glRotatef(90 * rx, 1, 0, 0); 
54
 
55
 glEnableClientState(GL_VERTEX_ARRAY); 
56
 glVertexPointer(3, GL_FLOAT, 0, spriteVertices); 
57
 
58
 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
59
 glTexCoordPointer(2, GL_FLOAT, 0, spriteTexcoords); 
60
 
61
 glEnableClientState( GL_NORMAL_ARRAY ); 
62
 glNormalPointer ( GL_FLOAT, 0, spriteNormals ); 
63
 
64
 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 
65
 
66
 glPopMatrix(); 
67
 } 
68
 @end 
69
 

Nuestro método Init establece las coordenadas del único plano, un plano horizontal sobre el eje XZ y que está a una altura en y = -1, luego el método Render llama 6 veces a drawPlane dándole las rotaciones necesarias para poner ese plano en todas las caras del cubo…. una forma cómoda de trabajar aunque una completísima aberración para las optimizaciones, lógicamente para dibujar 4 cubos tampoco tendrá importancia.

 Box.m (1.91 Kb)
 Box.h (593 Bytes)

EAGLView

El siguiente paso será inicializar nuestro programa y dibujar algunos cubos en pantalla, asi que vamos a ir directamente a ello. Empezamos por añadir estas variables a nuestra clase: la textura del cubo y un array de 7 cubos:

 C |  copy code |? 
1
 
2
 GLuint texture; 
3
 Box *box[7]; 
4
 

A continuación vamos a EAGLView.m y activamos este define, esto lo que hace es generar el buffer de profundidad, este buffer es el que se encarga de dibujar la profundidad de cada polígono que dibujamos en pantalla, de modo que el motor sabe en todo momento que polígonos solapan a otros. Es necesario usarlo siempre que trabajemos en 3D

 C |  copy code |? 
1
 
2
 #define USE_DEPTH_BUFFER 1 
3
 

Y ahora ya podemos ir a nuestro metodo Inicializar:

 C |  copy code |? 
01
 
02
 
03
 -(void)inicializar 
04
 { 
05
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
06
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
07
 glEnable(GL_TEXTURE_2D); 
08
 
09
 // Activamos el Blend 
10
 glEnable(GL_BLEND); 
11
 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 
12
 
13
 // Activamos el Cull Face 
14
 glEnable(GL_CULL_FACE); 
15
 glFrontFace(GL_CW); 
16
 
17
 // Activamos el DepthTest 
18
 glDepthFunc(GL_LESS); 
19
 glEnable(GL_DEPTH_TEST); 
20
 
21
 // Ponemos una luz 
22
 GLfloat	lightPosition1[] = { 10.0f, 10.0f, -10.0f, 1.0f }; 
23
 GLfloat	lightDiffuse1[]	 = { 1.0f, 1.0f, 1.0f, 1.0f }; 
24
 GLfloat	lightAmbient1[]	 = { 0.4f, 0.4f, 0.8f, 1.0f }; 
25
 glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient1); 
26
 glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse1); 
27
 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition1); 
28
 glEnable(GL_LIGHT0 ); 
29
 
30
 glEnable(GL_LIGHTING); 
31
 
32
 // bucle para inicializar las 7 cajas 
33
 for(int i=0;i<7;i++) 
34
 box[i] = [Box alloc]; 
35
 
36
 [box[0] init: 0 y: 0 z: 0]; // Centro 
37
 [box[1] init: 1 y: 0 z: 0]; // x =  1 
38
 [box[2] init:-1 y: 0 z: 0]; // x = -1 
39
 [box[3] init: 0 y: 1 z: 0]; // y =  1 
40
 [box[4] init: 0 y:-1 z: 0]; // y = -1 
41
 [box[5] init: 0 y: 0 z: 1]; // z =  1 
42
 [box[6] init: 0 y: 0 z:-1]; // z = -1 
43
 
44
 // Cargamos la textura 
45
 texture  = [GL loadTexture:"Box.png"]; 
46
 } 
47
 

 Box.png (712 Bytes)

En nuestro método clearBuffer deberemos añadir el borrado del buffer de profundidad, por defecto y hasta ahora solo habíamos limpiado el buffer de dibujado:

 C |  copy code |? 
01
 
02
 -(void)clearBuffer 
03
 { 
04
 [EAGLContext setCurrentContext:context]; 
05
 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); 
06
 glClear(GL_COLOR_BUFFER_BIT); 
07
 glClear(GL_DEPTH_BUFFER_BIT); 
08
 } 
09
 <code> 
10
 
11
 Y finalmente nuestro metodo Draw ... simplemente activa la textura y renderiza las 7 cajas que hemos creado 
12
 
13
 <code lang="c"> 
14
 
15
 // Updates the OpenGL view when the timer fires 
16
 - (void)drawView 
17
 { 
18
 static GLfloat anglex = 0.0f; anglex+=0.6f; 
19
 static GLfloat angley = 0.0f; angley+=0.5f; 
20
 static GLfloat anglez = 0.0f; anglez+=0.3f; 
21
 
22
 [self clearBuffer]; 
23
 
24
 glLoadIdentity(); 
25
 glTranslatef(0,0,-8); 
26
 
27
 glRotatef(anglex, 1, 0, 0); 
28
 glRotatef(angley, 0, 1, 0); 
29
 glRotatef(anglez, 0, 0, 1); 
30
 
31
 // Activamos la textura 
32
 glEnable(GL_TEXTURE_2D); 
33
 glBindTexture(GL_TEXTURE_2D, texture); 
34
 
35
 [box[0] Render]; 
36
 [box[1] Render]; 
37
 [box[2] Render]; 
38
 [box[3] Render]; 
39
 [box[4] Render]; 
40
 [box[5] Render]; 
41
 [box[6] Render]; 
42
 
43
 [self swapBuffer]; 
44
 } 
45
 
46
 

 EAGLView.m (7.3 Kb)
 EAGLView.h (1.29 Kb)

  • Delicious
  • Twitter
  • Facebook
  • Meneame
  • WordPress
  • Digg
  • Gmail
  • Google Reader
  • Google Bookmarks
  • Slashdot
  • Share/Bookmark

4 Comments

Tony S.  on April 22nd, 2009

Felicitaciones por tu blog. Es estupendo para ir aclarándose con esto del OpenGL.

Saludos

Eskema  on August 15th, 2009

Me surge una duda que tal vez estoy obviando. Si para dibujar un plano necesitamos 2 triangulos, lo cual son 6 vertices, ¿por que creas 12?, GLfloat spriteVertices[12];
¿No deberia ser solo 6? GLfloat spriteVertices[6];

Saludos,

neofar  on August 21st, 2009

se necesitan 2 triángulos, estos 2 triángulos comparten 2 vértices por lo que en realidad necesitamos 4 vértices …. y cada vértice tiene 3 coordenadas .. así que en nuestro array debe tener un espacio suficiente para que quepan 12 coordenadas

Néstor  on December 29th, 2009

no! esos codigos me generan monton de errores

Leave a Comment