LIBGDX APIMoverModelos3D

De MediaWiki
Ir a la navegación Ir a la búsqueda

UNIDADE 5: Mover modelos 3D


Introdución

Neste apartado imos ver como mover os modelos 3D cargados coa clase ModelInstance, facendo uso das matrices.

Para mover os modelos só temos que aplicar o aprendido na Unidade 4.


Preparación:

Creamos unha nova clase de nome EX_3_MoverModelos que sexa chamada pola clase PracticasNovaApi3D.


Movendo os Modelos 3D

A matriz de modelado-vista se atopa na propiedade transform do ModelInstance, e este a su vez está asociado a un Model.

Clase utilizada: Matrix4.

Operacións (todas elas sobrecargadas) sobre a propiedade transform do ModelInstance:

  • Traslación:
public Matrix4 setToTranslation(float x,float y, float z): Carga a matriz identidade e posiciona o obxecto nas coordenadas indicadas. Esta sería a forma que deberíamos utilizar se seguimos o esquema Modelo-Vista-Controlador.
public Matrix4 setTranslation(float x,float y, float z): Posiciona o obxecto nas coordenadas indicadas. Non carga a matriz identidade.
  • Rotación:
public Matrix4 setToRotation(Vector3 axis, float degrees): Carga a matriz de identidade e rota a matriz no ángulo indicado en grados e no eixe que teña o valor 1.
public Matrix4 rotate(float axisX,float axisY,float axisZ,float degrees): Rota a matriz no ángulo indicado en grados e no eixe que teña o valor 1.
  • Escala:
public Matrix4 setToScaling(Vector3 vector): Carga a matriz identidade e escala a matriz no valor indicado no eixe correspondente.
Atención:: Se usamos este método estaremos perdendo a información gardada na matriz de modelado. Para aplicar unha traslación e escala teremos que aplicar o método seguinte:
  • Traslación e escala:
public Matrix4 setToTranslationAndScaling(float translationX,float translationY,float translationZ,float scalingX,float scalingY,float scalingZ): Traslada e escala á vez. Carga a matriz de identidade e aplica a traslación e escala nos eixes indicados cun valor de 1.



Imos facer un exemplo.

Seguindo co exercicio anterior (o podedes gardar facendo copy e paste sobre o propio arquivo en Eclipse).

Código da clase EX_3_MoverModelos
Obxectivo: Cargar varios modelos e animalos. Operacións de escala, rotacion e traslación.

  1 import com.badlogic.gdx.Gdx;
  2 import com.badlogic.gdx.Screen;
  3 import com.badlogic.gdx.assets.AssetManager;
  4 import com.badlogic.gdx.graphics.GL20;
  5 import com.badlogic.gdx.graphics.PerspectiveCamera;
  6 import com.badlogic.gdx.graphics.g3d.Environment;
  7 import com.badlogic.gdx.graphics.g3d.Model;
  8 import com.badlogic.gdx.graphics.g3d.ModelBatch;
  9 import com.badlogic.gdx.graphics.g3d.ModelInstance;
 10 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
 11 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
 12 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
 13 import com.badlogic.gdx.utils.Array;
 14 
 15 
 16 
 17 public class EX_3_MoverModelos implements Screen {
 18 
 19 	private PerspectiveCamera camara3d;
 20 	private  ModelBatch modelBatch;
 21 
 22 	private Array<ModelInstance> instances;
 23 	private ModelInstance instanceNave;
 24 	
 25 	
 26 	private Environment environment;
 27 	private CameraInputController camController;
 28 	
 29 	private float pos;
 30 		
 31 	public EX_3_MoverModelos(){
 32 		camara3d = new PerspectiveCamera();
 33 		camController = new CameraInputController(camara3d);
 34 		Gdx.input.setInputProcessor(camController);
 35 		
 36 		modelBatch = new ModelBatch();
 37 		environment = new Environment();
 38         environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
 39         environment.add(new DirectionalLight().set(1f, 1f, 1f, 1f, 0f, 0f));
 40 
 41         instances = new Array<ModelInstance>();
 42 
 43         AssetManager assets = new AssetManager();
 44         assets.load("ship.obj", Model.class);
 45         assets.load("cube.g3db", Model.class);
 46         assets.finishLoading();
 47         
 48         Model modelNave = assets.get("ship.obj", Model.class);
 49         Model modelCubo = assets.get("cube.g3db", Model.class);
 50 
 51         instanceNave = new ModelInstance(modelNave);
 52         instanceNave.transform.setToRotation(0, 1, 0, 90);
 53         
 54         for (int cont=1; cont < 10;cont++){
 55         	ModelInstance cubo = new ModelInstance(modelCubo);
 56         	if (cont>3 && cont<6){
 57         		cubo.transform.setToTranslationAndScaling(cont*3, 0, 0, 0.5f, 0.5f, 0.5f);
 58         	}
 59         	else
 60         		cubo.transform.setTranslation(cont*3,0,0);
 61         	
 62             instances.add(cubo);
 63      
 64         }
 65 
 66 	}
 67 	
 68 
 69 	@Override
 70 	public void render(float delta) {
 71 		// TODO Auto-generated method stub
 72 		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
 73 		 
 74 		camController.update();
 75 		
 76 		pos+=delta * 1f;
 77 	
 78 		for (ModelInstance modelI : instances){
 79 			modelI.transform.rotate(0,1,0,delta*30f);	// Continua a rotación, non empeza de 0
 80 		}
 81 	
 82 		instanceNave.transform.setTranslation(pos,0,0);
 83 
 84 		
 85 		camara3d.lookAt(pos,0,0);
 86 		camara3d.update();
 87 		
 88         modelBatch.begin(camara3d);
 89 
 90         modelBatch.render(instances,environment);
 91         modelBatch.render(instanceNave,environment);
 92         
 93         modelBatch.end();	
 94 	}
 95 
 96 	
 97 	@Override
 98 	public void resize(int width, int height) {
 99 		// TODO Auto-generated method stub
100 		
101 		camara3d.fieldOfView=67;
102                 camara3D.viewportHeight=height;
103                 camara3D.viewportWidth=width;
104 		
105 		Gdx.input.setInputProcessor(camController);
106 		
107 		camara3d.position.set(0f,0f,15f);
108 		camara3d.lookAt(0,0,0);
109 		camara3d.near=1;
110 		camara3d.far=300f;
111 		camara3d.update();
112 		
113 
114 	}
115 
116 	@Override
117 	public void show() {
118 		// TODO Auto-generated method stub
119 	}
120 
121 	@Override
122 	public void hide() {
123 		// TODO Auto-generated method stub
124 		
125 	}
126 
127 	@Override
128 	public void pause() {
129 		// TODO Auto-generated method stub
130 		
131 	}
132 
133 	@Override
134 	public void resume() {
135 		// TODO Auto-generated method stub
136 		
137 	}
138 
139 	@Override
140 	public void dispose() {
141 		// TODO Auto-generated method stub
142 		
143 		modelBatch.dispose();
144 		instances.clear();
145 		
146 		
147 	}
148 
149 }

Comentemos o código:

  • Liñas 51-52: Creamos un ModelInstance a partires do Model da nave e rotamos no eixe Y 90 grados a nave, para poñela cara os cubos.
  • Liñas 54-62: Creamos o array de ModelInstance. Os trasladamos chamando ó método setTranslate e dous deles (os números 4 e 5) ademais de trasladalos os escalamos á metade do seu tamaño orixinal.
  • Liñas 78-80: Rotamos todos os cubos. Como xa están trasladados, a rotación é no punto onde se atopan (como o movemento de rotación da Terra). Chamamos a translate e non a setToTranslate xa que este último inicializa a matriz e polo tanto movería todos os cubos á posición (0,0,0).
  • Liña 82: Movemos a nave.
  • Liñas 85-86: Facemos que a cámara siga á nave.
  • Liñas 90-91: Renderizamos os ModelInstace dos bloques (array) e a nave.

Ó final teremos como resultado isto:

LIBGDX UD5 CargaModelos3D 3.jpg

Modelo-Vista-Controlador: Movendo os Modelos 3D

Imos modificar o exercicio anterior para que siga a arquitectura Modelo-Vista.

O controlador xa o sabedes implementar das unidades referidas o xogo 2D polo que por motivos de 'rapidez' non o imos utilizar neste exemplo.

Preparación:

  • Crear unha nova clase de nome EX_4_MoverModelosMVC.
  • Cambiade a clase PracticasNovaApi3D para que chame á nova clase.

Empecemos creando os modelos:

Código da clase Elemento3D
Obxectivo: Crear o Modelo. Saltamos o paso de crear a clase Mundo para facelo máis sinxelo.

 1 import com.badlogic.gdx.math.Matrix4;
 2 import com.badlogic.gdx.math.Vector3;
 3 
 4 public class Elemento3D {
 5 	public Matrix4 matriz;
 6 	public Vector3 posicion;
 7 	public float escala;
 8 	public Vector3 velocidade;
 9 	public Vector3 rotacion;
10 
11 	public float anguloRotacion;
12 	private int velocidadeRotacion;
13 	
14 	private Vector3 temp;
15 	
16 	public Elemento3D(Vector3 pos, float escala,Vector3 velocidade, Vector3 rotacion,int velocidadeRotacion){
17 		matriz = new Matrix4();
18 		posicion = pos;
19 		this.escala=escala;
20 		this.velocidade = velocidade;
21 		this.rotacion=rotacion;
22 		anguloRotacion=0;
23 		this.velocidadeRotacion=velocidadeRotacion;
24 		
25 		temp = new Vector3();
26 	}
27 	
28 	
29 	public void update(float delta){
30 		
31 		temp.set(velocidade);
32 		posicion.add(temp.scl(delta));
33 		anguloRotacion+=delta*velocidadeRotacion;
34 
35 		matriz.idt();
36 		matriz.translate(posicion);
37 		matriz.scl(escala);
38 		matriz.rotate(rotacion, anguloRotacion);
39 		
40 	}
41 
42 }


Como vemos o máis importante a ter en conta é que imos gardar nesta clase a Matriz de modelado que vai usarse para representar a figura. Fixarse como sempre partimos da matriz de identidade e aplicamos a traslación, escala e rotación (liñas 35-38).

  • Liñas 24-25: Agora xa non necesitamos un array de ModelInstances. Imos gardar un único ModelInstance por cada tipo de elemento gráfico (unha nave e un bloque).
  • Liñas 27-28: Gardamos en obxectos da clase Elemento3D os datos de cada figura.
  • Liñas 44-53: Facemos o mesmo que no exercicio anterior (os mesmos datos) pero esta vez son gardados en obxectos que pertencen á clase Elementos3D.
  • Liña 76: A cámara mira cara a posición da nave.
  • Liñas 81-86: Moi importante: Actualizamos a MATRIZ de cada bloque e asinamos ó ModelInstance a matriz gardada.
  • Liñas 88-92: Movemos a nave e a rotamos para que estea cara os bloques. Actualizamos a matriz e asinamos ó ModelInstance da nave a matriz gardada.
  • Liña 145: Limpamos o array del bloques.


