Author Topic: jBullet, a simple how to guide  (Read 29984 times)

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
jBullet, a simple how to guide
« on: January 18, 2010, 10:08:56 am »
Hi fine folks of the JPCT boards. I sat back down working on a new project using jBullet physics. So I thought for those of you who are not sure how to get jBullet working. I present this basic guide.

[This is a work in progress code and guide]

Since you have decided to use jBullet I suggest going here http://jbullet.advel.cz/ first. Download the latest version. Integrating straight forward raw physics is easy and won't cause any kind of hair pulling :) at least I've already dealt with part of that hair pulling for you :)

Things to know:
jBullet uses java3D vecmath library. You will need this. Fortunetly it is packed with the jBullet download.

jBullet unit scale by default is a 1:1 meter. Though feel free to scale it as 1 Unit as needed. For safety issues don't create objects less than 0.01. Really big objects also tend to start causing simulation problems if landing on top of smaller objects. IIRC up to 10 is safe.

jBullet uses a Y Z axis and coordinates that are more in line with OGL. This is important as JPCT has opposing  YZ.


Step 1
jBullet uses a dynamic world to handle simulation. Very similar to JPCT world setup. The following code below shows how to get a basic jBullet world. I would explain how this means, but i'm using some one else's API for the sake of time rather that learning how it works. So honestly I can not tell you how it all works.
Code: [Select]
collisionConfiguration = new DefaultCollisionConfiguration();
dispatcher = new CollisionDispatcher(collisionConfiguration);
Vector3f worldAabbMin = new Vector3f(-10000,-10000,-10000);
Vector3f worldAabbMax = new Vector3f(10000,10000,10000);
AxisSweep3 overlappingPairCache = new AxisSweep3(worldAabbMin, worldAabbMax);
SequentialImpulseConstraintSolver solver = new SequentialImpulseConstraintSolver();

dynamicWorld = new DiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
dynamicWorld.setGravity(new Vector3f(0,-10,0));
dynamicWorld.getDispatchInfo().allowedCcdPenetration = 0f;
That's it. It's a little heftier than getting a JPCT world going, but it's not that bad.

Step 2
This is a sample physics test. So we are going to need some objects to collide against. jBullet doesn't support a generic static plane at this time. So we are going to create a box that doesn't move. Obviously if you in a space ship you won't need this :)
Code: [Select]
CollisionShape groundShape = new BoxShape(new Vector3f(100.f, 50.f, 100.f));
Transform groundTransform = new Transform();
groundTransform.setIdentity();
groundTransform.origin.set(new Vector3f(0.f, -56.f, 0.f));
float mass = 0f;
Vector3f localInertia = new Vector3f(0, 0, 0);
  DefaultMotionState myMotionState = new DefaultMotionState(groundTransform);
RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(
mass, myMotionState, groundShape, localInertia);
RigidBody body = new RigidBody(rbInfo);
dynamicWorld.addRigidBody(body);
Time to start explaining what's going on. Some parts are straight forward other parts not so much.

Code: [Select]
CollisionShape groundShape = new BoxShape(new Vector3f(100.f, 50.f, 100.f));Similar to JPCT Box. This defines a simple collision shape. There are spheres and trimesh support if needed.

Code: [Select]
Transform groundTransform = new Transform();
groundTransform.setIdentity();
groundTransform.origin.set(new Vector3f(0.f, -56.f, 0.f));
A Bullet Transform is a Body package of information. It stores both the rotation Matrix and position or translation.
Transform.origin(Vector3f) is where you will find position.
Transform.basis(Matrix3f) is where you will find the bodies rotation.
When a new Transform is created make sure .setIdentity() is run to fill in 0 values.

Code: [Select]
float mass = 0f;
Vector3f localInertia = new Vector3f(0, 0, 0);
Make note of this. A mass of 0 means that the object is static. Static objects will not move in the simulation. Static objects do not need a starting inertia.

Code: [Select]
DefaultMotionState myMotionState = new DefaultMotionState(groundTransform);
This(MotionState) is a key component to integrating physics to your graphical world. The DefaultMotionState has methods you can call on to manually get the data for graphical updates.
DefaultMotionState.graphicsWorldTransform.origin
DefaultMotionState.graphicsWorldTransform.basis
For our purposes though we are using DefaultMotionState for a static object since we don't need to update it's position.

Code: [Select]
RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(
mass, myMotionState, groundShape, localInertia);
RigidBody body = new RigidBody(rbInfo);
dynamicWorld.addRigidBody(body);
Not much to say here. Create a parameter object to create the RigidBody. RigidBody is the equivalent of Object3D. It's important to keep track of it some way. Then finally add a body to the physics world.


Step 3
Static objects are no fun to watch. They don't do anything.  This step which is second to last is where coding get's more fun :)
Code: [Select]
             BoxShape shape = new BoxShape(new Vector3f(2,2,2));
       Vector3f localInertia = new Vector3f(0,0,0);
     shape.calculateLocalInertia(mass, localInertia);

    startTransform = new Transform();
    startTransform.setIdentity();
    startTransform.origin.set(0, 0, 0);
   
    ms = new JPCTBulletMotionState(yourObject3D, startTransform);
   
    rbInfo = new RigidBodyConstructionInfo(mass, ms, shape, localInertia);
    body = new RigidBody(rbInfo);
    body.setRestitution(0.1f);
    body.setFriction(0.50f);
    body.setDamping(0f, 0f);
   
    body.setUserPointer(boxgfx);

    dynamicWorld.addRigidBody(body);
Theres the starting code for your cool fun Bodies :) First create a shape. Our sample we have a 2x2x2 Cube. Makes using JPCT Primitives easier.

Code: [Select]
     
             Vector3f localInertia = new Vector3f(0,0,0);
     shape.calculateLocalInertia(mass, localInertia);
You don't need a separate inertia variable, but I left it in so you know the parameter arguments. The second line is
VERY IMPORTANT  Shape.calculateLocalInertia(float, Vector3f) MUST be called for your physics simulation to work properly. If you miss this after this warning don't rip out your hair for a week*cough* like I did *cough*  :-[

Create a new transform and set starting position and or rotation.

Code: [Select]
ms = new JPCTBulletMotionState(yourObject3D, startTransform);
Here is the magic where jBullet and JPCT will work together. You can find the code at the bottom(with warnings).

Code: [Select]
    body.setRestitution(0.1f);
    body.setFriction(0.50f);
    body.setDamping(0f, 0f);
Fairly basic representation.

Resitution(0.0 to 1.0) represent a value of energy return on collision. Bullet doesn't naturally support infinite return.

Friction(0.0 to 1.0) well roughness. How much sliding. 0 is as slick as possible while 1 should present no sliding.

Damping(0.0 to 1.0) Linear damping and rotation damping. This represents atmosphere. Space has no atmosphere an thus objects will move and rotate forever. While water would be very dense and limit movement and rotation very fast.

Code: [Select]
body.setUserPointer(boxgfx);You don't need this, but depending on you track objects(by physics in this case). You can set a reference to a Object in the body. That way you can call the Object later on with RigidBody.getUserPointer(). Just thought this might help.

Then finally add the body.

Step 4.
Ok you have a static body to check collisions against. You have dynamic RigidBody's that can be watched(I know I didn't show graphic code). Well like JPCT some extra code to move the simulation forward is required.
Code: [Select]
  float ms = clock.getTimeMicroseconds();
  clock.reset();
  dynamicWorld.stepSimulation(ms / 1000000f);
Here it is. It's simple, add it just before your render code. Don't thread it. jBullet has not implemented multi threads yet. This is the basic HelloWorld sample. It uses a timer like clock and steps the simulation based on time difference. There are advanced topics on deterministic physics else where, but this is a good start. Knowing how much time has past since last update.


Test Code

First the basic demo code. This demo code is super basic and was written to run on a AMD 2.6mhz dual core running the software rendered. If your running on less it will run slower. If it's a big different drop the numBoxes value near the top.
Code: [Select]

package jpctbullet;

import com.threed.jpct.*;
import com.threed.jpct.util.Light;

