Below is the single source file to the basic demonstration in Java of how to build a 3D mesh out of multiple objects and render it in a single call.
Optimising render calls like this reduces overhead and speeds things up a hell of a lot. Which is essential when you need every CPU clock cycle to process a shed load more information.
You can find the actual demo in action in HTML5 HERE (Demo3D2)…
This is using libGdx and it runs on desktop, android and in a web browser.
And it’s as simple as it gets.
package com.wlgfx.demo3d2;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.environment.PointLight;
import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
public class Demo3d2 extends ApplicationAdapter {
ModelBatch modelBatch;
SpriteBatch batch;
Texture img;
PerspectiveCamera cam;
Environment environment;
Model model;
Texture texture;
ModelInstance gridInstance;
Material mat;
PointLight light;
float camx = 0, camy = 0, camz = 0;
float camxs = 10, camys = 15, camzs = 20;
float camxr = 65, camyr = 75, camzr = 55;
@Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
modelBatch = new ModelBatch();
texture = new Texture("metal.jpg");
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));
light = new PointLight().set(1, 1, 1, 0, 0, 0, 50);
environment.add(light);
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(10f, 10f, 10f);
cam.lookAt(0,0,0);
cam.near = 0f;
cam.far = 1000f;
cam.update();
mat = new Material();
mat.set(TextureAttribute.createDiffuse(texture));
mat.set(TextureAttribute.createBump(texture));
mat.set(ColorAttribute.createSpecular(1, 1, 1, 1));
mat.set(FloatAttribute.createShininess(8f));
model = buildGrid();
gridInstance = new ModelInstance(model);
Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl20.glDepthFunc(GL20.GL_GREATER);
Gdx.gl20.glDepthMask(true);
Gdx.gl20.glDepthRangef(0.0f, 100.0f);
Gdx.gl20.glClearDepthf(1.0f);
}
private Model buildGrid() {
mat = new Material();
mat.set(TextureAttribute.createDiffuse(texture));
mat.set(TextureAttribute.createBump(texture));
mat.set(ColorAttribute.createSpecular(1, 1, 1, 1));
mat.set(FloatAttribute.createShininess(8f));
ModelBuilder builder = new ModelBuilder();
builder.begin();
MeshPartBuilder partBuilder = builder.part("meshX", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal | Usage.TextureCoordinates | Usage.BiNormal, mat);
int step = 20;
for (int a = -100; a <= 100; a += step) {
for (int b = -100; b <= 100; b += step) {
for (int c = -100; c <= 100; c += step * 4) {
partBuilder.box(a, b, c, 1, 1, step * 4);
partBuilder.box(a, c, b, 1, step * 4, 1);
partBuilder.box(c, a, b, step * 4, 1, 1);
}
}
}
model = builder.end();
return model;
}
private void updateCamera(float delta) {
camx = (camx + camxs * delta) % 360.0f;
camy = (camy + camys * delta) % 360.0f;
camz = (camz + camzs * delta) % 360.0f;
cam.position.x = (float)Math.sin(Math.toRadians(camx)) * camxr;
cam.position.y = (float)Math.cos(Math.toRadians(camy)) * camyr;
cam.position.z = (float)Math.sin(Math.toRadians(camz)) * camzr;
cam.lookAt(0, 0, 0);
light.setPosition(cam.position.x, cam.position.y, cam.position.z);
cam.update();
}
@Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
batch.begin();
batch.draw(img, 0, 0);
batch.end();
float delta = Gdx.graphics.getDeltaTime();
updateCamera(delta);
modelBatch.begin(cam);
modelBatch.render(gridInstance, environment);
modelBatch.end();
}
}
