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)
|
||||
|
||||
|
||||
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;
|
||||
|
||||
// Calculate the normal
|
||||
// IMPLEMENT smooth triangles, if available
|
||||
if (this->normal[0] == Vector3d{} || this->normal[1] == Vector3d{} || this->normal[2] == Vector3d{}) {
|
||||
ray.normal = normalized(crossProduct(edge1, edge2));
|
||||
} else {
|
||||
ray.normal = u * this->normal[1] + v * this->normal[2] + (1 - u - v) * this->normal[0];
|
||||
}
|
||||
if (length(this->normal[0]) * length(this->normal[1]) * length(this->normal[2]) > EPSILON)
|
||||
ray.normal = normalized(u * this->normal[1] + v * this->normal[2] + (1 - u - v) * this->normal[0]);
|
||||
else
|
||||
ray.normal = normalized(crossProduct(edge1, edge2));
|
||||
// calculate the tangent and bitangent vectors as well
|
||||
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
|
||||
|
|
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)) {}
|
||||
|
||||
Color BrdfShader::shade(Scene const &scene, Ray const &ray) const {
|
||||
Color illuminationColor;
|
||||
/*
|
||||
* Arvids Code
|
||||
static auto rebase = [](Vector3d const &axis_x,
|
||||
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
|
||||
};
|
||||
};
|
||||
// Calculate theta and phi
|
||||
float thetaIn = std::acos(dotProduct(-ray.normal, ray.direction));
|
||||
float phiIn = 0.0f;
|
||||
|
||||
for (auto &light: scene.lights()) {
|
||||
// Derive local coordinate system
|
||||
Vector3d const x = crossProduct(-ray.direction, ray.normal);
|
||||
Vector3d const y = crossProduct(ray.normal, x);
|
||||
|
||||
auto illum = light->illuminate(scene, ray);
|
||||
if (dotProduct(ray.normal, illum.direction) <= EPSILON) {
|
||||
continue;
|
||||
}
|
||||
// Accumulate the light over all light sources
|
||||
Color illuminationColor;
|
||||
for (const auto &light : scene.lights()) {
|
||||
Light::Illumination illum;
|
||||
illum = light->illuminate(scene, ray);
|
||||
|
||||
auto axis = orthoNormalized(ray.normal, ray.direction, illum.direction);
|
||||
auto axis_y = std::get<0>(axis);
|
||||
auto axis_x = std::get<1>(axis);
|
||||
auto axis_z = std::get<2>(axis);
|
||||
// Diffuse term
|
||||
float const cosine = dotProduct(-illum.direction, ray.normal);
|
||||
if (cosine > 0) {
|
||||
Color color;
|
||||
|
||||
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;
|
||||
// Avoid numeric instability
|
||||
if (cosine < 1) {
|
||||
float const thetaOut = std::acos(cosine);
|
||||
|
||||
illuminationColor += brdf->lookupBrdfValues(std::acos(dotProduct(ray.normal, -ray.direction)),
|
||||
0.0f,
|
||||
std::acos(dotProduct(illum.direction, ray.normal)),
|
||||
std::acos(dotProduct(D, L)));
|
||||
// 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));
|
||||
}
|
||||
|
||||
// Calculate colors
|
||||
Color const diffuseColor = scale * color * cosine;
|
||||
illuminationColor += diffuseColor * illum.color;
|
||||
}
|
||||
*/
|
||||
// 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),
|
||||
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 fragmentColor;
|
||||
|
||||
// IMPLEMENT ME
|
||||
for (auto &light: scene.lights()) {
|
||||
auto illum = light->illuminate(scene, ray);
|
||||
auto N = ray.normal;
|
||||
auto V = ray.direction;
|
||||
auto L = illum.direction;
|
||||
auto H = normalized(V + L);
|
||||
if (m >= 0.0f) {
|
||||
// Accumulate the light over all light sources
|
||||
for (const auto &light : scene.lights()) {
|
||||
Light::Illumination illum;
|
||||
illum = light->illuminate(scene, ray);
|
||||
|
||||
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 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 fragmentColor;
|
||||
|
||||
// IMPLEMENT ME
|
||||
for (auto& light : scene.lights()) {
|
||||
auto illum = light->illuminate(scene, ray);
|
||||
auto lightAngle = dotProduct(ray.normal, normalized(illum.direction));
|
||||
fragmentColor += illum.color * std::abs(lightAngle);
|
||||
// Accumulate the light over all light sources
|
||||
for (const auto &light : scene.lights()) {
|
||||
Light::Illumination const illum = light->illuminate(scene, ray);
|
||||
// Diffuse term
|
||||
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 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()) {
|
||||
auto illum = light->illuminate(scene, ray);
|
||||
|
|
Loading…
Reference in a new issue