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 #include <OpenImageIO/fmath.h> 00045 #include <OSL/genclosure.h> 00046 #include "osl_closures.h" 00047 00048 CCL_NAMESPACE_BEGIN 00049 00050 using namespace OSL; 00051 00052 00053 class OrenNayarClosure: public BSDFClosure { 00054 public: 00055 Vec3 m_N; 00056 float m_sigma; 00057 float m_a, m_b; 00058 00059 OrenNayarClosure(): BSDFClosure(Labels::DIFFUSE) {} 00060 00061 void setup() { 00062 m_sigma = clamp(m_sigma, 0.0f, 1.0f); 00063 m_a = 1.0f / ((1.0f + 0.5f * m_sigma) * M_PI); 00064 m_b = m_sigma / ((1.0f + 0.5f * m_sigma) * M_PI); 00065 } 00066 00067 bool mergeable(const ClosurePrimitive* other) const { 00068 const OrenNayarClosure* comp = static_cast<const OrenNayarClosure*>(other); 00069 return 00070 m_N == comp->m_N && 00071 m_sigma == comp->m_sigma && 00072 BSDFClosure::mergeable(other); 00073 } 00074 00075 size_t memsize() const { 00076 return sizeof(*this); 00077 } 00078 00079 const char* name() const { 00080 return "oren_nayar"; 00081 } 00082 00083 void print_on(std::ostream& out) const { 00084 out << name() << " ("; 00085 out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; 00086 out << m_sigma; 00087 out << ")"; 00088 } 00089 00090 float albedo(const Vec3& omega_out) const { 00091 return 1.0f; 00092 } 00093 00094 Color3 eval_reflect(const Vec3& omega_out, const Vec3& omega_in, float& pdf) const { 00095 if (m_N.dot(omega_in) > 0.0f) { 00096 pdf = float(0.5 * M_1_PI); 00097 float is = get_intensity(m_N, omega_out, omega_in); 00098 return Color3(is, is, is); 00099 } 00100 else { 00101 pdf = 0.0f; 00102 return Color3(0.0f, 0.0f, 0.0f); 00103 } 00104 } 00105 00106 Color3 eval_transmit(const Vec3& omega_out, const Vec3& omega_in, float& pdf) const { 00107 return Color3(0.0f, 0.0f, 0.0f); 00108 } 00109 00110 ustring sample( 00111 const Vec3& Ng, 00112 const Vec3& omega_out, const Vec3& domega_out_dx, const Vec3& domega_out_dy, 00113 float randu, float randv, 00114 Vec3& omega_in, Vec3& domega_in_dx, Vec3& domega_in_dy, 00115 float& pdf, Color3& eval 00116 ) const { 00117 sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); 00118 00119 if (Ng.dot(omega_in) > 0.0f) { 00120 float is = get_intensity(m_N, omega_out, omega_in); 00121 eval.setValue(is, is, is); 00122 00123 // TODO: find a better approximation for the bounce 00124 domega_in_dx = (2.0f * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; 00125 domega_in_dy = (2.0f * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; 00126 domega_in_dx *= 125.0f; 00127 domega_in_dy *= 125.0f; 00128 } 00129 else { 00130 pdf = 0.0f; 00131 } 00132 00133 return Labels::REFLECT; 00134 } 00135 00136 private: 00137 float get_intensity(Vec3 const& n, Vec3 const& v, Vec3 const& l) const { 00138 float nl = max(n.dot(l), 0.0f); 00139 float nv = max(n.dot(v), 0.0f); 00140 00141 Vec3 al = l - nl * n; 00142 al.normalize(); 00143 Vec3 av = v - nv * n; 00144 av.normalize(); 00145 float t = max(al.dot(av), 0.0f); 00146 00147 float cos_a, cos_b; 00148 if (nl < nv) { 00149 cos_a = nl; 00150 cos_b = nv; 00151 } 00152 else { 00153 cos_a = nv; 00154 cos_b = nl; 00155 } 00156 00157 float sin_a = sqrtf(1.0f - cos_a * cos_a); 00158 float tan_b = sqrtf(1.0f - cos_b * cos_b) / (cos_b + FLT_MIN); 00159 00160 return nl * (m_a + m_b * t * sin_a * tan_b); 00161 } 00162 }; 00163 00164 ClosureParam bsdf_oren_nayar_params[] = { 00165 CLOSURE_VECTOR_PARAM (OrenNayarClosure, m_N), 00166 CLOSURE_FLOAT_PARAM (OrenNayarClosure, m_sigma), 00167 CLOSURE_STRING_KEYPARAM ("label"), 00168 CLOSURE_FINISH_PARAM (OrenNayarClosure) 00169 }; 00170 00171 CLOSURE_PREPARE(bsdf_oren_nayar_prepare, OrenNayarClosure) 00172 00173 00174 CCL_NAMESPACE_END