Performance issues

Hello everybody,
I’m a beginner with JME and I have a problem. I have only few objects in my game and I’m running at 8fps! So I was wondering what makes the performance drop like this…
Here is my little code:
[java]package mygame;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.input.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Plane;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Quad;
import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.util.SkyFactory;
import com.jme3.water.SimpleWaterProcessor;

/**
*
*/
public class Main extends SimpleApplication implements AnalogListener, ActionListener , AnimEventListener
{
private PssmShadowRenderer pssmRenderer;
private Node sceneNode;
private Node map;
private Node player;
private Node playerCamNode;
private ChaseCamera chaseCam;

boolean rotate = false;
Vector3f direction = new Vector3f();

private BulletAppState bulletAppState;
private CharacterControl character;
private CharacterControl elephantCharacter;

private Spatial elephant;
private AnimChannel animationChannel;
private AnimChannel attackChannel;
private AnimControl animationControl;
private boolean left = false, right = false, up = false, down = false;

private Vector3f walkDirection = new Vector3f(0,0,0); // stop

private float airTime = 0;

public static void main(String[] args) 
{
    Main app = new Main();
    app.start();
}

@Override
public void simpleInitApp() 
{
    initScene();
    registerInput();
    initChaseCam();
    for (String anim : animationControl.getAnimationNames()) { System.out.println(anim); }
}

@Override
public void simpleUpdate(float tpf) 
{
    walk(tpf);
    elephantCharacter.setWalkDirection(walkDirection);
}

@Override
public void simpleRender(RenderManager rm) 
{
    //TODO: add render code
}
public void initScene()
{
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    bulletAppState.getPhysicsSpace().enableDebug(assetManager);
    
    

    sceneNode = new Node("sceneNode");
    rootNode.attachChild(sceneNode);
    sceneNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
    
    pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 3);
    pssmRenderer.setDirection(new Vector3f(-0.5f,-0.5f,-0.5f).normalizeLocal()); // light direction
    viewPort.addProcessor(pssmRenderer);
    
    map =(Node) assetManager.loadModel("Scenes/Map.j3o");
    map.addControl(new RigidBodyControl(0));
    sceneNode.attachChild(map);
    bulletAppState.getPhysicsSpace().addAll(map);
    map.setShadowMode(ShadowMode.Receive); 
   
    
    CapsuleCollisionShape capsule2 = new CapsuleCollisionShape(10f,8f,2);
    elephantCharacter = new CharacterControl(capsule2, 3f);
    elephantCharacter.setGravity(60);
    elephant =  assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
    elephant.scale(0.2f);
    elephant.setLocalTranslation(30f,5f,10);
    elephant.setShadowMode(ShadowMode.CastAndReceive); 
    elephant.addControl(elephantCharacter);
    bulletAppState.getPhysicsSpace().add(elephantCharacter);
    sceneNode.attachChild(elephant);
    
    CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
    character = new CharacterControl(capsule, 3f);
    character.setJumpSpeed(30f);
    character.setGravity(60);
    player = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
    player.setShadowMode(ShadowMode.CastAndReceive); 
    player.addControl(character);
    bulletAppState.getPhysicsSpace().add(character);
    player.setLocalTranslation(0f,5f,0);
    player.rotate(0f, 3f, 0f);
    playerCamNode = new Node("playerCamNode");
    playerCamNode.attachChild(player);
    rootNode.attachChild(playerCamNode);
    
    SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager);
    waterProcessor.setReflectionScene(sceneNode);
    
    Vector3f waterLocation=new Vector3f(0,-8,0);
    waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
    viewPort.addProcessor(waterProcessor);
    
    waterProcessor.setWaterDepth(40);         // transparency of water
    waterProcessor.setDistortionScale(0.05f); // strength of waves
    waterProcessor.setWaveSpeed(0.05f);  

    Quad quad = new Quad(60,60);
    quad.scaleTextureCoordinates(new Vector2f(6f,6f));

    Geometry water= new Geometry("water", quad);
    water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
    water.setLocalTranslation(-100, -15, 1);
    water.setShadowMode(ShadowMode.Receive);
    water.setMaterial(waterProcessor.getMaterial());
    rootNode.attachChild(water);

    DirectionalLight dayLight = new DirectionalLight();
    dayLight.setColor(ColorRGBA.White);
    dayLight.setDirection(new Vector3f(-0.5f,-0.5f,-0.5f));
    rootNode.addLight(dayLight);
    
    
    animationControl = player.getControl(AnimControl.class);
    animationControl.addListener(this);
    animationChannel = animationControl.createChannel();
    attackChannel = animationControl.createChannel();
    
    
    
}
public void initChaseCam()
{
    flyCam.setEnabled(false);

    chaseCam = new ChaseCamera(cam, player, inputManager);
    chaseCam.setDefaultDistance(80);
    chaseCam.setMinDistance(40);
    chaseCam.setMaxDistance(100);
    chaseCam.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE));
    chaseCam.setSmoothMotion(true);
}
public void registerInput() 
{                  
    inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("CharForward", new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping("CharBackward", new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping("CharJump", new KeyTrigger(KeyInput.KEY_RETURN));
    inputManager.addMapping("CharAttack", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(this, "CharLeft", "CharRight");
    inputManager.addListener(this, "CharForward", "CharBackward");
    inputManager.addListener(this, "CharJump", "CharAttack");
}

public void onAnalog(String name, float value, float tpf) 
{


}

public void onAction(String name, boolean value, float tpf) 
{
    if (name.equals("CharJump"))
    {
        character.jump();
    }
    else if (name.equals("CharLeft")) 
    {
        if (value) left = true;
        else left = false;
    } 
    else if (name.equals("CharRight")) 
    {
        if (value) right = true;
        else right = false;
    } 
    else if (name.equals("CharForward")) 
    {
        if (value) up = true;
        else up = false;
    } 
    else if (name.equals("CharBackward")) 
    {
        if (value) down = true;
        else down = false;
    } 
    
    if (name.equals("CharAttack"))
        attack();

}
private void walk(float timePerFrame)
{
    Vector3f camDir = cam.getDirection().clone().multLocal(0.25f);
    Vector3f camLeft = cam.getLeft().clone().multLocal(0.25f);
    camDir.y = 0;
    camLeft.y = 0;
    walkDirection.set(0, 0, 0);
    
    if (left)  walkDirection.addLocal(camLeft);
    if (right) walkDirection.addLocal(camLeft.negate());
    if (up) walkDirection.addLocal(camDir);
    if (down) walkDirection.addLocal(camDir.negate());
    
    if (!character.onGround()) 
    {
        airTime = airTime + timePerFrame;
        
    } 
    else 
    {
        airTime = 0;
    }

    if (walkDirection.length() == 0) 
    {
        if (!"IdleBase".equals(animationChannel.getAnimationName())) 
        {
          animationChannel.setAnim("IdleBase", 1f);
        }
    } 
    else 
    {
        character.setViewDirection(walkDirection);
        if (airTime > .3f) 
        {
            if (!"IdleBase".equals(animationChannel.getAnimationName())) 
            {
                animationChannel.setAnim("IdleBase");
            }
        } 
        else if (!"RunBase".equals(animationChannel.getAnimationName())) 
        {
          animationChannel.setAnim("RunBase");
        }
    }
    character.setWalkDirection(walkDirection); 
}
private void attack() 
{
    attackChannel.setAnim("SliceVertical", 0.1f);
    attackChannel.setLoopMode(LoopMode.DontLoop);
}
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) 
{
    if (channel == attackChannel) channel.setAnim("IdleBase");
}

public void onAnimChange(AnimControl control, AnimChannel channel, String animName) 
{ 
}

}
[/java]

If you need any other information tell me!

Maybe you can check what causes the low fps by disabling/removing several things
->like the skybox (maybe a very hight texture resolution?)
->the collision
->the shadows
->the water
->whatever…

how complex are those models you have?
Maybe a screenshot?

What are you running your game on?

I was working on a collision shape for the elephant (by the way I don’t know how to relocate the collisionShape at the right position), before this I’m at 60 fps (not much for so few objects I think)

http://postimg.org/image/gh9b30xkh/

My Computer is on windows 7 a i3 3GHz with 3 go ram and a graphic card ATI Radeon HD5600 1go.

What display settings are you using when you run? Did you turn vsync on? Did you have AA cranked? We really don’t have enough information to help fully.

If you have vsync on then the FPS will be capped at 60 anyway.

If you have the AA turned up very high (or even just not disabled) then you will kill performance, etc.

I’m using the lowest for everything, AA disabled, 800x600 , 16bpp, no fullscreen, no vsync.
The elephant, Sinbad and skytextures are from the java-test-data library.

for my terrain the total size is 512, the patch size 256 and the alpha blend texture size is 512.

Install the latest graphics driver from the graphics card manufacturer if you haven’t.

That’s done and it’s really strange that I have these issues because even games like Crysis are running well…

Some laptops have two video cards in them, one integrated and one dedicated. In most cases jME3 and OpenGL based games will run on the integrated card whereas DirectX games will run on the dedicated card. You have to go in the video card’s options menu to change the video card that is used for an application.

I had plenty of issues with my previous ATI card and recent driver with opengl. Did you try games that are running on top of opengl?

Try Uningine Heaven benchmark http://unigine.com/products/heaven/ with opengl and see if you have issues.

I have only one graphic cars and I don’t have a Laptope. I tried to change the code to make it quicker. The problems come from the capsulecollisionShape of the elephant, if I decrease It’s value to 1f,1f I have again 70 fps. It has something to do with the collision physics I think. Maybe I don’t call the méthodes the right way or I don’t use it correctly?

<cite>@nehon said:</cite> I had plenty of issues with my previous ATI card and recent driver with opengl. Did you try games that are running on top of opengl?

Try Uningine Heaven benchmark http://unigine.com/products/heaven/ with opengl and see if you have issues.

Ok I just tried this and I can’t reach more than 20 fps with the lowest settings… in OpenGL and DirectX both… Maybe I have a virus on my computer?

@Solringolt said: Ok I just tried this and I can't reach more than 20 fps with the lowest settings... in OpenGL and DirectX both... Maybe I have a virus on my computer?
No i doubt it, if the results are consistent between DX and opengl, it's not a driver issue. I'm not sure about the physics part though. The size of the capsule shouldn't matter.

Mmmm so no solution?

Your terrain is probably too dense (too many triangles per m^2), in combination with a big collision shape and so bullet works overtime i guess. I ran into a similar issue a year ago.

Put the elephant on a less dense area, or even on a similar sized quad as the elephant (just to make sure)

I tried to use a smaller and flat terrain, the fps are higher (70 fps). And if for example the elephant goes fall off the terrain i go directly to 300 fps so the problem really comes from this. Now the problem is, it’s ok for now with two objects but if I want for example four elephant in my game… the fps will drop again drastically…

So how did you solve your problem?

Has nobody an idea??

Is there another way than using physics if I want an object to move on the terrain?

Isn’t there a special collision shape to use for terrain that makes use of all the optimisations possible because of the nature of terrain?

Are you using that?

I tried it with this:
[java]
CollisionShape terrainShape = CollisionShapeFactory.createMeshShape((Node) terrain);
landscape = new RigidBodyControl(terrainShape, 0);
terrain.addControl(landscape);
[/java]
But in the tutorial it’s combined with a TerrainQuad, should I use a terrain quad too? Until now I just loaded the map.jo3 I made with the terrain editor.
[java]
map = (Node) assetManager.loadModel(“Scenes/Map.j3o”);
CollisionShape mapShape = CollisionShapeFactory.createMeshShape(map);
landscape = new RigidBodyControl(mapShape, 0);
map.addControl(landscape);
sceneNode.attachChild(map);
bulletAppState.getPhysicsSpace().add(map);
[/java]

Actuall that heightmap shape is not faster, its in fact a little slower, compared to the staticmesh one, but it allows for changes in the terrain without a additional computation intesive step.

Two possibilities:
Your terrain is not a statis mesh, this will slow things down.

Alternativly your elephant is a gimpact mesh shape, dynamic mesh to mesh collision are ultra computation intesive, so use a simpler shape instead. (eg 1 large sphere for body, one smaller for head, and 4 cylinders for the legs, and put them into a compount shape)

Can you show how you create the elephant physis?