@author Arjen
*/
public final class BuoyancyControl extends RigidBodyControl implements PhysicsTickListener, PhysicsControl
{
ShipTest myShip;
Node myHull;
float myScale;
float myMass;
float myDraft;
int qtyCP = 20; // Number of contol points to be used alongside the entire hull (half of them on startboard side , half of them on part side)
Vector3f[] vecControlPoint = new Vector3f[qtyCP]; // Position of control point relative to the ship.
Vector3f[] vecControlPointCalc = new Vector3f[qtyCP]; // Position of control point in world coordinates (for applying forces).
Quaternion shipQuat = new Quaternion(Quaternion.ZERO);
Vector3f shipPos = new Vector3f();
float[] waveHeight = new float[qtyCP];
float[] cpHeight = new float[qtyCP];
// Strength of the wave at every cross-section of the ship (displacement). Still hard-coded, but should be calculated in the future:
float[] waveStrength = {0.03f, 0.03f, 0.04f, 0.05f, 0.1f, 0.1f, 0.07f, 0.04f, 0.03f, 0.01f, 0.01f, 0.03f, 0.04f, 0.07f, 0.1f, 0.1f, 0.05f, 0.04f, 0.03f, 0.03f};
Vector3f waterImpulseForce = new Vector3f(), waterImpulseLocation = new Vector3f();
float waveForce; // Force applied to follow waves.
/**
Adds an empty BuoyancyControl.
*/
public BuoyancyControl()
{
}
/**
Adds a BuoyancyControl to the ship object.
@param ship The ship class object in which the ship is assembled.
@param hull Node which holds the hull of the ship in the Ship class.
@param scale Scale as set in the Ship class.
@param mass Float holding the ships mass.
@param draft Float holding the ships draft (distance from waterline to the bottom of the keel).
for (int i = 0; i<qtyCP; i++)
{
vecControlPoint[i] = new Vector3f(Vector3f.ZERO);
}
createControlPoints();
}
@Override
public void setPhysicsSpace(PhysicsSpace space)
{
super.setPhysicsSpace(space);
if (space != null)
{
space.addTickListener(this);
}
}
public void prePhysicsTick(PhysicsSpace space, float tpf)
{
checkWavePos();
}
public void physicsTick(PhysicsSpace space, float tpf)
{
followWave(tpf);
}
@Override
public void update(float tpf)
{
super.update(tpf);
}
/**
Here we are creating the positions of the control points which we use to calculate the depth of the hull in relation to the water.
*/
public void createControlPoints()
{
float myLength = ((BoundingBox)myHull.getWorldBound()).getXExtent() / myScale; // Lenght of the hull (half of its lenght).
float xCoor; // X-coordinate for the control point
float zCoor; // Z-coordinate for the control point
for (int i=0; i 0)
{
zCoor = results.getCollision(0).getDistance()/myScale; // Define the Z-coordinate for this cross-section.
}
else
{
zCoor = 0f; // To prevent ‘out of bound array error’ when there is no collision (especially at stern and bow, because mostly the waterline is shorter then the overal lenght of the hull).
}
vecControlPoint[i].set(xCoor, 0f, zCoor); // Set the coordinates for the given control point on starboard side.
vecControlPoint[i+qtyCP/2].set(xCoor, 0f, -zCoor); // Set the coordinates for the given control point on port side.
vecControlPointCalc[i] = new Vector3f(xCoor, 0f, zCoor); // Set the coordinates for the given calculated control point on starboard side.
vecControlPointCalc[i+qtyCP/2] = new Vector3f(xCoor, 0f, -zCoor); // Set the coordinates for the given calculated control point on port side.
}
for (int i=0; i<qtyCP; i++)
{
waveHeight[i] = 0f; // Fill/create the wave height values.
cpHeight[i] = 0f; // Fill/create the control point height values.
}
}
/**
Check the height of the waves for each control point location.
*/
public void checkWavePos()
{
shipQuat.set(this.getPhysicsRotation()); // Store the physic body's rotation.
shipPos.set(this.getPhysicsLocation()); // Store the physic body's location
// For every control point, calculate the world location, then get the height of the wave at that world location by accessing the waterheight generator, then set the control point height of that location:
for (int i=0; i<qtyCP; i++)
{
vecControlPointCalc[i] = shipPos.add(shipQuat.mult(vecControlPoint[i]).mult(myScale));
waveHeight[i] = myShip.myGame.whGEN.getHeight(vecControlPointCalc[i].x, vecControlPointCalc[i].z, myShip.myGame.grid.myTime);
cpHeight[i] = vecControlPointCalc[i].y;
}
}
/**
Apply the forces which make the hull follow the waves:
*/
public void followWave(float tpf)
{
shipPos.set(this.getPhysicsLocation()); // Store the physic body's location
// Process every control point:
for (int i=0; i -myDraft) // Only apply force when part of the ship is in the water, else only gravity will have to do its job.
{
waterImpulseForce.set(0, waveStrength[i]waveForce(1+(waveHeight[i]-cpHeight[i]))*tpf, 0); // Set the force.
waterImpulseLocation.set(vecControlPointCalc[i].subtract(shipPos)); // Set the location the force has to be applied to.
this.applyImpulse(waterImpulseForce, waterImpulseLocation); // Apply the force to the hull.
}
}
}
}
[/java]
You will have to implement the ProjectedGrid water in your application for this to work, though! For now, it is ‘optimized’ to work in my application (so you need a Ship class etc.) but with some creativity this can be changed to your own application. I am trying to make it as modular as possible, though. There is not much magic in the code, it is straight forward and I used a pragmatic approach. I am sure there will be a lot of things which can be optimized, but for me this works and it does not seem to eat a lot of my fps.
@author Arjen
*/
public final class BuoyancyControl extends RigidBodyControl implements PhysicsTickListener, PhysicsControl
{
ShipTest myShip;
Node myHull;
float myScale;
float myMass;
float myDraft;
int qtyCP = 20; // Number of contol points to be used alongside the entire hull (half of them on startboard side , half of them on part side)
Vector3f[] vecControlPoint = new Vector3f[qtyCP]; // Position of control point relative to the ship.
Vector3f[] vecControlPointCalc = new Vector3f[qtyCP]; // Position of control point in world coordinates (for applying forces).
Quaternion shipQuat = new Quaternion(Quaternion.ZERO);
Vector3f shipPos = new Vector3f();
float[] waveHeight = new float[qtyCP];
float[] cpHeight = new float[qtyCP];
// Strength of the wave at every cross-section of the ship (displacement). Still hard-coded, but should be calculated in the future:
float[] waveStrength = {0.03f, 0.03f, 0.04f, 0.05f, 0.1f, 0.1f, 0.07f, 0.04f, 0.03f, 0.01f, 0.01f, 0.03f, 0.04f, 0.07f, 0.1f, 0.1f, 0.05f, 0.04f, 0.03f, 0.03f};
Vector3f waterImpulseForce = new Vector3f(), waterImpulseLocation = new Vector3f();
float waveForce; // Force applied to follow waves.
/**
Adds an empty BuoyancyControl.
*/
public BuoyancyControl()
{
}
/**
Adds a BuoyancyControl to the ship object.
@param ship The ship class object in which the ship is assembled.
@param hull Node which holds the hull of the ship in the Ship class.
@param scale Scale as set in the Ship class.
@param mass Float holding the ships mass.
@param draft Float holding the ships draft (distance from waterline to the bottom of the keel).
for (int i = 0; i<qtyCP; i++)
{
vecControlPoint[i] = new Vector3f(Vector3f.ZERO);
}
createControlPoints();
}
@Override
public void setPhysicsSpace(PhysicsSpace space)
{
super.setPhysicsSpace(space);
if (space != null)
{
space.addTickListener(this);
}
}
public void prePhysicsTick(PhysicsSpace space, float tpf)
{
checkWavePos();
}
public void physicsTick(PhysicsSpace space, float tpf)
{
followWave(tpf);
}
@Override
public void update(float tpf)
{
super.update(tpf);
}
/**
Here we are creating the positions of the control points which we use to calculate the depth of the hull in relation to the water.
*/
public void createControlPoints()
{
float myLength = ((BoundingBox)myHull.getWorldBound()).getXExtent() / myScale; // Lenght of the hull (half of its lenght).
float xCoor; // X-coordinate for the control point
float zCoor; // Z-coordinate for the control point
for (int i=0; i 0)
{
zCoor = results.getCollision(0).getDistance()/myScale; // Define the Z-coordinate for this cross-section.
}
else
{
zCoor = 0f; // To prevent 'out of bound array error' when there is no collision (especially at stern and bow, because mostly the waterline is shorter then the overal lenght of the hull).
}
vecControlPoint[i].set(xCoor, 0f, zCoor); // Set the coordinates for the given control point on starboard side.
vecControlPoint[i+qtyCP/2].set(xCoor, 0f, -zCoor); // Set the coordinates for the given control point on port side.
vecControlPointCalc[i] = new Vector3f(xCoor, 0f, zCoor); // Set the coordinates for the given calculated control point on starboard side.
vecControlPointCalc[i+qtyCP/2] = new Vector3f(xCoor, 0f, -zCoor); // Set the coordinates for the given calculated control point on port side.
}
for (int i=0; i<qtyCP; i++)
{
waveHeight[i] = 0f; // Fill/create the wave height values.
cpHeight[i] = 0f; // Fill/create the control point height values.
}
}
/**
Check the height of the waves for each control point location.
*/
public void checkWavePos()
{
shipQuat.set(this.getPhysicsRotation()); // Store the physic body's rotation.
shipPos.set(this.getPhysicsLocation()); // Store the physic body's location
// For every control point, calculate the world location, then get the height of the wave at that world location by accessing the waterheight generator, then set the control point height of that location:
for (int i=0; i<qtyCP; i++)
{
vecControlPointCalc[i] = shipPos.add(shipQuat.mult(vecControlPoint[i]).mult(myScale));
waveHeight[i] = myShip.myGame.whGEN.getHeight(vecControlPointCalc[i].x, vecControlPointCalc[i].z, myShip.myGame.grid.myTime);
cpHeight[i] = vecControlPointCalc[i].y;
}
}
/**
Apply the forces which make the hull follow the waves:
*/
public void followWave(float tpf)
{
shipPos.set(this.getPhysicsLocation()); // Store the physic body's location
// Process every control point:
for (int i=0; i -myDraft) // Only apply force when part of the ship is in the water, else only gravity will have to do its job.
{
waterImpulseForce.set(0, waveStrength[i]waveForce(1+(waveHeight[i]-cpHeight[i]))*tpf, 0); // Set the force.
waterImpulseLocation.set(vecControlPointCalc[i].subtract(shipPos)); // Set the location the force has to be applied to.
this.applyImpulse(waterImpulseForce, waterImpulseLocation); // Apply the force to the hull.
}
}
}
}
[/java]
@author Arjen
*/
public final class BuoyancyControl extends RigidBodyControl implements PhysicsTickListener, PhysicsControl
{
ShipTest myShip;
Node myHull;
float myScale;
float myMass;
float myDraft;
int qtyCP = 20; // Number of contol points to be used alongside the entire hull (half of them on startboard side , half of them on part side)
Vector3f[] vecControlPoint = new Vector3f[qtyCP]; // Position of control point relative to the ship.
Vector3f[] vecControlPointCalc = new Vector3f[qtyCP]; // Position of control point in world coordinates (for applying forces).
Quaternion shipQuat = new Quaternion(Quaternion.ZERO);
Vector3f shipPos = new Vector3f();
float[] waveHeight = new float[qtyCP];
float[] cpHeight = new float[qtyCP];
// Strength of the wave at every cross-section of the ship (displacement). Still hard-coded, but should be calculated in the future:
float[] waveStrength = {0.03f, 0.03f, 0.04f, 0.05f, 0.1f, 0.1f, 0.07f, 0.04f, 0.03f, 0.01f, 0.01f, 0.03f, 0.04f, 0.07f, 0.1f, 0.1f, 0.05f, 0.04f, 0.03f, 0.03f};
Vector3f waterImpulseForce = new Vector3f(), waterImpulseLocation = new Vector3f();
float waveForce; // Force applied to follow waves.
/**
Adds an empty BuoyancyControl.
*/
public BuoyancyControl()
{
}
/**
Adds a BuoyancyControl to the ship object.
@param ship The ship class object in which the ship is assembled.
@param hull Node which holds the hull of the ship in the Ship class.
@param scale Scale as set in the Ship class.
@param mass Float holding the ships mass.
@param draft Float holding the ships draft (distance from waterline to the bottom of the keel).
for (int i = 0; i<qtyCP; i++)
{
vecControlPoint[i] = new Vector3f(Vector3f.ZERO);
}
createControlPoints();
}
@Override
public void setPhysicsSpace(PhysicsSpace space)
{
super.setPhysicsSpace(space);
if (space != null)
{
space.addTickListener(this);
}
}
public void prePhysicsTick(PhysicsSpace space, float tpf)
{
checkWavePos();
}
public void physicsTick(PhysicsSpace space, float tpf)
{
followWave(tpf);
}
@Override
public void update(float tpf)
{
super.update(tpf);
}
/**
Here we are creating the positions of the control points which we use to calculate the depth of the hull in relation to the water.
*/
public void createControlPoints()
{
float myLength = ((BoundingBox)myHull.getWorldBound()).getXExtent() / myScale; // Lenght of the hull (half of its lenght).
float xCoor; // X-coordinate for the control point
float zCoor; // Z-coordinate for the control point
for (int i=0; i 0)
{
zCoor = results.getCollision(0).getDistance()/myScale; // Define the Z-coordinate for this cross-section.
}
else
{
zCoor = 0f; // To prevent ‘out of bound array error’ when there is no collision (especially at stern and bow, because mostly the waterline is shorter then the overal lenght of the hull).
}
vecControlPoint[i].set(xCoor, 0f, zCoor); // Set the coordinates for the given control point on starboard side.
vecControlPoint[i+qtyCP/2].set(xCoor, 0f, -zCoor); // Set the coordinates for the given control point on port side.
vecControlPointCalc[i] = new Vector3f(xCoor, 0f, zCoor); // Set the coordinates for the given calculated control point on starboard side.
vecControlPointCalc[i+qtyCP/2] = new Vector3f(xCoor, 0f, -zCoor); // Set the coordinates for the given calculated control point on port side.
}
for (int i=0; i<qtyCP; i++)
{
waveHeight[i] = 0f; // Fill/create the wave height values.
cpHeight[i] = 0f; // Fill/create the control point height values.
}
}
/**
Check the height of the waves for each control point location.
*/
public void checkWavePos()
{
shipQuat.set(this.getPhysicsRotation()); // Store the physic body's rotation.
shipPos.set(this.getPhysicsLocation()); // Store the physic body's location
// For every control point, calculate the world location, then get the height of the wave at that world location by accessing the waterheight generator, then set the control point height of that location:
for (int i=0; i<qtyCP; i++)
{
vecControlPointCalc[i] = shipPos.add(shipQuat.mult(vecControlPoint[i]).mult(myScale));
waveHeight[i] = myShip.myGame.whGEN.getHeight(vecControlPointCalc[i].x, vecControlPointCalc[i].z, myShip.myGame.grid.myTime);
cpHeight[i] = vecControlPointCalc[i].y;
}
}
/**
Apply the forces which make the hull follow the waves:
*/
public void followWave(float tpf)
{
shipPos.set(this.getPhysicsLocation()); // Store the physic body's location
// Process every control point:
for (int i=0; i -myDraft) // Only apply force when part of the ship is in the water, else only gravity will have to do its job.
{
waterImpulseForce.set(0, waveStrength[i]waveForce(1+(waveHeight[i]-cpHeight[i]))*tpf, 0); // Set the force.
waterImpulseLocation.set(vecControlPointCalc[i].subtract(shipPos)); // Set the location the force has to be applied to.
this.applyImpulse(waterImpulseForce, waterImpulseLocation); // Apply the force to the hull.
}
}
}
}
==================================
==================================
This is the same code as I have paste in before, but now without the JAVA-tags.
And again, the FOR-loops are wrong??? I don’t get it: In my typing window the code is showing just fine, but after pressing ‘Submit’ it screws up somehow?
Just a little piece of code for testing. The first line should read ‘for (inti=0; i<qtyCP/2; i++)’:
[java]for (int i=0; i 0)
{
zCoor = results.getCollision(0).getDistance()/myScale; // Define the Z-coordinate for this cross-section.
}
else
{
zCoor = 0f; // To prevent 'out of bound array error' when there is no collision (especially at stern and bow, because mostly the waterline is shorter then the overal lenght of the hull).
vecControlPoint[i].set(xCoor, 0f, zCoor); // Set the coordinates for the given control point on starboard side.
vecControlPoint[i+qtyCP/2].set(xCoor, 0f, -zCoor); // Set the coordinates for the given control point on port side.
vecControlPointCalc[i] = new Vector3f(xCoor, 0f, zCoor); // Set the coordinates for the given calculated control point on starboard side.
vecControlPointCalc[i+qtyCP/2] = new Vector3f(xCoor, 0f, -zCoor); // Set the coordinates for the given calculated control point on port side.
}
}[/java]
[EDIT] But as you can see, it does read something different. Further, it has removed a lot of code…