bool SceneNode::intersect(const Ray& ray, Intersection& i) const { // Transform the ray from WCS->MCS for this node Ray r(m_invtrans * ray.origin(), m_invtrans * ray.direction()); bool intersects = false; for(auto child : m_children) { Intersection j; if(child->intersect(r, j)) { // We need to see if this intersection point is closer than the previous intersection point // If it is than replace the previous intersection if(std::isinf(i.q[0]) || std::isinf(i.q[1]) || std::isinf(i.q[2]) || (j.q-r.origin()).length() < (i.q-r.origin()).length()) i = j; intersects = true; } } // If intersection occurs than transform the intersection point and the normal from MCS->WCS // We have to convert the intersection point from MCS->WCS and the normal from MCS->WCS // Normals must be multiplied by the transpose of the inverse to throw away scaling (no translations either, but the normal is // a vector and vectors can't be translated) but preserve rotation if(intersects) { i.q = m_trans * i.q; i.n = transNorm(m_invtrans, i.n); } return intersects; }
bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSquare, which is // defined on the xy-plane, with vertices (0.5, 0.5, 0), // (-0.5, 0.5, 0), (-0.5, -0.5, 0), (0.5, -0.5, 0), and normal // (0, 0, 1). // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_hit. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Ray3D modelRay; // To store transformed model space ray. Vector3D surfaceNormal(0, 0, 1); // Constant surface normal. double t; // Intersection parameter. // Transform ray to model space. modelRay.origin = worldToModel * ray.origin; modelRay.dir = worldToModel * ray.dir;; // Compute intersection between ray and XY-plane. double d_dot_n = modelRay.dir.dot(surfaceNormal); // TODO: NEED MORE STABLE FLOAT EQUAL CHECK! if (d_dot_n == 0.0) { // Ray is parallel to plane. return false; } // Compute intersection and check if it occurs infront or behind the camera. t = -(Vector3D(modelRay.origin[0], modelRay.origin[1], modelRay.origin[2]).dot(surfaceNormal)) / d_dot_n; if (t < ray.intersection.t_min || t > ray.intersection.t_max) { return false; } if (!ray.intersection.none && t > ray.intersection.t_hit) { return false; } // Compute intersection point and check againt unit square bounds. Point3D intPoint = modelRay.origin + (t * modelRay.dir); if (!(intPoint[0] >= -0.5 && intPoint[0] <= 0.5 && intPoint[1] >= -0.5 && intPoint[1] <= 0.5)) { return false; } // Transform and set intersection info. ray.intersection.point = modelToWorld * intPoint; ray.intersection.normal = transNorm(worldToModel, surfaceNormal); ray.intersection.normal.normalize(); ray.intersection.t_hit = t; ray.intersection.none = false; ray.intersection.inside = false; return true; }
bool SceneNode::intersect (Point3D eye, Vector3D ray, Results &res, bool quit_early) const { bool ret = false; //std::cout << "start " << m_name << std::endl; eye = m_invtrans * eye; ray = m_invtrans * ray; res.normal = transNorm(m_trans, res.normal); ChildList::const_iterator it = m_children.begin(); for (it=m_children.begin(); it != m_children.end(); ++it) { //std::cout << m_name << std::endl; bool sub_ret = (*it)->intersect(eye, ray, res); ret = ret || sub_ret; if (ret && quit_early) return ret; } res.normal = transNorm(m_invtrans, res.normal); return ret; }
bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // DONE: implement intersection code for UnitSquare, which is // defined on the xy-plane, with vertices (0.5, 0.5, 0), // (-0.5, 0.5, 0), (-0.5, -0.5, 0), (0.5, -0.5, 0), and normal // (0, 0, 1). // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. // transform the ray into object space Ray3D obj_ray; obj_ray.origin = worldToModel * ray.origin; obj_ray.dir = worldToModel * ray.dir; // case 1: if the ray is in xy-plane, it will not intersect with the unit square if(obj_ray.dir[2] == 0) { return false; } // case 2: the general case, the ray is not in xy-plane double t_value = (-obj_ray.origin[2])/obj_ray.dir[2]; if(t_value <= 0) { return false; } // 1. x componet of the intersection double x = obj_ray.origin[0] + t_value * obj_ray.dir[0]; // 2. y componet of the intersection double y = obj_ray.origin[1] + t_value * obj_ray.dir[1]; // 3. z componet of the intersection double z = 0.0; if(x < -0.5 || x > 0.5 || y < -0.5 || y > 0.5) { return false; } if(ray.intersection.none || t_value < ray.intersection.t_value) { Point3D intersection = modelToWorld * Point3D(x, y, z); Vector3D normal(0, 0, 1); normal = transNorm(worldToModel, normal); ray.intersection.point = intersection; ray.intersection.normal = normal; ray.intersection.mat = ray.intersection.mat; ray.intersection.t_value = t_value; ray.intersection.none = false; return true; } }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSphere, which is centred // on the origin. // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Point3D world_origin(0, 0, 0); double lambda; Vector3D d = worldToModel * ray.dir; Point3D a = worldToModel * ray.origin; Point3D c(0, 0, 0); Vector3D nmb = a - c; double A = d.dot(d); double B = nmb.dot(d); double C = nmb.dot(nmb) - 1; double D = (B * B) - (A * C); if (D < 0){ return false; } else if(D == 0){ lambda = - (B / A); } else{ double lambda1 = - (B / A) + (sqrt(D) / A); double lambda2 = - (B / A) - (sqrt(D) / A); lambda = std::min(lambda1, lambda2); if (lambda < 0){ lambda = std::max(lambda1, lambda2); if (lambda < 0){ return false; } } } Point3D intersect_point = a + (lambda * d); Vector3D normal_vector = intersect_point - c; normal_vector.normalize(); ray.intersection.t_value = lambda; ray.intersection.normal = transNorm(worldToModel, normal_vector); ray.intersection.normal.normalize(); ray.intersection.point = modelToWorld * intersect_point; ray.intersection.none = false; return true; }
// Intersection code for UnitSphere, which is centred on the origin. bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // The sphere's radius double radius = 1; // Transform ray into object space Point3D modelPoint = worldToModel*ray.origin; Vector3D modelDirection = worldToModel*ray.dir; // Detemine if there is an intersection double a = dot(modelDirection, modelDirection); double b = dot(modelPoint, modelDirection); double c = dot(modelPoint, modelPoint) - radius; double d = b * b - a * c; double didIntersect = d >= 0; // Find how close the intersection is if (d >= 0) { double lambda = - b / a; double ld1, ld2; ld1 = ld2 = 0; if (d > 0) { ld1 = lambda + sqrt(d)/a; ld2 = lambda - sqrt(d)/a; if (ld1 > 0 && ld2 < 0) { lambda = ld1; } else if (ld1 > ld2 && ld2 > 0){ lambda = ld2; } else { lambda = ld1; } } // If a closer intersection exists, ignore this one if ((ray.intersection.t_value < lambda && !ray.intersection.none) || (ld1 < 0 && ld2 < 0)) { return false; } // Find the intersection and associated normal Point3D intersection = modelPoint + lambda*modelDirection; Vector3D normal = Vector3D(2 * intersection[0], 2 * intersection[1], 2 * intersection[2]); // Populate ray.intersection values ray.intersection.none = !didIntersect; ray.intersection.point = modelToWorld*intersection; ray.intersection.t_value = lambda; normal = transNorm(worldToModel, normal); normal.normalize(); ray.intersection.normal = normal; } return didIntersect; }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSphere, which is centred // on the origin. // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Ray3D r; r.origin = worldToModel * ray.origin; r.dir = worldToModel * ray.dir; Point3D sphere(0,0,0); Vector3D s_dist = r.origin - sphere; double int0 = -1, int1; double a = r.dir.dot(r.dir); double b = s_dist.dot(r.dir); double c = s_dist.dot(s_dist) - 1; double d = b * b - a * c; if (d == 0) int0 = -b/a; else if (d > 0) { int0 = (-b + sqrt(d)) / a; int1 = (-b - sqrt(d)) / a; int0 = int0 < int1 ? int0 : int1; } if (int0 <= 0) return false; if (ray.intersection.none || int0 < ray.intersection.t_value) { Point3D ip = r.origin + int0 * r.dir; Vector3D n = 2 * (ip - sphere); n.normalize(); ray.intersection.t_value = int0; ray.intersection.point = modelToWorld * ip; ray.intersection.normal = transNorm(worldToModel, n); ray.intersection.normal.normalize(); ray.intersection.none = false; return true; } return false; }
bool DifferenceNode::intersect(const Ray& ray, Intersection& i) const { Ray r(m_invtrans * ray.origin(), m_invtrans * ray.direction()); Intersection j, k; bool intersects_a = m_A->intersect(r, j); bool intersects_b = m_B->intersect(r, k); bool intersects = false; if(intersects_a) { double epsilon = std::numeric_limits<double>::epsilon(); if(intersects_b && ((k.q-r.origin()).length() < (j.q-r.origin()).length())) { int idx = (fabs(r.direction()[0]) > epsilon) ? 0 : ((fabs(r.direction()[1]) > epsilon) ? 1 : 2); double t = (j.q[idx] - r.origin()[idx]) / r.direction()[idx]; Ray nray(r.origin() + (t+1000*epsilon)*r.direction(), r.direction()); Intersection u, v; intersects_a = m_A->intersect(nray, u); intersects_b = m_B->intersect(nray, v); if(!intersects_b) { i = j; intersects = true; } else if(intersects_a && ((v.q-r.origin()).length() < (u.q-r.origin()).length())) { i = v; i.n = -i.n; intersects = true; } } else { i = j; intersects = true; } } if(intersects) { i.q = m_trans * i.q; i.n = transNorm(m_invtrans, i.n); } return (intersects || SceneNode::intersect(ray, i)); }
bool GeometryNode::intersect (Point3D eye, Vector3D ray, Results &res, bool quit_early) const { //std::cout << m_name << std::endl; // Find intersection with shape if (m_primitive->intersect(m_invtrans*eye, m_invtrans*ray, res)) { // Convert normal to WCS //*(res.normal) = m_revert * *(res.normal); res.normal = transNorm(m_invtrans, res.normal); // Update return value with material res.material = m_material; return true; } else { // No intersection return false; } }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSphere, which is centred // on the origin. // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Vector3D d = worldToModel*ray.dir; // d.normalize(); Point3D e = worldToModel*ray.origin; Point3D c; float A = d.dot(d); float B = d.dot(e-c); float C = (e-c).dot(e-c)-1.0; if ((B*B - A*C) < 0) { ray.intersection.none = true; return false; } else { float t1 = (-B - sqrt(B*B - A*C)) / A; float t2 = (-B + sqrt(B*B - A*C)) / A; float t = fmin(t1, t2); if (t > 0) { if (!ray.intersection.none && ray.intersection.t_value < t) { return false; } Vector3D n = e + t*d - c; n.normalize(); ray.intersection.point = modelToWorld * (e + t*d); ray.intersection.normal = transNorm(worldToModel, n); ray.intersection.none = false; ray.intersection.t_value = t; return true; } else return false; } }
bool IntersectionNode::intersect(const Ray& ray, Intersection& i) const { Ray r(m_invtrans * ray.origin(), m_invtrans * ray.direction()); Intersection j, k; bool intersects_a = m_A->intersect(r, j); bool intersects_b = m_B->intersect(r, k); if(intersects_a && intersects_b) { i = ((k.q-r.origin()).length() > (j.q-r.origin()).length()) ? k : j; i.q = m_trans * i.q; i.n = transNorm(m_invtrans, i.n); } return ((intersects_a && intersects_b) || SceneNode::intersect(ray, i)); }
bool UnionNode::intersect(const Ray& ray, Intersection& i) const { Ray r(m_invtrans * ray.origin(), m_invtrans * ray.direction()); Intersection j, k; bool intersects_a = m_A->intersect(r, j); bool intersects_b = m_B->intersect(r, k); if(intersects_a || intersects_b) { i = (std::isinf(j.q[0]) || std::isinf(j.q[1]) || std::isinf(j.q[2]) || (k.q-r.origin()).length() < (j.q-r.origin()).length()) ? k : j; i.q = m_trans * i.q; i.n = transNorm(m_invtrans, i.n); } return (intersects_a || intersects_b || SceneNode::intersect(ray, i)); }
bool GeometryNode::intersect(const Ray& ray, Intersection& i) const { // Test for intersection // But first transform ray to geometry's model coordinates (inverse transform from WCS->MCS) Ray r(m_invtrans * ray.origin(), m_invtrans * ray.direction()); Intersection k; bool intersects = m_primitive->intersect(r, k); if(intersects) { i = k; i.q = m_trans * i.q; i.n = transNorm(m_invtrans, i.n); i.m = m_material; } return (intersects || SceneNode::intersect(ray, i)); }
bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { //tranform ray into object space Vector3D obj_dir = worldToModel * ray.dir; Point3D obj_ori = worldToModel * ray.origin; //ray =obj_ori + t*obj_dir // N·(E + tD - Q) = 0 // t = N·(Q - E) / N·D Vector3D plane_norm = Vector3D(0,0,1); double result = plane_norm.dot(obj_dir); if(result == 0){ return false; }else{ Point3D plane_ptr = Point3D();//origin point is on the plane Vector3D m = plane_ptr - obj_ori; double t = plane_norm.dot(m)/result; if(t > 0){ double inter_x = obj_ori[0] + t * obj_dir[0]; double inter_y = obj_ori[1] + t * obj_dir[1]; if(inter_x < 0.5 && inter_x > -0.5 && inter_y < 0.5 && inter_y > -0.5 && (t < ray.intersection.t_value || ray.intersection.none)){ ray.intersection.point = modelToWorld * Point3D(inter_x, inter_y, 0); ray.intersection.t_value = t; ray.intersection.none = false; Vector3D n = Vector3D(0, 0, 1); Vector3D inter_norm = transNorm(worldToModel, n); ray.intersection.normal = inter_norm; ray.intersection.normal.normalize(); Point3D point = worldToModel * ray.intersection.point; ray.intersection.textcoor = Point3D(point[0] + 0.5, 0.5 - point[1], 0); return true; }else{ return false; } }else{ //no intersection return false; } } }
bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSquare, which is // defined on the xy-plane, with vertices (0.5, 0.5, 0), // (-0.5, 0.5, 0), (-0.5, -0.5, 0), (0.5, -0.5, 0), and normal // (0, 0, 1). // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Vector3D d = worldToModel * ray.dir; Point3D a = worldToModel * ray.origin; double lambda = - a[2] / d[2]; Point3D p = a + (lambda * d); if (ray.intersection.none || ray.intersection.t_value > lambda){ if(p[0] > 0.5 || p[0] < -0.5 || p[1] > 0.5 || p[1] < -0.5){ return false; } Vector3D normal_vector(0, 0, 1); ray.intersection.t_value = lambda; ray.intersection.normal = transNorm(worldToModel, normal_vector); ray.intersection.normal.normalize(); ray.intersection.point = modelToWorld * p; ray.intersection.none = false; return true; } return false; }
// Finds intersection for UnitSquare, which is // defined on the xy-plane, with vertices (0.5, 0.5, 0), // (-0.5, 0.5, 0), (-0.5, -0.5, 0), (0.5, -0.5, 0), and normal // (0, 0, 1). bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // Half oof the unit square's edge length double bound = 0.5; // Transform ray into object space Point3D modelPoint = worldToModel*ray.origin; Vector3D modelDirection = worldToModel*ray.dir; // The square's normal and a point on the square Vector3D normal = Vector3D(0, 0, 1); Point3D q1 = Point3D(0, 0, 0); // Find how close the intersection is double lambda = dot(q1 - modelPoint, normal)/dot(modelDirection, normal); // If a closer intersection exists, ignore this one if (ray.intersection.t_value < lambda && !ray.intersection.none) { return false; } // Find the intersection Point3D intersection = modelPoint + lambda*modelDirection; bool intersectionInBounds = intersection[0] >= -bound && intersection[0] <= bound && intersection[1] >= -bound && intersection[1] <= bound; // Populate ray.intersection values if (intersectionInBounds) { ray.intersection.point = modelToWorld*intersection; ray.intersection.normal = transNorm(worldToModel, normal); ray.intersection.normal.normalize(); ray.intersection.t_value = lambda; ray.intersection.none = false; } return intersectionInBounds; }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSphere, which is centred // on the origin. // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_hit. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Ray3D modelRay; double discriminant; double a, b, c; double t, t0, t1; int inside = 1; // Transform ray to model space. modelRay.origin = worldToModel * ray.origin; modelRay.dir = worldToModel * ray.dir; // Compute coefficients of quadractic formula. Vector3D vOrigin(modelRay.origin[0], modelRay.origin[1], modelRay.origin[2]); a = modelRay.dir.dot(modelRay.dir); b = modelRay.dir.dot(vOrigin); c = vOrigin.dot(vOrigin) - 1.0; // Compute discriminant of quadractic formula. discriminant = (b * b) - (a * c); if (discriminant < 0) { // No real roots. No intersection. return false; } t0 = (-b - sqrt(discriminant)) / a; t1 = (-b + sqrt(discriminant)) / a; t = t0; if (t < ray.intersection.t_min || t > ray.intersection.t_max) { t = t1; if (t < ray.intersection.t_min || t > ray.intersection.t_max) { return false; } inside = -1; ray.intersection.inside = true; } if (!ray.intersection.none && t > ray.intersection.t_hit) { return false; } Point3D intPoint = modelRay.origin + (t * modelRay.dir); Vector3D surfaceNormal = inside * (intPoint - Point3D(0, 0, 0)); ray.intersection.point = modelToWorld * intPoint; ray.intersection.normal = transNorm(worldToModel, surfaceNormal); ray.intersection.normal.normalize(); ray.intersection.t_hit = t; ray.intersection.none = false; return true; }
bool UnitFiniteCone::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { bool insideFlag1=false,insideFlag2=false; Point3D ray_origin = worldToModel*ray.origin; Vector3D ray_dir = worldToModel*ray.dir; Vector3D va(0,1,0);//axis for cylinder Point3D pa(0,0,0); Point3D pb(0, -1, 0);//the apex of the cone double cos_sqr= 0.5; double sin_sqr = 0.5; Point3D inter_pt_tmp; //At^2+B*t+C-1=0 double vva=ray_dir.dot(va);//the projection double A=cos_sqr*(ray_dir-vva*va).dot(ray_dir-vva*va)-sin_sqr*vva*vva; double B = 2*cos_sqr*(ray_dir-vva*va).dot((ray_origin-pa)-(ray_origin-pa).dot(va)*va)-2*sin_sqr*vva*(ray_origin-pa).dot(va); double C=cos_sqr*((ray_origin-pa)-(ray_origin-pa).dot(va)*va).dot((ray_origin-pa)-(ray_origin-pa).dot(va)*va)-sin_sqr*((ray_origin-pa).dot(va))*((ray_origin-pa).dot(va)); double t=0; double test = B*B-4*A*C; if(test<0||A==0){ return false;//no intersection }else if(test==0){ t=-B/(2*A); }else{//there are two roots. //testing for the infinite cylinder double t1 = (-B+ sqrt(test))/(2*A); double t2 = (-B - sqrt(test))/(2*A); if(t1>0 && t2<0){ t = t1; insideFlag1=true; }else if(t1<0 && t2>0){ t = t2; insideFlag1=true; }else if(t1 > 0 && t2 > 0){ if(t1 > t2){ t = t2; }else{ t = t1; } }else{//cylinder is behind the ray_origin so no intersection return false; } } inter_pt_tmp = ray_origin+t*ray_dir; if(((inter_pt_tmp-pb).dot(va)>=0)&&((inter_pt_tmp-pa).dot(va)<=0)){//between the two caps }else{ t=std::numeric_limits<double>::max(); } //testing for caps double t3 = (pb-ray_origin).dot(va)/ray_dir.dot(va);//intersection with the lower cap double tt=0; if(t3<0){ return false; }else{ tt=t3; } Point3D inter_pt_tmp1 = ray_origin+tt*ray_dir; if((inter_pt_tmp1-pb).length()<1){//in the cylinder insideFlag2=true; }else{//must on the cylinders tt=std::numeric_limits<double>::max(); } if(t<=tt){ if(t==std::numeric_limits<double>::max()) return false; if(ray.intersection.none||t<ray.intersection.t_value){ // std::cout<<"Here......1.."<<std::endl; inter_pt_tmp = ray_origin+t*ray_dir; ray.intersection.point = modelToWorld*inter_pt_tmp; Vector3D v; Vector3D cone_norm; if(insideFlag1){ v =Point3D(0,inter_pt_tmp[1],0)-inter_pt_tmp; cone_norm = v+Vector3D(0, inter_pt_tmp[1], 0); }else{ v =inter_pt_tmp-Point3D(0,inter_pt_tmp[1],0); cone_norm = v-Vector3D(0, inter_pt_tmp[1], 0); } cone_norm.normalize(); ray.intersection.normal = transNorm(modelToWorld, cone_norm); ray.intersection.normal.normalize(); ray.intersection.t_value=t; ray.intersection.none=false; ray.intersection.insideCrash = insideFlag1; return true; }else{ return true; } }else{ // std::cout<<"Here......2.."<<std::endl; if(ray.intersection.none||tt<ray.intersection.t_value){ inter_pt_tmp = ray_origin+tt*ray_dir; ray.intersection.point = modelToWorld*inter_pt_tmp; if(insideFlag2){ ray.intersection.normal = transNorm(modelToWorld, va); }else{ ray.intersection.normal = transNorm(modelToWorld, -va); } ray.intersection.normal.normalize(); ray.intersection.t_value=tt; ray.intersection.none=false; ray.intersection.insideCrash = insideFlag2; return true; }else{ return true; } } return false; }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // DONE: implement intersection code for UnitSphere, which is centred // on the origin. // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. // transform the ray into object space Ray3D obj_ray; obj_ray.origin = worldToModel * ray.origin; obj_ray.dir = worldToModel * ray.dir; // referred to the solution at: // http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection // analytic solution Vector3D L = obj_ray.origin - Point3D(0, 0, 0); double a = obj_ray.dir.dot(obj_ray.dir); double b = 2 * obj_ray.dir.dot(L); double c = L.dot(L) - 1.0; double discriminant = b * b - 4 * a * c; double x, y, z, t_value, t_value1, t_value2; // no solution if(discriminant < 0) { return false; } // 1 solution if(discriminant == 0) { t_value = - 0.5 * b / a; } // 2 solutions if(discriminant > 0) { float q = (b > 0) ? -0.5 * (b + sqrt(discriminant)) : -0.5 * (b - sqrt(discriminant)); t_value1 = q / a; t_value2 = c / q; } if (t_value1 < t_value2){ t_value = t_value1; } else{ t_value = t_value2; } if(ray.intersection.none || t_value < ray.intersection.t_value) { // 1. x componet of the intersection double x = obj_ray.origin[0] + t_value * obj_ray.dir[0]; // 2. y componet of the intersection double y = obj_ray.origin[1] + t_value * obj_ray.dir[1]; // 3. z componet of the intersection double z = obj_ray.origin[2] + t_value * obj_ray.dir[2]; Point3D intersection = modelToWorld * Point3D(x, y, z); Vector3D normal(x, y, z); normal = transNorm(worldToModel, normal); normal.normalize(); ray.intersection.point = intersection; ray.intersection.normal = normal; ray.intersection.mat = ray.intersection.mat; ray.intersection.t_value = t_value; ray.intersection.none = false; return true; } }
bool UnitFiniteCylinder::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { Point3D ray_origin = worldToModel*ray.origin; Vector3D ray_dir = worldToModel*ray.dir; Vector3D va(0,1,0);//axis for cylinder Point3D pa(0,0,0); Point3D pb(0, 1, 0); bool insideFlag1=false,insideFlag2=false; //At^2+B*t+C-1=0 double vva=ray_dir.dot(va);//the projection double A=(ray_dir-vva*va).dot(ray_dir-vva*va); double B = 2*(ray_dir-vva*va).dot(((ray_origin-pa)-(ray_origin-pa).dot(va)*va)); double C=(ray_origin-pa-(ray_origin-pa).dot(va)*va).dot(ray_origin-pa-vva*va)-1; double t=0; double test = B*B-4*A*C; if(test<0||A==0){ return false;//no intersection }else if(test==0){ t=-B/(2*A); }else{//there are two roots. //testing for the infinite cylinder double t1 = (-B+ sqrt(test))/(2*A); double t2 = (-B - sqrt(test))/(2*A); if(t1>0 && t2<0){ t = t1; insideFlag1=true; }else if(t1<0 && t2>0){ t = t2; insideFlag1 = true; }else if(t1 > 0 && t2 > 0){ if(t1 > t2){ t = t2; }else{ t = t1; } }else{//cylinder is behind the ray_origin so no intersection return false; } //testing for between the two planes. Point3D inter_pt_tmp = ray_origin+t*ray_dir; if(((inter_pt_tmp-pa).dot(va)>0)&&((inter_pt_tmp-pb).dot(va)<0)){//between the two caps }else{ t=std::numeric_limits<double>::max(); } //testing for caps double t3 = (pa-ray_origin).dot(va)/ray_dir.dot(va);//intersection with the lower cap double t4 = (pb-ray_origin).dot(va)/ray_dir.dot(va);//intersection with the upper cap double tt=0; Point3D po; if(t3<0&&t4<0){ return false; }else if(t3>0&&t4<0){ tt=t3; po=pa; insideFlag2 = true; }else if(t3<0&&t4>0){ tt=t4; po=pb; insideFlag2 = true; }else{ if(t4 > t3){ tt=t3; po=pa; }else{ tt=t4; po=pb; } } Point3D inter_pt_tmp1 = ray_origin+tt*ray_dir; if((inter_pt_tmp1-po).length()<1){//in the cylinder }else{//must on the cylinders tt=std::numeric_limits<double>::max(); } if(t<=tt){ if(t==std::numeric_limits<double>::max()) return false; if(ray.intersection.none||t<ray.intersection.t_value){ inter_pt_tmp = ray_origin+t*ray_dir; ray.intersection.point = modelToWorld*inter_pt_tmp; Vector3D cylinder_norm; if(insideFlag1){ cylinder_norm =Point3D(0,inter_pt_tmp[1],0)-inter_pt_tmp; }else{ cylinder_norm =inter_pt_tmp-Point3D(0,inter_pt_tmp[1],0); } cylinder_norm.normalize(); ray.intersection.normal = transNorm(modelToWorld,cylinder_norm ); ray.intersection.normal.normalize(); ray.intersection.t_value=t; ray.intersection.none=false; ray.intersection.insideCrash = insideFlag1; return true; }else{ return true; } }else{ if(ray.intersection.none||tt<ray.intersection.t_value){ inter_pt_tmp = ray_origin+tt*ray_dir; ray.intersection.point = modelToWorld*inter_pt_tmp; // if(tt==t3){ // ray.intersection.normal = transNorm(modelToWorld, -va); // }else{ // ray.intersection.normal = transNorm(modelToWorld, va); // } if((tt==t3&&insideFlag1==false)||(tt==t4&&insideFlag1)){ ray.intersection.normal = transNorm(modelToWorld, -va); }else if((tt==t4&&insideFlag1==false)||(tt==t3&&insideFlag1)){ ray.intersection.normal = transNorm(modelToWorld, va); } ray.intersection.normal.normalize(); ray.intersection.t_value=tt; ray.intersection.none=false; ray.intersection.insideCrash = insideFlag2; return true; }else{ return true; } } } return false; }
//---------------------------------------------------------------------------------------------------------------- bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // Implement intersection code for UnitSquare, which is // defined on the xy-plane, with vertices (0.5, 0.5, 0), // (-0.5, 0.5, 0), (-0.5, -0.5, 0), (0.5, -0.5, 0), and normal // (0, 0, 1). // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. // The original point is at 0,0,0 at its own model coordinates // Get ray direction in model coordinates Ray3D ObjectRay = Ray3D(worldToModel*ray.origin, worldToModel * ray.dir); Point3D origin(0,0,0); // always assume unitsquare is on x,y plane Vector3D squareNormal(0,0,1); double t_value; Point3D intersectionPoint; // If the ray is not moving towards the square, it means there is no intersection since // the square lies on the x and y axis, ray must move at some value on the z direction if (ObjectRay.dir[2] != 0) { t_value = -ObjectRay.origin[2]/ObjectRay.dir[2]; // Check for no self intersection if ((t_value )< 0.001) { return false; } } //the ray and the square are on the same plane else if (ObjectRay.dir[2] == 0 && ObjectRay.origin[2] == 0) { double temp1 = (-1.5 - ObjectRay.origin[0])/ObjectRay.dir[0]; double temp2 = (1.5 - ObjectRay.origin[0])/ObjectRay.dir[0]; double temp3 = (-1.5 - ObjectRay.origin[1])/ObjectRay.dir[1]; double temp4 = (1.5 - ObjectRay.origin[1])/ObjectRay.dir[1]; t_value = temp1; if (temp2 < t_value ) { t_value = temp2; } if (temp3 < t_value ) { t_value =temp3; } if (temp4< t_value ) { t_value = temp4; } } else { return false; } // Compute t_value from z intersection at z = 0 // If the ray already has an intersection at an earlier t_value, return but don't update // ray.intersection fields if(ray.intersection.none == false) { if(t_value > ray.intersection.t_value) { return false; } } // Compute coordinates Vector3D intersection(ObjectRay.origin[0] + ObjectRay.dir[0] * t_value, ObjectRay.origin[1] + ObjectRay.dir[1] * t_value, 0); double x = ObjectRay.origin[0] + ObjectRay.dir[0] * t_value; double y = ObjectRay.origin[1] + ObjectRay.dir[1] * t_value; // Test x if(x >= -0.5 && x <= 0.5) { // Text y if(y >= -0.5 && y <= 0.5) { // We have an intersection ray.intersection.t_value = t_value; ray.intersection.point = modelToWorld * Point3D(x, y, 0); ray.intersection.normal = Vector3D(0, 0, 1); // For Image Mapping ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); // every model thinks it is in the center ray.intersection.normal = transNorm(worldToModel, ray.intersection.normal); ray.intersection.normal.normalize(); ray.intersection.none = false; // false means there is an intersection return true; } } return false; }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSphere, which is centred // on the origin. // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Ray3D ObjectRay = Ray3D(worldToModel * ray.origin, worldToModel * ray.dir); double a = pow(ObjectRay.dir[0], 2) + pow(ObjectRay.dir[1], 2) + pow(ObjectRay.dir[2], 2); double b = 2 * (ObjectRay.origin[0] * ObjectRay.dir[0] + ObjectRay.origin[1] * ObjectRay.dir[1] + ObjectRay.origin[2] * ObjectRay.dir[2]); double c = pow(ObjectRay.origin[0], 2) + pow(ObjectRay.origin[1], 2) + pow(ObjectRay.origin[2], 2) -1; double discriminant = pow(b, 2) - 4 * a * c; // No intersection since no real roots if(discriminant < 0) { return false; } else { double t_1 = (-1 * b + sqrt(discriminant)) / (2 * a); double t_2 = (-1 * b - sqrt(discriminant)) / (2 * a); double t_value = 0; if ( t_2 < 0 && t_1 < 0) return false; else if ( t_1 < 0 ) t_value = t_2; else if ( t_2 < 0 ) t_value = t_1; else t_value = fmin(t_1, t_2); // If the ray already has an intersection at an earlier t_value, return but don't update // ray.intersection fields if(ray.intersection.none == false) { if(t_value > ray.intersection.t_value) { return true; } } double x = ObjectRay.origin[0] + ObjectRay.dir[0]*t_value; double y = ObjectRay.origin[1] + ObjectRay.dir[1]*t_value; double z = ObjectRay.origin[2] + ObjectRay.dir[2]*t_value; Vector3D intersection = Vector3D(x, y, z); ray.intersection.t_value = t_value; ray.intersection.point = modelToWorld * Point3D(x, y, z); ray.intersection.normal = transNorm(worldToModel, intersection); ray.intersection.normal.normalize(); // FOR TEXTURE MAPPING! ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); // every model thinks it is in the center ray.intersection.none = false; return true; } }
bool UnitCylinder::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { Ray3D modelRay; Point3D intPoint; Vector3D surfaceNormal; double discriminant; double a, b, c; double t0, t1, h, r, p_x, p_z, d_x, d_z; double t; bool isParallel = false; // 0 - cylinder_t0, 1 - cylinder_t1, 2 - top, 3 - bot double intersection_ts[4]; double inf = std::numeric_limits<double>::infinity(); // initialize intersection_ts to infinities for (int i=0; i < 4; i++) { intersection_ts[i] = inf; } h = 1.0; r = 0.5; // Transform ray to model space. modelRay.origin = worldToModel * ray.origin; modelRay.dir = worldToModel * ray.dir; //modelRay.dir.normalize(); // Compute coefficients of quadractic formula. p_x = modelRay.origin[0]; p_z = modelRay.origin[2]; d_x = modelRay.dir[0]; d_z = modelRay.dir[2]; a = pow(d_x, 2) + pow(d_z, 2); b = (2 * p_x * d_x) + (2 * p_z * d_z); c = pow(p_x, 2) + pow(p_z, 2) - pow(r, 2); // Compute discriminant of quadractic formula. discriminant = (b * b) - (4 * a * c); if (discriminant >= 0) { t0 = (-b - sqrt(discriminant)) / (2 * a); t1 = (-b + sqrt(discriminant)) / (2 * a); Point3D intPoint_0 = modelRay.origin + (t0 * modelRay.dir); Point3D intPoint_1 = modelRay.origin + (t1 * modelRay.dir); if (t0 >= ray.intersection.t_min && t0 <= ray.intersection.t_max) { if ((intPoint_0[1] >= 0 && intPoint_0[1] <= h)) { intersection_ts[0] = t0; } } if (t1 >= ray.intersection.t_min && t1 <= ray.intersection.t_max) { if ((intPoint_1[1] >= 0 && intPoint_1[1] <= h)) { intersection_ts[1] = t1; } } ray.intersection.inside = true; } // Check if it intersected the top or bottom cap Vector3D surfaceNormalTopCirc(0, 1, 0); // Constant surface normal. Vector3D surfaceNormalBotCirc(0, -1, 0); // Constant surface normal. double t_top, t_bot; // Intersection parameter. // Compute intersection between ray and ZX-plane. double d_dot_n_top = modelRay.dir.dot(surfaceNormalTopCirc); double d_dot_n_bot = modelRay.dir.dot(surfaceNormalBotCirc); if (d_dot_n_top == 0.0) { // Ray is parallel to planes isParallel = true; } if (!isParallel) { Vector3D vOrigin(modelRay.origin[0], modelRay.origin[1], modelRay.origin[2]); t_top = -(vOrigin.dot(surfaceNormalTopCirc) - h) / d_dot_n_top; t_bot = -(vOrigin.dot(surfaceNormalBotCirc)) / d_dot_n_bot; Point3D intPoint_top = modelRay.origin + (t_top * modelRay.dir); Point3D intPoint_bot = modelRay.origin + (t_bot * modelRay.dir); if ((t_top >= ray.intersection.t_min && t_top <= ray.intersection.t_max) && ((pow(intPoint_top[0], 2) + pow(intPoint_top[2], 2) - pow(r, 2)) <= 0)) { intersection_ts[2] = t_top; } if ((t_bot >= ray.intersection.t_min && t_bot <= ray.intersection.t_max) && ((pow(intPoint_bot[0], 2) + pow(intPoint_bot[2], 2) - pow(r, 2)) <= 0)) { intersection_ts[3] = t_bot; } } // Get the smallest t value index int indexOfSmallest = 0; double smallest_t = intersection_ts[0]; for (int i=0; i < 4; i++) { if (intersection_ts[i] < smallest_t) { smallest_t = intersection_ts[i]; indexOfSmallest = i; } } if (smallest_t == inf) { return false; } else { t = smallest_t; if (!ray.intersection.none && t > ray.intersection.t_hit) { return false; } intPoint = modelRay.origin + (t * modelRay.dir); if (indexOfSmallest == 0 || indexOfSmallest == 1) { surfaceNormal = intPoint - Point3D(0, intPoint[1], 0); } else if (indexOfSmallest == 2) { surfaceNormal = surfaceNormalTopCirc; } else { surfaceNormal = surfaceNormalBotCirc; } ray.intersection.point = modelToWorld * intPoint; ray.intersection.normal = transNorm(worldToModel, surfaceNormal); ray.intersection.normal.normalize(); ray.intersection.t_hit = t; ray.intersection.none = false; return true; } }
bool UnitSquare::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { // TODO: implement intersection code for UnitSquare, which is // defined on the xy-plane, with vertices (0.5, 0.5, 0), // (-0.5, 0.5, 0), (-0.5, -0.5, 0), (0.5, -0.5, 0), and normal // (0, 0, 1). // // Your goal here is to fill ray.intersection with correct values // should an intersection occur. This includes intersection.point, // intersection.normal, intersection.none, intersection.t_value. // // HINT: Remember to first transform the ray into object space // to simplify the intersection test. Vector3D v_d = worldToModel*ray.dir; Point3D p_e = worldToModel*ray.origin; Point3D p_a = Point3D(-0.5, -0.5, 0.0); Point3D p_b = Point3D(0.5, -0.5, 0.0); Point3D p_c = Point3D(-0.5, 0.5, 0.0); Vector3D ab = p_a - p_b; Vector3D ac = p_a - p_c; Vector3D ae = p_a - p_e; float a = ab[0]; float b = ab[1]; float c = ab[2]; float d = ac[0]; float e = ac[1]; float f = ac[2]; float g = v_d[0]; float h = v_d[1]; float i = v_d[2]; float j = ae[0]; float k = ae[1]; float l = ae[2]; float M = a*(e*i-h*f)+b*(g*f-d*i)+c*(d*h-e*g); float t = -(f*(a*k-j*b)+e*(j*c-a*l)+d*(b*l-k*c))/M; if (!ray.intersection.none && ray.intersection.t_value < t) { return false; } if (t < 0) { return false; } float gamma = (i*(a*k-j*b)+h*(j*c-a*l)+g*(b*l-k*c))/M; if ((gamma < 0)||(gamma>1)) { return false; } float beta = (j*(e*i-h*f)+k*(g*f-d*i)+l*(d*h-e*g))/M; if ((beta < 0)||(beta>1)) { return false; } ray.intersection.point = modelToWorld * (p_e + t*v_d); ray.intersection.normal = transNorm(modelToWorld, Vector3D(0.0, 0.0, 1.0)); ray.intersection.none = false; ray.intersection.t_value = t; return true; }
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) { Vector3D obj_dir = worldToModel * ray.dir; Point3D obj_ori = worldToModel * ray.origin; //ray =obj_ori + t * obj_dir //t^2 * (obj_dir·obj_dir)+ t * (2obj_ori·obj_dir) + obj_ori·obj_ori-1 double a = obj_dir.dot(obj_dir); Vector3D trans = obj_ori - Point3D(); //cast Point3D to Vector3D to use dot double b = 2 * trans.dot(obj_dir); double c = trans.dot(trans) - 1; double test = b*b - 4 * a * c; double t = 0; bool insideCrash=false; // std::cout << test <<std::endl; if(test < 0 || a == 0){ return false; }else if(test == 0){ t = -b/(2*a); }else{ double t1 = (-b + sqrt(test))/(2*a); double t2 = (-b - sqrt(test))/(2*a); if(t1>0 && t2<0){ insideCrash=true; t = t1; }else if(t1<=0 && t2>=0){ insideCrash=true; t = t2; }else if(t1 > 0 && t2 > 0){ if(t1 > t2){ t = t2; }else{ t = t1; } }else{ return false; } } double inter_x = obj_ori[0] + t * obj_dir[0]; double inter_y = obj_ori[1] + t * obj_dir[1]; double inter_z = obj_ori[2] + t * obj_dir[2]; if(t > 0 && (t < ray.intersection.t_value || ray.intersection.none)){ ray.intersection.point = modelToWorld * Point3D(inter_x, inter_y, inter_z); ray.intersection.t_value = t; ray.intersection.none = false; ray.intersection.insideCrash = insideCrash; Point3D p_n = Point3D(inter_x, inter_y, inter_z); //Vector3D n = Point3D() - p_n ; Vector3D n = p_n - Point3D(); n.normalize(); Vector3D inter_norm = transNorm(worldToModel, n); ray.intersection.normal = inter_norm; Point3D point = worldToModel * ray.intersection.point; double s = acos(point[2]/1.0)/M_PI; double t = acos(point[0]/(1.0*sin(M_PI * s)))/(2.0*M_PI); ray.intersection.textcoor = Point3D(s, t, 0); return true; }else{ return false; } }