Blender V2.61 - r43446
|
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