nuclear@4: #include nuclear@4: #include "geomobj.h" nuclear@4: nuclear@4: static LambertRefl lambert; nuclear@4: nuclear@4: GeomObject::GeomObject() nuclear@4: { nuclear@4: brdf = &lambert; nuclear@4: } nuclear@4: nuclear@4: ObjType GeomObject::get_type() const nuclear@4: { nuclear@4: return ObjType::geom; nuclear@4: } nuclear@4: nuclear@4: bool GeomObject::intersect(const Ray &ray, RayHit *hit) const nuclear@4: { nuclear@4: return false; nuclear@4: } nuclear@4: nuclear@8: Vector3 GeomObject::calc_normal(const RayHit &hit) const nuclear@8: { nuclear@8: // when you look at singularities, the singularities always look back at you :) nuclear@8: return -(hit.world_ray.dir).normalized(); nuclear@8: } nuclear@8: nuclear@8: Vector3 GeomObject::calc_tangent(const RayHit &hit) const nuclear@8: { nuclear@8: return Vector3(1, 0, 0); // whatever... nuclear@8: } nuclear@8: nuclear@8: Vector2 GeomObject::calc_texcoords(const RayHit &hit) const nuclear@8: { nuclear@8: return Vector2(); nuclear@8: } nuclear@8: nuclear@4: // --- class Sphere --- nuclear@4: nuclear@4: bool Sphere::intersect(const Ray &ray, RayHit *hit) const nuclear@4: { nuclear@4: // assumes center is the origin and radius is 1 nuclear@4: float a = dot_product(ray.dir, ray.dir); nuclear@4: float b = 2.0 * dot_product(ray.dir, ray.origin); nuclear@4: float c = dot_product(ray.origin, ray.origin) - 1.0; nuclear@4: nuclear@4: float d = b * b - 4.0 * a * c; nuclear@4: if(d < 1e-4) return false; nuclear@4: nuclear@4: float sqrt_d = sqrt(d); nuclear@4: float t0 = (-b + sqrt_d) / (2.0 * a); nuclear@4: float t1 = (-b - sqrt_d) / (2.0 * a); nuclear@4: nuclear@4: if(t0 < 1e-4) t0 = t1; nuclear@4: if(t1 < 1e-4) t1 = t0; nuclear@4: float t = t0 < t1 ? t0 : t1; nuclear@4: if(t < 1e-4) return false; nuclear@4: nuclear@4: if(hit) { nuclear@4: hit->dist = t; nuclear@4: hit->obj = this; nuclear@4: hit->subobj = 0; nuclear@4: } nuclear@4: return true; nuclear@4: } nuclear@4: nuclear@8: Vector3 Sphere::calc_normal(const RayHit &hit) const nuclear@8: { nuclear@8: Vector3 pt = hit.world_ray.origin + hit.world_ray.dir * hit.dist; nuclear@8: return pt.normalized(); nuclear@8: } nuclear@8: nuclear@8: static inline Vector3 sphvec(float u, float v) nuclear@8: { nuclear@8: float theta = u * M_PI * 2.0; nuclear@8: float phi = v * M_PI; nuclear@8: nuclear@8: return Vector3(sin(theta) * sin(phi), cos(phi), cos(theta) * sin(phi)); nuclear@8: } nuclear@8: nuclear@8: Vector3 Sphere::calc_tangent(const RayHit &hit) const nuclear@8: { nuclear@8: Vector2 uv = calc_texcoords(hit); nuclear@8: Vector3 pnext = sphvec(uv.x + 0.05, 0.5); nuclear@8: Vector3 pprev = sphvec(uv.y - 0.05, 0.5); nuclear@8: return (pnext - pprev).normalized(); nuclear@8: } nuclear@8: nuclear@8: Vector2 Sphere::calc_texcoords(const RayHit &hit) const nuclear@8: { nuclear@8: Vector3 pt = hit.world_ray.origin + hit.world_ray.dir * hit.dist; nuclear@8: pt.normalize(); nuclear@8: nuclear@8: float theta = atan2(pt.z, pt.x); nuclear@8: float phi = acos(pt.y); nuclear@8: nuclear@8: return Vector2(theta / M_PI + 0.5, phi / M_PI); nuclear@8: } nuclear@8: nuclear@8: nuclear@4: // --- class Box --- nuclear@4: nuclear@4: bool Box::intersect(const Ray &ray, RayHit *hit) const nuclear@4: { nuclear@4: return false; nuclear@4: } nuclear@4: nuclear@4: // --- class Triangle --- nuclear@4: nuclear@4: bool Triangle::intersect(const Ray &ray, RayHit *hit) const nuclear@4: { nuclear@4: return false; nuclear@4: } nuclear@4: nuclear@4: // --- class Mesh --- nuclear@4: nuclear@4: bool Mesh::intersect(const Ray &ray, RayHit *hit) const nuclear@4: { nuclear@4: RayHit nearest; nuclear@4: nearest.dist = FLT_MAX; nuclear@4: nuclear@4: for(size_t i=0; idist < nearest.dist) { nuclear@4: nearest = *hit; nuclear@4: } nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: if(nearest.dist < FLT_MAX) { nuclear@4: *hit = nearest; nuclear@4: hit->subobj = hit->obj; nuclear@4: hit->obj = this; nuclear@4: return true; nuclear@4: } nuclear@4: return false; nuclear@4: }