146 lines
6.4 KiB
C++
146 lines
6.4 KiB
C++
//
|
|
// Created by Göksu Güvendiren on 2019-05-14.
|
|
//
|
|
|
|
#include "Scene.hpp"
|
|
|
|
|
|
void Scene::buildBVH() {
|
|
printf(" - Generating BVH...\n\n");
|
|
this->bvh = new BVHAccel(objects, 1, BVHAccel::SplitMethod::NAIVE);
|
|
}
|
|
|
|
Intersection Scene::intersect(const Ray &ray) const
|
|
{
|
|
return this->bvh->Intersect(ray);
|
|
}
|
|
|
|
bool Scene::trace(
|
|
const Ray &ray,
|
|
const std::vector<Object*> &objects,
|
|
float &tNear, uint32_t &index, Object **hitObject)
|
|
{
|
|
*hitObject = nullptr;
|
|
for (uint32_t k = 0; k < objects.size(); ++k) {
|
|
float tNearK = kInfinity;
|
|
uint32_t indexK;
|
|
Vector2f uvK;
|
|
if (objects[k]->intersect(ray, tNearK, indexK) && tNearK < tNear) {
|
|
*hitObject = objects[k];
|
|
tNear = tNearK;
|
|
index = indexK;
|
|
}
|
|
}
|
|
|
|
|
|
return (*hitObject != nullptr);
|
|
}
|
|
|
|
// Implementation of the Whitted-syle light transport algorithm (E [S*] (D|G) L)
|
|
//
|
|
// This function is the function that compute the color at the intersection point
|
|
// of a ray defined by a position and a direction. Note that thus function is recursive (it calls itself).
|
|
//
|
|
// If the material of the intersected object is either reflective or reflective and refractive,
|
|
// then we compute the reflection/refracton direction and cast two new rays into the scene
|
|
// by calling the castRay() function recursively. When the surface is transparent, we mix
|
|
// the reflection and refraction color using the result of the fresnel equations (it computes
|
|
// the amount of reflection and refractin depending on the surface normal, incident view direction
|
|
// and surface refractive index).
|
|
//
|
|
// If the surface is duffuse/glossy we use the Phong illumation model to compute the color
|
|
// at the intersection point.
|
|
Vector3f Scene::castRay(const Ray &ray, int depth) const
|
|
{
|
|
if (depth > this->maxDepth) {
|
|
return Vector3f(0.0,0.0,0.0);
|
|
}
|
|
Intersection intersection = Scene::intersect(ray);
|
|
Material *m = intersection.m;
|
|
Object *hitObject = intersection.obj;
|
|
Vector3f hitColor = this->backgroundColor;
|
|
// float tnear = kInfinity;
|
|
Vector2f uv;
|
|
uint32_t index = 0;
|
|
if(intersection.happened) {
|
|
|
|
Vector3f hitPoint = intersection.coords;
|
|
Vector3f N = intersection.normal; // normal
|
|
Vector2f st; // st coordinates
|
|
hitObject->getSurfaceProperties(hitPoint, ray.direction, index, uv, N, st);
|
|
// Vector3f tmp = hitPoint;
|
|
switch (m->getType()) {
|
|
case REFLECTION_AND_REFRACTION:
|
|
{
|
|
Vector3f reflectionDirection = normalize(reflect(ray.direction, N));
|
|
Vector3f refractionDirection = normalize(refract(ray.direction, N, m->ior));
|
|
Vector3f reflectionRayOrig = (dotProduct(reflectionDirection, N) < 0) ?
|
|
hitPoint - N * EPSILON :
|
|
hitPoint + N * EPSILON;
|
|
Vector3f refractionRayOrig = (dotProduct(refractionDirection, N) < 0) ?
|
|
hitPoint - N * EPSILON :
|
|
hitPoint + N * EPSILON;
|
|
Vector3f reflectionColor = castRay(Ray(reflectionRayOrig, reflectionDirection), depth + 1);
|
|
Vector3f refractionColor = castRay(Ray(refractionRayOrig, refractionDirection), depth + 1);
|
|
float kr;
|
|
fresnel(ray.direction, N, m->ior, kr);
|
|
hitColor = reflectionColor * kr + refractionColor * (1 - kr);
|
|
break;
|
|
}
|
|
case REFLECTION:
|
|
{
|
|
float kr;
|
|
fresnel(ray.direction, N, m->ior, kr);
|
|
Vector3f reflectionDirection = reflect(ray.direction, N);
|
|
Vector3f reflectionRayOrig = (dotProduct(reflectionDirection, N) < 0) ?
|
|
hitPoint + N * EPSILON :
|
|
hitPoint - N * EPSILON;
|
|
hitColor = castRay(Ray(reflectionRayOrig, reflectionDirection),depth + 1) * kr;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// [comment]
|
|
// We use the Phong illumation model int the default case. The phong model
|
|
// is composed of a diffuse and a specular reflection component.
|
|
// [/comment]
|
|
Vector3f lightAmt = 0, specularColor = 0;
|
|
Vector3f shadowPointOrig = (dotProduct(ray.direction, N) < 0) ?
|
|
hitPoint + N * EPSILON :
|
|
hitPoint - N * EPSILON;
|
|
// [comment]
|
|
// Loop over all lights in the scene and sum their contribution up
|
|
// We also apply the lambert cosine law
|
|
// [/comment]
|
|
for (uint32_t i = 0; i < get_lights().size(); ++i)
|
|
{
|
|
auto area_ptr = dynamic_cast<AreaLight*>(this->get_lights()[i].get());
|
|
if (area_ptr)
|
|
{
|
|
// Do nothing for this assignment
|
|
}
|
|
else
|
|
{
|
|
Vector3f lightDir = get_lights()[i]->position - hitPoint;
|
|
// square of the distance between hitPoint and the light
|
|
float lightDistance2 = dotProduct(lightDir, lightDir);
|
|
lightDir = normalize(lightDir);
|
|
float LdotN = std::max(0.f, dotProduct(lightDir, N));
|
|
Object *shadowHitObject = nullptr;
|
|
float tNearShadow = kInfinity;
|
|
// is the point in shadow, and is the nearest occluding object closer to the object than the light itself?
|
|
bool inShadow = bvh->Intersect(Ray(shadowPointOrig, lightDir)).happened;
|
|
lightAmt += (1 - inShadow) * get_lights()[i]->intensity * LdotN;
|
|
Vector3f reflectionDirection = reflect(-lightDir, N);
|
|
specularColor += powf(std::max(0.f, -dotProduct(reflectionDirection, ray.direction)),
|
|
m->specularExponent) * get_lights()[i]->intensity;
|
|
}
|
|
}
|
|
hitColor = lightAmt * (hitObject->evalDiffuseColor(st) * m->Kd + specularColor * m->Ks);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hitColor;
|
|
} |