Merge remote-tracking branch 'base/master'
This commit is contained in:
commit
c5cfe34861
11 changed files with 326 additions and 99 deletions
|
@ -59,6 +59,9 @@ add_executable(tracey_ex4 ex4.cpp)
|
||||||
target_link_libraries(tracey_ex4 tracey)
|
target_link_libraries(tracey_ex4 tracey)
|
||||||
|
|
||||||
|
|
||||||
|
add_executable(tracey_ex5 ex5.cpp)
|
||||||
|
target_link_libraries(tracey_ex5 tracey)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
54
ex5.cpp
Normal file
54
ex5.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "camera/perspectivecamera.h"
|
||||||
|
|
||||||
|
#include "scene/fastscene.h"
|
||||||
|
|
||||||
|
#include "renderer/kdtreerenderer.h"
|
||||||
|
#include "renderer/simplerenderer.h"
|
||||||
|
|
||||||
|
#include "shader/cooktorranceshader.h"
|
||||||
|
|
||||||
|
#include "light/ambientlight.h"
|
||||||
|
#include "light/pointlight.h"
|
||||||
|
#include "light/spotlight.h"
|
||||||
|
|
||||||
|
#include "primitive/objmodel.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
FastScene scene;
|
||||||
|
scene.setEnvironmentMap(std::make_shared<Texture>("data/space.png"));
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(90.0f);
|
||||||
|
camera.setPosition(Vector3d(0.0f, -2.5f, 10.0f));
|
||||||
|
camera.setForwardDirection(Vector3d(0.0f, 0.6f, -1.0f));
|
||||||
|
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
// Add shaders
|
||||||
|
auto redCook = std::make_shared<CookTorranceShader>(Color(1.0f, 0.0f, 0.0f), Color(1.0f, 1.0f, 1.0f), 1.0f, 0.3f);
|
||||||
|
auto goldCook = std::make_shared<CookTorranceShader>(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f);
|
||||||
|
|
||||||
|
scene.addObj("data/teapot_stadium.obj", Vector3d(1.0f, 1.0f, 1.0f) * 40.0f, Vector3d(-0.25f, -0.5f, -2.5f), goldCook);
|
||||||
|
scene.addObj("data/stadium.obj", Vector3d(1.0f, 1.0f, 1.0f) * 70.0f, Vector3d(-0.5f, -1.0f, -3.0f), redCook);
|
||||||
|
|
||||||
|
// Add lights
|
||||||
|
scene.add(std::make_shared<AmbientLight>(0.1f));
|
||||||
|
scene.add(std::make_shared<PointLight>(Vector3d(-0.25f, 20.0f, -3.0f), 60.0f));
|
||||||
|
scene.add(
|
||||||
|
std::make_shared<SpotLight>(Vector3d(-0.25f, 7.0f, -4.0f), Vector3d(0.0f, -1.0f, 0.0f), 10.0f, 30.0f, 25.0f));
|
||||||
|
|
||||||
|
// build the tree
|
||||||
|
scene.buildTree();
|
||||||
|
|
||||||
|
// Render the scene
|
||||||
|
SimpleRenderer renderer;
|
||||||
|
renderer.renderImage(scene, camera, 1920, 1080).save("result.png");
|
||||||
|
|
||||||
|
KDTreeRenderer kd_renderer;
|
||||||
|
kd_renderer.renderKDTree(scene, camera, 1920, 1080).save("result_kd.png");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -112,12 +112,13 @@ bool Triangle::intersect(Ray &ray) const {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Calculate the normal
|
// Calculate the normal
|
||||||
// IMPLEMENT smooth triangles, if available
|
if (length(this->normal[0]) * length(this->normal[1]) * length(this->normal[2]) > EPSILON)
|
||||||
if (this->normal[0] == Vector3d{} || this->normal[1] == Vector3d{} || this->normal[2] == Vector3d{}) {
|
ray.normal = normalized(u * this->normal[1] + v * this->normal[2] + (1 - u - v) * this->normal[0]);
|
||||||
|
else
|
||||||
ray.normal = normalized(crossProduct(edge1, edge2));
|
ray.normal = normalized(crossProduct(edge1, edge2));
|
||||||
} else {
|
// calculate the tangent and bitangent vectors as well
|
||||||
ray.normal = u * this->normal[1] + v * this->normal[2] + (1 - u - v) * this->normal[0];
|
ray.tangent = normalized(u * this->tangent[1] + v * this->tangent[2] + (1 - u - v) * this->tangent[0]);
|
||||||
}
|
ray.bitangent = normalized(u * this->bitangent[1] + v * this->bitangent[2] + (1 - u - v) * this->bitangent[0]);
|
||||||
|
|
||||||
|
|
||||||
// Calculate the surface position
|
// Calculate the surface position
|
||||||
|
|
18
renderer/kdtreerenderer.cpp
Normal file
18
renderer/kdtreerenderer.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "camera/camera.h"
|
||||||
|
#include "renderer/kdtreerenderer.h"
|
||||||
|
#include "scene/fastscene.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
Texture KDTreeRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
||||||
|
Texture image(width, height);
|
||||||
|
std::cout << "KD Tree renderer will only output KD Tree visualization" << std::endl;
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture KDTreeRenderer::renderKDTree(FastScene const &scene, Camera const &camera, int width, int height) {
|
||||||
|
Texture image(width, height);
|
||||||
|
|
||||||
|
// IMPLEMENT ME
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
22
renderer/kdtreerenderer.h
Normal file
22
renderer/kdtreerenderer.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef KDTREERENDERER_H
|
||||||
|
#define KDTREERENDERER_H
|
||||||
|
|
||||||
|
#include "renderer/renderer.h"
|
||||||
|
|
||||||
|
// Forward Declaration
|
||||||
|
class FastScene;
|
||||||
|
|
||||||
|
class KDTreeRenderer : public Renderer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor / Destructor
|
||||||
|
KDTreeRenderer() = default;
|
||||||
|
~KDTreeRenderer() override = default;
|
||||||
|
|
||||||
|
// Render functions
|
||||||
|
Texture renderImage(Scene const &scene, Camera const &camera, int width, int height) override;
|
||||||
|
|
||||||
|
Texture renderKDTree(FastScene const &scene, Camera const &camera, int width, int height);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
73
scene/fastscene.cpp
Normal file
73
scene/fastscene.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#include "primitive/primitive.h"
|
||||||
|
#include "scene/fastscene.h"
|
||||||
|
#include "shader/shader.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int Node::countNodeIntersections(const Ray &ray, float t0, float t1) const {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Node::findIntersection(Ray &ray, float t0, float t1) const {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
// If this is a leaf node, we intersect with all the primitives...
|
||||||
|
// ... otherwise we continue through the branches
|
||||||
|
// Determine the order in which we intersect the child nodes
|
||||||
|
// Traverse the necessary children
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Node::findOcclusion(Ray &ray, float t0, float t1) const {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FastScene::countNodeIntersections(const Ray &ray) const {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FastScene::findIntersection(Ray &ray) const {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FastScene::findOcclusion(Ray &ray) const {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FastScene::buildTree(int maximumDepth, int minimumNumberOfPrimitives) {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
// Set the new depth and number of primitives
|
||||||
|
|
||||||
|
// Determine the bounding box of the kD-Tree
|
||||||
|
|
||||||
|
// Recursively build the kD-Tree
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Node> FastScene::build(Vector3d const &minimumBounds, Vector3d const &maximumBounds, const std::vector<std::shared_ptr<Primitive>> &primitives, int depth) {
|
||||||
|
// IMPLEMENT ME
|
||||||
|
// Determine the diameter of the bounding box
|
||||||
|
|
||||||
|
// Test whether we have reached a leaf node...
|
||||||
|
|
||||||
|
// ... otherwise create a new inner node by splitting through the widest
|
||||||
|
// dimension
|
||||||
|
|
||||||
|
// Determine the split position
|
||||||
|
// Note: Use the median of the minimum bounds of the primitives
|
||||||
|
|
||||||
|
// Divide primitives into the left and right lists
|
||||||
|
// Remember: A primitive can be in both lists!
|
||||||
|
// Also remember: You split exactly at the minimum of a primitive,
|
||||||
|
// make sure *that* primitive does *not* appear in both lists!
|
||||||
|
|
||||||
|
// Print out the number of primitives in the left and right child node
|
||||||
|
|
||||||
|
// Set the left and right split vectors
|
||||||
|
|
||||||
|
// Recursively build the tree
|
||||||
|
return nullptr;
|
||||||
|
}
|
46
scene/fastscene.h
Normal file
46
scene/fastscene.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef FASTSCENE_H
|
||||||
|
#define FASTSCENE_H
|
||||||
|
|
||||||
|
#include "scene/scene.h"
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
// Constructor / Destructor
|
||||||
|
Node() : dimension(0), split(0) {}
|
||||||
|
|
||||||
|
// Traversal function
|
||||||
|
bool findIntersection(Ray &ray, float t0, float t1) const;
|
||||||
|
bool findOcclusion(Ray &ray, float t0, float t1) const;
|
||||||
|
int countNodeIntersections(const Ray &ray, float t0, float t1) const;
|
||||||
|
inline bool isLeaf() const { return (!this->primitives.empty() || (!this->child[0] && !this->child[1])); }
|
||||||
|
|
||||||
|
// Branch split
|
||||||
|
std::unique_ptr<Node> child[2];
|
||||||
|
int dimension;
|
||||||
|
float split;
|
||||||
|
|
||||||
|
// Leaf primitives
|
||||||
|
std::vector<std::shared_ptr<Primitive>> primitives;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FastScene : public Scene {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Raytracing functions
|
||||||
|
bool findIntersection(Ray &ray) const override;
|
||||||
|
bool findOcclusion(Ray &ray) const override;
|
||||||
|
int countNodeIntersections(const Ray &ray) const;
|
||||||
|
|
||||||
|
// Setup functions
|
||||||
|
void buildTree(int maximumDepth = 10, int minimumNumberOfPrimitives = 2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Node> build(Vector3d const &minimumBounds, Vector3d const &maximumBounds,
|
||||||
|
const std::vector<std::shared_ptr<Primitive>> &primitives, int depth);
|
||||||
|
|
||||||
|
std::unique_ptr<Node> root;
|
||||||
|
int maximumDepth;
|
||||||
|
int minimumNumberOfPrimitives;
|
||||||
|
Vector3d absoluteMinimum, absoluteMaximum;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,90 +8,42 @@ BrdfShader::BrdfShader(char const *fileName, Color const &scale)
|
||||||
: scale(scale), brdf(std::make_unique<BRDFRead>(fileName)) {}
|
: scale(scale), brdf(std::make_unique<BRDFRead>(fileName)) {}
|
||||||
|
|
||||||
Color BrdfShader::shade(Scene const &scene, Ray const &ray) const {
|
Color BrdfShader::shade(Scene const &scene, Ray const &ray) const {
|
||||||
|
// Calculate theta and phi
|
||||||
|
float thetaIn = std::acos(dotProduct(-ray.normal, ray.direction));
|
||||||
|
float phiIn = 0.0f;
|
||||||
|
|
||||||
|
// Derive local coordinate system
|
||||||
|
Vector3d const x = crossProduct(-ray.direction, ray.normal);
|
||||||
|
Vector3d const y = crossProduct(ray.normal, x);
|
||||||
|
|
||||||
|
// Accumulate the light over all light sources
|
||||||
Color illuminationColor;
|
Color illuminationColor;
|
||||||
/*
|
for (const auto &light : scene.lights()) {
|
||||||
* Arvids Code
|
Light::Illumination illum;
|
||||||
static auto rebase = [](Vector3d const &axis_x,
|
illum = light->illuminate(scene, ray);
|
||||||
Vector3d const &axis_y,
|
|
||||||
Vector3d const &axis_z,
|
|
||||||
Vector3d const &vec) {
|
|
||||||
auto det = axis_x.x * axis_y.y * axis_z.z +
|
|
||||||
axis_x.y * axis_y.z * axis_z.x +
|
|
||||||
axis_x.z * axis_y.x * axis_z.y -
|
|
||||||
axis_x.x * axis_y.z * axis_z.y -
|
|
||||||
axis_x.y * axis_y.x * axis_z.z -
|
|
||||||
axis_x.z * axis_y.y * axis_z.x;
|
|
||||||
// Calculate resulting vector by using inverse matrix of new base vectors
|
|
||||||
return Vector3d{
|
|
||||||
((axis_y.y * axis_z.z - axis_y.z * axis_z.y) * vec.x +
|
|
||||||
(axis_y.z * axis_z.x - axis_y.x * axis_z.z) * vec.y +
|
|
||||||
(axis_y.x * axis_z.y - axis_z.x * axis_y.y) * vec.z) / det,
|
|
||||||
((axis_x.z * axis_z.y - axis_x.y * axis_z.z) * vec.x +
|
|
||||||
(axis_x.x * axis_z.z - axis_x.z * axis_z.x) * vec.y +
|
|
||||||
(axis_z.x * axis_x.y - axis_x.x * axis_z.y) * vec.z) / det,
|
|
||||||
((axis_x.y * axis_y.z - axis_x.z * axis_y.y) * vec.x +
|
|
||||||
(axis_y.x * axis_x.z - axis_x.x * axis_y.z) * vec.y +
|
|
||||||
(axis_x.x * axis_y.y - axis_y.x * axis_x.y) * vec.z) / det
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto &light: scene.lights()) {
|
// Diffuse term
|
||||||
|
float const cosine = dotProduct(-illum.direction, ray.normal);
|
||||||
|
if (cosine > 0) {
|
||||||
|
Color color;
|
||||||
|
|
||||||
auto illum = light->illuminate(scene, ray);
|
// Avoid numeric instability
|
||||||
if (dotProduct(ray.normal, illum.direction) <= EPSILON) {
|
if (cosine < 1) {
|
||||||
continue;
|
float const thetaOut = std::acos(cosine);
|
||||||
|
|
||||||
|
// Project outgoing vector into local coordinate system
|
||||||
|
Vector3d const c = crossProduct(-illum.direction, ray.normal);
|
||||||
|
float const phiOut = std::atan2(dotProduct(c, y), dotProduct(c, x));
|
||||||
|
|
||||||
|
color = Color(brdf->lookupBrdfValues(thetaIn, phiIn, thetaOut, phiOut));
|
||||||
|
} else {
|
||||||
|
color = Color(brdf->lookupBrdfValues(thetaIn, phiIn, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto axis = orthoNormalized(ray.normal, ray.direction, illum.direction);
|
// Calculate colors
|
||||||
auto axis_y = std::get<0>(axis);
|
Color const diffuseColor = scale * color * cosine;
|
||||||
auto axis_x = std::get<1>(axis);
|
illuminationColor += diffuseColor * illum.color;
|
||||||
auto axis_z = std::get<2>(axis);
|
|
||||||
|
|
||||||
auto N = normalized(rebase(axis_x, axis_y, axis_z, ray.normal));
|
|
||||||
auto D = normalized(rebase(axis_x, axis_y, axis_z, -ray.direction));
|
|
||||||
auto L = normalized(rebase(axis_x, axis_y, axis_z, -illum.direction));
|
|
||||||
D = axis_y * D.y + axis_z * D.z;
|
|
||||||
L = axis_y * L.y + axis_z * L.z;
|
|
||||||
|
|
||||||
illuminationColor += brdf->lookupBrdfValues(std::acos(dotProduct(ray.normal, -ray.direction)),
|
|
||||||
0.0f,
|
|
||||||
std::acos(dotProduct(illum.direction, ray.normal)),
|
|
||||||
std::acos(dotProduct(D, L)));
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
// IMPLEMENT ME
|
|
||||||
|
|
||||||
for(auto& light : scene.lights()){
|
|
||||||
Light::Illumination illum = light->illuminate(scene, ray);
|
|
||||||
|
|
||||||
Vector3d invertedDirection = -ray.direction;
|
|
||||||
Vector3d invertedIllum = -illum.direction;
|
|
||||||
|
|
||||||
// the dot-product cant be negative otherwise the light ray would come from the inside
|
|
||||||
if(dotProduct(invertedIllum, ray.normal) < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Calculate coordinate System
|
|
||||||
Vector3d axisX = crossProduct(invertedDirection, ray.normal);
|
|
||||||
Vector3d axisY = crossProduct(axisX, ray.normal);
|
|
||||||
|
|
||||||
// Project ray.direction and illum.direction into plane
|
|
||||||
Vector2d projectedIllum = Vector2d(dotProduct(axisX, invertedIllum), dotProduct(axisY, invertedIllum));
|
|
||||||
Vector2d projectedDirection = Vector2d(dotProduct(axisX, invertedDirection), dotProduct(axisY, invertedDirection));
|
|
||||||
|
|
||||||
// get Z coordinate for theta angles
|
|
||||||
double coordinateZDirection = dotProduct(ray.normal, invertedDirection);
|
|
||||||
double coordinateZIllum = dotProduct(ray.normal, invertedIllum);
|
|
||||||
|
|
||||||
// calculate theta1 and 2
|
|
||||||
double theta1Correct = std::atan2(length(projectedDirection), coordinateZDirection);
|
|
||||||
double theta2Correct = std::atan2(length(projectedIllum), coordinateZIllum);
|
|
||||||
|
|
||||||
// calculate phi
|
|
||||||
double phi = std::atan2(projectedIllum.u, projectedIllum.v);
|
|
||||||
|
|
||||||
illuminationColor += brdf->lookupBrdfValues(theta1Correct, 0.0, theta2Correct, phi);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return illuminationColor;
|
return illuminationColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,51 @@ CookTorranceShader::CookTorranceShader(Color const &diffCol, Color const &ctCol,
|
||||||
ctColor(ctCol * ctCoeff), F0(IOR),
|
ctColor(ctCol * ctCoeff), F0(IOR),
|
||||||
m(roughness) {}
|
m(roughness) {}
|
||||||
|
|
||||||
|
float CookTorranceShader::D(float NdotH) const {
|
||||||
|
// Beckmann distribution
|
||||||
|
float const r2 = m * m;
|
||||||
|
float const NdotH2 = NdotH * NdotH;
|
||||||
|
return expf((NdotH2 - 1.0f) / (r2 * NdotH2)) / (4.0f * r2 * powf(NdotH, 4.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
float CookTorranceShader::F(float VdotH) const {
|
||||||
|
// Schlicks approximation
|
||||||
|
return F0 + (1.0f - F0) * powf(1.0f - VdotH, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
float CookTorranceShader::G(float NdotH, float NdotV, float VdotH, float NdotL) const { return std::min(1.0f, std::min(2.0f * NdotH * NdotV / VdotH, 2.0f * NdotH * NdotL / VdotH)); }
|
||||||
|
|
||||||
Color CookTorranceShader::shade(Scene const &scene, Ray const &ray) const {
|
Color CookTorranceShader::shade(Scene const &scene, Ray const &ray) const {
|
||||||
Color fragmentColor;
|
Color fragmentColor;
|
||||||
|
|
||||||
// IMPLEMENT ME
|
if (m >= 0.0f) {
|
||||||
for (auto &light: scene.lights()) {
|
// Accumulate the light over all light sources
|
||||||
auto illum = light->illuminate(scene, ray);
|
for (const auto &light : scene.lights()) {
|
||||||
auto N = ray.normal;
|
Light::Illumination illum;
|
||||||
auto V = ray.direction;
|
illum = light->illuminate(scene, ray);
|
||||||
auto L = illum.direction;
|
|
||||||
auto H = normalized(V + L);
|
float const NdotL = std::max(0.0f, dotProduct(-illum.direction, ray.normal));
|
||||||
|
if (NdotL <= 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Diffuse term
|
||||||
|
Color const diffuse = this->diffuseColor / float(PI);
|
||||||
|
fragmentColor += diffuse * NdotL * illum.color;
|
||||||
|
|
||||||
|
// Cook-Torrance term
|
||||||
|
// half angle vector
|
||||||
|
Vector3d const H = normalized(-illum.direction - ray.direction);
|
||||||
|
float const NdotH = std::max(0.0f, dotProduct(ray.normal, H));
|
||||||
|
float const NdotV = std::max(0.0f, dotProduct(ray.normal, -ray.direction));
|
||||||
|
float const VdotH = std::max(0.0f, dotProduct(-ray.direction, H));
|
||||||
|
|
||||||
|
if (NdotV * NdotL > EPSILON) {
|
||||||
|
Color const specular = this->ctColor * (F(VdotH) * D(NdotH) * G(NdotH, NdotV, VdotH, NdotL)) / (float(PI) * NdotV * NdotL);
|
||||||
|
|
||||||
|
fragmentColor += specular * NdotL * illum.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto NV = dotProduct(N, V);
|
auto NV = dotProduct(N, V);
|
||||||
auto NL = dotProduct(N, L);
|
auto NL = dotProduct(N, L);
|
||||||
|
|
|
@ -7,11 +7,13 @@ LambertShader::LambertShader(Color const &diffuseColor) : diffuseColor(diffuseCo
|
||||||
Color LambertShader::shade(Scene const &scene, Ray const &ray) const {
|
Color LambertShader::shade(Scene const &scene, Ray const &ray) const {
|
||||||
Color fragmentColor;
|
Color fragmentColor;
|
||||||
|
|
||||||
// IMPLEMENT ME
|
// Accumulate the light over all light sources
|
||||||
for (auto& light : scene.lights()) {
|
for (const auto &light : scene.lights()) {
|
||||||
auto illum = light->illuminate(scene, ray);
|
Light::Illumination const illum = light->illuminate(scene, ray);
|
||||||
auto lightAngle = dotProduct(ray.normal, normalized(illum.direction));
|
// Diffuse term
|
||||||
fragmentColor += illum.color * std::abs(lightAngle);
|
Color const diffuse = this->diffuseColor * std::max(dotProduct(-illum.direction, ray.normal), 0.0f);
|
||||||
|
fragmentColor += diffuse * illum.color;
|
||||||
}
|
}
|
||||||
return fragmentColor * diffuseColor;
|
|
||||||
|
return fragmentColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,27 @@ PhongShader::PhongShader(Color const &diffuseColor, float diffuseCoefficient, Co
|
||||||
Color PhongShader::shade(Scene const &scene, Ray const &ray) const {
|
Color PhongShader::shade(Scene const &scene, Ray const &ray) const {
|
||||||
Color fragmentColor;
|
Color fragmentColor;
|
||||||
|
|
||||||
|
// Calculate the reflection vector
|
||||||
|
Vector3d const reflection = ray.direction - 2 * dotProduct(ray.normal, ray.direction) * ray.normal;
|
||||||
|
|
||||||
|
// Accumulate the light over all light sources
|
||||||
|
for (const auto &light : scene.lights()) {
|
||||||
|
Light::Illumination illum;
|
||||||
|
illum = light->illuminate(scene, ray);
|
||||||
|
|
||||||
|
// Diffuse term
|
||||||
|
Color const diffuse =
|
||||||
|
this->diffuseCoefficient * this->diffuseColor * std::max(dotProduct(-illum.direction, ray.normal), 0.0f);
|
||||||
|
fragmentColor += diffuse * illum.color;
|
||||||
|
|
||||||
|
// Specular term
|
||||||
|
float const cosine = dotProduct(-illum.direction, reflection);
|
||||||
|
if (cosine > 0) {
|
||||||
|
Color const specular = this->specularCoefficient * this->specularColor // highlight
|
||||||
|
* powf(cosine, this->shininessExponent); // shininess factor
|
||||||
|
fragmentColor += specular * illum.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &light: scene.lights()) {
|
for (auto &light: scene.lights()) {
|
||||||
auto illum = light->illuminate(scene, ray);
|
auto illum = light->illuminate(scene, ray);
|
||||||
|
|
Loading…
Reference in a new issue