Prevents unnecessary rays from being traced, that often caused faulty black pixels

This commit is contained in:
Maximilian Giller 2022-12-14 05:06:46 +01:00
parent eeed0e23a7
commit cf9e9175c2

View file

@ -6,20 +6,24 @@
Vector3d Vector3d
tangentToWorldSpace(const Vector3d &surfaceNormal, const Vector3d &surfaceTangent, const Vector3d &surfaceBitangent, tangentToWorldSpace(const Vector3d &surfaceNormal, const Vector3d &surfaceTangent, const Vector3d &surfaceBitangent,
const Vector3d &textureNormal) { const Vector3d &textureNormal)
{
return textureNormal.x * surfaceTangent + textureNormal.y * surfaceBitangent + textureNormal.z * surfaceNormal; return textureNormal.x * surfaceTangent + textureNormal.y * surfaceBitangent + textureNormal.z * surfaceNormal;
} }
MaterialShader::MaterialShader() : opacity(1.0f), normalCoefficient(1.0f), diffuseCoefficient(0.5f), reflectance(0.0f), MaterialShader::MaterialShader() : opacity(1.0f), normalCoefficient(1.0f), diffuseCoefficient(0.5f), reflectance(0.0f),
specularCoefficient(0.5f), shininessExponent(8) {} specularCoefficient(0.5f), shininessExponent(8)
{}
Color MaterialShader::shade(Scene const &scene, Ray const &ray) const { Color MaterialShader::shade(Scene const &scene, Ray const &ray) const
{
Color fragmentColor; Color fragmentColor;
// IMPLEMENT ME // IMPLEMENT ME
// (Normal Map) Calculate the new normal vector // (Normal Map) Calculate the new normal vector
Vector3d surfaceNormal = ray.normal; Vector3d surfaceNormal = ray.normal;
if (this->normalMap != nullptr) { if (this->normalMap != nullptr)
{
auto surfaceNormalMapColor = this->normalMap->color(ray.surface, true); auto surfaceNormalMapColor = this->normalMap->color(ray.surface, true);
Vector3d textureNormal = {surfaceNormalMapColor.r, surfaceNormalMapColor.g, surfaceNormalMapColor.b}; Vector3d textureNormal = {surfaceNormalMapColor.r, surfaceNormalMapColor.g, surfaceNormalMapColor.b};
textureNormal = textureNormal * 2.0f - Vector3d{1, 1, 1}; textureNormal = textureNormal * 2.0f - Vector3d{1, 1, 1};
@ -30,12 +34,14 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const {
// (Diffuse-/Specular Map) Accumulate the light over all light sources // (Diffuse-/Specular Map) Accumulate the light over all light sources
Color surfaceDiffuseColor(0, 0, 0); Color surfaceDiffuseColor(0, 0, 0);
if (this->diffuseMap != nullptr) { if (this->diffuseMap != nullptr)
{
surfaceDiffuseColor = this->diffuseMap->color(ray.surface, true); surfaceDiffuseColor = this->diffuseMap->color(ray.surface, true);
} }
Color surfaceSpecularColor(0, 0, 0); Color surfaceSpecularColor(0, 0, 0);
if (this->specularMap != nullptr) { if (this->specularMap != nullptr)
{
surfaceSpecularColor = this->specularMap->color(ray.surface, true); surfaceSpecularColor = this->specularMap->color(ray.surface, true);
} }
@ -43,7 +49,8 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const {
// (Reflection Map) Calculate the reflectance, create a reflection ray // (Reflection Map) Calculate the reflectance, create a reflection ray
Vector3d const reflection = ray.direction - 2 * dotProduct(surfaceNormal, ray.direction) * ray.normal; Vector3d const reflection = ray.direction - 2 * dotProduct(surfaceNormal, ray.direction) * ray.normal;
float surfaceReflectanceCoefficient = this->reflectance; float surfaceReflectanceCoefficient = this->reflectance;
if (this->reflectionMap != nullptr) { if (this->reflectionMap != nullptr)
{
auto surfaceReflectiveMapColor = this->reflectionMap->color(ray.surface, true); auto surfaceReflectiveMapColor = this->reflectionMap->color(ray.surface, true);
surfaceReflectanceCoefficient = surfaceReflectiveMapColor.r; surfaceReflectanceCoefficient = surfaceReflectiveMapColor.r;
} }
@ -55,7 +62,8 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const {
// (Alpha Map) Calculate the opacity, create a background ray // (Alpha Map) Calculate the opacity, create a background ray
float surfaceAlphaCoefficient(1); float surfaceAlphaCoefficient(1);
if (this->alphaMap != nullptr) { if (this->alphaMap != nullptr)
{
auto surfaceAlphaMapColor = this->alphaMap->color(ray.surface, true); auto surfaceAlphaMapColor = this->alphaMap->color(ray.surface, true);
surfaceAlphaCoefficient = surfaceAlphaMapColor.r; surfaceAlphaCoefficient = surfaceAlphaMapColor.r;
} }
@ -66,7 +74,8 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const {
propagatedRay.primitive = nullptr; propagatedRay.primitive = nullptr;
// Iterate over light sources // Iterate over light sources
for (const auto &light: scene.lights()) { for (const auto &light: scene.lights())
{
Light::Illumination const illum = light->illuminate(scene, ray); Light::Illumination const illum = light->illuminate(scene, ray);
// Diffuse term (lambertian) // Diffuse term (lambertian)
@ -76,7 +85,8 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const {
// Specular term (phong) // Specular term (phong)
float const cosine = dotProduct(-illum.direction, reflection); float const cosine = dotProduct(-illum.direction, reflection);
if (cosine > 0) { if (cosine > 0)
{
Color const specular = this->specularCoefficient * surfaceSpecularColor // highlight Color const specular = this->specularCoefficient * surfaceSpecularColor // highlight
* powf(cosine, this->shininessExponent); // shininess factor * powf(cosine, this->shininessExponent); // shininess factor
fragmentColor += specular * illum.color; fragmentColor += specular * illum.color;
@ -85,10 +95,21 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const {
} }
// Reflected ray // Reflected ray
fragmentColor += scene.traceRay(reflectionRay) * surfaceReflectanceCoefficient * reflectance; if (surfaceReflectanceCoefficient > 0)
{
Color const reflectionColor = scene.traceRay(reflectionRay);
fragmentColor += surfaceReflectanceCoefficient * reflectionColor * reflectance;
}
// Opacity // Opacity
return fragmentColor * surfaceAlphaCoefficient + scene.traceRay(propagatedRay) * (1 - surfaceAlphaCoefficient); if (surfaceAlphaCoefficient < 1)
{
Color const background = scene.traceRay(propagatedRay);
fragmentColor = (1 - surfaceAlphaCoefficient) * background + surfaceAlphaCoefficient * fragmentColor;
}
return fragmentColor;
} }
bool MaterialShader::isTransparent() const { return this->opacity < 1.0f || this->alphaMap; } bool MaterialShader::isTransparent() const
{ return this->opacity < 1.0f || this->alphaMap; }