📄 ivp_buoyancy_solver.cxx
字号:
edge_O_center_os.subtract(¢er_of_ellipse_os, &O_os);
IVP_DOUBLE b = edge_O_center_os.real_length();
IVP_U_Float_Point edge_Q_center_os;
edge_Q_center_os.subtract(¢er_of_ellipse_os, &Q_os);
IVP_DOUBLE radius_of_water_disection = IVP_Inline_Math::ivp_sqrtf(IVP_Inline_Math::fabsd(radius*radius - distance*distance));
IVP_DOUBLE height = IVP_Inline_Math::fabsd(b - edge_Q_center_os.real_length());
IVP_U_Float_Point center_of_ellipse_segment;
IVP_DOUBLE surface_content_up;
if (b < buoyancy_eps) { //safety check
surface_content_up = 0.0f;
center_of_ellipse_segment.set(0.0f, 0.0f, 0.0f);
} else {
surface_content_up = b*radius_of_water_disection*IVP_Inline_Math::save_acosf(edge_Q_center_os.real_length() / b) - edge_Q_center_os.real_length()*(0.5f*length_p1p2);
//compute center of ellipse segment above water
IVP_DOUBLE s = 2 * IVP_Inline_Math::ivp_sqrtf(IVP_Inline_Math::fabsd(2*height*b - height*height));
IVP_DOUBLE ellipse_arc = 2*IVP_Inline_Math::fast_asin( s/(2*b))*b;
IVP_DOUBLE A = IVP_Inline_Math::fabsd(0.5f * (ellipse_arc * b - s*(b - height)));
if (A < buoyancy_eps) {
surface_content_up = 0.0f;
center_of_ellipse_segment.set(0.0f, 0.0f, 0.0f);
} else {
//edge_O_center_os.normize();
//edge_O_center_os.mult(-1); //change direction
center_of_ellipse_segment.set(¢er_of_ellipse_os);
//center_of_ellipse_segment.add_multiple(&edge_O_center_os, s*s*s / (12 * A));
center_of_ellipse_segment.add_multiple(&direction_up, s*s*s / (12 * A));
}
}
/*** compute results ***/
//compute ball_projected_surface_content_under
ball_projected_surface_content_under = surface_content_up + surface_content_down;
if (ball_projected_surface_content_under < buoyancy_eps) {
ball_projected_surface_content_under = 0.0f;
ball_point_of_impulse.set(0.0f, 0.0f, 0.0f);
} else {
//compute ball_point_of_impulse
ball_point_of_impulse.set_multiple(¢er_of_segment_os, surface_content_down);
ball_point_of_impulse.add_multiple(¢er_of_ellipse_segment, surface_content_up);
ball_point_of_impulse.mult(1.0f / ball_projected_surface_content_under);
}
} else { //ball flies out of the water
//calc various ellipse specific values
IVP_U_Float_Point edge_O_center_os;
edge_O_center_os.subtract(¢er_of_ellipse_os, &O_os);
IVP_DOUBLE b = edge_O_center_os.real_length();
IVP_U_Float_Point edge_Q_center_os;
edge_Q_center_os.subtract(¢er_of_ellipse_os, &Q_os);
IVP_DOUBLE radius_of_water_disection = IVP_Inline_Math::ivp_sqrtf(IVP_Inline_Math::fabsd(radius*radius - distance*distance));
IVP_DOUBLE height = IVP_Inline_Math::fabsd(b - edge_Q_center_os.real_length());
//IVP_DOUBLE length_p1p2 = p1p2_os.real_length();
//calc segment of circle above water
IVP_U_Float_Point MQ_os;
MQ_os.subtract(&Q_os, geom_center_os);
IVP_DOUBLE h = radius - MQ_os.real_length(); //height of disected segment of circle
IVP_DOUBLE arc = 2*IVP_Inline_Math::fast_asin(length_p1p2 / (2.0f * radius)) * radius; //length of arc of circle segment
IVP_DOUBLE surface_content_of_circle_segment = IVP_Inline_Math::fabsd(0.5f * (arc*radius - length_p1p2*(radius - h)));
if (surface_content_of_circle_segment < buoyancy_eps) { //safety check
//if this is the case then case 4 can be applied
goto case_4;
}
//calc segment of ellipse above water
IVP_DOUBLE surface_content_of_ellipse_segment;
if (b < buoyancy_eps) { //safety check
surface_content_of_ellipse_segment = 0.0f;
} else {
surface_content_of_ellipse_segment = b*radius_of_water_disection*IVP_Inline_Math::save_acosf(edge_Q_center_os.real_length() / b) - edge_Q_center_os.real_length()*(length_p1p2 * 0.5f);
}
IVP_DOUBLE part_ring_above_water = IVP_Inline_Math::fabsd(surface_content_of_circle_segment - surface_content_of_ellipse_segment);
//calc surface content under water (surface_content_circle - surface_content_ellipse - part_ring_above_water)
ball_projected_surface_content_under = IVP_Inline_Math::fabsd(IVP_PI*(radius*radius - radius_of_water_disection*b) - part_ring_above_water);
if (ball_projected_surface_content_under < buoyancy_eps) { //safety check
ball_projected_surface_content_under = 0.0f;
goto calculate_impulse;
}
/*** calc ball_point_of_impulse ***/
//IVP_U_Float_Point direction;
//direction.set(&edge_O_center_os);
//direction.normize();
//calc mass center of circle segment above surface
IVP_U_Float_Point center_of_circle_segment;
center_of_circle_segment.set(geom_center_os);
center_of_circle_segment.add_multiple(&direction_up, length_p1p2*length_p1p2*length_p1p2 / (12*surface_content_of_circle_segment)); //safety check already above
//calc mass center of circle segment under surface
IVP_U_Float_Point center_of_circle_segment_under_surface;
center_of_circle_segment_under_surface.set_multiple(¢er_of_circle_segment, -surface_content_of_circle_segment);
center_of_circle_segment_under_surface.add_multiple(geom_center_os, IVP_PI*radius*radius);
IVP_DOUBLE surface_content_of_circle_segment_under_surface = IVP_Inline_Math::fabsd(IVP_PI*radius*radius - surface_content_of_circle_segment);
if (surface_content_of_circle_segment_under_surface < buoyancy_eps) { //safety check
surface_content_of_circle_segment_under_surface = 0.0f;
center_of_circle_segment_under_surface.set(0.0f, 0.0f, 0.0f);
} else {
center_of_circle_segment_under_surface.mult( 1.0f / surface_content_of_circle_segment_under_surface);
}
//calc mass center of ellipse segment
IVP_U_Float_Point center_of_ellipse_segment;
IVP_DOUBLE s = 2.0f * IVP_Inline_Math::ivp_sqrtf(IVP_Inline_Math::fabsd(2*height*b - height*height));
IVP_DOUBLE ellipse_arc = 2*IVP_Inline_Math::fast_asin(s / (2*b))*b;
IVP_DOUBLE A = 0.5f * (ellipse_arc * b - s*(b - height));
if ( (b<buoyancy_eps) || (A<buoyancy_eps) ) { //safety check
center_of_ellipse_segment.set(0.0f, 0.0f, 0.0f);
} else {
center_of_ellipse_segment.set(¢er_of_ellipse_os);
center_of_ellipse_segment.add_multiple(&direction_up, s*s*s / (12 * A));
}
//calc mass center of ellipse segment under surface
IVP_U_Float_Point center_of_ellipse_segment_under_surface;
center_of_ellipse_segment_under_surface.set_multiple(¢er_of_ellipse_segment, -surface_content_of_ellipse_segment);
center_of_ellipse_segment_under_surface.add_multiple(¢er_of_ellipse_os, IVP_PI*radius_of_water_disection*b);
IVP_DOUBLE surface_content_of_ellipse_segment_under_surface = IVP_Inline_Math::fabsd(IVP_PI*radius_of_water_disection*b - surface_content_of_ellipse_segment);
if (surface_content_of_ellipse_segment_under_surface < buoyancy_eps) { //safety check
center_of_ellipse_segment_under_surface.set(0.0f, 0.0f, 0.0f);
surface_content_of_ellipse_segment_under_surface = 0.0f;
} else {
center_of_ellipse_segment_under_surface.mult( 1.0f / surface_content_of_ellipse_segment_under_surface);
}
//calc ball_point_of_impulse
ball_point_of_impulse.set_multiple(¢er_of_ellipse_segment_under_surface, -surface_content_of_ellipse_segment_under_surface);
ball_point_of_impulse.add_multiple(¢er_of_circle_segment_under_surface, surface_content_of_circle_segment_under_surface);
ball_point_of_impulse.mult( 1.0f / ball_projected_surface_content_under ); //safety check above
}
}
break;
case 4: { //center lies under surface and speed_plane_os disects completely under surface
case_4:
//check in which direction the ball is heading
IVP_DOUBLE factor = surface_os->dot_product(&speed_plane_os);
if (factor <= 0.0f) {
ball_projected_surface_content_under = IVP_PI*radius*radius; //surface content of speed_plane_os
ball_point_of_impulse.set(geom_center_os);
} else {
//compute surface content of resulting ring
IVP_DOUBLE surface_content_circle = IVP_PI*radius*radius;
IVP_DOUBLE surface_content_ellipse = factor*IVP_PI*(radius*radius - distance*distance);
ball_projected_surface_content_under = IVP_Inline_Math::fabsd(surface_content_circle - surface_content_ellipse);
if (ball_projected_surface_content_under < buoyancy_eps) { //safety check
ball_projected_surface_content_under = 0.0f;
goto calculate_impulse;
}
//compute ball_point_of_impulse
IVP_U_Float_Point projected_center_on_surface_os;
surface_os->proj_on_plane(geom_center_os, &projected_center_on_surface_os);
IVP_U_Float_Point projected_center_on_ellipse_os;
speed_plane_os.proj_on_plane(&projected_center_on_surface_os, &projected_center_on_ellipse_os);
//compute center of resulting ring by weighed sum of both the center of the whole circle and the center of the ellipse
ball_point_of_impulse.set_multiple(&projected_center_on_ellipse_os, -surface_content_ellipse);
ball_point_of_impulse.add_multiple(geom_center_os, surface_content_circle);
ball_point_of_impulse.mult( 1.0f / ball_projected_surface_content_under );
}
}
break;
default: {
}
break;
}
calculate_impulse:
IVP_DOUBLE quad_length_of_speed = rel_speed_of_current_os.quad_length();
if (quad_length_of_speed < buoyancy_eps) {
quad_length_of_speed = 0.0f;
rel_speed_of_current_os.set(0.0f, 1.0f, 0.0f); //any value, is compensated by quad_length_of_speed=0
}
IVP_DOUBLE pressure_dampening_impulse = ball_projected_surface_content_under * quad_length_of_speed * pressure_damp_factor;
//area content of ball where water flows around is approximated with the help of ball_projected_surface_content_under
IVP_DOUBLE friction_dampening_impulse = (3.0f * ball_projected_surface_content_under) * quad_length_of_speed * friction_damp_factor;
rel_speed_of_current_os.normize();
ball_impulse_vector.set_multiple( &rel_speed_of_current_os, pressure_dampening_impulse + friction_dampening_impulse );
//add the surface content that's under the water to the corresponding global variable
object_visible_surface_content_under += ball_projected_surface_content_under;
//calc the cross product between the impulse vector and the point of impulse and add it to the global variable
IVP_U_Float_Point impulse_x_point;
impulse_x_point.inline_calc_cross_product(&ball_point_of_impulse, &ball_impulse_vector);
sum_impulse_x_point.add(&impulse_x_point);
//calc the move-direction vector
//setting it to zero value
IVP_U_Float_Point move_direction_os; move_direction_os.set_to_zero();
//calc cross product between impulse_vector and move-direction vector and add it to the global variable
IVP_U_Float_Point impulse_x_movevector;
impulse_x_movevector.inline_calc_cross_product(&move_direction_os, &ball_impulse_vector);
sum_impulse_x_movevector.add(&impulse_x_movevector);
//add impulse to global variable
sum_impulse.add(&ball_impulse_vector);
}
void IVP_Buoyancy_Solver::compute_values_for_one_ball(const IVP_Real_Object *object,
const IVP_U_Float_Hesse *surface_os,
const IVP_U_Float_Point *rel_speed_of_current_os) {
//fetch some ball related values
IVP_Ball *ball = (IVP_Ball *) object;
#if 0
IVP_U_Point non_float_geom_center_ws;
IVP_U_Float_Point geom_center_ws; //the mass(!!!!) center in world space
ball->get_geom_center_world_space(&non_float_geom_center_ws);
geom_center_ws.set(&non_float_geom_center_ws);
#endif
IVP_U_Float_Point geom_center_os; geom_center_os.set_to_zero();
IVP_FLOAT radius = ball->get_radius(); //get radius of ball
//create the plane the speed has an impact on
IVP_U_Float_Hesse speed_plane_os;
IVP_FLOAT scalar_speed=rel_speed_of_current_os->quad_length();
if(scalar_speed < P_DOUBLE_EPS) {
speed_plane_os.set(0.0f,1.0f,0.0f);
} else {
speed_plane_os.set(rel_speed_of_current_os);
}
speed_plane_os.calc_hesse_val(&geom_center_os);
speed_plane_os.normize();
//the disection points of the straight (which results from the disection of surface_ws and speed_plane_ws) and the ball
IVP_U_Float_Point p1_os;
IVP_U_Float_Point p2_os;
//compute whether the ball is under or above the surface
IVP_FLOAT distance = surface_os->get_dist(&geom_center_os); //get distance of center to surface
int decision = -1;
if (distance <= 0.0f) { //center lies above surface
if (IVP_Inline_Math::fabsd(distance) >= radius) { //ball is completely above surface
return; //nothing to do
} else { //ball partly under the surface, center lies above
int location = compute_disection_points_with_ball(surface_os, &speed_plane_os, &geom_center_os, radius, &p1_os, &p2_os);
if (location) {
decision = 1; //speed_plane_os disects ball under and above the surface
} else {
decision = 2; //speed_plane_os disects ball above the surface
}
}
} else { //center lies under surface
if (distance >= radius) { //speed_plane_os and/or ball is completely under surface
decision = 0;
} else { //ball partly under the surface, center lies under
int location = compute_disection_points_with_ball(surface_os, &speed_plane_os, &geom_center_os, radius, &p1_os, &p2_os);
if (location) {
decision = 3; //speed_plane_os disects ball under and above the surface
} else {
decision = 4; //speed_plane_os disects completely under surface
}
}
}
#if 0
P_IF(1) {
IVP_U_Float_Point geom_center_ws;
IVP_U_Float_Hesse surface_ws;
{
IVP_Cache_Object *cache_object = object->get_cache_object();
cache_object->transform_vector_to_world_coords(&geom_center_os, &geom_center_ws);
cache_object->transform_vector_to_world_coords(surface_os, &surface_ws);
cache_object->remove_reference();
}
//draw debug vectors to indicate surface (dirty!)
IVP_U_Point middle(geom_center_ws.k[0], -(surface_ws.hesse_val), geom_center_ws.k[2]);
IVP_U_Point vec1(-5.0f, 0.0f, 0.0f);
IVP_U_Point vec2(5.0f, 0.0f, 0.0f);
IVP_U_Point vec3(0.0f, 0.0f, 5.0f);
IVP_U_Point vec4(0.0f, 0.0f, -5.0f);
environment->add_draw_vector(&middle,&vec1,"",2);
environment->add_draw_vector(&middle,&vec2,"",2);
environment->add_draw_vector(&middle,&vec3,"",2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -