Libgdx中的3D frustum culling

This blog is a chinese version of xoppa’s Libgdx new 3D api tutorial. For English version, please refer to >>LINK<<

我要偷懒了,好久没看LibGDX,也很久没看3D,新教程的题目我就不懂了。不过看了课程的内容,相信你们都会理解。

正文:

当渲染一个3d场景时,其中真正可见的对象通常都比总对象数少很多。因此渲染全部的物体,包括那些根本看不到的,即浪费了富贵的GPU时间,还会影响游戏的画面速度。理想情况下,你可以可希望渲染对当前相机可见的对象,而忽略掉那些不可见的,比较在相机后面的。这就是题目中所说的frustum culling,并且,几种方法都可以实现。这篇教程,将会展示在LibGDX 3D API中,最基本的实现方法。

在我们真正开始之前,我们需要准备一个场景。所以我使用了Libgdx New 3D API 教程之 — 使用Libgdx加载3D场景中的场景和代码。我当你都看过以前的教程啦,所以代码的细节就不详说了。

我希望在在frustum culling时,能有一些反馈,来说明frustum culling的表现。所以让我们添加一个label,显示,有渲染对象的个数,再加上FPS。看看下面参考的代码先:

protected PerspectiveCamera cam;protected CameraInputController camController;protected ModelBatch modelBatch;protected AssetManager assets;protected Array instances = new Array();protected Environment environment;protected boolean loading;protected Array blocks = new Array();protected Array invaders = new Array();protected ModelInstance ship;protected ModelInstance space;protected Stage stage;protected Label label;protected BitmapFont font;protected StringBuilder stringBuilder;@Overridepublic void create () {stage = new Stage();font = new BitmapFont();label = new Label(" ", new Label.LabelStyle(font, Color.WHITE));stage.addActor(label);stringBuilder = new StringBuilder();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+"/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, true);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;}private int visibleCount;@Overridepublic void render () {if (loading && assets.update())doneLoading();camController.update();Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);modelBatch.begin(cam);visibleCount = 0;for (final ModelInstance instance : instances) {if (isVisible(cam, instance)) {modelBatch.render(instance, environment);visibleCount++;}}if (space != null)modelBatch.render(space);modelBatch.end();stringBuilder.setLength(0);stringBuilder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond());stringBuilder.append(" Visible: ").append(visibleCount);label.setText(stringBuilder);stage.draw();}protected boolean isVisible(final Camera cam, final ModelInstance instance) {return true; // FIXME: Implement frustum culling}@Overridepublic void dispose () {modelBatch.dispose();instances.clear();assets.dispose();}@Overridepublic void resize(int width, int height) {stage.getViewport().update(width, height, true);}@Overridepublic void pause() {}@Overridepublic void resume() {}}只有几处改动,看一下,首先有一个Stage, 然后有Label, BitmapFont 和 StringBuilderprotected Stage stage;protected Label label;protected BitmapFont font;protected StringBuilder stringBuilder;

然后在create方法中,对这些进行初始化:

@Overridepublic void create () {stage = new Stage();font = new BitmapFont();label = new Label(" ", new Label.LabelStyle(font, Color.WHITE));stage.addActor(label);stringBuilder = new StringBuilder();…}

注意在doneLoading方法中,我用了一个简便方法去创建ModelInstance。第三个参数(mergeTransform)等价于我们以前手动所做的内容,即:设置ModelInstance的位移,并重置Node的位移。(翻译的好啰嗦,还能再啰嗦点吗?)

如果你对Stage的概念不熟,建议你去看一看,因为它是实现UI界面很好的方式。现在我们来看看在render方法里,是如何去画界面的。

private int visibleCount;@Overridepublic void render () {…modelBatch.begin(cam);visibleCount = 0;for (final ModelInstance instance : instances) {if (isVisible(cam, instance)) {modelBatch.render(instance, environment);visibleCount++;}}if (space != null)modelBatch.render(space);modelBatch.end();stringBuilder.setLength(0);stringBuilder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond());stringBuilder.append(" Visible: ").append(visibleCount);label.setText(stringBuilder);stage.draw();}

我们不再一次性画出所有的对象,而是先去看看它是否可见,才去渲染。我们还会修改visibleCount去检测实际渲染对象的数量。这里space model instance不去判断,因为一直可见。

不能接受失败,也意味太想去成功了,从心理学上解释,

Libgdx中的3D frustum culling

相关文章:

你感兴趣的文章:

标签云: