public static Vector3 CalculateSlammingForce(TriangleData triangle, SlammingForceData slammingData, float slammingForceAmount, float bodyArea, float bodyMass) { //To capture the response of the fluid to sudden accelerations or penetrations //Add slamming if the normal is in the same direction as the velocity (the triangle is not receding from the water) //Also make sure thea area is not 0, which it sometimes is for some reason if (triangle.cosTheta < 0f || slammingData.originalArea <= 0f) { return(Vector3.zero); } //Step 1 - Calculate acceleration //Volume of water swept per second Vector3 dV = slammingData.submergedArea * slammingData.velocity; Vector3 dV_previous = slammingData.previousSubmergedArea * slammingData.previousVelocity; //Calculate the acceleration of the center point of the original triangle (not the current underwater triangle) //But the triangle the underwater triangle is a part of Vector3 accVec = (dV - dV_previous) / (slammingData.originalArea * Time.fixedDeltaTime); //The magnitude of the acceleration float acc = accVec.magnitude; //Step 2 - Calculate slamming force Vector3 F_stop = bodyMass * triangle.velocity * ((2f * triangle.area) / bodyArea); float p = 2f; float acc_max = acc; Vector3 slammingForce = -Mathf.Pow(Mathf.Clamp01(acc / acc_max), p) * triangle.cosTheta * F_stop * slammingForceAmount; return(CheckForceIsValid(slammingForce)); }
public static Vector3 SlammingForce(SlammingForceData slammingData, TriangleData triangleData, float boatArea, float boatMass) { if (triangleData.cosTheta < 0f || slammingData.originalArea <= 0f) { return(Vector3.zero); } Vector3 dV = slammingData.submergedArea * slammingData.velocity; Vector3 dV_previous = slammingData.previousSubmergedArea * slammingData.previousVelocity; Vector3 accVec = (dV - dV_previous) / (slammingData.originalArea * Time.fixedDeltaTime); float acc = accVec.magnitude; Vector3 F_stop = boatMass * triangleData.velocity * ((2f * triangleData.area) / boatArea); float p = 2f; float acc_max = acc; float slammingCheat = DebugPhysics.current.slammingCheat; Vector3 slammingForce = Mathf.Pow(Mathf.Clamp01(acc / acc_max), p) * triangleData.cosTheta * F_stop * slammingCheat; slammingForce *= -1f; slammingForce = CheckForceIsValid(slammingForce, "Slamming"); return(slammingForce); }
void AddUnderWaterForces() { float Cf = BoatPhysicsMath.ResistanceCoefficient( rhoWater, boatRB.velocity.magnitude, modifyBoatMesh.CalculateUnderWaterLength()); List <SlammingForceData> slammingForceData = modifyBoatMesh.slammingForceData; CalculateSlammingVelocities(slammingForceData); float boatArea = modifyBoatMesh.boatArea; float boatMass = boatRB.mass; List <int> indexOfOriginalTriangle = modifyBoatMesh.indexOfOriginalTriangle; List <TriangleData> underWaterTriangleData = modifyBoatMesh.underWaterTriangleData; for (int i = 0; i < underWaterTriangleData.Count; i++) { TriangleData triangleData = underWaterTriangleData[i]; Vector3 forceToAdd = Vector3.zero; forceToAdd += BoatPhysicsMath.BuoyancyForce(rhoWater, triangleData); forceToAdd += BoatPhysicsMath.ViscousWaterResistanceForce(rhoWater, triangleData, Cf); forceToAdd += BoatPhysicsMath.PressureDragForce(triangleData); int originalTriangleIndex = indexOfOriginalTriangle[i]; SlammingForceData slammingData = slammingForceData[originalTriangleIndex]; forceToAdd += BoatPhysicsMath.SlammingForce(slammingData, triangleData, boatArea, boatMass); boatRB.AddForceAtPosition(forceToAdd, triangleData.center); } }
//Force 3 - Slamming Force (Water Entry Force) public static Vector3 SlammingForce(SlammingForceData slammingData, TriangleData triangleData, float boatArea, float boatMass) { //To capture the response of the fluid to sudden accelerations or penetrations //Add slamming if the normal is in the same direction as the velocity (the triangle is not receding from the water) //Also make sure thea area is not 0, which it sometimes is for some reason if (triangleData.cosTheta < 0f || slammingData.originalArea <= 0f) { return(Vector3.zero); } //Step 1 - Calculate acceleration //Volume of water swept per second Vector3 dV = slammingData.submergedArea * slammingData.velocity; Vector3 dV_previous = slammingData.previousSubmergedArea * slammingData.previousVelocity; //Calculate the acceleration of the center point of the original triangle (not the current underwater triangle) //But the triangle the underwater triangle is a part of Vector3 accVec = (dV - dV_previous) / (slammingData.originalArea * Time.fixedDeltaTime); //The magnitude of the acceleration float acc = accVec.magnitude; //Debug.Log(slammingForceData.originalArea); //Step 2 - Calculate slamming force // F = clamp(acc / acc_max, 0, 1)^p * cos(theta) * F_stop // p - power to ramp up slamming force - should be 2 or more // F_stop = m * v * (2A / S) // m - mass of the entire boat // v - velocity // A - this triangle's area // S - total surface area of the entire boat Vector3 F_stop = boatMass * triangleData.velocity * ((2f * triangleData.area) / boatArea); //float p = DebugPhysics.current.p; //float acc_max = DebugPhysics.current.acc_max; float p = 2f; float acc_max = acc; float slammingCheat = DebugPhysics.current.slammingCheat; Vector3 slammingForce = Mathf.Pow(Mathf.Clamp01(acc / acc_max), p) * triangleData.cosTheta * F_stop * slammingCheat; //Vector3 slammingForce = Vector3.zero; //Debug.Log(slammingForce); //The force acts in the opposite direction slammingForce *= -1f; slammingForce = CheckForceIsValid(slammingForce, "Slamming"); return(slammingForce); }
//Add all forces that act on the squares below the water void AddUnderWaterForces() { //The resistance coefficient - same for all triangles float Cf = BoatPhysicsMath.ResistanceCoefficient( rhoWater, boatRB.velocity.magnitude, modifyBoatMesh.CalculateUnderWaterLength()); //To calculate the slamming force we need the velocity at each of the original triangles List <SlammingForceData> slammingForceData = modifyBoatMesh.slammingForceData; CalculateSlammingVelocities(slammingForceData); //Need this data for slamming forces float boatArea = modifyBoatMesh.boatArea; float boatMass = gameObject.GetComponent <Rigidbody>().mass; //Replace this line with your boat's total mass //To connect the submerged triangles with the original triangles List <int> indexOfOriginalTriangle = modifyBoatMesh.indexOfOriginalTriangle; //Get all triangles List <TriangleData> underWaterTriangleData = modifyBoatMesh.underWaterTriangleData; for (int i = 0; i < underWaterTriangleData.Count; i++) { TriangleData triangleData = underWaterTriangleData[i]; //Calculate the forces Vector3 forceToAdd = Vector3.zero; //Force 1 - The hydrostatic force (buoyancy) //forceToAdd += BoatPhysicsMath.BuoyancyForce(rhoWater, triangleData); //Force 2 - Viscous Water Resistance forceToAdd += BoatPhysicsMath.ViscousWaterResistanceForce(rhoWater, triangleData, Cf); //Force 3 - Pressure drag forceToAdd += BoatPhysicsMath.PressureDragForce(triangleData); //Force 4 - Slamming force //Which of the original triangles is this triangle a part of int originalTriangleIndex = indexOfOriginalTriangle[i]; SlammingForceData slammingData = slammingForceData[originalTriangleIndex]; forceToAdd += BoatPhysicsMath.SlammingForce(slammingData, triangleData, boatArea, boatMass); //Debug.Log(BoatPhysicsMath.SlammingForce(slammingData, triangleData, boatArea, boatMass)); //Add the forces to the boat //Debug.Log("Adding force: " + forceToAdd + " to triangle " + i); boatRB.AddForceAtPosition(forceToAdd, triangleData.center); //Debug //Normal //Debug.DrawRay(triangleData.center, triangleData.normal * 3f, Color.white); //Buoyancy //Debug.DrawRay(triangleData.center, BoatPhysicsMath.BuoyancyForce(rhoWater, triangleData).normalized * -3f, Color.blue, 2f, true); //Velocity //Debug.DrawRay(triangleCenter, triangleVelocityDir * 3f, Color.black); //Viscous Water Resistance //Debug.DrawRay(triangleCenter, viscousWaterResistanceForce.normalized * 3f, Color.black); } }
private void addTriangleForces() { float underwaterArea = 0; float underwaterMinZ = 0, underwaterMaxZ = 0; foreach (TriangleData triangle in underwaterTriangles) { if (triangle.distToWater < 0) { underwaterArea += triangle.area; } float z1 = (Quaternion.Inverse(transform.rotation) * (triangle.p1 - bodyMesh.transform.position)).z; float z2 = (Quaternion.Inverse(transform.rotation) * (triangle.p2 - bodyMesh.transform.position)).z; float z3 = (Quaternion.Inverse(transform.rotation) * (triangle.p3 - bodyMesh.transform.position)).z; if (z1 < underwaterMinZ || underwaterMinZ == 0) { underwaterMinZ = z1; } if (z2 < underwaterMinZ || underwaterMinZ == 0) { underwaterMinZ = z2; } if (z3 < underwaterMinZ || underwaterMinZ == 0) { underwaterMinZ = z3; } if (z1 > underwaterMaxZ || underwaterMaxZ == 0) { underwaterMaxZ = z1; } if (z2 > underwaterMaxZ || underwaterMaxZ == 0) { underwaterMaxZ = z2; } if (z3 > underwaterMaxZ || underwaterMaxZ == 0) { underwaterMaxZ = z3; } } float underwaterLength = underwaterMaxZ - underwaterMinZ; float resistanceCoeff = ShipForces.ResistanceCoefficient(rigidbody.velocity.magnitude, underwaterLength); calculateSlammingVelocities(); for (int i = 0; i < underwaterTriangles.Count; i++) { TriangleData triangle = underwaterTriangles[i]; Vector3 buoyancyForce = ShipForces.CalculateBuoyancyForce(triangle, waterDensity); Vector3 viscousWaterResistance = ShipForces.CalculateViscousWaterResistance(triangle, waterDensity, resistanceCoeff); Vector3 pressureDrag = ShipForces.CalculatePressureDrag(triangle, pressureFalloff, pressureCoeff1, pressureCoeff2, suctionFalloff, suctionCoeff1, suctionCoeff2); int originalTriangleIndex = underwaterTriangleIndices[i]; SlammingForceData slammingData = slammingForceData[originalTriangleIndex]; Vector3 slammingForce = ShipForces.CalculateSlammingForce(triangle, slammingData, slammingForceAmount, bodySurfaceArea, rigidbody.mass); Vector3 totalForce = buoyancyForce + viscousWaterResistance + pressureDrag + slammingForce; rigidbody.AddForceAtPosition(totalForce, triangle.center); } }