diff --git a/main/Scene.cc b/main/Scene.cc index 10888be..cf9681a 100644 --- a/main/Scene.cc +++ b/main/Scene.cc @@ -18,6 +18,8 @@ using namespace std; +#define MAX_AMBIENT_OCCLUSION_DISTANCE 50.0 + Scene::Scene(const map & options, const char * filename) { @@ -25,7 +27,7 @@ Scene::Scene(const map & options, m_height = 600; m_multisample_level = 1; m_vfov = 60.0; - m_ambient_light = Color(0.1, 0.1, 0.1); + m_ambient_light = Color(0.2, 0.2, 0.2); m_max_depth = 10; m_exposure = 1.0f; m_transforms.push(Transform()); @@ -213,7 +215,8 @@ Color Scene::computePhong(const refptr material, const Vector & surfacePoint, const Vector & surfaceNormal) { - Color result = m_ambient_light * material->getAmbientColor(); + Color result = m_ambient_light * material->getAmbientColor() + * calculateAmbientOcclusion(Ray(surfacePoint, surfaceNormal).shift(1e-7)); Vector viewDirection = -viewRay.getDirection(); double shininess = material->getShininess(); @@ -289,7 +292,7 @@ Color Scene::calculateLightContribution(const Ray & toLight, const Vector & lightPosition) { Color contrib(1.0, 1.0, 1.0); - double dist_to_light = lightPosition - toLight.getOrigin(); + double dist_to_light = (lightPosition - toLight.getOrigin()).mag(); double dist_so_far = 0.0; Ray currentRay = toLight; @@ -320,3 +323,44 @@ Color Scene::calculateLightContribution(const Ray & toLight, return contrib; } + +Color Scene::calculateAmbientOcclusion(const Ray & surfaceNormal) +{ + Color result(1, 1, 1); + const int nISteps = 6, nJSteps = 3; + int nRays = 0; + Vector perpX = surfaceNormal.getDirection().getPerpendicular().normalize(); + Vector perpY = (surfaceNormal.getDirection() * perpX).normalize(); + double istep = 2.0 * M_PI / nISteps; + double jstep = M_PI_2 / nJSteps; + for (int i = 0; i < nISteps; i++) + { + int lim = i > 0 ? nJSteps : 1; + for (int j = 0; j < lim; j++) + { + Vector direction = cos(i * istep) * sin(j * jstep) * perpX + + sin(i * istep) * sin(j * jstep) * perpY + + cos(j * jstep) * surfaceNormal.getDirection(); + Ray thisRay(surfaceNormal.getOrigin(), direction); + double dist = 0.0; + Color contrib(1, 1, 1); + while (contrib.r > 0.2 && contrib.g > 0.2 && contrib.b > 0.2) + { + Shape::Intersection hit = getRayClosestHit(thisRay); + if (hit.shape.isNull()) + break; + double hitDist = (hit.position - thisRay.getOrigin()).mag(); + dist += hitDist; + if (dist > MAX_AMBIENT_OCCLUSION_DISTANCE) + break; + contrib *= hit.shape->getMaterial()->getTransparency() + * hit.shape->getMaterial()->getDiffuseColor(); + thisRay = thisRay.shift(hitDist + 1E-7); + } + result += contrib; + nRays++; + } + } + result /= nRays; + return result; +} diff --git a/main/Scene.h b/main/Scene.h index 99781eb..f068523 100644 --- a/main/Scene.h +++ b/main/Scene.h @@ -50,6 +50,7 @@ class Scene const Vector & surfaceNormal); Color calculateLightContribution(const Ray & toLight, const Vector & lightPosition); + Color calculateAmbientOcclusion(const Ray & surfaceNormal); /* In Scene-load.cc */ void load(const char * filename); diff --git a/util/Color.h b/util/Color.h index 448aa4c..8524f07 100644 --- a/util/Color.h +++ b/util/Color.h @@ -38,6 +38,8 @@ class Color Color operator+(const Color & c1, const Color & c2); Color operator-(const Color & c1, const Color & c2); +static inline Color operator*(double d, const Color & c) { return c * d; } +static inline Color operator/(double d, const Color & c) { return c / d; } std::ostream & operator<<(std::ostream & out, const Color & color); #endif diff --git a/util/Vector.h b/util/Vector.h index 687c389..136ddbd 100644 --- a/util/Vector.h +++ b/util/Vector.h @@ -19,7 +19,6 @@ class Vector double dist_to(const Vector & other) const; Vector proj(const Vector & target) const; Vector reflect(const Vector & target) const; - operator double() const { return mag(); } Vector getPerpendicular() const; protected: @@ -33,5 +32,7 @@ Vector operator+(const Vector & v1, const Vector & v2); Vector operator-(const Vector & v1, const Vector & v2); Vector operator*(const Vector & v1, double scale); Vector operator/(const Vector & v1, double scale); +static inline Vector operator*(double d, const Vector & v) { return v * d; } +static inline Vector operator/(double d, const Vector & v) { return v / d; } #endif