// Using the same parameters as the previous function Spheres *intersect_scene(Point o, Vector u, Spheres *sph, Point *hit) { // Set up variables Spheres *sphereInput = sph; Spheres *nearestSphere = NULL;// NULL since we have not detected an intersection yet float distance, intersectionPoint; bool isCloser, PosIntersect; distance = FLT_MAX; // The farthest distance initially while (sphereInput != NULL){ // Calculate intersection intersectionPoint = intersect_sphere(o, u, sphereInput, hit); // Intersection conditions isCloser = distance > intersectionPoint; PosIntersect = (intersectionPoint != -1.0); // Check if it intersects if ( isCloser && PosIntersect ){ distance = intersectionPoint; nearestSphere = sphereInput; } // Move on to the next sphere sphereInput = sphereInput->next; } return nearestSphere; }
/********************************************************************* * This function returns a pointer to the sphere object that the * ray intersects first; NULL if no intersection. You should decide * which arguments to use for the function. For exmaple, note that you * should return the point of intersection to the calling function. **********************************************************************/ Spheres *intersect_scene(Point o, Vector u, Spheres *sph, Point *hit, int sindex) { Spheres *closest_sph = NULL; Point closest_hit; float min = -1; while (sph != NULL) { // skips this sphere (used for shadows) if (sph->index == sindex) { sph = sph->next; continue; } Point hit; float intersect; if (sph->index == 0) intersect = intersect_board(o, u, sph, &hit); else intersect = intersect_sphere(o, u, sph, &hit); if ( intersect > 0 && (intersect < min || min < 0) ) { min = intersect; closest_sph = sph; closest_hit = hit; } sph = sph->next; } if (hit != NULL) *hit = closest_hit; return closest_sph; }
// intersects the scene and return for any intersection bool intersect_shadow(Scene* scene, ray3f ray) { // foreach surface for(auto surface : scene->surfaces) { // if it is a quad if(surface->isquad) { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect quad if(intersect_quad(tray, surface->radius)) return true; } else { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect sphere if(intersect_sphere(tray, surface->radius)) return true; } } // foreach mesh for(auto mesh : scene->meshes) { // quads are not supported: check for error error_if_not(mesh->quad.empty(), "quad intersection is not supported"); // tranform the ray auto tray = transform_ray_inverse(mesh->frame, ray); // if it is accelerated if(mesh->bvh) { if(intersect_shadow(mesh->bvh, 0, tray, [mesh](int tid, ray3f tray){ // grab triangle auto triangle = mesh->triangle[tid]; // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // return if intersected return intersect_triangle(tray, v0, v1, v2);})) return true; } else { // foreach triangle for(auto triangle : mesh->triangle) { // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // intersect triangle if(intersect_triangle(tray, v0, v1, v2)) return true; } } } // no intersection found return false; }
/* intersect: check if ray intersects with object, return hit_test */ hit_test intersect(ray r, object obj) { switch (obj.tag) { case SPHERE : return intersect_sphere(r,obj); case POSTER : return intersect_poster(r,obj); default : fprintf(stderr,"error(intersect):rogue tag\n"); exit(1); } }
hit_test intersect (ray r, object o) { switch (o.tag) { case SPHERE : return intersect_sphere(r, o.o.s); case POSTER : return intersect_poster(r, o.o.p); case CYLINDER : return intersect_cylinder(r, o.o.cyl); } fprintf(stderr, "invalid object tag\n"); exit(1); }
float intersect(const ray *ray, const graphics_state *state, f3 *intersection, f3 *normal){ /* main raytrace loop: go through geometry, testing for intersections */ int i; float tmin = 1000000; for(i = 0; i < state->object_count; i++){ /* get geometry */ sphere *s = state->object_list + i; float t = intersect_sphere(ray, s, tmin, intersection, normal); if(t > 0 && t < tmin) tmin = t; } return (tmin < 100000) ? tmin : -1; }
int intersect_prim(t_env *e, t_ray *ray, size_t prim, double *t) { if (e->prim[prim]->type == PRIM_SPHERE) return (intersect_sphere(ray, e->prim[prim], t)); if (e->prim[prim]->type == PRIM_HEMI_SPHERE) return (intersect_hemi_sphere(ray, e->prim[prim], t)); if (e->prim[prim]->type == PRIM_PLANE) return (intersect_plane(ray, e->prim[prim], t)); if (e->prim[prim]->type == PRIM_CYLINDER) return (intersect_cylinder(ray, e->prim[prim], t)); if (e->prim[prim]->type == PRIM_CONE) return (intersect_cone(ray, e->prim[prim], t)); if (e->prim[prim]->type == PRIM_DISK) return (intersect_disk(ray, e->prim[prim], t)); return (0); }
static inline void trace_ray(rt_context_t *rtx) { rtx->dist = FARDIST; rtx->hit = NOHIT; unsigned int i; for (i = 0; i < rtx->objnum; i++) { int hit = 0; switch (rtx->obj[i].type) { case SPHERE: hit = intersect_sphere(rtx, i); break; case PLANE: hit = intersect_plane(rtx, i); break; default: break; } rtx->hit = (hit == 1) ? i : rtx->hit; } }
// intersects the scene and return the first intrerseciton intersection3f intersect(Scene* scene, ray3f ray) { // create a default intersection record to be returned auto intersection = intersection3f(); // foreach surface for(auto surface : scene->surfaces) { // if it is a quad if(surface->isquad) { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect quad auto t = 0.0f; auto p = zero3f; auto hit = intersect_quad(tray, surface->radius, t, p); // skip if not hit if(not hit) continue; // check if this is the closest intersection, continue if not if(t > intersection.ray_t and intersection.hit) continue; // if hit, set intersection record values intersection.hit = true; intersection.ray_t = t; intersection.pos = transform_point(surface->frame,p); intersection.norm = transform_normal(surface->frame,z3f); intersection.texcoord = {0.5f*p.x/surface->radius+0.5f,0.5f*p.y/surface->radius+0.5f}; intersection.mat = surface->mat; } else { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect sphere auto t = 0.0f; auto hit = intersect_sphere(tray, surface->radius, t); // skip if not hit if(not hit) continue; // check if this is the closest intersection, continue if not if(t > intersection.ray_t and intersection.hit) continue; // compute local point and normal auto p = tray.eval(t); auto n = normalize(p); // if hit, set intersection record values intersection.hit = true; intersection.ray_t = t; intersection.pos = transform_point(surface->frame,p); intersection.norm = transform_normal(surface->frame,n); intersection.texcoord = {(pif+(float)atan2(n.y, n.x))/(2*pif),(float)acos(n.z)/pif}; intersection.mat = surface->mat; } } // foreach mesh for(auto mesh : scene->meshes) { // quads are not supported: check for error error_if_not(mesh->quad.empty(), "quad intersection is not supported"); // tranform the ray auto tray = transform_ray_inverse(mesh->frame, ray); // save auto mesh intersection auto sintersection = intersection3f(); // if it is accelerated if(mesh->bvh) { sintersection = intersect(mesh->bvh, 0, tray, [mesh](int tid, ray3f tray){ // grab triangle auto triangle = mesh->triangle[tid]; // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // intersect triangle auto t = 0.0f, u = 0.0f, v = 0.0f; auto hit = intersect_triangle(tray, v0, v1, v2, t, u, v); // skip if not hit if(not hit) return intersection3f(); // if hit, set up intersection, trasforming hit data to world space auto sintersection = intersection3f(); sintersection.hit = true; sintersection.ray_t = t; sintersection.pos = tray.eval(t); sintersection.norm = normalize(mesh->norm[triangle.x]*u+ mesh->norm[triangle.y]*v+ mesh->norm[triangle.z]*(1-u-v)); if(mesh->texcoord.empty()) sintersection.texcoord = zero2f; else { sintersection.texcoord = mesh->texcoord[triangle.x]*u+ mesh->texcoord[triangle.y]*v+ mesh->texcoord[triangle.z]*(1-u-v); } sintersection.mat = mesh->mat; return sintersection; }); } else { // clear intersection sintersection = intersection3f(); // foreach triangle for(auto triangle : mesh->triangle) { // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // intersect triangle auto t = 0.0f, u = 0.0f, v = 0.0f; auto hit = intersect_triangle(tray, v0, v1, v2, t, u, v); // skip if not hit if(not hit) continue; // check if closer then the found hit if(t > sintersection.ray_t and sintersection.hit) continue; // if hit, set up intersection, trasforming hit data to world space sintersection.hit = true; sintersection.ray_t = t; sintersection.pos = tray.eval(t); sintersection.norm = normalize(mesh->norm[triangle.x]*u+ mesh->norm[triangle.y]*v+ mesh->norm[triangle.z]*(1-u-v)); if(mesh->texcoord.empty()) sintersection.texcoord = zero2f; else { sintersection.texcoord = mesh->texcoord[triangle.x]*u+ mesh->texcoord[triangle.y]*v+ mesh->texcoord[triangle.z]*(1-u-v); } sintersection.mat = mesh->mat; } } // if did not hit the mesh, skip if(not sintersection.hit) continue; // check not first intersection, skip if(sintersection.ray_t > intersection.ray_t and intersection.hit) continue; // set interserction intersection = sintersection; // transform by mesh frame intersection.pos = transform_point(mesh->frame,sintersection.pos); intersection.norm = transform_normal(mesh->frame,sintersection.norm); // set material intersection.mat = sintersection.mat; } // record closest intersection return intersection; }
// intersect sphere without returning values inline bool intersect_sphere(const ray3f& ray, float radius) { float t; return intersect_sphere(ray, radius, t); }
static void check_collision ( collision_data& coldat ) { float radius; if ( coldat.BoundingSphere.x == coldat.BoundingSphere.y && coldat.BoundingSphere.x == coldat.BoundingSphere.z ) { radius = coldat.BoundingSphere.x; } else { radius = 1.0f; // scale polygon for ( small x = 0; x < cache.count; x++ ) { cache.vertex [ x ].x /= coldat.BoundingSphere.x; cache.vertex [ x ].y /= coldat.BoundingSphere.y; cache.vertex [ x ].z /= coldat.BoundingSphere.z; } CalcNormal ( cache.vertex, &cache.normal ); D3DXVec3Normalize ( &cache.normal, &cache.normal ); } D3DXVECTOR3 r; D3DXVECTOR3 pt = cache.vertex [ 0 ]; D3DXVECTOR3 n = cache.normal; D3DXVECTOR3 s = coldat.src - n * radius; float t = D3DXVec3Dot ( &( s - pt ), &n ); if ( t > coldat.dir_len ) { return; } if ( t < -2 * radius ) { return; } if ( t < 0.0f ) { if ( !intersect_plane ( s, n * radius, pt, r ) ) return; } else { if ( !intersect_plane ( s, coldat.dir, pt, r ) ) return; } if ( !point_in_poly ( r ) ) { D3DXVECTOR3 line_dir; r = closest_on_poly ( r, &line_dir ); // mj change - sticky collision fix 27/08/02 D3DXVECTOR3 ndir; //D3DXVec3Cross ( &ndir, &coldat.ndir, &line_dir ); //D3DXVec3Cross ( &ndir, &line_dir, &ndir ); //D3DXVec3Normalize ( &ndir, &ndir ); ndir = coldat.ndir; t = intersect_sphere ( r, -ndir, coldat.src, radius ); } else { t = intersect_sphere ( r, -coldat.ndir, coldat.src, radius ); } if ( t >= 0.0f && t <= coldat.dir_len ) { if ( !coldat.found || t < coldat.dist ) { coldat.found = true; coldat.dist = t; coldat.nearest_poly = r; } } }