Você está na página 1de 3

When rendering a 3D scene, the actual amount of visible objects is often a lot l

ess than the total amount of objects within the scene. Rendering all object, eve
n those that are not visible, can be a waste of precious GPU time and decrease t
he speed of the game. Ideally you'd want to render only those objects which are
actually visible to the camera and ignore all other objects which for example ar
e behind the camera. This is known as frustum culling and there are several ways
to accomplish this. This tutorial will show you the very basics in how to accom
plish frustum culling using the 3D api of LibGDX.
Before we start with the actual frustum culling, we'll need a scene to which app
ly this technique. Therefor I used the scene and code of the previous tutorial:
Loading a scene with libGDX. I assume you've followed that tutorial and will not
go into the details of that code.
It might be useful to have some feedback of how well our frustum culling impleme
ntation performs. Therefor let's add a label to indicate the number of object be
ing rendered and while we're at it, let's include the frames per second also. Fo
r reference here's the complete listing, we'll discuss the changes below:
public class FrustumCullingTest implements ApplicationListener {
protected PerspectiveCamera cam;
protected CameraInputController camController;
protected ModelBatch modelBatch;
protected AssetManager assets;
protected Array instances = new Array();
protected Environment environment;
protected boolean loading;
protected
protected
protected
protected

Array blocks = new Array();


Array invaders = new Array();
ModelInstance ship;
ModelInstance space;

protected
protected
protected
protected

Stage stage;
Label label;
BitmapFont font;
StringBuilder stringBuilder;

@Override
public 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.ge
tHeight());
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;
@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(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
}
@Override
public void dispose () {
modelBatch.dispose();
instances.clear();
assets.dispose();
}
@Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
@Override
public void pause() {
}
@Override
public void resume() {
}
}
View on github
Just a few changes here, let's discuss them. First I added a Stage, Label, Bitma
pFont and StringBuilder;
protected Stage stage;
protected Label label;
protected BitmapFont font;
protected StringBuilder stringBuilder;
Next, in the create method we initialize these members:
@Override
public void create () {
stage = new Stage();
font = new BitmapFont();
label = new Label(" ", new Label.LabelStyle(font, Color.WHITE));
stage.addActor(label);
stringBuilder = new StringBuilder();
...
}
Note that in the doneLoading method I used a convenience method to create ModelI
nstance. The third argument (mergeTransform) does exactly the same as we manuall
y did before, namely set the transformation of the ModelInstance and reset the t
ransformation of the Node.
If you're unfamiliar with using a Stage (scene2d), I'd suggest following a tutor
ial on that also, since it's a great way to implement your UI. Now l

Você também pode gostar