libgdx3D第三讲-场景加载

来源:互联网 发布:网络设计培训 编辑:程序博客网 时间:2024/04/30 02:21
第三讲 场景加载

Loading a scene with LibGDX

网易云地址:http://note.youdao.com/share/?id=b79d9dbef936e1630bbd405dd1fbe590&type=note
说明:我是从网易云笔记直接粘过来的,可能图片显示不出来,附加资源下载不了,所以可以直接访问上面的地址来看。
  • 资源准备
四个模型,包括之前用到的飞船、入侵者、障碍、空间场景(有纹理和反向法线,因此内部可视)invaders.zip
  • 教程开始
1. 上一讲我们使用fbx-conv转换我们的模型,对新的模型也需要这样做,但现在我们先直接使用给出的OBJ文件。把他们拷贝到asset/data目录下,并像上次一样加载它们。下面给出今天的代码,并在下方讲解。
public class LoadSceneTest implements ApplicationListener {
    public PerspectiveCamera cam;
    public CameraInputController camController;
    public ModelBatch modelBatch;
    public AssetManager assets;
    public Array<ModelInstance> instances = new Array<ModelInstance>();
    public Environment environment;
    public boolean loading;
      
    public Array<ModelInstance> blocks = new Array<ModelInstance>();
    public Array<ModelInstance> invaders = new Array<ModelInstance>();
    public ModelInstance ship;
    public ModelInstance space;
      
    @Override
    public void create () {
        modelBatch = new ModelBatch();
        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
        environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
          
        cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        cam.position.set(0f, 7f, 10f);
        cam.lookAt(0,0,0);
        cam.near = 1f;
        cam.far = 300f;
        cam.update();
  
        camController = new CameraInputController(cam);
        Gdx.input.setInputProcessor(camController);
          
        assets = new AssetManager();
        assets.load("data/ship.obj", Model.class);
        assets.load("data/block.obj", Model.class);
        assets.load("data/invader.obj", Model.class);
        assets.load("data/spacesphere.obj", Model.class);
        loading = true;
    }
  
    private void doneLoading() {
        ship = new ModelInstance(assets.get("data/ship.obj", Model.class));
        ship.transform.setToRotation(Vector3.Y, 180).trn(0, 0, 6f);
        instances.add(ship);
  
        Model blockModel = assets.get("data/block.obj", Model.class);
        for (float x = -5f; x <= 5f; x += 2f) {
            ModelInstance block = new ModelInstance(blockModel);
            block.transform.setToTranslation(x, 0, 3f);
            instances.add(block);
            blocks.add(block);
        }
          
        Model invaderModel = assets.get("data/invader.obj", Model.class);
        for (float x = -5f; x <= 5f; x += 2f) {
            for (float z = -8f; z <= 0f; z += 2f) {
                ModelInstance invader = new ModelInstance(invaderModel);
                invader.transform.setToTranslation(x, 0, z);
                instances.add(invader);
                invaders.add(invader);
            }
        }
          
        space = new ModelInstance(assets.get("data/spacesphere.obj", Model.class));
          
        loading = false;
    }
      
    @Override
    public void render () {
        if (loading && assets.update())
            doneLoading();
        camController.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, environment);
        if (space != null)
            modelBatch.render(space);
        modelBatch.end();
    }
      
    @Override
    public void dispose () {
        modelBatch.dispose();
        instances.clear();
        assets.dispose();
    }
      
    @Override
    public void resume () {
    }
   
    @Override
    public void resize (int width, int height) {
    }
   
    @Override
    public void pause () {
    }
}
现在来看代码详解:
public Array<ModelInstance> blocks = new Array<ModelInstance>();
public Array<ModelInstance> invaders = new Array<ModelInstance>();
public ModelInstance ship;
public ModelInstance space;
这里我们增加Array存放障碍blocks和入侵者invaders,建立ModelInstance单例存飞船ship和场景space我们依然用它们来渲染,这样做的好处是我们可以很方便的控制每个部分。

