nuclear@0: #include nuclear@0: #include nuclear@0: #include "geom.h" nuclear@0: nuclear@0: GeomObject::~GeomObject() nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: nuclear@0: Sphere::Sphere() nuclear@0: { nuclear@0: radius = 1.0; nuclear@0: } nuclear@0: nuclear@0: Sphere::Sphere(const Vector3 ¢, float radius) nuclear@0: : center(cent) nuclear@0: { nuclear@0: this->radius = radius; nuclear@0: } nuclear@0: nuclear@0: void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2) nuclear@0: { nuclear@0: const Sphere *sph1 = dynamic_cast(obj1); nuclear@0: const Sphere *sph2 = dynamic_cast(obj2); nuclear@0: nuclear@0: if(!sph1 || !sph2) { nuclear@0: fprintf(stderr, "Sphere::set_union: arguments must be spheres"); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: float dist = (sph1->center - sph2->center).length(); nuclear@0: float surf_dist = dist - (sph1->radius + sph2->radius); nuclear@0: float d1 = sph1->radius + surf_dist / 2.0; nuclear@0: float d2 = sph2->radius + surf_dist / 2.0; nuclear@0: float t = d1 / (d1 + d2); nuclear@0: nuclear@0: if(t < 0.0) t = 0.0; nuclear@0: if(t > 1.0) t = 1.0; nuclear@0: nuclear@0: center = sph1->center * t + sph2->center * (1.0 - t); nuclear@0: radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius); nuclear@0: } nuclear@0: nuclear@0: void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2) nuclear@0: { nuclear@0: fprintf(stderr, "Sphere::intersection undefined\n"); nuclear@0: } nuclear@0: nuclear@0: bool Sphere::intersect(const Ray &ray, HitPoint *hit) const nuclear@0: { nuclear@0: float a = dot_product(ray.dir, ray.dir); nuclear@0: float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) + nuclear@0: 2.0 * ray.dir.y * (ray.origin.y - center.y) + nuclear@0: 2.0 * ray.dir.z * (ray.origin.z - center.z); nuclear@0: float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) - nuclear@0: 2.0 * dot_product(ray.origin, center) - radius * radius; nuclear@0: nuclear@0: float discr = b * b - 4.0 * a * c; nuclear@0: if(discr < 1e-4) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: float sqrt_discr = sqrt(discr); nuclear@0: float t0 = (-b + sqrt_discr) / (2.0 * a); nuclear@0: float t1 = (-b - sqrt_discr) / (2.0 * a); nuclear@0: nuclear@0: if(t0 < 1e-4) nuclear@0: t0 = t1; nuclear@0: if(t1 < 1e-4) nuclear@0: t1 = t0; nuclear@0: nuclear@0: float t = t0 < t1 ? t0 : t1; nuclear@0: if(t < 1e-4) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // fill the HitPoint structure nuclear@0: if(hit) { nuclear@0: hit->obj = this; nuclear@0: hit->dist = t; nuclear@0: hit->pos = ray.origin + ray.dir * t; nuclear@0: hit->normal = (hit->pos - center) / radius; nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: AABox::AABox() nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: AABox::AABox(const Vector3 &vmin, const Vector3 &vmax) nuclear@0: : min(vmin), max(vmax) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2) nuclear@0: { nuclear@0: const AABox *box1 = dynamic_cast(obj1); nuclear@0: const AABox *box2 = dynamic_cast(obj2); nuclear@0: nuclear@0: if(!box1 || !box2) { nuclear@0: fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n"); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: min.x = std::min(box1->min.x, box2->min.x); nuclear@0: min.y = std::min(box1->min.y, box2->min.y); nuclear@0: min.z = std::min(box1->min.z, box2->min.z); nuclear@0: nuclear@0: max.x = std::max(box1->max.x, box2->max.x); nuclear@0: max.y = std::max(box1->max.y, box2->max.y); nuclear@0: max.z = std::max(box1->max.z, box2->max.z); nuclear@0: } nuclear@0: nuclear@0: void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2) nuclear@0: { nuclear@0: const AABox *box1 = dynamic_cast(obj1); nuclear@0: const AABox *box2 = dynamic_cast(obj2); nuclear@0: nuclear@0: if(!box1 || !box2) { nuclear@0: fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n"); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: for(int i=0; i<3; i++) { nuclear@0: min[i] = std::max(box1->min[i], box2->min[i]); nuclear@0: max[i] = std::min(box1->max[i], box2->max[i]); nuclear@0: nuclear@0: if(max[i] < min[i]) { nuclear@0: max[i] = min[i]; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: bool AABox::intersect(const Ray &ray, HitPoint *hit) const nuclear@0: { nuclear@0: Vector3 param[2] = {min, max}; nuclear@0: Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); nuclear@0: int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; nuclear@0: nuclear@0: float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; nuclear@0: float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; nuclear@0: float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; nuclear@0: float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; nuclear@0: nuclear@0: if(tmin > tymax || tymin > tmax) { nuclear@0: return false; nuclear@0: } nuclear@0: if(tymin > tmin) { nuclear@0: tmin = tymin; nuclear@0: } nuclear@0: if(tymax < tmax) { nuclear@0: tmax = tymax; nuclear@0: } nuclear@0: nuclear@0: float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; nuclear@0: float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; nuclear@0: nuclear@0: if(tmin > tzmax || tzmin > tmax) { nuclear@0: return false; nuclear@0: } nuclear@0: if(tzmin > tmin) { nuclear@0: tmin = tzmin; nuclear@0: } nuclear@0: if(tzmax < tmax) { nuclear@0: tmax = tzmax; nuclear@0: } nuclear@0: nuclear@0: float t = tmin < 1e-4 ? tmax : tmin; nuclear@0: if(t >= 1e-4) { nuclear@0: nuclear@0: if(hit) { nuclear@0: hit->obj = this; nuclear@0: hit->dist = t; nuclear@0: hit->pos = ray.origin + ray.dir * t; nuclear@0: nuclear@0: float min_dist = FLT_MAX; nuclear@0: Vector3 offs = min + (max - min) / 2.0; nuclear@0: Vector3 local_hit = hit->pos - offs; nuclear@0: nuclear@0: static const Vector3 axis[] = { nuclear@0: Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) nuclear@0: }; nuclear@0: //int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}}; nuclear@0: nuclear@0: for(int i=0; i<3; i++) { nuclear@0: float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i])); nuclear@0: if(dist < min_dist) { nuclear@0: min_dist = dist; nuclear@0: hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0); nuclear@0: //hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: return false; nuclear@0: nuclear@0: } nuclear@0: nuclear@0: Plane::Plane() nuclear@0: : normal(0.0, 1.0, 0.0) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: Plane::Plane(const Vector3 &p, const Vector3 &norm) nuclear@0: : pt(p) nuclear@0: { nuclear@0: normal = norm.normalized(); nuclear@0: } nuclear@0: nuclear@0: Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3) nuclear@0: : pt(p1) nuclear@0: { nuclear@0: normal = cross_product(p2 - p1, p3 - p1).normalized(); nuclear@0: } nuclear@0: nuclear@0: Plane::Plane(const Vector3 &normal, float dist) nuclear@0: { nuclear@0: this->normal = normal.normalized(); nuclear@0: pt = this->normal * dist; nuclear@0: } nuclear@0: nuclear@0: void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2) nuclear@0: { nuclear@0: fprintf(stderr, "Plane::set_union undefined\n"); nuclear@0: } nuclear@0: nuclear@0: void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2) nuclear@0: { nuclear@0: fprintf(stderr, "Plane::set_intersection undefined\n"); nuclear@0: } nuclear@0: nuclear@0: bool Plane::intersect(const Ray &ray, HitPoint *hit) const nuclear@0: { nuclear@0: float ndotdir = dot_product(normal, ray.dir); nuclear@0: if(fabs(ndotdir) < 1e-4) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: if(hit) { nuclear@0: Vector3 ptdir = pt - ray.origin; nuclear@0: float t = dot_product(normal, ptdir) / ndotdir; nuclear@0: nuclear@0: hit->pos = ray.origin + ray.dir * t; nuclear@0: hit->normal = normal; nuclear@0: hit->obj = this; nuclear@0: } nuclear@0: return true; nuclear@0: }