Multhreading physics

is there anyway of creating threads for the physics simulation cause my game tends to slow down when a collision occurs ,iv set the bullet threading type to parallel but it hasnt help. is there a way you can assign more threads to the application as a whole or the bulletappstate ,just as you can use seperate threads when reading values from the scene graph by submitting a callable to a thread executor?

I think this is one of those cases where you’ve pre-asked yourself a question and pre-answered it with potentially bad information and now you are asking a follow on question that may not make sense.

If moving physics to parallel didn’t have any effect then moving it to “more parallel” probably won’t have any effect either… even if such a thing were possible.

So, the question you pre-asked and pre-answered was “how can I make physics more performant?” And that’s probably the question we really should be answering here.

Unfortunately, we don’t have enough information to answer that one. We don’t know if your machine is single core, multicore, multifakecore, etc… or what you tried and if it actually properly enabled parallel physics. I mean, if it had no effect at all then either it wasn’t enabled/setup properly or your machine only has one core anyway and it will make little difference… and/or you are running without vsync… or any number of other things I’d have to randomly guess.

@pspeed ,i was saying everything i have tried and yes ,the question is how to make physics more performant. i am using a singlecore 3.2 ghz processor with 1.5 gb ram and 128mb graphic card. Concerning the vsync issue, i have enabled it cause i saw a slight improvement after enabling it .the actual thing is in my car racing game,if i use full screen with a high resolution ,everything slows down and my car takes more than a minute to complete a lap. with low screen resolution ,there is improvement and my car takes about 46s to complete a lap. now im not sure if it is the renderer or the physics space which has a problem. i have played games that use up to 500mb ram without freezing on this pc but my application only uses about 120mb ,what could be my problem?

So, a single core machine will make no big difference with multiple parallel threads. They won’t have a place to run.

Still, the fact that your velocity seems to change with computer performance is a bad sign that something is broken somewhere. Something not being scaled properly (or being scaled improperly) with frame rate.

iv heard in one of the tutorials that the renderer can render faster than the number of ticks per second in the physicspace ,well im not so sure about the actual words but it has to do with the renderer and physics rates being different .Also ,when i used appsettings and set framerate to 60 ,i saw some consistency at different screen resolutions ,now im no longer sure what i have done here cause i was just experimenting .Could you please give me an insight to what exactly i can scale ,or what i have done.

I’m afraid I don’t know anything about bullet physics or how you are setting things on it.

Thanks for your ideas.

Bullet probably already runs in a separate thread (just guessing since we have no code to look at). If things run slower when the renderer can’t keep up it is most probably something really broken in your code (which we don’t see).
Have you changed to native bullet or is this the default settings? How do you start the physics space? How do you add things to it? Are you using collision listeners? Do you set physics-location on things in the render thread or using bullet the proper way with PhysicsTickListener? Do you have kinematic objects? Do you remove objects from physics space or just from the scene?
This is what pspeed is getting at, we can’t help, too many unknowns.
The best way forward is if you can make a very small test case yourself, the simplest you possibly can make that demonstrate how you set up and control things. Then see if you still have the same problem. I don’t know how many times I have done that and found the bug in my code :slight_smile:

@jmaasing ,well ,i wish i could post some code from one of my five classes but i am currently using my mobile device until i buy a new modem or find my usb cable ,we have closed at campus and i cant get wifi either.I initialise my bullet app state the usual way in the main class and attach it to the statemanager. i access it in a gameappstate via this.app.getStateManager().getState(BulletAppState.class). in the cleanup method ,i had bulletAppState.getPhysicsSpace().remove(object). i currently dont implement physicsticklistener ,the renderthread is empty ,i execute everything in the update-method,maybe it could be the way i initialise bullet?

I believe that using the physicsticklistener will enable the same observed velocity independent of the render frame rate. 8)

