/* * Ray++ - Object-oriented ray tracing library * Copyright (C) 1998-2001 Martin Reinecke and others. * See the AUTHORS file for more information. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * See the README file for more information. */ #include "renderers/raytracer.h" namespace RAYPP { extern HANDLE World; COLOUR RAYTRACER::Trace_Light_Ray (const RAY &Ray, const COLOUR &Ingoing) const { ci(); if ((Ingoing*Ray.Importance).TooSmall()) return COLOUR (0,0,0); if (!Shadow_Rays) return Ingoing; SHADING_INFO ShadingInfo; ShadingInfo.Importance = Ray.Importance; float8 dist; COLOUR Col = Ingoing; RAY Local_Ray = Ray; while (World->Get_Next_Intersection (Local_Ray, dist, ShadingInfo)) { if (Local_Ray.Inside.Vol) { Local_Ray.maxdist = dist - Small_dist; Col = Local_Ray.Inside.Vol->Get_Attenuated_Light (Local_Ray, Col); } if (ShadingInfo.Surf) Col = ShadingInfo.Surf->Get_Transmitted_Light (ShadingInfo, Col); else { float4 ior1=1.0, ior2=1.0; if (ShadingInfo.Ins1.Vol) ior1 = ShadingInfo.Ins1.Vol->Refractive_Index (ShadingInfo); if (ShadingInfo.Ins2.Vol) ior2 = ShadingInfo.Ins2.Vol->Refractive_Index (ShadingInfo); if (abs (ior1-ior2) > Small_float4) return COLOUR (0,0,0); } if ((Col*Ray.Importance).TooSmall()) return COLOUR (0,0,0); Local_Ray.mindist = dist + Small_dist; Local_Ray.maxdist = Ray.maxdist; Local_Ray.Inside = ShadingInfo.Ins2; } if (Local_Ray.Inside.Vol) Col = Local_Ray.Inside.Vol->Get_Attenuated_Light (Local_Ray, Col); return Col; } COLOUR RAYTRACER::Get_Emitted_Light (const SHADING_INFO &Info) const { ci(); LIGHT_ARRAY L_Arr; INCIDENT_ARRAY Arr; COLOUR Importance; VECTOR Dir; FULL_SHADING_INFO Full_Info; (Info.Surf)->Get_Full_Shading_Info (Info, Full_Info); // get light sources World->Get_Lights (Info.Intersect_Point, L_Arr); Arr.Ambient = L_Arr.Ambient; RAY Ray; Ray.mindist = 0.0; COLOUR tmpcol; for (LIGHT_ARRAY::iterator i=L_Arr.begin(); iPosition - Info.Intersect_Point).Norm(); Importance = (Info.Surf)->Get_Total_Importance (Full_Info, Dir); if (!((i->Intensity)*Importance).TooSmall()) { Ray.start = i->Position; Ray.Set_Direction (-Dir); Ray.maxdist = (Info.Intersect_Point - Ray.start).Length() - Small_dist; Ray.Inside = i->Inside; Ray.Importance = Importance; tmpcol = Trace_Light_Ray (Ray, i->Intensity); if (!tmpcol.TooSmall()) Arr.push_back (INCIDENT_ENTRY (tmpcol, Ray.dir)); } } COLOUR reflect_col (0,0,0); if (Full_Info.reflect) { if (Full_Info.specular_level < Max_Specular_Level) { if (Full_Info.Reflected.SquaredLength() > Small_dist*Small_dist) { reflect_col = Trace_Ray (RAY (Full_Info.Intersect_Point, Full_Info.Reflected, Small_dist, Large_dist, Full_Info.Ins1, /* to be improved */ Full_Info.Reflected_Imp, Full_Info.diffuse_level, Full_Info.specular_level+1)); } } } COLOUR refract_col (0,0,0); if (Full_Info.refract) { if (Full_Info.specular_level < Max_Specular_Level) { if (Full_Info.Refracted.SquaredLength() > Small_dist*Small_dist) refract_col = Trace_Ray (RAY (Full_Info.Intersect_Point, Full_Info.Refracted, Small_dist, Large_dist, Full_Info.Ins2, /* to be improved */ Full_Info.Refracted_Imp, Full_Info.diffuse_level, Full_Info.specular_level+1)); } } INCIDENT_ARRAY dummy; COLOUR result = (Info.Surf)->Get_Emitted_Light (Full_Info, Arr, reflect_col, refract_col, dummy, dummy, dummy); return result; } RAYTRACER::RAYTRACER () { Max_Specular_Level=10; Samples = 1; Shadow_Rays = true; } //virtual void RAYTRACER::Init () { if (initialized) return; Camera->Init(); initialized = true; } //virtual void RAYTRACER::Deinit () { if (!initialized) return; Camera->Deinit(); initialized = false; } //virtual COLOUR RAYTRACER::Trace_Ray (const RAY &Ray) const { ci(); if (Ray.Importance.TooSmall()) return COLOUR (0,0,0); SHADING_INFO ShadingInfo; float8 dist; if (!(World->Get_Next_Intersection (Ray, dist, ShadingInfo))) { COLOUR Incol = World->Get_Background(Ray.dir); if (Ray.Inside.Vol) return Ray.Inside.Vol->Calc_Modified_Colour (Ray, Incol); else return Incol; } else { RAY Local_Ray = Ray; Local_Ray.maxdist = dist; ShadingInfo.diffuse_level = Ray.diffuse_level; ShadingInfo.specular_level = Ray.specular_level; if (Local_Ray.Inside.Vol) ShadingInfo.Importance = Local_Ray.Inside.Vol->Calc_new_Importance (Local_Ray); else ShadingInfo.Importance = Local_Ray.Importance; COLOUR Ingoing; if (ShadingInfo.Surf) Ingoing = Get_Emitted_Light (ShadingInfo); else { RAY Local_Ray2 = Ray; float4 ior1=1.0, ior2=1.0; if (ShadingInfo.Ins1.Vol) ior1 = ShadingInfo.Ins1.Vol->Refractive_Index (ShadingInfo); if (ShadingInfo.Ins2.Vol) ior2 = ShadingInfo.Ins2.Vol->Refractive_Index (ShadingInfo); if (abs (ior1-ior2) > Small_float4) { // trace refracted ray Local_Ray2.start = ShadingInfo.Intersect_Point; Local_Ray2.mindist = Small_dist; error ("unimplemented feature; refraction without SURFACE"); } else { Local_Ray2.mindist = dist + Small_dist; } Local_Ray2.Inside = ShadingInfo.Ins2; Local_Ray2.Importance = ShadingInfo.Importance; Ingoing = Trace_Ray (Local_Ray2); } if (Local_Ray.Inside.Vol) return Local_Ray.Inside.Vol->Calc_Modified_Colour (Local_Ray, Ingoing); else return Ingoing; } } //virtual COLOUR RAYTRACER::Get_Pixel (float8 u, float8 v, float8 du, float8 dv) const { ci(); COLOUR Col(0,0,0); const float8 ddu = du/Samples, ddv = dv/Samples; u+=0.5*ddu; v+=0.5*ddv; for (int j=0; jCalc_Intensity (u,v); } //virtual void RAYTRACER::Calc_Illumination (const VECTOR &Loc, const COLOUR &Imp, INCIDENT_ARRAY &Arr) const { ci(); LIGHT_ARRAY L_Arr; // get light sources World->Get_Lights (Loc, L_Arr); Arr.Ambient = L_Arr.Ambient; VECTOR Dir; RAY Ray; Ray.mindist = 0.0; COLOUR tmpcol; for (LIGHT_ARRAY::iterator i=L_Arr.begin(); iPosition - Loc).Norm(); if (!((i->Intensity)*Imp).TooSmall()) { Ray.start = i->Position; Ray.Set_Direction (-Dir); Ray.maxdist = (Loc - Ray.start).Length() - Small_dist; Ray.Inside = i->Inside; Ray.Importance = Imp; tmpcol = Trace_Light_Ray (Ray, i->Intensity); if (!tmpcol.TooSmall()) Arr.push_back (INCIDENT_ENTRY (tmpcol, Ray.dir)); } } } void RAYTRACER::Add (const HANDLE &Cam) { cni(); if (!Cam) error ("RAYTRACER::Add: Invalid Handle"); Camera = Cam; } void RAYTRACER::Set_Shadow_Rays (bool new_value) { cni(); Shadow_Rays = new_value; } void RAYTRACER::Set_Samples (uint1 new_samples) { cni(); if ((new_samples<1) || (new_samples>10)) error ("Bad number of samples in RAYTRACER!"); Samples = new_samples; } } // namespace RAYPP