import java.util.Vector;
import java.util.List;
import java.util.ArrayList;
import javax.vecmath.Vector3f;
import javax.swing.*;
import java.awt.*;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;

import com.bulletphysics.BulletGlobals;
import com.bulletphysics.collision.broadphase.AxisSweep3;
import com.bulletphysics.collision.dispatch.CollisionObject;
import com.bulletphysics.collision.dispatch.CollisionWorld;
import com.bulletphysics.collision.shapes.BoxShape;
import com.bulletphysics.dynamics.DynamicsWorld;
import com.bulletphysics.dynamics.constraintsolver.Point2PointConstraint;
import com.bulletphysics.dynamics.constraintsolver.TypedConstraint;

import com.bulletphysics.linearmath.*;

import com.bulletphysics.collision.broadphase.BroadphaseInterface;
import com.bulletphysics.collision.broadphase.SimpleBroadphase;
import com.bulletphysics.collision.dispatch.CollisionDispatcher;
import com.bulletphysics.collision.dispatch.DefaultCollisionConfiguration;
import com.bulletphysics.collision.shapes.BoxShape;
import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.StaticPlaneShape;
import com.bulletphysics.dynamics.DiscreteDynamicsWorld;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.dynamics.RigidBodyConstructionInfo;
import com.bulletphysics.dynamics.constraintsolver.ConstraintSolver;
import com.bulletphysics.dynamics.constraintsolver.SequentialImpulseConstraintSolver;

public class BulletTest {
 
  public int numBoxes = 400;
  public int strHeight= 10;
 
private World world;
private FrameBuffer buffer;
private Object3D box; // only something for the camera to focus on.
private JFrame frame;
 
  public DiscreteDynamicsWorld dynamicWorld;
  public int maxSubSteps;
  public float timeStep, fixedTimeStep;
  protected Clock clock = new Clock();
private List<CollisionShape> collisionShapes = new ArrayList<CollisionShape>();
private BroadphaseInterface overlappingPairCache;
private CollisionDispatcher dispatcher;
private ConstraintSolver solver;
private DefaultCollisionConfiguration collisionConfiguration;
 
  private Vector<RigidBody> boxList;

public static void main(String[] args) throws Exception {
new BulletTest().loop();
}

public BulletTest() throws Exception {
frame=new JFrame("JPCTBullet Test");
frame.setSize(800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

  boxList = new Vector();  

    int cpu = Runtime.getRuntime().availableProcessors();
    if(cpu > 1){
      Config.useMultipleThreads = true;
      Config.maxNumberOfCores = cpu;
      Config.loadBalancingStrategy = 1;
    }
world = new World();
//World.setDefaultThread( Thread.currentThread() );
world.setAmbientLight(120, 120, 120);

TextureManager.getInstance().addTexture("box", new Texture("box.jpg"));

box = Primitives.getBox(1f, 1f);
box.translate(0, -50, 0);
box.setTexture("box");
box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);

Object3D ground = Primitives.getPlane(4,25);
ground.setTexture("box");
ground.setEnvmapped(Object3D.ENVMAP_ENABLED);
ground.rotateX((float)-Math.PI);
  ground.build();
world.addObject(ground);

world.getCamera().setPosition(150, -50, -5);
world.getCamera().lookAt(box.getTransformedCenter());

Light light = new Light(world);
light.setPosition(new SimpleVector(-200, -50 , 80));
light.setIntensity(150,140,150);


collisionConfiguration = new DefaultCollisionConfiguration();
dispatcher = new CollisionDispatcher(collisionConfiguration);
Vector3f worldAabbMin = new Vector3f(-10000,-10000,-10000);
Vector3f worldAabbMax = new Vector3f(10000,10000,10000);
AxisSweep3 overlappingPairCache = new AxisSweep3(worldAabbMin, worldAabbMax);
//SimpleBroadphase overlappingPairCache = new SimpleBroadphase(1026);
SequentialImpulseConstraintSolver solver = new SequentialImpulseConstraintSolver();

dynamicWorld = new DiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
dynamicWorld.setGravity(new Vector3f(0,-10,0));
dynamicWorld.getDispatchInfo().allowedCcdPenetration = 0f;

CollisionShape groundShape = new BoxShape(new Vector3f(100.f, 50.f, 100.f));
Transform groundTransform = new Transform();
groundTransform.setIdentity();
groundTransform.origin.set(new Vector3f(0.f, -56.f, 0.f));
float mass = 0f;
Vector3f localInertia = new Vector3f(0, 0, 0);
  DefaultMotionState myMotionState = new DefaultMotionState(groundTransform);
RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(
mass, myMotionState, groundShape, localInertia);
RigidBody body = new RigidBody(rbInfo);
dynamicWorld.addRigidBody(body);

dynamicWorld.clearForces();

initTestObects();
}

private void loop() throws Exception {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_NORMAL);
//Canvas canvas=buffer.enableGLCanvasRenderer();
//buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
//frame.add(canvas);

while (frame.isShowing()) {  
  float ms = clock.getTimeMicroseconds();
  clock.reset();
  dynamicWorld.stepSimulation(ms / 1000000f);
 
  box.rotateY(0.01f); // it's rotating because it looks neater :P
buffer.clear(java.awt.Color.BLUE);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
//buffer.displayGLOnly();
//canvas.repaint();
buffer.display(frame.getGraphics());
//Thread.sleep(10);
}
buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
buffer.dispose();
frame.dispose();
System.exit(0);
}


