problem of physical cubes

kurlrip
Posts: 5
Joined: Mon Aug 05, 2013 7:02 am

problem of physical cubes

Post by kurlrip »

Hello
First, sory for my English :)


I discover bullet, and in my case jbulle because i use it with java.
I try to do something simple (i supposed).
Like on many video on Youtube i try to put many cube at random position in a world.

I realise this with succes but i have a little problem and i don't know how to do.

I have a ground, i have some cube with texture etc.. The cube fall well, but, not like in reality. They don't "rotate" and stay alway on the same position.
For eg, i can make a staircase juste with cube, and even if a cube is on the edge to another cube, it does not fail to fall.

I hope you understand me

This is the code i try :

So, if someone could explain to me what i ve miss, that would be nice.




Code: Select all


public class Test_jBullet_DemoBasic {
    
        public static final     boolean             vsync = true;
        public                  boolean             fullscreen  = false;
        private static          int                 fps;
        private static          long                lastFPS;
        private static          long                lastFrame;
        private                 int                 delta;

        public                  int                 width       = 1024;
        public                  int                 height      = 768;


        private static          Texture             TEXTURE_SOL;
        private static          Texture             TEXTURE_CUBE;
        
        private                 FreeFlyCamera       cam;
        public                  double              angleZ  = 0;
        public                  double              angleX  = 0;
        private                 double              rX      = 0;
        private                 double              rY      = 0;
        private                 double              rZ      = 0;


        private static          Set<RigidBody>      rBody   = new HashSet<RigidBody>();
        
        private static          Sphere              sphere  = new Sphere();
        
        /*
         * 
         *          jBullet Demo Variables 
         * 
         */
        // create 125 (5x5x5) dynamic object
	private static final int ARRAY_SIZE_X = 5;
	private static final int ARRAY_SIZE_Y = 5;
	private static final int ARRAY_SIZE_Z = 5;

	// maximum number of objects (and allow user to shoot additional boxes)
	private static final int MAX_PROXIES = (ARRAY_SIZE_X*ARRAY_SIZE_Y*ARRAY_SIZE_Z + 1024);

	private static final int START_POS_X = -5;
	private static final int START_POS_Y = -5;
	private static final int START_POS_Z = -3;
	
	// keep the collision shapes, for deletion/cleanup
	private ObjectArrayList<CollisionShape> collisionShapes = new ObjectArrayList<CollisionShape>();
	private BroadphaseInterface broadphase;
	private CollisionDispatcher dispatcher;
	private ConstraintSolver solver;
	private DefaultCollisionConfiguration collisionConfiguration;
        
        
        
        /*
         * 
         *  Variable issue d'une autre classe
         * 
         */
        
