LIBGDX ModelBuilder
UNIDADE 5: ModelBuilder. Primeiros modelos 3D
Introdución
A clase ModelBuilder vainos permitir crear modelos en execución (por programación).
Como novidade con respecto ó dado na Unidade 4 imos engadir o uso de luces.
Preparación:
Empezamos co primeiro exercicio.
Preparación: Creade unha nova clase que implemente a interface Screen.
Código da clase EX_1_DefinicionLuz
Obxectivo: Cargar o noso primeiro modelo.
1 import com.badlogic.gdx.Gdx;
2 import com.badlogic.gdx.Screen;
3 import com.badlogic.gdx.graphics.GL20;
4 import com.badlogic.gdx.graphics.PerspectiveCamera;
5
6
7 public class EX_1_DefinicionLuz implements Screen {
8
9 private PerspectiveCamera camara3d;
10
11 public EX_1_DefinicionLuzInicial(){
12 camara3d = new PerspectiveCamera();
13
14 }
15
16 @Override
17 public void render(float delta) {
18 // TODO Auto-generated method stub
19 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
20
21 }
22
23 @Override
24 public void resize(int width, int height) {
25 // TODO Auto-generated method stub
26
27 camara3d.fieldOfView=67;
28 camara3d.viewportWidth=width;
29 camara3d.viewportHeight=height;
30
31 camara3d.position.set(0f,0f,15f);
32 camara3d.lookAt(0,0,0);
33 camara3d.near=1;
34 camara3d.far=300f;
35 camara3d.update();
36
37
38
39 }
40
41 @Override
42 public void show() {
43 // TODO Auto-generated method stub
44 }
45
46 @Override
47 public void hide() {
48 // TODO Auto-generated method stub
49
50 }
51
52 @Override
53 public void pause() {
54 // TODO Auto-generated method stub
55
56 }
57
58 @Override
59 public void resume() {
60 // TODO Auto-generated method stub
61
62 }
63
64 @Override
65 public void dispose() {
66 // TODO Auto-generated method stub
67
68 }
69
70 }
Como vemos nesta clase só definimos unha cámara en perspectiva como xa fixemos anteriormente.
Código da clase PracticasNovaApi3D
Obxectivo: Chamamos á clase anterior
1 import com.badlogic.gdx.Game;
2 import com.plategaxogo3davanzado.pantallas.EX_1_DefinicionLuzInicial;
3
4 public class PracticasNovaApi3D extends Game {
5
6 private EX_1_DefinicionLuz pantallaxogo;
7
8 @Override
9 public void create() {
10 // TODO Auto-generated method stub
11
12 pantallaxogo = new EX_1_DefinicionLuz();
13 setScreen(pantallaxogo);
14 }
15
16 @Override
17 public void dispose(){
18 super.dispose();
19 pantallaxogo.dispose();
20 }
21 }
Modificade ás clases principais das diferentes plataformas para que chamen a esta clase.
A partires de aquí todos os exercicios levarán consigo a creación dunha clase que implemente a interface Screen e será necesario modificar a clase PracticasNovaApi3D para que chame ó novo exercicio.
ModelBuilder
O obxectivo deste punto vai consistir en xerar unha figura xeométrica por programación e asinarlle unha cor, textura e unha luz á escena
Clase ModelBuilder. Información relacionada na wiki: https://github.com/libgdx/libgdx/wiki/Material-and-environment
O proceso é o seguinte:
- Instanciamos un obxecto da clase ModelBuilder:
1 ModelBuilder modelBuilder = new ModelBuilder();
- Chamamos ó método createXXXXX indicando o tipo de figura que queremos crear.
Pero....non todo vai ser tan fácil :)
Cando creamos unha figura temos que asinarlle un material (ven así no constructor). E para que serve un material ?
Os materiais están relacionados coa luz e como se reflexa nela. Dependendo do tipo de material a luz pode reflectirse dunha forma ou outra.
Tedes neste enlace máis información sobre o uso de Materiais e Luces.
Por exemplo, neste caso imos crear un cilindro:
1 private Model modelCilindro; 2 3 ............ 4 modelCilindro = modelBuilder.createCylinder(5f,5f, 10f, 10, 5 new Material(ColorAttribute.createDiffuse(Color.RED)), 6 Usage.Position | Usage.Normal);
Como xa vimos anteriormente, cando creamos unha figura sempre temos que enviarlle a lo menos á posición. Iso o indicamos có atributo Usage.position. O outro atributo, Ussage.Normal fai referencia a que calcule os vectores que son asociados á figura e que van indicar cara onde se vai a reflectir a luz (normal vector).
Nota: Podedes crear un cubo ou outras figuras para facer probas.
Tedes máis información neste enlace sobre os Vector Normal.
Neste caso estamos a definir un cilindro de dimensións alto=5,ancho=5,profundo=5 e 10 divisións, que veñen a ser o número de partes en que está dividido o cilindro (a mais partes máis 'calidade' visual do cilindro). Ademais o estamos pintando de vermello.
Nota: Débese liberar a memoria do modelo chamando ó método dispose.
Agora ben, có Model non indicamos onde ten que colocarse o figura. Para iso temos que crear unha instancia da clase ModelInstance.
- Creamos por tanto unha instancia da clase ModelInstance, pasando como parámetro o obxecto da clase Model.
1 private ModelInstance modeloInstanciaCilindro; 2 3 ............ 4 public EX_1_DefinicionLuzInicial(){ 5 modeloInstanciaCilindro = new ModelInstance(modelCilindro); 6 ..... 7 }
Nota:Por defecto os obxectos son posicionados na posición (0,0,0).
- Agora necesitamos renderizar o modelo. Para facelo debemos facer uso da clase ModelBatch, chamando ó método render e pasándolle como argumento o ModelInstance:
1 private ModelBatch modelBatch; 2 3 ..... 4 public EX_1_DefinicionLuzInicial(){ 5 modelBatch = new ModelBatch(); 6 ..... 7 } 8 ..... 9 @Override 10 public void render(float delta) { 11 // TODO Auto-generated method stub 12 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); 13 14 modelBatch.begin(camara3d); 15 16 modelBatch.render(modeloInstanciaCilindro); 17 18 modelBatch.end(); 19 }
O código completo:
Código da clase EX_1_DefinicionLuzInicial
Obxectivo: Visualiza un cilindro utilizando a clase ModelBuilder.
1 import com.badlogic.gdx.Gdx;
2 import com.badlogic.gdx.Screen;
3 import com.badlogic.gdx.graphics.Color;
4 import com.badlogic.gdx.graphics.GL20;
5 import com.badlogic.gdx.graphics.PerspectiveCamera;
6 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
7 import com.badlogic.gdx.graphics.g3d.Material;
8 import com.badlogic.gdx.graphics.g3d.Model;
9 import com.badlogic.gdx.graphics.g3d.ModelBatch;
10 import com.badlogic.gdx.graphics.g3d.ModelInstance;
11 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
12 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
13
14
15 public class EX_1_DefinicionLuzInicial implements Screen {
16
17 private PerspectiveCamera camara3d;
18 private Model modelCilindro;
19 private ModelInstance modeloInstanciaCilindro;
20 private ModelBatch modelBatch;
21
22
23 public EX_1_DefinicionLuzInicial(){
24 camara3d = new PerspectiveCamera();
25
26
27 ModelBuilder modelBuilder = new ModelBuilder();
28
29
30 modelCilindro = modelBuilder.createCylinder(5f,5f, 10f, 10,
31 new Material(ColorAttribute.createDiffuse(Color.RED)),
32 Usage.Position | Usage.Normal);
33
34 modeloInstanciaCilindro = new ModelInstance(modelCilindro);
35 modelBatch = new ModelBatch();
36
37 }
38
39 @Override
40 public void render(float delta) {
41 // TODO Auto-generated method stub
42 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
43
44 modelBatch.begin(camara3d);
45
46 modelBatch.render(modeloInstanciaCilindro);
47
48 modelBatch.end();
49 }
50
51 @Override
52 public void resize(int width, int height) {
53 // TODO Auto-generated method stub
54
55 camara3d.fieldOfView=67;
56 camara3d.viewportWidth=width;
57 camara3d.viewportHeight=height;
58
59 camara3d.position.set(0f,0f,15f);
60 camara3d.lookAt(0,0,0);
61 camara3d.near=1;
62 camara3d.far=300f;
63 camara3d.update();
64
65
66
67 }
68
69 @Override
70 public void show() {
71 // TODO Auto-generated method stub
72 }
73
74 @Override
75 public void hide() {
76 // TODO Auto-generated method stub
77
78 }
79
80 @Override
81 public void pause() {
82 // TODO Auto-generated method stub
83
84 }
85
86 @Override
87 public void resume() {
88 // TODO Auto-generated method stub
89
90 }
91
92 @Override
93 public void dispose() {
94 // TODO Auto-generated method stub
95 modelCilindro.dispose();
96 modelBatch.dispose();
97
98
99 }
100
101 }
Resultado:
Non é moi espectacular o resultado verdade ? :)
Para facelo un pouco máis bonito (con texturas mellora a cousa) imos darlle un pouco de luz.
Luces
- Máis información: http://sjbaker.org/steve/omniv/opengl_lighting.html
Existen diferentes tipos de fontes de luz:
- Luces de ambiente (ambient lights): Non é un tipo de luz direccional (que veña dun sitio concreto) pero fai que todos os obxectos se iluminen por igual.
- Puntos de luz (point lights): A luz parte dun punto no espazo e todas as direccións (coma unha bombilla).
- Luces direccionais (directional lights): A luz ven dunha dirección. Por exemplo o Sol (aínda que non sexa realmente así). A súa luz 'golpea' toda a superficie da Terra no mesmo ángulo pola distancia tan grande que hai.
- Spotlights: Parecidas ós puntos de luz pero cunha dirección formando un cono de luz, como por exemplo a luz dun farol da rúa.
A maiores da posición e dirección da luz, OPEN GL nos permite definir a intensidade da mesma. Esta é expresada en forma de cor RGBA, e especifica catro tipos diferentes de cor (intensidade) da mesma:
- Ambiente (ambient): A luz é uniforme en todo o obxecto.
- Difusa (diffuse): As caras do obxectos que non son iluminadas aparecen máis escuras.
- Especular (specular): Parecida á difusa pero só afecta a certos puntos que teñen unha determinada orientación entre a luz e o obxecto.
- Emisiva (emissive): Non se utiliza.
Como comentario, indicar que os materias poden ter a mesma cor/intensidade que os tipos indicados anteriormente.
Unha vez vista a teoría imos coa práctica.
Imos engadir á nosa escena unha luz ambiente e unha luz direccional.
Nota: As luces consumen bastantes recursos polo que non se debe abusar delas.
Para facer uso das luces debemos usar a clase Environment.
O proceso é o seguinte:
- Instanciamos un obxecto de dita clase:
1 private Environment environment;
2 .............
3 public EX_1_DefinicionLuzInicial(){
4 .............
5 environment = new Environment();
6
7 }
- Definimos os dous tipos de luz.
1 environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
2 environment.add(new DirectionalLight().set(1f, 1f, 1f, 1f, 0f, 0f));
- Renderizamos enviando o environment creado:
1 public void render(float delta) {
2 // TODO Auto-generated method stub
3 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
4
5 modelBatch.begin(camara3d);
6
7 modelBatch.render(modeloInstanciaCilindro,environment);
8
9 modelBatch.end();
10 }
Como vemos na definición do tipo de luz, a luz ambiente xa está creada. Cambiamos a súa intensidade e non leva posición (ven de todos lados).
A luz direccional a engadimos:
1 environment.add(new DirectionalLight().set(1f, 1f, 1f, 1f, 0f, 0f));
Indicamos a súa cor/intensidade(RGBA) e posición.
Resultado:
Controlando a escena
Para 'xogar' un pouco coa escena imos a engadir un control da cámara co rato, de tal forma que poderemos rotar a cámara e afastala coa roda do rato.
Código da clase EX_1_DefinicionLuz
Obxectivo: Poder mover a cámara premendo co rato o botón esquerdo e movendo o rato ó mesmo tempo. Coa roda achegamos ou afastamos a cámara.
1 import com.badlogic.gdx.Gdx;
2 import com.badlogic.gdx.Screen;
3 import com.badlogic.gdx.graphics.Color;
4 import com.badlogic.gdx.graphics.GL20;
5 import com.badlogic.gdx.graphics.PerspectiveCamera;
6 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
7 import com.badlogic.gdx.graphics.g3d.Environment;
8 import com.badlogic.gdx.graphics.g3d.Material;
9 import com.badlogic.gdx.graphics.g3d.Model;
10 import com.badlogic.gdx.graphics.g3d.ModelBatch;
11 import com.badlogic.gdx.graphics.g3d.ModelInstance;
12 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
13 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
14 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
15 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
16
17
18 public class EX_1_DefinicionLuz implements Screen {
19
20 private PerspectiveCamera camara3d;
21 private Model modelCilindro;
22 private ModelInstance modeloInstanciaCilindro;
23 private ModelBatch modelBatch;
24 private Environment environment;
25
26 private CameraInputController camController;
27
28 public EX_1_DefinicionLuzInicial(){
29 camara3d = new PerspectiveCamera();
30
31
32 ModelBuilder modelBuilder = new ModelBuilder();
33
34
35 modelCilindro = modelBuilder.createCylinder(5f,5f, 10f, 10,
36 new Material(ColorAttribute.createDiffuse(Color.RED)),
37 Usage.Position | Usage.Normal);
38
39 modeloInstanciaCilindro = new ModelInstance(modelCilindro);
40 modelBatch = new ModelBatch();
41
42 environment = new Environment();
43 environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
44 environment.add(new DirectionalLight().set(1f, 1f, 1f, 1f, 0f, 0f));
45
46 camController = new CameraInputController(camara3d);
47 Gdx.input.setInputProcessor(camController);
48
49 }
50
51 @Override
52 public void render(float delta) {
53 // TODO Auto-generated method stub
54 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
55
56 modelBatch.begin(camara3d);
57
58 modelBatch.render(modeloInstanciaCilindro,environment);
59
60 modelBatch.end();
61 }
62
63 @Override
64 public void resize(int width, int height) {
65 // TODO Auto-generated method stub
66
67 camara3d.fieldOfView=67;
68 camara3d.viewportWidth=width;
69 camara3d.viewportHeight=height;
70
71 camara3d.position.set(0f,0f,15f);
72 camara3d.lookAt(0,0,0);
73 camara3d.near=1;
74 camara3d.far=300f;
75 camara3d.update();
76
77
78
79 }
80
81 @Override
82 public void show() {
83 // TODO Auto-generated method stub
84 }
85
86 @Override
87 public void hide() {
88 // TODO Auto-generated method stub
89
90 }
91
92 @Override
93 public void pause() {
94 // TODO Auto-generated method stub
95
96 }
97
98 @Override
99 public void resume() {
100 // TODO Auto-generated method stub
101
102 }
103
104 @Override
105 public void dispose() {
106 // TODO Auto-generated method stub
107 modelCilindro.dispose();
108 modelBatch.dispose();
109
110
111 }
112
113 }
-- Ángel D. Fernández González -- (2015).