Blender V2.61 - r43446

bsdf_oren_nayar.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 /*
00020  *  An implementation of Oren-Nayar reflectance model, public domain
00021  *      http://www1.cs.columbia.edu/CAVE/publications/pdfs/Oren_SIGGRAPH94.pdf
00022  *
00023  *  NOTE:
00024  *      BSDF = A + B * cos() * sin() * tan()
00025  *
00026  *      The parameter sigma means different from original.
00027  *      A and B are calculated by the following formula:
00028  *          0 <= sigma <= 1
00029  *          A =     1 / ((1 + sigma / 2) * pi);
00030  *          B = sigma / ((1 + sigma / 2) * pi);
00031  *
00032  *      This formula is derived as following:
00033  *
00034  *      0. Normalize A-term and B-term of BSDF *individually*.
00035  *         B-term is normalized at maximum point: dot(L, N) = 0.
00036  *          A = (1/pi) * A'
00037  *          B = (2/pi) * B'
00038  *
00039  *      1. Solve the following equation:
00040  *          A' + B' = 1
00041  *          B / A = sigma
00042  */
00043 
00044 #include <OpenImageIO/fmath.h>
00045 #include <OSL/genclosure.h>
00046 #include "osl_closures.h"
00047 
00048 CCL_NAMESPACE_BEGIN
00049 
00050 using namespace OSL;
00051 
00052 
00053 class OrenNayarClosure: public BSDFClosure {
00054 public:
00055     Vec3 m_N;
00056     float m_sigma;
00057     float m_a, m_b;
00058 
00059     OrenNayarClosure(): BSDFClosure(Labels::DIFFUSE) {}
00060 
00061     void setup() {
00062         m_sigma = clamp(m_sigma, 0.0f, 1.0f);
00063         m_a =    1.0f / ((1.0f + 0.5f * m_sigma) * M_PI);
00064         m_b = m_sigma / ((1.0f + 0.5f * m_sigma) * M_PI);
00065     }
00066 
00067     bool mergeable(const ClosurePrimitive* other) const {
00068         const OrenNayarClosure* comp = static_cast<const OrenNayarClosure*>(other);
00069         return
00070             m_N == comp->m_N &&
00071             m_sigma == comp->m_sigma &&
00072             BSDFClosure::mergeable(other);
00073     }
00074 
00075     size_t memsize() const {
00076         return sizeof(*this);
00077     }
00078 
00079     const char* name() const {
00080         return "oren_nayar";
00081     }
00082 
00083     void print_on(std::ostream& out) const {
00084         out << name() << " (";
00085         out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
00086         out << m_sigma;
00087         out << ")";
00088     }
00089 
00090     float albedo(const Vec3& omega_out) const {
00091         return 1.0f;
00092     }
00093 
00094     Color3 eval_reflect(const Vec3& omega_out, const Vec3& omega_in, float& pdf) const {
00095         if (m_N.dot(omega_in) > 0.0f) {
00096             pdf = float(0.5 * M_1_PI);
00097             float is = get_intensity(m_N, omega_out, omega_in);
00098             return Color3(is, is, is);
00099         }
00100         else {
00101             pdf = 0.0f;
00102             return Color3(0.0f, 0.0f, 0.0f);
00103         }
00104     }
00105 
00106     Color3 eval_transmit(const Vec3& omega_out, const Vec3& omega_in, float& pdf) const {
00107         return Color3(0.0f, 0.0f, 0.0f);
00108     }
00109 
00110     ustring sample(
00111         const Vec3& Ng,
00112         const Vec3& omega_out, const Vec3& domega_out_dx, const Vec3& domega_out_dy,
00113         float randu, float randv,
00114         Vec3& omega_in, Vec3& domega_in_dx, Vec3& domega_in_dy,
00115         float& pdf, Color3& eval
00116     ) const {
00117         sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf);
00118 
00119         if (Ng.dot(omega_in) > 0.0f) {
00120             float is = get_intensity(m_N, omega_out, omega_in);
00121             eval.setValue(is, is, is);
00122 
00123             // TODO: find a better approximation for the bounce
00124             domega_in_dx = (2.0f * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
00125             domega_in_dy = (2.0f * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
00126             domega_in_dx *= 125.0f;
00127             domega_in_dy *= 125.0f;
00128         }
00129         else {
00130             pdf = 0.0f;
00131         }
00132 
00133         return Labels::REFLECT;
00134     }
00135 
00136 private:
00137     float get_intensity(Vec3 const& n, Vec3 const& v, Vec3 const& l) const {
00138         float nl = max(n.dot(l), 0.0f);
00139         float nv = max(n.dot(v), 0.0f);
00140 
00141         Vec3 al = l - nl * n;
00142         al.normalize();
00143         Vec3 av = v - nv * n;
00144         av.normalize();
00145         float t = max(al.dot(av), 0.0f);
00146 
00147         float cos_a, cos_b;
00148         if (nl < nv) {
00149             cos_a = nl;
00150             cos_b = nv;
00151         }
00152         else {
00153             cos_a = nv;
00154             cos_b = nl;
00155         }
00156 
00157         float sin_a = sqrtf(1.0f - cos_a * cos_a);
00158         float tan_b = sqrtf(1.0f - cos_b * cos_b) / (cos_b + FLT_MIN);
00159 
00160         return nl * (m_a + m_b * t * sin_a * tan_b);
00161     }
00162 };
00163 
00164 ClosureParam bsdf_oren_nayar_params[] = {
00165     CLOSURE_VECTOR_PARAM    (OrenNayarClosure, m_N),
00166     CLOSURE_FLOAT_PARAM     (OrenNayarClosure, m_sigma),
00167     CLOSURE_STRING_KEYPARAM ("label"),
00168     CLOSURE_FINISH_PARAM    (OrenNayarClosure)
00169 };
00170 
00171 CLOSURE_PREPARE(bsdf_oren_nayar_prepare, OrenNayarClosure)
00172 
00173 
00174 CCL_NAMESPACE_END