public void create () {
    modelBatch = new ModelBatch();
    ...
    cam.position.set(0f, 7f, 10f);
    ...
    assets.load("data/ship.obj", Model.class);
    assets.load("data/block.obj", Model.class);
    assets.load("data/invader.obj", Model.class);
    assets.load("data/spacesphere.obj", Model.class);
    loading = true;
}
给camera设置一个更合适的位置;
assetmanager加载所有模型;
private void doneLoading() {
    ship = new ModelInstance(assets.get("data/ship.obj", Model.class));
    ship.transform.setToRotation(Vector3.Y, 180).trn(0, 0, 6f);
    instances.add(ship);
 
    Model blockModel = assets.get("data/block.obj", Model.class);
    for (float x = -5f; x <= 5f; x += 2f) {
        ModelInstance block = new ModelInstance(blockModel);
        block.transform.setToTranslation(x, 0, 3f);
        instances.add(block);
        blocks.add(block);
    }
      
    Model invaderModel = assets.get("data/invader.obj", Model.class);
    for (float x = -5f; x <= 5f; x += 2f) {
        for (float z = -8f; z <= 0f; z += 2f) {
            ModelInstance invader = new ModelInstance(invaderModel);
            invader.transform.setToTranslation(x, 0, z);
            instances.add(invader);
            invaders.add(invader);
        }
    }
      
    space = new ModelInstance(assets.get("data/spacesphere.obj", Model.class));
      
    loading = false;
}
从这里开始就有趣了,第一行我们取飞船模型并建立ModelInstance
第二行我们把它回转180度,现在它面向远离照相机方向,然后将它在Z轴朝向相机移动6个单位;
第三行我们把它加入array中,使它能被渲染;
之后我们对block 和 invader 模型做相同的事,但在这里我们建立多个实例;block将在x轴上排成一列,并将它们加入到两个array中; invader将被放置在在XZ平面的网格上;
最后建立space,但我们不会将它加入array中,因为它不需要渲染光照。

public void render () {
    ...
    modelBatch.begin(cam);
    modelBatch.render(instances, environment);
    if (space != null)
        modelBatch.render(space);
    modelBatch.end();
}
在render()方法中,我们像之前一样使用渲染,我们也对space使用无灯光渲染,注意这里要检查space是否加载好,因为它是异步加载的。

效果如图:

看起来不错,我们现在可以只实现一些游戏功能,然后到此结束。事实上,我敢打赌,有相当多的游戏是这样做的。但对更大的场景就不能使用了,现在我们来调整它。


2.打开你喜欢的模型应用程序(modeling application ),建立新场景。我使用Maya,这个例子任何模型应用程序都可以。现在把四个模型导入到场景中,如果你是新手建议一个一个导入来保证正确显示,例如手动制定纹理、翻转纹理坐标等。另外给每个模型起名字,且在之后不要改名,如图:

scenetest2


我启用了X射线,以方便编辑,这就是为什么这些模型看起来是透明的。后面的是场景。你也可以看到 “ship”、“block”、“invader” 模型都堆在一起,因为它们的位置都是(0,0,0)。如果所有模型都正确加载并起好名字,你可以将其导出成FBX格式,起名为invaders.fbx。模型应用程序中也可以保存一份以备修改。

3.使用fbx-conv把FBX文件转换为G3DB格式
fbx-conv invaders.fbx
如果你在创建FBX文件时有翻转纹理坐标,你现在也需要将它们翻转,那么代码如下
fbx-conv -f invaders.fbx
现在把invaders.g3db拷贝到assets/data文件夹下,我们继续编程
public class LoadSceneTest extends GdxTest implements ApplicationListener {
    ...
    @Override
    public void create () {
        ...
        assets = new AssetManager();
        assets.load("data/invaders.g3db", Model.class);
        loading = true;
    }
  
