diff options
Diffstat (limited to 'intern/cycles/kernel/svm/bsdf_oren_nayar.h')
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_oren_nayar.h | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/intern/cycles/kernel/svm/bsdf_oren_nayar.h b/intern/cycles/kernel/svm/bsdf_oren_nayar.h new file mode 100644 index 00000000000..9eefdffe6ae --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_oren_nayar.h @@ -0,0 +1,143 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * An implementation of Oren-Nayar reflectance model, public domain + * http://www1.cs.columbia.edu/CAVE/publications/pdfs/Oren_SIGGRAPH94.pdf + * + * NOTE: + * BSDF = A + B * cos() * sin() * tan() + * + * The parameter sigma means different from original. + * A and B are calculated by the following formula: + * 0 <= sigma <= 1 + * A = 1 / ((1 + sigma / 2) * pi); + * B = sigma / ((1 + sigma / 2) * pi); + * + * This formula is derived as following: + * + * 0. Normalize A-term and B-term of BSDF *individually*. + * B-term is normalized at maximum point: dot(L, N) = 0. + * A = (1/pi) * A' + * B = (2/pi) * B' + * + * 1. Solve the following equation: + * A' + B' = 1 + * B / A = sigma + */ + +#ifndef __BSDF_OREN_NAYAR_H__ +#define __BSDF_OREN_NAYAR_H__ + +CCL_NAMESPACE_BEGIN + +typedef struct BsdfOrenNayarClosure { + float m_a; + float m_b; +} BsdfOrenNayarClosure; + +__device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc, float3 n, float3 v, float3 l) +{ + float nl = max(dot(n, l), 0.0f); + float nv = max(dot(n, v), 0.0f); + + float3 al = normalize(l - nl * n); + float3 av = normalize(v - nv * n); + float t = max(dot(al, av), 0.0f); + + float cos_a, cos_b; + if(nl < nv) { + cos_a = nl; + cos_b = nv; + } + else { + cos_a = nv; + cos_b = nl; + } + + float sin_a = sqrtf(1.0f - cos_a * cos_a); + float tan_b = sqrtf(1.0f - cos_b * cos_b) / (cos_b + FLT_MIN); + + float is = nl * (sc->data0 + sc->data1 * t * sin_a * tan_b); + return make_float3(is, is, is); +} + +__device void bsdf_oren_nayar_setup(ShaderData *sd, ShaderClosure *sc, float sigma) +{ + sc->type = CLOSURE_BSDF_OREN_NAYAR_ID; + sd->flag |= SD_BSDF | SD_BSDF_HAS_EVAL; + + sigma = clamp(sigma, 0.0f, 1.0f); + + sc->data0 = 1.0f / ((1.0f + 0.5f * sigma) * M_PI); + sc->data1 = sigma / ((1.0f + 0.5f * sigma) * M_PI); +} + +__device void bsdf_oren_nayar_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_oren_nayar_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + if (dot(sd->N, omega_in) > 0.0f) { + *pdf = 0.5f * M_1_PI_F; + return bsdf_oren_nayar_get_intensity(sc, sd->N, I, omega_in); + } + else { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +__device float3 bsdf_oren_nayar_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_oren_nayar_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__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) +{ + sample_uniform_hemisphere(sd->N, randu, randv, omega_in, pdf); + + if (dot(sd->Ng, *omega_in) > 0.0f) { + *eval = bsdf_oren_nayar_get_intensity(sc, sd->N, sd->I, *omega_in); + +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the bounce + *domega_in_dx = (2.0f * dot(sd->N, sd->dI.dx)) * sd->N - sd->dI.dx; + *domega_in_dy = (2.0f * dot(sd->N, sd->dI.dy)) * sd->N - sd->dI.dy; + *domega_in_dx *= 125.0f; + *domega_in_dy *= 125.0f; +#endif + } + else { + *pdf = 0.0f; + *eval = make_float3(0.0f, 0.0f, 0.0f); + } + + return LABEL_REFLECT | LABEL_DIFFUSE; +} + + +CCL_NAMESPACE_END + +#endif /* __BSDF_OREN_NAYAR_H__ */ |