Converting a Mesh for jbullet (JME2 -> JME3)

Well I kinda trying to recreate the method that converts Trimeshes into The jbullet ones that falcon uses in his jbullet implimentation



If you see anything that can help making the code better readable it would be really appreciated, also if you see mistakes a correction would be nice.



orginal for jme2


        if(alreadyUsed(name)){
           return;
        }
      ///////////////////Stolen 1to1 from Falcons implementation/////////////////////////
      TriangleIndexVertexArray jBulletMeshData = new TriangleIndexVertexArray();
        IndexedMesh jBulletIndexedMesh = new IndexedMesh();
        jBulletIndexedMesh.triangleIndexBase = ByteBuffer.allocate( node.getTriangleCount() * 3 * 4 );
        jBulletIndexedMesh.vertexBase = ByteBuffer.allocate( node.getVertexCount() * 3 * 4 );
        IntBuffer indices = node.getIndexBuffer();
        indices.rewind();
        FloatBuffer vertices = node.getVertexBuffer();
        vertices.rewind();
        int verticesLength = node.getVertexCount() * 3;
        jBulletIndexedMesh.numVertices = verticesLength;
        jBulletIndexedMesh.vertexStride = 12; //3 verts * 4 bytes per.
        for ( int i = 0; i < verticesLength; i++ ) {
            float tempFloat = vertices.get();
            jBulletIndexedMesh.vertexBase.putFloat( tempFloat );
        }
        int indicesLength = node.getTriangleCount() * 3;
        jBulletIndexedMesh.numTriangles = node.getTriangleCount();
        jBulletIndexedMesh.triangleIndexStride = 12; //3 index entries * 4 bytes each.
        for ( int i = 0; i < indicesLength; i++ ) {
            jBulletIndexedMesh.triangleIndexBase.putInt( indices.get() );
        }
        jBulletMeshData.addIndexedMesh( jBulletIndexedMesh );
        ///////////////////Stolen 1to1 from Falcons implementation/////////////////////////
        BvhTriangleMeshShape shape = new BvhTriangleMeshShape(jBulletMeshData,true);
        Store(name,shape);



Well and now the ugly version from me for JME3


public static void AddToCache(String name,Mesh toconvert){
      if(cache.get(name) != null){
         throw new RuntimeException("Physiccache overload " + name);
      }
      //kinda based on falcons jme2 implementation
      TriangleIndexVertexArray jBulletMeshData = new TriangleIndexVertexArray();
        IndexedMesh jBulletIndexedMesh = new IndexedMesh();
        jBulletIndexedMesh.triangleIndexBase = ByteBuffer.allocate( toconvert.getTriangleCount() * 3 * 4 );
        jBulletIndexedMesh.vertexBase = ByteBuffer.allocate( toconvert.getVertexCount() * 3 * 4 );
        jBulletIndexedMesh.triangleIndexBase.rewind();
        jBulletIndexedMesh.vertexBase.rewind();
        int count = 0;
        Triangle tricache = new Triangle();
        while(count < toconvert.getTriangleCount()){
           toconvert.getTriangle(count, tricache);
           
           //Add the index to the indexbase
           int index = tricache.getIndex();
           byte[] data = new byte[4];
           // int -> byte[] O.o
           for (int i = 0; i < 4; ++i) {
              int shift = i << 3; // i * 8
              data[3-i] = (byte)((index & (0xff << shift)) >>> shift);
           }
           jBulletIndexedMesh.triangleIndexBase.put(data);
           
           //7and now the vectors :/
           int vecindex = 0;
           while(vecindex < 3){
              Vector3f vector = tricache.get(vecindex);
              int floatindex = 0;
              while(floatindex < 3){
                 int value = Float.floatToRawIntBits(vector.get(vecindex));
                    byte[] result = new byte[4];
                    for (int i = 0; i < 4; i++) {
                        int offset = (result.length - 1 - i) * 8;
                        result[i] = (byte) ((value >>> offset) & 0xff);
                    }
                    jBulletIndexedMesh.vertexBase.put(result);
              }
           }
           count++;
        }
        jBulletIndexedMesh.numTriangles = toconvert.getTriangleCount();
        jBulletIndexedMesh.triangleIndexStride = 12; //3 index entries * 4 bytes each.
        jBulletMeshData.addIndexedMesh( jBulletIndexedMesh );
        BvhTriangleMeshShape shape = new BvhTriangleMeshShape(jBulletMeshData,true);
        cache.put(name, shape);
   }



*ducks* (due to shitty code)

Well in most cases you can assume the position buffer is going to be in float and index buffer in short, however there is a helpful wrapper for indices (mesh.getIndexBuffer()) and also for accessing the floats there's mesh.getFloatBuffer(Type.Position). Retrieving it with triangle is probably the least efficient…

