LIBGDX Figuras 3D Mesh

De Manuais Informática - IES San Clemente.
Ir a la navegación Ir a la búsqueda

UNIDADE 4: Figuras 3D. Mesh

Introducion

No espazo en tres dimensións (no que nos movemos) os obxectos están definidos por tres dimensións espaciais (eixes X, Y, Z). Ata o de agora estabamos a visualizar gráficos que estaban definidos nos eixes x-y de tal forma que non tiñan profundidade (eixe z).

A clase que nos permite definir os puntos que conforman as figuras no espazo tridimensional denomínase Mesh.

Pero todo non vai ser tan sinxelo como isto...


Shader Program

Resulta que a partires da versión OPEN GL 2.0 os gráficos renderízanse utilizando Shader´s. Os Shader son programas escritos en linguaxe parecida a C que se denomina GLSL e que permiten modificar as propiedades dos puntos que se van renderizar podendo facer efectos moi complexos.

O proceso de aplicar un Shader Program a unha figura se divide en dúas etapas:

  • Vertex Shader: aplícanse operacións a cada un dos vértices da figura. Por exemplo, poderíamos modificar a posición e tamaño dun obxecto 3D.
  • Fragment Shader: é a segunda etapa. A diferenza coa anterior é que se vai aplicar a cada fragmento da figura. Por simplificar imos identificar fragmento como pixel. Como podedes pensar o custe de GPU será maior que no caso anterior, por lo que non se debe abusar deste mecanismo. Por exemplo, poderíamos cambiar a cor de cada pixel da figura.

Un exemplo do que se pode facer cós Shader: https://www.youtube.com/watch?v=JkyGTZ0992s


Por que esta explicación...?

Porque cando no seguinte punto expliquemos como renderizar unha figura sinxela coma un triángulo, teremos que engadirlle un Shader Program. Loxicamente non tedes que aprender nada del, pero si é interesante que saibades porque aparece. É obrigatorio xa que estamos a utilizar OPEN GL ES 2.0.

O Shader Program que imos utilizar non vai facer ningunha modificación, só vai copiar a posición e a cor que traian cada un dos puntos da figura a debuxar.


Máis información en:

Definindo unha figura en 3D. A clase Mesh

Preparación: Debedes crear un novo proxecto (ou utilizar un xa feito como base, tal como xa explicamos no seguinte enlace).

Crear unha clase de nome UD4_1_Triangulos3D, que derive da clase Game e sexa chamada pola clase principal das diferentes versións (desktop, android,...).


Posición

O primeiro que imos facer vai ser definir un triángulo cun obxecto da clase Mesh. O Mesh vainos permitir representar unha figura xeométrica en tres dimensións.

