Adds rich transparency for shaders and implements if for light calculations

This commit is contained in:
Maximilian Giller 2023-01-24 21:11:30 +01:00
parent dcae587b8c
commit 17fd35fe76
11 changed files with 120 additions and 26 deletions

View file

@ -20,8 +20,10 @@ Light::Illumination PointLight::illuminate(Scene const &scene, Ray const &ray) c
lightRay.length = distance - LGT_EPS;
// If the target is not in shadow...
if (!scene.findOcclusion(lightRay))
if (!scene.findOcclusion(lightRay)) {
// ... compute the attenuation and light color
illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
Color rayTransparency = scene.getTransparency(lightRay, distance);
illum.color = 1.0f / (distance * distance) * this->color * this->intensity * rayTransparency;
}
return illum;
}

View file

@ -28,7 +28,8 @@ Light::Illumination SpotLight::illuminate(Scene const &scene, Ray const &ray) co
// ... and not in shadow ...
if (!scene.findOcclusion(lightRay)) {
// ... compute the attenuation and light color ...
illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
Color rayTransparency = scene.getTransparency(lightRay, distance);
illum.color = 1.0f / (distance * distance) * this->color * this->intensity * rayTransparency;
// ... then compute the falloff towards the edge of the cone
if (this->alphaMin < alpha)
illum.color *= 1.0f - (alpha - this->alphaMin) / (this->alphaMax - this->alphaMin);

View file

@ -25,7 +25,9 @@ Light::Illumination SunLight::illuminate(Scene const &scene, Ray const &ray) con
// Look at angleIntensity of light
float angleIntensity = dotProduct(-ray.normal,
this->direction); // 0 if light is behind surface, 1 if light is in front of surface
illum.color = this->color * this->intensity * angleIntensity;
Color rayTransparency = scene.getTransparency(lightRay, INFINITY);
illum.color = this->color * this->intensity * angleIntensity * rayTransparency;
}
return illum;
}

View file

@ -221,3 +221,27 @@ std::unique_ptr<Node> FastScene::build(Vector3d const &minimumBounds, Vector3d c
node->child[1] = this->build(minimumSplit, maximumBounds, rightPrimitives, depth);
return node;
}
Color FastScene::getTransparency(Ray &ray, float maxDistance) const
{
// TODO: Not taking advantage of the tree structure!
ray.length = maxDistance;
ray.primitive = nullptr;
Color transparency(1, 1, 1);
for (auto i: this->primitives())
{
Ray r = ray;
if (i->intersect(r) && r.length < maxDistance && i->shader()->isTransparent())
{
r.length = maxDistance; // To allow transparency to be calculated partially for objects
Color t = i->shader()->transparency(*this, r);
transparency.r *= t.r;
transparency.g *= t.g;
transparency.b *= t.b;
}
}
return transparency;
}

View file

@ -28,6 +28,7 @@ public:
// Raytracing functions
bool findIntersection(Ray &ray) const override;
bool findOcclusion(Ray &ray) const override;
Color getTransparency(Ray &ray, float maxDistance) const override;
int countNodeIntersections(const Ray &ray) const;
// Setup functions

View file

@ -41,6 +41,7 @@ public:
Color traceRay(Ray &ray) const;
virtual bool findIntersection(Ray &ray) const = 0;
virtual bool findOcclusion(Ray &ray) const = 0;
virtual Color getTransparency(Ray &ray, float maxDistance) const = 0;
protected:
Color backgroundColor;

View file

