Hi!
The method Camera.FrustumIntersect contains(BoundingVolume bound) of the interface Camera implemented in the abstract class AbstractCamera always returns Camera.FrustumIntersect.Inside even though the bounding volume is completely outside the view frustum. This bug has made me waste some weeks because I thought it was my fault and I watched in my own source code before checking if JME 2.0 was returning wrong results.
My test:
In my level, all portals are in the square ({0;0;0},{256;0;256}), go to {1;0;1} and look at the negative applicates (Z coordinates). Then, all portals are completely behind you and logically outside the view frustum. Perform the culled test on each portal by using the method I quoted at the beginning and unfortunately, it returns always Camera.FrustumIntersect.Inside.
After that, I checked in the debug mode of Eclipse that none of my bounding volume was null (when it is null, the Spatial instance is treated as inside), that each portal contained the good coordinates. I assumed that maybe the bug came from the fact that some portals had a zero extend for one coordinate (X or Z) but when I changed this, it didn't fix the bug.
Finally, I updated the source code of JME 2.0 by using SVN, I rebuilt all JARs, etc… It didn't solve my problem. Do you have any idea of what is wrong? Should I submit a bug report?
I will write a dummy test case with a Camera instance and a bounding box in order to help you to reproduce this bug and then I will submit a bug report. I'm very disappointed and I will waste a lot of time again.
Please post the test case. I think it might be something that you missed, unfortunately the contains() method in camera is intended to be used only for frustum culling of spatials inside the renderer so its entirely possible that it would lead to unexpected results when used in user code.
Momoko_Fan said:
Please post the test case. I think it might be something that you missed, unfortunately the contains() method in camera is intended to be used only for frustum culling of spatials inside the renderer so its entirely possible that it would lead to unexpected results when used in user code.
But a Portal instance is a kind of node that contains only a Spatial instance as a child and this child is used for the frustum culling. Ok I will write a test case as soon as possible. Thank you.
I have just written this test case but I don't even know if the syntax is correct, I'm going to run it at home in 5 hours, I'm currently at work
package jme;
import java.awt.Component;
import java.awt.Frame;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import com.jme.input.InputHandler;
import com.jme.input.InputSystem;
import com.jme.input.KeyInput;
import com.jme.input.KeyInputListener;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.input.controls.GameControl;
import com.jme.input.controls.GameControlManager;
import com.jme.input.controls.binding.KeyboardBinding;
import com.jme.input.controls.controller.ActionChangeController;
import com.jme.input.controls.controller.ControlChangeListener;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.system.PreferencesGameSettings;
import com.jme.system.jogl.JOGLSystemProvider;
import com.jmex.game.StandardGame;
import com.jmex.game.StandardGame.GameType;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameStateManager;
public class Testcase{
private Testcase(){
PreferencesGameSettings pgs=new PreferencesGameSettings(Preferences.userRoot());
pgs.setRenderer(JOGLSystemProvider.SYSTEM_IDENTIFIER);
pgs.setMusic(false);
pgs.setSFX(false);
pgs.setWidth(800);
pgs.setHeight(600);
pgs.setFullscreen(false);
StandardGame game=new StandardGame("testcase",GameType.GRAPHICAL,pgs);
game.start();
final Camera cam=game.getCamera();
cam.setFrustumPerspective(45.0f,800/(float)600,0.2f,2000.0f);
Vector3f loc = new Vector3f(0.0f,0.0f,25.0f);
Vector3f left = new Vector3f(-1.0f,0.0f,0.0f);
Vector3f up = new Vector3f(0.0f,1.0f,0.0f);
Vector3f dir = new Vector3f(0.0f,0.0f,-1.0f);
cam.setFrame(loc,left,up,dir);
cam.setLocation(new Vector3f(0.0f,0.0f,0.0f));
cam.update();
final BoundingBox boundingBox=new BoundingBox(new Vector3f(128.0f,0.0f,128.0f),0.5f,0.5f,0.5f);
BasicGameState state=new BasicGameState("testcase"){
@override
public final void render(final float tpf) {
super.render(tpf);
System.out.println(cam.contains(boundingBox));
}
};
GameStateManager.getInstance().attachChild(state);
GameStateManager.getInstance().activateAllChildren();
}
public static final void main(String[] args){
new Testcase();
}
}
I launched this test:
package jme;
import com.jme.bounding.BoundingBox;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.jogl.JOGLCamera;
public class Testcase {
private Testcase(){
final Camera cam=new JOGLCamera(800,600);
cam.setFrustumPerspective(45.0f,800/(float)600,0.2f,2000.0f);
Vector3f loc = new Vector3f(0.0f,0.0f,25.0f);
Vector3f left = new Vector3f(-1.0f,0.0f,0.0f);
Vector3f up = new Vector3f(0.0f,1.0f,0.0f);
Vector3f dir = new Vector3f(0.0f,0.0f,-1.0f);
cam.setFrame(loc,left,up,dir);
cam.setLocation(new Vector3f(0.0f,0.0f,0.0f));
cam.update();
final BoundingBox boundingBox=new BoundingBox(new Vector3f(128.0f,0.0f,128.0f),0.5f,0.5f,0.5f);
System.out.println(cam.contains(boundingBox));
}
public static final void main(String[] args){
new Testcase();
}
}
It gave the expected result, it works reliably.
Therefore, I try to understand why my source code does not work.
I launched this test:
package jme;
import com.jme.bounding.BoundingBox;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.jogl.JOGLCamera;
public class Testcase {
private Testcase(){
final Camera cam=new JOGLCamera(800,600);
cam.setFrustumPerspective(45.0f,800/(float)600,0.2f,2000.0f);
Vector3f loc = new Vector3f(0.0f,0.0f,25.0f);
Vector3f left = new Vector3f(-1.0f,0.0f,0.0f);
Vector3f up = new Vector3f(0.0f,1.0f,0.0f);
Vector3f dir = new Vector3f(0.0f,0.0f,-1.0f);
cam.setFrame(loc,left,up,dir);
cam.setLocation(new Vector3f(115.0f,0.0f,223.0f));
cam.update();
final BoundingBox boundingBox=new BoundingBox(new Vector3f(109.0f,0.0f,240.5f),0.0f,0.5f,14.5f);
System.out.println(cam.contains(boundingBox));
}
public static final void main(String[] args){
new Testcase();
}
}
It returns "Outside" which is the good result. However, when the same data are treated inside my game, it returns "Inside" :(
Momoko_Fan said:
Please post the test case. I think it might be something that you missed, unfortunately the contains() method in camera is intended to be used only for frustum culling of spatials inside the renderer so its entirely possible that it would lead to unexpected results when used in user code.
It is time to let me know what you meant as you seem to be right. Please do you have any idea of what would cause this difference?
Hi!
Momoko_Fan said:
Please post the test case. I think it might be something that you missed, unfortunately the contains() method in camera is intended to be used only for frustum culling of spatials inside the renderer so its entirely possible that it would lead to unexpected results when used in user code.
You were right. After some time of debugging, I added the line below and it worked:
((AbstractCamera)currentCamera).setPlaneState(0);
:D
Yeah, that's what I thought was the problem. The Camera.contains() method apparently skips some checks if the bound was already checked against one of it's planes… Glad you got it working
Momoko_Fan said:
Yeah, that's what I thought was the problem. The Camera.contains() method apparently skips some checks if the bound was already checked against one of it's planes.. Glad you got it working :)
Should I do something like this?
save the plane state
set the plane state to 0
do my own stuff
set the plane state to its previous value