Theres a cleaned version of falkens conversion method in jbullet-jme (com/jmex/jbullet/Util/Converter.java). You can see how its done there. I looked into jme3s mesh and its not much different. Just as momoko says, use the index and vertex buffers. He recently did some android-related changes in the Mesh class but I from a quick look I think theres no problems arising from that. May I ask what you need this for? :smiley:

Well building Collision Shapes

Empire Phoenix said:

Well building Collision Shapes

orly?  :D

What did you expect? I need it for a primitive jbullet jme3 binding

Empire Phoenix said:

What did you expect? I need it for a primitive jbullet jme3 binding

Actually something like that. :P I have started a local version of jbullet-jme3, some errors still and no tests, but I can give you the Converter.java (conversion jme3->jbullet) from it:


/*
 * Copyright (c) 2005-2008 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jmex.jbullet.util;

import com.g3d.scene.IndexBuffer;
import com.g3d.scene.VertexBuffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;

/**
 * Nice convenience methods for conversion between javax.vecmath and com.g3d.math
 * Objects, also some jme to jbullet mesh conversion.
 * @author normenhansen
 */
public class Converter {

    private Converter() {
    }

    public static com.g3d.math.Vector3f convert( javax.vecmath.Vector3f oldVec ) {
        com.g3d.math.Vector3f newVec = new com.g3d.math.Vector3f();
        convert( oldVec, newVec );
        return newVec;
    }

    public static void convert( javax.vecmath.Vector3f oldVec, com.g3d.math.Vector3f newVec ) {
        newVec.x = oldVec.x;
        newVec.y = oldVec.y;
        newVec.z = oldVec.z;
    }

    public static javax.vecmath.Vector3f convert( com.g3d.math.Vector3f oldVec ) {
        javax.vecmath.Vector3f newVec = new javax.vecmath.Vector3f();
        convert( oldVec, newVec );
        return newVec;
    }

    public static void convert( com.g3d.math.Vector3f oldVec, javax.vecmath.Vector3f newVec ) {
        newVec.x = oldVec.x;
        newVec.y = oldVec.y;
        newVec.z = oldVec.z;
    }

    public static void convert( com.g3d.math.Quaternion oldQuat, javax.vecmath.Quat4f newQuat ) {
        newQuat.w = oldQuat.getW();
        newQuat.x = oldQuat.getX();
        newQuat.y = oldQuat.getY();
        newQuat.z = oldQuat.getZ();
    }

    public static javax.vecmath.Quat4f convert( com.g3d.math.Quaternion oldQuat ) {
        javax.vecmath.Quat4f newQuat = new javax.vecmath.Quat4f();
        convert( oldQuat, newQuat );
        return newQuat;
    }

    public static void convert( javax.vecmath.Quat4f oldQuat, com.g3d.math.Quaternion newQuat ) {
        newQuat.set(oldQuat.x, oldQuat.y, oldQuat.z, oldQuat.w);
    }

    public static com.g3d.math.Quaternion convert( javax.vecmath.Quat4f oldQuat ) {
        com.g3d.math.Quaternion newQuat = new com.g3d.math.Quaternion();
        convert( oldQuat, newQuat );
        return newQuat;
    }

    public static com.g3d.math.Matrix3f convert( javax.vecmath.Matrix3f oldMatrix ) {
        com.g3d.math.Matrix3f newMatrix = new com.g3d.math.Matrix3f();
        convert( oldMatrix, newMatrix );
        return newMatrix;
    }

    public static void convert( javax.vecmath.Matrix3f oldMatrix, com.g3d.math.Matrix3f newMatrix ) {
        newMatrix.set(0,0, oldMatrix.m00);
        newMatrix.set(0,1, oldMatrix.m01);
        newMatrix.set(0,2, oldMatrix.m02);
        newMatrix.set(1,0, oldMatrix.m10);
        newMatrix.set(1,1, oldMatrix.m11);
        newMatrix.set(1,2, oldMatrix.m12);
        newMatrix.set(2,0, oldMatrix.m20);
        newMatrix.set(2,1, oldMatrix.m21);
        newMatrix.set(2,2, oldMatrix.m22);
    }

    public static javax.vecmath.Matrix3f convert( com.g3d.math.Matrix3f oldMatrix ) {
        javax.vecmath.Matrix3f newMatrix = new javax.vecmath.Matrix3f();
        convert( oldMatrix, newMatrix );
        return newMatrix;
    }

