https://manuais.iessanclemente.net/index.php?title=LIBGDX_APIMoverModelos3D&feed=atom&action=historyLIBGDX APIMoverModelos3D - Historial de revisiones2024-03-29T06:15:20ZHistorial de revisiones de esta página en el wikiMediaWiki 1.36.2https://manuais.iessanclemente.net/index.php?title=LIBGDX_APIMoverModelos3D&diff=48731&oldid=prevAngelfg en 21:02 3 oct 20142014-10-03T21:02:29Z<p></p>
<p><b>Página nueva</b></p><div><span style="font-size:150%;">UNIDADE 5: Mover modelos 3D</span><br />
<br />
<br />
<br />
===Introdución===<br />
<br />
Neste apartado imos ver como mover os modelos 3D cargados coa clase ModelInstance, facendo uso das matrices.<br />
<br />
Para mover os modelos só temos que aplicar o aprendido [http://manuais.iessanclemente.net/index.php?title=LIBGDX_Animacions3D#Animando_o_cubo:_translaci.C3.B3n.2C_rotaci.C3.B3n_e_escalado na Unidade 4].<br />
<br />
<br />
'''Preparación:'''<br />
<br />
Creamos unha nova clase de nome EX_3_MoverModelos que sexa chamada pola clase PracticasNovaApi3D.<br />
<br />
<br />
<br />
===Movendo os Modelos 3D===<br />
<br />
<br />
A matriz de modelado-vista se atopa na [http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/ModelInstance.html#transform propiedade transform] do ModelInstance, e este a su vez está asociado a un Model.<br />
<br />
Clase utilizada: [http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Matrix4.html Matrix4].<br />
<br />
Operacións (todas elas sobrecargadas) sobre a '''propiedade transform''' do ModelInstance:<br />
<br />
* Traslación: <br />
<br />
::[http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Matrix4.html#setToTranslation-float-float-float- 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'''.<br />
<br />
::[http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Matrix4.html#setTranslation-float-float-float- public Matrix4 setTranslation(float x,float y, float z)]: Posiciona o obxecto nas coordenadas indicadas. Non carga a matriz identidade.<br />
<br />
* Rotación:<br />
<br />
::[http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Matrix4.html#setToRotation-com.badlogic.gdx.math.Vector3-float- 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.<br />
<br />
::[http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Matrix4.html#rotate-float-float-float-float- 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.<br />
<br />
* Escala:<br />
<br />
::[http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Matrix4.html#setTranslation-float-float-float- public Matrix4 setToScaling(Vector3 vector)]: <u>Carga a matriz identidade</u> e escala a matriz no valor indicado no eixe correspondente.<br />
<br />
:'''<u>Atención:</u>''': 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:<br />
<br />
* Traslación e escala:<br />
<br />
::[http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Matrix4.html#setToTranslationAndScaling-float-float-float-float-float-float- public Matrix4 setToTranslationAndScaling(float translationX,float translationY,float translationZ,float scalingX,float scalingY,float scalingZ)]: Rota e escala á vez. Carga a matriz de identidade e aplica a rotación e escala nos eixes indicados cun valor de 1.<br />
<br />
<br />
<br />
<br />
Imos facer un exemplo.<br />
<br />
Seguindo co exercicio anterior (o podedes gardar facendo copy e paste sobre o propio arquivo en Eclipse).<br />
<br />
'''Código da clase EX_3_MoverModelos'''<br/><br />
'''Obxectivo:''' Cargar varios modelos e animalos. Operacións de escala, rotacion e traslación.<br />
<syntaxhighlight lang="java" line enclose="div" highlight="51-52,54-64,78-80,82,85-86,90-91" ><br />
import com.badlogic.gdx.Gdx;<br />
import com.badlogic.gdx.Screen;<br />
import com.badlogic.gdx.assets.AssetManager;<br />
import com.badlogic.gdx.graphics.GL20;<br />
import com.badlogic.gdx.graphics.PerspectiveCamera;<br />
import com.badlogic.gdx.graphics.g3d.Environment;<br />
import com.badlogic.gdx.graphics.g3d.Model;<br />
import com.badlogic.gdx.graphics.g3d.ModelBatch;<br />
import com.badlogic.gdx.graphics.g3d.ModelInstance;<br />
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;<br />
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;<br />
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;<br />
import com.badlogic.gdx.utils.Array;<br />
<br />
<br />
<br />
public class EX_3_MoverModelos implements Screen {<br />
<br />
private PerspectiveCamera camara3d;<br />
private ModelBatch modelBatch;<br />
<br />
private Array<ModelInstance> instances;<br />
private ModelInstance instanceNave;<br />
<br />
<br />
private Environment environment;<br />
private CameraInputController camController;<br />
<br />
private float pos;<br />
<br />
public EX_3_MoverModelos(){<br />
camara3d = new PerspectiveCamera();<br />
camController = new CameraInputController(camara3d);<br />
Gdx.input.setInputProcessor(camController);<br />
<br />
modelBatch = new ModelBatch();<br />
environment = new Environment();<br />
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));<br />
environment.add(new DirectionalLight().set(1f, 1f, 1f, 1f, 0f, 0f));<br />
<br />
instances = new Array<ModelInstance>();<br />
<br />
AssetManager assets = new AssetManager();<br />
assets.load("ship.obj", Model.class);<br />
assets.load("cube.g3db", Model.class);<br />
assets.finishLoading();<br />
<br />
Model modelNave = assets.get("ship.obj", Model.class);<br />
Model modelCubo = assets.get("cube.g3db", Model.class);<br />
<br />
instanceNave = new ModelInstance(modelNave);<br />
instanceNave.transform.setToRotation(0, 1, 0, 90);<br />
<br />
for (int cont=1; cont < 10;cont++){<br />
ModelInstance cubo = new ModelInstance(modelCubo);<br />
if (cont>3 && cont<6){<br />
cubo.transform.setToTranslationAndScaling(cont*3, 0, 0, 0.5f, 0.5f, 0.5f);<br />
}<br />
else<br />
cubo.transform.setTranslation(cont*3,0,0);<br />
<br />
instances.add(cubo);<br />
<br />
}<br />
<br />
}<br />
<br />
<br />
@Override<br />
public void render(float delta) {<br />
// TODO Auto-generated method stub<br />
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);<br />
<br />
camController.update();<br />
<br />
pos+=delta * 1f;<br />
<br />
for (ModelInstance modelI : instances){<br />
modelI.transform.rotate(0,1,0,delta*30f); // Continua a rotación, non empeza de 0<br />
}<br />
<br />
instanceNave.transform.setTranslation(pos,0,0);<br />
<br />
<br />
camara3d.lookAt(pos,0,0);<br />
camara3d.update();<br />
<br />
modelBatch.begin(camara3d);<br />
<br />
modelBatch.render(instances,environment);<br />
modelBatch.render(instanceNave,environment);<br />
<br />
modelBatch.end(); <br />
}<br />
<br />
<br />
@Override<br />
public void resize(int width, int height) {<br />
// TODO Auto-generated method stub<br />
<br />
camara3d.fieldOfView=67;<br />
camara3d.viewportWidth=width;<br />
camara3d.viewportHeight=height;<br />
<br />
Gdx.input.setInputProcessor(camController);<br />
<br />
camara3d.position.set(0f,0f,15f);<br />
camara3d.lookAt(0,0,0);<br />
camara3d.near=1;<br />
camara3d.far=300f;<br />
camara3d.update();<br />
<br />
<br />
}<br />
<br />
@Override<br />
public void show() {<br />
// TODO Auto-generated method stub<br />
}<br />
<br />
@Override<br />
public void hide() {<br />
// TODO Auto-generated method stub<br />
<br />
}<br />
<br />
@Override<br />
public void pause() {<br />
// TODO Auto-generated method stub<br />
<br />
}<br />
<br />
@Override<br />
public void resume() {<br />
// TODO Auto-generated method stub<br />
<br />
}<br />
<br />
@Override<br />
public void dispose() {<br />
// TODO Auto-generated method stub<br />
<br />
modelBatch.dispose();<br />
instances.clear();<br />
<br />
<br />
}<br />
<br />
}<br />
<br />
</syntaxhighlight> <br />
<br />
Comentemos o código:<br />
<br />
* 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.<br />
* 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.<br />
* 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).<br />
* Liña 82: Movemos a nave.<br />
* Liñas 85-86: Facemos que a cámara siga á nave.<br />
* Liñas 90-91: Renderizamos os ModelInstace dos bloques (array) e a nave.<br />
<br />
Ó final teremos como resultado isto:<br />
<br />
[[Imagen:LIBGDX_UD5_CargaModelos3D_3.jpg|400px|center]]<br />
<br />
===Modelo-Vista-Controlador: Movendo os Modelos 3D===<br />
<br />
Imos modificar o exercicio anterior para que siga a arquitectura Modelo-Vista.<br />
<br />
O controlador xa o sabedes implementar das unidades referidas o xogo 2D polo que por motivos de 'rapidez' non o imos utilizar neste exemplo.<br />
<br />
'''Preparación:''' <br />
* Crear unha nova clase de nome EX_4_MoverModelosMVC.<br />
* Cambiade a clase PracticasNovaApi3D para que chame á nova clase.<br />
<br />
Empecemos creando os modelos:<br />
<br />
'''Código da clase Elemento3D'''<br/><br />
'''Obxectivo:''' Crear o Modelo. Saltamos o paso de crear a clase Mundo para facelo máis sinxelo.<br />
<syntaxhighlight lang="java" line enclose="div" highlight="35-38" ><br />
import com.badlogic.gdx.math.Matrix4;<br />
import com.badlogic.gdx.math.Vector3;<br />
<br />
public class Elemento3D {<br />
public Matrix4 matriz;<br />
public Vector3 posicion;<br />
public float escala;<br />
public Vector3 velocidade;<br />
public Vector3 rotacion;<br />
<br />
public float anguloRotacion;<br />
private int velocidadeRotacion;<br />
<br />
private Vector3 temp;<br />
<br />
public Elemento3D(Vector3 pos, float escala,Vector3 velocidade, Vector3 rotacion,int velocidadeRotacion){<br />
matriz = new Matrix4();<br />
posicion = pos;<br />
this.escala=escala;<br />
this.velocidade = velocidade;<br />
this.rotacion=rotacion;<br />
anguloRotacion=0;<br />
this.velocidadeRotacion=velocidadeRotacion;<br />
<br />
temp = new Vector3();<br />
}<br />
<br />
<br />
public void update(float delta){<br />
<br />
temp.set(velocidade);<br />
posicion.add(temp.scl(delta));<br />
anguloRotacion+=delta*velocidadeRotacion;<br />
<br />
matriz.idt();<br />
matriz.translate(posicion);<br />
matriz.scl(escala);<br />
matriz.rotate(rotacion, anguloRotacion);<br />
<br />
}<br />
<br />
}<br />
<br />
</syntaxhighlight> <br />
<br />
<br />
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.<br />
Fixarse como sempre partimos da matriz de identidade e aplicamos a traslación, escala e rotación (liñas 35-38).<br />
* 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).<br />
* Liñas 27-28: Gardamos en obxectos da clase Elemento3D os datos de cada figura.<br />
* 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.<br />
* Liña 76: A cámara mira cara a posición da nave.<br />
* Liñas 81-86: '''Moi importante:''' Actualizamos a MATRIZ de cada bloque e asinamos ó ModelInstance a matriz gardada.<br />
* 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.<br />
* Liña 145: Limpamos o array del bloques.<br />
<br />
<br />
'''Código da clase EX_4_MoverModelosMVC'''<br/><br />
'''Obxectivo:''' Facemos o mesmo exercicio anterior pero utilizando a matriz gardada na clase Elemento3D.<br />
<syntaxhighlight lang="java" line enclose="div" highlight="24-25,27-28,44-53,76,81-86,88-92,145" ><br />
import com.badlogic.gdx.Gdx;<br />
import com.badlogic.gdx.Screen;<br />
import com.badlogic.gdx.assets.AssetManager;<br />
import com.badlogic.gdx.graphics.GL20;<br />
import com.badlogic.gdx.graphics.PerspectiveCamera;<br />
import com.badlogic.gdx.graphics.g3d.Environment;<br />
import com.badlogic.gdx.graphics.g3d.Model;<br />
import com.badlogic.gdx.graphics.g3d.ModelBatch;<br />
import com.badlogic.gdx.graphics.g3d.ModelInstance;<br />
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;<br />
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;<br />
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;<br />
import com.badlogic.gdx.math.Vector3;<br />
import com.badlogic.gdx.utils.Array;<br />
import com.plategaxogo3davanzado.angel.Elemento3D;<br />
<br />
<br />
<br />
public class EX_4_MoverModelosMVC implements Screen {<br />
<br />
private PerspectiveCamera camara3d;<br />
private ModelBatch modelBatch;<br />
<br />
private ModelInstance instanceNave;<br />
private ModelInstance instanceBloques;<br />
<br />
private Array<Elemento3D>bloques;<br />
private Elemento3D nave;<br />
<br />
private Environment environment;<br />
private CameraInputController camController;<br />
<br />
<br />
public EX_4_MoverModelosMVC(){<br />
camara3d = new PerspectiveCamera();<br />
camController = new CameraInputController(camara3d);<br />
Gdx.input.setInputProcessor(camController);<br />
<br />
modelBatch = new ModelBatch();<br />
environment = new Environment();<br />
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));<br />
environment.add(new DirectionalLight().set(1f, 1f, 1f, 1f, 0f, 0f));<br />
<br />
bloques = new Array<Elemento3D>();<br />
for (int cont=1; cont < 10;cont++){<br />
if (cont>3 && cont<6){<br />
bloques.add(new Elemento3D(new Vector3(3*cont, 0, 0),0.5f,new Vector3(0,0,0),new Vector3(1,1,1),30));<br />
}<br />
else<br />
bloques.add(new Elemento3D(new Vector3(3*cont, 0, 0),1f,new Vector3(0,0,0),new Vector3(1,1,1),50));<br />
}<br />
<br />
nave = new Elemento3D(new Vector3(0,0,0), 1, new Vector3(1f, 0, 0),new Vector3(0,0,0),0);<br />
<br />
<br />
<br />
AssetManager assets = new AssetManager();<br />
assets.load("ship.obj", Model.class);<br />
assets.load("cube.g3db", Model.class);<br />
assets.finishLoading();<br />
<br />
Model modelNave = assets.get("ship.obj", Model.class);<br />
Model modelCubo = assets.get("cube.g3db", Model.class);<br />
<br />
instanceBloques = new ModelInstance(modelCubo);<br />
instanceNave = new ModelInstance(modelNave);<br />
}<br />
<br />
@Override<br />
public void render(float delta) {<br />
// TODO Auto-generated method stub<br />
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);<br />
<br />
camController.update();<br />
<br />
camara3d.lookAt(nave.posicion);<br />
camara3d.update();<br />
<br />
modelBatch.begin(camara3d);<br />
<br />
for (Elemento3D bloque : bloques){<br />
bloque.update(delta);<br />
instanceBloques.transform.set(bloque.matriz);<br />
modelBatch.render(instanceBloques,environment);<br />
<br />
}<br />
<br />
nave.posicion.x += nave.velocidade.x*delta;<br />
nave.update(delta);<br />
nave.matriz.rotate(0, 1,0,90);<br />
instanceNave.transform.set(nave.matriz);<br />
modelBatch.render(instanceNave,environment);<br />
<br />
modelBatch.end(); <br />
}<br />
<br />
<br />
@Override<br />
public void resize(int width, int height) {<br />
// TODO Auto-generated method stub<br />
<br />
camara3d.fieldOfView=67;<br />
camara3d.viewportWidth=width;<br />
camara3d.viewportHeight=height;<br />
<br />
Gdx.input.setInputProcessor(camController);<br />
<br />
camara3d.position.set(0f,0f,15f);<br />
camara3d.lookAt(0,0,0);<br />
camara3d.near=1;<br />
camara3d.far=300f;<br />
camara3d.update();<br />
<br />
<br />
}<br />
<br />
@Override<br />
public void show() {<br />
// TODO Auto-generated method stub<br />
}<br />
<br />
@Override<br />
public void hide() {<br />
// TODO Auto-generated method stub<br />
<br />
}<br />
<br />
@Override<br />
public void pause() {<br />
// TODO Auto-generated method stub<br />
<br />
}<br />
<br />
@Override<br />
public void resume() {<br />
// TODO Auto-generated method stub<br />
<br />
}<br />
<br />
@Override<br />
public void dispose() {<br />
// TODO Auto-generated method stub<br />
<br />
modelBatch.dispose();<br />
bloques.clear();<br />
<br />
<br />
}<br />
<br />
}<br />
</syntaxhighlight> <br />
<br />
<br />
Vexamos as diferenzas:<br />
<br />
* 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).<br />
* Liñas 27-28: Gardamos en obxectos da clase Elemento3D os datos de cada figura.<br />
* 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.<br />
* Liña 76: A cámara mira cara a posición da nave.<br />
* Liñas 81-86: '''Moi importante:''' Actualizamos a MATRIZ de cada bloque e asinamos ó ModelInstance a matriz gardada.<br />
* 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.<br />
* Liña 145: Limpamos o array del bloques.<br />
<br />
<br />
Se executades o código o resultado é o mesmo que no caso anterior.<br />
<br />
Por eficiencia pode ser mellor ter un array de ModelInstances e renderizalos todos de vez.<br />
Isto o podemos facer igual pero teríamos que asinar a cada elemento do array de ModelInstace a matriz gardada no array de Elementos3D.<br />
<br />
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/<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br> -- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2014).</div>Angelfg