added ex04 task

This commit is contained in:
jp 2022-11-25 14:58:29 +01:00
parent a1f7c25ecd
commit 668e73ba36
13 changed files with 528 additions and 0 deletions

View file

@ -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
View 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
View 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
View 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;
}

View file

@ -100,6 +100,7 @@ bool Triangle::intersect(Ray &ray) const {
return false;
// Calculate the normal
// IMPLEMENT smooth triangles, if available
ray.normal = normalized(crossProduct(edge1, edge2));
// Calculate the surface position

13
shader/brdfshader.cpp Normal file
View 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
View 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

View 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;
}

View 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
View 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
View 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
View 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
View 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