        protected DynamicsWorld dynamicsWorld = null;
        
        
        
    
        public static void main(String[] args) throws LWJGLException {
            Test_jBullet_DemoBasic test_jBullet_DemoBasic = new Test_jBullet_DemoBasic();
	}
        
        
        public Test_jBullet_DemoBasic(){
            
            Init_Display();
            Init_GL();
            Init_Texture();
            
            initPhysics();

            cam = new FreeFlyCamera(new org.lwjgl.util.vector.Vector3f(-10,0,2),new org.lwjgl.util.vector.Vector3f(11,3,2));
            cam.init_Cam(new org.lwjgl.util.vector.Vector3f(1,0,0), new org.lwjgl.util.vector.Vector3f(-10,0,2));
            cam.setDebug(true);

            lastFPS = getTime();
        
            while(!Display.isCloseRequested()){

                rY = cam.getAngleH() * Math.PI / 180;
                rZ = cam.getAngleV() * Math.PI / 180;

                delta = getDelta();   
                angleZ += 0.05 * delta ;
                angleX += 0.05 * delta ;


                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
                dynamicsWorld.stepSimulation(1.0f / 60.0f); //mettre à jour la simulation physique à chaque frame


                glMatrixMode( GL_MODELVIEW );
                glLoadIdentity( );
                
                getIntput();
                
                
 
                for (RigidBody body : rBody) {
                    glPushMatrix();
                    Vector3f bodyPosition = body.getWorldTransform(new Transform()).origin;
                    glTranslatef(bodyPosition.x, bodyPosition.y, bodyPosition.z);
                    //sphere.setDrawStyle(GLU.GLU_SILHOUETTE);
                    dessiner_Cube();
                    glColor4f(1, 0, 0, 1);
                  
                    //sphere.draw(0.5f, 30, 30);
                    glPopMatrix();
                }
                    
         
                
                
                glFlush(); //s'assurer que toutes les commandes OpenGL ont été exécutées

                updateFPS();

                Display.update();
                if (vsync) {
                    Display.sync(60);
                }
                if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)){
                    Display.destroy();
                    System.exit(0);
                }
            }
            
            
            
            
        }
        
    public void initPhysics() {

            //setCameraDistance(50f);

            // collision configuration contains default setup for memory, collision setup
            collisionConfiguration = new DefaultCollisionConfiguration();

            // use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
            dispatcher = new CollisionDispatcher(collisionConfiguration);

            broadphase = new DbvtBroadphase();

            // the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
            SequentialImpulseConstraintSolver sol = new SequentialImpulseConstraintSolver();
            solver = sol;

            // TODO: needed for SimpleDynamicsWorld
            //sol.setSolverMode(sol.getSolverMode() & ~SolverMode.SOLVER_CACHE_FRIENDLY.getMask());

            dynamicsWorld = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);

            dynamicsWorld.setGravity(new Vector3f(0f, -10f, 0f));

            // create a few basic rigid bodies
            CollisionShape groundShape = new BoxShape(new Vector3f(50f, 50f, 50f));
            //CollisionShape groundShape = new StaticPlaneShape(new Vector3f(0, 1, 0), 50);

            collisionShapes.add(groundShape);

            Transform groundTransform = new Transform();
            groundTransform.setIdentity();
            groundTransform.origin.set(0, -56, 0);

            // We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here:
            {
                    float mass = 0f;

                    // rigidbody is dynamic if and only if mass is non zero, otherwise static
                    boolean isDynamic = (mass != 0f);

                    Vector3f localInertia = new Vector3f(0, 0, 0);
                    if (isDynamic) {
                            groundShape.calculateLocalInertia(mass, localInertia);
                    }

                    // using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
                    DefaultMotionState myMotionState = new DefaultMotionState(groundTransform);
                    RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, groundShape, localInertia);
                    RigidBody body = new RigidBody(rbInfo);

                    // add the body to the dynamics world
                    dynamicsWorld.addRigidBody(body);
            }

            {
                    // create a few dynamic rigidbodies
                    // Re-using the same collision is better for memory usage and performance

                    CollisionShape colShape = new BoxShape(new Vector3f(1, 1, 1));
                    //CollisionShape colShape = new SphereShape(1f);
                    collisionShapes.add(colShape);

                    // Create Dynamic Objects
                    Transform startTransform = new Transform();
                    startTransform.setIdentity();

                    float mass = 1f;

                    // rigidbody is dynamic if and only if mass is non zero, otherwise static
                    boolean isDynamic = (mass != 0f);

                    Vector3f localInertia = new Vector3f(0, 0, 0);
                    if (isDynamic) {
                            colShape.calculateLocalInertia(mass, localInertia);
                    }

                    float start_x = START_POS_X - ARRAY_SIZE_X / 2;
                    float start_y = START_POS_Y;
                    float start_z = START_POS_Z - ARRAY_SIZE_Z / 2;

                    for (int k = 0; k < ARRAY_SIZE_Y; k++) {
                            for (int i = 0; i < ARRAY_SIZE_X; i++) {
                                    for (int j = 0; j < ARRAY_SIZE_Z; j++) {
                                            startTransform.origin.set(
                                                            2f * i + start_x,
                                                            10f + 2f * k + start_y,
                                                            2f * j + start_z);

                                            // using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
                                            DefaultMotionState myMotionState = new DefaultMotionState(startTransform);
                                            RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia);
                                            RigidBody body = new RigidBody(rbInfo);
                                            body.setActivationState(RigidBody.DISABLE_DEACTIVATION);
                                            
                                            rBody.add(body);
                                            
                                            dynamicsWorld.addRigidBody(body);
                                            body.setActivationState(RigidBody.DISABLE_DEACTIVATION);
                                    }
                            }
                    }
            }

            //clientResetScene();
    }


    private void Init_Display() {

        try {
            if (fullscreen) {
                Display.setDisplayModeAndFullscreen(Display.getDesktopDisplayMode());
            } else {
                Display.setResizable(false);
                Display.setDisplayMode(new DisplayMode(width, height));


            }
            Display.setTitle("Test JBullet");
            Display.setVSyncEnabled(vsync);
            Display.create();

        } catch (LWJGLException ex) {
            ex.printStackTrace();
            Display.destroy();
            System.exit(1);
        }





        if (!GLContext.getCapabilities().OpenGL11) {
            System.err.println("Votre version OpenGL ne prend pas en charge la fonctionnalité requise.");
            Display.destroy();
            System.exit(1);
        }
    }

    private void Init_GL(){

        glMatrixMode( GL_PROJECTION );
        glLoadIdentity( );
        gluPerspective((float)70,(float)1024/768,1,1000);
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_TEXTURE_2D);



    }
    
    private void dessiner_Cube(){
        
        
        glColor3f(255,255,255); // On neutralise les couleurs utilisé précédement. Pour ce faire on utilise le blanc
            
            
        glPushMatrix(); // Push et Pop Matrix pour que la rotatin soit faite que sur le cube
                        // PushMatrix mémorise la matrice, PopMatrice la restitue
                        // Sans ça, tout les Obect 3D effectuent la rotation
        
    
        
        int nIdTexture;
        nIdTexture = TEXTURE_CUBE.getTextureID();
        
        glBindTexture(GL_TEXTURE_2D, nIdTexture);
        
        //glPolygonMode( GL_, GL_LINE );
        
        glBegin(GL_QUADS);
            
            
            //glColor3f(255,0,0); //face rouge
            glTexCoord2d(0,1);
            glVertex3d(1,1,1);
            glTexCoord2d(0,0);
            glVertex3d(1,1,-1);
            glTexCoord2d(1,0);
            glVertex3d(-1,1,-1);
            glTexCoord2d(1,1);
            glVertex3d(-1,1,1);
        
        
            //glColor3f(0,255,0); //face verte
            glTexCoord2d(0,1);
            glVertex3d(1,-1,1);
            glTexCoord2d(0,0);
            glVertex3d(1,-1,-1);
            glTexCoord2d(1,0);
            glVertex3d(1,1,-1);
            glTexCoord2d(1,1);
            glVertex3d(1,1,1);
        
            //glColor3f(0,0,255); //face bleue
            glTexCoord2d(0,1);
            glVertex3d(-1,-1,1);
            glTexCoord2d(0,0);
            glVertex3d(-1,-1,-1);
            glTexCoord2d(1,0);
            glVertex3d(1,-1,-1);
            glTexCoord2d(1,1);
            glVertex3d(1,-1,1);
            
            //glColor3f(255,255,0); //face jaune
            glTexCoord2d(0,1);
            glVertex3d(-1,1,1);
            glTexCoord2d(0,0);
            glVertex3d(-1,1,-1);
            glTexCoord2d(1,0);
            glVertex3d(-1,-1,-1);
            glTexCoord2d(1,1);
            glVertex3d(-1,-1,1);

            //glColor3f(0,255,255); //face cyan
            glTexCoord2d(0,1);
            glVertex3d(1,1,-1);
            glTexCoord2d(0,0);
            glVertex3d(1,-1,-1);
            glTexCoord2d(1,0);
            glVertex3d(-1,-1,-1);
            glTexCoord2d(1,1);
            glVertex3d(-1,1,-1);

            //glColor3f(255,0,255); //face magenta
            glTexCoord2d(0,1);
            glVertex3d(1,-1,1);
            glTexCoord2d(0,0);
            glVertex3d(1,1,1);
            glTexCoord2d(1,0);
            glVertex3d(-1,1,1);
            glTexCoord2d(1,1);
            glVertex3d(-1,-1,1);

        glEnd();
      
        glPopMatrix();

       

    }

    private void Init_Texture(){

    try {


            // load texture from PNG file
            TEXTURE_CUBE        = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("res/wood.png"));  
            TEXTURE_SOL         = TextureLoader.getTexture("jpg", ResourceLoader.getResourceAsStream("res/champ2.jpg"));


        } catch (IOException e) {
            e.printStackTrace();
        }

    } 

    private static long getTime() {
        return (Sys.getTime() * 1000) / Sys.getTimerResolution();
    }

    private static int getDelta() {
        long time = getTime();
        int delta = (int) (time - lastFrame);
        lastFrame = time;

        return delta;
    }
    
    public static void updateFPS() {
        if (getTime() - lastFPS > 1000) {
            Display.setTitle("FPS: " + fps); 
            fps = 0; //reset the FPS counter
            lastFPS += 1000; //add one second
        }
        fps++;
    }
    
    private void getIntput(){
                
        cam.pollInput(delta);
        cam.look();

        while (Keyboard.next()) {
            if (Keyboard.getEventKeyState()) {
                switch (Keyboard.getEventKey()) {
                    case Keyboard.KEY_F:
                    System.out.println("A Key Event");
                    break;
                }
            }
        }

        if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)){
            System.out.println("SPACE Key Event");        
        }
    }
    
}



