Merge remote-tracking branch 'base/master'
This commit is contained in:
commit
d077b8981c
20 changed files with 793 additions and 200 deletions
|
@ -54,6 +54,9 @@ if("${CMAKE_CURRENT_LIST_DIR}/primitive/objmodel.cpp" IN_LIST primitive_src)
|
|||
add_definitions(-DOBJMODEL_FOUND)
|
||||
endif()
|
||||
|
||||
add_executable(tracey_ex4 ex4.cpp)
|
||||
target_link_libraries(tracey_ex4 tracey)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
202
common/brdfread.cpp
Normal file
202
common/brdfread.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
// Copyright 2005 Mitsubishi Electric Research Laboratories All Rights Reserved.
|
||||
|
||||
// Permission to use, copy and modify this software and its documentation without
|
||||
// fee for educational, research and non-profit purposes, is hereby granted, provided
|
||||
// that the above copyright notice and the following three paragraphs appear in all copies.
|
||||
|
||||
// To request permission to incorporate this software into commercial products contact:
|
||||
// Vice President of Marketing and Business Development;
|
||||
// Mitsubishi Electric Research Laboratories (MERL), 201 Broadway, Cambridge, MA 02139 or
|
||||
// <license@merl.com>.
|
||||
|
||||
// IN NO EVENT SHALL MERL BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
|
||||
// OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND
|
||||
// ITS DOCUMENTATION, EVEN IF MERL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
// MERL SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED
|
||||
// HEREUNDER IS ON AN "AS IS" BASIS, AND MERL HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
|
||||
// UPDATES, ENHANCEMENTS OR MODIFICATIONS.
|
||||
#include "common/brdfread.h"
|
||||
|
||||
BRDFRead::BRDFRead(const char *filename) {
|
||||
if (!readBrdf(filename)) {
|
||||
std::cerr << "Cannot read BRDF file: " << filename << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
Color BRDFRead::lookupBrdfValues(double theta_in, double phi_in, double theta_out, double phi_out) {
|
||||
// std::cerr << theta_in << "," << theta_out;
|
||||
// Convert to halfangle / difference angle coordinates
|
||||
double theta_half, phi_half, theta_diff, phi_diff;
|
||||
std_coords_to_half_diff_coords(theta_in, phi_in, theta_out, phi_out, theta_half, phi_half, theta_diff, phi_diff);
|
||||
|
||||
// Find index.
|
||||
// Note that phi_half is ignored, since isotropic BRDFs are assumed
|
||||
int ind = phi_diff_index(phi_diff) + theta_diff_index(theta_diff) * BRDF_SAMPLING_RES_PHI_D / 2 +
|
||||
theta_half_index(theta_half) * BRDF_SAMPLING_RES_PHI_D / 2 * BRDF_SAMPLING_RES_THETA_D;
|
||||
|
||||
Color color;
|
||||
color.r = static_cast<float>(brdfData[ind] * RED_SCALE);
|
||||
color.g = static_cast<float>(
|
||||
brdfData[ind + BRDF_SAMPLING_RES_THETA_H * BRDF_SAMPLING_RES_THETA_D * BRDF_SAMPLING_RES_PHI_D / 2] *
|
||||
GREEN_SCALE);
|
||||
color.b = static_cast<float>(
|
||||
brdfData[ind + BRDF_SAMPLING_RES_THETA_H * BRDF_SAMPLING_RES_THETA_D * BRDF_SAMPLING_RES_PHI_D] * BLUE_SCALE);
|
||||
|
||||
// std::cerr << red_val << "," <<green_val << "," << blue_val<< std::endl;
|
||||
if (color.r < 0.0 || color.g < 0.0 || color.b < 0.0)
|
||||
fprintf(stderr, "Below horizon.\n");
|
||||
return color;
|
||||
}
|
||||
|
||||
bool BRDFRead::readBrdf(const char *filename) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
int dims[3];
|
||||
size_t numbytes = fread(dims, sizeof(int), 3, f);
|
||||
if (numbytes == 0) {
|
||||
return false;
|
||||
}
|
||||
int n = dims[0] * dims[1] * dims[2];
|
||||
if (n != BRDF_SAMPLING_RES_THETA_H * BRDF_SAMPLING_RES_THETA_D * BRDF_SAMPLING_RES_PHI_D / 2) {
|
||||
fprintf(stderr, "Dimensions don't match\n");
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
brdfData = (double *)malloc(sizeof(double) * 3 * n);
|
||||
numbytes = fread(brdfData, sizeof(double), 3 * n, f);
|
||||
if (numbytes == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BRDFRead::cross_product(double *v1, double *v2, double *out) {
|
||||
out[0] = v1[1] * v2[2] - v1[2] * v2[1];
|
||||
out[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||||
out[2] = v1[0] * v2[1] - v1[1] * v2[0];
|
||||
}
|
||||
|
||||
void BRDFRead::normalize(double *v) {
|
||||
// normalize
|
||||
double len = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
v[0] = v[0] / len;
|
||||
v[1] = v[1] / len;
|
||||
v[2] = v[2] / len;
|
||||
}
|
||||
|
||||
void BRDFRead::rotate_vector(double *vector, double *axis, double angle, double *out) {
|
||||
double temp;
|
||||
double cross[3];
|
||||
double cos_ang = cos(angle);
|
||||
double sin_ang = sin(angle);
|
||||
|
||||
out[0] = vector[0] * cos_ang;
|
||||
out[1] = vector[1] * cos_ang;
|
||||
out[2] = vector[2] * cos_ang;
|
||||
|
||||
temp = axis[0] * vector[0] + axis[1] * vector[1] + axis[2] * vector[2];
|
||||
temp = temp * (1.0 - cos_ang);
|
||||
|
||||
out[0] += axis[0] * temp;
|
||||
out[1] += axis[1] * temp;
|
||||
out[2] += axis[2] * temp;
|
||||
|
||||
cross_product(axis, vector, cross);
|
||||
|
||||
out[0] += cross[0] * sin_ang;
|
||||
out[1] += cross[1] * sin_ang;
|
||||
out[2] += cross[2] * sin_ang;
|
||||
}
|
||||
|
||||
void BRDFRead::std_coords_to_half_diff_coords(double theta_in, double phi_in, double theta_out, double phi_out,
|
||||
double &theta_half, double &phi_half, double &theta_diff,
|
||||
double &phi_diff) {
|
||||
// compute in vector
|
||||
double in_vec_z = cos(theta_in);
|
||||
double proj_in_vec = sin(theta_in);
|
||||
double in_vec_x = proj_in_vec * cos(phi_in);
|
||||
double in_vec_y = proj_in_vec * sin(phi_in);
|
||||
double in[3] = {in_vec_x, in_vec_y, in_vec_z};
|
||||
normalize(in);
|
||||
|
||||
// compute out vector
|
||||
double out_vec_z = cos(theta_out);
|
||||
double proj_out_vec = sin(theta_out);
|
||||
double out_vec_x = proj_out_vec * cos(phi_out);
|
||||
double out_vec_y = proj_out_vec * sin(phi_out);
|
||||
double out[3] = {out_vec_x, out_vec_y, out_vec_z};
|
||||
normalize(out);
|
||||
|
||||
// compute halfway vector
|
||||
double half_x = (in_vec_x + out_vec_x) / 2.0f;
|
||||
double half_y = (in_vec_y + out_vec_y) / 2.0f;
|
||||
double half_z = (in_vec_z + out_vec_z) / 2.0f;
|
||||
double half[3] = {half_x, half_y, half_z};
|
||||
normalize(half);
|
||||
|
||||
// compute theta_half, phi_half
|
||||
theta_half = acos(half[2]);
|
||||
phi_half = atan2(half[1], half[0]);
|
||||
|
||||
double bi_normal[3] = {0.0, 1.0, 0.0};
|
||||
double normal[3] = {0.0, 0.0, 1.0};
|
||||
double temp[3];
|
||||
double diff[3];
|
||||
|
||||
// compute diff vector
|
||||
rotate_vector(in, normal, -phi_half, temp);
|
||||
rotate_vector(temp, bi_normal, -theta_half, diff);
|
||||
|
||||
// compute theta_diff, phi_diff
|
||||
theta_diff = acos(diff[2]);
|
||||
phi_diff = atan2(diff[1], diff[0]);
|
||||
}
|
||||
|
||||
int BRDFRead::theta_half_index(double theta_half) {
|
||||
if (theta_half <= 0.0)
|
||||
return 0;
|
||||
double theta_half_deg = ((theta_half / (M_PI / 2.0)) * BRDF_SAMPLING_RES_THETA_H);
|
||||
double temp = theta_half_deg * BRDF_SAMPLING_RES_THETA_H;
|
||||
temp = sqrt(temp);
|
||||
int ret_val = (int)temp;
|
||||
if (ret_val < 0)
|
||||
ret_val = 0;
|
||||
if (ret_val >= BRDF_SAMPLING_RES_THETA_H)
|
||||
ret_val = BRDF_SAMPLING_RES_THETA_H - 1;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int BRDFRead::theta_diff_index(double theta_diff) {
|
||||
int tmp = int(theta_diff / (M_PI * 0.5) * BRDF_SAMPLING_RES_THETA_D);
|
||||
if (tmp < 0)
|
||||
return 0;
|
||||
else if (tmp < BRDF_SAMPLING_RES_THETA_D - 1)
|
||||
return tmp;
|
||||
else
|
||||
return BRDF_SAMPLING_RES_THETA_D - 1;
|
||||
}
|
||||
|
||||
int BRDFRead::phi_diff_index(double phi_diff) {
|
||||
// Because of reciprocity, the BRDF is unchanged under
|
||||
// phi_diff -> phi_diff + M_PI
|
||||
if (phi_diff < 0.0)
|
||||
phi_diff += M_PI;
|
||||
|
||||
// In: phi_diff in [0 .. pi]
|
||||
// Out: tmp in [0 .. 179]
|
||||
int tmp = int(phi_diff / M_PI * BRDF_SAMPLING_RES_PHI_D / 2);
|
||||
if (tmp < 0)
|
||||
return 0;
|
||||
else if (tmp < BRDF_SAMPLING_RES_PHI_D / 2 - 1)
|
||||
return tmp;
|
||||
else
|
||||
return BRDF_SAMPLING_RES_PHI_D / 2 - 1;
|
||||
}
|
100
common/brdfread.h
Normal file
100
common/brdfread.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2005 Mitsubishi Electric Research Laboratories All Rights Reserved.
|
||||
|
||||
// Permission to use, copy and modify this software and its documentation without
|
||||
// fee for educational, research and non-profit purposes, is hereby granted, provided
|
||||
// that the above copyright notice and the following three paragraphs appear in all copies.
|
||||
|
||||
// To request permission to incorporate this software into commercial products contact:
|
||||
// Vice President of Marketing and Business Development;
|
||||
// Mitsubishi Electric Research Laboratories (MERL), 201 Broadway, Cambridge, MA 02139 or
|
||||
// <license@merl.com>.
|
||||
|
||||
// IN NO EVENT SHALL MERL BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
|
||||
// OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND
|
||||
// ITS DOCUMENTATION, EVEN IF MERL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
// MERL SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED
|
||||
// HEREUNDER IS ON AN "AS IS" BASIS, AND MERL HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
|
||||
// UPDATES, ENHANCEMENTS OR MODIFICATIONS.
|
||||
|
||||
// The Implementation has been moved to "brdfread.cpp" for compatibility
|
||||
#ifndef BRDFREAD_H
|
||||
#define BRDFREAD_H
|
||||
|
||||
#include <cmath>
|
||||
#include <common/color.h>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#define BRDF_SAMPLING_RES_THETA_H 90
|
||||
#define BRDF_SAMPLING_RES_THETA_D 90
|
||||
#define BRDF_SAMPLING_RES_PHI_D 360
|
||||
|
||||
#define RED_SCALE (1.0 / 1500.0)
|
||||
#define GREEN_SCALE (1.15 / 1500.0)
|
||||
#define BLUE_SCALE (1.66 / 1500.0)
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
|
||||
class BRDFRead {
|
||||
public:
|
||||
BRDFRead(const char *filename);
|
||||
|
||||
/**
|
||||
* Given a pair of incoming/outgoing angles, look up the BRDF.
|
||||
*/
|
||||
Color lookupBrdfValues(double theta_in, double phi_in, double theta_out, double phi_out);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Read BRDF data
|
||||
*/
|
||||
bool readBrdf(const char *filename);
|
||||
|
||||
/**
|
||||
* cross product of two vectors
|
||||
*/
|
||||
void cross_product(double *v1, double *v2, double *out);
|
||||
|
||||
/**
|
||||
* normalize vector
|
||||
*/
|
||||
void normalize(double *v);
|
||||
|
||||
/**
|
||||
* rotate vector along one axis
|
||||
*/
|
||||
void rotate_vector(double *vector, double *axis, double angle, double *out);
|
||||
|
||||
/**
|
||||
* convert standard coordinates to half vector/difference vector coordinates
|
||||
*/
|
||||
void std_coords_to_half_diff_coords(double theta_in, double phi_in, double theta_out, double phi_out,
|
||||
double &theta_half, double &phi_half, double &theta_diff, double &phi_diff);
|
||||
|
||||
/**
|
||||
* Lookup theta_half index
|
||||
* This is a non-linear mapping!
|
||||
* In: [0 .. pi/2]
|
||||
* Out: [0 .. 89]
|
||||
*/
|
||||
inline int theta_half_index(double theta_half);
|
||||
|
||||
/**
|
||||
* Lookup theta_diff index
|
||||
* In: [0 .. pi/2]
|
||||
* Out: [0 .. 89]
|
||||
*/
|
||||
inline int theta_diff_index(double theta_diff);
|
||||
|
||||
/**
|
||||
* Lookup phi_diff index
|
||||
*/
|
||||
inline int phi_diff_index(double phi_diff);
|
||||
|
||||
double *brdfData;
|
||||
};
|
||||
|
||||
#endif
|
74
ex4.cpp
Normal file
74
ex4.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "camera/perspectivecamera.h"
|
||||
#include "renderer/simplerenderer.h"
|
||||
#include "scene/simplescene.h"
|
||||
|
||||
#include "primitive/box.h"
|
||||
#include "primitive/infiniteplane.h"
|
||||
#include "primitive/objmodel.h"
|
||||
#include "primitive/sphere.h"
|
||||
|
||||
#include "shader/brdfshader.h"
|
||||
|
||||
#include "shader/lambertshader.h"
|
||||
#include "shader/mirrorshader.h"
|
||||
#include "shader/phongshader.h"
|
||||
#include "shader/cooktorranceshader.h"
|
||||
|
||||
#include "light/ambientlight.h"
|
||||
#include "light/pointlight.h"
|
||||
#include "light/spotlight.h"
|
||||
|
||||
int main() {
|
||||
// Let's create a simple scene...
|
||||
SimpleScene scene;
|
||||
|
||||
// Add shaders
|
||||
auto mirror = std::make_shared<MirrorShader>();
|
||||
auto white = std::make_shared<LambertShader>(Color(0.9f, 0.9f, 0.9f));
|
||||
auto red = std::make_shared<LambertShader>(Color(1.0f, 0.3f, 0.2f));
|
||||
auto blue = std::make_shared<LambertShader>(Color(0.2f, 0.3f, 1.0f));
|
||||
auto orange = std::make_shared<PhongShader>(Color(1.0f, 0.64f, 0.0f), 1.0f, Color(1.0f, 1.0f, 1.0f), 1.0f, 25.0f);
|
||||
auto gold= std::make_shared<CookTorranceShader>(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f);
|
||||
auto blueMetallic = std::make_shared<BrdfShader>("data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||
auto darkRed = std::make_shared<BrdfShader>("data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||
|
||||
// Set up the walls
|
||||
// ---------------------------------------------------------------------------
|
||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), mirror));
|
||||
|
||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror));
|
||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, +5.0f, 0.0f), Vector3d(0.0f, -1.0f, 0.0f), white));
|
||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, +1.0f, 0.0f), white));
|
||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), blue));
|
||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(-5.0f, 0.0f, 0.0f), Vector3d(+1.0f, 0.0f, 0.0f), red));
|
||||
|
||||
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, blueMetallic));
|
||||
scene.add(std::make_shared<Sphere>(Vector3d(0.0f, 2.0f, 0.0f), 1.0f, orange));
|
||||
scene.add(std::make_shared<Sphere>(Vector3d(3.0f, 0.0f, 0.0f), 1.0f, darkRed));
|
||||
|
||||
// Add the teapot
|
||||
auto teapot = std::make_shared<ObjModel>(gold);
|
||||
teapot->loadObj("data/teapot.obj", Vector3d(3.0f, 3.0f, 3.0f), Vector3d(0.0f, -5.0f, 0.0f));
|
||||
scene.add(teapot);
|
||||
|
||||
// Add ambient light
|
||||
scene.add(std::make_shared<AmbientLight>(0.15f));
|
||||
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, -4.0f), 15.0f));
|
||||
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, 4.0f), 15.0f));
|
||||
|
||||
// Set up the camera
|
||||
PerspectiveCamera camera;
|
||||
camera.setFovAngle(90.0f);
|
||||
camera.setPosition(Vector3d(0.0f, 0.0f, -10.0f));
|
||||
camera.setForwardDirection(Vector3d(0.0f, 0.0f, 1.0f));
|
||||
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||
|
||||
// Render the scene
|
||||
SimpleRenderer renderer;
|
||||
renderer.renderImage(scene, camera, 512, 512).save("result.png");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,32 +1,5 @@
|
|||
//
|
||||
// Created by marcel on 21.11.22.
|
||||
//
|
||||
|
||||
#include "light/ambientlight.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
AmbientLight::AmbientLight(float intensity, const Color &color) : Light(intensity, color) {}
|
||||
|
||||
Light::Illumination AmbientLight::illuminate(Scene const &scene, Ray const &ray) const {
|
||||
Vector3d const target = ray.origin + (ray.length - LGT_EPS) * ray.direction;
|
||||
|
||||
Illumination illum;
|
||||
illum.direction = -ray.normal;
|
||||
|
||||
// Precompute the distance from the light source
|
||||
float const distance = length(ray.normal);
|
||||
|
||||
|
||||
// Define a secondary ray from the surface point to the light source.
|
||||
Ray lightRay;
|
||||
lightRay.origin = target;
|
||||
lightRay.direction = -illum.direction;
|
||||
lightRay.length = distance - LGT_EPS;
|
||||
|
||||
// If the target is not in shadow...
|
||||
if (!scene.findOcclusion(lightRay))
|
||||
// ... compute the attenuation and light color
|
||||
illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
|
||||
return illum;
|
||||
return illum;
|
||||
return {this->color * this->intensity, -ray.normal};
|
||||
}
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
//
|
||||
// Created by marcel on 21.11.22.
|
||||
//
|
||||
|
||||
#ifndef CG1_TRACER_AMBIENTLIGHT_H
|
||||
#define CG1_TRACER_AMBIENTLIGHT_H
|
||||
#ifndef AMBIENTLIGHT_H
|
||||
#define AMBIENTLIGHT_H
|
||||
|
||||
#include "light/light.h"
|
||||
|
||||
class AmbientLight : public Light{
|
||||
class AmbientLight : public Light {
|
||||
|
||||
public:
|
||||
explicit AmbientLight(float intensity, Color const &color = Color(1, 1, 1));
|
||||
// Constructor
|
||||
AmbientLight(float intensity, Color color = Color(1, 1, 1)) : Light(intensity, color) {}
|
||||
|
||||
Illumination illuminate(Scene const &scene, Ray const &ray) const override;
|
||||
|
||||
protected:
|
||||
Vector3d direction;
|
||||
// Light functions
|
||||
Illumination illuminate(Scene const &scene, Ray const &ray) const override;
|
||||
};
|
||||
|
||||
|
||||
#endif //CG1_TRACER_AMBIENTLIGHT_H
|
||||
#endif
|
||||
|
|
|
@ -1,45 +1,38 @@
|
|||
#include "light/spotlight.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
SpotLight::SpotLight(Vector3d position, Vector3d direction, float innerAngle, float outerAngle, float intensity,
|
||||
const Color &color) : Light(intensity, color), position(position), direction(direction),
|
||||
innerAngle(innerAngle), outerAngle(outerAngle) {};
|
||||
SpotLight::SpotLight(Vector3d const &position, Vector3d const &direction, float alphaMin, float alphaMax, float intensity, Color const &color)
|
||||
: Light(intensity, color), position(position), direction(normalized(direction)), alphaMin(alphaMin), alphaMax(alphaMax) {}
|
||||
|
||||
Light::Illumination SpotLight::illuminate(Scene const &scene, Ray const &ray) const {
|
||||
// Calculate distance to surface
|
||||
Vector3d const x = ray.origin + (ray.length - SPLT_EPS) * ray.direction;
|
||||
Vector3d const target = ray.origin + (ray.length - LGT_EPS) * ray.direction;
|
||||
|
||||
// Illumination object
|
||||
Illumination illum;
|
||||
illum.direction = normalized(x - this->position);
|
||||
// Illumination object
|
||||
Illumination illum;
|
||||
illum.direction = normalized(target - this->position);
|
||||
|
||||
// Precompute the distance from the light source
|
||||
float const distance = length(x - this->position);
|
||||
// Precompute the distance from the light source
|
||||
float const distance = length(target - this->position);
|
||||
|
||||
// Define a secondary ray from the surface point to the light source.
|
||||
Ray lightRay;
|
||||
lightRay.origin = x;
|
||||
lightRay.direction = -illum.direction;
|
||||
lightRay.length = distance - SPLT_EPS;
|
||||
// Define a secondary ray from the surface point to the light source
|
||||
Ray lightRay;
|
||||
lightRay.origin = target;
|
||||
lightRay.direction = -illum.direction;
|
||||
lightRay.length = distance - LGT_EPS;
|
||||
|
||||
//calculate angle
|
||||
float angle = acos(dotProduct(x - this->position, this->direction) / (length(x - this->position)
|
||||
* length(this->direction)));
|
||||
// Determine the angle of the inner cone
|
||||
float const alpha = std::fabs(std::acos(dotProduct(illum.direction, this->direction)) * 180.0f / float(PI));
|
||||
|
||||
if (!scene.findOcclusion(lightRay)) { // If the target is not in shadow...
|
||||
|
||||
// ... compute the attenuation and light color
|
||||
if (angle > outerAngle * (PI / 180)) {
|
||||
illum.color = Color(0, 0, 0);
|
||||
} else if (angle > innerAngle * (PI / 180)) {
|
||||
float outerIllumRange = (outerAngle - innerAngle) * (PI / 180);
|
||||
float leftOverAngle = angle - innerAngle * (PI / 180);
|
||||
float percentageOfAngle = leftOverAngle / outerIllumRange;
|
||||
float illumValue = 1 - percentageOfAngle;
|
||||
illum.color = (1.0f / (distance * distance) * this->color * this->intensity) * illumValue;
|
||||
} else {
|
||||
illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
|
||||
}
|
||||
// If the target is within the cone...
|
||||
if (this->alphaMax > alpha) {
|
||||
// ... and not in shadow ...
|
||||
if (!scene.findOcclusion(lightRay)) {
|
||||
// ... compute the attenuation and light color ...
|
||||
illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
|
||||
// ... 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);
|
||||
}
|
||||
return illum;
|
||||
}
|
||||
}
|
||||
return illum;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
#ifndef CG1_TRACER_SPOTLIGHT_H
|
||||
#define CG1_TRACER_SPOTLIGHT_H
|
||||
#ifndef SPOTLIGHT_H
|
||||
#define SPOTLIGHT_H
|
||||
|
||||
#include "light/light.h"
|
||||
|
||||
class SpotLight : public Light{
|
||||
class SpotLight : public Light {
|
||||
|
||||
public:
|
||||
SpotLight(Vector3d position, Vector3d direction, float innerAngle, float outerAngle,float intensity, Color const &color = Color(1, 1, 1));
|
||||
// Constructor
|
||||
SpotLight(Vector3d const &position, Vector3d const &direction, float alphaMin, float alphaMax, float intensity,
|
||||
Color const &color = Color(1, 1, 1));
|
||||
|
||||
Illumination illuminate(Scene const &scene, Ray const &ray) const override;
|
||||
// Set
|
||||
void setDirection(Vector3d const &direction) { this->direction = normalized(direction); }
|
||||
void setPosition(Vector3d const &position) { this->position = position; }
|
||||
void setAlphaMax(float alphaMax) { this->alphaMax = alphaMax; }
|
||||
void setAlphaMin(float alphaMin) { this->alphaMin = alphaMin; }
|
||||
|
||||
// Light functions
|
||||
Illumination illuminate(Scene const &scene, Ray const &ray) const override;
|
||||
|
||||
protected:
|
||||
Vector3d direction;
|
||||
Vector3d position;
|
||||
float innerAngle;
|
||||
float outerAngle;
|
||||
Vector3d position, direction;
|
||||
float alphaMin, alphaMax;
|
||||
};
|
||||
|
||||
|
||||
#endif //CG1_TRACER_SPOTLIGHT_H
|
||||
#endif
|
||||
|
|
|
@ -1,60 +1,43 @@
|
|||
#include "objmodel.h"
|
||||
#include "shader/flatshader.h"
|
||||
#include "../scene/scene.h"
|
||||
#include "primitive/objmodel.h"
|
||||
#include "primitive/box.h"
|
||||
#include "primitive/triangle.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
void ObjModel::loadObj(const char* fileName, Vector3d scale, Vector3d translation) {
|
||||
ObjModel::ObjModel(std::shared_ptr<Shader> const &shader) : Primitive(shader), boundingBox(Vector3d(-INFINITY, -INFINITY, -INFINITY), Vector3d(INFINITY, INFINITY, INFINITY), shader) {}
|
||||
|
||||
this->faces = (Scene::loadObj(fileName, scale, translation, this->shader()));
|
||||
void ObjModel::loadObj(char const *fileName, Vector3d const &scale, Vector3d const &translation) {
|
||||
// Load faces
|
||||
this->primitives = Scene::loadObj(fileName, scale, translation, shader());
|
||||
|
||||
Vector3d minBounds;
|
||||
Vector3d maxBounds;
|
||||
// Extent of box
|
||||
Vector3d minVert(INFINITY, INFINITY, INFINITY);
|
||||
Vector3d maxVert(-INFINITY, -INFINITY, -INFINITY);
|
||||
|
||||
auto minCalc = [this](int dimension) {
|
||||
return std::min_element(this->faces.begin(),
|
||||
this->faces.end(),
|
||||
[&dimension](auto &face1, auto &face2) {
|
||||
return face1->minimumBounds(dimension) < face2->minimumBounds(dimension);
|
||||
})->get()->minimumBounds(dimension);
|
||||
};
|
||||
minBounds = {minCalc(0), minCalc(1), minCalc(2)};
|
||||
|
||||
auto maxCalc = [this](int dimension) {
|
||||
return std::max_element(this->faces.begin(),
|
||||
this->faces.end(),
|
||||
[&dimension](auto &face1, auto &face2) {
|
||||
return face1->maximumBounds(dimension) < face2->maximumBounds(dimension);
|
||||
})->get()->maximumBounds(dimension);
|
||||
};
|
||||
maxBounds = {maxCalc(0), maxCalc(1), maxCalc(2)};
|
||||
|
||||
boundingBox.setCenter(minBounds + (maxBounds - minBounds) / 2);
|
||||
boundingBox.setSize(maxBounds - minBounds);
|
||||
// For each face, update the extent
|
||||
for (const auto &primitive : this->primitives) {
|
||||
minVert = Vector3d(std::min(minVert.x, primitive->minimumBounds(0)), std::min(minVert.y, primitive->minimumBounds(1)), std::min(minVert.z, primitive->minimumBounds(2)));
|
||||
maxVert = Vector3d(std::max(maxVert.x, primitive->maximumBounds(0)), std::max(maxVert.y, primitive->maximumBounds(1)), std::max(maxVert.z, primitive->maximumBounds(2)));
|
||||
}
|
||||
|
||||
// Update the bounding box
|
||||
boundingBox.setCenter(0.5f * (maxVert + minVert));
|
||||
boundingBox.setSize(maxVert - minVert + Vector3d(SPLT_EPS, SPLT_EPS, SPLT_EPS));
|
||||
}
|
||||
|
||||
bool ObjModel::intersect(Ray &ray) const {
|
||||
auto testRay = Ray(ray.origin, ray.direction);
|
||||
if (!boundingBox.intersect(testRay)) {
|
||||
return false;
|
||||
// Ray box intersection
|
||||
Ray boxRay = ray;
|
||||
if (boundingBox.intersect(boxRay)) {
|
||||
// ray primitive intersection
|
||||
bool hit = false;
|
||||
for (const auto &p : this->primitives) {
|
||||
hit |= p->intersect(ray);
|
||||
}
|
||||
return std::count_if(this->faces.begin(),
|
||||
this->faces.end(),
|
||||
[&ray](auto &face) {
|
||||
return face->intersect(ray);
|
||||
}) > 0;
|
||||
}
|
||||
|
||||
float ObjModel::minimumBounds(int dimension) const {
|
||||
return this->boundingBox.minimumBounds(dimension);
|
||||
}
|
||||
|
||||
float ObjModel::maximumBounds(int dimension) const {
|
||||
return this->boundingBox.maximumBounds(dimension);
|
||||
}
|
||||
|
||||
ObjModel::ObjModel(const std::shared_ptr<Shader> &shader) :
|
||||
Primitive(shader),
|
||||
boundingBox(Box(std::make_shared<FlatShader>(Color(0, 0, 0)))) {
|
||||
return hit;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float ObjModel::minimumBounds(int dimension) const { return this->boundingBox.minimumBounds(dimension); }
|
||||
|
||||
float ObjModel::maximumBounds(int dimension) const { return this->boundingBox.maximumBounds(dimension); }
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
#ifndef CG1_TRACER_OBJMODEL_H
|
||||
#define CG1_TRACER_OBJMODEL_H
|
||||
#ifndef OBJMODEL_H
|
||||
#define OBJMODEL_H
|
||||
|
||||
#include "primitive.h"
|
||||
#include "box.h"
|
||||
#include "primitive/box.h"
|
||||
#include <vector>
|
||||
|
||||
class ObjModel : public Primitive {
|
||||
public:
|
||||
explicit ObjModel(const std::shared_ptr<Shader> &shader);
|
||||
void loadObj(const char* fileName, Vector3d scale, Vector3d translation);
|
||||
// Constructor
|
||||
ObjModel(std::shared_ptr<Shader> const &shader);
|
||||
~ObjModel() override{};
|
||||
|
||||
bool intersect(Ray &ray) const override;
|
||||
// Load object data
|
||||
void loadObj(char const *fileName, Vector3d const &scale = Vector3d(1, 1, 1),
|
||||
Vector3d const &translation = Vector3d(0, 0, 0));
|
||||
|
||||
[[nodiscard]] float minimumBounds(int dimension) const override;
|
||||
[[nodiscard]] float maximumBounds(int dimension) const override;
|
||||
// Primitive functions
|
||||
bool intersect(Ray &ray) const override;
|
||||
|
||||
// Bounding box
|
||||
float minimumBounds(int dimension) const override;
|
||||
float maximumBounds(int dimension) const override;
|
||||
|
||||
protected:
|
||||
std::vector<std::shared_ptr<Primitive>> faces;
|
||||
Box boundingBox;
|
||||
|
||||
|
||||
Box boundingBox;
|
||||
std::vector<std::shared_ptr<Primitive>> primitives;
|
||||
};
|
||||
|
||||
#endif //CG1_TRACER_OBJMODEL_H
|
||||
#endif
|
||||
|
|
|
@ -111,14 +111,9 @@ bool Triangle::intersect(Ray &ray) const {
|
|||
if (t < EPSILON || ray.length < t)
|
||||
return false;
|
||||
|
||||
// Calculate the normal
|
||||
if (this->normal[0] == Vector3d(0, 0, 0)
|
||||
|| this->normal[1] == Vector3d(0, 0, 0)
|
||||
|| this->normal[2] == Vector3d(0, 0, 0)) {
|
||||
ray.normal = normalized(crossProduct(edge1, edge2));
|
||||
} else {
|
||||
ray.normal = normalized(u * normalized(this->normal[1]) + v * normalized(this->normal[2]) + (1 - u - v) * normalized(this->normal[0]));
|
||||
}
|
||||
// Calculate the normal
|
||||
// IMPLEMENT smooth triangles, if available
|
||||
ray.normal = normalized(crossProduct(edge1, edge2));
|
||||
|
||||
// Calculate the surface position
|
||||
ray.surface = u * this->surface[1] + v * this->surface[2] + (1 - u - v) * this->surface[0];
|
||||
|
|
204
scene/scene.cpp
204
scene/scene.cpp
|
@ -42,49 +42,167 @@ std::vector<std::shared_ptr<Primitive>> Scene::loadObj(char const *fileName, Vec
|
|||
std::vector<std::shared_ptr<Primitive>> faces;
|
||||
std::vector<std::array<int, 3>> indices;
|
||||
|
||||
std::vector<Vector3d> vertices;
|
||||
std::vector<Vector3d> vertex_normals;
|
||||
std::ifstream file;
|
||||
file.open(fileName);
|
||||
if (file.is_open()) {
|
||||
while (!file.eof()) {
|
||||
std::string key;
|
||||
file >> key;
|
||||
if (key == "v") {
|
||||
float x, y, z;
|
||||
file >> x >> y >> z;
|
||||
vertices.emplace_back(x, y, z);
|
||||
} else if (key == "vn") {
|
||||
float x, y, z;
|
||||
file >> x >> y >> z;
|
||||
vertex_normals.emplace_back(x, y, z);
|
||||
} else if (key == "f") {
|
||||
int x, y, z,
|
||||
xn, yn, zn = 0;
|
||||
{
|
||||
std::string token;
|
||||
std::getline(file, token, '/');
|
||||
std::stringstream tokens(token);
|
||||
tokens >> x;
|
||||
}
|
||||
file.ignore(1);
|
||||
file >> xn;
|
||||
{
|
||||
std::string token;
|
||||
std::getline(file, token, '/');
|
||||
std::stringstream tokens(token);
|
||||
tokens >> y;
|
||||
}
|
||||
file.ignore(1);
|
||||
file >> yn;
|
||||
{
|
||||
std::string token;
|
||||
std::getline(file, token, '/');
|
||||
std::stringstream tokens(token);
|
||||
tokens >> z;
|
||||
}
|
||||
file.ignore(1);
|
||||
file >> zn;
|
||||
// Open file from disk
|
||||
std::ifstream file;
|
||||
file.open(fileName);
|
||||
if (!file.is_open()) {
|
||||
std::cout << "(Scene): Could not open .obj file: " << fileName << std::endl;
|
||||
return std::vector<std::shared_ptr<Primitive>>();
|
||||
}
|
||||
|
||||
// Print the file name
|
||||
std::cout << "(Scene): Loading \"" << fileName << "\"" << std::endl;
|
||||
|
||||
// Actual model data
|
||||
std::vector<Vector3d> vData;
|
||||
std::vector<Vector3d> tangentData;
|
||||
std::vector<Vector3d> bitangentData;
|
||||
std::vector<Vector3d> normalData;
|
||||
std::vector<Vector3d> vnData;
|
||||
std::vector<Vector2d> vtData;
|
||||
|
||||
// Read vertices, normals, textures, and faces from the file
|
||||
std::string line;
|
||||
while (getline(file, line)) {
|
||||
std::stringstream lineStream(trim(line));
|
||||
std::string type;
|
||||
lineStream >> type;
|
||||
|
||||
// Vertices
|
||||
if (type == "v") {
|
||||
float x, y, z;
|
||||
lineStream >> x >> y >> z;
|
||||
vData.emplace_back(componentProduct(Vector3d(x, y, z), scale) + translation);
|
||||
tangentData.emplace_back();
|
||||
bitangentData.emplace_back();
|
||||
normalData.emplace_back();
|
||||
}
|
||||
|
||||
// Texture coordinates
|
||||
if (type == "vt") {
|
||||
float u, v;
|
||||
lineStream >> u >> v;
|
||||
vtData.emplace_back(flipU ? 1.0f - u : u, flipV ? 1.0f - v : v);
|
||||
}
|
||||
|
||||
// Normals
|
||||
if (type == "vn") {
|
||||
float a, b, c;
|
||||
lineStream >> a >> b >> c;
|
||||
vnData.emplace_back(normalized(componentQuotient(
|
||||
Vector3d(a, b, c),
|
||||
scale))); // Division needed for preventing stretched normals, normals' = (transform^-1)^T * normals
|
||||
}
|
||||
|
||||
// Faces
|
||||
if (type == "f") {
|
||||
std::string vertex[3];
|
||||
std::array<int, 3> vertInd = {-1, -1, -1};
|
||||
std::array<int, 3> texInd = {-1, -1, -1};
|
||||
std::array<int, 3> normInd = {-1, -1, -1};
|
||||
lineStream >> vertex[0] >> vertex[1] >> vertex[2];
|
||||
|
||||
// triangulate polygons, like quads (which must be given in triangle fan notation)
|
||||
while (!vertex[2].empty()) {
|
||||
auto triangle = std::make_shared<Triangle>(shader);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
std::stringstream vertexSteam(vertex[i]);
|
||||
std::string reference;
|
||||
|
||||
// vertex index
|
||||
getline(vertexSteam, reference, '/');
|
||||
try {
|
||||
vertInd[i] = stoi(reference) - 1;
|
||||
triangle->setVertex(i, vData.at(vertInd[i]));
|
||||
} catch (...) {
|
||||
std::cout << "Error: vertex index invalid on line \"" << line << "\"" << std::endl;
|
||||
}
|
||||
|
||||
// texture index
|
||||
if (getline(vertexSteam, reference, '/')) {
|
||||
if (!reference.empty()) {
|
||||
try {
|
||||
texInd[i] = stoi(reference) - 1;
|
||||
triangle->setSurface(i, vtData.at(texInd[i]));
|
||||
} catch (...) {
|
||||
std::cout << "Error: texture coordinate index invalid on line \"" << line << "\"" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// normal index
|
||||
if (getline(vertexSteam, reference, '/')) {
|
||||
try {
|
||||
normInd[i] = stoi(reference) - 1;
|
||||
triangle->setNormal(i, vnData.at(normInd[i]));
|
||||
} catch (...) {
|
||||
std::cout << "Error: normal index invalid on line \"" << line << "\"" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate and accumulate tangent and bitangent vectors
|
||||
if (std::all_of(vertInd.begin(), vertInd.end(), [](int i) { return i > -1; }) &&
|
||||
std::all_of(texInd.begin(), texInd.end(), [](int i) { return i > -1; })) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const Vector3d deltaPos1 = vData.at(vertInd[(i + 1) % 3]) - vData.at(vertInd[i]);
|
||||
const Vector3d deltaPos2 = vData.at(vertInd[(i + 2) % 3]) - vData.at(vertInd[i]);
|
||||
|
||||
const Vector2d deltaUV1 = vtData.at(texInd[(i + 1) % 3]) - vtData.at(texInd[i]);
|
||||
const Vector2d deltaUV2 = vtData.at(texInd[(i + 2) % 3]) - vtData.at(texInd[i]);
|
||||
|
||||
const float r = 1.0f / (deltaUV1.u * deltaUV2.v - deltaUV1.v * deltaUV2.u);
|
||||
tangentData[vertInd[i]] += (deltaPos1 * deltaUV2.v - deltaPos2 * deltaUV1.v) * r;
|
||||
bitangentData[vertInd[i]] += (deltaPos2 * deltaUV1.u - deltaPos1 * deltaUV2.u) * r;
|
||||
|
||||
normalData[vertInd[i]] += crossProduct(tangentData[vertInd[i]], bitangentData[vertInd[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
faces.push_back(triangle);
|
||||
indices.push_back(vertInd);
|
||||
|
||||
// get the next triangle
|
||||
if (lineStream.eof())
|
||||
break;
|
||||
|
||||
vertex[1] = vertex[2];
|
||||
lineStream >> vertex[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close the file
|
||||
file.close();
|
||||
|
||||
// set the normalized tangents and bitangents
|
||||
for (int i = 0; i < faces.size(); i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Vector3d tangent = normalized(tangentData[indices[i][j]]);
|
||||
const Vector3d bitangent = normalized(bitangentData[indices[i][j]]);
|
||||
// try to use the normal from the obj file, if it doesn't exist, use the computed normal
|
||||
Vector3d normal = normalized(normalData[indices[i][j]]);
|
||||
if (vnData.size() > 0)
|
||||
normal = dynamic_cast<Triangle *>(faces[i].get())->getNormal(j);
|
||||
|
||||
// gram-schmidt orthogonalization
|
||||
tangent = normalized(tangent - normal * dotProduct(normal, tangent));
|
||||
// check handedness of coordinate system
|
||||
if (dotProduct(crossProduct(normal, tangent), bitangent) < 0.0f)
|
||||
tangent *= -1.0f;
|
||||
|
||||
dynamic_cast<Triangle *>(faces[i].get())->setTangent(j, tangent);
|
||||
dynamic_cast<Triangle *>(faces[i].get())->setBitangent(j, bitangent);
|
||||
dynamic_cast<Triangle *>(faces[i].get())->setNormal(j, normal);
|
||||
}
|
||||
}
|
||||
|
||||
// Debug output
|
||||
std::cout << " -> " << vData.size() << " vertices parsed" << std::endl;
|
||||
std::cout << " -> " << vnData.size() << " normals parsed" << std::endl;
|
||||
std::cout << " -> " << vtData.size() << " uv-positions parsed" << std::endl;
|
||||
std::cout << " -> " << faces.size() << " primitives parsed" << std::endl;
|
||||
|
||||
faces.push_back(std::make_shared<Triangle>(vertices[x - 1] * scale + translation,
|
||||
vertices[y - 1] * scale + translation,
|
||||
|
|
13
shader/brdfshader.cpp
Normal file
13
shader/brdfshader.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "light/light.h"
|
||||
#include "scene/scene.h"
|
||||
#include "shader/brdfshader.h"
|
||||
|
||||
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;
|
||||
|
||||
// IMPLEMENT ME
|
||||
return illuminationColor;
|
||||
}
|
23
shader/brdfshader.h
Normal file
23
shader/brdfshader.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef BRDFSHADER_H
|
||||
#define BRDFSHADER_H
|
||||
|
||||
#include "common/brdfread.h"
|
||||
#include "shader/shader.h"
|
||||
#include <memory>
|
||||
|
||||
class BrdfShader : public Shader {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
BrdfShader(char const *fileName, Color const &scale);
|
||||
~BrdfShader() override = default;
|
||||
|
||||
// Shader functions
|
||||
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||
|
||||
private:
|
||||
Color scale;
|
||||
std::unique_ptr<BRDFRead> brdf;
|
||||
};
|
||||
|
||||
#endif
|
13
shader/cooktorranceshader.cpp
Normal file
13
shader/cooktorranceshader.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "light/light.h"
|
||||
#include "scene/scene.h"
|
||||
#include "shader/cooktorranceshader.h"
|
||||
|
||||
CookTorranceShader::CookTorranceShader(Color const &diffCol, Color const &ctCol, float IOR, float roughness, float diffCoeff, float ctCoeff) : diffuseColor(diffCol * diffCoeff), ctColor(ctCol * ctCoeff), F0(IOR), m(roughness) {}
|
||||
|
||||
Color CookTorranceShader::shade(Scene const &scene, Ray const &ray) const {
|
||||
Color fragmentColor;
|
||||
|
||||
// IMPLEMENT ME
|
||||
|
||||
return fragmentColor;
|
||||
}
|
26
shader/cooktorranceshader.h
Normal file
26
shader/cooktorranceshader.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef COOKTORRANCESHADER_H
|
||||
#define COOKTORRANCESHADER_H
|
||||
|
||||
#include "shader/shader.h"
|
||||
|
||||
class CookTorranceShader : public Shader {
|
||||
public:
|
||||
CookTorranceShader(Color const &diffuseColor, Color const &ctColor, float IOR, float roughness,
|
||||
float diffuseCoefficient = PI / 2.0f, float ctCoefficient = PI / 2.0f);
|
||||
// Shader functions
|
||||
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||
|
||||
private:
|
||||
float D(float NdotH) const;
|
||||
float F(float VdotH) const;
|
||||
float G(float NdotH, float NdotV, float VdotH, float NdotL) const;
|
||||
|
||||
Color diffuseColor;
|
||||
|
||||
Color ctColor;
|
||||
|
||||
float F0;
|
||||
float m;
|
||||
};
|
||||
|
||||
#endif
|
13
shader/lambertshader.cpp
Normal file
13
shader/lambertshader.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "light/light.h"
|
||||
#include "scene/scene.h"
|
||||
#include "shader/lambertshader.h"
|
||||
|
||||
LambertShader::LambertShader(Color const &diffuseColor) : diffuseColor(diffuseColor) {}
|
||||
|
||||
Color LambertShader::shade(Scene const &scene, Ray const &ray) const {
|
||||
Color fragmentColor;
|
||||
|
||||
// IMPLEMENT ME
|
||||
|
||||
return fragmentColor;
|
||||
}
|
19
shader/lambertshader.h
Normal file
19
shader/lambertshader.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef LAMBERTSHADER_H
|
||||
#define LAMBERTSHADER_H
|
||||
|
||||
#include "shader/shader.h"
|
||||
|
||||
class LambertShader : public Shader {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
LambertShader(Color const &diffuseColor = Color(1, 1, 1));
|
||||
|
||||
// Shader functions
|
||||
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||
|
||||
protected:
|
||||
Color diffuseColor;
|
||||
};
|
||||
|
||||
#endif
|
16
shader/phongshader.cpp
Normal file
16
shader/phongshader.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "light/light.h"
|
||||
#include "scene/scene.h"
|
||||
#include "shader/phongshader.h"
|
||||
|
||||
PhongShader::PhongShader(Color const &diffuseColor, float diffuseCoefficient, Color const &specularColor,
|
||||
float specularCoefficient, float shininessExponent)
|
||||
: diffuseColor(diffuseColor), diffuseCoefficient(diffuseCoefficient), specularColor(specularColor),
|
||||
specularCoefficient(specularCoefficient), shininessExponent(shininessExponent) {}
|
||||
|
||||
Color PhongShader::shade(Scene const &scene, Ray const &ray) const {
|
||||
Color fragmentColor;
|
||||
|
||||
// IMPLEMENT ME
|
||||
|
||||
return fragmentColor;
|
||||
}
|
25
shader/phongshader.h
Normal file
25
shader/phongshader.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef PHONGSHADER_H
|
||||
#define PHONGSHADER_H
|
||||
|
||||
#include "shader/shader.h"
|
||||
|
||||
class PhongShader : public Shader {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
PhongShader(Color const &diffuseColor, float diffuseCoefficient, Color const &specularColor,
|
||||
float specularCoefficient, float shininessExponent);
|
||||
|
||||
// Shader functions
|
||||
Color shade(Scene const &scene, Ray const &ray) const override;
|
||||
|
||||
private:
|
||||
Color diffuseColor;
|
||||
float diffuseCoefficient;
|
||||
|
||||
Color specularColor;
|
||||
float specularCoefficient;
|
||||
float shininessExponent;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue