Bullet physics with modern openGL lwjgl

Started by
22 comments, last by orange451 5 years, 8 months ago

I need a tutorial on how to implement Bullet Physics with Modern OpenGL, otherwise here is my problem:

I am currently working on a game engine in LWJGL, legacy OpenGL fixed function pipeline. I am using Bullet Physics library for my physics engine and so far, everything is working excellent (cubes are colliding perfectly, spheres are colliding perfectly) but I don’t want to work in Legacy OpenGL, I want to work with modern OpenGL. The problem is that to make everything work perfectly in legacy OpenGL (my situation currently), I have to use glMultMatrix(). Now if I want to work with Modern OpenGL and have same results, I don’t know how. Because glMultMatrix() is deprecated, it can NOT be used in modern OpenGL. Source code (not all of it):

Advertisement
43 minutes ago, Ali Aman said:

LWJGL, legacy OpenGL fixed function pipeline. I am using Bullet Physics library for my physics engine

This is not a Game Design matter. Moving to appropriate forum.

-- Tom Sloper -- sloperama.com

Did you mean to include some source code in your post? (I see 'Source code' at the end, but don't see anything after that.)

Are you just using the OpenGL matrix functions for rendering purposes? Or are you also using them for physics by querying matrices from OpenGL?

In other words, what functionality is it exactly that you're currently using OpenGL's matrix functions for, but that you want to implement differently?

I don't use OpenGL (or at least not in years) and I'm not sure why it was removed. However you can probably write that function in 10 minutes. Just look up matrix multiplication. Here's the wiki page:

https://en.wikipedia.org/wiki/Matrix_multiplication

Go down to the illustration for the simple explanation.  Alternatively you can find some library which  is optimized for the latest intel intrinsics like this one:

https://software.intel.com/en-us/mkl

To translate to modern OpenGL 3.3+ you have to:

1.) Build the matrix stack yourself, as every gl*Matrix* function is deprecated

2.) You cannot use any glBegin(), glVertex*(), glColor*() functions anymore -> Use VBO instead.

3.) You cannot use glClient*() related functions, such as glClientActiveTexture or glEnableClientState

4.) You need to use at least one active shader program, because there is no function pipeline anymore

5.) You need a active vertex array, otherwise you wont see anything (Some drivers have a default VA bound, so keep that in mind)

 

For more details see the following tutorial:

https://ahbejarano.gitbook.io/lwjglgamedev/

23 hours ago, Zakwayda said:

