LIBGDX ModelBuilder

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

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:

LIBGDX UD5 ModelBuilder 1.jpg


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

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:

LIBGDX UD5 ModelBuilder 2.jpg



Controlando a escena

Clase CameraInputController.

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 -- (2014).