Blender V2.61 - r43446

bsdf_microfacet.cpp

Go to the documentation of this file.
00001 /*
00002  * Adapted from Open Shading Language with this license:
00003  *
00004  * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
00005  * All Rights Reserved.
00006  *
00007  * Modifications Copyright 2011, Blender Foundation.
00008  * 
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions are
00011  * met:
00012  * * Redistributions of source code must retain the above copyright
00013  *   notice, this list of conditions and the following disclaimer.
00014  * * Redistributions in binary form must reproduce the above copyright
00015  *   notice, this list of conditions and the following disclaimer in the
00016  *   documentation and/or other materials provided with the distribution.
00017  * * Neither the name of Sony Pictures Imageworks nor the names of its
00018  *   contributors may be used to endorse or promote products derived from
00019  *   this software without specific prior written permission.
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00023  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00024  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00026  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00027  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00028  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00030  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 
00033 #include <OpenImageIO/fmath.h>
00034 
00035 #include <OSL/genclosure.h>
00036 
00037 #include "osl_closures.h"
00038 
00039 #include "util_math.h"
00040 
00041 using namespace OSL;
00042 
00043 CCL_NAMESPACE_BEGIN
00044 
00045 // TODO: fresnel_dielectric is only used for derivatives, could be optimized
00046 
00047 // TODO: refactor these two classes so they share everything by the microfacet
00048 //       distribution terms
00049 
00050 // microfacet model with GGX facet distribution
00051 // see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf
00052 template <int Refractive = 0>
00053 class MicrofacetGGXClosure : public BSDFClosure {
00054 public:
00055     Vec3 m_N;
00056     float m_ag;   // width parameter (roughness)
00057     float m_eta;  // index of refraction (for fresnel term)
00058     MicrofacetGGXClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { m_eta = 1.0f; }
00059 
00060     void setup()
00061     {
00062         m_ag = clamp(m_ag, 1e-5f, 1.0f);
00063     }
00064 
00065     bool mergeable (const ClosurePrimitive *other) const {
00066         const MicrofacetGGXClosure *comp = (const MicrofacetGGXClosure *)other;
00067         return m_N == comp->m_N && m_ag == comp->m_ag &&
00068             m_eta == comp->m_eta && BSDFClosure::mergeable(other);
00069     }
00070 
00071     size_t memsize () const { return sizeof(*this); }
00072 
00073     const char *name () const {
00074         return Refractive ? "microfacet_ggx_refraction" : "microfacet_ggx";
00075     }
00076 
00077     void print_on (std::ostream &out) const {
00078         out << name() << " (";
00079         out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
00080         out << m_ag << ", ";
00081         out << m_eta;
00082         out << ")";
00083     }
00084 
00085     float albedo (const Vec3 &omega_out) const
00086     {
00087         return 1.0f;
00088     }
00089 
00090     Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
00091     {
00092         if (Refractive == 1) return Color3 (0, 0, 0);
00093         float cosNO = m_N.dot(omega_out);
00094         float cosNI = m_N.dot(omega_in);
00095         if (cosNI > 0 && cosNO > 0) {
00096             // get half vector
00097             Vec3 Hr = omega_in + omega_out;
00098             Hr.normalize();
00099             // eq. 20: (F*G*D)/(4*in*on)
00100             // eq. 33: first we calculate D(m) with m=Hr:
00101             float alpha2 = m_ag * m_ag;
00102             float cosThetaM = m_N.dot(Hr);
00103             float cosThetaM2 = cosThetaM * cosThetaM;
00104             float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
00105             float cosThetaM4 = cosThetaM2 * cosThetaM2;
00106             float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
00107             // eq. 34: now calculate G1(i,m) and G1(o,m)
00108             float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
00109             float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); 
00110             float G = G1o * G1i;
00111             float out = (G * D) * 0.25f / cosNO;
00112             // eq. 24
00113             float pm = D * cosThetaM;
00114             // convert into pdf of the sampled direction
00115             // eq. 38 - but see also:
00116             // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
00117             pdf = pm * 0.25f / Hr.dot(omega_out);
00118             return Color3 (out, out, out);
00119         }
00120         return Color3 (0, 0, 0);
00121     }
00122 
00123     Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
00124     {
00125         if (Refractive == 0) return Color3 (0, 0, 0);
00126         float cosNO = m_N.dot(omega_out);
00127         float cosNI = m_N.dot(omega_in);
00128         if (cosNO <= 0 || cosNI >= 0)
00129             return Color3 (0, 0, 0); // vectors on same side -- not possible
00130         // compute half-vector of the refraction (eq. 16)
00131         Vec3 ht = -(m_eta * omega_in + omega_out);
00132         Vec3 Ht = ht; Ht.normalize();
00133         float cosHO = Ht.dot(omega_out);
00134 
00135         float cosHI = Ht.dot(omega_in);
00136         // eq. 33: first we calculate D(m) with m=Ht:
00137         float alpha2 = m_ag * m_ag;
00138         float cosThetaM = m_N.dot(Ht);
00139         float cosThetaM2 = cosThetaM * cosThetaM;
00140         float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
00141         float cosThetaM4 = cosThetaM2 * cosThetaM2;
00142         float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
00143         // eq. 34: now calculate G1(i,m) and G1(o,m)
00144         float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
00145         float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); 
00146         float G = G1o * G1i;
00147         // probability
00148         float invHt2 = 1 / ht.dot(ht);
00149         pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
00150         float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
00151         return Color3 (out, out, out);
00152     }
00153 
00154     ustring sample (const Vec3 &Ng,
00155                  const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
00156                  float randu, float randv,
00157                  Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
00158                  float &pdf, Color3 &eval) const
00159     {
00160         float cosNO = m_N.dot(omega_out);
00161         if (cosNO > 0) {
00162             Vec3 X, Y, Z = m_N;
00163             make_orthonormals(Z, X, Y);
00164             // generate a random microfacet normal m
00165             // eq. 35,36:
00166             // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
00167             //                  and sin(atan(x)) == x/sqrt(1+x^2)
00168             float alpha2 = m_ag * m_ag;
00169             float tanThetaM2 = alpha2 * randu / (1 - randu);
00170             float cosThetaM  = 1 / sqrtf(1 + tanThetaM2);
00171             float sinThetaM  = cosThetaM * sqrtf(tanThetaM2);
00172             float phiM = 2 * float(M_PI) * randv;
00173             Vec3 m = (cosf(phiM) * sinThetaM) * X +
00174                      (sinf(phiM) * sinThetaM) * Y +
00175                                    cosThetaM  * Z;
00176             if (Refractive == 0) {
00177                 float cosMO = m.dot(omega_out);
00178                 if (cosMO > 0) {
00179                     // eq. 39 - compute actual reflected direction
00180                     omega_in = 2 * cosMO * m - omega_out;
00181                     if (Ng.dot(omega_in) > 0) {
00182                         // microfacet normal is visible to this ray
00183                         // eq. 33
00184                         float cosThetaM2 = cosThetaM * cosThetaM;
00185                         float cosThetaM4 = cosThetaM2 * cosThetaM2;
00186                         float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
00187                         // eq. 24
00188                         float pm = D * cosThetaM;
00189                         // convert into pdf of the sampled direction
00190                         // eq. 38 - but see also:
00191                         // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
00192                         pdf = pm * 0.25f / cosMO;
00193                         // eval BRDF*cosNI
00194                         float cosNI = m_N.dot(omega_in);
00195                         // eq. 34: now calculate G1(i,m) and G1(o,m)
00196                         float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
00197                         float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); 
00198                         float G = G1o * G1i;
00199                         // eq. 20: (F*G*D)/(4*in*on)
00200                         float out = (G * D) * 0.25f / cosNO;
00201                         eval.setValue(out, out, out);
00202                         domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
00203                         domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
00204 
00205                         /* disabled for now - gives texture filtering problems */
00206 #if 0
00207                         // Since there is some blur to this reflection, make the
00208                         // derivatives a bit bigger. In theory this varies with the
00209                         // roughness but the exact relationship is complex and
00210                         // requires more ops than are practical.
00211                         domega_in_dx *= 10;
00212                         domega_in_dy *= 10;
00213 #endif
00214                     }
00215                 }
00216             } else {
00217                 // CAUTION: the i and o variables are inverted relative to the paper
00218                 // eq. 39 - compute actual refractive direction
00219                 Vec3 R, dRdx, dRdy;
00220                 Vec3 T, dTdx, dTdy;
00221                 bool inside;
00222                 fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
00223                                    R, dRdx, dRdy,
00224                                    T, dTdx, dTdy,
00225                                    inside);
00226 
00227                 if (!inside) {
00228                     omega_in = T;
00229                     domega_in_dx = dTdx;
00230                     domega_in_dy = dTdy;
00231                     // eq. 33
00232                     float cosThetaM2 = cosThetaM * cosThetaM;
00233                     float cosThetaM4 = cosThetaM2 * cosThetaM2;
00234                     float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
00235                     // eq. 24
00236                     float pm = D * cosThetaM;
00237                     // eval BRDF*cosNI
00238                     float cosNI = m_N.dot(omega_in);
00239                     // eq. 34: now calculate G1(i,m) and G1(o,m)
00240                     float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
00241                     float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); 
00242                     float G = G1o * G1i;
00243                     // eq. 21
00244                     float cosHI = m.dot(omega_in);
00245                     float cosHO = m.dot(omega_out);
00246                     float Ht2 = m_eta * cosHI + cosHO;
00247                     Ht2 *= Ht2;
00248                     float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
00249                     // eq. 38 and eq. 17
00250                     pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
00251                     eval.setValue(out, out, out);
00252 
00253                     /* disabled for now - gives texture filtering problems */
00254 #if 0
00255                     // Since there is some blur to this refraction, make the
00256                     // derivatives a bit bigger. In theory this varies with the
00257                     // roughness but the exact relationship is complex and
00258                     // requires more ops than are practical.
00259                     domega_in_dx *= 10;
00260                     domega_in_dy *= 10;
00261 #endif
00262                 }
00263             }
00264         }
00265         return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
00266     }
00267 };
00268 
00269 // microfacet model with Beckmann facet distribution
00270 // see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf
00271 template <int Refractive = 0>
00272 class MicrofacetBeckmannClosure : public BSDFClosure {
00273 public:
00274     Vec3 m_N;
00275     float m_ab;   // width parameter (roughness)
00276     float m_eta;  // index of refraction (for fresnel term)
00277     MicrofacetBeckmannClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { }
00278 
00279     void setup()
00280     {
00281         m_ab = clamp(m_ab, 1e-5f, 1.0f);
00282     }
00283 
00284     bool mergeable (const ClosurePrimitive *other) const {
00285         const MicrofacetBeckmannClosure *comp = (const MicrofacetBeckmannClosure *)other;
00286         return m_N == comp->m_N && m_ab == comp->m_ab &&
00287             m_eta == comp->m_eta && BSDFClosure::mergeable(other);
00288     }
00289 
00290     size_t memsize () const { return sizeof(*this); }
00291 
00292     const char * name () const {
00293         return Refractive ? "microfacet_beckmann_refraction" 
00294                           : "microfacet_beckmann";
00295     }
00296 
00297     void print_on (std::ostream &out) const
00298     {
00299         out << name() << " (";
00300         out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
00301         out << m_ab << ", ";
00302         out << m_eta;
00303         out << ")";
00304     }
00305 
00306     float albedo (const Vec3 &omega_out) const
00307     {
00308         return 1.0f;
00309     }
00310 
00311     Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
00312     {
00313         if (Refractive == 1) return Color3 (0, 0, 0);
00314         float cosNO = m_N.dot(omega_out);
00315         float cosNI = m_N.dot(omega_in);
00316         if (cosNO > 0 && cosNI > 0) {
00317            // get half vector
00318            Vec3 Hr = omega_in + omega_out;
00319            Hr.normalize();
00320            // eq. 20: (F*G*D)/(4*in*on)
00321            // eq. 25: first we calculate D(m) with m=Hr:
00322            float alpha2 = m_ab * m_ab;
00323            float cosThetaM = m_N.dot(Hr);
00324            float cosThetaM2 = cosThetaM * cosThetaM;
00325            float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
00326            float cosThetaM4 = cosThetaM2 * cosThetaM2;
00327            float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 *  cosThetaM4);
00328            // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
00329            float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
00330            float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
00331            float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
00332            float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
00333            float G = G1o * G1i;
00334            float out = (G * D) * 0.25f / cosNO;
00335            // eq. 24
00336            float pm = D * cosThetaM;
00337            // convert into pdf of the sampled direction
00338            // eq. 38 - but see also:
00339            // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
00340            pdf = pm * 0.25f / Hr.dot(omega_out);
00341            return Color3 (out, out, out);
00342         }
00343         return Color3 (0, 0, 0);
00344     }
00345 
00346     Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
00347     {
00348         if (Refractive == 0) return Color3 (0, 0, 0);
00349         float cosNO = m_N.dot(omega_out);
00350         float cosNI = m_N.dot(omega_in);
00351         if (cosNO <= 0 || cosNI >= 0)
00352             return Color3 (0, 0, 0);
00353         // compute half-vector of the refraction (eq. 16)
00354         Vec3 ht = -(m_eta * omega_in + omega_out);
00355         Vec3 Ht = ht; Ht.normalize();
00356         float cosHO = Ht.dot(omega_out);
00357 
00358         float cosHI = Ht.dot(omega_in);
00359         // eq. 33: first we calculate D(m) with m=Ht:
00360         float alpha2 = m_ab * m_ab;
00361         float cosThetaM = m_N.dot(Ht);
00362         float cosThetaM2 = cosThetaM * cosThetaM;
00363         float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
00364         float cosThetaM4 = cosThetaM2 * cosThetaM2;
00365         float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 *  cosThetaM4);
00366         // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
00367         float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
00368         float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
00369         float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
00370         float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
00371         float G = G1o * G1i;
00372         // probability
00373         float invHt2 = 1 / ht.dot(ht);
00374         pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
00375         float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
00376         return Color3 (out, out, out);
00377     }
00378 
00379     ustring sample (const Vec3 &Ng,
00380                  const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
00381                  float randu, float randv,
00382                  Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
00383                  float &pdf, Color3 &eval) const
00384     {
00385         float cosNO = m_N.dot(omega_out);
00386         if (cosNO > 0) {
00387             Vec3 X, Y, Z = m_N;
00388             make_orthonormals(Z, X, Y);
00389             // generate a random microfacet normal m
00390             // eq. 35,36:
00391             // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
00392             //                  and sin(atan(x)) == x/sqrt(1+x^2)
00393             float alpha2 = m_ab * m_ab;
00394             float tanThetaM = sqrtf(-alpha2 * logf(1 - randu));
00395             float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM);
00396             float sinThetaM = cosThetaM * tanThetaM;
00397             float phiM = 2 * float(M_PI) * randv;
00398             Vec3 m = (cosf(phiM) * sinThetaM) * X +
00399                      (sinf(phiM) * sinThetaM) * Y +
00400                                    cosThetaM  * Z;
00401             if (Refractive == 0) {
00402                 float cosMO = m.dot(omega_out);
00403                 if (cosMO > 0) {
00404                     // eq. 39 - compute actual reflected direction
00405                     omega_in = 2 * cosMO * m - omega_out;
00406                     if (Ng.dot(omega_in) > 0) {
00407                         // microfacet normal is visible to this ray
00408                         // eq. 25
00409                         float cosThetaM2 = cosThetaM * cosThetaM;
00410                         float tanThetaM2 = tanThetaM * tanThetaM;
00411                         float cosThetaM4 = cosThetaM2 * cosThetaM2;
00412                         float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 *  cosThetaM4);
00413                         // eq. 24
00414                         float pm = D * cosThetaM;
00415                         // convert into pdf of the sampled direction
00416                         // eq. 38 - but see also:
00417                         // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
00418                         pdf = pm * 0.25f / cosMO;
00419                         // Eval BRDF*cosNI
00420                         float cosNI = m_N.dot(omega_in);
00421                         // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
00422                         float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
00423                         float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
00424                         float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
00425                         float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
00426                         float G = G1o * G1i;
00427                         // eq. 20: (F*G*D)/(4*in*on)
00428                         float out = (G * D) * 0.25f / cosNO;
00429                         eval.setValue(out, out, out);
00430                         domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
00431                         domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
00432 
00433                         /* disabled for now - gives texture filtering problems */
00434 #if 0
00435                         // Since there is some blur to this reflection, make the
00436                         // derivatives a bit bigger. In theory this varies with the
00437                         // roughness but the exact relationship is complex and
00438                         // requires more ops than are practical.
00439                         domega_in_dx *= 10;
00440                         domega_in_dy *= 10;
00441 #endif
00442                     }
00443                 }
00444             } else {
00445                 // CAUTION: the i and o variables are inverted relative to the paper
00446                 // eq. 39 - compute actual refractive direction
00447                 Vec3 R, dRdx, dRdy;
00448                 Vec3 T, dTdx, dTdy;
00449                 bool inside;
00450                 fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
00451                                    R, dRdx, dRdy,
00452                                    T, dTdx, dTdy,
00453                                    inside);
00454                 if (!inside) {
00455                     omega_in = T;
00456                     domega_in_dx = dTdx;
00457                     domega_in_dy = dTdy;
00458                     // eq. 33
00459                     float cosThetaM2 = cosThetaM * cosThetaM;
00460                     float tanThetaM2 = tanThetaM * tanThetaM;
00461                     float cosThetaM4 = cosThetaM2 * cosThetaM2;
00462                     float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 *  cosThetaM4);
00463                     // eq. 24
00464                     float pm = D * cosThetaM;
00465                     // eval BRDF*cosNI
00466                     float cosNI = m_N.dot(omega_in);
00467                     // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
00468                     float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
00469                     float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
00470                     float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
00471                     float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
00472                     float G = G1o * G1i;
00473                     // eq. 21
00474                     float cosHI = m.dot(omega_in);
00475                     float cosHO = m.dot(omega_out);
00476                     float Ht2 = m_eta * cosHI + cosHO;
00477                     Ht2 *= Ht2;
00478                     float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
00479                     // eq. 38 and eq. 17
00480                     pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
00481                     eval.setValue(out, out, out);
00482 
00483                     /* disabled for now - gives texture filtering problems */
00484 #if 0
00485                     // Since there is some blur to this refraction, make the
00486                     // derivatives a bit bigger. In theory this varies with the
00487                     // roughness but the exact relationship is complex and
00488                     // requires more ops than are practical.
00489                     domega_in_dx *= 10;
00490                     domega_in_dy *= 10;
00491 #endif
00492                 }
00493             }
00494         }
00495         return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
00496     }
00497 };
00498 
00499 
00500 
00501 ClosureParam bsdf_microfacet_ggx_params[] = {
00502     CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N),
00503     CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<0>, m_ag),
00504     CLOSURE_STRING_KEYPARAM("label"),
00505     CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>) };
00506 
00507 ClosureParam bsdf_microfacet_ggx_refraction_params[] = {
00508     CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N),
00509     CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_ag),
00510     CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_eta),
00511     CLOSURE_STRING_KEYPARAM("label"),
00512     CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>) };
00513 
00514 ClosureParam bsdf_microfacet_beckmann_params[] = {
00515     CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N),
00516     CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<0>, m_ab),
00517     CLOSURE_STRING_KEYPARAM("label"),
00518     CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>) };
00519 
00520 ClosureParam bsdf_microfacet_beckmann_refraction_params[] = {
00521     CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N),
00522     CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_ab),
00523     CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_eta),
00524     CLOSURE_STRING_KEYPARAM("label"),
00525     CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>) };
00526 
00527 CLOSURE_PREPARE(bsdf_microfacet_ggx_prepare,                 MicrofacetGGXClosure<0>)
00528 CLOSURE_PREPARE(bsdf_microfacet_ggx_refraction_prepare,      MicrofacetGGXClosure<1>)
00529 CLOSURE_PREPARE(bsdf_microfacet_beckmann_prepare,            MicrofacetBeckmannClosure<0>)
00530 CLOSURE_PREPARE(bsdf_microfacet_beckmann_refraction_prepare, MicrofacetBeckmannClosure<1>)
00531 
00532 CCL_NAMESPACE_END
00533