Colored refraction shader
This commit is contained in:
parent
7ec5a8a5f4
commit
3b76969ff2
2 changed files with 63 additions and 51 deletions
|
@ -1,51 +1,60 @@
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
#include "shader/refractionshader.h"
|
#include "shader/refractionshader.h"
|
||||||
|
|
||||||
RefractionShader::RefractionShader(float indexInside, float indexOutside) : indexInside(indexInside), indexOutside(indexOutside) {}
|
RefractionShader::RefractionShader(float indexInside, float indexOutside, Color const &objectColor) : indexInside(
|
||||||
|
indexInside), indexOutside(indexOutside), objectColor(objectColor)
|
||||||
|
{}
|
||||||
|
|
||||||
Color RefractionShader::shade(Scene const &scene, Ray const &ray) const {
|
Color RefractionShader::shade(Scene const &scene, Ray const &ray) const
|
||||||
// Circumvent getting environment map color into the mix
|
{
|
||||||
if (ray.getRemainingBounces() > 0) {
|
// Circumvent getting environment map color into the mix
|
||||||
// Get the normal of the primitive which was hit
|
if (ray.getRemainingBounces() > 0)
|
||||||
Vector3d normalVector = ray.normal;
|
{
|
||||||
|
// Get the normal of the primitive which was hit
|
||||||
|
Vector3d normalVector = ray.normal;
|
||||||
|
|
||||||
// Calculate the index of refraction
|
// Calculate the index of refraction
|
||||||
float refractiveIndex = indexOutside / indexInside;
|
float refractiveIndex = indexOutside / indexInside;
|
||||||
// What if we are already inside the object?
|
// What if we are already inside the object?
|
||||||
if (dotProduct(normalVector, ray.direction) > 0) {
|
if (dotProduct(normalVector, ray.direction) > 0)
|
||||||
normalVector = -normalVector;
|
{
|
||||||
refractiveIndex = indexInside / indexOutside;
|
normalVector = -normalVector;
|
||||||
|
refractiveIndex = indexInside / indexOutside;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using the notation from the lecture
|
||||||
|
float cosineTheta = dotProduct(normalVector, -ray.direction);
|
||||||
|
float cosinePhi = std::sqrt(1 + refractiveIndex * refractiveIndex * (cosineTheta * cosineTheta - 1));
|
||||||
|
// Calculate t, the new ray direction
|
||||||
|
Vector3d t = refractiveIndex * ray.direction + (refractiveIndex * cosineTheta - cosinePhi) * normalVector;
|
||||||
|
|
||||||
|
// Create the refraction ray
|
||||||
|
Ray refractionRay = ray;
|
||||||
|
// Reset the ray
|
||||||
|
refractionRay.length = INFINITY;
|
||||||
|
refractionRay.primitive = nullptr;
|
||||||
|
|
||||||
|
// Check whether it is a refraction.
|
||||||
|
if (dotProduct(t, normalVector) <= 0.0)
|
||||||
|
{
|
||||||
|
refractionRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
|
||||||
|
refractionRay.direction = normalized(t);
|
||||||
|
} else
|
||||||
|
{ // Otherwise, it is a total reflection.
|
||||||
|
refractionRay.origin = ray.origin + (ray.length - REFR_EPS) * ray.direction;
|
||||||
|
// Next we get the reflection vector
|
||||||
|
Vector3d const reflectionVector =
|
||||||
|
ray.direction - 2.0f * dotProduct(normalVector, ray.direction) * normalVector;
|
||||||
|
|
||||||
|
// Change the ray direction and origin
|
||||||
|
refractionRay.direction = normalized(reflectionVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send out a new refracted ray into the scene
|
||||||
|
return scene.traceRay(refractionRay) * objectColor;
|
||||||
}
|
}
|
||||||
|
return Color(0.0f, 0.0f, 0.0f);
|
||||||
// Using the notation from the lecture
|
|
||||||
float cosineTheta = dotProduct(normalVector, -ray.direction);
|
|
||||||
float cosinePhi = std::sqrt(1 + refractiveIndex * refractiveIndex * (cosineTheta * cosineTheta - 1));
|
|
||||||
// Calculate t, the new ray direction
|
|
||||||
Vector3d t = refractiveIndex * ray.direction + (refractiveIndex * cosineTheta - cosinePhi) * normalVector;
|
|
||||||
|
|
||||||
// Create the refraction ray
|
|
||||||
Ray refractionRay = ray;
|
|
||||||
// Reset the ray
|
|
||||||
refractionRay.length = INFINITY;
|
|
||||||
refractionRay.primitive = nullptr;
|
|
||||||
|
|
||||||
// Check whether it is a refraction.
|
|
||||||
if (dotProduct(t, normalVector) <= 0.0) {
|
|
||||||
refractionRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
|
|
||||||
refractionRay.direction = normalized(t);
|
|
||||||
} else { // Otherwise, it is a total reflection.
|
|
||||||
refractionRay.origin = ray.origin + (ray.length - REFR_EPS) * ray.direction;
|
|
||||||
// Next we get the reflection vector
|
|
||||||
Vector3d const reflectionVector = ray.direction - 2.0f * dotProduct(normalVector, ray.direction) * normalVector;
|
|
||||||
|
|
||||||
// Change the ray direction and origin
|
|
||||||
refractionRay.direction = normalized(reflectionVector);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send out a new refracted ray into the scene
|
|
||||||
return scene.traceRay(refractionRay);
|
|
||||||
}
|
|
||||||
return Color(0.0f, 0.0f, 0.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RefractionShader::isTransparent() const { return true; }
|
bool RefractionShader::isTransparent() const
|
||||||
|
{ return true; }
|
||||||
|
|
|
@ -3,19 +3,22 @@
|
||||||
|
|
||||||
#include "shader/shader.h"
|
#include "shader/shader.h"
|
||||||
|
|
||||||
class RefractionShader : public Shader {
|
class RefractionShader : public Shader
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
RefractionShader(float indexInside, float indexOutside);
|
RefractionShader(float indexInside, float indexOutside, Color const &objectColor = Color(1, 1, 1));
|
||||||
|
|
||||||
// Shader functions
|
// Shader functions
|
||||||
Color shade(Scene const &scene, Ray const &ray) const override;
|
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||||
bool isTransparent() const override;
|
|
||||||
|
bool isTransparent() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float indexInside;
|
float indexInside;
|
||||||
float indexOutside;
|
float indexOutside;
|
||||||
|
Color objectColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue