Hello everyone,
I’m currently working with the HelloWind.java example in jMonkeyEngine, and I’m facing an issue when using a GLTF export from Blender. The problem occurs whenmultiple objects with their respective soft bodies are created. It seems that all the objects are linked to the last soft body in the list.
I have the following code snippet in my implementation:
class SceneGraphVisitorImpl implements SceneGraphVisitor{
Mesh mesh;
@Override
public void visit(Spatial spatial) {
if(spatial instanceof Geometry) {
mesh = ((Geometry)spatial).getMesh();
}
}
public Mesh getMesh() {
return mesh;
}
}
public class Main
extends SimpleApplication
implements PhysicsTickListener {
// *************************************************************************
// constants
/**
* wind speed, in psu per second
*/
final private static float windSpeed = 3f;
// *************************************************************************
// fields
/**
* true when the left-arrow key is pressed, otherwise false
*/
private static volatile boolean turnLeft;
/**
* true when the right-arrow key is pressed, otherwise false
*/
private static volatile boolean turnRight;
/**
* wind direction (in radians from +X)
*/
private static float windAzimuth = -0.8f;
/**
* temporary storage for velocity vectors
*/
final private static Vector3f tmpVelocity = new Vector3f();
// *************************************************************************
// new methods exposed
List<PhysicsSoftBody> flagList = new ArrayList<PhysicsSoftBody>();
/**
* Main entry point for the HelloWind application.
*
* @param arguments array of command-line arguments (not null)
*/
public static void main(String[] arguments) {
Main application = new Main();
application.start();
}
// *************************************************************************
// SimpleApplication methods
private Mesh getMesh(Node node) {
SceneGraphVisitorImpl graphVisitorImpl = new SceneGraphVisitorImpl();
node.depthFirstTraversal(graphVisitorImpl);
return graphVisitorImpl.getMesh();
}
PhysicsSoftBody createflag(Vector3f location,Node flagModel) {
// Create a soft rectangle for the flag.
SoftBodyControl softBodyControl = new SoftBodyControl();
flagModel.addControl(softBodyControl);
PhysicsSoftBody flag = softBodyControl.getBody();
NativeSoftBodyUtil.appendFromTriMesh(getMesh(flagModel), flag);
flag.setMargin(0.1f);
flag.setMass(1f);
// Pin the left edge of the flag.
int nodeIndex = 0; // upper left corner
flag.setNodeMass(nodeIndex, PhysicsBody.massForStatic);
nodeIndex = 2; // lower left corner
flag.setNodeMass(nodeIndex, PhysicsBody.massForStatic);
/*
* Make the flag flexible by reducing the angular stiffness
* of its material.
*/
SoftBodyMaterial softMaterial = flag.getSoftMaterial();
softMaterial.setAngularStiffness(0f);
// Configure the flag's aerodynamics.
SoftBodyConfig config = flag.getSoftConfig();
config.setAerodynamics(Aero.F_TwoSidedLiftDrag);
config.set(Sbcp.Damping, 0.01f); // default = 0
config.set(Sbcp.Drag, 0.5f); // default = 0.2
config.set(Sbcp.Lift, 1f); // default = 0
/*
* Improve simulation accuracy by increasing
* the number of position-solver iterations for the flag.
*/
config.setPositionIterations(3);
Quaternion rotation
= new Quaternion().fromAngles(FastMath.HALF_PI, 0f, 0f);
flag.applyRotation(rotation);
flag.applyTranslation(location);
// Initialize the wind velocity.
tmpVelocity.x = windSpeed * FastMath.cos(windAzimuth);
tmpVelocity.z = windSpeed * FastMath.sin(windAzimuth);
flag.setWindVelocity(tmpVelocity);
flag.setDebugNumSides(2);
getStateManager().getState(SoftPhysicsAppState.class).getPhysicsSoftSpace().addCollisionObject(flag);
return flag;
}
/**
* Initialize the application.
*/
@Override
public void simpleInitApp() {
configureCamera();
configureInput();
//stateManager.attach(new VideoRecorderAppState());
// Set the viewport's background color to light blue.
ColorRGBA skyColor = ColorRGBA.Cyan;
viewPort.setBackgroundColor(skyColor);
// Set up Bullet physics (with debug enabled).
SoftPhysicsAppState bulletAppState = new SoftPhysicsAppState();
stateManager.attach(bulletAppState);
bulletAppState.setDebugEnabled(true); // for debug visualization
bulletAppState.setWindVelocityFilter(new FilterAll(true));
PhysicsSoftSpace physicsSpace = bulletAppState.getPhysicsSoftSpace();
physicsSpace.setAccuracy(0.01f); // 10-msec timestep
Vector3f gravityVector = new Vector3f(0f, -1f, 0f);
physicsSpace.setGravity(gravityVector);
// To enable the callbacks, register the application as a tick listener.
//physicsSpace.addTickListener(this);
// Generate a subdivided rectangle mesh with alternating diagonals.
// int xLines = 20;
// int zLines = 2 * xLines; // 2x as wide as it is tall
// float width = 2f;
// float lineSpacing = width / zLines;
// Mesh mesh = new ClothGrid(xLines, zLines, lineSpacing);
GltfModelKey modelKey = new GltfModelKey("/Models/flag.glb");
for(int i=0; i <5;i++) {
Node flagModel = (Node)getAssetManager().loadModel(modelKey);
flagModel.setLocalTranslation(new Vector3f(0,0,i * 4));
flagList.add(createflag(new Vector3f(i * 4,0,0),flagModel));
rootNode.attachChild(flagModel);
}
rootNode.addLight(new AmbientLight());
rootNode.addLight(new DirectionalLight(new Vector3f(0,0,-1)));
ModelKey Key = new ModelKey("/Models/Sky_Cloudy.j3o");
Node scene = (Node) getAssetManager().loadModel(Key);
LightProbe lightProbe = (LightProbe) scene.getLocalLightList().get(0);
lightProbe.setName("Default LightProbe");
lightProbe.setPosition(new Vector3f());
lightProbe.getArea().setRadius(1000);
getRootNode().addLight(lightProbe);
getRenderManager().setPreferredLightMode(LightMode.SinglePassAndImageBased);
flyCam.setMoveSpeed(20);
}