added task 06 solution
This commit is contained in:
parent
227335f869
commit
fc608346c0
4 changed files with 179 additions and 199 deletions
|
@ -51,28 +51,33 @@ void Texture::setPixelAt(int x, int y, Color const &color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Texture::color(float u, float v, bool interpolate) const {
|
Color Texture::color(float u, float v, bool interpolate) const {
|
||||||
Color color;
|
Color color;
|
||||||
if (!interpolate) {
|
if (!interpolate) {
|
||||||
color = this->getPixelAt(int(roundf(u * this->width())), int(roundf(v * this->height())));
|
color = this->getPixelAt(int(roundf(u * this->width())), int(roundf(v * this->height())));
|
||||||
} else {
|
} else {
|
||||||
// IMPLEMENT bilinear interpolation
|
// bilinear interpolation
|
||||||
float x = u * this->width();
|
// adjacent pixel coordinates
|
||||||
float x1 = std::floor(x);
|
int left = int(floorf(u * this->width()));
|
||||||
float x2 = std::ceil(x);
|
int right = int(ceilf(u * this->width()));
|
||||||
|
int top = int(floorf(v * this->height()));
|
||||||
|
int bottom = int(ceilf(v * this->height()));
|
||||||
|
|
||||||
float y = v * this->height();
|
// weights
|
||||||
float y1 = std::floor(y);
|
float w[4];
|
||||||
float y2 = std::ceil(y);
|
w[0] = right - u * this->width();
|
||||||
|
w[1] = 1 - w[0];
|
||||||
|
w[2] = bottom - v * this->height();
|
||||||
|
w[3] = 1 - w[2];
|
||||||
|
|
||||||
Color x1y1 = this->getPixelAt(static_cast<int>(x1), static_cast<int>(y1));
|
// get color values and interpolate
|
||||||
Color x2y1 = this->getPixelAt(static_cast<int>(x2), static_cast<int>(y1));
|
Color val[4];
|
||||||
Color x1y2 = this->getPixelAt(static_cast<int>(x1), static_cast<int>(y2));
|
val[0] = this->getPixelAt(left, top);
|
||||||
Color x2y2 = this->getPixelAt(static_cast<int>(x2), static_cast<int>(y2));
|
val[1] = this->getPixelAt(right, top);
|
||||||
Color fxy1 = (x2 - x) * x1y1 + (x - x1) * x2y1;
|
val[2] = this->getPixelAt(left, bottom);
|
||||||
Color fxy2 = (x2 - x) * x1y2 + (x - x1) * x2y2;
|
val[3] = this->getPixelAt(right, bottom);
|
||||||
color = (y2 - y) * fxy1 + (y - y1) * fxy2;
|
color = w[2] * w[0] * val[0] + w[2] * w[1] * val[1] + w[3] * w[0] * val[2] + w[3] * w[1] * val[3];
|
||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
|
Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
|
||||||
|
|
|
@ -1,110 +1,94 @@
|
||||||
//
|
#include "renderer/superrenderer.h"
|
||||||
// Created by arvids on 13.12.22.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "superrenderer.h"
|
|
||||||
#include "common/ray.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <chrono>
|
|
||||||
#include <vector>
|
|
||||||
#include <iomanip>
|
|
||||||
#include "camera/camera.h"
|
#include "camera/camera.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
void SuperRenderer::renderThread(const Scene *scene, Camera const *camera, Texture *image, int width, int widthStep,
|
void SuperRenderer::renderThread(const Scene *scene, Camera const *camera, Texture *image, int width, int widthStep, int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k, int const stepSize,
|
||||||
int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k,
|
int superSamplingFactor) {
|
||||||
int const stepSize, int superSamplingFactor) {
|
int const sampleCount = superSamplingFactor * superSamplingFactor;
|
||||||
float const aspectRatio = static_cast<float>(height) / width;
|
float const samplingStep = 1.0f / superSamplingFactor;
|
||||||
for (int y = heightOffset; y < height; y += heightStep) {
|
float const aspectRatio = static_cast<float>(height) / width;
|
||||||
for (int x = widthOffset; x < width; x += widthStep) {
|
|
||||||
Color fragmentColor = {};
|
for (int y = heightOffset; y < image->height(); y += heightStep) {
|
||||||
fragmentColor = calcSuperColor(scene, camera, width, height, superSamplingFactor, aspectRatio, y, x,
|
for (int x = widthOffset; x < image->width(); x += widthStep) {
|
||||||
fragmentColor);
|
// The fragment color is averaged over all sub-pixel rays
|
||||||
fragmentColor /= static_cast<float>(superSamplingFactor * superSamplingFactor);
|
Color fragmentColor;
|
||||||
image->setPixelAt(x, y, clamped(fragmentColor));
|
for (int xs = 0; xs < superSamplingFactor; ++xs) {
|
||||||
// Super hacky progress bar!
|
for (int ys = 0; ys < superSamplingFactor; ++ys) {
|
||||||
if (++*k % stepSize == 0) {
|
Ray ray = camera->createRay(((xs * samplingStep + x) / width * 2 - 1), -((ys * samplingStep + y) / height * 2 - 1) * aspectRatio);
|
||||||
std::cout << "=" << std::flush;
|
fragmentColor += scene->traceRay(ray);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
image->setPixelAt(x, y, clamped(fragmentColor / float(sampleCount)));
|
||||||
|
|
||||||
Color &
|
// Super hacky progress bar!
|
||||||
SuperRenderer::calcSuperColor(const Scene *scene, const Camera *camera, int width, int height, int superSamplingFactor,
|
if (++*k % stepSize == 0) {
|
||||||
const float aspectRatio, int y, int x, Color &fragmentColor) {
|
std::cout << "=" << std::flush;
|
||||||
for (int x1 = 0; x1 < superSamplingFactor; x1++) {
|
}
|
||||||
for (int y1 = 0; y1 < superSamplingFactor; y1++) {
|
|
||||||
float offsetX = (-0.5f + static_cast<float>(x1) / static_cast<float>(superSamplingFactor - 1));
|
|
||||||
float offsetY = (-0.5f + static_cast<float>(y1) / static_cast<float>(superSamplingFactor - 1));
|
|
||||||
|
|
||||||
Ray ray = camera->createRay(((static_cast<float>(x) + offsetX) / static_cast<float>(width) * 2.0f - 1),
|
|
||||||
-((static_cast<float>(y) + offsetY) / static_cast<float>(height) * 2.0f - 1) * aspectRatio);
|
|
||||||
fragmentColor += scene->traceRay(ray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return fragmentColor;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture SuperRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
Texture SuperRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
||||||
Texture image(width, height);
|
Texture image(width, height);
|
||||||
|
|
||||||
// Setup timer
|
// Setup timer
|
||||||
std::chrono::steady_clock::time_point start, stop;
|
std::chrono::steady_clock::time_point start, stop;
|
||||||
|
|
||||||
// Reset Ray counting
|
// ICGVARIANT ray_counting
|
||||||
Ray::resetRayCount();
|
// Reset Ray counting
|
||||||
|
Ray::resetRayCount();
|
||||||
|
|
||||||
// Super-hacky progress bar!
|
// ENDVARIANT ray_counting
|
||||||
std::cout << "(SuperRenderer): Begin rendering..." << std::endl;
|
// Super-hacky progress bar!
|
||||||
std::cout << "| 0%";
|
std::cout << "(SuperRenderer): Begin rendering..." << std::endl;
|
||||||
int const barSize = 50;
|
std::cout << "| 0%";
|
||||||
int const stepSize = (width * height) / barSize;
|
int const barSize = 50;
|
||||||
for (int i = 0; i < barSize - 3 - 5; ++i)
|
int const stepSize = (width * height) / barSize;
|
||||||
std::cout << " ";
|
for (int i = 0; i < barSize - 3 - 5; ++i)
|
||||||
std::cout << "100% |" << std::endl << "|";
|
std::cout << " ";
|
||||||
std::atomic<int> k(0);
|
std::cout << "100% |" << std::endl << "|";
|
||||||
|
std::atomic<int> k(0);
|
||||||
|
|
||||||
/* Start timer */ start = std::chrono::steady_clock::now();
|
// Start timer
|
||||||
|
start = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
// Spawn a thread for every logical processor -1, calling the renderThread function
|
// Spawn a thread for every logical processor -1, calling the renderThread function
|
||||||
int const nThreads = std::thread::hardware_concurrency();
|
int const nThreads = std::thread::hardware_concurrency();
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
for (int t = 0; t < nThreads - 1; ++t) {
|
for (int t = 0; t < nThreads - 1; ++t) {
|
||||||
threads.emplace_back(renderThread, &scene, &camera, &image, width, nThreads, t, height, 1, 0, &k, stepSize,
|
threads.emplace_back(renderThread, &scene, &camera, &image, width, nThreads, t, height, 1, 0, &k, stepSize, this->superSamplingFactor_);
|
||||||
this->superSamplingFactor);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Call the renderThread function yourself
|
// Call the renderThread function yourself
|
||||||
renderThread(&scene, &camera, &image, width, nThreads, nThreads - 1, height, 1, 0, &k, stepSize,
|
renderThread(&scene, &camera, &image, width, nThreads, nThreads - 1, height, 1, 0, &k, stepSize, this->superSamplingFactor_);
|
||||||
this->superSamplingFactor);
|
|
||||||
|
|
||||||
// Rejoin the threads
|
// Rejoin the threads
|
||||||
for (int t = 0; t < nThreads - 1; ++t) {
|
for (int t = 0; t < nThreads - 1; ++t) {
|
||||||
threads[t].join();
|
threads[t].join();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop timer
|
// Stop timer
|
||||||
stop = std::chrono::steady_clock::now();
|
stop = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
std::cout << "| Done!" << std::endl;
|
std::cout << "| Done!" << std::endl;
|
||||||
|
|
||||||
// Calculate the Time taken in seconds
|
// Calculate the Time taken in seconds
|
||||||
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(stop - start).count();
|
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(stop - start).count();
|
||||||
|
|
||||||
std::cout << "Time: " << seconds << "s" << std::endl;
|
std::cout << "Time: " << seconds << "s" << std::endl;
|
||||||
|
|
||||||
// Get the number of seconds per ray
|
// ICGVARIANT ray_counting
|
||||||
int rays = Ray::getRayCount();
|
// Get the number of seconds per ray
|
||||||
|
int rays = Ray::getRayCount();
|
||||||
|
|
||||||
std::cout << "Paths: " << rays << std::endl;
|
std::cout << "Paths: " << rays << std::endl;
|
||||||
std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << std::endl;
|
std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << std::endl;
|
||||||
|
|
||||||
|
// ENDVARIANT ray_counting
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SuperRenderer::setSuperSamplingFactor(int superSamplingFactor) {
|
|
||||||
SuperRenderer::superSamplingFactor = superSamplingFactor;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,30 @@
|
||||||
//
|
#ifndef SUPERRENDERER_H
|
||||||
// Created by arvids on 13.12.22.
|
#define SUPERRENDERER_H
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef CG1_TRACER_SUPERRENDERER_H
|
#include "renderer/renderer.h"
|
||||||
#define CG1_TRACER_SUPERRENDERER_H
|
|
||||||
|
|
||||||
#include "renderer.h"
|
|
||||||
#include <thread>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
class SuperRenderer : public Renderer {
|
class SuperRenderer : public Renderer {
|
||||||
|
static void renderThread(const Scene *scene, Camera const *camera, Texture *image, int width, int widthStep,
|
||||||
|
int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k,
|
||||||
|
int const stepSize, int superSamplingFactor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void
|
// Constructor / Destructor
|
||||||
renderThread(const Scene *scene, Camera const *camera, Texture *image, int width, int widthStep,
|
SuperRenderer() = default;
|
||||||
int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k,
|
~SuperRenderer() override = default;
|
||||||
int const stepSize, int superSamplingFactor);
|
|
||||||
|
|
||||||
Texture renderImage(const Scene &scene, const Camera &camera, int width, int height) override;
|
// Get
|
||||||
void setSuperSamplingFactor(int superSamplingFactor);
|
int superSamplingFactor() { return this->superSamplingFactor_; }
|
||||||
|
|
||||||
|
// Set
|
||||||
|
void setSuperSamplingFactor(int factor) { this->superSamplingFactor_ = factor; }
|
||||||
|
|
||||||
|
// Render functions
|
||||||
|
Texture renderImage(Scene const &scene, Camera const &camera, int width, int height) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
private:
|
int superSamplingFactor_ = 2;
|
||||||
|
|
||||||
int superSamplingFactor;
|
|
||||||
|
|
||||||
static Color &
|
|
||||||
calcSuperColor(const Scene *scene, const Camera *camera, int width, int height, int superSamplingFactor,
|
|
||||||
const float aspectRatio, int y, int x, Color &fragmentColor);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif //CG1_TRACER_SUPERRENDERER_H
|
|
||||||
|
|
|
@ -6,64 +6,88 @@
|
||||||
|
|
||||||
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 normal = ray.normal;
|
||||||
if (this->normalMap != nullptr)
|
if (this->normalMap) {
|
||||||
{
|
Color const normalColor = this->normalMap->color(ray.surface);
|
||||||
auto surfaceNormalMapColor = this->normalMap->color(ray.surface, true);
|
Vector3d const textureNormal =
|
||||||
Vector3d textureNormal = {surfaceNormalMapColor.r, surfaceNormalMapColor.g, surfaceNormalMapColor.b};
|
Vector3d(2.0f * normalColor.r, 2.0f * normalColor.g, 2.0f * normalColor.b) - Vector3d(1, 1, 1);
|
||||||
textureNormal = textureNormal * 2.0f - Vector3d{1, 1, 1};
|
normal = normalized(tangentToWorldSpace(normal, ray.tangent, ray.bitangent, normalized(textureNormal)) *
|
||||||
surfaceNormal = ray.normal * normalCoefficient +
|
this->normalCoefficient + (1.0f - this->normalCoefficient) * normal);
|
||||||
(1 - normalCoefficient) *
|
|
||||||
tangentToWorldSpace(ray.normal, ray.tangent, ray.bitangent, textureNormal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the reflection vector
|
||||||
|
Vector3d const reflection = normalized(ray.direction - 2 * dotProduct(normal, ray.direction) * normal);
|
||||||
|
|
||||||
// (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);
|
for (const auto &light: scene.lights()) {
|
||||||
if (this->diffuseMap != nullptr)
|
|
||||||
{
|
// Retrieve an illumination object
|
||||||
surfaceDiffuseColor = this->diffuseMap->color(ray.surface, true);
|
Light::Illumination illum = light->illuminate(scene, ray);
|
||||||
|
|
||||||
|
// Diffuse term
|
||||||
|
Color const diffuse =
|
||||||
|
this->diffuseCoefficient * illum.color * std::max(dotProduct(-illum.direction, normal), 0.0f);
|
||||||
|
if (this->diffuseMap)
|
||||||
|
fragmentColor += diffuse * this->diffuseMap->color(ray.surface);
|
||||||
|
else
|
||||||
|
fragmentColor += diffuse;
|
||||||
|
|
||||||
|
// Specular term
|
||||||
|
float const cosine = dotProduct(-illum.direction, reflection);
|
||||||
|
if (cosine > 0) {
|
||||||
|
Color const specular = this->specularCoefficient * illum.color * std::pow(cosine, shininessExponent);
|
||||||
|
if (this->specularMap)
|
||||||
|
fragmentColor += specular * this->specularMap->color(ray.surface);
|
||||||
|
else
|
||||||
|
fragmentColor += specular;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color surfaceSpecularColor(0, 0, 0);
|
// (Reflection Map) Calculate the reflectance
|
||||||
if (this->specularMap != nullptr)
|
float reflectance = this->reflectance;
|
||||||
{
|
if (this->reflectionMap)
|
||||||
surfaceSpecularColor = this->specularMap->color(ray.surface, true);
|
reflectance *= this->reflectionMap->color(ray.surface).r;
|
||||||
|
if (reflectance > 0.0f) {
|
||||||
|
// Create a new reflection ray
|
||||||
|
Ray reflectionRay = ray;
|
||||||
|
reflectionRay.origin = ray.origin + (ray.length - EPSILON) * ray.direction;
|
||||||
|
reflectionRay.direction = reflection;
|
||||||
|
reflectionRay.length = INFINITY;
|
||||||
|
reflectionRay.primitive = nullptr;
|
||||||
|
// Mix the object and the reflected image
|
||||||
|
Color const reflectionColor = scene.traceRay(reflectionRay);
|
||||||
|
fragmentColor = (1 - reflectance) * fragmentColor + reflectance * reflectionColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (Alpha Map) Calculate the opacity
|
||||||
// (Reflection Map) Calculate the reflectance, create a reflection ray
|
float alpha = this->opacity;
|
||||||
Vector3d const reflection = ray.direction - 2 * dotProduct(surfaceNormal, ray.direction) * ray.normal;
|
if (this->alphaMap)
|
||||||
float surfaceReflectanceCoefficient = this->reflectance;
|
alpha *= this->alphaMap->color(ray.surface).r;
|
||||||
if (this->reflectionMap != nullptr)
|
if (alpha < 1) {
|
||||||
{
|
// Create a new alpha ray
|
||||||
auto surfaceReflectiveMapColor = this->reflectionMap->color(ray.surface, true);
|
Ray alphaRay = ray;
|
||||||
surfaceReflectanceCoefficient = surfaceReflectiveMapColor.r;
|
alphaRay.origin = ray.origin + (ray.length + EPSILON) * ray.direction;
|
||||||
|
alphaRay.length = INFINITY;
|
||||||
|
alphaRay.primitive = nullptr;
|
||||||
|
// Mix the foreground and background colors
|
||||||
|
Color const backgroundColor = scene.traceRay(alphaRay);
|
||||||
|
fragmentColor = alpha * fragmentColor + (1 - alpha) * backgroundColor;
|
||||||
}
|
}
|
||||||
Ray reflectionRay = ray;
|
|
||||||
reflectionRay.origin = ray.origin + (ray.length - REFR_EPS) * ray.direction;
|
|
||||||
reflectionRay.direction = normalized(reflection);
|
|
||||||
reflectionRay.length = INFINITY;
|
|
||||||
reflectionRay.primitive = nullptr;
|
|
||||||
|
|
||||||
// (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;
|
||||||
}
|
}
|
||||||
|
@ -73,37 +97,8 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const
|
||||||
propagatedRay.length = INFINITY;
|
propagatedRay.length = INFINITY;
|
||||||
propagatedRay.primitive = nullptr;
|
propagatedRay.primitive = nullptr;
|
||||||
|
|
||||||
// Iterate over light sources
|
|
||||||
for (const auto &light: scene.lights())
|
|
||||||
{
|
|
||||||
Light::Illumination const illum = light->illuminate(scene, ray);
|
|
||||||
|
|
||||||
// Diffuse term (lambertian)
|
|
||||||
Color const diffuse = this->diffuseCoefficient * surfaceDiffuseColor *
|
|
||||||
std::max(dotProduct(-illum.direction, ray.normal), 0.0f);
|
|
||||||
fragmentColor += diffuse * illum.color;
|
|
||||||
|
|
||||||
// Specular term (phong)
|
|
||||||
float const cosine = dotProduct(-illum.direction, reflection);
|
|
||||||
if (cosine > 0)
|
|
||||||
{
|
|
||||||
Color const specular = this->specularCoefficient * surfaceSpecularColor // highlight
|
|
||||||
* powf(cosine, this->shininessExponent); // shininess factor
|
|
||||||
fragmentColor += specular * illum.color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
// Reflected ray
|
|
||||||
if (surfaceReflectanceCoefficient > 0)
|
|
||||||
{
|
|
||||||
Color const reflectionColor = scene.traceRay(reflectionRay);
|
|
||||||
fragmentColor += surfaceReflectanceCoefficient * reflectionColor * reflectance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opacity
|
// Opacity
|
||||||
if (surfaceAlphaCoefficient < 1)
|
if (surfaceAlphaCoefficient < 1) {
|
||||||
{
|
|
||||||
Color const background = scene.traceRay(propagatedRay);
|
Color const background = scene.traceRay(propagatedRay);
|
||||||
fragmentColor = (1 - surfaceAlphaCoefficient) * background + surfaceAlphaCoefficient * fragmentColor;
|
fragmentColor = (1 - surfaceAlphaCoefficient) * background + surfaceAlphaCoefficient * fragmentColor;
|
||||||
}
|
}
|
||||||
|
@ -111,5 +106,4 @@ Color MaterialShader::shade(Scene const &scene, Ray const &ray) const
|
||||||
return fragmentColor;
|
return fragmentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MaterialShader::isTransparent() const
|
bool MaterialShader::isTransparent() const { return this->opacity < 1.0f || this->alphaMap; }
|
||||||
{ return this->opacity < 1.0f || this->alphaMap; }
|
|
||||||
|
|
Loading…
Reference in a new issue