Blender V2.61 - r43446

bsdf_oren_nayar.h

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 /*
00020  *  An implementation of Oren-Nayar reflectance model, public domain
00021  *      http://www1.cs.columbia.edu/CAVE/publications/pdfs/Oren_SIGGRAPH94.pdf
00022  *
00023  *  NOTE:
00024  *      BSDF = A + B * cos() * sin() * tan()
00025  *
00026  *      The parameter sigma means different from original.
00027  *      A and B are calculated by the following formula:
00028  *          0 <= sigma <= 1
00029  *          A =     1 / ((1 + sigma / 2) * pi);
00030  *          B = sigma / ((1 + sigma / 2) * pi);
00031  *
00032  *      This formula is derived as following:
00033  *
00034  *      0. Normalize A-term and B-term of BSDF *individually*.
00035  *         B-term is normalized at maximum point: dot(L, N) = 0.
00036  *          A = (1/pi) * A'
00037  *          B = (2/pi) * B'
00038  *
00039  *      1. Solve the following equation:
00040  *          A' + B' = 1
00041  *          B / A = sigma
00042  */
00043 
00044 #ifndef __BSDF_OREN_NAYAR_H__
00045 #define __BSDF_OREN_NAYAR_H__
00046 
00047 CCL_NAMESPACE_BEGIN
00048 
00049 typedef struct BsdfOrenNayarClosure {
00050     float m_a;
00051     float m_b;
00052 } BsdfOrenNayarClosure;
00053 
00054 __device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc, float3 n, float3 v, float3 l)
00055 {
00056     float nl = max(dot(n, l), 0.0f);
00057     float nv = max(dot(n, v), 0.0f);
00058 
00059     float3 al = normalize(l - nl * n);
00060     float3 av = normalize(v - nv * n);
00061     float t = max(dot(al, av), 0.0f);
00062 
00063     float cos_a, cos_b;
00064     if(nl < nv) {
00065         cos_a = nl;
00066         cos_b = nv;
00067     }
00068     else {
00069         cos_a = nv;
00070         cos_b = nl;
00071     }
00072 
00073     float sin_a = sqrtf(max(1.0f - cos_a * cos_a, 0.0f));
00074     float tan_b = sqrtf(max(1.0f - cos_b * cos_b, 0.0f)) / max(cos_b, 1e-8f);
00075 
00076     float is = nl * (sc->data0 + sc->data1 * t * sin_a * tan_b);
00077     return make_float3(is, is, is);
00078 }
00079 
00080 __device void bsdf_oren_nayar_setup(ShaderData *sd, ShaderClosure *sc, float sigma)
00081 {
00082     sc->type = CLOSURE_BSDF_OREN_NAYAR_ID;
00083     sd->flag |= SD_BSDF | SD_BSDF_HAS_EVAL;
00084 
00085     sigma = clamp(sigma, 0.0f, 1.0f);
00086 
00087     float div = 1.0f / ((1.0f + 0.5f * sigma) * M_PI_F);
00088 
00089     sc->data0 =  1.0f * div;
00090     sc->data1 = sigma * div;
00091 }
00092 
00093 __device void bsdf_oren_nayar_blur(ShaderClosure *sc, float roughness)
00094 {
00095 }
00096 
00097 __device float3 bsdf_oren_nayar_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
00098 {
00099     if (dot(sd->N, omega_in) > 0.0f) {
00100         *pdf = 0.5f * M_1_PI_F;
00101         return bsdf_oren_nayar_get_intensity(sc, sd->N, I, omega_in);
00102     }
00103     else {
00104         *pdf = 0.0f;
00105         return make_float3(0.0f, 0.0f, 0.0f);
00106     }
00107 }
00108 
00109 __device float3 bsdf_oren_nayar_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
00110 {
00111     return make_float3(0.0f, 0.0f, 0.0f);
00112 }
00113 
00114 __device float bsdf_oren_nayar_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
00115 {
00116     return 1.0f;
00117 }
00118 
00119 __device int bsdf_oren_nayar_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)
00120 {
00121     sample_uniform_hemisphere(sd->N, randu, randv, omega_in, pdf);
00122 
00123     if (dot(sd->Ng, *omega_in) > 0.0f) {
00124         *eval = bsdf_oren_nayar_get_intensity(sc, sd->N, sd->I, *omega_in);
00125 
00126 #ifdef __RAY_DIFFERENTIALS__
00127         // TODO: find a better approximation for the bounce
00128         *domega_in_dx = (2.0f * dot(sd->N, sd->dI.dx)) * sd->N - sd->dI.dx;
00129         *domega_in_dy = (2.0f * dot(sd->N, sd->dI.dy)) * sd->N - sd->dI.dy;
00130         *domega_in_dx *= 125.0f;
00131         *domega_in_dy *= 125.0f;
00132 #endif
00133     }
00134     else {
00135         *pdf = 0.0f;
00136         *eval = make_float3(0.0f, 0.0f, 0.0f);
00137     }
00138 
00139     return LABEL_REFLECT | LABEL_DIFFUSE;
00140 }
00141 
00142 
00143 CCL_NAMESPACE_END
00144 
00145 #endif /* __BSDF_OREN_NAYAR_H__ */