Problem with bone weight

I try to write an importer for half life’s (Counter Strike) SMD-format.

It actually works to load a model and the skeleton is also loaded correctly. My problem for now is, though I set the bone-weight buffer of the mesh with a FloatBuffer, a test-program throws this exception I have no use for:

[java]15.03.2011 16:07:09 com.jme3.app.Application handleError

SCHWERWIEGEND: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.UnsupportedOperationException

at java.nio.FloatBuffer.array(FloatBuffer.java:957)

at com.jme3.animation.AnimControl.softwareSkinUpdate(AnimControl.java:424)

at com.jme3.animation.AnimControl.controlUpdate(AnimControl.java:395)

at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:93)

at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:504)

at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:621)

at com.jme3.scene.Node.updateLogicalState(Node.java:151)

at com.jme3.scene.Node.updateLogicalState(Node.java:154)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:242)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:158)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:203)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:221)

at java.lang.Thread.run(Thread.java:636)[/java]

But FloatBuffer does support the method array() and I also create the buffer from a float-array.

Thanks in advance,

doe300

No this error does not mean loatBuffer does support the method array(), it means that something done in java.nioFloatBuffer is not supported.



how do you build your FloatBuffer?

per

[java]mesh.setBuffer(Type.BoneWeight, 1,BufferUtils.createFloatBuffer(float[]));[/java]

Maybe you can follow the same steps this guy used:

http://hub.jmonkeyengine.org/groups/user-code-projects/forum/topic/tactical-turn-basedreal-time-game-attempt/#post-117247

I think there must be a bug (or at least some troubling code) somewhere in the system, because the following code also gives the same exception:

[java]public static void main(final String[] args)

{

FloatBuffer fb = BufferUtils.createFloatBuffer(randomData());

System.out.println(fb);//this still works

System.err.println(fb.arrayOffset());//here is an UnsupportedOperationException

System.err.println(fb.hasArray());//if we comment the previous line, this here returns ‘false’ …

System.out.println(fb.array());// … and this throws the UnsupportedOperationException

}

//generate some random floats

static float[] randomData( )

{

final int num = (int) (Math.random() * 1000.0);

final float[] data = new float[num];

for (int i = 0; i < num; i++)

{

data = (float) Math.random();

}

return data;

}

[/java]



I think this is either not a jme3 problem, but one of openjdk, or this problem lies in the few lines of code in BufferUtils.

Does this code work for somebody on other machines??

mhh…I think there is an issue yeah, i have the same exception

this work though



float[] f=randomData();

FloatBuffer fb = FloatBuffer.allocate(f.length);

fb.clear();

fb.put(f);

fb.flip();





for more info for assigning bone weight look at the ogre mesh loader

http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java#329

Thanks for the help.

yeah my bone weights actually don’t work properly yet, I currently only set the weight of the (source) bone to 1.

The problem continues…

Now if I try your solution, the program wants to have a direct FloatBuffer:

[java]SCHWERWIEGEND: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.IllegalArgumentException: FloatBuffer is not direct

at org.lwjgl.BufferChecks.checkDirect(BufferChecks.java:139)

at org.lwjgl.opengl.GL15.glBufferData(GL15.java:155)

at com.jme3.renderer.lwjgl.LwjglRenderer.updateBufferData(LwjglRenderer.java:1791)

at com.jme3.renderer.lwjgl.LwjglRenderer.setVertexAttrib(LwjglRenderer.java:1894)

at com.jme3.renderer.lwjgl.LwjglRenderer.setVertexAttrib(LwjglRenderer.java:1949)

at com.jme3.renderer.lwjgl.LwjglRenderer.renderMeshDefault(LwjglRenderer.java:2150)

at com.jme3.renderer.lwjgl.LwjglRenderer.renderMesh(LwjglRenderer.java:2183)

at com.jme3.material.Material.render(Material.java:863)

at com.jme3.renderer.RenderManager.renderGeometry(RenderManager.java:434)

at com.jme3.renderer.queue.RenderQueue.renderGeometryList(RenderQueue.java:132)

at com.jme3.renderer.queue.RenderQueue.renderQueue(RenderQueue.java:183)

at com.jme3.renderer.RenderManager.renderViewPortQueues(RenderManager.java:575)

at com.jme3.renderer.RenderManager.flushQueue(RenderManager.java:555)

at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:721)

at com.jme3.renderer.RenderManager.render(RenderManager.java:742)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:249)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:158)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:203)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:221)

at java.lang.Thread.run(Thread.java:636)[/java]

Ok, I create now a FloatBuffer via

[java]ByteBuffer.allocateDirect(weights.length*4).asFloatBuffer();[/java]

and it shows up the UnsupportedOperationException again :frowning:

Did you look at how it’s done in the MeshLoader?

Look at the startBoneAssign and endBoneAssign method

In MeshLoader:

[java]

//HARDWARE_SKINNING is always ‘false’, so the else-part is executed

if (HARDWARE_SKINNING){

weightsFloatData = BufferUtils.createFloatBuffer(vertCount * 4);

indicesData = BufferUtils.createByteBuffer(vertCount * 4);

}else{

// create array-backed buffers if software skinning for access speed

weightsFloatData = FloatBuffer.allocate(vertCount * 4);

indicesData = ByteBuffer.allocate(vertCount * 4);

}

//here a new VertexBuffer is created from the FloatBuffer

VertexBuffer weights = new VertexBuffer(Type.BoneWeight);

VertexBuffer indices = new VertexBuffer(Type.BoneIndex);



Usage usage = HARDWARE_SKINNING ? Usage.Static : Usage.CpuOnly;

//the VertexBuffer is set

weights.setupData(usage, 4, Format.Float, weightsFloatData);

indices.setupData(usage, 4, Format.UnsignedByte, indicesData);



mesh.setBuffer(weights);

mesh.setBuffer(indices);[/java]

So the real interesting code would be:

[java]VertexBuffer weights = new VertexBuffer(Type.BoneWeight);

weights.setupData(Usage.CpuOnly, 4, Format.Float, FloatBuffer.allocate(vertCount * 4));

[/java]

…plus adding some content of course. but I tried this too, and than it throws a “IllegalArgumentException: ByteBuffer is not direct”

:?

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes

I know it, I also read it.

My problem is not the Mesh (it works fine), but the boneWeight for the AnimControl. And I don’t know how to create a FloatBuffer, based upon an array and being direct.

And if you iterate over your array and set values to the FloatBuffer like it’s done in the endBoneAssign

yeah but there shouldn’t be any difference between setting all data via put(float[]) and setting single values via put(float).

Yes there is, this is native buffers, you have to use the buffer factory to create them.

Notice the usage is set to “CpuOnly” … That means the buffers will not be used as vertex shader attributes but are expected to be used CPU-side only

Thanks for your tips,

I will brood some more time over this problem and ask again if I have some other questions. :slight_smile: (They sure will come)