Adds rich transparency for shaders and implements if for light calculations
This commit is contained in:
parent
dcae587b8c
commit
17fd35fe76
11 changed files with 120 additions and 26 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue