/* * DoRayMe - a quick and dirty Raytracer * Cone implementation * * Created by Manoƫl Trapier * Copyright (c) 2020 986-Studio. * */ #include #include #include #include #include bool Cone::checkCap(Ray r, double t, double y) { /* Helping function to reduce duplication. * Checks to see if the intersection ot t is within a radius * of 1 (the radius of our Cone from the y axis */ double x = r.origin.x + t * r.direction.x; double z = r.origin.z + t * r.direction.z; return (x * x + z * z) <= fabs(y); } void Cone::intersectCaps(Ray r, Intersect &xs) { /* Caps only mattter is the Cone is closed, and might possibly be * intersected by the ray */ if ((this->isClosed) && (fabs(r.direction.y) > getEpsilon())) { double t; /* Check for an intersection with the lower end cap by intersecting * the ray with the plan at y = this->minCap */ t = (this->minCap - r.origin.y) / r.direction.y; if (this->checkCap(r, t, this->minCap)) { xs.add(Intersection(t, this)); } /* Check for an intersection with the upper end cap by intersecting * the ray with the plan at y = this->maxCap */ t = (this->maxCap - r.origin.y) / r.direction.y; if (this->checkCap(r, t, this->maxCap)) { xs.add(Intersection(t, this)); } } } Intersect Cone::localIntersect(Ray r) { Intersect ret; double A = (r.direction.x * r.direction.x) - (r.direction.y * r.direction.y) + (r.direction.z * r.direction.z); double B = (2 * r.origin.x * r.direction.x) - (2 * r.origin.y * r.direction.y) + (2 * r.origin.z * r.direction.z); double C = (r.origin.x * r.origin.x) - (r.origin.y * r.origin.y) + (r.origin.z * r.origin.z); if ((fabs(A) <= getEpsilon()) && (fabs(B) >= getEpsilon())) { double t = -C / (2*B); ret.add(Intersection(t, this)); } else if (fabs(A) >= getEpsilon()) { double disc = (B * B) - 4 * A * C; if (disc >= 0) { double t0 = (-B - sqrt(disc)) / (2 * A); double t1 = (-B + sqrt(disc)) / (2 * A); double y0 = r.origin.y + t0 * r.direction.y; if ((this->minCap < y0) && (y0 < this->maxCap)) { ret.add(Intersection(t0, this)); } double y1 = r.origin.y + t1 * r.direction.y; if ((this->minCap < y1) && (y1 < this->maxCap)) { ret.add(Intersection(t1, this)); } } } this->intersectCaps(r, ret); return ret; } Tuple Cone::localNormalAt(Tuple point, Intersection *hit) { /* Compute the square of the distance from the Y axis */ double dist = point.x * point.x + point.z * point.z; if ((dist < 1) && (point.y >= (this->maxCap - getEpsilon()))) { return Vector(0, 1, 0); } if ((dist < 1) && (point.y <= this->minCap + getEpsilon())) { return Vector(0, -1, 0); } double y = sqrt(point.x * point.x + point.z * point.z); if (point.y > 0) { y = -y; } return Vector(point.x, y, point.z); } BoundingBox Cone::getLocalBounds() { BoundingBox ret; double a = fabs(this->minCap); double b = fabs(this->maxCap); double limit = (a > b)?a:b; ret | Point(-limit, this->minCap, -limit); ret | Point(limit, this->maxCap, limit); return ret; } void Cone::dumpMe(FILE *fp) { fprintf(fp, "\"Type\": \"Cylinder\",\n"); Tuple t = this->transformMatrix * Point(0, 0, 0); fprintf(fp, "\"pseudocenter\": { \"x\": %f, \"y\": %f, \"z\": %f}, \n", t.x, t.y, t.z); t = this->transformMatrix * Point(0, this->minCap, 0); fprintf(fp, "\"min\": %f, \n", t.y); t = this->transformMatrix * Point(1, this->maxCap, 1); fprintf(fp, "\"max\": %f, \n", t.y); Shape::dumpMe(fp); }