cloudy-raytracer/shader/refractionshader.cpp

82 lines
2.9 KiB
C++
Raw Normal View History

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 {
// 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) {
return {0,0,0};
}
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 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 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 19:22:30 +01:00
return resultingColor;
2022-11-11 14:39:48 +01:00
}
bool RefractionShader::isTransparent() const { return true; }