diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2011-11-14 21:31:47 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2011-11-14 21:31:47 +0400 |
commit | e731ffb64884e1e74b4736538533698dee1e21a7 (patch) | |
tree | c70e045e1f256032ac4cd11f3999586eb063ca2b /intern | |
parent | 90871d54c59be6eb66cd086c1387786526595f1f (diff) |
Cycles: Oren-Nayar BSDF support. This is not a separate shader node, rather it
is available through the Roughness input on the Diffuse BSDF.
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Shaders#Diffuse
Patch by Yasuhiro Fujii, thanks!
Diffstat (limited to 'intern')
-rw-r--r-- | intern/cycles/kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/bsdf_oren_nayar.cpp | 174 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl | 6 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/nodes/stdosl.h | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/osl_closures.cpp | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/osl_closures.h | 3 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/bsdf_oren_nayar.h | 143 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_bsdf.h | 13 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_closure.h | 7 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_types.h | 1 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 3 |
12 files changed, 351 insertions, 3 deletions
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 614391bd3f2..2bfb6c58120 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC_SVM_HEADERS svm/bsdf.h svm/bsdf_ashikhmin_velvet.h svm/bsdf_diffuse.h + svm/bsdf_oren_nayar.h svm/bsdf_microfacet.h svm/bsdf_reflection.h svm/bsdf_refraction.h diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt index ae88008cf71..13b2a39d7d0 100644 --- a/intern/cycles/kernel/osl/CMakeLists.txt +++ b/intern/cycles/kernel/osl/CMakeLists.txt @@ -12,6 +12,7 @@ set(SRC background.cpp bsdf_ashikhmin_velvet.cpp bsdf_diffuse.cpp + bsdf_oren_nayar.cpp bsdf_microfacet.cpp bsdf_reflection.cpp bsdf_refraction.cpp diff --git a/intern/cycles/kernel/osl/bsdf_oren_nayar.cpp b/intern/cycles/kernel/osl/bsdf_oren_nayar.cpp new file mode 100644 index 00000000000..a42c81e78f3 --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_oren_nayar.cpp @@ -0,0 +1,174 @@ +/* + * 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 + */ + +#include <OpenImageIO/fmath.h> +#include <OSL/genclosure.h> +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + + +class OrenNayarClosure: public BSDFClosure { +public: + Vec3 m_N; + float m_sigma; + float m_a, m_b; + + OrenNayarClosure(): BSDFClosure(Labels::DIFFUSE) {} + + void setup() { + m_sigma = clamp(m_sigma, 0.0f, 1.0f); + m_a = 1.0f / ((1.0f + 0.5f * m_sigma) * M_PI); + m_b = m_sigma / ((1.0f + 0.5f * m_sigma) * M_PI); + } + + bool mergeable(const ClosurePrimitive* other) const { + const OrenNayarClosure* comp = static_cast<const OrenNayarClosure*>(other); + return + m_N == comp->m_N && + m_sigma == comp->m_sigma && + BSDFClosure::mergeable(other); + } + + size_t memsize() const { + return sizeof(*this); + } + + const char* name() const { + return "oren_nayar"; + } + + void print_on(std::ostream& out) const { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; + out << m_sigma; + out << ")"; + } + + float albedo(const Vec3& omega_out) const { + return 1.0f; + } + + Color3 eval_reflect(const Vec3& omega_out, const Vec3& omega_in, float& pdf) const { + if (m_N.dot(omega_in) > 0.0f) { + pdf = float(0.5 * M_1_PI); + float is = get_intensity(m_N, omega_out, omega_in); + return Color3(is, is, is); + } + else { + pdf = 0.0f; + return Color3(0.0f, 0.0f, 0.0f); + } + } + + Color3 eval_transmit(const Vec3& omega_out, const Vec3& omega_in, float& pdf) const { + return Color3(0.0f, 0.0f, 0.0f); + } + + ustring sample( + const Vec3& Ng, + const Vec3& omega_out, const Vec3& domega_out_dx, const Vec3& domega_out_dy, + float randu, float randv, + Vec3& omega_in, Vec3& domega_in_dx, Vec3& domega_in_dy, + float& pdf, Color3& eval + ) const { + sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); + + if (Ng.dot(omega_in) > 0.0f) { + float is = get_intensity(m_N, omega_out, omega_in); + eval.setValue(is, is, is); + + // TODO: find a better approximation for the bounce + domega_in_dx = (2.0f * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; + domega_in_dy = (2.0f * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; + domega_in_dx *= 125.0f; + domega_in_dy *= 125.0f; + } + else { + pdf = 0.0f; + } + + return Labels::REFLECT; + } + +private: + float get_intensity(Vec3 const& n, Vec3 const& v, Vec3 const& l) const { + float nl = max(n.dot(l), 0.0f); + float nv = max(n.dot(v), 0.0f); + + Vec3 al = l - nl * n; + al.normalize(); + Vec3 av = v - nv * n; + av.normalize(); + float t = max(al.dot(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); + + return nl * (m_a + m_b * t * sin_a * tan_b); + } +}; + +ClosureParam bsdf_oren_nayar_params[] = { + CLOSURE_VECTOR_PARAM (OrenNayarClosure, m_N), + CLOSURE_FLOAT_PARAM (OrenNayarClosure, m_sigma), + CLOSURE_STRING_KEYPARAM ("label"), + CLOSURE_FINISH_PARAM (OrenNayarClosure) +}; + +CLOSURE_PREPARE(bsdf_oren_nayar_prepare, OrenNayarClosure) + + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl index 8cf161c17cc..6075b7c93f3 100644 --- a/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl +++ b/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl @@ -20,9 +20,13 @@ shader node_diffuse_bsdf( color Color = color(0.8, 0.8, 0.8), + float Roughness = 0.0, normal Normal = N, output closure color BSDF = diffuse(Normal)) { - BSDF = Color*diffuse(Normal); + if(Roughness == 0.0) + BSDF = Color * diffuse(Normal); + else + BSDF = Color * oren_nayar(Normal, Roughness); } diff --git a/intern/cycles/kernel/osl/nodes/stdosl.h b/intern/cycles/kernel/osl/nodes/stdosl.h index 6fe4f52df4a..e4a110e737c 100644 --- a/intern/cycles/kernel/osl/nodes/stdosl.h +++ b/intern/cycles/kernel/osl/nodes/stdosl.h @@ -435,6 +435,7 @@ string concat (string a, string b, string c, string d, string e, string f) { // Closures closure color diffuse(normal N) BUILTIN; +closure color oren_nayar(normal N, float sigma) BUILTIN; closure color translucent(normal N) BUILTIN; closure color reflection(normal N, float eta) BUILTIN; closure color reflection(normal N) { return reflection (N, 0.0); } diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index 4c2261942fd..b87cdf8af86 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -69,6 +69,7 @@ static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, O void OSLShader::register_closures(OSL::ShadingSystem *ss) { register_closure(ss, "diffuse", OSL_CLOSURE_BSDF_DIFFUSE_ID, bsdf_diffuse_params, bsdf_diffuse_prepare); + register_closure(ss, "oren_nayar", OSL_CLOSURE_BSDF_OREN_NAYAR_ID, bsdf_oren_nayar_params, bsdf_oren_nayar_prepare); register_closure(ss, "translucent", OSL_CLOSURE_BSDF_TRANSLUCENT_ID, bsdf_translucent_params, bsdf_translucent_prepare); register_closure(ss, "reflection", OSL_CLOSURE_BSDF_REFLECTION_ID, bsdf_reflection_params, bsdf_reflection_prepare); register_closure(ss, "refraction", OSL_CLOSURE_BSDF_REFRACTION_ID, bsdf_refraction_params, bsdf_refraction_prepare); diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 20a759586b0..1b4288b8601 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -41,6 +41,7 @@ CCL_NAMESPACE_BEGIN enum { OSL_CLOSURE_BSDF_DIFFUSE_ID, + OSL_CLOSURE_BSDF_OREN_NAYAR_ID, OSL_CLOSURE_BSDF_TRANSLUCENT_ID, OSL_CLOSURE_BSDF_REFLECTION_ID, OSL_CLOSURE_BSDF_REFRACTION_ID, @@ -62,6 +63,7 @@ enum { }; extern OSL::ClosureParam bsdf_diffuse_params[]; +extern OSL::ClosureParam bsdf_oren_nayar_params[]; extern OSL::ClosureParam bsdf_translucent_params[]; extern OSL::ClosureParam bsdf_reflection_params[]; extern OSL::ClosureParam bsdf_refraction_params[]; @@ -82,6 +84,7 @@ extern OSL::ClosureParam closure_holdout_params[]; extern OSL::ClosureParam closure_subsurface_params[]; void bsdf_diffuse_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_oren_nayar_prepare(OSL::RendererServices *, int id, void *data); void bsdf_translucent_prepare(OSL::RendererServices *, int id, void *data); void bsdf_reflection_prepare(OSL::RendererServices *, int id, void *data); void bsdf_refraction_prepare(OSL::RendererServices *, int id, void *data); 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__ */ diff --git a/intern/cycles/kernel/svm/svm_bsdf.h b/intern/cycles/kernel/svm/svm_bsdf.h index 411efc8be8f..411916f8aa0 100644 --- a/intern/cycles/kernel/svm/svm_bsdf.h +++ b/intern/cycles/kernel/svm/svm_bsdf.h @@ -18,6 +18,7 @@ #include "bsdf_ashikhmin_velvet.h" #include "bsdf_diffuse.h" +#include "bsdf_oren_nayar.h" #include "bsdf_microfacet.h" #include "bsdf_reflection.h" #include "bsdf_refraction.h" @@ -38,6 +39,9 @@ __device int svm_bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, floa label = bsdf_diffuse_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; #ifdef __SVM__ + case CLOSURE_BSDF_OREN_NAYAR_ID: + label = bsdf_oren_nayar_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; case CLOSURE_BSDF_TRANSLUCENT_ID: label = bsdf_translucent_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; @@ -91,6 +95,9 @@ __device float3 svm_bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, con eval = bsdf_diffuse_eval_reflect(sd, sc, sd->I, omega_in, pdf); break; #ifdef __SVM__ + case CLOSURE_BSDF_OREN_NAYAR_ID: + eval = bsdf_oren_nayar_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; case CLOSURE_BSDF_TRANSLUCENT_ID: eval = bsdf_translucent_eval_reflect(sd, sc, sd->I, omega_in, pdf); break; @@ -137,6 +144,9 @@ __device float3 svm_bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, con eval = bsdf_diffuse_eval_transmit(sd, sc, sd->I, omega_in, pdf); break; #ifdef __SVM__ + case CLOSURE_BSDF_OREN_NAYAR_ID: + eval = bsdf_oren_nayar_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; case CLOSURE_BSDF_TRANSLUCENT_ID: eval = bsdf_translucent_eval_transmit(sd, sc, sd->I, omega_in, pdf); break; @@ -188,6 +198,9 @@ __device void svm_bsdf_blur(ShaderClosure *sc, float roughness) bsdf_diffuse_blur(sc, roughness); break; #ifdef __SVM__ + case CLOSURE_BSDF_OREN_NAYAR_ID: + bsdf_oren_nayar_blur(sc, roughness); + break; case CLOSURE_BSDF_TRANSLUCENT_ID: bsdf_translucent_blur(sc, roughness); break; diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index fcda7ac6fe1..8409e83d94e 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -80,7 +80,12 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st case CLOSURE_BSDF_DIFFUSE_ID: { ShaderClosure *sc = svm_node_closure_get(sd); svm_node_closure_set_mix_weight(sc, mix_weight); - bsdf_diffuse_setup(sd, sc); + + float roughness = param1; + if(roughness == 0.0f) + bsdf_diffuse_setup(sd, sc); + else + bsdf_oren_nayar_setup(sd, sc, roughness); break; } case CLOSURE_BSDF_TRANSLUCENT_ID: { diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 89fc413c539..071477a83c7 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -258,6 +258,7 @@ typedef enum ShaderType { typedef enum ClosureType { CLOSURE_BSDF_ID, CLOSURE_BSDF_DIFFUSE_ID, + CLOSURE_BSDF_OREN_NAYAR_ID, CLOSURE_BSDF_TRANSLUCENT_ID, CLOSURE_BSDF_REFLECTION_ID, CLOSURE_BSDF_REFRACTION_ID, diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index f934b703103..d7bd74c9ec7 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1003,11 +1003,12 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler) DiffuseBsdfNode::DiffuseBsdfNode() { closure = CLOSURE_BSDF_DIFFUSE_ID; + add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f); } void DiffuseBsdfNode::compile(SVMCompiler& compiler) { - BsdfNode::compile(compiler, NULL, NULL); + BsdfNode::compile(compiler, input("Roughness"), NULL); } void DiffuseBsdfNode::compile(OSLCompiler& compiler) |