From a8137256e983a49f97ff1fbecd26a1a0372f7b0b Mon Sep 17 00:00:00 2001 From: Roland Hieber Date: Sat, 30 Jan 2010 19:58:01 +0100 Subject: [PATCH] code for assignment 4, gitignored *.ppm, *.png --- .gitignore | 2 + Box.cxx | 57 +++++++++++++ Box.hxx | 33 ++++++++ Image.cxx | 18 ++-- InfinitePlane.cxx | 12 +++ InfinitePlane.hxx | 2 + Light.hxx | 1 + Makefile | 9 +- MicroTrace.cxx | 136 +++++------------------------- PerspectiveCamera.cxx | 6 +- PhongShader.cxx | 88 ++++++++++++++------ PhongShader.hxx | 5 +- PointLight.cxx | 38 +++++---- PointLight.hxx | 2 + Primitive.hxx | 3 + QuadAreaLight.cxx | 74 +++++++++++++++++ QuadAreaLight.hxx | 30 +++++++ ReflectiveEyeLightShader.cxx | 9 +- Scene.cxx | 157 ++++++++++++++++++++++++++++++++--- Scene.hxx | 42 ++++++++-- Sphere.cxx | 12 +++ Sphere.hxx | 2 + SpotLight.cxx | 55 ++++++++++-- SpotLight.hxx | 3 +- Triangle.cxx | 12 +++ Triangle.hxx | 2 + Vec3f.hxx | 2 +- cone.obj | 99 ++++++++++++++++++++++ kDTree.cxx | 139 +++++++++++++++++++++++++++++++ kDTree.hxx | 85 +++++++++++++++++++ 30 files changed, 931 insertions(+), 204 deletions(-) create mode 100644 Box.cxx create mode 100644 Box.hxx create mode 100644 QuadAreaLight.cxx create mode 100644 QuadAreaLight.hxx create mode 100644 cone.obj create mode 100644 kDTree.cxx create mode 100644 kDTree.hxx diff --git a/.gitignore b/.gitignore index 3c86eb8..e1fe704 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.o MicroTrace +*.png +*.ppm diff --git a/Box.cxx b/Box.cxx new file mode 100644 index 0000000..ef9f750 --- /dev/null +++ b/Box.cxx @@ -0,0 +1,57 @@ +#include "Box.hxx" + +Box::Box() +{ +} + +Box::~Box() +{ +} + +Box::Box(const Box& b) +{ +} + +Box& +Box::operator=(const Box& b) +{ + return *this; +} + +void +Box::Clear() +{ +} + +void +Box::Extend(const Vec3f& a) +{ +} + +void +Box::Extend(const Box& box) +{ +} + +bool +Box::Overlaps(const Box& b) const +{ + return false; +} + +void +Box::Clip(const Ray& ray, float& tnear, float& tfar) const +{ +} + +const Vec3f& +Box::min() const +{ + return m_min; +} + +const Vec3f& +Box::max() const +{ + return m_max; +} diff --git a/Box.hxx b/Box.hxx new file mode 100644 index 0000000..1417e80 --- /dev/null +++ b/Box.hxx @@ -0,0 +1,33 @@ +#ifndef BOX_HXX +#define BOX_HXX + +#include "Ray.hxx" + +class Box +{ +public: + Box(); + ~Box(); + + Box(const Box& b); + Box& operator=(const Box& b); + + //! Extend the bounding box to contain point a + void Extend(const Vec3f& a); + //! Clear the bounding box, i.e. set dimensions to infinity. + void Clear(); + //! Extend the box to contain the given box. + void Extend(const Box& box); + //! Test for overlap with the given box b. + bool Overlaps(const Box& b) const; + //! Clip the given ray against the box. tnear and tfar should be filled by this function! + void Clip(const Ray& ray, float& tnear,float& tfar) const; + + //! Query the dimension of the bounding box. + const Vec3f& min() const; + const Vec3f& max() const; +private: + Vec3f m_min, m_max; +}; + +#endif diff --git a/Image.cxx b/Image.cxx index bc8134b..b45cac9 100644 --- a/Image.cxx +++ b/Image.cxx @@ -39,34 +39,28 @@ Image::operator()(int x, int y) { assert(x >= 0 && x < m_resX); assert(y >= 0 && y < m_resY); - - return m_pixel[y*m_resX+x]; + + return m_pixel[y*m_resX+x]; } void Image::WritePPM(const std::string& fileName) { std::cerr << "(Image): Writing to file " << fileName << std::endl; std::ofstream file(fileName.c_str()); - + if(!file.is_open()) { std::cerr << "(Image): Could not open file " << fileName << std::endl; return; } - + file << "P3" << std::endl; file << m_resX << " " << m_resY << " " << 255 << std::endl; - for (int y=m_resY-1;y>=0;y--) + for (int y=m_resY-1;y>=0;y--) { for (int x=0;x 255) (*this)(x,y)[0] = 255; - if ((*this)(x,y)[1] > 255) (*this)(x,y)[1] = 255; - if ((*this)(x,y)[2] > 255) (*this)(x,y)[2] = 255; - file + file << (int)(255.99999999 * (*this)(x,y)[0]) << " " << (int)(255.99999999 * (*this)(x,y)[1]) << " " << (int)(255.99999999 * (*this)(x,y)[2]) << " " diff --git a/InfinitePlane.cxx b/InfinitePlane.cxx index f73d835..c11fb8a 100644 --- a/InfinitePlane.cxx +++ b/InfinitePlane.cxx @@ -31,3 +31,15 @@ InfinitePlane::GetNormal(Ray& ray) { return m_n; } + +Box +InfinitePlane::CalcBounds() +{ + return Box(); +} + +bool +InfinitePlane::InVoxel(const Box& box) +{ + return false; +} diff --git a/InfinitePlane.hxx b/InfinitePlane.hxx index 06a5aa0..b855851 100644 --- a/InfinitePlane.hxx +++ b/InfinitePlane.hxx @@ -11,6 +11,8 @@ public: virtual bool Intersect(Ray& ray); virtual Vec3f GetNormal(Ray& ray); + virtual Box CalcBounds(); + virtual bool InVoxel(const Box& box); private: Vec3f m_a, m_n; }; diff --git a/Light.hxx b/Light.hxx index a152693..8392b1d 100644 --- a/Light.hxx +++ b/Light.hxx @@ -14,6 +14,7 @@ public: virtual ~Light(); virtual bool Illuminate(Ray& shadowray, Vec3f& intensity) = 0; + virtual bool IsArea() = 0; protected: Scene* m_scene; diff --git a/Makefile b/Makefile index f263909..ac86170 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ all: MicroTrace CC = g++ -CFLAGS = -O3 -Wall +CFLAGS = -O3 -Wall -fopenmp OBJ = MicroTrace.o\ @@ -24,7 +24,10 @@ OBJ = MicroTrace.o\ PointLight.o\ SpotLight.o\ Scene.o\ - Primitive.o + Primitive.o\ + QuadAreaLight.o\ + Box.o\ + kDTree.o %.o: %.cxx *.hxx $(CC) $(CFLAGS) -c $< -o $@ @@ -35,6 +38,6 @@ OBJ = MicroTrace.o\ MicroTrace: $(OBJ) - + g++ -fopenmp $(OBJ) -o MicroTrace clean: rm *~ *.o *.a MicroTrace diff --git a/MicroTrace.cxx b/MicroTrace.cxx index e0fd688..6bb474c 100644 --- a/MicroTrace.cxx +++ b/MicroTrace.cxx @@ -1,156 +1,58 @@ +#ifdef _OPENMP +#include +#endif + #include #include "Vec3f.hxx" -#include "Sphere.hxx" -#include "Triangle.hxx" -#include "InfinitePlane.hxx" - #include "Image.hxx" #include "PerspectiveCamera.hxx" -#include "FlatShader.hxx" -#include "EyeLightShader.hxx" -#include "ReflectiveEyeLightShader.hxx" -#include "PhongShader.hxx" -#include "PointLight.hxx" -#include "SpotLight.hxx" #include "Scene.hxx" -void RenderFramePhongPointLight(const std::string& fileName) +void RenderFrameCone(const std::string& fileName) { /* Scene definition */ Scene scene; - /* Flat shaders */ - PhongShader shd1(&scene, Vec3f(1,0,0),Vec3f(1,0,0),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // red surface - PhongShader shd2(&scene, Vec3f(0,1,0),Vec3f(0,1,0),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // green surface - PhongShader shd3(&scene, Vec3f(0,0,1),Vec3f(0,0,1),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // blue surface - PhongShader shd4(&scene, Vec3f(1,1,0),Vec3f(1,1,0),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // yellow surface - PhongShader shd5(&scene, Vec3f(0,1,1),Vec3f(0,1,1),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // cyan surface - PhongShader shd6(&scene, Vec3f(1,1,1),Vec3f(1,1,1),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // white surface - - /* scene objects */ - Sphere s1(Vec3f(-2,1.7,0), 2, &shd1); - Sphere s2(Vec3f(1,-1,1), 2.2, &shd2); - Sphere s3(Vec3f(3,0.8,-2), 2, &shd3); - InfinitePlane p1(Vec3f(0,-1,0),Vec3f(0,1,0), &shd4); - - - Triangle t1(Vec3f(-2,3,1),Vec3f(1,2,1),Vec3f(3,2.8,3), &shd5); - - /* add to scene */ - scene.Add(&s1); - scene.Add(&s2); - scene.Add(&s3); - scene.Add(&p1); - scene.Add(&t1); + scene.ParseOBJ("cone.obj", 1.0f); + + // alter the camera definition appropriately to see the cow + // you may need to implement some set/get routines for the scene class + scene.setCamera(new PerspectiveCamera(Vec3f(0,0,0.5), + Vec3f(0,0,-1), + Vec3f(0,1,0), + 60, + 640, + 480)); - /* light sources */ - Vec3f lightPosition1(4,5,6); - Vec3f lightPosition2(-3,5,4); - Vec3f pointLightSourceIntensity(50,50,50); - PointLight pointLight1(&scene, lightPosition1, pointLightSourceIntensity); - PointLight pointLight2(&scene, lightPosition2, pointLightSourceIntensity); - - scene.Add(&pointLight1); - scene.Add(&pointLight2); - - Image img(scene.camera()->resX(),scene.camera()->resY()); // image array - Ray ray; // primary ray - + // primary ray +#pragma omp parallel for for(int y = 0; y < scene.camera()->resY(); y++) { for (int x = 0; x < scene.camera()->resX(); x++) { /* Initialize your ray here */ - + Ray ray; scene.camera()->InitRay(x+0.5,y+0.5,ray); // initialize ray Vec3f col = scene.RayTrace(ray); img(x,y) = col; // store pixel color - //std::cerr << "Main: Image color = " << img(x,y) << std::endl; } } img.WritePPM(fileName); // write final image } -void RenderFramePhongSpotLight(const std::string& fileName) -{ - /* Scene definition */ - Scene scene; - - /* Flat shaders */ - PhongShader shd1(&scene, Vec3f(1,0,0),Vec3f(1,0,0),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // red surface - PhongShader shd2(&scene, Vec3f(0,1,0),Vec3f(0,1,0),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // green surface - PhongShader shd3(&scene, Vec3f(0,0,1),Vec3f(0,0,1),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // blue surface - PhongShader shd4(&scene, Vec3f(1,1,0),Vec3f(1,1,0),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // yellow surface - PhongShader shd5(&scene, Vec3f(0,1,1),Vec3f(0,1,1),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // cyan surface - PhongShader shd6(&scene, Vec3f(1,1,1),Vec3f(1,1,1),Vec3f(1,1,1), 0.1, 0.5, 0.5, 40); // white surface - - /* scene objects */ - Sphere s1(Vec3f(-2,1.7,0), 2, &shd1); - Sphere s2(Vec3f(1,-1,1), 2.2, &shd2); - Sphere s3(Vec3f(3,0.8,-2), 2, &shd3); - InfinitePlane p1(Vec3f(0,-1,0),Vec3f(0,1,0), &shd4); - - - Triangle t1(Vec3f(-2,3,1),Vec3f(1,2,1),Vec3f(3,2.8,3), &shd5); - - /* add to scene */ - scene.Add(&s1); - scene.Add(&s2); - scene.Add(&s3); - scene.Add(&p1); - scene.Add(&t1); - - /* light sources */ - Vec3f lightPosition1(4,5,6); - Vec3f lightPosition2(-3,5,4); - Vec3f spotLightSourceIntensity(50,50,50); - Vec3f lightDir1 = lightPosition1 * (-1.0f); - lightDir1.normalize(); - Vec3f lightDir2 = lightPosition2 *(-1.0f); - lightDir2.normalize(); - float alpha_min = 15.0f; - float alpha_max = 30.0f; - - SpotLight spotLight1(&scene, lightPosition1, lightDir1, spotLightSourceIntensity, alpha_min, alpha_max); - SpotLight spotLight2(&scene, lightPosition2, lightDir2, spotLightSourceIntensity, alpha_min, alpha_max); - - scene.Add(&spotLight1); - scene.Add(&spotLight2); - - Image img(scene.camera()->resX(),scene.camera()->resY()); // image array - Ray ray; // primary ray - - for(int y = 0; y < scene.camera()->resY(); y++) - { - for (int x = 0; x < scene.camera()->resX(); x++) - { - - /* Initialize your ray here */ - - scene.camera()->InitRay(x+0.5,y+0.5,ray); // initialize ray - - Vec3f col = scene.RayTrace(ray); - - img(x,y) = col; // store pixel color - //std::cerr << "Main: Image color = " << img(x,y) << std::endl; - } - } - img.WritePPM(fileName); // write final image -} #define RESX 640 // image x-resolution #define RESY 480 // image y-resolution int main(int, char**) { - RenderFramePhongPointLight("phong_point.ppm"); - RenderFramePhongSpotLight("phong_spot.ppm"); + RenderFrameCone("cone.ppm"); } diff --git a/PerspectiveCamera.cxx b/PerspectiveCamera.cxx index fb9282d..e97e956 100644 --- a/PerspectiveCamera.cxx +++ b/PerspectiveCamera.cxx @@ -1,5 +1,6 @@ #include #include +#include #include "PerspectiveCamera.hxx" @@ -21,7 +22,9 @@ PerspectiveCamera::PerspectiveCamera(const Vec3f& pos, m_angle(angle) { // preprocess the values and fill the rest of the member variables here - + m_dir.normalize(); + m_up.normalize(); + // compute local coordinate system m_zAxis = dir; m_xAxis = dir.cross(up); @@ -50,6 +53,7 @@ PerspectiveCamera::PerspectiveCamera(const PerspectiveCamera& ) PerspectiveCamera& PerspectiveCamera::operator=(const PerspectiveCamera& ) { + assert(!"Not implemented!"); return *this; } diff --git a/PhongShader.cxx b/PhongShader.cxx index c44966e..f6bc870 100644 --- a/PhongShader.cxx +++ b/PhongShader.cxx @@ -1,5 +1,8 @@ +#include + #include "PhongShader.hxx" #include "Primitive.hxx" +#include "Scene.hxx" PhongShader::PhongShader(Scene* scene, const Vec3f& am_c, @@ -32,34 +35,65 @@ PhongShader::~PhongShader() Vec3f PhongShader::Shade(Ray& ray) { - // surface normal at hit point of object - Vec3f normal = ray.hit()->GetNormal(ray); - // turn to front if angle > 90° - if(normal.dot(ray.direction()) < 0) { - normal = normal * -1; - } - // direction of reflection - Vec3f refl_dir = ray.direction() - normal * 2 * normal.dot(ray.direction()); - refl_dir.normalize(); - - // ambient color term - Vec3f amb_color = m_ambient_color * m_ka; + // surface normal at hit point + Vec3f N = ray.hit()->GetNormal(ray); + // turn normal to front + if(N.dot(ray.direction()) > 0) + { + N *= -1; + } + + // reflection vector + Vec3f R = ray.direction() - N*2*N.dot(ray.direction()); + R.normalize(); - Vec3f intensity, light_dir; + // ambient term + Vec3f color = m_ambient_color * 1.0 * m_ka; + + // construct shadow ray + Vec3f shadow_org = ray.origin()+ray.direction()*ray.t(); + Ray shadow_ray; + shadow_ray.setOrigin(shadow_org); + - // diffuse and specular color for each light source - Vec3f diff_sum; - Vec3f spec_sum; - for(std::vector::iterator it = m_scene->m_lights.begin(); - it != m_scene->m_lights.end(); it++) { - Ray light_ray; - (*it)->Illuminate(light_ray, intensity); - diff_sum += intensity * light_ray.direction().dot(normal); - Vec3f view_dir = ray.direction()*-1; // direction from hitpoint to viewer - spec_sum += intensity * pow(fmax(view_dir.dot(refl_dir),0), m_ke); - } - Vec3f diff_color = m_diffuse_color * m_kd * diff_sum; - Vec3f spec_color = m_specular_color * m_ks * spec_sum; + int n_area_rays = 1000; + std::vector lights = m_scene->lights(); + for(unsigned int i = 0; i < lights.size(); ++i) + { + Vec3f intensity; - return amb_color + diff_color + spec_color; + int max_s = (lights[i]->IsArea()) ? n_area_rays : 1; + Vec3f color_l(0.0f,0.0f,0.0f); + for(int s = 0; s < max_s; ++s) + { + + if(lights[i]->Illuminate(shadow_ray, intensity)) + { + // check for occluders + if(m_scene->Occluded(shadow_ray)) + { + continue; + } + + float IdotN = shadow_ray.direction().dot(N); + if(IdotN > 0) + { + // diffuse term + color_l += m_diffuse_color * intensity * IdotN * m_kd; + } + + // specular term + float IdotR = shadow_ray.direction().dot(R); + if(IdotR > 0) + { + color_l += m_specular_color * intensity * pow(IdotR,m_ke) * m_ks; + } + } + } + color_l /= static_cast(max_s); + color += color_l; + } + color.clamp(); + + return color; } diff --git a/PhongShader.hxx b/PhongShader.hxx index 3a18d6c..b83e670 100644 --- a/PhongShader.hxx +++ b/PhongShader.hxx @@ -2,7 +2,6 @@ #define PHONGSHADER_HXX #include "Shader.hxx" -#include "Scene.hxx" class PhongShader : public Shader { @@ -16,11 +15,11 @@ public: float ks, float ke); virtual ~PhongShader(); - + virtual Vec3f Shade(Ray& ray); private: PhongShader(); - + Vec3f m_ambient_color, m_diffuse_color, m_specular_color; float m_ka, m_kd, m_ks, m_ke; }; diff --git a/PointLight.cxx b/PointLight.cxx index 925a6b5..61e4ec8 100644 --- a/PointLight.cxx +++ b/PointLight.cxx @@ -1,7 +1,7 @@ #include "PointLight.hxx" PointLight::PointLight(Scene* scene, const Vec3f& pos, const Vec3f& intensity) - : Light(scene), + : Light(scene), m_pos(pos), m_intensity(intensity) { @@ -12,27 +12,31 @@ PointLight::~PointLight() } PointLight::PointLight() - : Light(0), + : Light(0), m_pos(Vec3f()), m_intensity(Vec3f()) { } bool -PointLight::Illuminate(Ray& ray, Vec3f& intensity) +PointLight::Illuminate(Ray& shadow_ray, Vec3f& intensity) { - Vec3f dir = (ray.origin() + ray.direction() * (ray.t()-Epsilon)) - m_pos; - float dist = dir.norm(); + // distance to light source + Vec3f dir = m_pos-shadow_ray.origin(); + float r = dir.norm()-Epsilon; + float falloff = 1.0f/(r*r); + + + intensity = m_intensity * falloff; + + // modify ray for shadow computation + shadow_ray.setHit(0); + // for shadow calculation + shadow_ray.setT(r); + // set direction to light source dir.normalize(); - - float c1 = 1, c2 = 0.5, c3 = 0; - //float f_att = 1 / (dist*dist); - float f_att = 1 / (c1 + c2*dist + c3*dist*dist); - - intensity = m_intensity * f_att; - - // store direction from light to hitpoint - ray.setDir(dir); + shadow_ray.setDir(dir); + return true; } @@ -48,4 +52,8 @@ PointLight::intensity() const return m_intensity; } - +bool +PointLight::IsArea() +{ + return false; +} diff --git a/PointLight.hxx b/PointLight.hxx index b086116..ffd4390 100644 --- a/PointLight.hxx +++ b/PointLight.hxx @@ -14,6 +14,8 @@ public: const Vec3f& position() const; const Vec3f& intensity() const; + virtual bool IsArea(); + private: PointLight(); diff --git a/Primitive.hxx b/Primitive.hxx index 68dd11c..14233ad 100644 --- a/Primitive.hxx +++ b/Primitive.hxx @@ -3,6 +3,7 @@ #include "Ray.hxx" #include "Shader.hxx" +#include "Box.hxx" class Primitive { @@ -13,6 +14,8 @@ public: virtual bool Intersect(Ray &ray) = 0; virtual bool Occluded(Ray& ray); virtual Vec3f GetNormal(Ray& ray) = 0; + virtual Box CalcBounds() = 0; + virtual bool InVoxel(const Box& box) = 0; Shader* shader(); protected: diff --git a/QuadAreaLight.cxx b/QuadAreaLight.cxx new file mode 100644 index 0000000..ed64910 --- /dev/null +++ b/QuadAreaLight.cxx @@ -0,0 +1,74 @@ +#include + +#include "QuadAreaLight.hxx" + +QuadAreaLight::QuadAreaLight(Scene* scene, + const Vec3f& intensity, + const Vec3f& p1, + const Vec3f& p2, + const Vec3f& p3, + const Vec3f& p4) + : Light(scene), + m_p0(p1), + m_e1(p2-p1), + m_e2(p3-p1), + m_intensity(intensity) +{ + m_n = m_e1.cross(m_e2); + m_area = m_n.norm(); + m_n.normalize(); +} + +QuadAreaLight::QuadAreaLight() + : Light(0), + m_p0(Vec3f()), + m_e1(Vec3f()), + m_e2(Vec3f()), + m_n(Vec3f()), + m_intensity(Vec3f()) +{ +} + +QuadAreaLight::~QuadAreaLight() +{ +} + +bool +QuadAreaLight::Illuminate(Ray& shadow_ray, Vec3f& intensity) +{ + // generate random factors + float xi1 = drand48(); + float xi2 = drand48(); + + // bilinear interpolation of position + Vec3f pos = m_p0 + m_e1 * xi1 + m_e2* xi2; + // direction of shadow ray + Vec3f dir = pos-shadow_ray.origin(); + + float dist = dir.norm(); + float cosN = (dir.dot(m_n)) / dist; + + if(cosN <= 0.0f ) + return false; + + // squared falloff and projected area + intensity = m_intensity * ( m_area * cosN / ( dist*dist)); + + dir.normalize(); + shadow_ray.setDir(dir); + shadow_ray.setT(dist); + + return true; +} + +bool +QuadAreaLight::IsArea() +{ + return true; +} + +const Vec3f& +QuadAreaLight::GetNormal(const Vec3f& pos) const +{ + return m_n; +} diff --git a/QuadAreaLight.hxx b/QuadAreaLight.hxx new file mode 100644 index 0000000..108d5c4 --- /dev/null +++ b/QuadAreaLight.hxx @@ -0,0 +1,30 @@ +#ifndef QUADAREALIGHT_HXX +#define QUADAREALIGHT_HXX + +#include "Light.hxx" + +class QuadAreaLight : public Light +{ +public: + //! Points p1 to p4 are assumed to define a planar rectangular region and have to be given counter-clockwise + QuadAreaLight(Scene* scene, const Vec3f& intensity, const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& p4); + virtual ~QuadAreaLight(); + + virtual bool Illuminate(Ray& shadow_ray, Vec3f& intensity); + virtual bool IsArea(); + + const Vec3f& GetNormal(const Vec3f& position) const; + +private: + QuadAreaLight(); + + // defines the quad by one point and to vectors + Vec3f m_p0, m_e1, m_e2; + // normal + Vec3f m_n; + // emission(red, green, blue) + Vec3f m_intensity; + // area + float m_area; +}; +#endif diff --git a/ReflectiveEyeLightShader.cxx b/ReflectiveEyeLightShader.cxx index 0adb174..59f9444 100644 --- a/ReflectiveEyeLightShader.cxx +++ b/ReflectiveEyeLightShader.cxx @@ -24,11 +24,14 @@ Vec3f ReflectiveEyeLightShader::Shade(Ray& ray) { Vec3f N = ray.hit()->GetNormal(ray); + // turn normal to front + if(N.dot(ray.direction()) > 0) + N *= -1; - // diffuse color - Vec3f color = EyeLightShader::Shade(ray); + float cos_phi = fabs(ray.direction().dot(N)); + + Vec3f color = m_color * cos_phi; - // add reflection if(ray.recursionDepth() < RecursionDepth) { // generate reflected ray diff --git a/Scene.cxx b/Scene.cxx index a1d3acd..9d78bc6 100644 --- a/Scene.cxx +++ b/Scene.cxx @@ -1,21 +1,37 @@ +#include +#include + + #include "Scene.hxx" #include "PerspectiveCamera.hxx" +#include "EyeLightShader.hxx" +#include "Triangle.hxx" Scene::Scene() - : m_camera(new PerspectiveCamera(Vec3f(0,0,8), - Vec3f(0,0,-1), - Vec3f(0,1,0), - 50, - 640, + : m_camera(new PerspectiveCamera(Vec3f(0,0,8), + Vec3f(0,0,-1), + Vec3f(0,1,0), + 60, + 640, 480) ), - m_bgColor(Vec3f(0,0,0)) + m_bgColor(Vec3f(0,0,0)), + m_shader(0), + m_scene_box(Box()) { } Scene::~Scene() { delete m_camera; + if(m_shader != 0) + delete m_shader; + + for(unsigned int i = 0; i < m_primitives.size(); ++i) + { + delete m_primitives[i]; + } + m_primitives.clear(); } Scene::Scene(const Scene& s) @@ -29,7 +45,7 @@ Scene::operator=(const Scene& s) return *this; } -void +void Scene::Add(Primitive* p) { m_primitives.push_back(p); @@ -50,14 +66,14 @@ Scene::Intersect(Ray& ray) { intersect |= m_primitives[i]->Intersect(ray); } - + return intersect; } bool Scene::Occluded(Ray& ray) { - return false; + return this->Intersect(ray); } Vec3f @@ -67,8 +83,129 @@ Scene::RayTrace(Ray& ray) return (intersect) ? ray.hit()->shader()->Shade(ray) : m_bgColor; } -const Camera* +const Camera* Scene::camera() const { return m_camera; } + +std::vector +Scene::lights() const +{ + return m_lights; +} + +void +Scene::setCamera(const Camera* camera) +{ + if(m_camera != 0) + delete m_camera; + m_camera = const_cast(camera); +} + +void +Scene::ParseOBJ(const std::string& file, float scale) +{ + std::cerr << "(Scene): Parsing OBJ file : " << file << std::endl; + + // clear old buffers + m_vertices.clear(); + m_faces.clear(); + + // for the moment, we will attach a white eyelight shader to each object + // in the future, you will extend your parser to also read in material definitiions + if(m_shader == 0) // not yet defined + m_shader = new EyeLightShader(this, Vec3f(1.0,1.0,1.0)); + + + // now open file + std::fstream in; + in.open(file.c_str(), std::ios::in); + if(in.bad() || in.fail()) + { + std::cerr << "(Scene): Could not open file " << file << std::endl; + return; + } + + // read lines + std::string line; + while(!in.eof()) + { + std::getline(in, line); + this->parseOBJLine(line); + } + + // finished parsing file -> close fileStream + in.close(); + + // build triangle list from parsed vertices + this->buildTriangleList(scale); + + std::cerr << "(Scene): Finished parsing." << std::endl; +} + + +void +Scene::parseOBJLine(const std::string& line) +{ + std::istringstream iss(line); + std::string key; + iss >> key; + if (key == "v") + { + // parse vertex // + this->parseVertex(iss); + } + else if (key == "f") + { + // parse face // + this->parseFace(iss); + } +} + +void +Scene::parseVertex(std::istringstream& iss) +{ + Vec3f v; + iss >> v[0] >> v[1] >> v[2]; + + m_vertices.push_back(v); + m_centroid += v; +} + +void +Scene::parseFace(std::istringstream& iss) +{ + Vec3f f; + iss >> f[0] >> f[1] >> f[2]; + m_faces.push_back(f); +} + +void +Scene::buildTriangleList(float fac) +{ + for(unsigned int f = 0; f < m_faces.size(); ++f) + { + // stores indices of triangle into vertex list + // remember: indices start at 1!! + Vec3f face_idx = m_faces[f]; + this->Add(new Triangle(m_vertices[ face_idx[0]-1 ] * fac, + m_vertices[ face_idx[1]-1 ] * fac, + m_vertices[ face_idx[2]-1 ] * fac, + m_shader)); + + } + m_centroid /= static_cast(m_vertices.size()); + std::cerr << "(Scene): Model centroid = " << m_centroid * fac << std::endl; +} + +void +Scene::CalcBounds() +{ +} + +const Box& +Scene::GetSceneBox() const +{ + return m_scene_box; +} diff --git a/Scene.hxx b/Scene.hxx index 74154eb..baafce6 100644 --- a/Scene.hxx +++ b/Scene.hxx @@ -2,6 +2,9 @@ #define SCENE_HXX #include +#include +#include + #include "Ray.hxx" #include "Camera.hxx" @@ -13,7 +16,7 @@ class Scene public: Scene(); virtual ~Scene(); - + // add another primitive to the scene void Add(Primitive* p); // add another light source to the scene @@ -23,22 +26,49 @@ public: virtual bool Intersect(Ray& ray); // find occluder virtual bool Occluded(Ray& ray); - + // trace the given ray and shade it, returnt the color of the shaded ray Vec3f RayTrace(Ray& ray); + + // acces to camera and light sources + const Camera* camera() const; + std::vector lights() const; - const Camera* camera() const; - // lights - std::vector m_lights; + // set new camera + void setCamera(const Camera* camera); + + // reads in a scene description + void ParseOBJ(const std::string& file, float factor); + // calculate scene bounding box + void CalcBounds(); + + const Box& GetSceneBox() const; private: Scene(const Scene& ); Scene& operator=(const Scene& ); + void parseOBJLine(const std::string& line); + void parseVertex(std::istringstream& iss); + void parseFace(std::istringstream& iss); + void buildTriangleList(float scale); + Camera* m_camera; // background color Vec3f m_bgColor; - + // primitives std::vector m_primitives; + // lights + std::vector m_lights; + + // shader used by loading routine + Shader* m_shader; + + // storage for vertices and face indices + std::vector m_vertices, m_faces; + Vec3f m_centroid; + + // scene bounding box + Box m_scene_box; }; #endif diff --git a/Sphere.cxx b/Sphere.cxx index 6b8d943..fd9ba89 100644 --- a/Sphere.cxx +++ b/Sphere.cxx @@ -48,3 +48,15 @@ Sphere::GetNormal(Ray& ray) return N; } + +Box +Sphere::CalcBounds() +{ + return Box(); +} + +bool +Sphere::InVoxel(const Box& box) +{ + return false; +} diff --git a/Sphere.hxx b/Sphere.hxx index 28604e7..cc07bfe 100644 --- a/Sphere.hxx +++ b/Sphere.hxx @@ -12,6 +12,8 @@ public: virtual bool Intersect(Ray& ray); virtual Vec3f GetNormal(Ray& ray); + virtual Box CalcBounds(); + virtual bool InVoxel(const Box& box); private: Vec3f m_center; float m_radius; diff --git a/SpotLight.cxx b/SpotLight.cxx index 8ec7cf6..0ccef8a 100644 --- a/SpotLight.cxx +++ b/SpotLight.cxx @@ -4,15 +4,16 @@ SpotLight::SpotLight(Scene* scene, const Vec3f& pos, const Vec3f& dir, const Vec3f& intensity, - float alpha_min, - float alpha_max) + float alpha_min, // in degree + float alpha_max) // in degree : Light(scene), m_pos(pos), m_dir(dir), m_intensity(intensity), - m_alpha_min(alpha_min), + m_alpha_min(alpha_min), m_alpha_max(alpha_max) { + m_dir.normalize(); } SpotLight::~SpotLight() @@ -30,9 +31,47 @@ SpotLight::SpotLight() } bool -SpotLight::Illuminate(Ray& ray, Vec3f& intensity) +SpotLight::Illuminate(Ray& shadow_ray, Vec3f& intensity) { - return false; + // direction vector from light source to surface point + Vec3f D = shadow_ray.origin()-m_pos; + D.normalize(); + // angle between light source dir and shadow ray dir + float phi = fabs(acos(D.dot(m_dir))*180/M_PI); + + // outside cone + if(phi > m_alpha_max) + { + return false; + } + else + { + Vec3f dir = m_pos-shadow_ray.origin(); + float r = dir.norm()-Epsilon; + float falloff = 1.0f/(r*r); // falloff for distance + + // modify ray for shadow computation + shadow_ray.setHit(0); + // for shadow calculation + shadow_ray.setT(r); + // set direction to light source + dir.normalize(); + shadow_ray.setDir(dir); + + if(phi < m_alpha_min) + { + intensity = m_intensity * falloff; + } + else + { + // linear falloff from 1 at alpha_min to 0 at alpha_max + float partial = 1.0f-(phi-m_alpha_min)/(m_alpha_max-m_alpha_min); + intensity = m_intensity * falloff * partial; + + } + return true; + } + return true; } const Vec3f& @@ -46,3 +85,9 @@ SpotLight::direction() const { return m_dir; } + +bool +SpotLight::IsArea() +{ + return false; +} diff --git a/SpotLight.hxx b/SpotLight.hxx index ed404d8..4a938b9 100644 --- a/SpotLight.hxx +++ b/SpotLight.hxx @@ -10,10 +10,11 @@ public: virtual ~SpotLight(); virtual bool Illuminate(Ray& ray, Vec3f& intensity); + virtual bool IsArea(); const Vec3f& position() const; const Vec3f& direction() const; - + private: SpotLight(); diff --git a/Triangle.cxx b/Triangle.cxx index 498757e..ed12db0 100644 --- a/Triangle.cxx +++ b/Triangle.cxx @@ -60,3 +60,15 @@ Triangle::GetNormal(Ray& ray) { return m_n; } + +Box +Triangle::CalcBounds() +{ + return Box(); +} + +bool +Triangle::InVoxel(const Box& box) +{ + return false; +} diff --git a/Triangle.hxx b/Triangle.hxx index 6abbe53..8e56231 100644 --- a/Triangle.hxx +++ b/Triangle.hxx @@ -11,6 +11,8 @@ public: virtual bool Intersect(Ray& ray); virtual Vec3f GetNormal(Ray& ray); + virtual Box CalcBounds(); + virtual bool InVoxel(const Box& box); private: Vec3f m_a, m_b, m_c; Vec3f m_n; diff --git a/Vec3f.hxx b/Vec3f.hxx index 81c0c8b..eef3409 100644 --- a/Vec3f.hxx +++ b/Vec3f.hxx @@ -11,7 +11,7 @@ #endif -#define Epsilon 1E-3 +#define Epsilon 1E-4 #define Infinity HUGE_VAL //! Standard operators and useful methods for 3d vectors diff --git a/cone.obj b/cone.obj new file mode 100644 index 0000000..7cf97f8 --- /dev/null +++ b/cone.obj @@ -0,0 +1,99 @@ +cp# The units used in this file are centimeters. +v 0.196157 -0.150000 -0.039018 +v 0.184776 -0.150000 -0.076537 +v 0.166294 -0.150000 -0.111114 +v 0.141421 -0.150000 -0.141421 +v 0.111114 -0.150000 -0.166294 +v 0.076537 -0.150000 -0.184776 +v 0.039018 -0.150000 -0.196157 +v 0.000000 -0.150000 -0.200000 +v -0.039018 -0.150000 -0.196157 +v -0.076537 -0.150000 -0.184776 +v -0.111114 -0.150000 -0.166294 +v -0.141421 -0.150000 -0.141421 +v -0.166294 -0.150000 -0.111114 +v -0.184776 -0.150000 -0.076537 +v -0.196157 -0.150000 -0.039018 +v -0.200000 -0.150000 -0.000000 +v -0.196157 -0.150000 0.039018 +v -0.184776 -0.150000 0.076537 +v -0.166294 -0.150000 0.111114 +v -0.141421 -0.150000 0.141421 +v -0.111114 -0.150000 0.166294 +v -0.076537 -0.150000 0.184776 +v -0.039018 -0.150000 0.196157 +v -0.000000 -0.150000 0.200000 +v 0.039018 -0.150000 0.196157 +v 0.076537 -0.150000 0.184776 +v 0.111114 -0.150000 0.166294 +v 0.141421 -0.150000 0.141421 +v 0.166294 -0.150000 0.111114 +v 0.184776 -0.150000 0.076537 +v 0.196157 -0.150000 0.039018 +v 0.200000 -0.150000 0.000000 +v 0.000000 -0.150000 0.000000 +v 0.000000 0.150000 0.000000 +f 2 1 33 +f 3 2 33 +f 4 3 33 +f 5 4 33 +f 6 5 33 +f 7 6 33 +f 8 7 33 +f 9 8 33 +f 10 9 33 +f 11 10 33 +f 12 11 33 +f 13 12 33 +f 14 13 33 +f 15 14 33 +f 16 15 33 +f 17 16 33 +f 18 17 33 +f 19 18 33 +f 20 19 33 +f 21 20 33 +f 22 21 33 +f 23 22 33 +f 24 23 33 +f 25 24 33 +f 26 25 33 +f 27 26 33 +f 28 27 33 +f 29 28 33 +f 30 29 33 +f 31 30 33 +f 32 31 33 +f 1 32 33 +f 1 2 34 +f 2 3 34 +f 3 4 34 +f 4 5 34 +f 5 6 34 +f 6 7 34 +f 7 8 34 +f 8 9 34 +f 9 10 34 +f 10 11 34 +f 11 12 34 +f 12 13 34 +f 13 14 34 +f 14 15 34 +f 15 16 34 +f 16 17 34 +f 17 18 34 +f 18 19 34 +f 19 20 34 +f 20 21 34 +f 21 22 34 +f 22 23 34 +f 23 24 34 +f 24 25 34 +f 25 26 34 +f 26 27 34 +f 27 28 34 +f 28 29 34 +f 29 30 34 +f 30 31 34 +f 31 32 34 +f 32 1 34 diff --git a/kDTree.cxx b/kDTree.cxx new file mode 100644 index 0000000..d329a83 --- /dev/null +++ b/kDTree.cxx @@ -0,0 +1,139 @@ +#include "kDTree.hxx" + +/*************** kDTreeInnerNode ******************/ + +kDTreeInnerNode::kDTreeInnerNode(float split, + int axis) + : m_split(split), + m_axis(axis) +{ +} + +kDTreeInnerNode::~kDTreeInnerNode() +{ + // think about correct memory management! +} + +kDTreeInnerNode::kDTreeInnerNode() +{ +} + +kDTreeInnerNode::kDTreeInnerNode(const kDTreeInnerNode& node) +{ + operator=(node); +} + +kDTreeInnerNode& +kDTreeInnerNode::operator=(const kDTreeInnerNode& ) +{ + return *this; +} + +bool +kDTreeInnerNode::Traverse(Ray& ray, float& t0, float& t1) +{ + // implement the traversal of an inner node + // think about the correct order + + return false; +} + +void +kDTreeInnerNode::setChildren(kDTreeNode* left, + kDTreeNode* right) +{ + m_children[0] = left; + m_children[1] = right; +} + + +/******************** kDTreeLeafNode *******************/ + +kDTreeLeafNode::kDTreeLeafNode(const std::vector& prim) + : m_primitives(prim) +{ + +} + +kDTreeLeafNode::~kDTreeLeafNode() +{ +} + +kDTreeLeafNode::kDTreeLeafNode() +{ +} + +kDTreeLeafNode::kDTreeLeafNode(const kDTreeLeafNode& node) +{ + operator=(node); +} + +kDTreeLeafNode& +kDTreeLeafNode::operator=(const kDTreeLeafNode& ) +{ + return *this; +} + +bool +kDTreeLeafNode::Traverse(Ray& ray, float& t0, float& t1) +{ + // implement the leaf node traversal here + return false; +} + + +/******************** kDTree ***********************/ + +kDTree::kDTree(const Box& bounds, + const std::vector& prim) + : m_root(0), + m_bounds(bounds), + m_maxDepth(20), + m_minTri(3) +{ + m_root = BuildTree(m_bounds, prim, 0); +} + +kDTree::~kDTree() +{ + // think about correct memory management + delete m_root; +} + +kDTree::kDTree() + : m_root(0), + m_bounds(Box()) +{ +} + +kDTree::kDTree(const kDTree& tree) +{ + operator=(tree); +} + +kDTree& +kDTree::operator=(const kDTree& ) +{ + return *this; +} + +kDTreeNode* +kDTree::BuildTree(const Box& bounds, + const std::vector& prim, + int depth) +{ + // setup tree structure here + // these two variables are only here to solve compilation issues! + float dummy_split = 0.0f; + int dummy_axis = 0; + kDTreeInnerNode* node = new kDTreeInnerNode(dummy_split, dummy_axis); + + return node; +} + +bool +kDTree::Intersect(Ray& ray) +{ + // implement the tree traversal + return false; +} diff --git a/kDTree.hxx b/kDTree.hxx new file mode 100644 index 0000000..13c1bc4 --- /dev/null +++ b/kDTree.hxx @@ -0,0 +1,85 @@ +#ifndef KDTREE_HXX +#define KDTREE_HXX + +#include + +#include "Box.hxx" +#include "Primitive.hxx" + +//! Interface for tree nodes +class kDTreeNode +{ +public: + virtual ~kDTreeNode(){;}; + // interface for the traversal. [t0,t1] code the active ray interval. + virtual bool Traverse(Ray &ray, float& t0, float& t1) = 0; +}; + +//! An inner node of the kD-tree +class kDTreeInnerNode : public kDTreeNode +{ +public: + kDTreeInnerNode(float split, int axis); + virtual ~kDTreeInnerNode(); + + virtual bool Traverse(Ray& ray, float& t0, float& t1); + + void setChildren(kDTreeNode* left, kDTreeNode* right); +private: + kDTreeInnerNode(); + kDTreeInnerNode(const kDTreeInnerNode& ); + kDTreeInnerNode& operator=(const kDTreeInnerNode& ); + + // pointer to the children + kDTreeNode* m_children[2]; + // encodes the position of the splitting plane on the splitting axis + float m_split; + // encodes the splitting axis + int m_axis; +}; + +//! A leaf node of the kD-tree +class kDTreeLeafNode : public kDTreeNode +{ +public: + kDTreeLeafNode(const std::vector& prim); + virtual ~kDTreeLeafNode(); + + virtual bool Traverse(Ray& ray, float& t0, float& t1); + +private: + kDTreeLeafNode(); + kDTreeLeafNode(const kDTreeLeafNode& ); + kDTreeLeafNode& operator=(const kDTreeLeafNode& ); + + std::vector m_primitives; +}; + +//! The actual kDTree interface +class kDTree +{ +public: + kDTree(const Box& bounds, const std::vector& prim); + ~kDTree(); + + kDTreeNode* BuildTree(const Box& bounds, + const std::vector& prim, + int depth); + + bool Intersect(Ray &ray); + +private: + kDTree(); + kDTree(const kDTree& ); + kDTree& operator=(const kDTree& ); + + // root node + kDTreeNode* m_root; + // bounding box of the entire tree + Box m_bounds; + // maximal recursion depth + int m_maxDepth; + // minimal number of triangles per node + int m_minTri; +}; +#endif -- 2.20.1