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