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 CCL_NAMESPACE_BEGIN 00042 00043 using namespace OSL; 00044 00045 // anisotropic ward - leaks energy at grazing angles 00046 // see http://www.graphics.cornell.edu/~bjw/wardnotes.pdf 00047 class WardClosure : public BSDFClosure { 00048 public: 00049 Vec3 m_N; 00050 Vec3 m_T; 00051 float m_ax, m_ay; 00052 WardClosure() : BSDFClosure(Labels::GLOSSY) { } 00053 00054 void setup() 00055 { 00056 m_ax = clamp(m_ax, 1e-5f, 1.0f); 00057 m_ay = clamp(m_ay, 1e-5f, 1.0f); 00058 } 00059 00060 bool mergeable (const ClosurePrimitive *other) const { 00061 const WardClosure *comp = (const WardClosure *)other; 00062 return m_N == comp->m_N && m_T == comp->m_T && 00063 m_ax == comp->m_ax && m_ay == comp->m_ay && 00064 BSDFClosure::mergeable(other); 00065 } 00066 00067 size_t memsize () const { return sizeof(*this); } 00068 00069 const char *name () const { return "ward"; } 00070 00071 void print_on (std::ostream &out) const { 00072 out << name() << " (("; 00073 out << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ("; 00074 out << m_T[0] << ", " << m_T[1] << ", " << m_T[2] << "), "; 00075 out << m_ax << ", " << m_ay << ")"; 00076 } 00077 00078 float albedo (const Vec3 &omega_out) const 00079 { 00080 return 1.0f; 00081 } 00082 00083 Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const 00084 { 00085 float cosNO = m_N.dot(omega_out); 00086 float cosNI = m_N.dot(omega_in); 00087 if (cosNI > 0 && cosNO > 0) { 00088 // get half vector and get x,y basis on the surface for anisotropy 00089 Vec3 H = omega_in + omega_out; 00090 H.normalize(); // normalize needed for pdf 00091 Vec3 X, Y; 00092 make_orthonormals(m_N, m_T, X, Y); 00093 // eq. 4 00094 float dotx = H.dot(X) / m_ax; 00095 float doty = H.dot(Y) / m_ay; 00096 float dotn = H.dot(m_N); 00097 float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); 00098 float denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI)); 00099 float exp_val = expf(-exp_arg); 00100 float out = cosNI * exp_val / denom; 00101 float oh = H.dot(omega_out); 00102 denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn; 00103 pdf = exp_val / denom; 00104 return Color3 (out, out, out); 00105 } 00106 return Color3 (0, 0, 0); 00107 } 00108 00109 Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const 00110 { 00111 return Color3 (0, 0, 0); 00112 } 00113 00114 ustring sample (const Vec3 &Ng, 00115 const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, 00116 float randu, float randv, 00117 Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, 00118 float &pdf, Color3 &eval) const 00119 { 00120 float cosNO = m_N.dot(omega_out); 00121 if (cosNO > 0) { 00122 // get x,y basis on the surface for anisotropy 00123 Vec3 X, Y; 00124 make_orthonormals(m_N, m_T, X, Y); 00125 // generate random angles for the half vector 00126 // eq. 7 (taking care around discontinuities to keep 00127 // output angle in the right quadrant) 00128 // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) 00129 // and sin(atan(x)) == x/sqrt(1+x^2) 00130 float alphaRatio = m_ay / m_ax; 00131 float cosPhi, sinPhi; 00132 if (randu < 0.25f) { 00133 float val = 4 * randu; 00134 float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); 00135 cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); 00136 sinPhi = tanPhi * cosPhi; 00137 } else if (randu < 0.5) { 00138 float val = 1 - 4 * (0.5f - randu); 00139 float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); 00140 // phi = (float) M_PI - phi; 00141 cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); 00142 sinPhi = -tanPhi * cosPhi; 00143 } else if (randu < 0.75f) { 00144 float val = 4 * (randu - 0.5f); 00145 float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); 00146 //phi = (float) M_PI + phi; 00147 cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); 00148 sinPhi = tanPhi * cosPhi; 00149 } else { 00150 float val = 1 - 4 * (1 - randu); 00151 float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); 00152 // phi = 2 * (float) M_PI - phi; 00153 cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); 00154 sinPhi = -tanPhi * cosPhi; 00155 } 00156 // eq. 6 00157 // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) 00158 // and sin(atan(x)) == x/sqrt(1+x^2) 00159 float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay); 00160 float tanTheta2 = -logf(1 - randv) / thetaDenom; 00161 float cosTheta = 1 / sqrtf(1 + tanTheta2); 00162 float sinTheta = cosTheta * sqrtf(tanTheta2); 00163 00164 Vec3 h; // already normalized becaused expressed from spherical coordinates 00165 h.x = sinTheta * cosPhi; 00166 h.y = sinTheta * sinPhi; 00167 h.z = cosTheta; 00168 // compute terms that are easier in local space 00169 float dotx = h.x / m_ax; 00170 float doty = h.y / m_ay; 00171 float dotn = h.z; 00172 // transform to world space 00173 h = h.x * X + h.y * Y + h.z * m_N; 00174 // generate the final sample 00175 float oh = h.dot(omega_out); 00176 omega_in.x = 2 * oh * h.x - omega_out.x; 00177 omega_in.y = 2 * oh * h.y - omega_out.y; 00178 omega_in.z = 2 * oh * h.z - omega_out.z; 00179 if (Ng.dot(omega_in) > 0) { 00180 float cosNI = m_N.dot(omega_in); 00181 if (cosNI > 0) { 00182 // eq. 9 00183 float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); 00184 float denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn; 00185 pdf = expf(-exp_arg) / denom; 00186 // compiler will reuse expressions already computed 00187 denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI)); 00188 float power = cosNI * expf(-exp_arg) / denom; 00189 eval.setValue(power, power, power); 00190 domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; 00191 domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; 00192 00193 /* disabled for now - gives texture filtering problems */ 00194 #if 0 00195 // Since there is some blur to this reflection, make the 00196 // derivatives a bit bigger. In theory this varies with the 00197 // roughness but the exact relationship is complex and 00198 // requires more ops than are practical. 00199 domega_in_dx *= 10; 00200 domega_in_dy *= 10; 00201 #endif 00202 } 00203 } 00204 } 00205 return Labels::REFLECT; 00206 } 00207 }; 00208 00209 00210 00211 ClosureParam bsdf_ward_params[] = { 00212 CLOSURE_VECTOR_PARAM(WardClosure, m_N), 00213 CLOSURE_VECTOR_PARAM(WardClosure, m_T), 00214 CLOSURE_FLOAT_PARAM (WardClosure, m_ax), 00215 CLOSURE_FLOAT_PARAM (WardClosure, m_ay), 00216 CLOSURE_STRING_KEYPARAM("label"), 00217 CLOSURE_FINISH_PARAM(WardClosure) }; 00218 00219 CLOSURE_PREPARE(bsdf_ward_prepare, WardClosure) 00220 00221 CCL_NAMESPACE_END 00222