2022-11-11 14:39:48 +01:00
|
|
|
#include "scene/scene.h"
|
|
|
|
#include "shader/refractionshader.h"
|
|
|
|
|
|
|
|
RefractionShader::RefractionShader(float indexInside, float indexOutside) : indexInside(indexInside), indexOutside(indexOutside) {}
|
|
|
|
|
|
|
|
Color RefractionShader::shade(Scene const &scene, Ray const &ray) const {
|
2022-11-17 17:45:26 +01:00
|
|
|
// IMPLEMENT ME
|
|
|
|
// Calculate the refracted ray using the surface normal vector and
|
|
|
|
// indexInside, indexOutside
|
|
|
|
// Also check for total internal reflection
|
|
|
|
// Send out a new refracted ray into the scene; recursively call traceRay()
|
|
|
|
|
|
|
|
if (ray.getRemainingBounces() < 1) {
|
2022-11-17 20:28:23 +01:00
|
|
|
return {0,0,0};
|
2022-11-17 17:45:26 +01:00
|
|
|
}
|
2022-11-17 19:22:30 +01:00
|
|
|
|
2022-11-17 20:34:37 +01:00
|
|
|
float eta1 = indexOutside;
|
|
|
|
float eta2 = indexInside;
|
2022-11-17 17:45:26 +01:00
|
|
|
|
|
|
|
|
2022-11-17 22:26:43 +01:00
|
|
|
Vector3d v = (ray.direction);
|
2022-11-17 19:22:30 +01:00
|
|
|
Vector3d n = normalized(ray.normal);
|
2022-11-17 17:45:26 +01:00
|
|
|
|
2022-11-17 19:22:30 +01:00
|
|
|
// Check whether we are entering or leaving the object
|
2022-11-17 20:34:37 +01:00
|
|
|
if (dotProduct(v, n) > 0) {
|
2022-11-17 22:27:10 +01:00
|
|
|
n = -n;
|
|
|
|
std::swap(eta1, eta2);
|
2022-11-17 19:22:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate refraction percentage
|
|
|
|
float denominator = 1.0f -
|
2022-11-17 20:34:37 +01:00
|
|
|
(std::pow(eta1, 2) * (1 - std::pow(dotProduct(v, n), 2)) /
|
|
|
|
std::pow(eta2, 2));
|
2022-11-17 19:22:30 +01:00
|
|
|
|
|
|
|
// Check whether there is any refracted ray at all or whether we have total internal reflection
|
|
|
|
if (denominator <= 0) {
|
|
|
|
Vector3d newDirection = v - 2.0f * dotProduct(n, v) * n;
|
|
|
|
|
|
|
|
Ray mirroredRay = Ray(ray.origin + ray.length * v, newDirection);
|
|
|
|
mirroredRay.setRemainingBounces(ray.getRemainingBounces() - 1);
|
|
|
|
|
|
|
|
return scene.traceRay(mirroredRay);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate refracted ray direction t
|
2022-11-17 22:26:43 +01:00
|
|
|
Vector3d t = (
|
2022-11-17 19:22:30 +01:00
|
|
|
eta1 / eta2 *
|
|
|
|
(v - dotProduct(v, n) * n) -
|
2022-11-17 20:34:37 +01:00
|
|
|
n * std::sqrt(denominator));
|
2022-11-17 19:22:30 +01:00
|
|
|
|
|
|
|
// Calculate reflected ray direction
|
2022-11-17 22:27:10 +01:00
|
|
|
auto cosTheta1 = dotProduct(-n, normalized(v));
|
|
|
|
auto cosTheta2 = std::sqrt(denominator);
|
2022-11-17 19:22:30 +01:00
|
|
|
|
2022-11-17 22:27:10 +01:00
|
|
|
auto polarizationParallel = (eta2 * cosTheta1 - eta1 * cosTheta2) /
|
2022-11-17 19:22:30 +01:00
|
|
|
(eta2 * cosTheta1 + eta1 * cosTheta2);
|
2022-11-17 22:27:10 +01:00
|
|
|
auto polarizationOrthogonal = (eta1 * cosTheta1 - eta2 * cosTheta2) /
|
2022-11-17 19:22:30 +01:00
|
|
|
(eta1 * cosTheta1 + eta2 * cosTheta2);
|
|
|
|
|
2022-11-17 22:27:10 +01:00
|
|
|
auto reflectionFactor = (polarizationParallel * polarizationParallel + polarizationOrthogonal * polarizationOrthogonal) / 2;
|
|
|
|
Vector3d reflectionVector = v - 2.0f * dotProduct(n, v) * n;
|
2022-11-17 19:22:30 +01:00
|
|
|
// Calculate rays
|
|
|
|
Vector3d rayOrigin = ray.origin + ray.length * ray.direction;
|
|
|
|
Ray refractionRay = Ray(rayOrigin, t);
|
|
|
|
Ray reflectionRay = Ray(rayOrigin, reflectionVector);
|
|
|
|
|
|
|
|
int remainingBounces = ray.getRemainingBounces() - 1;
|
|
|
|
|
|
|
|
refractionRay.setRemainingBounces(remainingBounces);
|
|
|
|
reflectionRay.setRemainingBounces(remainingBounces);
|
|
|
|
|
|
|
|
// Calculate Color
|
|
|
|
Color refractionColor = scene.traceRay(refractionRay);
|
|
|
|
Color reflectionColor = scene.traceRay(reflectionRay);
|
|
|
|
|
2022-11-17 22:27:10 +01:00
|
|
|
Color resultingColor = (1-reflectionFactor) * refractionColor + reflectionFactor * reflectionColor;
|
2022-11-17 17:45:26 +01:00
|
|
|
|
2022-11-17 19:22:30 +01:00
|
|
|
return resultingColor;
|
2022-11-11 14:39:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RefractionShader::isTransparent() const { return true; }
|