Lesson 3 expanding causes NPE in Material.getContentHandlingDetails()

Hello all,



I just started playing with jME and Physics 2 so chances are Im doing something fundamentally wrong.  I took the Lesson 3 which had 4 cubes of different materials and enclosed them into a crude area so I could watch them bounce around more. I also added a rubber sphere as well.  When the sphere hits the red block from Lesson 3 I get a NPE comming out of Material.


     [java] java.lang.NullPointerException
     [java]     at com.jmex.physics.material.Material.getContactHandlingDetails(Material.java:318)
     [java]     at com.jmex.physics.material.MaterialContactCallback.adjustContact(MaterialContactCa
llback.java:67)
     [java]     at com.jmex.physics.PhysicsSpace.adjustContact(PhysicsSpace.java:125)
     [java]     at com.jmex.physics.impl.ode.OdePhysicsSpace.iterateContacts(OdePhysicsSpace.java:82
9)
     [java]     at com.jmex.physics.impl.ode.OdePhysicsSpace.computeTimeStep(OdePhysicsSpace.java:75
6)
     [java]     at com.jmex.physics.impl.ode.OdePhysicsSpace.update(OdePhysicsSpace.java:589)
     [java]     at com.jmex.physics.util.SimplePhysicsGame.update(SimplePhysicsGame.java:141)
     [java]     at com.jme.app.BaseGame.start(Unknown Source)



The code is as follows:

package client;

import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.MaterialState;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.StaticPhysicsNode;
import com.jmex.physics.contact.MutableContactInfo;
import com.jmex.physics.material.Material;
import com.jmex.physics.util.SimplePhysicsGame;

/**
 * Learn about physics materials, friction, bounciness etc.
 *
 * @author Irrisor
 */
public class FrontEndGui extends SimplePhysicsGame {

    protected void simpleInitGame() {

      //root static object node
      StaticPhysicsNode staticNode = getPhysicsSpace().createStaticNode();
      rootNode.attachChild( staticNode );

      // first we will create the floor
      final Box visualFloorBox = new Box( "floor", new Vector3f(), 5, 0.25f, 10 );
      //tilt it a bit
      visualFloorBox.getLocalRotation().fromAngleNormalAxis( 0.3f, new Vector3f( 0, 0, -1 ) );
      staticNode.attachChild( visualFloorBox );

      // and create another part below
      final Box visualFloorBox2 = new Box( "floor", new Vector3f(), 5, 0.25f, 10 );
      visualFloorBox2.getLocalTranslation().set( 9.7f, -1.5f, 0 );
      staticNode.attachChild( visualFloorBox2 );

      //another part
      final Box visualFloorBox3 = new Box("floor", new Vector3f(),5,0.25f,10);
      visualFloorBox3.getLocalRotation().fromAngleNormalAxis(0.3f,new Vector3f(0,0,1));
      visualFloorBox3.getLocalTranslation().set( 19.4f, 0, 0 );
      staticNode.attachChild( visualFloorBox3 );

      //wall 1
      final Box visualWall1 = new Box("wall", new Vector3f(),15f,6,0.25f);
      visualWall1.getLocalTranslation().set(10f,0,-10);
      staticNode.attachChild(visualWall1);

      //wall 2
      final Box visualWall2 = new Box("wall", new Vector3f(),15f,6,0.25f);
      visualWall2.getLocalTranslation().set(10f,0,10);
      staticNode.attachChild(visualWall2);

      //wall 3
      final Box visualWall3 = new Box("wall", new Vector3f(),0.25f,2.5f,10);
      visualWall3.getLocalTranslation().set(-5f,3,0);
      staticNode.attachChild(visualWall3);

      //wall 4
      final Box visualWall4 = new Box("wall", new Vector3f(),0.25f,2.5f,10);
      visualWall4.getLocalTranslation().set(24f,3,0);
      staticNode.attachChild(visualWall4);

      //create the physics for the current static node
      staticNode.generatePhysicsGeometry();

      cam.setLocation(new Vector3f(0,10,10));
      cam.lookAt(new Vector3f(10,0,0),new Vector3f(0,1,0));


      // second we create a box - as we create multiple boxes this time the code moved into a separate method
      DynamicPhysicsNode dynamicNode = createBox();
      dynamicNode.computeMass();
      // the first box gets in the center above the floor
      dynamicNode.getLocalTranslation().set( 0, 5, 0 );
      // this box keeps the default material

      // ok first we will explore some predefined materials
      // lets create an ice block...
      final DynamicPhysicsNode iceQube = createBox();
      iceQube.setMaterial( Material.ICE );
      // changing material means changing desity
      // you may choose to compute the mass from the volume and density of an object
      iceQube.computeMass();
      // color the visual representation in transparent blue
      color( iceQube, new ColorRGBA( 0.5f, 0.5f, 0.9f, 0.6f ) );
      // move the iceQube besides the first box
      iceQube.getLocalTranslation().set( 0, 5, 1.5f );

      // ... a rubber ...
      final DynamicPhysicsNode rubber = createBox();
      rubber.setMaterial( Material.RUBBER );
      rubber.computeMass();
      // color the visual representation in yellow
      color( rubber, new ColorRGBA( 0.9f, 0.9f, 0.3f, 1 ) );
      // move the rubber on the other side of the first box
      rubber.getLocalTranslation().set( 0, 5, -1.5f );

      // finally we define a custom material
      final Material customMaterial = new Material( "supra-stopper" );
      // we make it really light
      customMaterial.setDensity( 0.05f );
      // a material should define contact detail pairs for each other material it could collide with in the scene
      // do that just for the floor material - the DEFAULT material
      MutableContactInfo contactDetails = new MutableContactInfo();
      // our material should not bounce on DEFAULT
      contactDetails.setBounce( 0 );
      // and should never slide on DEFAULT
      contactDetails.setMu( 1000 ); // todo: Float.POSITIVE_INFINITY seems to cause issues on Linux (only o_O)
      // now set that behaviour
      customMaterial.putContactHandlingDetails( Material.DEFAULT, contactDetails );

      // ... finally test our supra-stopper with a red cube
      final DynamicPhysicsNode stopper = createBox();
      stopper.setMaterial( customMaterial );
      // don't forget to compute mass from density
      stopper.computeMass();
      // color the visual representation in yellow
      color( stopper, new ColorRGBA( 1, 0, 0, 1 ) );
      // move the stopper to the front
      stopper.getLocalTranslation().set( 0, 5, 3 );

      DynamicPhysicsNode ball1 = createBall();
      ball1.getLocalTranslation().set(20,10,1);
      ball1.setMaterial(Material.RUBBER);
      ball1.computeMass();
      color(ball1,new ColorRGBA( 0.9f, 0.9f, 0.3f, 0.6f ));


      // start paused - press P to start the action :)
      pause = true;
    }