Did you mean to include some source code in your post? (I see 'Source code' at the end, but don't see anything after that.)

Are you just using the OpenGL matrix functions for rendering purposes? Or are you also using them for physics by querying matrices from OpenGL?

In other words, what functionality is it exactly that you're currently using OpenGL's matrix functions for, but that you want to implement differently?

Yes, I did mean to include the source code but unfortunately forgot it. I'll paste it again so the problem is more clear. I got a bit updated with my code and moved onto modern opengl (>3.0). Every object is translating appropriately, but they are not rotating as they should.

My problem is clearly in the code commented in the render() method.  

 


package renderEngine;

import java.util.HashSet;
import java.util.Set;

import javax.vecmath.Quat4f;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.glu.Sphere;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.newdawn.slick.Color;
import org.newdawn.slick.TrueTypeFont;

import com.bulletphysics.collision.broadphase.BroadphaseInterface;
import com.bulletphysics.collision.broadphase.DbvtBroadphase;
import com.bulletphysics.collision.dispatch.CollisionConfiguration;
import com.bulletphysics.collision.dispatch.CollisionDispatcher;
import com.bulletphysics.collision.dispatch.CollisionObject;
import com.bulletphysics.collision.dispatch.DefaultCollisionConfiguration;
import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.SphereShape;
import com.bulletphysics.collision.shapes.StaticPlaneShape;
import com.bulletphysics.dynamics.DiscreteDynamicsWorld;
import com.bulletphysics.dynamics.DynamicsWorld;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.dynamics.RigidBodyConstructionInfo;
import com.bulletphysics.dynamics.constraintsolver.ConstraintSolver;
import com.bulletphysics.dynamics.constraintsolver.SequentialImpulseConstraintSolver;
import com.bulletphysics.linearmath.DefaultMotionState;
import com.bulletphysics.linearmath.MotionState;
import com.bulletphysics.linearmath.Transform;

import abstracts.GameObject;
import enums.ObjectID;
import shaders.Shader;
import tools.Utils;

public class Game {
	
	public static Loader loader;
	public static BufferedImageLoader imageLoader = new BufferedImageLoader();

	private static final Transform DEFAULT_BALL_TRANSFORM = new Transform(new javax.vecmath.Matrix4f(new Quat4f(0, 0, 0, 1), new javax.vecmath.Vector3f(0, 35, 0), 1.0f));
	
	private Renderer renderer;
	private Shader shader;
	private Handler handler;
	private Camera camera;
	
	private static DynamicsWorld dynamicsWorld;
    private static Set<RigidBody> balls = new HashSet<RigidBody>();
    private static RigidBody controlBall;
    private static boolean applyForce = false;
    private static boolean createNewShape = false;
    private static boolean resetControlBall = false;
    private static Sphere sphere = new Sphere();
    
    private void setUpPhysics() {
    	Transform DEFAULT_BALL_TRANSFORM = new Transform(new javax.vecmath.Matrix4f(new Quat4f(0, 0, 0, 1), 
    	new javax.vecmath.Vector3f(0, 17, -10), 1.0f));
        BroadphaseInterface broadphase = new DbvtBroadphase();
        CollisionConfiguration collisionConfiguration = new DefaultCollisionConfiguration();
        CollisionDispatcher dispatcher = new CollisionDispatcher(collisionConfiguration);
        ConstraintSolver solver = new SequentialImpulseConstraintSolver();
        dynamicsWorld = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
        dynamicsWorld.setGravity(new javax.vecmath.Vector3f(0, -10 /* m/s2 */, 0));
        CollisionShape groundShape = new StaticPlaneShape(new javax.vecmath.Vector3f(0, 1, 0), 0.25f /* m */);
        CollisionShape ballShape = new SphereShape(0.5f);
        MotionState groundMotionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(
                new Quat4f(0, 0, 0, 1),
                new javax.vecmath.Vector3f(0, 0, 0), 1.0f)));
        RigidBodyConstructionInfo groundBodyConstructionInfo = new RigidBodyConstructionInfo(0, groundMotionState, groundShape, new javax.vecmath.Vector3f(0, 0, 0));
        groundBodyConstructionInfo.restitution = 0.25f;
        RigidBody groundRigidBody = new RigidBody(groundBodyConstructionInfo);
        dynamicsWorld.addRigidBody(groundRigidBody);
        MotionState ballMotionState = new DefaultMotionState(DEFAULT_BALL_TRANSFORM);
        javax.vecmath.Vector3f ballInertia = new javax.vecmath.Vector3f(0, 0, 0);
        ballShape.calculateLocalInertia(2.5f, ballInertia);
        RigidBodyConstructionInfo ballConstructionInfo = new RigidBodyConstructionInfo(2.5f, ballMotionState, ballShape, ballInertia);
        ballConstructionInfo.restitution = 0.5f;
        ballConstructionInfo.angularDamping = 0.95f;
        controlBall = new RigidBody(ballConstructionInfo);
        controlBall.setActivationState(CollisionObject.DISABLE_DEACTIVATION);
        balls.add(controlBall);
        dynamicsWorld.addRigidBody(controlBall);
    }
	private static TrueTypeFont font;
	private static TrueTypeFont font2;
	
	private Game() {
		try {			
			Display.setDisplayMode(new DisplayMode(1250, 660));
			Display.setTitle("Game");
			Display.setLocation(54, 32);
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
		}
	}
	
	private void init() {
		setUpPhysics();
		handler = new Handler();
		camera = new Camera(new Vector3f(0, 17, 0));
		loader = new Loader();
		shader = new Shader("src/shaders/Vertex.glsl", "src/shaders/Fragment.glsl");
		renderer = new Renderer(shader);
		GameObject.init();
	}
	
	private void run() {
		while(!Display.isCloseRequested()) {
			render();
			tick();
			input();
		}
		destroy();
	}
	
	private void render() {
		renderer.prepare();		
		shader.enable();
		Matrix4f viewMatrix = Utils.createViewMatrix(camera);
		shader.loadMatrix(viewMatrix, "viewMatrix");
		sphere.setDrawStyle(GLU.GLU_SILHOUETTE);
		for(RigidBody body : balls) {
			javax.vecmath.Vector3f ballPosition = body.getWorldTransform(new Transform()).origin;
			
			Matrix4f transformationMatrix = new Matrix4f();
			
			transformationMatrix.translate(new Vector3f(ballPosition.x, ballPosition.y, ballPosition.z));
			// ^ this translates the object (of course) appropriately. I don't know how to work around rotation them. 
			// I have tried doing transformationMatrix.rotate(...), it does rotate, but not properly. I don't know how to work around that :(
			
			shader.enable();
			shader.loadMatrix(transformationMatrix, "transformationMatrix");
			renderer.setColor(0, 1, 1, 1, shader);
			renderer.render(GameObject.cube, shader);
		}
		
		System.out.println(balls.size());
		
		Matrix4f trans2 = new Matrix4f();
		shader.enable();
		shader.loadMatrix(trans2, "transformationMatrix");
		renderer.setColor(0.5f, 0.5f, 0.5f, 1, shader);
		renderer.render(GameObject.rect, shader);
		shader.enable();
		shader.enable();
		shader.disable();
		shader.disable();
		handler.renderObjects(renderer);
	}
	
	public static void renderTTF(String text, int x, int y, Color color) {
		font.drawString(x, y, text, color);
	    font2.drawString(-1000, -1000, "", Color.green);
	}
	
	private void tick() {
		camera.move();
		handler.tickObjects();
		dynamicsWorld.stepSimulation(1.0f/60.0f);
		Set<RigidBody> ballsToBeRemoved = new HashSet<RigidBody>();
		for(RigidBody body : balls) {
			javax.vecmath.Vector3f position = body.getWorldTransform(new Transform()).origin;
			if(!body.equals(controlBall) && (position.x > -50 || position.x > 50 || position.z < -50 || position.z > 50)) {
				ballsToBeRemoved.add(body);
			}
		}
		
		for(RigidBody body : ballsToBeRemoved) {
			balls.remove(body);
			dynamicsWorld.removeRigidBody(body);
		}
		
		if (applyForce) {
            Transform controlBallTransform = new Transform();
            controlBall.getMotionState().getWorldTransform(controlBallTransform);
            javax.vecmath.Vector3f controlBallLocation = controlBallTransform.origin;
            javax.vecmath.Vector3f cameraPosition = new javax.vecmath.Vector3f(camera.getPosition().x, camera.getPosition().y, camera.getPosition().z);
            javax.vecmath.Vector3f force = new javax.vecmath.Vector3f();
            force.sub(cameraPosition, controlBallLocation);
            controlBall.activate(true);
            controlBall.applyCentralForce(force);
        }
        if (createNewShape) {
            createNewShape(0, 35, 0);
        }
        if (resetControlBall) {
            controlBall.setCenterOfMassTransform(DEFAULT_BALL_TRANSFORM);
            controlBall.setAngularVelocity(new javax.vecmath.Vector3f(0, 0, 0));
            controlBall.setLinearVelocity(new javax.vecmath.Vector3f(0, 0, 0));
            resetControlBall = false;
        }
		for(int i = 0; i < handler.objects.size(); i++) {
			GameObject object = handler.objects.get(i);
			if(object.getId() == ObjectID.PLAYER) {
				if(Keyboard.isKeyDown(Keyboard.KEY_UP)) object.getPosition().y += 0.04f;
				if(Keyboard.isKeyDown(Keyboard.KEY_DOWN)) object.getPosition().y -= 0.04f;
				if(Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) object.getPosition().x += 0.04f;
				if(Keyboard.isKeyDown(Keyboard.KEY_LEFT)) object.getPosition().x -= 0.04f;
			}
		}
		
		Display.sync(60);
		Display.update();
		
		if (Mouse.isButtonDown(0) && !Mouse.isGrabbed()) {
            Mouse.setGrabbed(true);
        } else if (Mouse.isButtonDown(1) && Mouse.isGrabbed()) {
            Mouse.setGrabbed(false);
        } else if (Mouse.isButtonDown(0) && Mouse.isGrabbed()) {
        	createNewShape(0, 35, 0);
            applyForce = true;
        } else {
            applyForce = false;
        }
        while (Keyboard.next()) {
            if (Keyboard.getEventKeyState()) {
                switch (Keyboard.getEventKey()) {
                    case Keyboard.KEY_G:
                        createNewShape = true;
                        break;
                    case Keyboard.KEY_F:
                        resetControlBall = true;
                        break;
                }
            }
        }
	}
	
	private void createNewShape(float x, float y, float z) {
		CollisionShape shape = new SphereShape(3.0f);
        DefaultMotionState motionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(new Quat4f(0, 0, 0, 1), new javax.vecmath.Vector3f(x, y, z), 1)));
        javax.vecmath.Vector3f inertia = new javax.vecmath.Vector3f();
        shape.calculateLocalInertia(1.0f, inertia);
        RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(1.0f, motionState, shape, inertia);
        constructionInfo.restitution = 0.75f;
        RigidBody body = new RigidBody(constructionInfo);
        dynamicsWorld.addRigidBody(body);
        balls.add(body);
        createNewShape = false;
	}
	
	private void input() {
		
	}
	
	private void destroy() {
		Display.destroy();
	}
	
	public static void main(String[] args) {
		Game game = new Game();
		game.init();
		game.run();
	}
	
}

 

 

