LIBGDX Shader Program
UNIDADE 2: Creando o mundo
Sumario
Introdución
Información: https://github.com/mattdesl/lwjgl-basics/wiki/Shaders
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 divídese 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.
Onde gardar o Program Shader
O Shader Program pódese definir na propia clase ou ben nun arquivo externo.
Arquivo externo
- Temos que gardar o Vertex Shader nun arquivo con extensión .vert (non é obrigatorio).
- Temos que gardar o Fragment Shader nun arquivo con extensión .frag (non é obrigatorio).
Vexamos un exemplo sinxelo, no que simplemente asinamos a posición a cada vértice dun triángulo.
Preparación: Crear unha clase de nome UD4_4_ProgramShader, que derive da clase Game e sexa chamada pola clase principal das diferentes versións (desktop, android,...).
Creamos dous arquivos que colocaremos no cartafol assets da versión Android e terán de nome:
- vertex.vert
1 attribute vec4 a_position;
2 void main()
3 {
4 gl_Position = a_position;
5 }
Comentarios do código:
- Liña 4: nesta liña copiamos a posición de cada vértice a un Vec4 interno de ShaderProgram, que será o dato que envía á GPU (Graphics Procesor Unit).
- Liña 1: definimos unha variable de tipo vec4(vector de 4 dimensións). Esta variable é un parámetro onde van chegar cada unha das posicións dos vértices definidos no Mesh. E vos estaredes preguntando, pero as posicións son Vector3(x,y,z) como pode ser que o almacene un Vector4 ? Pois debido a que internamente traballa con matrices de 4x4. O que fai é encher o último número cun 1.
- Tamén poderíamos poñer:
1 attribute vec3 a_position; 2 void main() 3 { 4 gl_Position = vec4(a_position,1); 5 }
- fragment.frag
1 #ifdef GL_ES
2 precision mediump float;
3 #endif
4 void main()
5 {
6 }
Agora mesmo non fai nada. As liñas 1 a 3 define a precisión dos vectores. Sempre se debe de poñer as liñas anteriores xa que esa é a precisión adecuada para traballar con texturas e posicións.
Definición interna
Tamén podemos definir o contido dos arquivos en forma de texto dentro do código da clase da seguinte forma:
Código da clase UD4_4_ProgramShader
Obxectivo: Definimos os contidos do Program Shader internamente.
1 @Override
2 public void create() {
3 // TODO Auto-generated method stub
4
5 // create shader program
6 String vertexShader = "attribute vec4 "+ ShaderProgram.POSITION_ATTRIBUTE +";\n"
7 + "void main() \n"
8 + "{ \n"
9 + " gl_Position = " + ShaderProgram.POSITION_ATTRIBUTE +";\n"
10 +"} \n";
11 String fragmentShader = "#ifdef GL_ES \n"
12 + "precision mediump float; \n"
13 + "#endif \n"
14 + "void main() \n"
15 + "{ \n"
16 + "} \n";
17 }
Comentar no código que podemos facer uso das constantes da clase ShaderProgram para acceder ó nome dos atributos que van recoller os datos enviados polo Mesh de posición, cor e textura. No exemplo anterior, poñer:
- "attribute vec4 "+ ShaderProgram.POSITION_ATTRIBUTE +";\n"
é equivalente a poñer:
- "attribute vec4 a_position;\n"
Funcionamento do ShaderProgram
Unha vez decido onde vai ir o código analizaremos o funcionamento dos Shader´s.
Nota: A partires de aquí usaremos a opción de gardar o arquivo de forma externa en dous arquivos.
Como dixemos anteriormente o proceso de aplicar un shader consta de dous pasos. Nun primeiro paso se aplican transformacións ós vértices da figura e nun segundo paso se aplican transformacións a fragmentos (pixeles) da figura.
Traballando coa posición
Inicialmente nos temos que pasarlle ó programa información como pode ser a posición de cada vértice. Para pasarlle información usaremos a liña:
- attribute vec4 a_position;
Coa palabra clave atribute estamos a definir un parámetro. Este parámetro (o da posición) ten un nome xa predefinido e un tipo (Vector4).
Cando definimos o Mesh da forma:
- trianguloRed = new Mesh(true, 3, 3, VertexAttribute.Position());
Estamos a dicir que imos enviar como datos a información da posición ó parámetro a_position definido no programa vertex.vert.
O código completo:
Código da clase UD4_4_ProgramShader
Obxectivo: Ver como funciona o Shader Program.
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.OrthographicCamera;
6 import com.badlogic.gdx.graphics.VertexAttribute;
7 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
8
9 /**
10 * Funcionamento do ShaderProgram
11 * @author ANGEL
12 */
13
14 public class UD4_4_ProgramShader extends Game {
15
16 private Mesh trianguloRed;
17 private ShaderProgram shaderProgram;
18
19 private OrthographicCamera camara2d;
20
21 @Override
22 public void create() {
23 // TODO Auto-generated method stub
24
25 shaderProgram = new ShaderProgram(Gdx.files.internal("vertex.vert"), Gdx.files.internal("fragment.frag"));
26 if (shaderProgram.isCompiled() == false) {
27 Gdx.app.log("ShaderError", shaderProgram.getLog());
28 System.exit(0);
29 }
30
31 trianguloRed = new Mesh(true, 3, 3, VertexAttribute.Position());
32 trianguloRed.setVertices(new float[] {
33 -0.5f, -0.5f, 0f,
34 0.5f, -0.5f, 0f,
35 0f, 0.5f, 0f,
36 });
37 trianguloRed.setIndices(new short[] {0, 1, 2});
38
39
40 }
41
42
43 @Override
44 public void render() {
45
46 Gdx.gl20.glClearColor(1f, 1f, 1f, 1f);
47 Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
48
49
50 Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST);
51
52 shaderProgram.begin();
53
54 trianguloRed.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
55
56 shaderProgram.end();
57
58 Gdx.gl20.glDisable(GL20.GL_DEPTH_TEST);
59
60 }
61
62 @Override
63 public void dispose(){
64 shaderProgram.dispose();
65 trianguloRed.dispose();
66
67 }
68
69 }
Podemos consultar neste enlace as operacións que podemos facer sobre os tipos de datos da linguaxe GLSL (coa que definimos o Program Shader).
Por exemplo, podemos facer que o triángulo se estreita desta forma:
1 attribute vec3 a_position;
2 void main()
3 {
4 vec4 v = vec4(a_position,1);
5 v.x = v.x/4;
6 gl_Position = v;
7 }
TAREFA 4.3 A FACER: Esta parte está asociada á realización dunha tarefa.
Traballando coa cor
O proceso para traballar coa cor é o mesmo que no caso da posición.
A nome do parámetro a definir no arquivo vertex.vert é a_color ou se estamos a definir o Program Shader internamente poderíamos utilizar a constante: ShaderProgram.COLOR_ATTRIBUTE.
1 attribute vec4 a_color;
Nota: Fixarxe como a cor é un vector4 xa que enviamos RGBA.
O parámetro temos que definilo no vertex.vert pero o valor da cor non se vai utilizar neste arquivo se non que ten que pasarse ó Fragment Shader.
Para pasalo temos que definir unha variable de tipo varying. O que facemos é pasarlle o valor (a cor) ó parámetro a_color, despois gardaremos dito valor na variable de tipo varying v_color e dende o Fragment Program (o arquivo fragment.frag) podemos acceder a dito valor.
- Arquivo vertex.vert
1 attribute vec3 a_position;
2 attribute vec4 a_color;
3 varying vec4 v_color;
4 void main()
5 {
6 gl_Position = vec4(a_position,1);
7 v_color = a_color;
8 }
Agora modificaremos o arquivo fragment.frag e recoller o dato e pasalo á variable gl_FragColor, que é o que se vai pasar á GPU.
- Arquivo fragment.frag
1 #ifdef GL_ES
2 precision mediump float;
3 #endif
4 varying vec4 v_color;
5 void main()
6 {
7 gl_FragColor = v_color;
8 }
Por último modificamos o Mesh para enviarlle os datos da cor:
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.OrthographicCamera;
8 import com.badlogic.gdx.graphics.VertexAttribute;
9 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
10
11 /**
12 * Funcionamento do ShaderProgram
13 * @author ANGEL
14 */
15
16 public class UD4_4_ProgramShader extends Game {
17
18 private Mesh trianguloRed;
19 private ShaderProgram shaderProgram;
20
21 private OrthographicCamera camara2d;
22
23 @Override
24 public void create() {
25 // TODO Auto-generated method stub
26
27 shaderProgram = new ShaderProgram(Gdx.files.internal("vertex.vert"), Gdx.files.internal("fragment.frag"));
28 if (shaderProgram.isCompiled() == false) {
29 Gdx.app.log("ShaderError", shaderProgram.getLog());
30 System.exit(0);
31 }
32
33 trianguloRed = new Mesh(true, 3, 3, VertexAttribute.Position(), VertexAttribute.ColorUnpacked());
34 trianguloRed.setVertices(new float[] {
35 -0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f,
36 0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f,
37 0f, 0.5f, 0f, 1f, 0f, 0f, 1f
38 });
39 trianguloRed.setIndices(new short[] {0, 1, 2});
40
41
42 }
43
44
45 @Override
46 public void render() {
47
48 Gdx.gl20.glClearColor(0f, 0f, 0f, 1f);
49 Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
50
51
52 Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST);
53
54 shaderProgram.begin();
55
56 trianguloRed.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
57
58 shaderProgram.end();
59
60 Gdx.gl20.glDisable(GL20.GL_DEPTH_TEST);
61
62 }
63
64 @Override
65 public void dispose(){
66 shaderProgram.dispose();
67 trianguloRed.dispose();
68
69 }
70
71 }
Traballando coa textura
Xa vimos anteriormente como asociar unha textura a un Mesh.
Imos explicar un pouco en profundidade o proceso.
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.
O proceso é moi parecido a como fixemos coa cor, pero cunhas pequenas diferenzas.
O código do Mesh será o seguinte:
1 trianguloRed = new Mesh(true, 3, 3, VertexAttribute.Position(), VertexAttribute.ColorUnpacked(),VertexAttribute.TexCoords(0));
Esta liña indica que imos enviar os datos da textura, cun identificador de 0 (TexCoords(0)).
Ese 0 vai pasarse como parámetro ó programa do vertex.vert, na variable a_texCoordX. Polo tanto, teremos que poñer algo como isto:
- Programa vertex.vert
1 attribute vec3 a_position;
2 attribute vec4 a_color;
3 attribute vec2 a_texCoord0;
4 varying vec4 v_color;
5 varying vec2 v_textCoord;
6 void main()
7 {
8 gl_Position = vec4(a_position,1);
9 v_color = a_color;
10 v_textCoord = a_texCoord0;
11 }
- Liña 3: Fixarse como as coordenadas da textura é un Vector2.
- Liña 5: Definimos unha variable de tipo varying para pasarlle o valor ó programa Fragment (fragment.frag).
- Liña 10: Gardamos o valor na variable v_textCoord.
Ata aquí o código da clase UD4_4_ProgramShader é o seguinte:
Código da clase UD4_4_ProgramShader
Obxectivo: Debuxar unha textura utilizando un ShaderProgram.
1 public class UD4_4_ProgramShader extends Game {
2
3 private Mesh trianguloRed;
4 private ShaderProgram shaderProgram;
5
6 private Texture textura;
7
8 @Override
9 public void create() {
10 // TODO Auto-generated method stub
11
12 shaderProgram = new ShaderProgram(Gdx.files.internal("vertex.vert"), Gdx.files.internal("fragment.frag"));
13 if (shaderProgram.isCompiled() == false) {
14 Gdx.app.log("ShaderError", shaderProgram.getLog());
15 System.exit(0);
16 }
17
18 trianguloRed = new Mesh(true, 3, 3, VertexAttribute.Position(), VertexAttribute.ColorUnpacked(),VertexAttribute.TexCoords(0));
19 trianguloRed.setVertices(new float[] {
20 -0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f, 0f, 1f,
21 0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f, 1f, 1f,
22 0f, 0.5f, 0f, 1f, 0f, 0f, 1f, 0.5f,0f
23 });
24 trianguloRed.setIndices(new short[] {0, 1, 2});
25
26 FileHandle imageFileHandle = Gdx.files.internal("badlogic.jpg");
27 textura = new Texture(imageFileHandle);
28 }
29 ...............
30 }
Imos analizar agora a parte render desta clase.
Para asociar unha textura a un obxecto temos que chamar ó método bind da textura. Ó facelo, indicamos un número que vai indicar á qué número de textura de OPEN GL vai asociarse. Por defecto é 0 (se non podemos nada).
O código sería este:
1 textura.bind(0);
Agora temos que buscar a maneira de 'pasarlle' esta textura o programa Fragment, xa que é aquí onde asignamos a cor e a textura. A idea é que colla punto a punto (en texturas falamos de fragmentos) da textura e a debuxe no sitio que lle corresponda de acordo á posición indicada na figura.
Como facendo o bind xa estamos a cargar a textura en OPEN GL ES, imos a enviarlle o programa o índice utilizado, para que dende o programa Fragment accede a dita textura.
A forma de pasarlle o índice é así:
1 shaderProgram.begin();
2 shaderProgram.setUniformi("u_texture", 0);
3 trianguloRed.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
4
5 shaderProgram.end();
- Liña 2: pasamos á variable u_texture ó valor 0 que se corresponde co índice empregado na textura con bind.
Agora modificamos o programa vertex.vert para que recolla o índice e acceda á textura:
- Programa fragment.frag
1 #ifdef GL_ES
2 precision mediump float;
3 #endif
4 varying vec4 v_color;
5 varying vec2 v_textCoord;
6 uniform sampler2D u_texture;
7 void main()
8 {
9 vec4 texColor = texture2D(u_texture, v_textCoord);
10 gl_FragColor = v_color*texColor;
11 }
- Liña 6: O índice é utilizado para acceder á textura correspondente (sampler2D é un tipo de dato co que accedemos á textura).
- Liña 9: Accedemos a un punto da textura.
- Liña 10: Mandamos a textura a debuxar. Multiplicamos pola cor para tintar a textura. Se non queremos que a cor teña efecto sobre a textura podemos quitar v_color da multiplicación.
O código completo da clase:
Código da clase UD4_4_ProgramShader
Obxectivo: Mandar unha textura ó ShaderProgram
1 import com.badlogic.gdx.Game;
2 import com.badlogic.gdx.Gdx;
3 import com.badlogic.gdx.files.FileHandle;
4 import com.badlogic.gdx.graphics.GL20;
5 import com.badlogic.gdx.graphics.Mesh;
6 import com.badlogic.gdx.graphics.Texture;
7 import com.badlogic.gdx.graphics.VertexAttribute;
8 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
9
10 /**
11 * Funcionamento do ShaderProgram
12 * @author ANGEL
13 */
14
15 public class UD4_4_ProgramShader extends Game {
16
17 private Mesh trianguloRed;
18 private ShaderProgram shaderProgram;
19
20 private Texture textura;
21
22 @Override
23 public void create() {
24 // TODO Auto-generated method stub
25
26 shaderProgram = new ShaderProgram(Gdx.files.internal("vertex.vert"), Gdx.files.internal("fragment.frag"));
27 if (shaderProgram.isCompiled() == false) {
28 Gdx.app.log("ShaderError", shaderProgram.getLog());
29 System.exit(0);
30 }
31
32 trianguloRed = new Mesh(true, 3, 3, VertexAttribute.Position(), VertexAttribute.ColorUnpacked(),VertexAttribute.TexCoords(0));
33 trianguloRed.setVertices(new float[] {
34 -0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f, 0f, 1f,
35 0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f, 1f, 1f,
36 0f, 0.5f, 0f, 1f, 0f, 0f, 1f, 0.5f,0f
37 });
38 trianguloRed.setIndices(new short[] {0, 1, 2});
39
40 FileHandle imageFileHandle = Gdx.files.internal("badlogic.jpg");
41 textura = new Texture(imageFileHandle);
42 }
43
44
45 @Override
46 public void render() {
47
48 Gdx.gl20.glClearColor(0f, 0f, 0f, 1f);
49 Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
50
51
52 Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST);
53
54 textura.bind(0);
55 shaderProgram.begin();
56 shaderProgram.setUniformi("u_texture", 0);
57 trianguloRed.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
58
59 shaderProgram.end();
60
61 Gdx.gl20.glDisable(GL20.GL_DEPTH_TEST);
62
63 }
64
65 @Override
66 public void resize (int width,int height){
67 // Definimos os parámetros da cámara
68
69 }
70
71 @Override
72 public void dispose(){
73 shaderProgram.dispose();
74 trianguloRed.dispose();
75
76 }
77
78 }
Traballando coa cámara
Como último paso temos que pasarlle a matriz da cámara para que axuste cada punto da figura e os visualice no lugar correcto en función da cámara.
Lembrar que cando vimos as cámaras comentamos que para posicionar correctamente os puntos, usamos as matrices de proxección e modelado. Unha matriz servía para definir os planos far, near e viewportwidth / viewportheight (a matriz de proxección) e a outra matriz (modelado) servía para mover a cámara, rotala,...non é que servira para iso, quero dicir que cando movemos a cámara para unha posición, todos as figuras da nosa escena se teñen que debuxar de acordo á posición da cámara.
Polo tanto é necesario enviarlle as dúas matrices ó programa Vertex.vert, xa que é aquí onde posicionamos os puntos da nosa figura.
Lembrar que a matriz de proxección e modelado se combinan para dar a matriz combinada a cal temos acceso a través de método combined das cámaras.
Como pasamos dita matriz ó programa Vertex.vert ?
- Programa vertex.vert:
1 attribute vec3 a_position;
2 attribute vec4 a_color;
3 attribute vec2 a_texCoord0;
4 varying vec4 v_color;
5 varying vec2 v_textCoord;
6 uniform mat4 u_worldView;
7 void main()
8 {
9 gl_Position = u_worldView *vec4(a_position,1);
10 v_color = a_color;
11 v_textCoord = a_texCoord0;
12 }
- Liña 6: definimos a matriz de 4x4 como de tipo uniform (vaise pasar como parámetro dende a clase).
- Liña 9: multiplicamos a posición da figura Mesh pola matriz da cámara.
IMPORTANTE: Hai que ter ven claro que as figuras en 3D se debuxan todas no punto (0,0,0). A partires dese punto se moven de acordo a súa posición (o veremos no seguinte punto) e unha vez movidas se aplica a cámara para sacar unha 'foto' do que se ve. Lembrar que todos son operacións matemáticas feitas con matrices.
Código da clase UD4_4_ProgramShader
Obxectivo: Aplicar a matriz combinada dunha cámara ó Shader Program.
1 import com.badlogic.gdx.Game;
2 import com.badlogic.gdx.Gdx;
3 import com.badlogic.gdx.files.FileHandle;
4 import com.badlogic.gdx.graphics.GL20;
5 import com.badlogic.gdx.graphics.Mesh;
6 import com.badlogic.gdx.graphics.PerspectiveCamera;
7 import com.badlogic.gdx.graphics.Texture;
8 import com.badlogic.gdx.graphics.VertexAttribute;
9 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
10
11 /**
12 * Funcionamento do ShaderProgram
13 * @author ANGEL
14 */
15
16 public class UD4_4_ProgramShader extends Game {
17
18 private Mesh trianguloRed;
19 private ShaderProgram shaderProgram;
20
21 private Texture textura;
22 private PerspectiveCamera camara3d;
23
24 @Override
25 public void create() {
26 // TODO Auto-generated method stub
27
28 shaderProgram = new ShaderProgram(Gdx.files.internal("vertex.vert"), Gdx.files.internal("fragment.frag"));
29 if (shaderProgram.isCompiled() == false) {
30 Gdx.app.log("ShaderError", shaderProgram.getLog());
31 System.exit(0);
32 }
33
34 trianguloRed = new Mesh(true, 3, 3, VertexAttribute.Position(), VertexAttribute.ColorUnpacked(),VertexAttribute.TexCoords(0));
35 trianguloRed.setVertices(new float[] {
36 -0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f, 0f, 1f,
37 0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f, 1f, 1f,
38 0f, 0.5f, 0f, 1f, 0f, 0f, 1f, 0.5f,0f
39 });
40 trianguloRed.setIndices(new short[] {0, 1, 2});
41
42 FileHandle imageFileHandle = Gdx.files.internal("badlogic.jpg");
43 textura = new Texture(imageFileHandle);
44
45 camara3d = new PerspectiveCamera();
46 }
47
48
49 @Override
50 public void render() {
51
52 Gdx.gl20.glClearColor(0f, 0f, 0f, 1f);
53 Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
54
55
56 Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST);
57
58 shaderProgram.begin();
59 shaderProgram.setUniformMatrix("u_worldView", camara3d.combined);
60
61 textura.bind(0);
62 shaderProgram.setUniformi("u_texture", 0);
63
64 trianguloRed.render(shaderProgram, GL20.GL_TRIANGLES,0,3);
65
66 shaderProgram.end();
67
68 Gdx.gl20.glDisable(GL20.GL_DEPTH_TEST);
69
70 }
71
72 @Override
73 public void resize (int width,int height){
74 // Definimos os parámetros da cámara
75 float aspectRatio = (float) width / (float) height;
76 camara3d.viewportWidth = 1f*aspectRatio;
77 camara3d.viewportHeight = 1f;
78 camara3d.far=1000f;
79 camara3d.near=0.1f;
80 camara3d.lookAt(0,0,0);
81 camara3d.position.set(0f,0f,3f);
82 camara3d.update();
83 }
84
85 @Override
86 public void dispose(){
87 shaderProgram.dispose();
88 trianguloRed.dispose();
89
90 }
91
92 }
- Liña 22: Definimos a cámara.
- Liña 45: Instanciamos o obxecto.
- Liñas 73-83: Actualizamos os valores da cámara. Importante chamar ó método update.
- Liña 82: Mandamos a matriz ó programa vertex.vert.
TAREFA 4.4 A FACER: Esta parte está asociada á realización dunha tarefa.
-- Ángel D. Fernández González -- (2015).