Subversion Repositories gelsvn

Rev

Rev 294 | Rev 309 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#ifndef __RAY_H__
#define __RAY_H__

#include "../CGLA/Vec3i.h"
#include "../CGLA/Vec3f.h"
#include "TriMesh.h"

namespace Geometry 
{
  const double d_eps = 0.000001;
  const float f_eps = 0.01f;

  struct Ray 
  {
    // Constructor
    Ray() 
      : origin(0.0f), direction(0.0f), hit_pos(0.0f), hit_normal(0.0f), 
        has_hit(false), dist(CGLA::BIG), ior(1.0f), u(0.0f), v(0.0f), 
        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), dist(CGLA::BIG), ior(1.0f), u(0.0f), v(0.0f), 
        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

    double dist;  // Distance from origin to current intersection
    float ior;    // Current index of refraction for media
    float u, v;   // uv-coordinates on current surface
    float ran;

    int trace_depth;  // Current recursion number
    size_t hit_face_id;
    int id;

    Geometry::TriMesh* hit_object;

    void reset()
    {
      dist = CGLA::BIG; 
      hit_object = 0;
      u=0.0f;
      v=0.0f;
      has_hit=false;      
    }

    void compute_position()
    {
      hit_pos = origin + dist*direction;      
    }
    
    void compute_normal()
    {
      CGLA::Vec3i face = hit_object->normals.face(hit_face_id);
      CGLA::Vec3f normal0 = hit_object->normals.vertex(face[0]);
      CGLA::Vec3f normal1 = hit_object->normals.vertex(face[1]);
      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, 
                            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;
      }
    }
  };
}
#endif