LIBGDX APIMoverModelos3D

De MediaWiki
Saltar a: navegación, buscar

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