int intersect_shadow(float t, t_scene *scene, t_ray *ray) { t_vec3 intersect_pt; t_ray shadow; float t_tmp; intersect_pt.x = ray->o.x + t * ray->d.x; intersect_pt.y = ray->o.y + t * ray->d.y; intersect_pt.z = ray->o.z + t * ray->d.z; init_coord(&shadow.o, 0, 0, -30); init_vec3(&(shadow.d), shadow.o.x - intersect_pt.x, shadow.o.y - intersect_pt.y, shadow.o.z - intersect_pt.z); t_tmp = -1; while (scene != NULL) { if (scene->type == CIRCLE) t_tmp = intersect_circle(&shadow, scene->object); else if (scene->type == PLANE) t_tmp = intersect_plane(&shadow, scene->object); else if (scene->type == CYLINDER) t_tmp = intersect_cylinder(&shadow, scene->object); if (t_tmp > 0) { return (1); } scene = scene->next; } return (0); }
/* Function that returns whether a ray intersects a capped cylinder and fills out a variable for the distance from the ray's origin to the intersection if there is one and also fills out the "type" of the intersection -- 1 for a cylinder body intersection, 2 for a top cap intersection, and 3 for a bottom cap intersection */ bool intersect_capped_cylinder(const ray3f& ray, float r, float h, float& t, int& type) { bool valid_intersect = false; t = ray.tmax; vec3f intersect = zero3f; /* Check whether the ray intersects the cylinder body, ensuring that the intersection is not between the end caps. Note: most of this code is from the previous function, written by Jon Denning */ if(intersect_cylinder(ray, r, h, t)) { valid_intersect = true; type = BODY; } /* Now check the circles on top/bottom of cylinder http://orca.st.usm.edu/~jchen/courses/graphics/lectures/Raytracing.pdf proved helpful for this section of the code */ /* Using the notes on ray-plane intersection... */ /* Intersect the top end cap, first; intersect the plane at {0, 0, h} */ vec3f n = vec3f(0, 0, 1); // Normal vec3f c = vec3f(0, 0, h); // Center float t_cap; if (dot(ray.d, n) != 0) { t_cap = dot((c-ray.e), n)/dot(ray.d, n); if (t_cap >= ray.tmin && t_cap <= ray.tmax) { intersect = ray.eval(t_cap); if((intersect.x * intersect.x + intersect.y * intersect.y) <= r*r) { if(t_cap < t) { t = t_cap; valid_intersect = true; type = CAP_TOP; } } } } /* Intersect the bottom end cap; intersect the plane at {0, 0, 0} */ n = vec3f(0, 0, -1); c = vec3f(0, 0, 0); if (dot(ray.d, n) != 0) { t_cap = dot((c-ray.e), n)/dot(ray.d, n); if (t_cap >= ray.tmin && t_cap <= ray.tmax) { intersect = ray.eval(t_cap); if((intersect.x * intersect.x + intersect.y * intersect.y) <= r*r) { if(t_cap < t) { t = t_cap; valid_intersect = true; type = CAP_BOT; } } } } if(valid_intersect) return true; else return false; }
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); }
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); }
void get_nearest_cylinder(t_vector ray, t_object *cylinder, t_surface *surface, t_scene *scene) { t_double2 distance; t_surface *tmp; t_vector ray_s; ray_s = transform_ray(ray, cylinder); if (intersect_cylinder(ray_s, cylinder, &distance)) { tmp = cut_object(ray, cylinder, distance, scene); if (tmp->object != NULL && (surface->distance == -1 || surface->distance > tmp->distance)) { surface->object = tmp->object; surface->distance = tmp->distance; surface->normal = tmp->normal; // surface->color = tmp->object->color; surface->color = cylindrical_mapping(scene, surface, ray_s, cylinder); free(tmp); } } }
/* *The timestep and collision situations are used to find points of * contact and new velocities after balls hit each other */ void compute_velocities() { double rt,rt2,rt4,lamda=10000; TVector norm,uveloc; TVector normal,point; double RestTime,BallTime; TVector col_pos; int ball=0,ball1,ball2; TVector Nc; int j; RestTime = TimeStep; lamda = 1000; /* Compute velocity for next timestep using Euler equations */ for (j = 0; j < ball_count; j++) { ball_vel[j]-= (ball_vel[j] * friction); } /* while timestep not over */ while (RestTime>ZERO) { lamda = 10000; /* initialize to very large value */ /* For all the balls find closest intersection between * balls and planes/cylinders */ for (int i = 0; i < ball_count; i++) { /* compute new position and distance */ old_pos[i] = ball_pos[i]; TVector::unit(ball_vel[i],uveloc); ball_pos[i] = ball_pos[i]+ball_vel[i]*RestTime; rt2 = old_pos[i].dist(ball_pos[i]); /* Now test intersection with the outer cylinder */ if (intersect_cylinder(cyl1,old_pos[i],uveloc,rt,norm,Nc)) { rt4 = rt*RestTime / rt2; if (rt4 <= lamda) { if (rt4 <= RestTime+ZERO) if (! ((rt <= ZERO)&&(uveloc.dot(norm) < ZERO)) ) { normal=norm; point=Nc; lamda=rt4; ball=i; } } } } /* After all balls were tested with planes/cylinders test for collision * between them and replace if collision time smaller */ if (find_collision(col_pos,BallTime,RestTime,ball1,ball2)) { if ( (lamda == 10000) || (lamda > BallTime) ) { RestTime = RestTime-BallTime; TVector pb1,pb2,xaxis,U1x,U1y,U2x,U2y,V1x,V1y,V2x,V2y; double a,b; pb1=old_pos[ball1]+ball_vel[ball1]*BallTime; // Find position of ball1 pb2=old_pos[ball2]+ball_vel[ball2]*BallTime; // Find position of ball2 xaxis=(pb2-pb1).unit(); a=xaxis.dot(ball_vel[ball1]); /* U1 and U2 are the velocity vectors of the two spheres at the * time of impact */ U1x=xaxis*a; U1y=ball_vel[ball1]-U1x; xaxis=(pb1-pb2).unit(); b=xaxis.dot(ball_vel[ball2]); U2x=xaxis*b; U2y=ball_vel[ball2]-U2x; /* V1,V2 are the new velocities after the impact */ V1x=( (U1x*mass[ball1]+U2x*mass[ball2] - (U1x-U2x))*mass[ball2] ) * (1 / (mass[ball1] + mass[ball2])); V2x=( (U1x*mass[ball1]+U2x*mass[ball2] - (U2x-U1x))*mass[ball1] ) * (1 / (mass[ball1] + mass[ball2])); V1y=U1y; V2y=U2y; for (j=0;j<ball_count;j++) ball_pos[j]=old_pos[j]+ball_vel[j]*BallTime; ball_vel[ball1]=V1x+V1y; ball_vel[ball2]=V2x+V2y; /* continue; */ give_point(ball1, ball2); } } /* End of tests */ /* If test occured move simulation for the correct timestep */ /* and compute response for the colliding ball */ if (lamda!=10000) { RestTime-=lamda; for (j=0;j<ball_count;j++) ball_pos[j]=old_pos[j]+ball_vel[j]*lamda; rt2=ball_vel[ball].mag(); ball_vel[ball].unit(); ball_vel[ball]=TVector::unit( (normal*(2*normal.dot(-ball_vel[ball]))) + ball_vel[ball] ); ball_vel[ball]=ball_vel[ball]*rt2; } else { RestTime=0; } } }
GimpRGB get_ray_color_cylinder (GimpVector3 *pos) { GimpVector3 lvp, ldir, vp, p, dir, ns, nn; GimpRGB color, color2; gfloat m[16]; gint i; FaceIntersectInfo face_intersect[2]; color = background; vp = mapvals.viewpoint; p = *pos; vp.x = vp.x - mapvals.position.x; vp.y = vp.y - mapvals.position.y; vp.z = vp.z - mapvals.position.z; p.x = p.x - mapvals.position.x; p.y = p.y - mapvals.position.y; p.z = p.z - mapvals.position.z; /* Compute direction */ /* ================= */ gimp_vector3_sub (&dir, &p, &vp); gimp_vector3_normalize (&dir); /* Compute inverse of rotation matrix and apply it to */ /* the viewpoint and direction. This transforms the */ /* observer into the local coordinate system of the box */ /* ==================================================== */ memcpy (m, rotmat, sizeof (gfloat) * 16); transpose_mat (m); vecmulmat (&lvp, &vp, m); vecmulmat (&ldir, &dir, m); if (intersect_cylinder (lvp, ldir, face_intersect) == TRUE) { /* We've hit the cylinder. Transform the hit points and */ /* normals back into the world coordinate system */ /* ==================================================== */ for (i = 0; i < 2; i++) { vecmulmat (&ns, &face_intersect[i].s, rotmat); vecmulmat (&nn, &face_intersect[i].n, rotmat); ns.x = ns.x + mapvals.position.x; ns.y = ns.y + mapvals.position.y; ns.z = ns.z + mapvals.position.z; face_intersect[i].s = ns; face_intersect[i].n = nn; } color = get_cylinder_color (face_intersect[0].face, face_intersect[0].u, face_intersect[0].v); /* Check for transparency... */ /* ========================= */ if (color.a < 1.0) { /* Hey, we can see through here! */ /* Lets see what's on the other side.. */ /* =================================== */ color = phong_shade (&face_intersect[0].s, &mapvals.viewpoint, &face_intersect[0].n, &mapvals.lightsource.position, &color, &mapvals.lightsource.color, mapvals.lightsource.type); gimp_rgb_clamp (&color); color2 = get_cylinder_color (face_intersect[1].face, face_intersect[1].u, face_intersect[1].v); /* Make the normal point inwards */ /* ============================= */ gimp_vector3_mul (&face_intersect[1].n, -1.0); color2 = phong_shade (&face_intersect[1].s, &mapvals.viewpoint, &face_intersect[1].n, &mapvals.lightsource.position, &color2, &mapvals.lightsource.color, mapvals.lightsource.type); gimp_rgb_clamp (&color2); if (mapvals.transparent_background == FALSE && color2.a < 1.0) { gimp_rgb_composite (&color2, &background, GIMP_RGB_COMPOSITE_BEHIND); } /* Compute a mix of the first and second colors */ /* ============================================ */ gimp_rgb_composite (&color, &color2, GIMP_RGB_COMPOSITE_NORMAL); gimp_rgb_clamp (&color); } else if (color.a != 0.0 && mapvals.lightsource.type != NO_LIGHT) { color = phong_shade (&face_intersect[0].s, &mapvals.viewpoint, &face_intersect[0].n, &mapvals.lightsource.position, &color, &mapvals.lightsource.color, mapvals.lightsource.type); gimp_rgb_clamp (&color); } } else { if (mapvals.transparent_background == TRUE) gimp_rgb_set_alpha (&color, 0.0); } return color; }