Blame | Last modification | View Log | RSS feed
/* ----------------------------------------------------------------------- *
* This file is part of GEL, http://www.imm.dtu.dk/GEL
* Copyright (C) the authors and DTU Informatics
* For license and list of authors, see ../../doc/intro.pdf
* ----------------------------------------------------------------------- */
/**
* @file Ray.h
* @brief A ray class for ray tracing.
*/
#ifndef __GEOMETRY_RAY_H__
#define __GEOMETRY_RAY_H__
#include "../CGLA/Vec3i.h"
#include "../CGLA/Vec3f.h"
#include "TriMesh.h"
#include "Material.h"
namespace Geometry
{
const double d_eps = 1.0e-12;
const float f_eps = 1.0e-6f;
/// Represents a ray as used for ray tracing.
struct Ray
{
// Constructor
Ray()
: origin(0.0f), direction(0.0f), hit_pos(0.0f), hit_normal(0.0f),
has_hit(false), inside(false), did_hit_diffuse(false), dist(CGLA::BIG),
ior(1.0f), u(0.0f), v(0.0f), trace_depth(0), hit_object(0)
{ }
Ray(const CGLA::Vec3f& _origin, const CGLA::Vec3f& _direction)
: origin(_origin), direction(_direction), hit_pos(0.0f), hit_normal(0.0f),
has_hit(false), inside(false), did_hit_diffuse(false), dist(CGLA::BIG),
ior(1.0f), u(0.0f), v(0.0f), trace_depth(0), hit_object(0)
{ }
CGLA::Vec3f origin;
CGLA::Vec3f direction;
CGLA::Vec3f hit_pos;
CGLA::Vec3f hit_normal;
bool has_hit; // Did the ray hit an object
bool inside; // Is the ray inside an object
bool did_hit_diffuse;
double dist; // Distance from origin to current intersection
float ior; // Current index of refraction for media
float u, v; // uv-coordinates on current surface
int trace_depth; // Current recursion number
size_t hit_face_id;
int id;
const TriMesh* hit_object;
const Material* get_hit_material() const
{
if(!hit_object)
return 0;
return &hit_object->materials[hit_object->mat_idx[hit_face_id]];
}
void reset()
{
has_hit=false;
inside = false;
did_hit_diffuse = false;
dist = CGLA::BIG;
ior = 1.0f;
u=0.0f;
v=0.0f;
trace_depth = 0;
hit_object = 0;
}
void compute_position()
{
hit_pos = origin + dist*direction;
}
void compute_normal()
{
const CGLA::Vec3i& face = hit_object->normals.face(hit_face_id);
const CGLA::Vec3f& normal0 = hit_object->normals.vertex(face[0]);
const CGLA::Vec3f& normal1 = hit_object->normals.vertex(face[1]);
const CGLA::Vec3f& normal2 = hit_object->normals.vertex(face[2]);
hit_normal = normalize(normal0*(1 - u - v) + normal1*u + normal2*v);
}
void reflect(const CGLA::Vec3f &normal)
{
assert(dot(direction, normal) < 0.0f);
direction = normal*2.0f*dot(-direction,normal) + direction;
}
void refract(const CGLA::Vec3f& normal, float new_ior)
{
float ref_ratio = ior/new_ior;
float cos_N_I = dot(normal, direction);
CGLA::Vec3f norm(normal);
if(cos_N_I > 0.0f)
{
norm = -norm;
cos_N_I = dot(norm, direction);
}
float selector = 1+(ref_ratio*ref_ratio)*(cos_N_I*cos_N_I - 1);
if(selector > 0.0f)
{
direction = norm*(ref_ratio*(-cos_N_I) - sqrt(selector))
+ direction*ref_ratio;
ior = new_ior;
}
else
// Total internal reflection.
reflect(normal);
}
bool cond_set_parameter(float t, float _u, float _v, const Geometry::TriMesh* mesh, size_t idx)
{
if(t < dist)
{
dist = t;
u = _u;
v = _v;
hit_object = mesh;
hit_face_id = idx;
has_hit = true;
return true;
}
return false;
}
};
}
#endif