public void initTestObects(){
  Transform transform;
  Object3D boxgfx;
  BoxShape shape = new BoxShape(new Vector3f(2,2,2));
  JPCTBulletMotionState ms;
  float mass = 2;
  //MotionState ms;
  Vector3f localInertia = new Vector3f(0,0,0);
  shape.calculateLocalInertia(mass, localInertia);
  RigidBodyConstructionInfo rbInfo;
  RigidBody body;
 
  for(int i = 1; i < numBoxes; i++){
      boxgfx = Primitives.getCube(2);
    boxgfx.setTexture("box");
    boxgfx.setEnvmapped(Object3D.ENVMAP_ENABLED);
    boxgfx.build();
    world.addObject(boxgfx);
   
    transform = new Transform();
    transform.setIdentity();
    //transform.origin.set(0, strHeight+(i * 4),(float) (-(numBoxes / 3.3)) + i/2);
    transform.origin.set(0, strHeight+(i * 4),(float) -50 + i/3);
   
    //ms = new DefaultMotionState(transform);
    ms = new JPCTBulletMotionState(boxgfx, transform);
   
    rbInfo = new RigidBodyConstructionInfo(mass, ms, shape, localInertia);
    body = new RigidBody(rbInfo);
    body.setRestitution(0.1f);
    body.setFriction(0.50f);
    body.setDamping(0f, 0f);
   
    body.setUserPointer(boxgfx);
    boxList.add(body);
   
    dynamicWorld.addRigidBody(body);
  } // end for loop

}

}



Heres is the magic code. I must warn that this code is still in work of progress. There is a problem with the rotation. You will see the problem in execution.
Code: [Select]

package jpctbullet;

import javax.vecmath.Vector3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;


import com.threed.jpct.SimpleVector;
import com.threed.jpct.Object3D;
import com.threed.jpct.Matrix;

import com.bulletphysics.linearmath.MotionState;
import com.bulletphysics.linearmath.Transform;


public class JPCTBulletMotionState implements MotionState{
public final Transform graphicsWorldTrans = new Transform();
public final Transform centerOfMassOffset = new Transform();
public final Transform startWorldTrans = new Transform();

  private Object3D obj3d;
 
