diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a62839..48a0af5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) + diff --git a/common/brdfread.cpp b/common/brdfread.cpp new file mode 100644 index 0000000..3032998 --- /dev/null +++ b/common/brdfread.cpp @@ -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 +// . + +// 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(brdfData[ind] * RED_SCALE); + color.g = static_cast( + brdfData[ind + BRDF_SAMPLING_RES_THETA_H * BRDF_SAMPLING_RES_THETA_D * BRDF_SAMPLING_RES_PHI_D / 2] * + GREEN_SCALE); + color.b = static_cast( + brdfData[ind + BRDF_SAMPLING_RES_THETA_H * BRDF_SAMPLING_RES_THETA_D * BRDF_SAMPLING_RES_PHI_D] * BLUE_SCALE); + + // std::cerr << red_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; +} diff --git a/common/brdfread.h b/common/brdfread.h new file mode 100644 index 0000000..eb990a2 --- /dev/null +++ b/common/brdfread.h @@ -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 +// . + +// 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 +#include +#include +#include + +#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 diff --git a/ex4.cpp b/ex4.cpp new file mode 100644 index 0000000..cadf20c --- /dev/null +++ b/ex4.cpp @@ -0,0 +1,74 @@ +#include +#include + +#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(); + auto white = std::make_shared(Color(0.9f, 0.9f, 0.9f)); + auto red = std::make_shared(Color(1.0f, 0.3f, 0.2f)); + auto blue = std::make_shared(Color(0.2f, 0.3f, 1.0f)); + auto orange = std::make_shared(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(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f); + auto blueMetallic = std::make_shared("data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f)); + auto darkRed = std::make_shared("data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f)); + + // Set up the walls + // --------------------------------------------------------------------------- + scene.add(std::make_shared(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), mirror)); + + scene.add(std::make_shared(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror)); + scene.add(std::make_shared(Vector3d(0.0f, +5.0f, 0.0f), Vector3d(0.0f, -1.0f, 0.0f), white)); + scene.add(std::make_shared(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, +1.0f, 0.0f), white)); + scene.add(std::make_shared(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), blue)); + scene.add(std::make_shared(Vector3d(-5.0f, 0.0f, 0.0f), Vector3d(+1.0f, 0.0f, 0.0f), red)); + + scene.add(std::make_shared(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, blueMetallic)); + scene.add(std::make_shared(Vector3d(0.0f, 2.0f, 0.0f), 1.0f, orange)); + scene.add(std::make_shared(Vector3d(3.0f, 0.0f, 0.0f), 1.0f, darkRed)); + + // Add the teapot + auto teapot = std::make_shared(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(0.15f)); + scene.add(std::make_shared(Vector3d(0.0f, 4.0f, -4.0f), 15.0f)); + scene.add(std::make_shared(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; +} diff --git a/primitive/triangle.cpp b/primitive/triangle.cpp index b98c539..34da50a 100644 --- a/primitive/triangle.cpp +++ b/primitive/triangle.cpp @@ -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 diff --git a/shader/brdfshader.cpp b/shader/brdfshader.cpp new file mode 100644 index 0000000..ab77d37 --- /dev/null +++ b/shader/brdfshader.cpp @@ -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(fileName)) {} + +Color BrdfShader::shade(Scene const &scene, Ray const &ray) const { + Color illuminationColor; + + // IMPLEMENT ME + return illuminationColor; +} diff --git a/shader/brdfshader.h b/shader/brdfshader.h new file mode 100644 index 0000000..250eb9f --- /dev/null +++ b/shader/brdfshader.h @@ -0,0 +1,23 @@ +#ifndef BRDFSHADER_H +#define BRDFSHADER_H + +#include "common/brdfread.h" +#include "shader/shader.h" +#include + +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 brdf; +}; + +#endif diff --git a/shader/cooktorranceshader.cpp b/shader/cooktorranceshader.cpp new file mode 100644 index 0000000..3f9cff5 --- /dev/null +++ b/shader/cooktorranceshader.cpp @@ -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; +} \ No newline at end of file diff --git a/shader/cooktorranceshader.h b/shader/cooktorranceshader.h new file mode 100644 index 0000000..7c2844d --- /dev/null +++ b/shader/cooktorranceshader.h @@ -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 \ No newline at end of file diff --git a/shader/lambertshader.cpp b/shader/lambertshader.cpp new file mode 100644 index 0000000..3aebacd --- /dev/null +++ b/shader/lambertshader.cpp @@ -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; +} diff --git a/shader/lambertshader.h b/shader/lambertshader.h new file mode 100644 index 0000000..f5feb43 --- /dev/null +++ b/shader/lambertshader.h @@ -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 diff --git a/shader/phongshader.cpp b/shader/phongshader.cpp new file mode 100644 index 0000000..da6d3e2 --- /dev/null +++ b/shader/phongshader.cpp @@ -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; +} diff --git a/shader/phongshader.h b/shader/phongshader.h new file mode 100644 index 0000000..81e4b5e --- /dev/null +++ b/shader/phongshader.h @@ -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