[java]
//Here is my main class
public class Main extends SimpleApplication
implements ActionListener{
GameInputs input;
BitmapText locText ,timeText;
BulletAppState bulletAppState;
GameState gameState;
int gameLevel=1;
boolean gameWon=false;

StartScreenState screenState;
Trigger pause_key=new KeyTrigger(KeyInput.KEY_P) ;
boolean isRunning=false;
BitmapText displaytext ;
public static void main(String[] args) {

    AppSettings settings=new AppSettings(true);
    settings.setFrameRate(60);
 settings.setFullscreen(true);
  settings.setResolution(640,480);
    settings.setVSync(true);
    settings.setTitle("GAMER RALLY 3D");
    Main app = new Main();
    app.setSettings(settings);
   app.setShowSettings(false);
    app.start();
}

@Override
public void simpleInitApp() {

setDisplayFps(false);
setDisplayStatView(false);

 bulletAppState=new BulletAppState();
 bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
 stateManager.attach(bulletAppState);

input=new GameInputs();

gameState=new GameState();
screenState=new StartScreenState();
inputManager.addMapping(“pause”, pause_key);
inputManager.addListener(this, “pause”);

stateManager.attach(screenState);

int height=cam.getHeight();

int width =cam.getWidth();
locText =new BitmapText(guiFont,false);
locText.setSize(32);
locText.setColor(ColorRGBA.Orange);
locText.setLocalTranslation(new Vector3f(.1fwidth,.5fheight,0));
guiNode.attachChild(locText);

setUpLight();

}

public void  setUpLight(){
 




AmbientLight ai=new AmbientLight();

ai.setName(“ai”);
rootNode.addLight(ai);

}

@Override
public void simpleUpdate(float tpf) {

}

@Override
public void simpleRender(RenderManager rm) {

}

public void onAction(String name, boolean isPressed, float tpf) {

  if (name.equals("pause") && !isPressed) {
 
        if(!stateManager.hasState(gameState)){
                 if(gameState.gameFinished()){
                if(gameState.getLevel()!=3){
                        stateManager.detach(screenState);
            gameState.setLevel(gameState.getLevel(), true);
             stateManager.attach(gameState);
                }

       }
                 else{
           stateManager.detach(screenState);
        if  (gameState.getLevel()==0){
              gameState.setLevel(1, false);
    stateManager.attach(gameState); 
        }
    gameState.setLevel(gameState.getLevel(), false);
    stateManager.attach(gameState);           
                 }        
    } else {
          
            
      stateManager.detach(gameState);
    stateManager.attach(screenState);
    
    }
   
  } 

isRunning = !isRunning;
}

}

//and here is my GameState app state

public class GameState extends AbstractAppState {

private AssetManager assetManager;
private Node rootNode;
private Node guiNode;
DirectionalLight light;
private InputManager inputManager;
private Camera cam;
private AppStateManager stateManager;
BulletAppState physics;
Spatial carNode;
Vector3f loc = null;
VehicleControl car_con;
BitmapFont guiFont;
ChaseCamera chase;
GameState player;
Node localRootNode=new Node(“GameNode”);
Node localGuiNode=new Node(“GameGui”);
BitmapText speedText ,timeText,locText,countText,lapText;
float speed=0,lap1time=0f,lap2time=0f;
Spatial racingTrack;
Geometry checkPt ,checkPt1;
Box pt,pt1;
boolean setLap=false;
HashSet<Geometry> hs =new HashSet<Geometry>();
HashSet<Geometry> laps =new HashSet<Geometry>();
Timer timer;
BoundingVolume c1,c2;
float startTime,stopTime,time;
boolean timeRun=false;
SimpleApplication app;
GameInputs input;
Trigger select=new KeyTrigger(KeyInput.KEY_SPACE);

boolean lapFinished=false;
Factory factory;
boolean gameFinished=false;
Vector3f velocity;
float bestTime;
int gameLevel;
Future speed_future =null;
ScheduledThreadPoolExecutor executor ;
Main main;
public GameState(){

}

@Override
public void initialize(AppStateManager stateManager,Application app) {
    super.initialize(stateManager, app);
    this.app=(SimpleApplication)app;
   this.stateManager=stateManager;
       this.rootNode=this.app.getRootNode();

this.assetManager=this.app.getAssetManager();
this.guiNode=this.app.getGuiNode();
this.inputManager=this.app.getInputManager();
this.cam=this.app.getCamera();
this.timer=this.app.getTimer();
factory=new Factory();
executor = new ScheduledThreadPoolExecutor(4);
rootNode.attachChild(localRootNode);
guiNode.attachChild(localGuiNode);

localRootNode.attachChild(SkyFactory.createSky(assetManager, “Textures/Sky/Bright/BrightSky.dds”, false));

    physics=stateManager.getState(BulletAppState.class);
    physics.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
    physics.setSpeed(60);
    stateManager.attach(physics);

setUpTrack();
setUpCar(“AudiR8”);
setUpText();
checkPoints();
inputManager.addMapping(“next”, select);
main=new Main();
input=new GameInputs();
light=new DirectionalLight();

rootNode.addLight(light);
}

public void setLevel(int level,boolean finished){
if(finished){

      gameLevel=level+1; 

  }
  else{
      gameLevel=level;
  }
          
  gameFinished=false;

}
public int getLevel(){

  return gameLevel;

}
public void setUpText(){
int height=cam.getHeight();
int width =cam.getWidth();
guiFont =assetManager.loadFont(“Interface/Fonts/VirtualDJ.fnt”);

  locText =new BitmapText(guiFont,false);
   locText.setSize(28);
  locText.setColor(ColorRGBA.Cyan);
  locText.setLocalTranslation(new Vector3f(.7f*width,.95f*height,0));

locText.setText(“Lap 1/2”);
localGuiNode.attachChild(locText);

   speedText =new BitmapText(guiFont,false);
   speedText.setSize(28);
  speedText.setColor(ColorRGBA.Cyan);
  speedText.setLocalTranslation(new Vector3f(.7f*width,.1f*height,0));

localGuiNode.attachChild(speedText);

timeText =new BitmapText(guiFont,false);
timeText.setSize(24);
timeText.setColor(ColorRGBA.Cyan);
timeText.setLocalTranslation(new Vector3f(.05fwidth,.95fheight,0));
localGuiNode.attachChild(timeText);

 lapText =new BitmapText(guiFont,false);
   lapText.setSize(24);
  lapText.setColor(ColorRGBA.Yellow);
  lapText.setLocalTranslation(new Vector3f(.05f*width,.90f*height,0));
  localGuiNode.attachChild(lapText);     
  
   countText =new BitmapText(guiFont,false);
  countText.setSize(32);
  countText.setColor(ColorRGBA.Orange);
  countText.setLocalTranslation(new Vector3f(.1f*width,.5f*height,0));
  localGuiNode.attachChild(countText);    
  

}

public void checkPoints(){
pt1 =new Box(new Vector3f(factory.getStartPoint(gameLevel)),46,10,5);
checkPt=new Geometry(“pt1”,pt1);
Material mat=new Material(assetManager,“Common/MatDefs/Misc/Unshaded.j3md”);
mat.setColor(“Color”, ColorRGBA.LightGray);
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.FrontAndBack);
checkPt.setMaterial(mat);
localRootNode.attachChild(checkPt);

pt =new Box(factory.getCheckPoint(gameLevel),46,10,5);
checkPt1=new Geometry(“pt”,pt);
checkPt1.setMaterial(mat);
localRootNode.attachChild(checkPt1);

c1=checkPt1.getModelBound();
c2=checkPt.getModelBound();

}

