ModifiedPhongBSDF.cpp
Go to the documentation of this file.00001 /**<!--------------------------------------------------------------------> 00002 @file ModifiedPhongBSDF.cpp 00003 @author Travis Fischer (fisch0920@gmail.com) 00004 @author Matthew Jacobs (jacobs.mh@gmail.com) 00005 @date Fall 2008 00006 00007 @brief 00008 Physically-correct modified phong model for glossy/specular surfaces, 00009 defined at a single point on a surface in 3-space. The modified phong 00010 model has two inputs: Kd, and Ks in [0, 1] subject to Kd + Ks <= 1, 00011 where Kd and Ks represent the diffuse and specular reflectivity of the 00012 surface respectively (fraction of incoming energy that is reflected 00013 diffusely/specularly). A third input, n, represents the specular 00014 shininess of the surface, where higher values of n correspond to tighter / 00015 sharper specular highlights, and lower values of n correspond to wider / 00016 glossier highlights. 00017 00018 @note For more information, please see: 00019 E. Lafortune and Y. Willems. Using the modified Phong reflectance 00020 model for physically based rendering. Technical Report CW197, Dept of 00021 Computer Science, K.U. Leuven, 1994. 00022 00023 @param 00024 kd - SpectralSampleSet which scales / attenuates the overall reflectance 00025 of the material (diffuse albedo) 00026 00027 @param 00028 ks - SpectralSampleSet which scales / attenuates the overall reflectance 00029 of the material (specular albedo) 00030 00031 @param 00032 n - Wavelength-dependent shininess exponent 00033 00034 @note Also known as modified Blinn-Phong model 00035 <!-------------------------------------------------------------------->**/ 00036 00037 #include "ModifiedPhongBSDF.h" 00038 #include <Material.h> 00039 #include <Random.h> 00040 00041 enum { 00042 MODIFIED_PHONG_EVENT_ABSORPTION = 0, 00043 MODIFIED_PHONG_EVENT_DIFFUSE, 00044 MODIFIED_PHONG_EVENT_SPECULAR, 00045 }; 00046 00047 void ModifiedPhongBSDF::init() { 00048 BSDF::init(); 00049 00050 if (m_parent->contains("ks")) { 00051 m_ks = m_parent->getSpectralSampleSet("ks", m_pt); 00052 m_kd = m_parent->getSpectralSampleSet("kd", SpectralSampleSet::black(), m_pt); 00053 } else if (m_parent->contains("kd")) { 00054 m_kd = m_parent->getSpectralSampleSet("kd", m_pt); 00055 m_ks = m_parent->getSpectralSampleSet("ks", SpectralSampleSet::black(), m_pt); 00056 } else { 00057 m_kd = m_parent->getSpectralSampleSet("kd", SpectralSampleSet::fill(.5), m_pt); 00058 m_ks = m_parent->getSpectralSampleSet("ks", SpectralSampleSet::fill(.5), m_pt); 00059 } 00060 00061 /*unsigned k = m_ks.getMaxFrequency(); 00062 if (m_ks[k] > 0) { 00063 real_t ratio = (1 - m_ks[k]) / m_ks[k]; 00064 00065 for(unsigned i = m_kd.N; i--;) 00066 m_kd[i] = m_ks[i] * ratio; 00067 }*/ 00068 //m_ks = SpectralSampleSet::black(); // TODO: temporary 00069 //m_kd = SpectralSampleSet::black(); // TODO: temporary 00070 //cerr << "temporary\n\n" << endl; 00071 00072 m_n = m_parent->getSpectralSampleSet("n" , SpectralSampleSet::fill(1.0), m_pt); 00073 00074 ASSERT(m_kd + m_ks <= SpectralSampleSet::identity()); 00075 ASSERT(m_n >= SpectralSampleSet::black()); 00076 00077 m_kda = m_kd.getAverage(); 00078 m_ksa = m_ks.getAverage(); 00079 m_na = m_n.getAverage(); 00080 } 00081 00082 Event ModifiedPhongBSDF::sample() { 00083 ASSERT(m_n >= SpectralSampleSet::fill(0)); 00084 00085 const real_t p0 = Random::sample() - EPSILON; 00086 unsigned index = MODIFIED_PHONG_EVENT_ABSORPTION; 00087 00088 if (p0 <= m_kda) { // diffuse reflection 00089 index = MODIFIED_PHONG_EVENT_DIFFUSE; 00090 00091 const Vector3 &wo = Vector3::cosRandom(m_pt.normalS); 00092 00093 return Event(wo, this, index); 00094 } else if (p0 <= m_kda + m_ksa) { // specular reflection 00095 index = MODIFIED_PHONG_EVENT_SPECULAR; 00096 00097 const real_t alpha = acos(pow(Random::sample(), 00098 1.0 / (m_na + 1))); 00099 const real_t phi = 2.0 * M_PI * Random::sample(); 00100 00101 // perfect specular direction 00102 const Vector3 &R = m_wi.reflectVector(m_pt.normalS); 00103 Vector3 r = R; 00104 Vector3 u, v; 00105 00106 if (ABS(m_pt.normal.dot(r)) < .95) { 00107 // construct orthonormal basis with r and v in the plane shared by 00108 // r and the local surface normal 00109 u = r.cross(m_pt.normalS).getNormalized(); 00110 v = u.cross(r); 00111 } else { // r approximately collinear with normal 00112 r.getOrthonormalBasis(v, u); 00113 } 00114 00115 const Vector3 &w = Vector3::fromSpherical(alpha, phi); 00116 const Vector3 &wo = u * w[0] + r * w[1] + v * w[2]; 00117 00118 if (m_pt.normal.dot(wo) > 0) 00119 return Event(wo, this, index); 00120 00121 // randomly sampled vector on opposite side of hemisphere 00122 return Event(R, this, index); 00123 } 00124 00125 // absorbed 00126 return Event(Vector3(), this, index); 00127 } 00128 00129 real_t ModifiedPhongBSDF::getPdf(const Event &event) { 00130 const unsigned index = event.getMetadata<unsigned>(); 00131 real_t pdf = 1; 00132 00133 if (index == MODIFIED_PHONG_EVENT_ABSORPTION) { 00134 pdf = (1 - (m_kda + m_ksa)); 00135 ASSERT(pdf > 0); 00136 00137 return pdf; 00138 } else { 00139 const Vector3 &wo = event.getValue<const Vector3&>(); 00140 const real_t cosA = m_pt.normal.dot(wo); 00141 if (cosA <= 0) 00142 return 0; 00143 00144 if (index == MODIFIED_PHONG_EVENT_SPECULAR) { // specular reflection 00145 const Vector3 &r = m_wi.reflectVector(m_pt.normalS); 00146 const real_t cosA = ABS(r.dot(wo)); 00147 ASSERT(m_ksa > 0); 00148 ASSERT(r.isUnit()); 00149 00150 pdf = MIN(1, (m_na + 1) / (2 * M_PI) * pow(cosA, m_na)); 00151 } else { // diffuse reflection 00152 ASSERT(index == MODIFIED_PHONG_EVENT_DIFFUSE); 00153 ASSERT(m_kda > 0); 00154 00155 pdf = (ABS(m_pt.normal.dot(wo)) / M_PI); 00156 ASSERT(pdf > 0); 00157 } 00158 00159 return pdf / cosA; 00160 } 00161 } 00162 00163 SpectralSampleSet ModifiedPhongBSDF::getBSDF(const Vector3 &wi, const Vector3 &wo) { 00164 if (m_pt.normal.dot(wo) <= 0) 00165 return SpectralSampleSet::black(); 00166 00167 const Vector3 &r = wi.reflectVector(m_pt.normalS); 00168 const real_t a = CAP(r.dot(wo), 0, 1); 00169 SpectralSampleSet a_n(m_n); 00170 00171 for(unsigned i = m_n.getN(); i--;) 00172 a_n[i].value = pow(a, m_n[i].value); 00173 00174 const SpectralSampleSet &fs_s = 00175 (m_ksa > 0 ? ((m_n + SpectralSampleSet::fill(2)) / (2 * M_PI * m_ksa)) * a_n : 00176 SpectralSampleSet::black()); 00177 const real_t fs_d = (m_kda > 0 ? 1.0 / (M_PI * m_kda) : 0); 00178 00179 return m_kd * fs_d + m_ks * fs_s; 00180 } 00181
Generated on 28 Feb 2009 for Milton by
1.5.6