//Force 2 - Pressure Drag Force public static Vector3 PressureDragForce(TriangleData triangleData) { //Modify for different turning behavior and planing forces //f_p and f_S - falloff power, should be smaller than 1 //C - coefficients to modify float velocity = triangleData.velocity.magnitude; //A reference speed used when modifying the parameters float velocityReference = velocity; velocity = velocity / velocityReference; Vector3 pressureDragForce = Vector3.zero; if (triangleData.cosTheta > 0f) { //float C_PD1 = 10f; //float C_PD2 = 10f; //float f_P = 0.5f; //To change the variables real-time - add the finished values later float C_PD1 = DebugPhysics.current.C_PD1; float C_PD2 = DebugPhysics.current.C_PD2; float f_P = DebugPhysics.current.f_P; pressureDragForce = -(C_PD1 * velocity + C_PD2 * (velocity * velocity)) * triangleData.area * Mathf.Pow(triangleData.cosTheta, f_P) * triangleData.normal; } else { //float C_SD1 = 10f; //float C_SD2 = 10f; //float f_S = 0.5f; //To change the variables real-time - add the finished values later float C_SD1 = DebugPhysics.current.C_SD1; float C_SD2 = DebugPhysics.current.C_SD2; float f_S = DebugPhysics.current.f_S; pressureDragForce = (C_SD1 * velocity + C_SD2 * (velocity * velocity)) * triangleData.area * Mathf.Pow(Mathf.Abs(triangleData.cosTheta), f_S) * triangleData.normal; } pressureDragForce = CheckForceIsValid(pressureDragForce, "Pressure drag"); return(pressureDragForce); }
//Add all forces that act on the squares above the water void AddAboveWaterForces() { //Get all triangles List <TriangleData> aboveWaterTriangleData = modifyBoatMesh.aboveWaterTriangleData; //Loop through all triangles for (int i = 0; i < aboveWaterTriangleData.Count; i++) { TriangleData triangleData = aboveWaterTriangleData[i]; //Calculate the forces Vector3 forceToAdd = Vector3.zero; //Force 1 - Air resistance //Replace VisbyData.C_r with your boat's drag coefficient forceToAdd += BoatPhysicsMath.AirResistanceForce(rhoAir, triangleData, 1f); //Add the forces to the boat boatRB.AddForceAtPosition(forceToAdd, triangleData.center); //Debug //The normal //Debug.DrawRay(triangleCenter, triangleNormal * 3f, Color.white); //The velocity //Debug.DrawRay(triangleCenter, triangleVelocityDir * 3f, Color.black); if (triangleData.cosTheta > 0f) { //Debug.DrawRay(triangleCenter, triangleVelocityDir * 3f, Color.black); } //Air resistance //-3 to show it in the opposite direction to see what's going on //Debug.DrawRay(triangleCenter, airResistanceForce.normalized * -3f, Color.blue); } }
// // Buoyancy from http://www.gamasutra.com/view/news/237528/Water_interaction_model_for_boats_in_video_games.php // //The buoyancy force so the boat can float public static Vector3 BuoyancyForce(float rho, TriangleData triangleData) { //Buoyancy is a hydrostatic force - it's there even if the water isn't flowing or if the boat stays still // F_buoyancy = rho * g * V // rho - density of the mediaum you are in // g - gravity // V - volume of fluid directly above the curved surface // V = z * S * n // z - distance to surface // S - surface area // n - normal to the surface Vector3 buoyancyForce = rho * Physics.gravity.y * triangleData.distanceToSurface * triangleData.area * triangleData.normal; //The vertical component of the hydrostatic forces don't cancel out but the horizontal do buoyancyForce.x = 0f; buoyancyForce.z = 0f; //Check that the force is valid, such as not NaN to not break the physics model buoyancyForce = CheckForceIsValid(buoyancyForce, "Buoyancy"); return(buoyancyForce); }
//Force 3 - Air resistance on the part of the ship above the water (typically 4 to 8 percent of total resistance) public static Vector3 AirResistanceForce(float rho, TriangleData triangleData, float C_air) { // R_air = 0.5 * rho * v^2 * A_p * C_air // rho - air density // v - speed of ship // A_p - projected transverse profile area of ship // C_r - coefficient of air resistance (drag coefficient) //Only add air resistance if normal is pointing in the same direction as the velocity if (triangleData.cosTheta < 0f) { return(Vector3.zero); } //Find air resistance force Vector3 airResistanceForce = 0.5f * rho * triangleData.velocity.magnitude * triangleData.velocity * triangleData.area * C_air; //Acting in the opposite side of the velocity airResistanceForce *= -1f; airResistanceForce = CheckForceIsValid(airResistanceForce, "Air resistance"); return(airResistanceForce); }
// // Resistance forces from http://www.gamasutra.com/view/news/263237/Water_interaction_model_for_boats_in_video_games_Part_2.php // //Force 1 - Viscous Water Resistance (Frictional Drag) public static Vector3 ViscousWaterResistanceForce(float rho, TriangleData triangleData, float Cf) { //Viscous resistance occurs when water sticks to the boat's surface and the boat has to drag that water with it // F = 0.5 * rho * v^2 * S * Cf // rho - density of the medium you have // v - speed // S - surface area // Cf - Coefficient of frictional resistance //We need the tangential velocity //Projection of the velocity on the plane with the normal normalvec //http://www.euclideanspace.com/maths/geometry/elements/plane/lineOnPlane/ Vector3 B = triangleData.normal; Vector3 A = triangleData.velocity; Vector3 velocityTangent = Vector3.Cross(B, (Vector3.Cross(A, B) / B.magnitude)) / B.magnitude; //The direction of the tangential velocity (-1 to get the flow which is in the opposite direction) Vector3 tangentialDirection = velocityTangent.normalized * -1f; //Debug.DrawRay(triangleCenter, tangentialDirection * 3f, Color.black); //Debug.DrawRay(triangleCenter, velocityVec.normalized * 3f, Color.blue); //Debug.DrawRay(triangleCenter, normal * 3f, Color.white); //The speed of the triangle as if it was in the tangent's direction //So we end up with the same speed as in the center of the triangle but in the direction of the flow Vector3 v_f_vec = triangleData.velocity.magnitude * tangentialDirection; //The final resistance force Vector3 viscousWaterResistanceForce = 0.5f * rho * v_f_vec.magnitude * v_f_vec * triangleData.area * Cf; viscousWaterResistanceForce = CheckForceIsValid(viscousWaterResistanceForce, "Viscous Water Resistance"); return(viscousWaterResistanceForce); }
//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); }