Culling objects

Is there any way how I can make a camera cull objects which are hidden behind others?



Let’s say I have two boxes - one is behind the other. From the current camera position, the box which is behind is not visible. However, it is till rendered as if it’s visible. Is there any way I can fix this?



The same happens with Faces.

I tried to use the following code, but even if it worked (not as I wanted, but I can improve it), the result is disastrous. In fact, it would be better if I culled nothing.



[java]for (int i = 0; i < geom.length; i++){

Vector3f dir = (new Vector3f(cam.getLocation().subtract

(geom.getLocalTranslation()))).normalizeLocal();

Ray ray = new Ray(geom.getLocalTranslation(), dir);

CollisionResults results = new CollisionResults();

rootNode.collideWith(ray, results);

CollisionResult closest = results.getClosestCollision();

System.out.println(i + ": " + results.size() + "; " + closest.getGeometry().getName());

if (results.size() > 3){

geom.setCullHint(CullHint.Always);

} else {

geom.setCullHint(CullHint.Never);

}

}[/java]

Well you’re right and you’re wrong…



You’re right because, the occluded geometry is still sent to the GPU (counted as a rendered object)

You’re wrong because the occluded pixels are not rendered unless you disabled depth testing (but I doubt you did).



To address the first issue there is a technique known as Occlusion Query or Occlusion Culling. It is not supported by the engine.

here are some GPU gem articles about it

http://http.developer.nvidia.com/GPUGems/gpugems_ch29.html

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter06.html



I don’t really know if it’s widely used

Doesn’t it still slow down FrameRate though if it’s still sent to the GPU?



I’m toying with GeometryBatchFactory, because it greatly increases performance.

I tried batching spatials, however, they are not being batched. This is what I’m doing:



[java]for (int i = 0; i < geom.length; i++){

geom = assetManager.loadModel(“Models/Ani/Ani.j3o”);

geom.setLocalTranslation(0, 0, -10±2*i);

x.attachChild(geom);

}



Node optimized = (Node) GeometryBatchFactory.optimize(x);

rootNode.attachChild(optimized);

flyCam.setMoveSpeed(10);[/java]



The same code works when I use Boxes instead of a Model.

This is a simplification but as I understand it: Essentially it takes longer to work out whether everything is behind everything else than it does to just tell the graphics card to draw them all and let the z buffer sort it out.

How do you know they’re not being batched? Are you getting an error message?

You’re not setting a material in the code, I assume the j3o file has a material set?

As far as I understand GeometryBatchFactory as well as BatchNode batches geometries if they have the same material (so they create one batch per material). The materials should be equal (as determined by the equals method).

Sorry for not replying before. I was trying to batch models. They have the same material. There is no error message, but when I look at all the models, the object count doesn’t increase by 1, but by 100 (the number of models).

Is it impossible to batch models?

@memonick said:
Is it impossible to batch models?

-.- Yes...you're right that may be the issue...noone ever achieved to batch models....

Of course it's possible, but under certain conditions, the major one being the geometries have to have the same material.
Post the complete code

They can’t be more ‘the same’ than this :stuck_out_tongue:



[java]

for (int i = 0; i < 100; i++){

walls = assetManager.loadModel(“Models/HighWall/HighWall.j3o”);

walls.setMaterial(assetManager.loadMaterial(“Materials/HighWall.j3m”));

walls.setLocalTranslation(10*i, 0, 0);

TangentBinormalGenerator.generate(walls);

y.attachChild(walls);

}

rootNode.attachChild(GeometryBatchFactory.optimize(y));

[/java]



It doesn’t crash or anything, but the object count stays at 114.

Post the complete code, there might be something wrong

Have you tried

[java]

Material mat = assetManager.loadMaterial(“Materials/HighWall.j3m”);

for (int i = 0; i < 100; i++){

walls = assetManager.loadModel(“Models/HighWall/HighWall.j3o”);

walls.setMaterial(mat);

walls.setLocalTranslation(10*i, 0, 0);

TangentBinormalGenerator.generate(walls);

y.attachChild(walls);

}

rootNode.attachChild(GeometryBatchFactory.optimize(y));

[/java]



I know it shouldn’t matter but it might be worth a try…

1 Like

That did the trick @zarch ! Thanks to you, FPS is up to 3000 from 1500 on my PC. Thanks a lot!

@memonick said:
That did the trick @zarch ! Thanks to you, FPS is up to 3000 from 1500 on my PC. Thanks a lot!

@memonick said:
They can't be more 'the same' than this :P


Always check your assumptions ;)

Glad I could help.

I thought assetmanager.loadmaterial() was supposed to return the same material if 1 already existed?

That’s what I thought too, it does seem a bit odd - that’s why I put “I know it shouldn’t matter but it might be worth a try…” at the end of my post.

@wezrule said:
I thought assetmanager.loadmaterial() was supposed to return the same material if 1 already existed?


It's a clone of the loaded material so that you can change its parameters without affecting the 90 other ones you loaded.

@memonick what version of JME do you use?

Your first code should work against last svn. We now have a material.equals() method that is used to merge geometries together, material don’t need to be the same instance anymore.

@nehon said:
@memonick what version of JME do you use?
Your first code should work against last svn. We now have a material.equals() method that is used to merge geometries together, material don't need to be the same instance anymore.


If you convince him to use nightly then you will help him with all of the issue he will encounter? :) Nightly is for very advanced users. I do not recommend it in this case.