  public JPCTBulletMotionState(Object3D obj)
  {
    obj3d = obj;
graphicsWorldTrans.setIdentity();
centerOfMassOffset.setIdentity();
startWorldTrans.setIdentity();
  }
 
public JPCTBulletMotionState(Object3D obj, Transform startTrans)
  {
    obj3d = obj;
    this.graphicsWorldTrans.set(startTrans);
centerOfMassOffset.setIdentity();
this.startWorldTrans.set(startTrans);

 
public JPCTBulletMotionState(Object3D obj, Transform startTrans, Transform centerOfMassOffset)
  {
    obj3d = obj;
    this.graphicsWorldTrans.set(startTrans);
this.centerOfMassOffset.set(centerOfMassOffset);
this.startWorldTrans.set(startTrans);


  //public void getWorldTransform(Transform worldTrans){
  public Transform getWorldTransform(Transform worldTrans){
  //worldTrans.set(graphicsWorldTrans);
    //worldTrans.inverse(centerOfMassOffset);
    //worldTrans.set(centerOfMassOffset);
//worldTrans.mul(graphicsWorldTrans);
 
worldTrans.inverse(centerOfMassOffset);
worldTrans.mul(graphicsWorldTrans);

//Matrix4f matrix4 = new Matrix4f(obj3d.getRotationMatrix().getDump());
//matrix4.rotX((float)Math.PI);
//matrix4.getRotationScale(worldTrans.basis);// want to place matrix in argument
    return worldTrans;
  }
 
  public void setWorldTransform(Transform worldTrans)
  {
    SimpleVector pos = obj3d.getTransformedCenter();
   
    obj3d.translate(worldTrans.origin.x - pos.x,
  (-worldTrans.origin.y) - pos.y,
  (-worldTrans.origin.z) - pos.z);
   
   
   
    // following rotation may or maynot work. no working rotation to
    // find out and fix.
    float[] ma = new float[4];
    float[] dump = new float[16]; //obj3d.getRotationMatrix().getDump();
    Matrix4f matrix4 = new Matrix4f();
    Matrix matrixGfx = new Matrix();
   
    matrix4.set(worldTrans.basis); // want to set current matrix by arg
   
    matrix4.getRow(0, ma);
    dump[0] = ma[0]; dump[1] = ma[1]; dump[2] = ma[2]; dump[3] = ma[3];
    matrix4.getRow(1, ma);
    dump[4] = ma[0]; dump[5] = ma[1]; dump[6] = ma[2]; dump[7] = ma[3];
    matrix4.getRow(2, ma);
    dump[8] = ma[0]; dump[9] = ma[1]; dump[10] = ma[2]; dump[11] = ma[3];
    matrix4.getRow(3, ma);
    dump[12] = ma[0]; dump[13] = ma[1]; dump[14] = ma[2]; dump[15] = ma[3];
   
    /*
    Matrix3f matrix3 = worldTrans.basis;
    matrix3.normalize();
    matrix3.getRow(0, ma);
    dump[0] = ma[0]; dump[1] = ma[1]; dump[2] = ma[2];// dump[3] = ma[3];
    matrix3.getRow(1, ma);
    dump[4] = ma[0]; dump[5] = ma[1]; dump[6] = ma[2];// dump[7] = ma[3];
    matrix3.getRow(2, ma);
    dump[8] = ma[0]; dump[9] = ma[1]; dump[10] = ma[2];// dump[11] = ma[3];
    */
    matrixGfx.setDump(dump);
    matrixGfx.rotateX((float)Math.PI);
   
    obj3d.setRotationMatrix(matrixGfx);
  }

}



Here is the source. I have limited bandwidth so don't download to much please :) Also server sometimes goes down. So just be patient and it will be up. Usually less than a day.
http://sre.hopto.org/share/jBulletTest.zip



Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: jBullet, a simple how to guide
« Reply #1 on: January 18, 2010, 11:21:33 am »
This is cool. It would be a nice addition to the wiki: http://www.jpct.net/wiki/index.php/Physics

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #2 on: January 19, 2010, 12:52:40 am »
ok done. It's up on the Wiki. I hope people will enjoy and get some use out of it.

Sorry about the lateness of it. I was working on it some time ago. After overcomplicating the projects(I do that to often) I just walked away without leaving the physics part all that usable.

I'm really not sure how to fix the rotation issues. Some boxes graphical representation just don't match the physics bodies. I'm not sure how or where the matrix problems are ocuring. On running the demo one of the boxes that appears in the middle height and going to right shows it "rolling", but it's rolling on the wrong axis. I'm wondering if the jBullet is using Column major and not row major. I'm not going to bear my head about it right now to perfect it. It's a required fix, but I will probably get to it as my project progresses.


Offline raft

  • quad
  • ******
  • Posts: 1993
    • View Profile
    • http://www.aptalkarga.com
Re: jBullet, a simple how to guide
« Reply #3 on: January 19, 2010, 02:49:30 am »
very nice :)

i had some hard times too while porting Ardor3d's skeleton rotations. maybe the procedure i followed may help:
* i started ignoring coordinate system difference
* at first I involved jPCT only at final step: Ardor3d's demo and calculations were running and at final render stage just converted data to jPCT. (again with no transform)
* after i'm convinced i got the same result (only with a transformed coordinate system) i went backwards step by step, converting data to jPCT and making calculations with jPCT at each step
* at this point all calculations were done in jPCT and rendering is same as Ardor's but in a transformed coordinate system
* then finally i transformed the coordinate system

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #4 on: January 19, 2010, 04:28:03 am »
Well I got positioning down solid. Just rotation is a problem. Though I will try your suggestion of rotating the the object first before applying it JPCT.

What I really want to do is implement jBullet IDebugDraw. Though the problem is I use JPCT or other 3d api to avoid learning how to do 3d drawing. Implementing IDebugDraw is all about manually drawing the physics lines. What it does is send all the lines in 3d space, but requires the user to code it from there. That way I would be able to "see" where JPCT and jBullet are going wrong.
« Last Edit: January 19, 2010, 04:33:44 am by .jayderyu »

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #5 on: January 19, 2010, 08:09:19 am »
I tried raft suggestions to work with the "other" api first. Unfortunately anything I do in regards to rotation will blank out the matrix and have all graphical rotation cease. Seems that it's just best to get it out of the jBullet matrix asap.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: jBullet, a simple how to guide
« Reply #6 on: January 19, 2010, 05:04:59 pm »
Maybe the rotation problem comes from the fact, that the boxes created by Primitives are not axis aligned? They are rotated 45 degrees around y.

Code: [Select]
box.rotate((float) Math.PI/4f);
box.rotateMesh();
box.getRotationMatrix().setIdentity();

will axis-align a box. Maybe that's better? Or maybe you are already doing this? I've no idea, it's just a guess...
« Last Edit: January 19, 2010, 05:07:44 pm by EgonOlsen »

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #7 on: January 20, 2010, 04:37:35 am »
LOL, I went out shopping earlier today and it dawned on me that Primitive.get....  don't create axis aligned objects. I was going to muddle about and do a mesh rotation. In the end thank you Egon. I appreciate it. When I sit down I'm very positive that this will solve the problem. All the non aligned boxes seem to sit abotu 45deg off angle.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: jBullet, a simple how to guide
« Reply #8 on: January 20, 2010, 07:18:32 am »
I think i should add something about this in the docs or add methods that return axis aligned objects... ;)

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #9 on: January 20, 2010, 05:43:59 pm »
It works better. There are a few that seem off, but they look like they are next to other objects. Which might just leaning against it. I think it will consider the rotation problem solved unless something crops up during mesh rotation objects.