@ -2,16 +2,40 @@
#include "primitive/primitive.h"
#include "shader/shader.h"
bool SimpleScene::findIntersection(Ray &ray) const {
bool SimpleScene::findIntersection(Ray &ray) const
{
bool hit = false;
for (auto i : this->primitives())
for (auto i: this->primitives())
hit |= i->intersect(ray);
return hit;
}
bool SimpleScene::findOcclusion(Ray &ray) const {
for (auto i : this->primitives())
bool SimpleScene::findOcclusion(Ray &ray) const
{
for (auto i: this->primitives())
if (i->intersect(ray) && !i->shader()->isTransparent())
return true;
return false;
}
Color SimpleScene::getTransparency(Ray &ray, float maxDistance) const
{
ray.length = maxDistance;
ray.primitive = nullptr;
Color transparency(1, 1, 1);
for (auto i: this->primitives())
{
Ray r = ray;
if (i->intersect(r) && r.length < maxDistance && i->shader()->isTransparent())
{
r.length = maxDistance; // To allow transparency to be calculated partially for objects
Color t = i->shader()->transparency(*this, r);
transparency.r *= t.r;
transparency.g *= t.g;
transparency.b *= t.b;
}
}
return transparency;
}

View file

@ -9,6 +9,7 @@ public:
// Raytracing functions
bool findIntersection(Ray &ray) const override;
bool findOcclusion(Ray &ray) const override;
Color getTransparency(Ray &ray, float maxDistance) const override;
};
#endif

View file

@ -1,7 +1,8 @@
#include "scene/scene.h"
#include "shader/refractionshader.h"
RefractionShader::RefractionShader(float indexInside, float indexOutside, Color const &objectColor, float lightLoss) : indexInside(
RefractionShader::RefractionShader(float indexInside, float indexOutside, Color const &objectColor, float lightLoss)
: indexInside(
indexInside), indexOutside(indexOutside), objectColor(objectColor), lightLoss(lightLoss)
{}
@ -52,14 +53,36 @@ Color RefractionShader::shade(Scene const &scene, Ray const &ray) const
// Send out a new refracted ray into the scene
Color hitColor = scene.traceRay(refractionRay);
// Calculate light lost
float lightRemaining = 1;
if (refractionRay.primitive == ray.primitive) lightRemaining = 1 - lightLoss + exp(-refractionRay.length / 10) * lightLoss;
if (ray.primitive == refractionRay.primitive) lightRemaining = remainingLightIntensity(refractionRay.length);
return hitColor * objectColor * lightRemaining;
}
return Color(0.0f, 0.0f, 0.0f);
}
float RefractionShader::remainingLightIntensity(float distanceThroughObject) const
{
return 1 - lightLoss + exp(-distanceThroughObject / 10) * lightLoss;
}
bool RefractionShader::isTransparent() const
{ return true; }
Color RefractionShader::transparency(const Scene &scene, const Ray &ray) const
{
// Determine length through the object
Ray lengthRay = ray;
// Reset the ray
lengthRay.length = INFINITY;
lengthRay.primitive = nullptr;
lengthRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
scene.traceRay(lengthRay);
float transparencyDistance = std::min(ray.length, lengthRay.length);
float lightRemaining = 1;
if (ray.primitive == lengthRay.primitive) lightRemaining = remainingLightIntensity(transparencyDistance);
return objectColor * lightRemaining;
}

View file

@ -14,12 +14,15 @@ public:
Color shade(Scene const &scene, Ray const &ray) const override;
bool isTransparent() const override;
Color transparency(Scene const &scene, Ray const &ray) const override;
private:
float indexInside;
float indexOutside;
float lightLoss;
Color objectColor;
float remainingLightIntensity(float distanceThroughObject) const;
};
#endif

View file

@ -7,14 +7,26 @@
// Forward declarations
class Scene;
class Shader {
class Shader
{
public:
// Constructor / Desctructor
Shader() = default;
virtual ~Shader() = default;
// Get
virtual bool isTransparent() const { return false; }
virtual bool isTransparent() const
{ return false; }
/**
* Especially used for lighting calculations.
* @brief Returns the light let through the shader in opposite direction of the given ray.
* @param ray Origin and direction of the desired path.
* @return 0 if the shader is opaque, 1 if the shader is transparent, for each color channel.
*/
virtual Color transparency(Scene const &scene, Ray const &ray) const
{ return isTransparent() ? Color(1, 1, 1) : Color(0, 0, 0); }
// Shader functions
virtual Color shade(Scene const &scene, Ray const &ray) const = 0;