bool CPicoSurface::TestRay (const ray_t *ray, vec_t *dist) const { int i; vec_t start_dist = *dist; vec_t local_dist = *dist; if (aabb_intersect_ray(&m_BBox, ray, &local_dist)) { switch( PicoGetSurfaceType(m_pSurface) ) { case PICO_TRIANGLES: for (i=0; i<PicoGetSurfaceNumIndexes(m_pSurface); i+=3) { local_dist = ray_intersect_triangle(ray, true, PicoGetSurfaceXYZ(m_pSurface,PicoGetSurfaceIndex(m_pSurface,i+2)), PicoGetSurfaceXYZ(m_pSurface,PicoGetSurfaceIndex(m_pSurface,i+1)), PicoGetSurfaceXYZ(m_pSurface,PicoGetSurfaceIndex(m_pSurface,i))); if (local_dist < *dist) *dist = local_dist; } break; default: Sys_Printf( "ERROR: Unsupported Pico Surface Type: %i", PicoGetSurfaceType(m_pSurface) ); break; } } return (*dist < start_dist); }
static void find_nearest_block(struct group *group, struct ray const *ray, struct nearest *nearest) { struct groupdata *groupdata = group->data; struct ray groupspaceray; vec3_subtract(&groupspaceray.origin, &ray->origin, &group->position); groupspaceray.direction = ray->direction; buffer *buffer = create_buffer(); ptrarray *blocks = groupdata->blocks; size_t blockcount = ptrarray_count(blocks); for (size_t i = 0; i < blockcount; ++i) { block *block = get_ptrarray(blocks, i); get_block_triangles(block, buffer); triangle *tris = buffer_data(buffer); size_t tricount = buffer_count(buffer, sizeof(struct triangle)); for (size_t j = 0; j < tricount; ++j) { float temp; if (ray_intersect_triangle(&temp, &groupspaceray, &tris[j])) { /* * Use <= for distance comparsion here so that when there are * multiple candidates for selection the last block added will * be selected. It is useful after pasting that the new blocks * can be dragged to a new location. */ if (temp <= nearest->distance) { nearest->distance = temp; nearest->group = group; nearest->block = block; nearest->triangle = tris[j]; } } } clear_buffer(buffer); } destroy_buffer(buffer); struct ptrarray *groups = groupdata->groups; size_t groupcount = ptrarray_count(groups); for (size_t i = 0; i < groupcount; ++i) { struct group *childgroup = get_ptrarray(groups, i); find_nearest_block(childgroup, ray, nearest); } }
DTboolean PrimitiveCollisions::extruded_sphere_intersect_triangle ( const Vector3 &from, const Vector3 &to, const Sphere &s, const Vector3 &vert0, const Vector3 &vert1, const Vector3 &vert2, DTfloat &t, Vector3 &n, Vector3 &p) { Vector3 temp, from_offset, to_offset; Plane plane; // set up the plane plane.set(vert0, vert1, vert2); // get distance DTfloat from_dist = plane.distance_to_point(from); DTfloat to_dist = plane.distance_to_point(to); // Make sure it could potentially be colliding if (to_dist > s.radius() || from_dist < 0.0F || from_dist <= to_dist) return false; // Offset the from and to vectors by the radius of the sphere Vector3::displace(from, plane.normal(), -s.radius(), from_offset); Vector3::displace(to, plane.normal(), -s.radius(), to_offset); // If we have made it this far, we know that the closest spot on the sphere to // the plane crosses the plane boundary. // Check the case where the ray intersects the triangle if (ray_intersect_triangle(from_offset, to_offset, vert0, vert1, vert2, t, n, p)) return true; // Even if the ray doesn't intersect the triangle, the sphere might touch an edge const Vector3* verts[] = { &vert0, &vert1, &vert2 }; // references to verts DTfloat r_squared = s.radius()*s.radius(); // save the values for the vertices DTfloat kss_save[3]; DTfloat kgs_save[3]; DTfloat kgg_save[3]; // Some intermediate calcs that don't change in the loop Vector3 ks; ks = to - from; DTfloat kss; kss = Vector3::dot(ks,ks); // Mark that we haven't found a collision yet DTboolean found_collision = false; for (DTint i = 0; i < 3; ++i) { DTint j = (i+1) % 3; // next index // Some intermediate calcs that do change in the loop Vector3 ke, kg; ke = *verts[j] - *verts[i]; kg = *verts[i] - from; DTfloat kee,kes,kgs,keg,kgg; kee = Vector3::dot(ke,ke); keg = Vector3::dot(ke,kg); kes = Vector3::dot(ke,ks); kgg = Vector3::dot(kg,kg); kgs = Vector3::dot(kg,ks); // save a few values for vertex collision later kss_save[i] = kss; kgs_save[i] = kgs; kgg_save[i] = kgg; // Coefficients of quadratic DTfloat a,b,c; a = kee*kss - kes*kes; b = 2.0F * (keg*kes - kee*kgs); c = kee * (kgg - r_squared) - keg * keg; // Calculate collision time by solving quadratic DTfloat t0,t1; MoreMath::solve_quadratic (a, b, c, t0, t1); // sort the t's if (t1 < t0) std::swap(t0,t1); // Pick a t DTfloat test_t; if (t0 >= 0.0F && t0 <= t) test_t = t0; else if (t1 >= 0.0F && t1 <= t) test_t = t1; else continue; // t not in 0-t range // find distance along edge to collision Vector3 ct; DTfloat d; ct = ks * test_t; ct = ct + from - *verts[i]; d = Vector3::dot(ct, ke); d = d / kee; // Check for d in 0-1 range if (d < 0.0F || d > 1.0F) continue; // We have found a collision with an edge t = test_t; // Calculate a normal Vector3 d_pos; d_pos = ke * d; n = ct - d_pos; // Calculate contact point Vector3::displace(*verts[i], ke, d, p); found_collision = true; } // If we've found an edge collision, we are done if (found_collision) return true; // Check the vertices for (DTint i = 0; i < 3; ++i) { // Calculate collision time DTfloat t0,t1; MoreMath::solve_quadratic (kss_save[i], -2.0F * kgs_save[i], kgg_save[i] - r_squared, t0, t1); // sort the t's if (t1 < t0) std::swap(t0,t1); // Pick a t if (t0 >= 0.0F && t0 <= t) t = t0; else if (t1 >= 0.0F && t1 <= t) t = t1; else continue; // t not in 0-t range // update normal Vector3 ct; Vector3::displace(from, ks, t, ct); n = ct - *verts[i]; // Calc contact point - same as vertex p = *verts[i]; found_collision = true; } // return the results return found_collision; }
void ray_intersect_mesh_list_initial(ray_scene_type *scene,ray_scene_slice_type *slice,ray_point_type *eye_point,ray_vector_type *eye_vector,ray_collision_type *collision) { int n,mesh_idx,poly_idx,trig_idx, list_idx,poly_count; float it,iu,iv; ray_point_type trig_pnt; ray_mesh_type *mesh; ray_poly_type *poly; ray_trig_type *trig; ray_material_type *material; ray_collision_type tmp_collision; // clear collision // anything > 1.0f is outside // the max eye distance collision->mesh_idx=-1; collision->poly_idx=-1; collision->trig_idx=-1; collision->t=1.0f; // run through the mesh-polys // for initial collisions, we use the // slice mesh list, which has been pared // down for the slice's pixel box, // hidden, and non-ray trace blocking // we don't bound check the meshes because // the slices are small enough that we will // almost always hit this pared down list list_idx=0; while (list_idx<slice->mesh_pack_list.idx) { mesh_idx=slice->mesh_pack_list.list[list_idx++]; poly_count=slice->mesh_pack_list.list[list_idx++]; mesh=scene->mesh_list.meshes[mesh_idx]; // check the polygons for (n=0;n!=poly_count;n++) { poly_idx=slice->mesh_pack_list.list[list_idx++]; poly=&mesh->poly_block.polys[poly_idx]; if (!ray_bound_ray_collision(eye_point,eye_vector,&poly->bound)) continue; // check triangle/ray intersection // we don't do bound checking as it's // about as fast as the intersection test // first hit exits out of polygons as you // can only hit one triangle of a polygon for (trig_idx=0;trig_idx!=poly->trig_block.count;trig_idx++) { trig=&poly->trig_block.trigs[trig_idx]; // have we intersected this triangle // closer to the last hit? if (!ray_intersect_triangle(scene,eye_point,eye_vector,mesh,trig,&it,&iu,&iv)) continue; if (it>collision->t) continue; // special check for // alpha==0.0f, which is a skip material=ray_global.material_list.materials[poly->material_idx]; if (!material->no_alpha) { tmp_collision.t=it; tmp_collision.u=iu; tmp_collision.v=iv; tmp_collision.mesh_idx=mesh_idx; tmp_collision.poly_idx=poly_idx; tmp_collision.trig_idx=trig_idx; ray_vector_find_line_point_for_T(eye_point,eye_vector,it,&trig_pnt); if (ray_get_material_alpha(scene,eye_point,&trig_pnt,&tmp_collision)==0.0f) break; } // if material is a tint, then add the tint // and continue on to next hit if (material->alpha_type==RL_MATERIAL_ALPHA_ADDITIVE) { if (collision->tint_block.count<ray_max_tint_per_pixel) { tmp_collision.t=it; tmp_collision.u=iu; tmp_collision.v=iv; tmp_collision.mesh_idx=mesh_idx; tmp_collision.poly_idx=poly_idx; tmp_collision.trig_idx=trig_idx; ray_get_material_color(scene,eye_point,&trig_pnt,&tmp_collision,&collision->tint_block.tints[collision->tint_block.count].col); collision->tint_block.tints[collision->tint_block.count].t=it; collision->tint_block.count++; } break; } // set the hit and exit out // of the trig loop collision->t=it; collision->u=iu; collision->v=iv; collision->mesh_idx=mesh_idx; collision->poly_idx=poly_idx; collision->trig_idx=trig_idx; break; } } } }
bool ray_block_light(ray_scene_type *scene,ray_scene_slice_type *slice,ray_point_type *pnt,ray_vector_type *vct,ray_vector_type *normal_vct,float vct_dist,ray_collision_type *collision,int light_idx,int light_collide_idx) { int k,mesh_idx,poly_idx,trig_idx, list_idx,poly_count; float t,u,v; ray_point_type trig_pnt; ray_light_type *light; ray_mesh_type *mesh; ray_poly_type *poly; ray_trig_type *trig; ray_collision_type lit_collision; ray_scene_slice_likey_block_type *likely_block; ray_mesh_poly_pack_list *pack_list; // any possible blocking polygons? light=scene->light_list.lights[light_idx]; if (light->mesh_poly_pack_collide_list.idx==0) return(FALSE); // slices remember the last poly // that blocked them reaching a certain light // we can assume that in a lot of cases, the same // polygon will be a blocker, so this is // a good optimization // only polygons that are setup to block light // (non-alpha, etc) will not be in this list, so // other checks can be skipped likely_block=&slice->likely_block[light_idx]; if (likely_block->mesh_idx!=-1) { if ((collision->mesh_idx!=likely_block->mesh_idx) || (collision->poly_idx!=likely_block->poly_idx)) { mesh=scene->mesh_list.meshes[likely_block->mesh_idx]; poly=&mesh->poly_block.polys[likely_block->poly_idx]; for (trig_idx=0;trig_idx!=poly->trig_block.count;trig_idx++) { trig=&poly->trig_block.trigs[trig_idx]; if (!ray_intersect_triangle(scene,pnt,vct,mesh,trig,&t,&u,&v)) continue; if (t<1.0f) return(TRUE); } } } // check the list of possible // light to mesh collision // this list has been precalced and // already pared down non-render, // non-hidden, and non-light blocking // and only polygons within the light cone mesh=scene->mesh_list.meshes[collision->mesh_idx]; pack_list=&mesh->light_collide.lights[light_collide_idx].mesh_poly_pack_block_list; list_idx=0; while (list_idx<pack_list->idx) { mesh_idx=pack_list->list[list_idx++]; poly_count=pack_list->list[list_idx++]; mesh=scene->mesh_list.meshes[mesh_idx]; if (!ray_bound_ray_collision(pnt,vct,&mesh->bound)) { list_idx+=poly_count; continue; } for (k=0;k!=poly_count;k++) { poly_idx=pack_list->list[list_idx++]; poly=&mesh->poly_block.polys[poly_idx]; if (!ray_bound_ray_collision(pnt,vct,&poly->bound)) continue; if (!ray_plane_ray_collision(pnt,normal_vct,vct_dist,&poly->plane)) continue; // skip self if ((collision->mesh_idx==mesh_idx) && (collision->poly_idx==poly_idx)) continue; // check trigs for (trig_idx=0;trig_idx!=poly->trig_block.count;trig_idx++) { trig=&poly->trig_block.trigs[trig_idx]; // check for intersection, but // only except t that is less 1.0f, otherwise // we've gone past the light if (!ray_intersect_triangle(scene,pnt,vct,mesh,trig,&t,&u,&v)) continue; if (t>=1.0f) continue; // if no alpha, then it's // automatically a blocking hit // and also becomes a quick hit polygon if (ray_global.material_list.materials[poly->material_idx]->no_alpha) { likely_block->mesh_idx=mesh_idx; likely_block->poly_idx=poly_idx; return(TRUE); } // setup the collision // so we can check the alpha lit_collision.t=t; lit_collision.u=u; lit_collision.v=v; lit_collision.mesh_idx=mesh_idx; lit_collision.poly_idx=poly_idx; lit_collision.trig_idx=trig_idx; ray_vector_find_line_point_for_T(pnt,vct,t,&trig_pnt); if (ray_get_material_alpha(scene,pnt,&trig_pnt,&lit_collision)==1.0f) return(TRUE); } } } // reset likely block likely_block->mesh_idx=-1; return(FALSE); }
void ray_intersect_mesh_list_other_bounce(ray_scene_type *scene,ray_scene_slice_type *slice,ray_point_type *eye_point,ray_vector_type *eye_vector,ray_vector_type *eye_normal_vector,ray_collision_type *collision) { int n,mesh_idx,poly_idx,trig_idx, list_idx,poly_count; float it,iu,iv; bool skip; ray_point_type trig_pnt; ray_mesh_type *mesh; ray_poly_type *poly; ray_trig_type *trig; ray_material_type *material; ray_collision_type tmp_collision; // clear collision // anything > 1.0f is outside // the max eye distance collision->mesh_idx=-1; collision->poly_idx=-1; collision->trig_idx=-1; collision->t=1.0f; // run through the meshes // for bounces, we need to retreat to the // main scene list because bounces could go // in any direction list_idx=0; while (list_idx<scene->render.view_mesh_pack_list.idx) { mesh_idx=scene->render.view_mesh_pack_list.list[list_idx++]; poly_count=scene->render.view_mesh_pack_list.list[list_idx++]; mesh=scene->mesh_list.meshes[mesh_idx]; // main list isn't pared down // for flags, so we need to do that if ((mesh->flags&RL_MESH_FLAG_NON_BOUNCE_TRACE_BLOCKING)!=0) { list_idx+=poly_count; continue; } // mesh bounds check if (!ray_bound_ray_collision(eye_point,eye_vector,&mesh->bound)) { list_idx+=poly_count; continue; } // run through the polys // the view mesh list is just meshes and all // poly counts are 0 for (poly_idx=0;poly_idx!=mesh->poly_block.count;poly_idx++) { // bounds check poly=&mesh->poly_block.polys[poly_idx]; if (!ray_bound_ray_collision(eye_point,eye_vector,&poly->bound)) continue; // supergumba -- plane collisions are bad here, will need to check //if (!ray_plane_ray_collision(eye_point,eye_normal_vector,scene->eye.max_dist,&poly->plane)) continue; // skiping polys, this is used // so reflections or pass throughs // so we don't re-hit any polys we've // already hit. note this means we will // only bounce off a surface once but we // won't have problems with overlayed polygons skip=FALSE; for (n=0;n!=collision->skip_block.count;n++) { if ((mesh_idx==collision->skip_block.skips[n].mesh_idx) && (poly_idx==collision->skip_block.skips[n].poly_idx)) { skip=TRUE; break; } } if (skip) continue; // check triangle/ray intersection // we don't do bound checking as it's // about as fast as the intersection test // first hit exits out of polygons as you // can only hit one triangle of a polygon for (trig_idx=0;trig_idx!=poly->trig_block.count;trig_idx++) { trig=&poly->trig_block.trigs[trig_idx]; // have we intersected this triangle // closer to the last hit? if (!ray_intersect_triangle(scene,eye_point,eye_vector,mesh,trig,&it,&iu,&iv)) continue; if (it>collision->t) continue; // special check for // alpha==0.0f, which is a skip material=ray_global.material_list.materials[poly->material_idx]; if (!material->no_alpha) { tmp_collision.t=it; tmp_collision.u=iu; tmp_collision.v=iv; tmp_collision.mesh_idx=mesh_idx; tmp_collision.poly_idx=poly_idx; tmp_collision.trig_idx=trig_idx; ray_vector_find_line_point_for_T(eye_point,eye_vector,it,&trig_pnt); if (ray_get_material_alpha(scene,eye_point,&trig_pnt,&tmp_collision)==0.0f) break; } // if material is a tint, then add the tint // and continue on to next hit if (material->alpha_type==RL_MATERIAL_ALPHA_ADDITIVE) { if (collision->tint_block.count<ray_max_tint_per_pixel) { tmp_collision.t=it; tmp_collision.u=iu; tmp_collision.v=iv; tmp_collision.mesh_idx=mesh_idx; tmp_collision.poly_idx=poly_idx; tmp_collision.trig_idx=trig_idx; ray_get_material_color(scene,eye_point,&trig_pnt,&tmp_collision,&collision->tint_block.tints[collision->tint_block.count].col); collision->tint_block.tints[collision->tint_block.count].t=it; collision->tint_block.count++; } break; } // set the hit and exit out // of the trig loop collision->t=it; collision->u=iu; collision->v=iv; collision->mesh_idx=mesh_idx; collision->poly_idx=poly_idx; collision->trig_idx=trig_idx; break; } } } }
void ray_intersect_mesh_list_pass_through_bounce(ray_scene_type *scene,ray_scene_slice_type *slice,ray_point_type *eye_point,ray_vector_type *eye_vector,ray_collision_type *collision) { int n,mesh_idx,poly_idx,trig_idx, list_idx,poly_count; float it,iu,iv; bool skip; ray_point_type trig_pnt; ray_mesh_type *mesh; ray_poly_type *poly; ray_trig_type *trig; ray_material_type *material; ray_collision_type tmp_collision; // clear collision // anything > 1.0f is outside // the max eye distance collision->mesh_idx=-1; collision->poly_idx=-1; collision->trig_idx=-1; collision->t=1.0f; // run through the meshes // these bounces have only hit // materials that are pass through, // so we can remain on the slice list list_idx=0; while (list_idx<slice->mesh_pack_list.idx) { mesh_idx=slice->mesh_pack_list.list[list_idx++]; poly_count=slice->mesh_pack_list.list[list_idx++]; mesh=scene->mesh_list.meshes[mesh_idx]; // check the polygons for (n=0;n!=poly_count;n++) { poly_idx=slice->mesh_pack_list.list[list_idx++]; poly=&mesh->poly_block.polys[poly_idx]; if (!ray_bound_ray_collision(eye_point,eye_vector,&poly->bound)) continue; // skiping polys, this is used // so reflections or pass throughs // so we don't re-hit any polys we've // already hit. note this means we will // only bounce off a surface once but we // won't have problems with overlayed polygons skip=FALSE; for (n=0;n!=collision->skip_block.count;n++) { if ((mesh_idx==collision->skip_block.skips[n].mesh_idx) && (poly_idx==collision->skip_block.skips[n].poly_idx)) { skip=TRUE; break; } } if (skip) continue; // check triangle/ray intersection // we don't do bound checking as it's // about as fast as the intersection test // first hit exits out of polygons as you // can only hit one triangle of a polygon for (trig_idx=0;trig_idx!=poly->trig_block.count;trig_idx++) { trig=&poly->trig_block.trigs[trig_idx]; // have we intersected this triangle // closer to the last hit? if (!ray_intersect_triangle(scene,eye_point,eye_vector,mesh,trig,&it,&iu,&iv)) continue; if (it>collision->t) continue; // special check for // alpha==0.0f, which is a skip material=ray_global.material_list.materials[poly->material_idx]; if (!material->no_alpha) { tmp_collision.t=it; tmp_collision.u=iu; tmp_collision.v=iv; tmp_collision.mesh_idx=mesh_idx; tmp_collision.poly_idx=poly_idx; tmp_collision.trig_idx=trig_idx; ray_vector_find_line_point_for_T(eye_point,eye_vector,it,&trig_pnt); if (ray_get_material_alpha(scene,eye_point,&trig_pnt,&tmp_collision)==0.0f) break; } // if material is a tint, then add the tint // and continue on to next hit if (material->alpha_type==RL_MATERIAL_ALPHA_ADDITIVE) { if (collision->tint_block.count<ray_max_tint_per_pixel) { tmp_collision.t=it; tmp_collision.u=iu; tmp_collision.v=iv; tmp_collision.mesh_idx=mesh_idx; tmp_collision.poly_idx=poly_idx; tmp_collision.trig_idx=trig_idx; ray_get_material_color(scene,eye_point,&trig_pnt,&tmp_collision,&collision->tint_block.tints[collision->tint_block.count].col); collision->tint_block.tints[collision->tint_block.count].t=it; collision->tint_block.count++; } break; } // set the hit and exit out // of the trig loop collision->t=it; collision->u=iu; collision->v=iv; collision->mesh_idx=mesh_idx; collision->poly_idx=poly_idx; collision->trig_idx=trig_idx; break; } } } }