    private void doneLoading() {
        Model model = assets.get("data/invaders.g3db", Model.class);
        ship = new ModelInstance(model, "ship");
        ship.transform.setToRotation(Vector3.Y, 180).trn(0, 0, 6f);
        instances.add(ship);
  
        for (float x = -5f; x <= 5f; x += 2f) {
            ModelInstance block = new ModelInstance(model,"block");
            block.transform.setToTranslation(x, 0, 3f);
            instances.add(block);
            blocks.add(block);
        }
          
        for (float x = -5f; x <= 5f; x += 2f) {
            for (float z = -8f; z <= 0f; z += 2f) {
                ModelInstance invader = new ModelInstance(model, "invader");
                invader.transform.setToTranslation(x, 0, z);
                instances.add(invader);
                invaders.add(invader);
            }
        }
          
        space = new ModelInstance(model, "space");
          
        loading = false;
    }
...
}
在create()方法中我们删除了其他模型加载,换上了invaders.g3db
在doneLoading()方法中,我们从assetmanager获取该模型。并创建ModelInstances,参数为model和创建FBX时所使用的名称。以后我们会深入讲解,但现在让我们运行它,看看它的完全和以前一样。
这是很有用的,因为我们可以把所有模型放在一个场景中。而且ModelInstances只加载一个模型,因此可以共享资源,而且这使得ModelBatch(稍后详述)性能提升。当然,如果需要的话,你仍然可以使用多个文件,其实有时(如与皮肤或动画模型)使用一个单独的文件更方便。

4.让我们回到模型应用程序,并打开我们之前创建的场景,现在修改ship模型,绕Y轴旋转180度,并把沿Z轴移动6格,就像在java中做的一样;接着修改block模型,把它在Z轴移动3格,X轴移动-5格,然后重命名其为block1;修改invader模型,X轴移动-5格,重命名为invader1;复制block1五次,依次以X轴2格间距摆放,现在一共有6个block,重命名其为block1-block6;再按上步同一方法复制invader1,得到下图:

scenetest3

注意:网格间距5个单位。

5.仍然使用fbx-conv转换,然后加载场景
public void create () {
    ...
    assets = new AssetManager();
    assets.load("data/invaderscene.g3db", Model.class);
    loading = true;
}
 
private void doneLoading() {
    Model model = assets.get("data/invaderscene.g3db", Model.class);
    for (int i = 0; i < model.nodes.size; i++) {
        String id = model.nodes.get(i).id;
        ModelInstance instance = new ModelInstance(model, id);
        Node node = instance.getNode(id);
          
        instance.transform.set(node.globalTransform);
        node.translation.set(0,0,0);
        node.scale.set(1,1,1);
        node.rotation.idt();
        instance.calculateTransforms();
          
        if (id.equals("space")) {
            space = instance;
            continue;
        }
          
        instances.add(instance);
          
        if (id.equals("ship"))
            ship = instance;
        else if (id.startsWith("block"))
            blocks.add(instance);
        else if (id.startsWith("invader"))
            invaders.add(instance);
    }
 
    loading = false;
}
取得invaders模型,遍历节点得到每个节点的id,然后使用model和id建立ModelInstance;

设置ModelInstance的转换(一般是读取在模型应用程序中修改的旋转和平移等),然后我们重置节点的转换信息,因为现在我们可以直接读取ModelInstance中存放的信息。重置的方法如下: translation为(0,0,0);scale为(1,1,1);rotation shiyong idt();最后调用calculateTransforms()使ModelInstance被更新。(这段翻译可能不太对,原文如下)

Next we set the transformation of the ModelInstance to the transformation of the node. Practically this reads the transformation (like rotation and translation) we set earlier within the modeling application. Then we need to reset the node’s transformation, because we now use the ModelInstance transform. For translation this is (0,0,0), for scale this is (1,1,1) and for rotation we set the quaternion to identity. This is followed by a call to calculateTransforms() to make sure the ModelInstance is updated with these new values.


把不是space的ModelInstance都加入到array中,使其得到渲染,然后把ship、lobck、incader各加入其array中。

大功告成!


0 0
原创粉丝点击