Thanks for the code Egon. I will wonder less about that problem.

I agree. It would be nice to know in that particular method of Primitive the object mesh rotation. I typicly have problems with planes after i leave them for a month or two :P

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #10 on: January 20, 2010, 06:47:28 pm »
Hi Egon

I was wondering is there a way to have a manual 3d point to point drawLine from JPCT camera/perspective. I was looking at jBullet IDebugDraw and some samples from other sources. It would be a nice bonus to get this working, but well as stated my 3d math skills is near zero. Since JPCT has a software renderer I figure it may have all the mathematical methods in place to have manual line drawing in 3d. It can draw in  wireframe after all?

I was looking at some sample implementations of btIDebugDraw from http://sio2interactive.forumotion.net/sio2-engine-f3/enabling-bullet-debug-draw-code-included-t599.htm , and Ogre3D sample of the same method. One was using direct openGL library functions and Ogre3D was using some form of DynamicLineDrawer which I'm making an assumption takes into account camera, fov, angle of perspective stuff. Then line points are added and I guess drawn part of the system.

Here are the methods I'm looking to eventually implement. The locations from what I can tell are in 3d space. So to sum up. I'm just wondering if there is 3d space line draw algorithm.

drawLine(Vector3f from, Vector3f to, Vector3f color)
drawAabb(Vector3f from, Vector3f to, Vector3f color)
drawTriangle(Vector3f v0, Vector3f v1, Vector3f v2, Vector3f color, float alpha)
drawTriangle(Vector3f v0, Vector3f v1, Vector3f v2, Vector3f n0, Vector3f n1, Vector3f n2, Vector3f color, float alpha)
drawContactPoint(Vector3f PointOnB, Vector3f normalOnB, float distance, int lifeTime, Vector3f color)
draw3dText(Vector3f location, String textString)

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: jBullet, a simple how to guide
« Reply #11 on: January 20, 2010, 10:22:29 pm »
Interact2D has some methods to project a SimpleVector from 3D to 2D (and back). That should help to get the required screen coordinates. However, jPCT doesn't expose any line drawing capability. With the software renderer, you can use plain Java2D for this, for the hardware renderer, you have to do it in OpenGL yourself.

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #12 on: January 21, 2010, 08:11:59 am »
ooohhhh, thank you. I think I've been looking for this

