本篇教程用到的模型资源点击 飞船模型资源下载 进行下载。
您可以使用自己喜欢的建模软件来创建一个模型。这里我使用了 libGDX 的 gdx-invaders 附带的飞船模型,你可以在这里找到。您可以将其解压缩到资源文件夹中。请注意,这里主要用到下面三个文件(ship.g3db是转换后的模型,这里可以先不管,本篇教程后面会详细说明),必须包含在同一文件夹中:
本教程这个模型采用 OBJ 文件格式。但是在 libGDX 中 OBJ 格式支持不好,应避免使用。在本教程的后面,我们会把模型转换为更合适的文件格式。如果使用自己的(OBJ)模型,它可能会无法正确渲染。
我们在第一篇教程的基础上,更改其创建立方体的部分,将其换成导入我们的模型:
@Override
public void create () {
env = new Environment();
env.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
env.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
modelBatch = new ModelBatch();
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(1f, 1f, 1f);
cam.lookAt(0,0,0);
cam.near = 1f;
cam.far = 300f;
cam.update();
camCtrol = new CameraInputController(cam);
Gdx.input.setInputProcessor(camCtrol);
ModelLoader loader = new ObjLoader();
model = loader.loadModel(Gdx.files.internal("model/ship/ship.obj"));
instance = new ModelInstance(model);
}
这里只有一些变化。首先,我把相机放得离原点更近,因为船模型很小。接下来,我们删除了ModelBuilder,然后创建了一个ModelLoader,让它加载飞船模型,效果如下。
在更大的应用程序中,要性能最优的话,需要使用AssetManager来管理模型。因此,让我们添加AssetManager:
public class MainGame implements ApplicationListener {
private CameraInputController camCtrol;
private Environment env;
public PerspectiveCamera cam;
private Model model;
private ModelInstance instance;
private ModelBatch modelBatch;
private AssetManager assets;
private Array<ModelInstance> instances = new Array<>();
private boolean loading;
@Override
public void create() {
env = new Environment();
env.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
env.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
modelBatch = new ModelBatch();
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(1f, 1f, 1f);
cam.lookAt(0,0,0);
cam.near = 1f;
cam.far = 300f;
cam.update();
camCtrol = new CameraInputController(cam);
Gdx.input.setInputProcessor(camCtrol);
assets = new AssetManager();
assets.load("model/ship/ship.obj", Model.class);
loading = true;
}
private void doneLoading() {
Model ship = assets.get("model/ship/ship.obj", Model.class);
ModelInstance shipInstance = new ModelInstance(ship);
instances.add(shipInstance);
loading = false;
}
@Override
public void resize (int width, int height) {
}
@Override
public void render () {
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
camCtrol.update();
if (loading && assets.update()) {
doneLoading();
}
camCtrol.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(instances, env);
modelBatch.end();
}
@Override
public void pause () {
}
@Override
public void resume () {
}
@Override
public void dispose () {
modelBatch.dispose();
instances.clear();
assets.dispose();
}
}
我们删除了模型实例,并将其替换为AssetManager。我们将其替换为一组实例,而不是一个ModelInstance,这是一个更现实的场景,允许我们以后渲染更多的Instance。我们还添加了一个标志,表明我们是否仍在加载。
现在在Create方法中,我们创建资产管理器,并告诉它加载飞船模型。接下来我们设置加载标志,这样我们就知道需要更新assetmanager。在我们的渲染方法中,我们检查是否设置了加载标志,如果设置了,我们调用 assets.update()。如果是 assets.update() 返回true,我们知道它已经完成加载,所以我们调用了一个名为doneLoading()的新方法。此外,在render方法中,我们渲染所有实例,而不是仅渲染一个实例。如果 assets 尚未加载,这意味着数组为空。
新方法doneLoading()获取我们刚刚加载的船模型,创建一个名为shipInstance的实例,并将其添加到实例数组中,从而使其呈现。最后,我们需要将加载标志设置为false,这样就可以删除 assets。不再 assets.update() 方法。
由于我们现在支持多个模型实例,所以让我们再添加几个。
@Override
public void create () {
...
cam.position.set(7f, 7f, 7f);
...
}
private void doneLoading() {
Model ship = assets.get("data/ship.obj", Model.class);
for (float x = -5f; x <= 5f; x += 2f) {
for (float z = -5f; z <= 5f; z += 2f) {
ModelInstance shipInstance = new ModelInstance(ship);
shipInstance.transform.setToTranslation(x, 0, z);
instances.add(shipInstance);
}
}
loading = false;
}
在这里,我们把摄像机移到远离原点的地方,这样我们就能看到我们所有的船只。请注意,您也可以滚动鼠标进行放大或缩小。在doneLoad方法中,我们现在创建多个实例,并将它们放置在XZ平面上的网格中。
使用 obj 文件进行测试还可以。但它不适合在实际应用中使用,因为文件格式不包含足够的信息来渲染复杂模型。事实上,libGDX附带的ObjLoader仅用于测试,并没有实现您可能想要使用的所有功能。
因此我们需要使用 fbx-conv 工具,它将从建模软件导出的模型转换为适合使用libGDX 进行渲染的格式。与名称不同,fbx-conv 工具适合转换许多模型文件格式(包括obj),尽管fbx是首选的模型文件格式,因为几乎每个建模应用程序都支持这种格式。libGDX 支持两种文件格式:g3dj(为了便于调试,它是json文本格式)和g3db(在发布时应该使用二进制格式,因为它更小,加载速度更快)。
fbx-conv的使用教程可以点击这里阅读,我们转换后可以得到如下 ship.g3db 的模型:
我们在代码中就可以使用转换后的 g3db 模型了。
@Override
public void create () {
...
assets.load("model/ship/ship.g3db", Model.class);
...
}
private void doneLoading() {
Model ship = assets.get("model/ship/ship.g3db", Model.class);
...
}