Código da clase UD4_1_Triangulos3D
Obxectivo: Definir un triángulo en 3D.

 1 import com.badlogic.gdx.Game;
 2 import com.badlogic.gdx.Gdx;
 3 import com.badlogic.gdx.graphics.GL20;
 4 import com.badlogic.gdx.graphics.Mesh;
 5 import com.badlogic.gdx.graphics.VertexAttribute;
 6 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
 7 
 8 /**
 9  * Traballos coa clase Mesh para definir un triángulo en 3D
10  * @author ANGEL
11  */
12 
13 public class UD4_1_Triangulos3D extends Game {
14 
15 	private Mesh triangulo1; // Definimos un obxecto pertencente á clase Mesh
16 	private ShaderProgram shaderProgram;
17 	
18 	@Override
19 	public void create() {
20 		// TODO Auto-generated method stub
21 
22 
23 		// Creamos o ShaderProgram ===> NON NECESARIO MIRALO
24 		String vertexShader = "attribute vec4 a_position; 	\n"
25 				+ "varying vec4 v_color;                \n"
26 				+ "void main()				\n" 
27                                 + "{                                    \n"
28 				+ "	gl_Position = a_position;	\n"  
29 				+"}				        \n";
30 		String fragmentShader = "#ifdef  GL_ES 		\n"
31 				+     "precision mediump float;	\n"
32                                 + "#endif 			\n"
33 				+ "varying vec4 v_color;\n"  
34 				+ "void main()		        \n" 
35                                 + "{				\n"
36                                 + "   gl_FragColor = vec4(0,0,0,1); \n"
37 				+ "}				\n";
38 
39 		// Creamos o ShaderProgram en base ós programas definidos anteriormente
40 		shaderProgram = new ShaderProgram(vertexShader, fragmentShader);
41 		if (shaderProgram.isCompiled() == false) {
42 			Gdx.app.log("ShaderError", shaderProgram.getLog());
43 			System.exit(0);
44 		}
45 
46 		triangulo1 = new Mesh(true, 3, 3, VertexAttribute.Position());
47 		triangulo1.setVertices(new float[] { -0.5f, -0.5f, 0, 
48 						  0.5f, -0.5f, 0, 
49 						  0, 0.5f, 0 });
50 		triangulo1.setIndices(new short[] { 0, 1, 2 });
51 
52 	}

Analicemos o constructur empregado na creación do obxecto Mesh:

		triangulo1 = new Mesh(true, 3, 3, VertexAttribute.Position());
  • 1º parámetro (true): indicámoslle se é de clase ou non. Este parámetro é usado internamente por motivos de 'eficiencia' e se aplica á función glBufferData de OpenGL e normalmente sempre poñeremos true excepto no caso de usar animacións no que o mesh varía en cada frame (http://stackoverflow.com/questions/5402567/whats-glbufferdata-for-inopengl-es).
  • 2º parámetro: é o número de vértices que ten a figura (no noso caso 3, un triángulo).
  • 3º parámetro: é o número de índices. Os índices van a indicar en que orden se deben unir as liñas entre os vértices. No noso caso son tres índices.
  • 4º parámetro: indicamos que información imos a enviarlle o mesh (pode ser a posición, a cor, a textura,...). No noso caso pasámoslle a posición dos vértices que conforman o triángulo no espazo x,y,z.. Cada vértice terá tres números (as coordenadas x,y,z)


A continuación indicamos as coordenadas x,y,z do noso triángulo.

Nota: Cabe sinalar que a cámara, por defecto, se sitúa na posición (0,0,0) mirando cara a coordenada z negativa. É dicir, se a vosa cabeza é a cámara, os vosos ollos están a mirar agora mesmo cara ó monitor. Esa liña é o eixe Z que se vai afastando con valores Z negativos.

Definimos por tanto a posición dos vértices do triángulo:

triangulo1.setVertices(new float[] { -0.5f, -0.5f, 0,
                                      0.5f, -0.5f, 0,
                                      0, 0.5f, 0 });


Por defecto a cámara vai visualizar a seguinte área:

LIBGDX UD4 Mesh 1.jpg


Polo tanto o triángulo estará nesta posición:

LIBGDX UD4 Mesh 2.jpg

Nota: A coordenada Z sempre é 0 xa que estamos a debuxar un triángulo 'plano', non unha pirámide.

A forma en como a cámara interpreta o signo positivo ou negativo das coordenadas x,y,z é o que se coñece como regra da man dereita:

LIBGDX UD4 Mesh 3.jpg
Neste gráfico os eixes indican a dirección dos valores positivos. O dedo medio apuntaría cara o teu corpo.


Cando definimos unha cámara, por defecto, mira cara ao z negativo (ven ser coma nos mirando cara o monitor, a nosa cabeza estaría situada na coordenada z=0 e o monitor nun z cun valor negativo). Por detrás da nosa cabeza o z aumenta. O X e Y serán igual ca sempre: X positivo cara a dereita e negativo cara á esquerda e Y positivo cara arriba e negativo cara abaixo.

LIBGDX UD4 Mesh 4.jpg
Imaxe obtida dos apuntes de Cristina Cañero Morales


Seguimos co exemplo do triángulo:

O seguinte é indicarlle a orde que ten que seguir polos vértices para debuxar a figura. Os vértices empezan a numerarse polo 0.

triangulo1.setIndices(new short[] { 0, 1, 2 });


No noso caso non importaría a orden xa que sempre debuxamos un triángulo:

LIBGDX UD4 Mesh 5.jpg

Agora temos que sobreescribir o método render para debuxar o triangulo1. Para facelo imos utilizar a versión de OpenGL ES 2.0.

 1 	@Override
 2 	public void render() {
 3 
 4 		Gdx.gl20.glClearColor(1f, 1f, 1f, 1f);
 5 		Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
 6 		shaderProgram.begin();
 7 		triangulo1.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
 8 		shaderProgram.end();
 9 
10 	}

Analicemos agora o código:

  • Liña 4: Indicamos a cor que queremos que teñan por defecto cada un dos puntos que se envían á GPU no formato (RGBA). Xa visto neste enlace.
  • Liña 5: Esta liña borra o buffer onde se garda a información de cada punto que se vai enviar á GPU.
  • Liñas 6 e 8: Todo que se queira enviar á GPU aplicándolle o ShaderProgram definido terá que estar ente o begin - end.
  • Liña 7: Indicamos que queremos renderizar o Mesh. Parámetros:
shaderProgram: Aplica o Shader Program definido.
GL20.GL_TRIANGLES: Imos utilizar triángulos (os cadrados se poden forman con dous

triángulos).

Valor 0: O terceiro parámetro indica o desprazamento dentro do buffer de vértices. Normalmente poñeremos 0 (é o array onde están definidos os vértices).
Valor 3: O carto parámetro indica o nº de índices ou vértices a utilizar.


Finalmente liberaremos a memoria.

1 	@Override
2 	public void dispose(){
3 		shaderProgram.dispose();
4 		triangulo1.dispose();
5 	}


Código da clase UD4_1_Triangulos3D
Obxectivo: Visualizar unha figura 3D usando a clase Mesh.

 1 package com.plategaxogo3d.exemplos;
 2 
 3 import com.badlogic.gdx.Game;
 4 import com.badlogic.gdx.Gdx;
 5 import com.badlogic.gdx.graphics.GL20;
 6 import com.badlogic.gdx.graphics.Mesh;
 7 import com.badlogic.gdx.graphics.VertexAttribute;
 8 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
 9 
10 /**
11  * Traballos coa clase Mesh para definir un triángulo en 3D
12  * @author ANGEL
13  */
14 
15 public class UD4_1_Triangulos3D extends Game {
16 
17 	private Mesh triangulo1; // Definimos un obxecto pertencente á clase Mesh
18 	private ShaderProgram shaderProgram;
19 	
20 	@Override
21 	public void create() {
22 		// TODO Auto-generated method stub
23 
24 		// create shader program
25 		String vertexShader = "attribute vec4 a_position; 	\n"
26 				+ "varying vec4 v_color; 		\n"
27 				+ "void main()					\n" 
28 				+ "{							\n"
29 				+ "	gl_Position = a_position;	\n"  
30 				+"}								\n";
31 		String fragmentShader = "#ifdef GL_ES 	\n"
32 				+ "precision mediump float;		\n" 
33 				+ "#endif						\n"
34 				+ "varying vec4 v_color;		\n"  
35 				+ "void main()					\n" 
36 				+ "{							\n"
37                                 + "   gl_FragColor = vec4(0,0,0,1); \n"
38 				+ "}							\n";
39 		
40 		// Creamos o ShaderProgram en base ós programas definidos anteriormente
41 		shaderProgram = new ShaderProgram(vertexShader, fragmentShader);
42 		if (shaderProgram.isCompiled() == false) {
43 			Gdx.app.log("ShaderError", shaderProgram.getLog());
44 			System.exit(0);
45 		}
46 
47 		triangulo1 = new Mesh(true, 3, 3, VertexAttribute.Position());
48 		triangulo1.setVertices(new float[] { -0.5f, -0.5f, 0, 
49 						  0.5f, -0.5f, 0, 
50 					          0, 0.5f, 0 });
51 		triangulo1.setIndices(new short[] { 0, 1, 2 });
52 
53 	}
54 
55 	@Override
56 	public void render() {
57 
58 		Gdx.gl20.glClearColor(1f, 1f, 1f, 1f);
59 		Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
60 		shaderProgram.begin();
61 		triangulo1.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
62 		shaderProgram.end();
63 
64 	}
65 	
66 	@Override
67 	public void dispose(){
68 		shaderProgram.dispose();
69 		triangulo1.dispose();
70 	}
71 
72 }

Cor

Agora imos modificar a clase Mesh para indicarlle que imos a enviar información acerca da cor que van ter cada un dos vértices da figura Mesh.

Para facelo imos ter que modificar o ShaderProgram para que lle pase a cada 'fragmento' a cor definida na clase Mesh.

Código da clase UD4_1_Triangulos3D
Obxectivo: Definir unha cor en cada vértice da figura 3D.

 1 	@Override
 2 	public void create() {
 3 		// TODO Auto-generated method stub
 4 
 5 		// create shader program
 6 		String vertexShader = "attribute vec4 a_position; 	\n"
 7 				+ "attribute vec4 a_color; 		\n"
 8 				+ "varying vec4 v_color; 		\n"
 9 				+ "void main()					\n" 
10 				+ "{							\n"
11 				+ "	gl_Position = a_position;	\n"  
12 				+ " v_color = a_color; \n" 	
13 				+"}								\n";
14 		String fragmentShader = "#ifdef GL_ES 	\n"
15 				+ "precision mediump float;		\n" 
16 				+ "#endif						\n"
17 				+ "varying vec4 v_color;		\n"  
18 				+ "void main()					\n" 
19 				+ "{							\n"
20 				+ "	gl_FragColor = v_color;	\n"
21 				+ "}							\n";
22 		
23 		// Creamos o ShaderProgram en base ós programas definidos anteriormente
24 		shaderProgram = new ShaderProgram(vertexShader, fragmentShader);
25 		if (shaderProgram.isCompiled() == false) {
26 			Gdx.app.log("ShaderError", shaderProgram.getLog());
27 			System.exit(0);
28 		}
29 	
30 		// CON COR
31 		triangulo1 = new Mesh(false, 3, 3, VertexAttribute.Position(), 
32                                                    VertexAttribute.ColorUnpacked());
33 		triangulo1.setVertices(new float[] {-0.5f, -0.5f, 0, 1, 0, 0, 1, 
34 						 0.5f, -0.5f, 0, 1, 0, 0, 1,  
35 						 0, 0.5f, 0, 1, 0, 0, 1});
36 		triangulo1.setIndices(new short[] { 0, 1, 2 });
37 
38 	}
39 	@Override
40 	public void render() {
41 
42 		Gdx.gl20.glClearColor(0f, 0f, 0f, 1f);
43 		Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
44 		shaderProgram.begin();
45 		triangulo1.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
46 		shaderProgram.end();
47 
48 	}

Analicemos o código:

  • Liña 7: Esta variable recibe a cor que ven do Mesh (definido en cada un dos vértices).
  • Liña 8: Como o dato da cor temos que pasalo ao FragmentProgram utilizamos unha variable de tipo variant.
  • Liñas 12 e 20: modificamos o Shader Program para que amose a cor definida no mesh.
  • Liñas 31-32: indicamos que o mesh terá como atributos a posición e a cor. Cada cor está definida por catro número no formato RGBA cun float de valor 0 a 1.
  • Liñas 33-35: indicamos a posición e cor de cada vértice do triángulo. Poñemos como cor a cor vermella (1,0,0,0).
  • Liña 42: Modificamos a cor de fondo polo negro para que se vexa mellor.

Se executades o programa teremos como resultado o seguinte:

LIBGDX UD4 Mesh 6.jpg


Nota: O parámetro alfa indica o nivel de transparencia que pode ir dende 0 (transparente) a 1 (opaco).

Cada cor está asociada a cada un dos vértices. Se poñemos valores diferentes en cada vértice fai un varrido de cor dende un valor a outro.

1 		triangulo1.setVertices(new float[] {-0.5f, -0.5f, 0, 1, 0, 0, 1, 
2 						 0.5f, -0.5f, 0, 0, 0, 1, 1,  
3 						 0, 0.5f, 0, 0, 1, 0, 1});
LIBGDX UD4 Mesh 7.jpg

Texturas

Información sobre o manexo de texturas:


Preparación: Deberemos copiar o arquivo seguinte ó cartafol assets do proxecto Android. Se o proxecto está xerado coa ferramenta de Libgdx xa deberedes ter este gráfico.

Badlogic.jpg

Unha textura é unha imaxe que imos 'pegar' sobre un gráfico. Xa traballamos coas texturas no xogo 2D.

Imaxinade que tedes unha parede e un cartel. O cartel é a textura e a parede a unha parte da figura en 3D (Mesh).

Normalmente as texturas teñen formas cadradas ou rectangulares. Xa veremos como 'adaptamos' esas formas ás formas dun modelo 3D...

Cando falamos de texturas, as unidades nas que se miden denomínanse U e V, que serían ó equivalente ás coordenadas X / Y. Ditas coordenadas U / V teñen uns valores que se moven entre 0 e 1, como amosamos na seguinte figura:

LIBGDX UD4 Mesh 8.jpg

Se queremos que dita textura se debuxe sobre un triángulo, temos que indicar as coordenadas na que se ten que debuxar a parte da textura que queiramos:

LIBGDX UD4 Mesh 9.jpg

No noso caso serían as coordenadas da textura (0,1) – (1,1) – (0.5f,0) que irán en cada vértice do triángulo.

Fixarse como parte da textura vaise perder xa que a textura ten unha forma cadrada. Xa veremos máis adiante como podemos formar un cadrado con dous triángulos e desa forma a textura vai cadrar cua figura do Mesh.

A nivel de código, teremos que facer as seguintes modificacións:

Modificamos o Shader Program:

 1 		String vertexShader = "attribute vec4 "+ ShaderProgram.POSITION_ATTRIBUTE +";\n"
 2 				+ "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE +";	\n"
 3 				+ "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n"
 4 				+ "varying vec4 v_color; 		\n"
 5 				+ "varying vec2 v_textCoord; 		\n"
 6 				+ "void main()					\n" 
 7 				+ "{							\n"
 8 				+ "	gl_Position = " + ShaderProgram.POSITION_ATTRIBUTE +";\n"
 9 				+ " v_color = " + ShaderProgram.COLOR_ATTRIBUTE +";\n" 	
10 				+ " v_textCoord = " + ShaderProgram.TEXCOORD_ATTRIBUTE+ "0;	\n"
11 				+"}								\n";
12 		String fragmentShader = "#ifdef GL_ES 	\n"
13 				+ "precision mediump float;		\n" 
14 				+ "#endif						\n"
15 				+ "varying vec4 v_color;		\n"  
16 				+ "varying vec2 v_textCoord;	\n"  
17 				+ "uniform sampler2D u_texture; \n"
18 				+ "void main()					\n" 
19 				+ "{							\n"
20 				+ " vec4 texColor = texture2D(u_texture, v_textCoord); \n"
21 				+ " gl_FragColor = texColor*v_color; \n"
22 				+ "}							\n";

Non vos preocupedes se non entendedes esta parte, xa falaremos dos Shader´s no seguinte punto. Igual que no caso das cores, temos que recoller as coordenadas das texturas (que veremos a continuación) e pasalas ó fragmentShader. Dende aquí accederemos á textura a visualizar para que cada punto se debuxe con dita textura.


Agora modificamos a definición do Mesh para indicarlle que imos a enviarlle as coordenadas da textura:'

triangulo1 = new Mesh(false, 3, 3, VertexAttribute.Position(),
                      VertexAttribute.ColorUnpacked(),VertexAttribute.TexCoords(0));


E agora pasamos os datos do Mesh:

		triangulo1.setVertices(new float[] {-0.5f, -0.5f, 0, 1, 0, 0, 1, 0, 1, 
						 0.5f, -0.5f, 0, 0, 0, 1, 1, 1, 1,  
						 0, 0.5f, 0, 0, 1, 0, 1, 0.5f,0});

Lembrar que os datos da textura son os dous últimos. Estamos a indicar onde debería ir cada vértice do triángulo na textura.

  • VÉRTICE 1: X=> -0.5f,Y=>-0.5f,Z=>0,RED=>1,GREEN=>0,BLUE=>0,ALFA=>1,TEXTURA_U=>0,TEXTURA_V=>1
  • VÉRTICE 2: X=> 0.5f,Y=>-0.5f,Z=>0,RED=>0,GREEN=>0,BLUE=>1,ALFA=>1,TEXTURA_U=>1,TEXTURA_V=>1
  • VÉRTICE 3: X=> 0,Y=>0.5f,Z=>0,RED=>0,GREEN=>1,BLUE=>0,ALFA=>1,TEXTURA_U=>0.5f,TEXTURA_V=>0


Agora temos que cargar a textura. Isto xa o fixemos no xogo 2D. Poderíamos utilizar a clase AssetManager. Para cargar a textura creamos unha propiedade Texture:

private Texture textura;

No método create cargamos a textura dende o arquivo e a asociamos ó obxecto:

FileHandle imageFileHandle = Gdx.files.internal("badlogic.jpg");
textura = new Texture(imageFileHandle);


Agora temos que debuxar a textura. Para facelo temos que habilitar o uso de texturas e 'vincular' a textura ó Mesh:

 1 	@Override
 2 	public void render() {
 3 
 4 		Gdx.gl20.glClearColor(0f, 0f, 0f, 1f);
 5 		Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
 6 		Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
 7 		textura.bind(0);
 8 		shaderProgram.begin();
 9 		shaderProgram.setUniformi("u_texture", 0);
10 		triangulo1.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
11 		shaderProgram.end();
12 
13 	}

Imos analizar un pouco o código:

  • Liña 6: habilitamos o uso de texturas.
  • Liña 7: en OPEN GL temos un conxunto de textura a utilizar. O que fai o bind é asociar a textura que cargamos a unha das texturas dispoñibles en OPEN GL. Concretamente á número 0. A cero é a textura por defecto polo que cando chamamos ó método bind poderíamos non enviarlle ningún numero.
  • Liña 9: isto xa o veremos cando expliquemos o uso de Shader´s. Con esta liña estamos a 'pasar' a textura 0 (que está cargada na liña 7) ó fragmentShader para que cada punto poida coller o punto da textura que lle corresponda.

O código completo:

Código da clase UD4_1_Triangulos3D
Obxectivo: Vincular unha textura a un Mesh.

 1 package com.plategaxogo3d.exemplos;
 2 
 3 import com.badlogic.gdx.Game;
 4 import com.badlogic.gdx.Gdx;
 5 import com.badlogic.gdx.files.FileHandle;
 6 import com.badlogic.gdx.graphics.GL20;
 7 import com.badlogic.gdx.graphics.Mesh;
 8 import com.badlogic.gdx.graphics.Texture;
 9 import com.badlogic.gdx.graphics.VertexAttribute;
10 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
11 
12 /**
13  * Traballos coa clase Mesh para definir un triángulo en 3D
14  * @author ANGEL
15  */
16 
17 public class UD4_1_Triangulos3D extends Game {
18 
19 	private Mesh triangulo1; // Definimos un obxecto pertencente á clase Mesh
20 	private ShaderProgram shaderProgram;
21 	private Texture textura;
22 	private Texture prueba;
23 	
24 	@Override
25 	public void create() {
26 		// TODO Auto-generated method stub
27 
28 		// create shader program
29 		String vertexShader = "attribute vec4 "+ ShaderProgram.POSITION_ATTRIBUTE +";\n"
30 				+ "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE +";	\n"
31 				+ "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n"
32 				+ "varying vec4 v_color; 		\n"
33 				+ "varying vec2 v_textCoord; 		\n"
34 				+ "void main()					\n" 
35 				+ "{							\n"
36 				+ "	gl_Position = " + ShaderProgram.POSITION_ATTRIBUTE +";\n"
37 				+ " v_color = " + ShaderProgram.COLOR_ATTRIBUTE +";\n" 	
38 				+ " v_textCoord = " + ShaderProgram.TEXCOORD_ATTRIBUTE+ "0;	\n"
39 				+"}								\n";
40 		String fragmentShader = "#ifdef GL_ES 	\n"
41 				+ "precision mediump float;		\n" 
42 				+ "#endif						\n"
43 				+ "varying vec4 v_color;		\n"  
44 				+ "varying vec2 v_textCoord;	\n"  
45 				+ "uniform sampler2D u_texture; \n"
46 				+ "void main()					\n" 
47 				+ "{							\n"
48 				+ " vec4 texColor = texture2D(u_texture, v_textCoord); \n"
49 				+ " gl_FragColor = texColor*v_color; \n"
50 				+ "}							\n";
51 		
52 		// Creamos o ShaderProgram en base ós programas definidos anteriormente
53 		shaderProgram = new ShaderProgram(vertexShader, fragmentShader);
54 		if (shaderProgram.isCompiled() == false) {
55 			Gdx.app.log("ShaderError", shaderProgram.getLog());
56 			System.exit(0);
57 		}
58 
59 		// CON COR
60 		triangulo1 = new Mesh(false, 3, 3, VertexAttribute.Position(), VertexAttribute.ColorUnpacked(),VertexAttribute.TexCoords(0));
61 		triangulo1.setVertices(new float[] {-0.5f, -0.5f, 0, 1, 0, 0, 1, 0, 1, 
62 						 0.5f, -0.5f, 0, 0, 0, 1, 1, 1, 1,  
63 						 0, 0.5f, 0, 0, 1, 0, 1, 0.5f,0});
64 		triangulo1.setIndices(new short[] { 0, 1, 2 });
65 
66 		FileHandle imageFileHandle = Gdx.files.internal("badlogic.jpg");
67 		textura = new Texture(imageFileHandle);
68 		
69 	}
70 	
71 	@Override
72 	public void render() {
73 
74 		Gdx.gl20.glClearColor(0f, 0f, 0f, 1f);
75 		Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
76 		Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
77 
78 		textura.bind();		
79 		shaderProgram.begin();
80 		shaderProgram.setUniformi("u_texture", 0);
81 		triangulo1.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
82 		shaderProgram.end();
83 	}
84 	
85 	@Override
86 	public void dispose(){
87 		shaderProgram.dispose();
88 		triangulo1.dispose();
89 	}
90 
91 }


Ó executar o código dará como resultado o seguinte:

LIBGDX UD4 Mesh 10.jpg

Fixarse como a cor se aplica sobre a textura para darlle diferentes tonalidades. Isto é así porque no fragmentShader temos a seguinte liña: gl_FragColor = texColor*v_color; Se queremos que a cor non modifique a textura teríamos que poñer: gl_FragColor = texColor;



TAREFA 4.1 A FACER: Esta parte está asociada á realización dunha tarefa. En caso de decidir facer o xogo proposto non será necesario facela.



-- Ángel D. Fernández González -- (2014).