SimpleVector Interact2D.project3D2D(Camera camera, FrameBuffer buffer, SimpleVector vertex)

I'm going out on an assumption that this takes a 3d world vertex and gives 2d screen. that's what it says and that sounds like exactly what I was looking for. I tried looking in the various Renderes, but didn't find what I was looking for. If this works you can have a virtual hug :)

So I get a 2d reference in the return type. Then I draw on the FrameBuffer IIRC.

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #13 on: January 22, 2010, 04:56:01 am »
Hey Egon or any 3d guy :)

Alrighty then. So I've been working on IDebugDraw to some success and some bizarre failure. After some experiments I figure the next step to do is some trigonomtry or maybe cheap pretendy, but not real trig.

I am passed 2 Vector3f. They are similar to SimpleVector so no worries. They represent world coordinates, a vertex. Before I convert them over to screen. I need to rotate pointB around pointA along the ZY axis.

public void drawLine(Vector3f from, Vector3f to, Vector3f color)

My trig is lousy, but here was my thought in psuedo

Code: [Select]
vertex = to - from                  // i'm hoping that this will treat the new vertix around a point 0/0/0
vertex.y/z = -vertex.y/z                                //i'm reversing yz
To = vertex + from


The reason i'm doing this is because all the lines in the debugdrawing are well wrong. The (RGB)axis lines YZ are wrong.  Now I wouldn't mind them being just backwards. I can handle them just backwards. The problem arises that if a box rotates along the Y axis by  1.0. The graphical box goes one way, but the axis lines are going the other.

I'm sure if the wireframe on the debug drawing worked it would probably cause all sorts of mistaken rotation lines. But they are not so I might as well address the axis lines first.

Offline .jayderyu

  • long
  • ***
  • Posts: 116
    • View Profile
Re: jBullet, a simple how to guide
« Reply #14 on: January 22, 2010, 06:04:34 am »
Answer is ummm, maybe.

Seems to sorta work. but now I have to wonder if i'm still rotating Object3D wrong or i'm drawing the debug wrong.

edit:
Wheel A makes sense, but in the samples this may not be what's happeing.
Wheel B is what is happening visually. The box rotates one way, very smoothly for a box?
Wheel C is what i'm getting from the axis debug drawing. the box is flat and spinning along the z axis, but graphicly it looks more like B.

I can see C happening because I have very little friction. so a spinning box on the side while sliding in a direction makes sense. but it looks like the box is rotating in example B.

anyone have any thoughts. Yes the debug could be wrong, but the interaction along the axis seems to look more accurate that the graphical boxes. I have rotates the graphical box along the X to invert ZY.

edit:
finally got it. It was a piece of code I left in that I didn't need. It did something with the matrix before graphic processing. rotation issue seems sovled.

Though too note. ZY rotation axis is upside, but behaves correctly in regards to binding. I don't see this being a problem in implementation of the physics engine.
« Last Edit: January 22, 2010, 06:53:37 am by .jayderyu »