nuclear@16: #include nuclear@4: #include nuclear@41: #include nuclear@4: #include "geomobj.h" nuclear@41: #include "erebus_impl.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@41: Vector3 GeomObject::gen_surface_point() const nuclear@41: { nuclear@41: return Vector3(0, 0, 0); nuclear@41: } nuclear@41: 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@43: if(d < 1e-5) 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@43: if(t0 < 1e-5) t0 = t1; nuclear@43: if(t1 < 1e-5) t1 = t0; nuclear@4: float t = t0 < t1 ? t0 : t1; nuclear@43: if(t < 1e-5) 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@41: Vector3 Sphere::gen_surface_point() const nuclear@41: { nuclear@41: return sphrand(1.0); nuclear@41: } nuclear@41: 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@43: float t = tmin < 1e-5 ? tmax : tmin; nuclear@43: if(t >= 1e-5) { 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@41: } nuclear@18: nuclear@41: #define SIGN(x) (x >= 0.0 ? 1.0 : -1.0) nuclear@41: nuclear@41: Vector3 Box::gen_surface_point() const nuclear@41: { nuclear@41: Vector3 rnd{randf(-1, 1), randf(-1, 1), randf(-1, 1)}; nuclear@41: float absrnd[3]; nuclear@41: nuclear@41: absrnd[0] = fabs(rnd.x); nuclear@41: absrnd[1] = fabs(rnd.y); nuclear@41: absrnd[2] = fabs(rnd.z); nuclear@41: nuclear@41: int major = 0; nuclear@41: for(int i=1; i<3; i++) { nuclear@41: if(absrnd[i] > absrnd[major]) { nuclear@41: major = i; nuclear@41: } nuclear@41: } nuclear@41: rnd[major] = SIGN(rnd[major]); nuclear@41: return rnd; 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@41: Vector3 Triangle::gen_surface_point() const nuclear@41: { nuclear@41: float bu = randf(); nuclear@41: float bv = randf(); nuclear@41: float bw = 1.0 - (bu + bv); nuclear@41: nuclear@41: return v[0] * bu + v[1] * bv + v[2] * bw; nuclear@41: } nuclear@41: 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: } nuclear@41: nuclear@41: Vector3 Mesh::gen_surface_point() const nuclear@41: { nuclear@41: // this needs some precalculation... nuclear@41: return Vector3(0, 0, 0); // TODO nuclear@41: }