Blender V2.61 - r43446

bsdf_ward.h

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 #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