//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 = 1f; //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); //Add the forces to the boat 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); //Velocity //Debug.DrawRay(triangleCenter, triangleVelocityDir * 3f, Color.black); //Viscous Water Resistance //Debug.DrawRay(triangleCenter, viscousWaterResistanceForce.normalized * 3f, Color.black); } }
//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); }