public TriangleData(Vector3 p1, Vector3 p2, Vector3 p3, Rigidbody boatRB, float timeSinceStart) { this.p1 = p1; this.p2 = p2; this.p3 = p3; //Center of the triangle this.center = (p1 + p2 + p3) / 3f; //Distance to the surface from the center of the triangle this.distanceToSurface = Mathf.Abs(WaterController.current.DistanceToWater(this.center, timeSinceStart)); //Normal to the triangle this.normal = Vector3.Cross(p2 - p1, p3 - p1).normalized; //Area of the triangle this.area = BoatPhysicsMath.GetTriangleArea(p1, p2, p3); //Velocity vector of the triangle at the center this.velocity = BoatPhysicsMath.GetTriangleVelocity(boatRB, this.center); //Velocity direction this.velocityDir = this.velocity.normalized; //Angle between the normal and the velocity //Negative if pointing in the opposite direction //Positive if pointing in the same direction this.cosTheta = Vector3.Dot(this.velocityDir, this.normal); }
//Calculate the area of each triangle in the boat mesh and store them in an array private void CalculateOriginalTrianglesArea() { //Loop through all the triangles (3 vertices at a time = 1 triangle) int i = 0; int triangleCounter = 0; while (i < boatTriangles.Length) { Vector3 p1 = boatVertices[boatTriangles[i]]; i++; Vector3 p2 = boatVertices[boatTriangles[i]]; i++; Vector3 p3 = boatVertices[boatTriangles[i]]; i++; //Calculate the area of the triangle float triangleArea = BoatPhysicsMath.GetTriangleArea(p1, p2, p3); //Store the area in a list slammingForceData[triangleCounter].originalArea = triangleArea; //The total area boatArea += triangleArea; triangleCounter += 1; } }
//Calculate the current velocity at the center of each triangle of the original boat mesh private void CalculateSlammingVelocities(List <SlammingForceData> slammingForceData) { for (int i = 0; i < slammingForceData.Count; i++) { //Set the new velocity to the old velocity slammingForceData[i].previousVelocity = slammingForceData[i].velocity; //Center of the triangle in world space Vector3 center = transform.TransformPoint(slammingForceData[i].triangleCenter); //Get the current velocity at the center of the triangle slammingForceData[i].velocity = BoatPhysicsMath.GetTriangleVelocity(boatRB, center); } }
//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); } }
//Build the new triangles where two of the old vertices are above the water private void AddTrianglesTwoAboveWater(List <VertexData> vertexData, int triangleCounter) { //H and M are above the water //H is after the vertice that's below water, which is L //So we know which one is L because it is last in the sorted list Vector3 L = vertexData[2].globalVertexPos; //Find the index of H int H_index = vertexData[2].index + 1; if (H_index > 2) { H_index = 0; } //We also need the heights to water float h_L = vertexData[2].distance; float h_H = 0f; float h_M = 0f; Vector3 H = Vector3.zero; Vector3 M = Vector3.zero; //This means that H is at position 1 in the list if (vertexData[1].index == H_index) { H = vertexData[1].globalVertexPos; M = vertexData[0].globalVertexPos; h_H = vertexData[1].distance; h_M = vertexData[0].distance; } else { H = vertexData[0].globalVertexPos; M = vertexData[1].globalVertexPos; h_H = vertexData[0].distance; h_M = vertexData[1].distance; } //Now we can find where to cut the triangle //Point J_M Vector3 LM = M - L; float t_M = -h_L / (h_M - h_L); Vector3 LJ_M = t_M * LM; Vector3 J_M = LJ_M + L; //Point J_H Vector3 LH = H - L; float t_H = -h_L / (h_H - h_L); Vector3 LJ_H = t_H * LH; Vector3 J_H = LJ_H + L; //Save the data, such as normal, area, etc //1 triangle above the water underWaterTriangleData.Add(new TriangleData(L, J_H, J_M, boatRB, timeSinceStart)); //2 triangles below the water aboveWaterTriangleData.Add(new TriangleData(J_H, H, J_M, boatRB, timeSinceStart)); aboveWaterTriangleData.Add(new TriangleData(J_M, H, M, boatRB, timeSinceStart)); //Calculate the submerged area slammingForceData[triangleCounter].submergedArea = BoatPhysicsMath.GetTriangleArea(L, J_H, J_M); indexOfOriginalTriangle.Add(triangleCounter); }
//Build the new triangles where one of the old vertices is above the water private void AddTrianglesOneAboveWater(List <VertexData> vertexData, int triangleCounter) { //H is always at position 0 Vector3 H = vertexData[0].globalVertexPos; //Left of H is M //Right of H is L //Find the index of M int M_index = vertexData[0].index - 1; if (M_index < 0) { M_index = 2; } //We also need the heights to water float h_H = vertexData[0].distance; float h_M = 0f; float h_L = 0f; Vector3 M = Vector3.zero; Vector3 L = Vector3.zero; //This means M is at position 1 in the List if (vertexData[1].index == M_index) { M = vertexData[1].globalVertexPos; L = vertexData[2].globalVertexPos; h_M = vertexData[1].distance; h_L = vertexData[2].distance; } else { M = vertexData[2].globalVertexPos; L = vertexData[1].globalVertexPos; h_M = vertexData[2].distance; h_L = vertexData[1].distance; } //Now we can calculate where we should cut the triangle to form 2 new triangles //because the resulting area will always form a square //Point I_M Vector3 MH = H - M; float t_M = -h_M / (h_H - h_M); Vector3 MI_M = t_M * MH; Vector3 I_M = MI_M + M; //Point I_L Vector3 LH = H - L; float t_L = -h_L / (h_H - h_L); Vector3 LI_L = t_L * LH; Vector3 I_L = LI_L + L; //Save the data, such as normal, area, etc //2 triangles below the water underWaterTriangleData.Add(new TriangleData(M, I_M, I_L, boatRB, timeSinceStart)); underWaterTriangleData.Add(new TriangleData(M, I_L, L, boatRB, timeSinceStart)); //1 triangle above the water aboveWaterTriangleData.Add(new TriangleData(I_M, H, I_L, boatRB, timeSinceStart)); //Calculate the total submerged area float totalArea = BoatPhysicsMath.GetTriangleArea(M, I_M, I_L) + BoatPhysicsMath.GetTriangleArea(M, I_L, L); slammingForceData[triangleCounter].submergedArea = totalArea; indexOfOriginalTriangle.Add(triangleCounter); //Add 2 times because 2 submerged triangles need to connect to the same original triangle indexOfOriginalTriangle.Add(triangleCounter); }
//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); } }