kurlrip
Posts: 5
Joined: Mon Aug 05, 2013 7:02 am

Re: problem of physical cubes

Post by kurlrip »

anyone ?

tell me if my English is not quite correct, or if I explained poorly ?

thk

PS : a little picture :

Image


With a "real" physic, the three cube should fall on a rotating...
Basroil
Posts: 463
Joined: Fri Nov 30, 2012 4:50 am

Re: problem of physical cubes

Post by Basroil »

I don't really see why it HAS to fall in real life, the overall center of gravity (projected in the direction of gravity) of the top two cubes is within the bottom cube, and center of gravity of the top cube is inside the middle one. A more exaggerated difference would cause the overall center of gravity of the ones above be outside the one below, and at that moment you would generate a moment to topple it (yes I'm leaving out a lot of the actual explanation there). A lack of rotation though is generally a sign that inertia has been set to zero, or rotation turned off in settings. If you are certain that your moment of inertia passed into the cubes is correct (non-zero), then you have a more serious problem.
kurlrip
Posts: 5
Joined: Mon Aug 05, 2013 7:02 am

Re: problem of physical cubes

Post by kurlrip »

I wrote "in real life" because it s a means for me to explain what i want to say. Because as i wrote maybe my english isn t as good for write exactly waht i want....
but in all demo i ve saw, the cube "rotate and fall", in my exemple, i can launch 1000 cube at random position, they never rotate and fall all in the same position as in picture.

