Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

bsdf.cpp

Go to the documentation of this file.
00001 /*
00002     toxic - A Global Illumination Renderer
00003     Copyright (C) 2003-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of toxic.
00007 
00008     toxic is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     toxic is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with toxic; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "bsdf.h"   // include first
00024 #include "context.h"
00025 
00026 #include <cassert>
00027 
00028 using namespace sheep;
00029 using namespace std;
00030 using namespace toxic;
00031 
00032 BSDF::BSDF() :
00033     m_total_weight(0.0)
00034 {
00035 }
00036 
00037 void BSDF::Insert(const IBRDF *brdf, Real weight) {
00038     assert(brdf);
00039     assert(weight >= 0.0 && weight <= 1.0);
00040 
00041     m_brdfs.push_back(make_pair(brdf, weight));
00042 
00043     if(brdf->IsSpecular())
00044         m_specular_brdfs.push_back(make_pair(brdf, weight));
00045 
00046     m_total_weight += weight;
00047     assert(m_total_weight <= 1.0);
00048 }
00049 
00050 void BSDF::Insert(const IBTDF *btdf, Real weight) {
00051     assert(btdf);
00052     assert(weight >= 0.0 && weight <= 1.0);
00053 
00054     m_btdfs.push_back(make_pair(btdf, weight));
00055 
00056     if(btdf->IsSpecular())
00057         m_specular_btdfs.push_back(make_pair(btdf, weight));
00058 
00059     m_total_weight += weight;
00060     assert(m_total_weight <= 1.0);
00061 }
00062 
00063 Real BSDF::Evaluate(const Context &context,
00064                     const Vector3 &incoming,
00065                     const Vector3 &outgoing) const
00066 {
00067     assert(incoming.m_y > 0.0);
00068     assert(incoming.IsUnitLength());
00069     assert(outgoing.m_y > 0.0);
00070     assert(outgoing.IsUnitLength());
00071 
00072     Real value = 0.0;
00073 
00074     if(incoming.m_y * outgoing.m_y >= 0.0) {
00075         // Same hemisphere: evaluate BRDFs.
00076         for(brdf_vector_const_it i = m_brdfs.begin(), e = m_brdfs.end(); i != e; ++i)
00077             value += i->second * i->first->Evaluate(context, incoming, outgoing);
00078     } else {
00079         // Opposite hemispheres: evaluate BTDFs.
00080         for(btdf_vector_const_it i = m_btdfs.begin(), e = m_btdfs.end(); i != e; ++i)
00081             value += i->second * i->first->Evaluate(context, incoming, outgoing);
00082     }
00083 
00084 //  assert(value <= 1.0);
00085 
00086     return value;
00087 }
00088 
00089 Real BSDF::EvaluateSpecular(const Context &context,
00090                             const Vector3 &incoming,
00091                             Vector3 *outgoing) const
00092 {
00093     assert(incoming.m_y > 0.0);
00094     assert(incoming.IsUnitLength());
00095     assert(outgoing);
00096 
00097     // Uniformly choose amongst available specular BRDFs and BTDFs.
00098     //!\todo Sample according to the albedo or the weight of the component.
00099     const int index = context.m_rng->RandomInt(0, m_specular_brdfs.size() + m_specular_btdfs.size() - 1);
00100     const IBDF *chosen_bdf;
00101     Real chosen_bdf_weight;
00102     if(index < m_specular_brdfs.size()) {
00103         chosen_bdf = m_specular_brdfs[index].first;
00104         chosen_bdf_weight = m_specular_brdfs[index].second;
00105     } else {
00106         chosen_bdf = m_specular_btdfs[index - m_specular_brdfs.size()].first;
00107         chosen_bdf_weight = m_specular_btdfs[index - m_specular_brdfs.size()].second;
00108     }
00109 
00110     // Sample according to the chosen BDF.
00111     return chosen_bdf_weight * chosen_bdf->EvaluateSpecular(context, incoming, outgoing);
00112 }
00113 
00114 void BSDF::Sample(const Context &context,
00115                   const Vector3 &incoming,
00116                   Vector3 *outgoing,
00117                   Real *prob,
00118                   Real *value) const
00119 {
00120     assert(incoming.m_y > 0.0);
00121     assert(incoming.IsUnitLength());
00122     assert(outgoing);
00123     assert(prob);
00124     assert(value);
00125 
00126     // Uniformly choose amongst available BRDFs and BTDFs.
00127     //!\todo Sample according to the albedo or the weight of the component.
00128     const int index = context.m_rng->RandomInt(0, m_brdfs.size() + m_btdfs.size() - 1);
00129     const IBDF *chosen_bdf;
00130     if(index < m_brdfs.size())
00131         chosen_bdf = m_brdfs[index].first;
00132     else chosen_bdf = m_btdfs[index - m_brdfs.size()].first;
00133 
00134     // Sample according to the chosen BDF.
00135     chosen_bdf->Sample(context, incoming, outgoing, prob, value);
00136 
00137     // We're using multiple importance sampling here.
00138 
00139     for(brdf_vector_const_it i = m_brdfs.begin(), e = m_brdfs.end(); i != e; ++i) {
00140         if(i->first != chosen_bdf)
00141             *prob += i->first->ComputeScatteringProbability(incoming, *outgoing);
00142     }
00143 
00144     for(btdf_vector_const_it i = m_btdfs.begin(), e = m_btdfs.end(); i != e; ++i) {
00145         if(i->first != chosen_bdf)
00146             *prob += i->first->ComputeScatteringProbability(incoming, *outgoing);
00147     }
00148 
00149     //!\todo Precompute the division.
00150     *prob /= m_brdfs.size() + m_btdfs.size();
00151 
00152     assert(*prob <= 1.0);
00153 }
00154 
00155 Real BSDF::ComputeScatteringProbability(const Vector3 &incoming,
00156                                         const Vector3 &outgoing) const
00157 {
00158     // We're using multiple importance sampling here.
00159 
00160     Real scatteringprob = 0.0;
00161 
00162     for(brdf_vector_const_it i = m_brdfs.begin(), e = m_brdfs.end(); i != e; ++i)
00163         scatteringprob += i->first->ComputeScatteringProbability(incoming, outgoing);
00164 
00165     for(btdf_vector_const_it i = m_btdfs.begin(), e = m_btdfs.end(); i != e; ++i)
00166         scatteringprob += i->first->ComputeScatteringProbability(incoming, outgoing);
00167 
00168     //!\todo Precompute the division.
00169     scatteringprob /= m_brdfs.size() + m_btdfs.size();
00170 
00171     assert(scatteringprob <= 1.0);
00172 
00173     return scatteringprob;
00174 }
00175 
00176 Real BSDF::ComputeReflectance(const Context &context) const {
00177     Real reflectance = 0.0;
00178 
00179     for(brdf_vector_const_it i = m_brdfs.begin(), e = m_brdfs.end(); i != e; ++i)
00180         reflectance += i->second * i->first->ComputeReflectance(context);
00181 
00182     for(btdf_vector_const_it i = m_btdfs.begin(), e = m_btdfs.end(); i != e; ++i)
00183         reflectance += i->second * i->first->ComputeReflectance(context);
00184 
00185     return reflectance;
00186 }
00187 
00188 Real BSDF::ComputeReflectance(const Context &context,
00189                               const Vector3 &incoming) const
00190 {
00191     assert(incoming.m_y > 0.0);
00192     assert(incoming.IsUnitLength());
00193 
00194     Real reflectance = 0.0;
00195 
00196     for(brdf_vector_const_it i = m_brdfs.begin(), e = m_brdfs.end(); i != e; ++i)
00197         reflectance += i->second * i->first->ComputeReflectance(context, incoming);
00198 
00199     for(btdf_vector_const_it i = m_btdfs.begin(), e = m_btdfs.end(); i != e; ++i)
00200         reflectance += i->second * i->first->ComputeReflectance(context, incoming);
00201 
00202     return reflectance;
00203 }

Generated on Tue May 11 01:31:49 2004 for toxic by doxygen 1.3.6