@Override
public void update(float tpf) {

Vector3f camDir=null;
try {
camDir = executor.submit(new Callable<Vector3f>(){

        public Vector3f call() throws Exception {
            return cam.getDirection();
        }

}).get();
} catch (InterruptedException ex) {
Logger.getLogger(GameState.class.getName()).log(Level.SEVERE, null, ex);
} catch (ExecutionException ex) {
Logger.getLogger(GameState.class.getName()).log(Level.SEVERE, null, ex);
}

light.setDirection(camDir);
processLaps();

float times=timer.getTimeInSeconds();
if(times>4&&times<=7){
countText.setText(“3”);
}
if(times>7&&times<=9){
countText.setText(“2”);
}
if(times>9&&times<=11){
countText.setText(“1”);
}
if(times>11&&times<=13){
countText.setText(“GO!!”);
stateManager.attach(input);
}
if(times>13&&times<20){
countText.setText("");
}
try{
speed=executor.submit(new Callable<Float>(){

        public Float call() throws Exception {
        return        car_con.getCurrentVehicleSpeedKmHour();
        }
     
  }).get();

}
catch(Exception ex){

} 

String outSpeed= String.valueOf(speed);
speedText.setText(“Speed\n”+outSpeed.substring(0, outSpeed.indexOf(".")+2) +“km/h”);
processTime();
}

public void setUpCar(String car) {

    carNode=factory.getCar(car,assetManager);

   car_con=carNode.getControl(VehicleControl.class);

car_con.setPhysicsLocation(factory.getStartPoint(gameLevel));
carNode.addControl(new CarControl());

  physics.getPhysicsSpace().add(car_con);

localRootNode.attachChild(carNode);

chase =new ChaseCamera(cam,carNode,inputManager) ;
chase.setDefaultDistance(15);
chase.setDefaultHorizontalRotation(FastMath.HALF_PI);
chase.setSmoothMotion(true);
chase.setLookAtOffset(new Vector3f(0,2,0));
chase.setDefaultVerticalRotation(FastMath.INV_PI);

}    

public void setLap1Time(Float time1){
if(!lapFinished) {
this.lap1time=time1;

 }
 lapFinished=true;

}
public void setLap2Time(Float time2){
if(!setLap) {
this.lap2time=time2;

 }

setLap=true;
}
public float getLap1Time(){
return lap1time;
}

public float getLap2Time(){
return lap2time;
}

public boolean gameFinished(){
return this.gameFinished;
}

