So, I have been noticing a very strange problem with the DLOD objects, basically I have created several DLOD spheres and when any sphere is outside the frustum and moves back into view on it's own the object is ALWAYS culled. Turning on the physics reveals, that yes the object is there and interacting with the other objects (the physics wireframe is always visible). However the textured sphere itself is culled.
These spheres are all created and then added to a single node then added to the rootNode. Is this an incorrect approach
/*
import com.jme.bounding.BoundingSphere;
import com.jme.image.Texture;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.DistanceSwitchModel;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.lod.DiscreteLodNode;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.callback.FrictionCallback;
import com.jmex.physics.contact.MutableContactInfo;
import com.jmex.physics.material.Material;
public class Balls {
Node ballsNode = null;
Ball balls[] = null;
Material ballMaterial = null;
MutableContactInfo ballContactDetails = null;
Jme_Driver jme_Driver = null;
protected Balls( Jme_Driver parent ) {
jme_Driver = parent;
}
protected void createBalls() {
ballsNode = new Node();
int numBalls = jme_Driver.getDriver().getNumberOfBalls();
setMaterial();
balls = new Ball[ numBalls ];
for ( int i=0; i < numBalls; ++i ) {
balls[i] = new Ball( i );
ballsNode.attachChild( balls[i].getBall() );
}
rackEm();
}
protected Node getBalls() {
return ballsNode;
}
protected void rackEm() {
Vector3f position = new Vector3f();
float [] ballPosition;
for ( int i=0; i < balls.length; ++i ) {
ballPosition = jme_Driver.getDriver().getLogic().getInitPosition( i );
position.x = ballPosition[0];
position.z = ballPosition[1];
balls[i].setLocation( position );
}
}
protected Vector3f getLocation( int ballNumber ) {
return balls[0].getLocation();
}
protected Material getMaterial() {
return ballMaterial;
}
protected MutableContactInfo getContactDetails() {
return ballContactDetails;
}
private void setMaterial() {
ballMaterial = new Material( "Ball Material" );
ballMaterial.setDensity( 1.25f );
ballMaterial.setSpringPenetrationDepth( 0 );
ballContactDetails = new MutableContactInfo();
ballContactDetails.setBounce( 0.35f );
ballContactDetails.setMu( 0.15f );
ballContactDetails.setSpringConstant( 0.01f );
ballContactDetails.setDampingCoefficient( 10000 );
ballContactDetails.setMinimumBounceVelocity( 0.01f );
}
private class Ball {
private String ballName = "";
private DynamicPhysicsNode physicsBall = null;
private Ball( int number ) {
ballName = "ball_" + number;
DiscreteLodNode dlod = buildBall();
textureBall( dlod, number );
Utils.color( dlod, ColorRGBA.white, 128 );
dlod.setLocalRotation( new Quaternion().fromAngleAxis(
-90 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X ) );
physicsBall = jme_Driver.getPhysics().createDynamicNode();
physicsBall.setName( "Physics_" + ballName );
physicsBall.attachChild( dlod );
physicsBall.setMaterial( ballMaterial );
physicsBall.generatePhysicsGeometry();
physicsBall.setMass( Globals.ballMass );
FrictionCallback callback = new FrictionCallback();
callback.add( physicsBall, 0.15f, 0.15f );
jme_Driver.getPhysics().addToUpdateCallbacks(callback);
physicsBall.lockMeshes();
}
private DynamicPhysicsNode getBall() {
return physicsBall;
}
private void setLocation( Vector3f location ) {
physicsBall.getLocalTranslation().set( location );
}
private Vector3f getLocation() {
return physicsBall.getLocalTranslation();
}
private void shootBall() {
physicsBall.addForce( new Vector3f( 0, 0, 400000 ) );
}
private DiscreteLodNode buildBall() {
Sphere s1 = new Sphere( ballName, 50, 50, Globals.ballSize );
s1.setModelBound(new BoundingSphere() );
s1.updateModelBound();
s1.setTextureMode( Sphere.TEX_PROJECTED );
// s1.setVBOInfo(new VBOInfo(true));
Sphere s2 = new Sphere( ballName, 25, 25, Globals.ballSize );
s2.setModelBound(new BoundingSphere() );
s2.updateModelBound();
s2.setTextureMode( Sphere.TEX_PROJECTED );
// s2.setVBOInfo(new VBOInfo(true));
Sphere s3 = new Sphere( ballName, 12, 12, Globals.ballSize );
s3.setModelBound(new BoundingSphere() );
s3.updateModelBound();
s3.setTextureMode( Sphere.TEX_PROJECTED );
// s3.setVBOInfo(new VBOInfo(true));
Sphere s4 = new Sphere( ballName, 6, 6, Globals.ballSize );
s4.setModelBound(new BoundingSphere() );
s4.updateModelBound();
s4.setTextureMode( Sphere.TEX_PROJECTED );
// s4.setVBOInfo(new VBOInfo(true));
DistanceSwitchModel m = new DistanceSwitchModel(4);
m.setModelDistance( 0, 0, 50 );
m.setModelDistance( 1, 50, 200);
m.setModelDistance( 2, 200, 500);
m.setModelDistance( 3, 500, 10000 );
DiscreteLodNode dlod = new DiscreteLodNode("DLOD", m);
dlod.attachChild(s1);
dlod.attachChild(s2);
dlod.attachChild(s3);
dlod.attachChild(s4);
dlod.setActiveChild(0);
return dlod;
}
protected void textureBall( Spatial spatial, int ballNumber ) {
DisplaySystem display = DisplaySystem.getDisplaySystem();
TextureState textureState = display.getRenderer().createTextureState();
Texture texture = TextureManager.loadTexture(
getClass().getResource( "/Images/Ball_Textures/ball_" + ballNumber + ".png" ),
Texture.MM_LINEAR_LINEAR,
Texture.FM_LINEAR );
textureState.setTexture( texture );
textureState.getTexture().setScale( new Vector3f( 2, 1, 1 ) );
textureState.getTexture().setWrap( Texture.WM_WRAP_S_CLAMP_T );
spatial.setRenderState(textureState);
}
}
}
Here is the simpleInitGame code that loads the balls.
@Override
protected void simpleInitGame() {
DisplaySystem display = DisplaySystem.getDisplaySystem();
table.buildTable();
balls.createBalls();
// attach everything to the root node
rootNode.attachChild( balls.getBalls() );
rootNode.attachChild( table.getTable() );
rootNode.updateGeometricState( 0, true );
rootNode.updateRenderState();
// Set our keys
input.addAction( new InputAction() {
public void performAction( InputActionEvent evt ) {
if ( evt.getTriggerPressed() ) {
balls.shootBall( "Ball" );
}
}
}, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_SPACE, InputHandler.AXIS_NONE, false );
Text label = Text.createDefaultTextLabel( "instructions", "Press [space] to spawn a ball" );
label.setLocalTranslation( 0, 20, 0 );
fpsNode.attachChild( label );
}
When a single sphere is substituted for the DLOD ones, the problem completly vanishes and the sphere is always visible when it should be.
If this is unclear and someone would like me to make a demonstration I would be glad to.