diff --git a/src/Geometry.cc b/src/Geometry.cc index 1cd9c5a..6bc61bb 100644 --- a/src/Geometry.cc +++ b/src/Geometry.cc @@ -40,6 +40,8 @@ Vector3f Sphere::normal(const Vector3f &p) const { return (p - center).normalized(); } +Vector3f Sphere::sample() const { return center + Vector3f(radius, 0, 0); } + bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b, const Vector3f &c, const Vector3f &d, const Vector3f &n) { float s1 = (b - a).cross(p - a).dot(n); @@ -67,3 +69,5 @@ Optional Rectangle::intersect(const Ray &r) const { } Vector3f Rectangle::normal(const Vector3f &p) const { return normal_; } + +Vector3f Rectangle::sample() const { return p1; } diff --git a/src/Geometry.h b/src/Geometry.h index 2b8c947..e9e4d0f 100644 --- a/src/Geometry.h +++ b/src/Geometry.h @@ -20,6 +20,7 @@ public: virtual ~Geometry() = default; virtual Optional intersect(const Ray &) const = 0; virtual Vector3f normal(const Vector3f &) const = 0; + virtual Vector3f sample() const = 0; protected: Geometry(Type type, float ka, float kd, float ks, const Vector3f &ca, @@ -54,6 +55,7 @@ public: Optional intersect(const Ray &) const override; Vector3f normal(const Vector3f &) const override; + Vector3f sample() const override; private: float radius; @@ -70,6 +72,7 @@ public: Optional intersect(const Ray &) const override; Vector3f normal(const Vector3f &) const override; + Vector3f sample() const override; private: Vector3f p1, p2, p3, p4; diff --git a/src/Light.cc b/src/Light.cc index ce29101..c5d8b40 100644 --- a/src/Light.cc +++ b/src/Light.cc @@ -22,6 +22,10 @@ bool Light::isUse() const { return use; } Vector3f PointLight::getCenter() const { return center; } +bool lightOnSurface(Vector3f center, Geometry *g) { + return (g->sample() - center).dot(g->normal(center)) < 1e-5; +} + Vector3f PointLight::illumination(const HitRecord &hit, const vector &geometries) const { Vector3f shadingPoint = hit.point(); @@ -30,9 +34,9 @@ Vector3f PointLight::illumination(const HitRecord &hit, Ray shadowRay(shadingPoint, rayDirection); for (auto g : geometries) - if (g != geometry && g->intersect(shadowRay).hasValue() && - g->type() == Geometry::Type::SPHERE) - return Vector3f::Zero(); + if (g != geometry && g->intersect(shadowRay).hasValue()) + if (g->type() == Geometry::Type::SPHERE || !lightOnSurface(center, g)) + return Vector3f::Zero(); Vector3f ambient_ = geometry->ka() * geometry->ca().array() * Scene::current->ai().array(); diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 6b88d7b..a403a4b 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -67,6 +67,11 @@ void RayTracer::parse() { lights.push_back(Parser::getLight(*i)); } +Vector3f gammaCorrection(Vector3f color, float gammaInv) { + return Vector3f(std::pow(color.x(), gammaInv), std::pow(color.y(), gammaInv), + std::pow(color.z(), gammaInv)); +} + /** * Render the current scene * @@ -109,7 +114,7 @@ void RayTracer::render() { } if (success) - color = accumulate / success; + color = gammaCorrection(accumulate / success, 1.0f / 2.1f); } else { Ray ray = getRay(x, y); Optional hitRecord = getHitRecord(ray); @@ -141,15 +146,12 @@ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { /** * Find the nearest geometry to intersect */ -Optional RayTracer::getHitRecord(Ray r, const Geometry *self, - bool notRectangle) const { +Optional RayTracer::getHitRecord(Ray r, const Geometry *self) const { priority_queue records; for (auto g : geometries) { Optional t = g->intersect(r); if (t.hasValue() && g != self) - if (!notRectangle || - notRectangle && g->type() != Geometry::Type::RECTANGLE) - records.push(HitRecord(t.value(), r, g)); + records.push(HitRecord(t.value(), r, g)); } if (!records.empty()) { @@ -161,12 +163,8 @@ Optional RayTracer::getHitRecord(Ray r, const Geometry *self, return Optional::nullopt; } -Optional RayTracer::getHitRecord(Ray r, const Geometry *g) const { - return getHitRecord(r, g, false); -} - Optional RayTracer::getHitRecord(Ray r) const { - return getHitRecord(r, nullptr, false); + return getHitRecord(r, nullptr); } Light *RayTracer::singleLightSource() const { @@ -199,8 +197,8 @@ void writeColor(int i, const Vector3f &color) { Vector3f getRandomDirection() { RETRY_RANDOM: - float x = (float)rand() / RAND_MAX; - float y = (float)rand() / RAND_MAX; + float x = ((float)rand() / RAND_MAX) * 2 - 1; + float y = ((float)rand() / RAND_MAX) * 2 - 1; if (x * x + y * y > 1) goto RETRY_RANDOM; @@ -222,6 +220,17 @@ Vector3f getGlobalRandDirection(Vector3f normal) { return local2World * getRandomDirection(); } +bool lightOnSurface(HitRecord hit, const Light *l) { + Vector3f center = l->getCenter(); + Geometry *g = hit.geometry(); + Geometry::Type type = g->type(); + if (type == Geometry::Type::RECTANGLE) { + return (g->sample() - center).dot(g->normal(center)) < 1e-5; + } + + return false; +} + Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { RETRY_TRACING: bool finish = !bounce || ((float)rand() / RAND_MAX < prob); @@ -238,14 +247,16 @@ RETRY_TRACING: direction.normalize(); Ray ray(point + hit.normal() * 1e-6, direction); - Optional hitRecord = getHitRecord(ray, geometry, finish); + Optional hitRecord = getHitRecord(ray, geometry); Vector3f traceColor = Vector3f::Zero(); if (!finish && hitRecord.hasValue()) traceColor = trace(hitRecord.value(), bounce - 1, prob); else if (!finish && !hitRecord.hasValue()) goto RETRY_TRACING; - else if (finish && !hitRecord.hasValue()) - traceColor = light->id(); + else if (finish) + if (!hitRecord.hasValue() || + (hitRecord.hasValue() && lightOnSurface(hitRecord.value(), light))) + traceColor = light->id(); return traceColor.array() * geometry->cd().array() * std::max(0.0f, hit.normal().dot(direction)); diff --git a/src/RayTracer.h b/src/RayTracer.h index d3c635a..d6ff470 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -24,7 +24,6 @@ private: void parse(); void render(); - Optional getHitRecord(Ray, const Geometry *, bool) const; Optional getHitRecord(Ray, const Geometry *) const; Optional getHitRecord(Ray) const; Vector3f calculateColor(const HitRecord &, int) const;