    /**
     * Little helper method to color a spatial.
     *
     * @param spatial the spatial to be colored
     * @param color   desired color
     */
    private void color( Spatial spatial, ColorRGBA color ) {
   final MaterialState materialState = display.getRenderer().createMaterialState();
   materialState.setDiffuse( color );
   if ( color.a < 1 ) {
       final AlphaState alphaState = display.getRenderer().createAlphaState();
       alphaState.setEnabled( true );
       alphaState.setBlendEnabled( true );
       alphaState.setSrcFunction( AlphaState.SB_SRC_ALPHA );
       alphaState.setDstFunction( AlphaState.DB_ONE_MINUS_SRC_ALPHA );
       spatial.setRenderState( alphaState );
       spatial.setRenderQueueMode( Renderer.QUEUE_TRANSPARENT );
   }
   spatial.setRenderState( materialState );
    }

    /**
     * Create a box like known from Lesson2.
     *
     * @return a physics node containing a box
     */
    private DynamicPhysicsNode createBox() {
      DynamicPhysicsNode dynamicNode = getPhysicsSpace().createDynamicNode();
      rootNode.attachChild( dynamicNode );
      final Box visualFallingBox = new Box( "falling box", new Vector3f(), 0.5f, 0.5f, 0.5f );
      dynamicNode.attachChild( visualFallingBox );
      dynamicNode.generatePhysicsGeometry();
      return dynamicNode;
    }

    private DynamicPhysicsNode createBall() {
      DynamicPhysicsNode dynamicNode = getPhysicsSpace().createDynamicNode();
      rootNode.attachChild( dynamicNode );
      final Sphere visualFallingSphere = new Sphere( "falling sphere", 10, 10, 1.0f);
      dynamicNode.attachChild( visualFallingSphere );
      dynamicNode.generatePhysicsGeometry();
      return dynamicNode;
    }

    /**
     * The main method to allow starting this class as application.
     *
     * @param args command line arguments
     */
    public static void main( String[] args ) {
   Logger.getLogger( "" ).setLevel( Level.WARNING ); // to see the important stuff
   new FrontEndGui().start();
    }
}



Any help would be appreciated.  I was looking in the Material class and the error is here:

            if ( details == null && contactMaterial != null ) {
                // use default contact details
                details = contactDetails.get( null );
                if ( details.isIgnored() ||    // <---### error line, did the above line not work?
                        !details.isApplied() ) {
                    return details;
                }

The exception should not be thrown. I've fixed that in jME Physics.



From a short glance at your code it seems everything is fine.

Thanks for the reply :slight_smile:



Do I not have the current code from cvs?  I stopped using the red box for now but I see myself making custom materials very soon.  Material.java was made 9/22/07 if that helps any.

I meant: I changed the cvs version after reading about the problem in your post :slight_smile: - so you probably had the current code :wink: