nuclear@16: #include 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@17: return -(hit.local_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@17: if(d < 1e-6) 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@17: if(t0 < 1e-6) t0 = t1; nuclear@17: if(t1 < 1e-6) t1 = t0; nuclear@4: float t = t0 < t1 ? t0 : t1; nuclear@17: if(t < 1e-6) 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@17: Vector3 pt = hit.local_ray.origin + hit.local_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@17: Vector3 pt = hit.local_ray.origin + hit.local_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@18: Vector3 param[2] = {Vector3{-0.5, -0.5, -0.5}, Vector3{0.5, 0.5, 0.5}}; nuclear@18: Vector3 inv_dir{1.0f / ray.dir.x, 1.0f / ray.dir.y, 1.0f / ray.dir.z}; nuclear@18: int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; nuclear@18: nuclear@18: float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; nuclear@18: float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; nuclear@18: float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; nuclear@18: float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; nuclear@18: nuclear@18: if(tmin > tymax || tymin > tmax) { nuclear@18: return false; nuclear@18: } nuclear@18: if(tymin > tmin) { nuclear@18: tmin = tymin; nuclear@18: } nuclear@18: if(tymax < tmax) { nuclear@18: tmax = tymax; nuclear@18: } nuclear@18: nuclear@18: float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; nuclear@18: float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; nuclear@18: nuclear@18: if(tmin > tzmax || tzmin > tmax) { nuclear@18: return false; nuclear@18: } nuclear@18: if(tzmin > tmin) { nuclear@18: tmin = tzmin; nuclear@18: } nuclear@18: if(tzmax < tmax) { nuclear@18: tmax = tzmax; nuclear@18: } nuclear@18: nuclear@18: float t = tmin < 1e-4 ? tmax : tmin; nuclear@18: if(t >= 1e-4) { nuclear@18: if(hit) { nuclear@18: hit->obj = this; nuclear@18: hit->dist = t; nuclear@18: } nuclear@18: return true; nuclear@18: } nuclear@4: return false; nuclear@18: nuclear@18: } nuclear@18: nuclear@18: #define BOX_EXT 0.499999 nuclear@18: Vector3 Box::calc_normal(const RayHit &hit) const nuclear@18: { nuclear@18: Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist; nuclear@18: if(pt.x > BOX_EXT) return Vector3(1, 0, 0); nuclear@18: if(pt.x < -BOX_EXT) return Vector3(-1, 0, 0); nuclear@18: if(pt.y > BOX_EXT) return Vector3(0, 1, 0); nuclear@18: if(pt.y < -BOX_EXT) return Vector3(0, -1, 0); nuclear@18: if(pt.z > BOX_EXT) return Vector3(0, 0, 1); nuclear@18: if(pt.z < -BOX_EXT) return Vector3(0, 0, -1); nuclear@18: return Vector3(0, 0, 0); // shouldn't happen unless numerical precision is fucked nuclear@18: } nuclear@18: nuclear@18: Vector3 Box::calc_tangent(const RayHit &hit) const nuclear@18: { nuclear@18: return Vector3(1, 0, 0); // TODO nuclear@18: } nuclear@18: nuclear@18: Vector2 Box::calc_texcoords(const RayHit &hit) const nuclear@18: { nuclear@18: return Vector2(0, 0); // TODO 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: }