The first thing I'd check is transform order. The order you want is rotate->translate. Depending on the conventions used by the math library, that could equate to:


transformationMatrix.rotate(...)
transformationMatrix.translate(...)

Or:


transformationMatrix.translate(...)
transformationMatrix.rotate(...)

So I would try both. (Eventually it'd be good to find out what conventions are used so you don't have to guess.)

If that doesn't work, then perhaps you could post the code where you apply the rotation, and describe in what way it's behaving incorrectly.

16 minutes ago, Zakwayda said:

The first thing I'd check is transform order. The order you want is rotate->translate. Depending on the conventions used by the math library, that could equate to:



transformationMatrix.rotate(...)
transformationMatrix.translate(...)

Or:



transformationMatrix.translate(...)
transformationMatrix.rotate(...)

So I would try both. (Eventually it'd be good to find out what conventions are used so you don't have to guess.)

If that doesn't work, then perhaps you could post the code where you apply the rotation, and describe in what way it's behaving incorrectly.

Ok, I rotated it before translating. I am getting some really weird results :0 the object is rotation really weirdly. I can't elaborate more than that. It is super weird. 

Can you post the code where you apply the rotation?

If you're still stuck on this, I'd at least try describing the behavior, even if it seems difficult. Here are some possible questions you could answer. Is the object deforming? Or is it keeping its shape but just rotating incorrectly? Does it look like it's 'orbiting' something, or maybe traveling in a spiral or loop? Or is it rotating around its own center, but just incorrectly? Is it rotating too fast or too slow? And so on.

I've seen people post screen captures here occasionally, so that might be one way to show what's happening if it's difficult to describe in words.

Edit: Something else you might check for is degree<->radian conversion errors.

45 minutes ago, Zakwayda said:

Can you post the code where you apply the rotation?

If you're still stuck on this, I'd at least try describing the behavior, even if it seems difficult. Here are some possible questions you could answer. Is the object deforming? Or is it keeping its shape but just rotating incorrectly? Does it look like it's 'orbiting' something, or maybe traveling in a spiral or loop? Or is it rotating around its own center, but just incorrectly? Is it rotating too fast or too slow? And so on.

I've seen people post screen captures here occasionally, so that might be one way to show what's happening if it's difficult to describe in words.

Edit: Something else you might check for is degree<->radian conversion errors.

Yes, it is orbiting vertically--exactly the word I was looking for--and the speed of orbiting gets slower and slower until it stops. The object is keeping its shape but not rotating correctly.  

This topic is closed to new replies.

Advertisement