I ll see innertia and rotation as you say. because as you can see on code, i have :

Vector3f localInertia = new Vector3f(0, 0, 0);
if (isDynamic) {
groundShape.calculateLocalInertia(mass, localInertia);
}

so as you said, inertia is at 0

and i don t put anything for rotation setting, as you can see in code.


Else, i try to draw the collision shape for see if the cube i draw are really same that boxshape (hope it s understable...)

Thank for help
Basroil
Posts: 463
Joined: Fri Nov 30, 2012 4:50 am

Re: problem of physical cubes

Post by Basroil »

kurlrip wrote:Vector3f localInertia = new Vector3f(0, 0, 0);
if (isDynamic) {
groundShape.calculateLocalInertia(mass, localInertia);
}

so as you said, inertia is at 0
Technically the local inertia should be non-zero after that code considering you have shape.calculateLocalInertia called (since mass!=0 so isDynamic=true). If it actually is inertia based (and boxes don't rotate at all) errors causing this, there's a simple test. Drop one box from any height, but make the initial rotation be 45 degrees on two axis (doesn't matter which two) and 0<angle<45 for the last. That makes the box unstable and will rotate as long as rotations are possible (even if it takes a long time when inertia is huge). Another one that can slow rotations (but not always stop them entirely) is the angular damping factor, but the defaults shouldn't be that high to begin with.
kurlrip
Posts: 5
Joined: Mon Aug 05, 2013 7:02 am

Re: problem of physical cubes

Post by kurlrip »

i v already try this.

so i add the line glRotatef(45, 1,0,0);

in

Code: Select all



                for (RigidBody body : rBody) {
                    glPushMatrix();
                    Vector3f bodyPosition = body.getWorldTransform(new Transform()).origin;
                    glTranslatef(bodyPosition.x, bodyPosition.y, bodyPosition.z);
                    glRotatef(45, 1,0,0);
                    dessiner_Cube();
                    glColor4f(1, 0, 0, 1);
                    glPopMatrix();
                }
                
and i have this :

Image

As i said, no rotate.

Don t forget i m beginner, so maybe my questions are stupid :(
but i try...

So i wonder if i don t made confusion between the collision shape and the cube i draw. I remeber that in LibGDX i had a problem like this (in 2D) le square i draw are not the same thing that the box shape, and box shape made rotation correctly, but the square didn t move. because i didn t apply the same rotation to the square that for the box shape. (if you see what i means)
So i wonder if i dont have same problem here.

Thk
Basroil
Posts: 463
Joined: Fri Nov 30, 2012 4:50 am

Re: problem of physical cubes

Post by Basroil »

kurlrip wrote:i v already try this.

so i add the line glRotatef(45, 1,0,0);

in

Code: Select all



                for (RigidBody body : rBody) {
                    glPushMatrix();
                    Vector3f bodyPosition = body.getWorldTransform(new Transform()).origin;
                    glTranslatef(bodyPosition.x, bodyPosition.y, bodyPosition.z);
                    glRotatef(45, 1,0,0);
                    dessiner_Cube();
                    glColor4f(1, 0, 0, 1);
                    glPopMatrix();
                }
                
Completely the wrong way to go about it! :wink: As you guessed at, you are simply discarding rotation information before passing it to OGL, so the boxes move but never rotate on screen. We can't even know if bullet is working correctly because the rendering isn't representative of the bullet world.

The rotation you did there is a rotation in OGL that should have no impact on the bullet transforms. To check for rotation you need to pass the rigid body rotations as well as the position of the origin, and the initial rotation must be made to the initial transform you pass to the rigid body when you created it.

You need to really look at the built in demos and understand how they work before trying to reinvent the wheel. The btMotionState object already has OGL friendly code built in so you can pass the entire transform rather than translation and rotation separately, and unlike some other methods it has built in interpolation for when your time step is not equal to the bullet timestep. If you google for bullet physics tutorials, there are a few basic ones in French that might be useful to reference.
kurlrip
Posts: 5
Joined: Mon Aug 05, 2013 7:02 am

Re: problem of physical cubes

Post by kurlrip »

Thk a lot.
So, i finally succes to do what i want.

i declare this :

Code: Select all

    private Transform trans = new Transform();
    float[] matrix = new float[16];
And after, when i do render i do this :

Code: Select all


        for (PhysicsCube body : Cubes) {
            
            trans = body.getRigidBody().getMotionState().getWorldTransform(trans);
            
            trans.getOpenGLMatrix(matrix);
            // pass that matrix to OpenGL and render the cube
            FloatBuffer buffer = ByteBuffer.allocateDirect(4*16).order(ByteOrder.nativeOrder()).asFloatBuffer().put(matrix);
            buffer.rewind();
            glPushMatrix();
            glMultMatrix(buffer);
            body.draw();
            
            glPopMatrix();
        }


The line 'body.draw();' is a function in my PhysicCube Class :

private void draw(){


glColor3f(255,255,255); // On neutralise les couleurs utilisé précédement. Pour ce faire on utilise le blanc

glBindTexture(GL_TEXTURE_2D, cubeTexture.getTextureID());


glBegin(GL_QUADS);


//glColor3f(255,0,0); //face rouge
glTexCoord2d(0,1);
glVertex3d(1,1,1);
glTexCoord2d(0,0);
glVertex3d(1,1,-1);
glTexCoord2d(1,0);
glVertex3d(-1,1,-1);
glTexCoord2d(1,1);
glVertex3d(-1,1,1);


//glColor3f(0,255,0); //face verte
glTexCoord2d(0,1);
glVertex3d(1,-1,1);
glTexCoord2d(0,0);
glVertex3d(1,-1,-1);
glTexCoord2d(1,0);
glVertex3d(1,1,-1);
glTexCoord2d(1,1);
glVertex3d(1,1,1);

//glColor3f(0,0,255); //face bleue
glTexCoord2d(0,1);
glVertex3d(-1,-1,1);
glTexCoord2d(0,0);
glVertex3d(-1,-1,-1);
glTexCoord2d(1,0);
glVertex3d(1,-1,-1);
glTexCoord2d(1,1);
glVertex3d(1,-1,1);

//glColor3f(255,255,0); //face jaune
glTexCoord2d(0,1);
glVertex3d(-1,1,1);
glTexCoord2d(0,0);
glVertex3d(-1,1,-1);
glTexCoord2d(1,0);
glVertex3d(-1,-1,-1);
glTexCoord2d(1,1);
glVertex3d(-1,-1,1);

//glColor3f(0,255,255); //face cyan
glTexCoord2d(0,1);
glVertex3d(1,1,-1);
glTexCoord2d(0,0);
glVertex3d(1,-1,-1);
glTexCoord2d(1,0);
glVertex3d(-1,-1,-1);
glTexCoord2d(1,1);
glVertex3d(-1,1,-1);

//glColor3f(255,0,255); //face magenta
glTexCoord2d(0,1);
glVertex3d(1,-1,1);
glTexCoord2d(0,0);
glVertex3d(1,1,1);
glTexCoord2d(1,0);
glVertex3d(-1,1,1);
glTexCoord2d(1,1);
glVertex3d(-1,-1,1);

glEnd();



}

Thk again.