Código da clase EX_4_MoverModelosMVC
Obxectivo: Facemos o mesmo exercicio anterior pero utilizando a matriz gardada na clase Elemento3D.

  1 import com.badlogic.gdx.Gdx;
  2 import com.badlogic.gdx.Screen;
  3 import com.badlogic.gdx.assets.AssetManager;
  4 import com.badlogic.gdx.graphics.GL20;
  5 import com.badlogic.gdx.graphics.PerspectiveCamera;
  6 import com.badlogic.gdx.graphics.g3d.Environment;
  7 import com.badlogic.gdx.graphics.g3d.Model;
  8 import com.badlogic.gdx.graphics.g3d.ModelBatch;
  9 import com.badlogic.gdx.graphics.g3d.ModelInstance;
 10 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
 11 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
 12 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
 13 import com.badlogic.gdx.math.Vector3;
 14 import com.badlogic.gdx.utils.Array;
 15 import com.plategaxogo3davanzado.angel.Elemento3D;
 16 
 17 
 18 
 19 public class EX_4_MoverModelosMVC implements Screen {
 20 
 21 	private PerspectiveCamera camara3d;
 22 	private  ModelBatch modelBatch;
 23 
 24 	private ModelInstance instanceNave;
 25 	private ModelInstance instanceBloques;
 26 	
 27 	private Array<Elemento3D>bloques;
 28 	private Elemento3D nave;
 29 	
 30 	private Environment environment;
 31 	private CameraInputController camController;
 32 	
 33 		
 34 	public EX_4_MoverModelosMVC(){
 35 		camara3d = new PerspectiveCamera();
 36 		camController = new CameraInputController(camara3d);
 37 		Gdx.input.setInputProcessor(camController);
 38 		
 39 		modelBatch = new ModelBatch();
 40 		environment = new Environment();
 41                 environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
 42                 environment.add(new DirectionalLight().set(1f, 1f, 1f, 1f, 0f, 0f));
 43 
 44                 bloques = new Array<Elemento3D>();
 45                 for (int cont=1; cont < 10;cont++){
 46           	   if (cont>3 && cont<6){
 47         		bloques.add(new Elemento3D(new Vector3(3*cont, 0, 0),0.5f,new Vector3(0,0,0),new Vector3(1,1,1),30));
 48         	   }
 49         	   else
 50         		bloques.add(new Elemento3D(new Vector3(3*cont, 0, 0),1f,new Vector3(0,0,0),new Vector3(1,1,1),50));
 51                 }
 52         
 53                 nave = new Elemento3D(new Vector3(0,0,0), 1, new Vector3(1f, 0, 0),new Vector3(0,0,0),0);
 54         
 55         
 56 
 57                 AssetManager assets = new AssetManager();
 58                 assets.load("ship.obj", Model.class);
 59                 assets.load("cube.g3db", Model.class);
 60                 assets.finishLoading();
 61         
 62                 Model modelNave = assets.get("ship.obj", Model.class);
 63                 Model modelCubo = assets.get("cube.g3db", Model.class);
 64 
 65                 instanceBloques = new ModelInstance(modelCubo);
 66                 instanceNave = new ModelInstance(modelNave);
 67 	}
 68 	
 69 	@Override
 70 	public void render(float delta) {
 71 		// TODO Auto-generated method stub
 72 		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
 73 		 
 74 		camController.update();
 75 		
 76 		camara3d.lookAt(nave.posicion);
 77 		camara3d.update();
 78 		
 79         modelBatch.begin(camara3d);
 80 
 81         for (Elemento3D bloque : bloques){
 82         	bloque.update(delta);
 83         	instanceBloques.transform.set(bloque.matriz);
 84             modelBatch.render(instanceBloques,environment);
 85         	
 86         }
 87         
 88         nave.posicion.x += nave.velocidade.x*delta;
 89         nave.update(delta);
 90         nave.matriz.rotate(0, 1,0,90);
 91         instanceNave.transform.set(nave.matriz);
 92         modelBatch.render(instanceNave,environment);
 93         
 94         modelBatch.end();	
 95 	}
 96 
 97 	
 98 	@Override
 99 	public void resize(int width, int height) {
100 		// TODO Auto-generated method stub
101 		
102 		camara3d.fieldOfView=67;
103 		camara3d.viewportWidth=width;
104 		camara3d.viewportHeight=height;
105 		
106 		Gdx.input.setInputProcessor(camController);
107 		
108 		camara3d.position.set(0f,0f,15f);
109 		camara3d.lookAt(0,0,0);
110 		camara3d.near=1;
111 		camara3d.far=300f;
112 		camara3d.update();
113 		
114 
115 	}
116 
117 	@Override
118 	public void show() {
119 		// TODO Auto-generated method stub
120 	}
121 
122 	@Override
123 	public void hide() {
124 		// TODO Auto-generated method stub
125 		
126 	}
127 
128 	@Override
129 	public void pause() {
130 		// TODO Auto-generated method stub
131 		
132 	}
133 
134 	@Override
135 	public void resume() {
136 		// TODO Auto-generated method stub
137 		
138 	}
139 
140 	@Override
141 	public void dispose() {
142 		// TODO Auto-generated method stub
143 		
144 		modelBatch.dispose();
145 		bloques.clear();
146 		
147 		
148 	}
149 
150 }


Vexamos as diferenzas:

  • Liñas 24-25: Agora xa non necesitamos un array de ModelInstances. Imos gardar un único ModelInstance por cada tipo de elemento gráfico (unha nave e un bloque).
  • Liñas 27-28: Gardamos en obxectos da clase Elemento3D os datos de cada figura.
  • Liñas 44-53: Facemos o mesmo que no exercicio anterior (os mesmos datos) pero esta vez son gardados en obxectos que pertencen á clase Elementos3D.
  • Liña 76: A cámara mira cara a posición da nave.
  • Liñas 81-86: Moi importante: Actualizamos a MATRIZ de cada bloque e asinamos ó ModelInstance a matriz gardada.
  • Liñas 88-92: Movemos a nave e a rotamos para que estea cara os bloques. Actualizamos a matriz e asinamos ó ModelInstance da nave a matriz gardada.
  • Liña 145: Limpamos o array del bloques.


Se executades o código o resultado é o mesmo que no caso anterior.

Por eficiencia pode ser mellor ter un array de ModelInstances e renderizalos todos de vez. Isto o podemos facer igual pero teríamos que asinar a cada elemento do array de ModelInstace a matriz gardada no array de Elementos3D.

No blog de Xoppa tedes unha entrada no que amosa como podemos cargar todos os modelos de vez dun só acceso á disco: http://blog.xoppa.com/loading-a-scene-with-libgdx/







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