    public static void convert( com.g3d.math.Matrix3f oldMatrix, javax.vecmath.Matrix3f newMatrix ) {
        newMatrix.m00 = oldMatrix.get(0,0);
        newMatrix.m01 = oldMatrix.get(0,1);
        newMatrix.m02 = oldMatrix.get(0,2);
        newMatrix.m10 = oldMatrix.get(1,0);
        newMatrix.m11 = oldMatrix.get(1,1);
        newMatrix.m12 = oldMatrix.get(1,2);
        newMatrix.m20 = oldMatrix.get(2,0);
        newMatrix.m21 = oldMatrix.get(2,1);
        newMatrix.m22 = oldMatrix.get(2,2);
    }

    public static com.bulletphysics.collision.shapes.TriangleIndexVertexArray convert( com.g3d.scene.Mesh mesh ) {
        com.bulletphysics.collision.shapes.TriangleIndexVertexArray jBulletMeshData
                = new com.bulletphysics.collision.shapes.TriangleIndexVertexArray();

        com.bulletphysics.collision.shapes.IndexedMesh jBulletIndexedMesh
                = new com.bulletphysics.collision.shapes.IndexedMesh();
        jBulletIndexedMesh.triangleIndexBase = ByteBuffer.allocate( mesh.getTriangleCount() * 3 * 4 );
        jBulletIndexedMesh.vertexBase = ByteBuffer.allocate( mesh.getVertexCount() * 3 * 4 );

        IndexBuffer indices = mesh.getIndexBuffer();
//        indices.rewind();

        FloatBuffer vertices = mesh.getFloatBuffer(VertexBuffer.Type.Position);
        vertices.rewind();

        int verticesLength = mesh.getVertexCount() * 3;
        jBulletIndexedMesh.numVertices = verticesLength;
        jBulletIndexedMesh.vertexStride = 12; //3 verts * 4 bytes per.
        for ( int i = 0; i < verticesLength; i++ ) {
            float tempFloat = vertices.get();
            jBulletIndexedMesh.vertexBase.putFloat( tempFloat );
        }

        int indicesLength = mesh.getTriangleCount() * 3;
        jBulletIndexedMesh.numTriangles = mesh.getTriangleCount();
        jBulletIndexedMesh.triangleIndexStride = 12; //3 index entries * 4 bytes each.
        for ( int i = 0; i < indicesLength; i++ ) {
            jBulletIndexedMesh.triangleIndexBase.putInt( indices.get(i) );
        }

        jBulletMeshData.addIndexedMesh( jBulletIndexedMesh );

        return jBulletMeshData;
    }
}



Dont know if the mesh conversion works, I just hacked it in..

Should work fine I think. Just a note though, Android doesn't use floating point position buffers, but it probably won't run the java-jbullet anyway…

well not my target group anyway^^ so I wont care.

Thanks for sharing that code,w ill certainly help me.

Momoko_Fan said:

Should work fine I think. Just a note though, Android doesn't use floating point position buffers, but it probably won't run the java-jbullet anyway..

Did not dig into that yet, but I think you might be right. Maybe the native version is a way to go here? Or is Android completely "C++less"?

@EmpirePhoenix you're welcome :)
normen said:

Did not dig into that yet, but I think you might be right. Maybe the native version is a way to go here? Or is Android completely "C++less"?

@EmpirePhoenix you're welcome :)

You gotta compile native bullet for ARM architecture, and distribute the .so file in the APK. That's how people compile their C++ code for Android. They create a java front-end essentially, then bind into the native library and execute it. So is it possible? Yes it is, but considering that Quake2 barely runs on android, I wouldn't bother with a full-blown physics engine.  ;)
Momoko_Fan said:

normen said:

Did not dig into that yet, but I think you might be right. Maybe the native version is a way to go here? Or is Android completely "C++less"?

@EmpirePhoenix you're welcome :)

You gotta compile native bullet for ARM architecture, and distribute the .so file in the APK. That's how people compile their C++ code for Android. They create a java front-end essentially, then bind into the native library and execute it. So is it possible? Yes it is, but considering that Quake2 barely runs on android, I wouldn't bother with a full-blown physics engine.  ;)
Yep. Rather place your bets on Jinngine for more lightweight, Android-friendly Java physics :)
Momoko_Fan said:

So is it possible? Yes it is, but considering that Quake2 barely runs on android, I wouldn't bother with a full-blown physics engine.  ;)

Lol, yea, you're probably right, maybe it should be something even more simple than jinngine.. :)

a java 2d engine maybee as real 3d games ar rare and more 2.5d games on handys exist (Maybee cause a lack of moues makes sterrig shooters kinda shitty)?

Yeah I don't think anyone will need actual 3D physics. And Box2D (or Phys2D?) was ported on the native side of android, so it can be used from there if you want to write 2D games with physics.