Subversion Repositories gelsvn

Rev

Rev 318 | Rev 420 | 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 = 1.0e-12;
                const float f_eps = 1.0e-6f;

                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;

                                const 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;
                                                                                return true;
                                                                }
                                                                return false;
                                                }
                };
}
#endif