LIBGDX Carga Modelos3D
UNIDADE 4: Carga de Modelos 3D
Sumario
Deseñando os nosos modelos 3D
Loxicamente os nosos modelos 3D non vai ser creados 'manualmente', se non utilizando programas gráficos.
Algún deles:
- Blender: http://www.blender.org/
- Moi completo pero tamén bastante complexo.
- Wings3D: http://www.wings3d.com
- Bastante máis sinxelo.
Nos imos usar o wings3d aínda que os alumnos podedes utilizar calquera que manexedes.
A continuación tedes un enlace con tres vídeos (e o códec de vídeo por se non o visualizades) de como se manexa o Wings3D e como podemos crear un obxecto 3D e asinarlle unha textura.
Conversión de formatos en 3D
En canto os formatos gráficos que podemos cargar están, entre outros:
- obj: https://en.wikipedia.org/wiki/Wavefront_.obj_file
- md2: https://en.wikipedia.org/wiki/MD2_%28file_format%29
- fbx: http://en.wikipedia.org/wiki/FBX
- g3dj: Formato g3d en mode texto Json (se pode editar).
- g3db: Formato g3d en binario. É o mais rápido de cargar e o que menos ocupa.
Para pasar dun formato a outro podemos utilizar unha ferramenta: fbx-conv.
Podemos ver o código fonte en: https://github.com/libgdx/fbx-conv
Podemos descargar a versión compilada en: http://libgdx.badlogicgames.com/fbx-conv/
Información na wiki: https://github.com/libgdx/fbx-conv
O proceso para pasar dun obj a un g3db sería:
- Descargar a versión compilada do enlace anterior.
- Descomprimide e abride unha consola.
- Se estades en Linux hai que copiar a librería libfbxsdk.so a /usr/lib.
- Se estades en Windows debedes ter instalado o paquete VC 2010 Redistributable Package.
- Vos situades onde se atopan os executables e escolledes a versión correspondente ó voso S.O.:
- fbx-conv-win32.exe: Windows
- fbx-conv-lin64: Linux
- fbx-conv-mac: Mac
- A orde para pasar por exemplo de obj a g3db seria:
1 fbx-conv-win32.exe modelo_entrada.obj modelo_saida.g3db
NOTA: Sempre que queiramos acelerar a carga dos modelos deberemos de pasalos a binario.
Carga de Modelos 3D
Nota: O que imos ver aquí é unha forma de cargar os Mesh cun formato obj. Dito formato non leva información de cor en cada vértice como vimos nos anteriores puntos, e polo tanto o ShaderProgram non ten que recoller o parámetro de cor.
Polo tanto os arquivos vertex.vrt e fragment.frag quedarían da seguinte maneira:
Arquivo vertext.vert
1 attribute vec3 a_position; 2 attribute vec2 a_texCoord0; 3 varying vec2 v_textCoord; 4 uniform mat4 u_worldView; 5 void main() 6 { 7 gl_Position = u_worldView *vec4(a_position,1); 8 9 v_textCoord = a_texCoord0; 10 }
Arquivo fragment.frag
1 #ifdef GL_ES 2 precision mediump float; 3 #endif 4 varying vec2 v_textCoord; 5 uniform sampler2D u_texture; 6 void main() 7 { 8 vec4 texColor = texture2D(u_texture, v_textCoord); 9 gl_FragColor = texColor; 10 }
Para cargar e manexar os modelos dunha forma máis sinxela mirade o punto: Programación avanzada 3D. De todas formas recomendo a lectura desta parte para entender os principios básicos.
Carga Modelos obj
Para cargar un modelo obj temos que facer uso da clase ModelLoader.
O proceso sería:
- Crear unha instancia de dita clase:
1 ModelLoader loader = new ObjLoader();
- Chamar ó método loadModel:
1 Model model = loader.loadModel(Gdx.files.internal("modelos/ship.obj"));
Dito método espera recibir como parámetro o arquivo obj.
Este método devolve un obxecto da clase Model.
Para nos un Model ven ser como un Mesh, o que sucede é que nun model poden ser cargados moitos Mesh de vez, polo que para ter unha referencia a un concreto faremos o seguinte:
- Cargamos o Mesh:
1 private Mesh meshNave; 2 ............. 3 meshNave = model.meshes.get(0);
No noso caso só temos un Mesh no obj.
Exemplo:
Imos ver un exemplo completo, engadindo un modelo dunha nave e movéndoa cara a cámara, facendo que a cámara siga a nave cando a pase.
Preparación: Crear unha clase de nome UD4_6_CargaModelos3D, que derive da clase Game e sexa chamada pola clase principal das diferentes versións (desktop, android,...).
Crea un cartafol de nome modelos dentro do cartafol assets da versión Android.
Leva ó cartafol assets/modelos os arquivos ship.mtl, ship.obj e ship.png que se atopan no seguinte arquivo comprimido:
Creamos unha clase Elementos3D que garde a información de calquera elemento 3D. É igual á clase Cubo que utilizamos no exercicio anterior:
Código da clase Elementos3D
Obxectivo: Definir unha clase que garde o que necesitamos dun obxecto 3d.
1 import com.badlogic.gdx.math.Matrix4;
2 import com.badlogic.gdx.math.Vector3;
3
4 public class Elemento3D {
5
6 public Matrix4 matriz;
7 public Vector3 posicion;
8 public float escala;
9 public Vector3 velocidade;
10 private Vector3 temp;
11
12 public Elemento3D(Vector3 pos, float escala,Vector3 velocidade){
13 matriz = new Matrix4();
14 posicion = pos;
15 this.escala=escala;
16 this.velocidade = velocidade;
17
18 temp = new Vector3();
19
20 }
21
22 public void update(float delta){
23
24 temp.set(velocidade);
25 posicion.add(temp.scl(delta));
26
27
28 matriz.idt();
29 matriz.translate(posicion);
30 matriz.scl(escala);
31
32
33 }
34
35 }
Agora imos ver o código de carga da nave.
1 import com.badlogic.gdx.Game;
2 import com.badlogic.gdx.Gdx;
3 import com.badlogic.gdx.assets.loaders.ModelLoader;
4 import com.badlogic.gdx.files.FileHandle;
5 import com.badlogic.gdx.graphics.GL20;
6 import com.badlogic.gdx.graphics.Mesh;
7 import com.badlogic.gdx.graphics.PerspectiveCamera;
8 import com.badlogic.gdx.graphics.Texture;
9 import com.badlogic.gdx.graphics.g3d.Model;
10 import com.badlogic.gdx.graphics.g3d.loader.ObjLoader;
11 import com.badlogic.gdx.graphics.glutils.ShaderProgram;
12 import com.badlogic.gdx.math.Vector3;
13
14 /**
15 * Cargando modelos 3D
16 * @author ANGEL
17 */
18
19 public class UD4_6_CargaModelos3D extends Game {
20
21 private Mesh meshNave;
22 private Elemento3D nave;
23 private ShaderProgram shaderProgram;
24
25 private Texture textura;
26 private PerspectiveCamera camara3d;
27
28
29
30 @Override
31 public void create() {
32 // TODO Auto-generated method stub
33
34 shaderProgram = new ShaderProgram(Gdx.files.internal("vertex.vert"), Gdx.files.internal("fragment.frag"));
35 if (shaderProgram.isCompiled() == false) {
36 Gdx.app.log("ShaderError", shaderProgram.getLog());
37 System.exit(0);
38 }
39
40
41 ModelLoader loader = new ObjLoader();
42 Model model = loader.loadModel(Gdx.files.internal("modelos/ship.obj"));
43 meshNave = model.meshes.get(0);
44
45 FileHandle imageFileHandle = Gdx.files.internal("modelos/ship.png");
46 textura = new Texture(imageFileHandle);
47
48 camara3d = new PerspectiveCamera();
49 nave = new Elemento3D(new Vector3(0,-1f,-20f), 2f, new Vector3(0.1f,0.1f,2f));
50
51 }
52
53
54 @Override
55 public void render() {
56
57 Gdx.gl20.glClearColor(0f, 0f, 0f, 1f);
58 Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
59
60 Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST);
61 Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
62
63 nave.update(Gdx.graphics.getDeltaTime());
64
65 camara3d.lookAt(nave.posicion);
66 camara3d.update();
67
68 shaderProgram.begin();
69 textura.bind(0);
70 shaderProgram.setUniformi("u_texture", 0);
71 shaderProgram.setUniformMatrix("u_worldView", camara3d.combined.cpy().mul(nave.matriz));
72 meshNave.render(shaderProgram, GL20.GL_TRIANGLES);
73
74
75
76 shaderProgram.end();
77
78 Gdx.gl20.glDisable(GL20.GL_TEXTURE_2D);
79 Gdx.gl20.glDisable(GL20.GL_DEPTH_TEST);
80
81 }
82
83 @Override
84 public void resize (int width,int height){
85 // Definimos os parámetros da cámara
86 float aspectRatio = (float) width / (float) height;
87 camara3d.viewportWidth=aspectRatio*1f;
88 camara3d.viewportHeight=1f;
89 camara3d.far=1000f;
90 camara3d.near=0.1f;
91 camara3d.lookAt(0,0,0);
92 camara3d.position.set(0f,0f,5f);
93 camara3d.update();
94 }
95
96 @Override
97 public void dispose(){
98 shaderProgram.dispose();
99 meshNave.dispose();
100
101 }
102
103 }
- Liña 21: Definimos o obxecto Mesh que vai representar a nave.
- Liñas 41-43: Cargamos o obj utilizando a clase ModelLoader.
- Liña 49: Instanciamos a nave pasándolle uns datos concretos.
- Liñas 65-66: Facemos que a cámara mire cara a nave. LEMBRAR CHAMAR AO UPDATE.
- Liña 72: Renderizamos a nave.
- Liña 99: Liberamos a memoria.
TAREFA 4.5 A FACER: Esta parte está asociada á realización dunha tarefa.
Carga Modelos g3db
Para cargar estes modelos debemos facer uso da clase AssetManager.
Como isto é optativo na parte 2D non fai falla que o provedes.
Para cargar un modelo g3db previamente obtido coa ferramenta fbx-conv debemos facer o seguinte:
- Crear un obxecto da clase AssetManager (que xa podemos ter creado se utilizamos esta forma de carga dos gráficos do xogo):
1 AssetManager assetManager = new AssetManager();
- Chamamos ó método load para cargar o modelo e esperamos a que remate de cargar.
1 assetManager.load("modelos/ship.g3db", Model.class);
2
3 assetManager.finishLoading();
- Obtemos o obxecto da clase Model como fixemos no caso anterior:
1 Model model = assetManager.get("modelos/ship.g3db", Model.class);
- Cargamos o Mesh que se atopa no Model (só temos un).
1 meshNave = model.meshes.get(0);
O código completo:
1 AssetManager assetManager = new AssetManager();
2 assetManager.load("modelos/ship.g3db", Model.class);
3
4 assetManager.finishLoading();
5
6 Model model = assetManager.get("modelos/ship.g3db", Model.class);
7 meshNave = model.meshes.get(0);
Modelos 3D xa feitos
Temos diferentes sitios web onde obter modelos 3D.
-- Ángel D. Fernández González -- (2015).