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 #ifndef __BSDF_WARD_H__ 00034 #define __BSDF_WARD_H__ 00035 00036 CCL_NAMESPACE_BEGIN 00037 00038 /* WARD */ 00039 00040 typedef struct BsdfWardClosure { 00041 //float3 m_N; 00042 //float3 m_T; 00043 float m_ax; 00044 float m_ay; 00045 } BsdfWardClosure; 00046 00047 __device void bsdf_ward_setup(ShaderData *sd, ShaderClosure *sc, float3 T, float ax, float ay) 00048 { 00049 float m_ax = clamp(ax, 1e-5f, 1.0f); 00050 float m_ay = clamp(ay, 1e-5f, 1.0f); 00051 00052 sc->data0 = m_ax; 00053 sc->data1 = m_ay; 00054 00055 sc->type = CLOSURE_BSDF_WARD_ID; 00056 sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; 00057 } 00058 00059 __device void bsdf_ward_blur(ShaderClosure *sc, float roughness) 00060 { 00061 sc->data0 = fmaxf(roughness, sc->data0); 00062 sc->data1 = fmaxf(roughness, sc->data1); 00063 } 00064 00065 __device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) 00066 { 00067 float m_ax = sc->data0; 00068 float m_ay = sc->data1; 00069 float3 m_N = sd->N; 00070 float3 m_T = normalize(sd->dPdu); 00071 00072 float cosNO = dot(m_N, I); 00073 float cosNI = dot(m_N, omega_in); 00074 00075 if(cosNI > 0 && cosNO > 0) { 00076 // get half vector and get x,y basis on the surface for anisotropy 00077 float3 H = normalize(omega_in + I); // normalize needed for pdf 00078 float3 X, Y; 00079 make_orthonormals_tangent(m_N, m_T, &X, &Y); 00080 // eq. 4 00081 float dotx = dot(H, X) / m_ax; 00082 float doty = dot(H, Y) / m_ay; 00083 float dotn = dot(H, m_N); 00084 float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); 00085 float denom = (4 * M_PI_F * m_ax * m_ay * sqrtf(cosNO * cosNI)); 00086 float exp_val = expf(-exp_arg); 00087 float out = cosNI * exp_val / denom; 00088 float oh = dot(H, I); 00089 denom = 4 * M_PI_F * m_ax * m_ay * oh * dotn * dotn * dotn; 00090 *pdf = exp_val / denom; 00091 return make_float3 (out, out, out); 00092 } 00093 return make_float3 (0, 0, 0); 00094 } 00095 00096 __device float3 bsdf_ward_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) 00097 { 00098 return make_float3(0.0f, 0.0f, 0.0f); 00099 } 00100 00101 __device float bsdf_ward_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) 00102 { 00103 return 1.0f; 00104 } 00105 00106 __device int bsdf_ward_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) 00107 { 00108 float m_ax = sc->data0; 00109 float m_ay = sc->data1; 00110 float3 m_N = sd->N; 00111 float3 m_T = normalize(sd->dPdu); 00112 00113 float cosNO = dot(m_N, sd->I); 00114 if(cosNO > 0) { 00115 // get x,y basis on the surface for anisotropy 00116 float3 X, Y; 00117 make_orthonormals_tangent(m_N, m_T, &X, &Y); 00118 // generate random angles for the half vector 00119 // eq. 7 (taking care around discontinuities to keep 00120 //ttoutput angle in the right quadrant) 00121 // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) 00122 //tttt and sin(atan(x)) == x/sqrt(1+x^2) 00123 float alphaRatio = m_ay / m_ax; 00124 float cosPhi, sinPhi; 00125 if(randu < 0.25f) { 00126 float val = 4 * randu; 00127 float tanPhi = alphaRatio * tanf(M_PI_2_F * val); 00128 cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); 00129 sinPhi = tanPhi * cosPhi; 00130 } else if(randu < 0.5f) { 00131 float val = 1 - 4 * (0.5f - randu); 00132 float tanPhi = alphaRatio * tanf(M_PI_2_F * val); 00133 // phi = M_PI_F - phi; 00134 cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); 00135 sinPhi = -tanPhi * cosPhi; 00136 } else if(randu < 0.75f) { 00137 float val = 4 * (randu - 0.5f); 00138 float tanPhi = alphaRatio * tanf(M_PI_2_F * val); 00139 //phi = M_PI_F + phi; 00140 cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); 00141 sinPhi = tanPhi * cosPhi; 00142 } else { 00143 float val = 1 - 4 * (1 - randu); 00144 float tanPhi = alphaRatio * tanf(M_PI_2_F * val); 00145 // phi = 2 * M_PI_F - phi; 00146 cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); 00147 sinPhi = -tanPhi * cosPhi; 00148 } 00149 // eq. 6 00150 // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) 00151 //tttt and sin(atan(x)) == x/sqrt(1+x^2) 00152 float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay); 00153 float tanTheta2 = -logf(1 - randv) / thetaDenom; 00154 float cosTheta = 1 / sqrtf(1 + tanTheta2); 00155 float sinTheta = cosTheta * sqrtf(tanTheta2); 00156 00157 float3 h; // already normalized becaused expressed from spherical coordinates 00158 h.x = sinTheta * cosPhi; 00159 h.y = sinTheta * sinPhi; 00160 h.z = cosTheta; 00161 // compute terms that are easier in local space 00162 float dotx = h.x / m_ax; 00163 float doty = h.y / m_ay; 00164 float dotn = h.z; 00165 // transform to world space 00166 h = h.x * X + h.y * Y + h.z * m_N; 00167 // generate the final sample 00168 float oh = dot(h, sd->I); 00169 *omega_in = 2.0f * oh * h - sd->I; 00170 if(dot(sd->Ng, *omega_in) > 0) { 00171 float cosNI = dot(m_N, *omega_in); 00172 if(cosNI > 0) { 00173 // eq. 9 00174 float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); 00175 float denom = 4 * M_PI_F * m_ax * m_ay * oh * dotn * dotn * dotn; 00176 *pdf = expf(-exp_arg) / denom; 00177 // compiler will reuse expressions already computed 00178 denom = (4 * M_PI_F * m_ax * m_ay * sqrtf(cosNO * cosNI)); 00179 float power = cosNI * expf(-exp_arg) / denom; 00180 *eval = make_float3(power, power, power); 00181 #ifdef __RAY_DIFFERENTIALS__ 00182 *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; 00183 *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; 00184 // Since there is some blur to this reflection, make the 00185 // derivatives a bit bigger. In theory this varies with the 00186 // roughness but the exact relationship is complex and 00187 // requires more ops than are practical. 00188 *domega_in_dx *= 10.0f; 00189 *domega_in_dy *= 10.0f; 00190 #endif 00191 } 00192 } 00193 } 00194 return LABEL_REFLECT|LABEL_GLOSSY; 00195 } 00196 00197 CCL_NAMESPACE_END 00198 00199 #endif /* __BSDF_WARD_H__ */ 00200