📄 ivp_ray_solver.cxx
字号:
int tri_cnt = ledge_to_compare->get_n_triangles();
for(; --tri_cnt>=0; ){
// if plane looks in opposite direction: no hit!
IVP_U_Hesse hesse_vec_os;
IVP_CLS.calc_hesse_vec_object_not_normized(edge, ledge_to_compare, &hesse_vec_os);
IVP_DOUBLE dot_p = hesse_vec_os.dot_product(&ray_dir_os);
if(dot_p > -P_DOUBLE_RES){ // @@@ select correct EPS
// walked beyond the 'terminator'
return IVP_FALSE;
}
const IVP_U_Float_Point *p0 = IVP_CLS.give_object_coords(edge, ledge_to_compare);
IVP_DOUBLE z = hesse_vec_os.dot_product(p0);
IVP_DOUBLE a = ray_start_point.dot_product( &hesse_vec_os ) - z;
IVP_DOUBLE b = ray_end_point.dot_product( &hesse_vec_os ) - z;
if (a*b >= 0 ){
return IVP_FALSE; // does not hit because
// a>0 b>0 : both points are outside the object
// a<0 b<0 both points are inside the object, no hits possible
}
IVP_DOUBLE hit_dist = a/(a-b);
IVP_U_Point intersect_point; intersect_point.set_interpolate( &ray_start_point, &ray_end_point, hit_dist);
// what neighboring triangle shall be visited?
IVP_Unscaled_QR_Result qr;
IVP_CLS.calc_unscaled_qr_vals_F_space(ledge_to_compare, edge, &intersect_point,&qr);
// search best edge and take corresponding neighbor triangle
{
const IVP_Compact_Edge *e;
int j;
for (e=edge,j=0; j<3; e=e->get_next(),j++){
if (qr.checks[j] > 0.0f ) continue; // inside triangle
edge = e->get_opposite();
goto continue_with_next_triangle;
break;
}
}
// no movement possible anymore, take this triangle as final triangle
hit_dist *= ray_length;
hesse_vec_os.IVP_U_Point::normize();
hit_listener->add_hit_object(object, ledge_to_compare, edge->get_triangle(), hit_dist, &hesse_vec_os);
return IVP_TRUE;
continue_with_next_triangle:;
} // for (tricnt)
// now we know that we are in an endless loop
// ...
IVP_IF(1){
printf("check_ray_against_compact_ledge: endl loop.\n");
}
return IVP_FALSE;
}
}
void IVP_Ray_Solver_Os::check_ray_against_ledge_tree_node_os(const IVP_Compact_Ledgetree_Node *node){
// Recursive function
// Check whether ray hits the ledge tree node sphere
IVP_U_Float_Point center; center.set( node->center.k);
IVP_BOOL ray_hits_sphere = this->check_ray_against_sphere_os(¢er, node->radius);
if(!ray_hits_sphere) return; // no hit
// Check ledge that is contained by this node.
if(node->is_terminal() == IVP_TRUE){
const IVP_Compact_Ledge *ledge = node->get_compact_ledge();
this->check_ray_against_compact_ledge_os(ledge);
return;
}
// check nodes children
check_ray_against_ledge_tree_node_os(node->left_son());
check_ray_against_ledge_tree_node_os(node->right_son());
}
void IVP_Ray_Solver_Os::check_ray_against_compact_surface_os(const IVP_Compact_Surface *compact_surface_to_compare){
// Checks wether the specified compact surface is hit by the specified ray.
// Adds the corresponding object to the min hash for each hit compact ledge.
const IVP_Compact_Ledgetree_Node *lt_node_root;
lt_node_root = compact_surface_to_compare->get_compact_ledge_tree_root();
check_ray_against_ledge_tree_node_os(lt_node_root);
}
IVP_Ray_Solver_Os::IVP_Ray_Solver_Os(class IVP_Ray_Solver *so, IVP_Real_Object *obj){
object = obj;
hit_listener = so;
IVP_Cache_Object *co = object->get_cache_object_no_lock();
co->transform_position_to_object_coords(&so->ray_start_point, &this->ray_start_point);
co->transform_vector_to_object_coords(&so->ray_direction, &this->ray_direction);
this->ray_length = so->ray_length;
this->ray_end_point.add_multiple( &this->ray_start_point, &this->ray_direction, this->ray_length);
this->ray_center_point.set(&this->ray_start_point);
this->ray_center_point.add_multiple( &this->ray_direction, this->ray_length * 0.5f);
//co->remove_reference();
}
void IVP_Ray_Solver::check_ray_against_ball(IVP_Ball *ball)
{
// what is the exact hit distance (if any)?
IVP_Cache_Object *co = ball->get_cache_object_no_lock();
IVP_U_Float_Point center_ws;
center_ws.set( co->m_world_f_object.get_position());
// does ray start inside the ball?
IVP_DOUBLE quad_sphere_radius = ball->get_radius() * ball->get_radius();
IVP_DOUBLE quad_delta_len = ray_start_point.quad_distance_to(¢er_ws);
if(quad_delta_len < quad_sphere_radius){
//IVP_U_Point dummy_dir(0,1,0);
//dummy_dir.set_to_zero();
//this->add_hit_object(ball, NULL, NULL, 0.0f, &dummy_dir);
return;
}
// calculate hit distance
IVP_U_Point equ; // quadratic equation
IVP_U_Point delta;
delta.subtract(&ray_start_point, ¢er_ws);
equ.k[0] = 1.0f;
equ.k[1] = 2.0f * delta.dot_product(&ray_direction);
equ.k[2] = quad_delta_len - quad_sphere_radius;
IVP_U_Point solution;
solution.solve_quadratic_equation_accurate(&equ); //TL: was fast
if(solution.k[0] < 0.0f) return; // sphere missed!
IVP_FLOAT hit_dist = (IVP_FLOAT)solution.k[1];
if(hit_dist < 0.0f){
hit_dist = (IVP_FLOAT)solution.k[2];
if(hit_dist < 0.0f) return; // hit lies in negative ray direction
}
IVP_U_Point sur_hit_point;
sur_hit_point.add_multiple(&ray_start_point, &ray_direction, hit_dist);
IVP_U_Point hit_sur_normal;
hit_sur_normal.subtract(&sur_hit_point, ¢er_ws);
if(hit_sur_normal.normize()!=IVP_OK) {
hit_sur_normal.set(1.0f, 0.0f, 0.0f);
}
add_hit_object(ball, NULL, NULL, hit_dist, &hit_sur_normal);
}
void IVP_Ray_Solver::check_ray_against_object(IVP_Real_Object *object){
// Checks wether the specified object is hit by the specified ray.
// Adds the corresponding object to the min hash for each hit.
// check flags
if (object){
if(ray_flags & IVP_RAY_SOLVER_IGNORE_PHANTOMS){
if (object->get_controller_phantom())
return;
}
if(ray_flags & IVP_RAY_SOLVER_IGNORE_MOVINGS){
if (!IVP_MTIS_IS_STATIC(object->get_movement_state()))
return;
}
if(ray_flags & IVP_RAY_SOLVER_IGNORE_STATICS){
if (IVP_MTIS_IS_STATIC(object->get_movement_state()))
return;
}
}
IVP_OBJECT_TYPE type = object->get_type();
switch(type){
case IVP_BALL:
{
IVP_Ball *ball = object->to_ball();
this->check_ray_against_ball(ball);
break;
}
case IVP_POLYGON:
{
IVP_Polygon *poly = object->to_poly();
IVP_SurfaceManager *surman = poly->get_surface_manager();
// Check all ledges within ray radius
surman->insert_all_ledges_hitting_ray(this, poly);
break;
}
default:
break;
}
}
void IVP_Ray_Solver_Group::check_ray_group_against_object(IVP_Real_Object *object){
// Checks wether the specified object is hit by the specified ray.
// Adds the corresponding object to the min hash for each hit.
// check flags
if (object){
IVP_RAY_SOLVER_FLAGS ray_flags = ray_solvers[0]->ray_flags;
if(ray_flags & IVP_RAY_SOLVER_IGNORE_PHANTOMS){
if (object->get_controller_phantom())
return;
}
if(ray_flags & IVP_RAY_SOLVER_IGNORE_MOVINGS){
if (!IVP_MTIS_IS_STATIC(object->get_movement_state()))
return;
}
if(ray_flags & IVP_RAY_SOLVER_IGNORE_STATICS){
if (IVP_MTIS_IS_STATIC(object->get_movement_state()))
return;
}
}
IVP_OBJECT_TYPE type = object->get_type();
switch(type){
case IVP_BALL:
{
IVP_Ball *ball = object->to_ball();
for (int i = n_ray_solvers-1; i>=0;i--){
ray_solvers[i]->check_ray_against_ball(ball);
}
break;
}
case IVP_POLYGON:
{
IVP_Polygon *poly = object->to_poly();
IVP_SurfaceManager *surman = poly->get_surface_manager();
for (int i = n_ray_solvers-1; i>=0;i--){
surman->insert_all_ledges_hitting_ray(ray_solvers[i], poly);
}
// Check all ledges within ray radius
break;
}
default:
break;
}
}
void IVP_Ray_Solver::check_ray_against_node(IVP_OV_Node *node, IVP_OV_Tree_Manager *ov_tree_man) {
// Recursive function
// Check whether ray hits the long range cluster node.
IVP_U_Float_Point luf_point, rlb_point; // left upper front / right lower back
IVP_FLOAT cubesize;
ov_tree_man->get_luf_coordinates_ws(node, &luf_point, &cubesize); // fills vars with left-upper-front corner's coordinates
rlb_point.set(luf_point.k[0]+cubesize, luf_point.k[1]+cubesize, luf_point.k[2]+cubesize);
IVP_BOOL ray_hits_cube = this->check_ray_against_cube(&luf_point, &rlb_point);
if(!ray_hits_cube) return; // not hit
// Check all objects that are contained by this node.
{
int i;
for(i=node->elements.len()-1; i>=0; --i){
IVP_OV_Element *elem = node->elements.element_at(i);
// Does ray hit object's surrounding sphere?
IVP_Core *core = elem->real_object->get_core();
IVP_U_Float_Point object_center_os(core->get_position_PSI());
IVP_BOOL ray_hits_sphere = check_ray_against_sphere(&object_center_os, core->upper_limit_radius);
if(ray_hits_sphere){
this->check_ray_against_object(elem->real_object);
}
}
}
// Check node's children.
{
int i;
for(i=node->children.len()-1; i>=0; --i){
IVP_OV_Node *child_node = node->children.element_at(i);
this->check_ray_against_node(child_node, ov_tree_man);
}
}
}
void IVP_Ray_Solver_Group::check_ray_group_against_node(IVP_OV_Node *node, IVP_OV_Tree_Manager *ov_tree_man) {
// Recursive function
// Check whether ray hits the long range cluster node.
IVP_U_Float_Point luf_point, cube_center_point; // left upper front / right lower back
IVP_FLOAT cubesize;
ov_tree_man->get_luf_coordinates_ws(node, &luf_point, &cubesize); // fills vars with left-upper-front corner's coordinates
IVP_FLOAT csh = cubesize * 0.5f;
cube_center_point.set( luf_point.k[0] + csh, luf_point.k[1] + csh, luf_point.k[2] + csh );
IVP_BOOL ray_hits_cube = this->check_ray_group_against_cube(&cube_center_point, cubesize);
if(!ray_hits_cube) return; // not hit
// Check all objects that are contained by this node.
{
int i;
for(i=node->elements.len()-1; i>=0; --i){
IVP_OV_Element *elem = node->elements.element_at(i);
// Does ray hit object's surrounding sphere?
IVP_Core *core = elem->real_object->get_core();
IVP_U_Float_Point object_center_os(core->get_position_PSI());
IVP_BOOL ray_hits_sphere = check_ray_group_against_sphere(&object_center_os, core->upper_limit_radius);
if(ray_hits_sphere){
this->check_ray_group_against_object(elem->real_object);
}
}
}
// Check node's children.
{
int i;
for(i=node->children.len()-1; i>=0; --i){
IVP_OV_Node *child_node = node->children.element_at(i);
this->check_ray_group_against_node(child_node, ov_tree_man);
}
}
}
void IVP_Ray_Solver::check_ray_against_all_objects_in_sim(const IVP_Environment *environment)
{
// Checks wether any object in long range tree is hit by the specified ray.
// Returns IVP_TRUE and adds the corresponding objects each time they are hit.
// Returns IVP_FALSE if the object is not hit by the ray.
// get root node from long range cluster manager
IVP_OV_Tree_Manager *ov_tree_man = environment->get_ov_tree_manager();
if(!ov_tree_man) return;
IVP_OV_Node *node = ov_tree_man->root;
check_ray_against_node(node, ov_tree_man);
}
void IVP_Ray_Solver_Group::check_ray_group_against_all_objects_in_sim(const IVP_Environment *environment){
// Checks wether any object in long range tree is hit by the specified ray.
// Returns IVP_TRUE and adds the corresponding objects each time they are hit.
// Returns IVP_FALSE if the object is not hit by the ray.
// get root node from long range cluster manager
IVP_OV_Tree_Manager *ov_tree_man = environment->get_ov_tree_manager();
if(!ov_tree_man) return;
IVP_OV_Node *node = ov_tree_man->root;
check_ray_group_against_node(node, ov_tree_man);
}
IVP_Ray_Solver_Group::IVP_Ray_Solver_Group( int n_ray_solvers_, IVP_Ray_Solver **ray_solvers_ ){
ray_solvers = ray_solvers_;
n_ray_solvers = n_ray_solvers_;
center_ws.set_to_zero();
for (int i =0; i < n_ray_solvers; i++){
center_ws.add( &ray_solvers[i]->ray_center_point );
}
center_ws.mult(1.0f / n_ray_solvers);
IVP_DOUBLE qradius = 0.0f;
for (int j = 0; j < n_ray_solvers; j++){
IVP_DOUBLE qdist = ray_solvers[j]->ray_start_point.quad_distance_to( ¢er_ws );
if (qdist > qradius) qradius = qdist;
qdist = ray_solvers[j]->ray_end_point.quad_distance_to( ¢er_ws );
if (qdist > qradius) qradius = qdist;
}
radius = IVP_Inline_Math::sqrtd(qradius);
}
void IVP_Ray_Solver_Min::add_hit_object(IVP_Real_Object *object, const IVP_Compact_Ledge *compact_ledge, const IVP_Compact_Triangle *compact_triangle, IVP_DOUBLE hit_dist, IVP_U_Point *hit_sur_vec_os){
if (hit_dist >= this->min_dist) return;
min_dist = hit_dist;
ray_hit.hit_real_object = object;
ray_hit.hit_compact_ledge = compact_ledge;
ray_hit.hit_compact_triangle = compact_triangle;
ray_hit.hit_distance = hit_dist;
ray_hit.hit_surface_direction_os.set( hit_sur_vec_os);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -