- #1
WiredCat
- 6
- 0
Hello there, I'm trying to write a sailing model simulator (for ships with sails) i got buoyancy force and gravity force calculated so far.
Before i go any further i need to tell you how i am calculating anything, and what is my ship exactly.
First of all i am making that on a phone, it looks like this:
Now let's consider that this ship on the picture is made of triangles, (set of points, that every 3 next points create closed shape (solid), its convex polyhedra), the most simple 3-dimensional shape is tetrahedron, which is made out of 4 triangles that 'close' the shape - this is important for you to know.
Now to calculate buoyancy force and drag acting on a ship (but only for submerged part) i slice that ship shape (set of triangles) like this: (green thing is my set of triangles on which i calculate buoyancy and drag) (note that i return the shape that is below waterline, i do not close this shape (this means if my ship is a simple tetrahedron and its covered in half with water, i only cut triangles (sides of that tetrahedron) and do not close (create new triangle) at the top of the new shape, like in this picture:
but that's irrevelant.Final shape can look like this:
I'll tell you how i calculate the buoyuancy but you can skip this part since its calculated properly.
For any number of triangles(in that green shape), create a tetrahedron that base is each triangle and apex is the center of mass of the ship, then calculate the volume of each such tetrahedron, then go again through all triangles and do the same but now we perform a cut on tetrahedrons, (we cut by water plane) and we substract each triangle volume by this cut tetrahedron to get total submerged area), after this i calculate geometric center of all submerged tetrahedrons and this gives me the point where i apply buoyancy force.
Forgot to mention that i also calculate area of each submerged triangle.Before i go any further i would like you to see what is the actual shape of my ship (its made out of 24 triangles, i later cut the ship model into 4 sections from front to back, and return with 120 triangles)
any way hull at bottom ain't flat it looks like a triangle, and at front there isn't any curve but flat 2 triangles that are angled:
Back:
Side: (front curve - the one at bottom)
Front:
You will see a quad (2 tris as a flat angled plate)
and from other perspective:
I need to use really small amount of triangles since its realtime simulation on mobile phones, and i need to run it as fast as possible (not mentioning i have there some time consuming things and somewhat simplified physically based rendering)
And i forgot to straight forward what is divided into sections and one thing: i only calculate ships hull not masts etc or this stick in front of it)
sections are made like that:
from 24 triangles to 120 :P (this is important since when the model is rotating drag applied on center of triangle can somehow correspond to real one since in low polygon model(24 tris) 2 triangles defined one side (where cannons are) so actually when such tris are cut horizontally drag will be applied almost at center of the ships hull) with divided tris i can apply drag force to non center of mass point 'a bit more preceisely'
I may not described that properly, sorry for that/Now... given velocity vector 'vel' [m/s] and frame time dt (consider 0.033)
i calculate drag like this:
for all submerged triangles
{
get geometric center of each triangle, surface and volume of shape that is made out of tetrahedron which apex is on ships center of mass and its cut by waterplane...
get triangle local velocity = ship_linear_vel + ship_angular_vel x vector_form_tri_geom_center_to_ship_center_of_mass;
now i calculate form drag percentage coefficient (to know how much my triangle faces the velocity vector)
form_percentage_coeff = absolute_value( arcus_cosinus( dot_product(triangle_normal, vel_normalized)) / pi ); - reason i return absolute value is that even when triangle is not facing the same direction like vel, the suction force occurs (i managed to calculate that its 0.6666666 of element form drag force).999.1026 - water density
element_form_drag = (-local_velocity_normalized) * (form_percentage_coeff * (999.1026 * 0.5 * local_vel_squared) * triangle_surface_area);now for skin friction drag:
skin_percentage_coeff = absolute_value(1.0 - form_percentage_coeff);
then i do some magic that calculates the choord length for that triangle (projected local velocity vector, onto triangle surface, that comes through triangle geometric center)
0.894 - water dynamic viscocsity..
form this i calculate Reynolds number, and then a coefficient
CFRn = 1.328 / square_root(Rn);
element_skin_drag = (-normalized_local_vel) * (CFRn * ((999.1026 * local_vel_squared) / 2.0 ) * triangle_surface_area * skin_percentage_coeff);
drag_of_element = element_skin_drag + element_form_drag;
total_drag = total_drag + drag_of_element; //for linear motion
}i also sum all torques that are made up by all of tris + torque made by buoyancy force.
(this is another part of the post - at the end i will ask my questions)
I am not sure if my angular acceleration which is rad/s is correct. and if i am using my moment of inertia tensor properly.
after summing all torques i do something like this:
//angular acceleration.
AngAcc.x = summed_torque.x / Ixx;
AngAcc.y = summed_torque.y / Iyy;
AngAcc.z = summed_torque.z / Izz;
now this is a bit weird for me, because x component describes rotation around x axis, and Ixx defines rotation around which axis uh? i think it defines rotation around Z one.
Anyway next question
after summing doing each iteration step: ship_angular_vel = ship_angular_vel + AngAcc*dt;
is that correct to get each triangle local vel by:
triangle local velocity = ship_linear_vel + ship_angular_vel x vector_form_tri_geom_center_to_ship_center_of_mass;
or maybe my units are bad? in example i add meters per second and radians per second cross some_vector.My ship is unstable when i apply thrust at center of mass (i mean after some time its front starts bobbing like mad (going up and going down in time the amplitude of bobbing increases to finally reach so ridicilous number that processor can't handle it) another thing is when ship is trying to make a turn. it turns but after some time it flips over and acts really weird (i could try to make a video of that if requested)So my questions are:
What i am doing wrong? - i know i am trying to simulate simplified shape (and try to use 'corners' instead of soft curves'
How is form drag and skin friction drag calculated for any surface (or for any shape that is made up out of tiny surfaces (just don't tell me i need to convert all these cut triangles into something else :X)
Is rotation, and angular velcoity correctly calculated.
How to improove the simulation so i can eaisly make turns with ship without causing it to flip over.here is code: (theres also a part with rudder deflection (for turning)
Please help the kitten ;]
Before i go any further i need to tell you how i am calculating anything, and what is my ship exactly.
First of all i am making that on a phone, it looks like this:
Now to calculate buoyancy force and drag acting on a ship (but only for submerged part) i slice that ship shape (set of triangles) like this: (green thing is my set of triangles on which i calculate buoyancy and drag) (note that i return the shape that is below waterline, i do not close this shape (this means if my ship is a simple tetrahedron and its covered in half with water, i only cut triangles (sides of that tetrahedron) and do not close (create new triangle) at the top of the new shape, like in this picture:
but that's irrevelant.Final shape can look like this:
For any number of triangles(in that green shape), create a tetrahedron that base is each triangle and apex is the center of mass of the ship, then calculate the volume of each such tetrahedron, then go again through all triangles and do the same but now we perform a cut on tetrahedrons, (we cut by water plane) and we substract each triangle volume by this cut tetrahedron to get total submerged area), after this i calculate geometric center of all submerged tetrahedrons and this gives me the point where i apply buoyancy force.
Forgot to mention that i also calculate area of each submerged triangle.Before i go any further i would like you to see what is the actual shape of my ship (its made out of 24 triangles, i later cut the ship model into 4 sections from front to back, and return with 120 triangles)
any way hull at bottom ain't flat it looks like a triangle, and at front there isn't any curve but flat 2 triangles that are angled:
Back:
Side: (front curve - the one at bottom)
Front:
You will see a quad (2 tris as a flat angled plate)
and from other perspective:
And i forgot to straight forward what is divided into sections and one thing: i only calculate ships hull not masts etc or this stick in front of it)
sections are made like that:
from 24 triangles to 120 :P (this is important since when the model is rotating drag applied on center of triangle can somehow correspond to real one since in low polygon model(24 tris) 2 triangles defined one side (where cannons are) so actually when such tris are cut horizontally drag will be applied almost at center of the ships hull) with divided tris i can apply drag force to non center of mass point 'a bit more preceisely'
I may not described that properly, sorry for that/Now... given velocity vector 'vel' [m/s] and frame time dt (consider 0.033
i calculate drag like this:
for all submerged triangles
{
get geometric center of each triangle, surface and volume of shape that is made out of tetrahedron which apex is on ships center of mass and its cut by waterplane...
get triangle local velocity = ship_linear_vel + ship_angular_vel x vector_form_tri_geom_center_to_ship_center_of_mass;
now i calculate form drag percentage coefficient (to know how much my triangle faces the velocity vector)
form_percentage_coeff = absolute_value( arcus_cosinus( dot_product(triangle_normal, vel_normalized)) / pi ); - reason i return absolute value is that even when triangle is not facing the same direction like vel, the suction force occurs (i managed to calculate that its 0.6666666 of element form drag force).999.1026 - water density
element_form_drag = (-local_velocity_normalized) * (form_percentage_coeff * (999.1026 * 0.5 * local_vel_squared) * triangle_surface_area);now for skin friction drag:
skin_percentage_coeff = absolute_value(1.0 - form_percentage_coeff);
then i do some magic that calculates the choord length for that triangle (projected local velocity vector, onto triangle surface, that comes through triangle geometric center)
0.894 - water dynamic viscocsity..
form this i calculate Reynolds number, and then a coefficient
CFRn = 1.328 / square_root(Rn);
element_skin_drag = (-normalized_local_vel) * (CFRn * ((999.1026 * local_vel_squared) / 2.0 ) * triangle_surface_area * skin_percentage_coeff);
drag_of_element = element_skin_drag + element_form_drag;
total_drag = total_drag + drag_of_element; //for linear motion
}i also sum all torques that are made up by all of tris + torque made by buoyancy force.
(this is another part of the post - at the end i will ask my questions)
I am not sure if my angular acceleration which is rad/s is correct. and if i am using my moment of inertia tensor properly.
after summing all torques i do something like this:
//angular acceleration.
AngAcc.x = summed_torque.x / Ixx;
AngAcc.y = summed_torque.y / Iyy;
AngAcc.z = summed_torque.z / Izz;
now this is a bit weird for me, because x component describes rotation around x axis, and Ixx defines rotation around which axis uh? i think it defines rotation around Z one.
Anyway next question
after summing doing each iteration step: ship_angular_vel = ship_angular_vel + AngAcc*dt;
is that correct to get each triangle local vel by:
triangle local velocity = ship_linear_vel + ship_angular_vel x vector_form_tri_geom_center_to_ship_center_of_mass;
or maybe my units are bad? in example i add meters per second and radians per second cross some_vector.My ship is unstable when i apply thrust at center of mass (i mean after some time its front starts bobbing like mad (going up and going down in time the amplitude of bobbing increases to finally reach so ridicilous number that processor can't handle it) another thing is when ship is trying to make a turn. it turns but after some time it flips over and acts really weird (i could try to make a video of that if requested)So my questions are:
What i am doing wrong? - i know i am trying to simulate simplified shape (and try to use 'corners' instead of soft curves'
How is form drag and skin friction drag calculated for any surface (or for any shape that is made up out of tiny surfaces (just don't tell me i need to convert all these cut triangles into something else :X)
Is rotation, and angular velcoity correctly calculated.
How to improove the simulation so i can eaisly make turns with ship without causing it to flip over.here is code: (theres also a part with rudder deflection (for turning)
Code:
void ProcessOceanFrame(TWaterWaves * ocean, float dt) //rotate model due to water
{
if (dt < 0.0010) return;
// ALOG("FRAME DT: "+FloatToStr(dt));
result_force = vec3(0.0, 0.0, 0.0);
vec3 thrust_force = vec3(0.0, 0.0, 1.0) * 1000.0;vec3 elements_torque;
/*
for each element
calculate local velocity related as EAngVel
Calculate all forces acting on body at this frame (add linear force) and add torque
----
after that rotate body
move body
*/
/*
* Buoyancy effect
* ******************************************************************************************
*/
vec3 cog2cob_vec = vectorAB(pos + ROTATION_MAT * CENTER_OF_GRAVITY, CENTER_OF_BUOYANCY);
vec3 buoyancy_force = vec3(0.0, 1.0, 0.0) * (GForce * SUBMERGED_VOLUME * 999.1026);vec3 ETorque = cog2cob_vec * buoyancy_force;
elements_torque = ETorque;
/*
* Eof buoyancy effect
* ******************************************************************************************
*/
vec3 gravity_force = vec3(0.0, -1.0, 0.0) * (mass*9.81);
vec3 drag_force;vec3 form_drag;
vec3 skin_drag;
for (int i=0; i < submerged_tri_count; i++)
if (ACTUAL_FRAME[i].surface > 0.1) //do not coun't anything that is less than 10 cm^2
{
//ALOG("SKIN FRICTION PRESENT");
vec3 element_form_drag = vec3(0.0, 0.0, 0.0); //somehow i don't trust that compiler due to optimization will zero it
vec3 element_skin_drag = vec3(0.0, 0.0, 0.0);
vec3 cog2pC = vectorAB(pos + ROTATION_MAT * CENTER_OF_GRAVITY, ACTUAL_FRAME[i].pC);
vec3 local_vel = vel + AngVel * cog2pC;
vec3 vn = Normalize(local_vel);
float vv = VectorLength(local_vel);
float v2 = vv;
vv = vv * vv;
float form_percentage_coeff = absnf( acos(dot(ACTUAL_FRAME[i].normal, vn)) / float(pi) );
if (dot(ACTUAL_FRAME[i].normal, vn) <= 0.0) form_percentage_coeff = form_percentage_coeff*0.66; //suction force
element_form_drag = (-vn) * (form_percentage_coeff * (999.1026 * 0.5 * vv) * ACTUAL_FRAME[i].surface); //form drag
float skin_percentage_coeff = absnf(1.0 - form_percentage_coeff); //due to float inaccuracy
vec3 surf_n = Normal(ACTUAL_FRAME[i].V[0], ACTUAL_FRAME[i].V[1], ACTUAL_FRAME[i].V[2], true);
float surf_choordlen = getTriangleChoordLength(
-local_vel, surf_n, ACTUAL_FRAME[i].pC,
ACTUAL_FRAME[i].V[0], ACTUAL_FRAME[i].V[1], ACTUAL_FRAME[i].V[2], true, ACTUAL_FRAME[i].pC);
if (surf_choordlen > 20.0) surf_choordlen = 3.0;
//calc reynolds number
float Rn = ReynoldsNum(VectorLength(local_vel), surf_choordlen, 0.894);
bool ah = false;
if (absnf(Rn) <= 0.001 ) {Rn = 1.0; ah= true;}
float CFRn = 1.328 / (sqrt(Rn));
if (ah) CFRn = 0.0;
//float CFRn = 0.075 / (lg * lg); //1.328 / (sqrt(Rn));//
vec3 Vfi = Normalize(ProjectVectorOnPlane(ACTUAL_FRAME[i].normal, -local_vel));
element_skin_drag = (-vn) * (CFRn * ((999.1026 * vv) / 2.0 ) * ACTUAL_FRAME[i].surface * skin_percentage_coeff);
skin_drag = skin_drag + element_skin_drag;
form_drag = form_drag + element_form_drag;
cog2cob_vec = vectorAB(pos + ROTATION_MAT * CENTER_OF_GRAVITY, ACTUAL_FRAME[i].pC);
ETorque = cog2cob_vec * ( element_skin_drag + element_form_drag );
elements_torque = elements_torque + ETorque;
}
drag_force = form_drag + skin_drag;
float yv = 30.0;
vec3 vf = YPRangle.GetFrontVector(); vf.y = 0.0;
vec3 thrust_vec = vf * (1.2 * 1.250 * 0.5 * yv*yv * 800.0);
if (pos.z > 520.0)
if (!rudder_deflection)
{
TurnLeft();
}
// Rudder deflection
if (rudder_deflection)
{
float deflection_angle;
if (rudder_left) deflection_angle = 60.0;
else deflection_angle = -60.0;
Matrix44<float> rudmat;
rudmat.RotateY(deflection_angle*imopi); vec3 cog2cor_vec = vectorAB(pos + ROTATION_MAT * CENTER_OF_GRAVITY, pos + ROTATION_MAT * rudder_pos); vec3 local_vel = vel + AngVel * cog2cor_vec;
vec3 vn = Normalize(local_vel);
float vv = VectorLength(local_vel);
vv = vv * vv; rudder_force = -vn * 1.2 * ( ( 998.0 * vv) / 2.0 ) * 2.33 * 100.0;
vec3 rETorque = cog2cor_vec * rudder_force;
elements_torque = elements_torque + rETorque;
}
result_force = gravity_force + buoyancy_force + drag_force;// + thrust_vec + rudder_force;
mat4 inv_rot = ROTATION_MAT;
inv_rot.Inverse();
vec3 local_torque = inv_rot * elements_torque;
vec3 EAngAcc;
EAngAcc.x = local_torque.x / Ixx;//Ixx;
EAngAcc.y = local_torque.y / Iyy;
EAngAcc.z = local_torque.z / Izz;
EAngVel = EAngAcc*dt;
//ALOG("EAngAcc: " +POINT_TO_TEXT(EAngAcc));AngVel = AngVel + EAngVel;
vec3 vLocalAngularMoment = (AngVel*dt)*RAD_TO_DEG;
YPRangle.pitch(cos(vLocalAngularMoment.x*imopi), -sin(vLocalAngularMoment.x*imopi));
YPRangle.DoRotation();
YPRangle.yaw(cos(vLocalAngularMoment.y*imopi), sin(vLocalAngularMoment.y*imopi));
YPRangle.DoRotation();
YPRangle.roll(cos(vLocalAngularMoment.z*imopi), -sin(vLocalAngularMoment.z*imopi));
YPRangle.DoRotation();ROTATION_MAT.LoadGLMatrix(YPRangle.AIR_MATRIX);
vec3 accel = result_force / mass;
vel = vel + accel*dt;
pos = pos + vel*dt;
}void StepSim(TWaterWaves * ocean, float dt)
{
SliceHullByWater(ocean);
SliceAndCalculateSubmergedHullArea();
CalculateBuoyancy();
ShootOutSubmergedShape();
ProcessOceanFrame(ocean, dt);
}
Please help the kitten ;]