public void setUpTrack() {
racingTrack=factory.getTrack(gameLevel,assetManager);

      RigidBodyControl track_con=new RigidBodyControl(0.0f);
         racingTrack.addControl(track_con);
         physics.getPhysicsSpace().add(track_con);
    localRootNode.attachChild(racingTrack);
}

public void processTime(){

try{
startTime=executor.submit(new Callable&lt;Float&gt;(){

    public Float call() throws Exception {

return timer.getTimeInSeconds()-13f;
}
}).get();
}
catch(Exception x){

}

if(startTime<60f&&startTime>0){
String act=String.valueOf(startTime);
timeText.setText(“Time “+“00:” +(act.substring(0,act.indexOf(”.”)+2)));
}
if((startTime>60f)&&startTime<120f){
String act=String.valueOf( startTime-60) ;
timeText.setText(“Time “+“01:” +(act.substring(0,act.indexOf(”.”)+2)));
}
if((startTime>120f)&&startTime<180f){
String act= String.valueOf(startTime-120) ;
timeText.setText(“Time “+“02:” +(act.substring(0,act.indexOf(”.”)+2)));
}
if((startTime>180f)&&startTime<240f){
String act=String.valueOf(startTime-180);
timeText.setText(“Time “+“03:” +(act.substring(0,act.indexOf(”.”)+2)));
}
if((startTime>240f)&&startTime<300f){
String act=String.valueOf(startTime-240);
timeText.setText(“Time “+“03:” +(act.substring(0,act.indexOf(”.”)+2)));
}
}
private void processLaps() {

    try{    
 loc=executor.submit(new Callable&lt;Vector3f&gt;(){

        public Vector3f call() throws Exception {
        return        car_con.getPhysicsLocation();
        }
     
  }).get();
}      
catch(Exception ex){
    
}     

float lap1=0,lap2=0;

    if((c1.contains(loc))&amp;&amp;hs.isEmpty()) {
        hs.add(checkPt1);
       
    }
    if((c2.contains(loc))&amp;&amp;hs.contains(checkPt1)) {
      laps.add(checkPt1);

locText.setText(“Lap 2/2”);
setLap1Time(startTime);

String act1 =String.valueOf(getLap1Time());
lapText.setText(“Lap1 Time :”+act1.substring(0,act1.indexOf(".")+2));
}
if((c1.contains(loc))&&laps.contains(checkPt1)) {
hs.add(checkPt);

    }   
   if((c2.contains(loc))&amp;&amp;hs.contains(checkPt)) {
   
 setLap2Time(startTime-lap1time);
       
 String act2=String.valueOf(lap2time);

String act1 =String.valueOf(lap1time);

if(gameLevel==3){
countText.setText(“FINISHED”);
}else {
countText.setText(“Press P To\n go to next track”);
}

lapText.setText(“Lap2 Time :”+act2.substring(0,act2.indexOf(".")+2)
+"\nLap1 Time :"+act1.substring(0,act1.indexOf(".")+2)) ;

    gameFinished=true;
    stateManager.detach(input);
   }

}

@Override

public void cleanup() {
   
    hs.clear();
    laps.clear();
    if(stateManager.hasState(input)){
            stateManager.detach(input);
    }

  cam.setRotation(Quaternion.IDENTITY);
  cam.setLocation(Vector3f.ZERO);
  try{
  physics.getPhysicsSpace().removeAll(carNode);

physics.getPhysicsSpace().removeAll(racingTrack);
}
catch(Exception e){

  }
  localRootNode.detachAllChildren();
  localGuiNode.detachAllChildren();
   rootNode.detachChild(localRootNode);
   guiNode.detachChild(localGuiNode);

executor.shutdown();
this.lapFinished=false;
this.setLap=false;

  this.app.getViewPort().clearProcessors();
    super.cleanup();
}         






    }

 [/java] 

@pspeed ,concerning the multicore issue and multithreading ,isnt it that multithreading creates more threads for your application which results in your game being allocated more memory , such that if your processor is quick enough ,most of your threads will get executed within a short time frame ,cause looking at my 3.2Ghz single core processor ,i think it is better than a dual core with two 1.4Ghz processors ,or im wrong?

When one processor is running multiple threads it does it by swapping out slices of time. If your processor is already maxed out running one thread then running two is not going to suddenly help you. However, on a multicore system, running one CPU maxed out means you can still run other threads on the other CPU.

If physics was already your bottleneck and consuming all CPU time then moving it to another thread won’t help on a single core system.

Imagine an office worker that must process paperwork. Putting another “in box” on his desk is not going to help. Putting another “in box” on someone else’s desk will, though. Now they can split the load.

In this analogy, your CPU cores are the office workers.