Skip to content

Instantly share code, notes, and snippets.

@denyskoch
Created February 7, 2014 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save denyskoch/8867240 to your computer and use it in GitHub Desktop.
Save denyskoch/8867240 to your computer and use it in GitHub Desktop.
Ray Tracing
bool
Plane::
intersect(const Ray& _ray,
vec3& _intersection_point,
vec3& _intersection_normal,
double& _intersection_t ) const
{
double dpDN = dot(_ray.direction, this->normal);
if( dpDN == 0)
return false;
double d = dot(this->normal, this->center);
double t = (d - dot(this->normal, _ray.origin))/dpDN;
if( t > 1e-5) {
_intersection_t = t;
_intersection_point = _ray(t);
_intersection_normal = this->normal;
return true;
}
return false;
}
//=============================================================================
//
// Exercise code for the lecture
// "Introduction to Computer Graphics"
// by Prof. Dr. Mario Botsch, Bielefeld University
//
// Copyright (C) Computer Graphics Group, Bielefeld University.
//
//=============================================================================
//== includes =================================================================
#include "StopWatch.h"
#include "Sphere.h"
#include "Plane.h"
#include "Mesh.h"
#include "Light.h"
#include "Ray.h"
#include "Material.h"
#include "Image.h"
#include "Camera.h"
#include <vector>
#include <iostream>
#include <fstream>
#include <float.h>
/// \file raytrace.cpp
/// In this file the main raytracing routines are implemented.
//== function declarations ====================================================
/// reads the scene to raytrace from the given filename (\c _filename)
void read_scene(const char* _filename);
/// writes the resulting image in tga format to a given filename (\c _filename)
void write_image(const char* _filename);
/// main function where the image is allocated and the raytracing is started
void compute_image();
/// finds the closest colision point for the passed Ray and returns the computed color for this object
vec3 trace(const Ray& _ray, int _depth);
/// computes the intersection between a ray and the object
bool intersect(const Ray& _ray, Object_ptr&, vec3& _point, vec3& _normal, double& _t);
/// computes the phong lighting
vec3 lighting(const vec3& _point, const vec3& _normal, const vec3& _view, const Material& _material);
//== global variables =========================================================
/// camera stores eye position, view direction, and can generate primary rays
Camera camera;
/// our image is just a large array of color values
Image image;
/// array for all lights in the scene
std::vector<Light> lights;
/// array for all the objects in the scene
std::vector<Object_ptr> objects;
/// max recursion depth for mirroring
int max_depth;
/// background color
vec3 background;
/// global ambient light
vec3 ambience;
//== implementation ===========================================================
int main(int argc, char **argv)
{
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << " input.sce output.tga\n\n";
exit(1);
}
// read scene from file
std::cout << "Read scene...";
read_scene(argv[1]);
std::cout << "done (" << objects.size() << " objects)\n";
// raytrace image
StopWatch timer;
timer.start();
std::cout << "Ray tracing..." << std::flush;
compute_image();
timer.stop();
std::cout << "done (" << timer << ")\n";
// write the resulting image
std::cout << "Write image...";
image.write(argv[2]);
std::cout << "done\n";
// clean up
for (Object_ptr o: objects)
{
delete o;
}
}
//-----------------------------------------------------------------------------
void read_scene(const char* _filename)
{
std::ifstream ifs(_filename);
if (!ifs)
{
std::cerr << "Cannot open file " << _filename << std::endl;
exit(1);
}
char line[200];
std::string token;
// parse file
while (ifs && (ifs >> token) && (!ifs.eof()))
{
if (token[0] == '#')
{
ifs.getline(line, 200);
}
else if (token == "depth")
{
ifs >> max_depth;
}
else if (token == "camera")
{
ifs >> camera;
}
else if (token == "background")
{
ifs >> background;
}
else if (token == "ambience")
{
ifs >> ambience;
}
else if (token == "light")
{
Light light;
ifs >> light;
lights.push_back(light);
}
else if (token == "plane")
{
Plane *p = new Plane;
ifs >> (*p);
objects.push_back(p);
}
else if (token == "sphere")
{
Sphere *sphere = new Sphere();
ifs >> (*sphere);
objects.push_back(sphere);
}
else if (token == "mesh")
{
std::string filename, mode;
ifs >> filename >> mode;
// add path of scene-file to mesh's filename
std::string path(_filename);
#ifdef _WIN32
path = path.substr(0, path.find_last_of('\\')+1);
#else
path = path.substr(0, path.find_last_of('/')+1);
#endif
filename = path+filename;
Mesh *mesh = new Mesh((mode=="FLAT" ? Mesh::FLAT : Mesh::PHONG),
filename.c_str());
ifs >> mesh->material;
objects.push_back(mesh);
}
}
ifs.close();
}
//-----------------------------------------------------------------------------
void compute_image()
{
// allocate memory by resizing image
image.resize(camera.width, camera.height);
// here comes the main ray tracing loop
for (unsigned int y=0; y<camera.height; ++y)
{
// uncomment the following line in order to use OpenMP
// #pragma omp parallel for schedule(dynamic)
for (int x=0; x<camera.width; ++x)
{
Ray ray = camera.primary_ray(x,y);
// compute color by tracing this ray
vec3 color = trace(ray, 0);
// avoid over-saturation
color = min(color, vec3(1, 1, 1));
// store pixel color
image(x,y) = color;
}
}
}
//-----------------------------------------------------------------------------
vec3 trace(const Ray& _ray, int _depth)
{
// stop if recursion depth (=number of reflection) is too large
if (_depth > max_depth) return vec3(0,0,0);
// Find first intersection with an object. If an intersection is found,
// it is stored in object, point, normal, and t.
Object_ptr object;
vec3 point;
vec3 normal;
double t;
if (!intersect(_ray, object, point, normal, t))
{
return background;
}
// compute local Phong lighting (ambient+diffuse+specular)
vec3 color = lighting(point, normal, _ray.direction, object->material);
if(object->material.mirror != 0) {
color += trace(Ray(point, reflect(_ray.direction, normal)), _depth + 1) * object->material.mirror;
}
return color;
}
//-----------------------------------------------------------------------------
bool intersect(const Ray& _ray, Object_ptr& _object, vec3& _point, vec3& _normal, double& _t)
{
double t, tmin(DBL_MAX);
vec3 p, n;
for (Object_ptr o: objects) // for each object
{
if (o->intersect(_ray, p, n, t)) // does ray intersect object?
{
if (t < tmin) // is intersection point the currently closest one?
{
tmin = t;
_object = o;
_point = p;
_normal = n;
_t = t;
}
}
}
return (tmin < DBL_MAX);
}
//-----------------------------------------------------------------------------
vec3 lighting(const vec3& _point, const vec3& _normal, const vec3& _view, const Material& _material)
{
// start with global ambient term
vec3 color = ambience * _material.ambient;
double dpNL = 0; // dot product of N * L
double dpRV = 0; // dot product R * V
vec3 L;
vec3 R;
Object_ptr object;
vec3 point;
vec3 normal;
double t;
Ray shadowRay;
for (auto l:lights ){
L = normalize(l.position - _point);
dpNL = dot(L, _normal);
R = normalize(2 * _normal * dpNL - L);
dpRV = dot(R, normalize(-1*_view));
shadowRay = Ray(_point, L);
if (!intersect(shadowRay, object, point, normal, t))
{
if(dpNL >= 0) {
color += l.color * _material.diffuse * dpNL;
if(dpRV >= 0) {
color += l.color * _material.specular * pow(dpRV, _material.shininess);
}
}
}
}
return color;
}
//=============================================================================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment