Limit of moving object3D

Started by Mr_Chaos, February 13, 2015, 12:43:05 PM

Previous topic - Next topic

Mr_Chaos

I was wondering if there is a limit to how many Object3D you can have, I'm looking into a requirement that might mean we have to have 50000 objects on screen at the same time, running at 30fps.

EgonOlsen

That either means to execute 50000 draw calls each frame (for compiled objects) or processing ~500000 polygons each frame on the CPU in hybrid mode. The former one is GPU, driver and bus intense the latter is cpu intense. I made this test case, which renders 50000+ cubes at a time:

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

import org.lwjgl.opengl.Display;

import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IPaintListener;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;
import com.threed.jpct.WorldProcessor;
import com.threed.jpct.util.Light;

public class CubeRow implements IPaintListener {

private static final long serialVersionUID = 1L;

private FrameBuffer buffer;

private World world;

private Object3D center;

private List<Object3D> objs = new ArrayList<Object3D>();

private int fps = 0;

public static void main(String[] args) {
new CubeRow().loop();
}

public CubeRow() {
Logger.setLogLevel(Logger.LL_DEBUG);
Logger.setOnError(Logger.ON_ERROR_THROW_EXCEPTION);

Config.maxPolysVisible = 500000;
Config.lightMul = 1;

world = new World();
world.setAmbientLight(20, 20, 20);

Object3D obj = null;
Object3D mcube = Primitives.getCube(10);

mcube.build();

center = Object3D.createDummyObj();

for (int z = 0; z < 25; z++) {
for (int x = 0; x < 45; x++) {
for (int i = 0; i < 45; i++) {
obj = new Object3D(mcube, true);
obj.translate((x - 22) * 50, (i - 22) * 50, z * 50);
obj.shareCompiledData(mcube);
//obj.compile(); // Uncomment for compiled mode
obj.build();
obj.addParent(center);
world.addObject(obj);
objs.add(obj);
}
}
}

Config.farPlane = 10000;
world.getCamera().setPosition(50, 0, -4000);
world.setWorldProcessor(new WorldProcessor(8, 16));

Light l1 = new Light(world);
l1.setPosition(new SimpleVector(0, -10, -40));
l1.setIntensity(255, 0, 0);
l1.setAttenuation(-1);
}

private void loop() {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_NORMAL);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

buffer.setPaintListener(this);
long s = System.currentTimeMillis();

while (!buffer.isInitialized()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

while (!Display.isCloseRequested()) {
buffer.clear(Color.BLUE);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.display(null);
center.rotateX(0.1f);
center.rotateY(0.1f);
if (System.currentTimeMillis() - s >= 1000) {
s = System.currentTimeMillis();
System.out.println(fps + "fps/" + world.getVisibilityList().getSize() + " objects visible");
fps = 0;
}
}
buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
buffer.dispose();
System.exit(0);
}

@Override
public void startPainting() {
// TODO Auto-generated method stub

}

@Override
public void finishedPainting() {
fps++;
}
}


On a Core i7@4GHz with a GTX 680, it manages ~ 5fps in hybrid and ~4 fps in compiled mode when using a custom WorldProcessor instance with 8 threads and 16 work units. Hybrid mode is actually faster here, because it batches more draw calls into one at the expense of a higher cpu load. In hybrid mode, you can add Config.useMultipleThreads=true; at the beginning in addition, which brings to up to 6fps...
However, nothing comes close to 30 fps here...and this is the best case, i.e. simple objects that all share the same mesh. I don't see how this is going to work out. It's also not limited by either jPCT or Java but simply by the fact that 50000 draw calls take their time in OpenGL.

Mr_Chaos

:/

Could you make one large Object3D and move it's vertices manually that should make 1 drawcall, right ?

EgonOlsen

Yes, you could and it will be faster...i'll try to modify the test case to see how much...

EgonOlsen

...well, actually it's not that much faster. The object itself can render @ xxx fps without a problem, but as soon as you start to modify it's vertices each frame, it breaks down to ~6fps. That's because each frame requires the upload of ~500000 vertices to the GPU and that's expensive. For simple cases, one could do the vertex updates in a custom vertex shader instead, but that's most likely not feasible in your case...which actually is...??? Maybe it helps to know what exactly you have in mind that needs this insane amount of objects.

Mr_Chaos

I have to show 25000 carts each consisting of the cart (1 object3D) and 1 item in the cars (another Object3D).

But i'm thinking if maybee I can change the view distance, so not all of the objects are visible at a time.

EgonOlsen

I see. On my setup, i have to go down to approx. 7000 draw calls/objects to get the 30fps. The items are all individual? They can't be merged with the cart somehow?

Mr_Chaos

I could half it, by having some Object3d which will be empty carts and some Object3Ds with bags, that way I only have 25000 objects.

Could draw distance help here, so some of the objects won't be drawn each frame ?

EgonOlsen


Mr_Chaos

Then I think that's the solution