00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "metal.h"
00025 #include "bxdf.h"
00026 #include "fresnelconductor.h"
00027 #include "microfacet.h"
00028 #include "blinn.h"
00029 #include "anisotropic.h"
00030 #include "paramset.h"
00031 #include "dynload.h"
00032 #include "error.h"
00033
00034 #include "irregular.h"
00035
00036 #include <boost/lexical_cast.hpp>
00037 #include <boost/regex.hpp>
00038 #include <fstream>
00039
00040 using namespace lux;
00041
00042 Metal::Metal(boost::shared_ptr<SPD > n, boost::shared_ptr<SPD > k,
00043 boost::shared_ptr<Texture<float> > u, boost::shared_ptr<Texture<float> > v,
00044 boost::shared_ptr<Texture<float> > bump, const CompositingParams &cp) {
00045 N = n;
00046 K = k;
00047 nu = u;
00048 nv = v;
00049 bumpMap = bump;
00050 compParams = new CompositingParams(cp);
00051 }
00052
00053 BSDF *Metal::GetBSDF(const TsPack *tspack, const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const {
00054
00055 DifferentialGeometry dgs;
00056 if (bumpMap)
00057 Bump(bumpMap, dgGeom, dgShading, &dgs);
00058 else
00059 dgs = dgShading;
00060
00061 SWCSpectrum n(tspack, N.get());
00062 SWCSpectrum k(tspack, K.get());
00063
00064 float u = nu->Evaluate(tspack, dgs);
00065 float v = nv->Evaluate(tspack, dgs);
00066
00067 MicrofacetDistribution *md;
00068 if(u == v)
00069 md = BSDF_ALLOC(tspack, Blinn)(1.f / u);
00070 else
00071 md = BSDF_ALLOC(tspack, Anisotropic)(1.f/u, 1.f/v);
00072
00073 Fresnel *fresnel = BSDF_ALLOC(tspack, FresnelConductor)(n, k);
00074 BxDF *bxdf = BSDF_ALLOC(tspack, Microfacet)(1.f, fresnel, md);
00075 SingleBSDF *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dgs, dgGeom.nn, bxdf);
00076
00077
00078 bsdf->SetCompositingParams(compParams);
00079
00080 return bsdf;
00081 }
00082
00083
00084 static float eVtolambda(float eV) {
00085
00086
00087
00088 return (4.135667e-15f * 299792458.f * 1e9f) / eV;
00089 }
00090
00091
00092 static float umtolambda(float um) {
00093 return um * 1000.f;
00094 }
00095
00096
00097 static float invcmtolambda(float invcm)
00098 {
00099 return 1e7f / invcm;
00100 }
00101
00102
00103 static float nmtolambda(float nm)
00104 {
00105 return nm;
00106 }
00107
00108 bool ReadSOPRAData(std::ifstream &fs, vector<float> &wl, vector<float> &n, vector<float> &k) {
00109
00110 string line;
00111
00112 if (!getline(fs, line).good())
00113 return false;
00114
00115 boost::smatch m;
00116
00117
00118 boost::regex header_expr("(\\d+)\\s+(\\d*\\.?\\d+)\\s+(\\d*\\.?\\d+)\\s+(\\d+)");
00119
00120 if (!boost::regex_search(line, m, header_expr))
00121 return false;
00122
00123
00124 float (*tolambda)(float) = NULL;
00125
00126 float lambda_first, lambda_last;
00127
00128 if (m[1] == "1") {
00129
00130
00131 lambda_last = boost::lexical_cast<float>(m[2]);
00132 lambda_first = boost::lexical_cast<float>(m[3]);
00133 tolambda = &eVtolambda;
00134 } else if (m[1] == "2") {
00135
00136 lambda_first = boost::lexical_cast<float>(m[2]);
00137 lambda_last = boost::lexical_cast<float>(m[3]);
00138 tolambda = &umtolambda;
00139 } else if (m[1] == "3") {
00140
00141 lambda_last = boost::lexical_cast<float>(m[2]);
00142 lambda_first = boost::lexical_cast<float>(m[3]);
00143 tolambda = &invcmtolambda;
00144 } else if (m[1] == "4") {
00145
00146 lambda_first = boost::lexical_cast<float>(m[2]);
00147 lambda_last = boost::lexical_cast<float>(m[3]);
00148 tolambda = &nmtolambda;
00149 } else
00150 return false;
00151
00152
00153 int count = boost::lexical_cast<int>(m[4]);
00154
00155
00156 boost::regex sample_expr("(\\d*\\.?\\d+)\\s+(\\d*\\.?\\d+)");
00157
00158
00159 wl.clear();
00160 n.clear();
00161 k.clear();
00162
00163 wl.resize(count);
00164 n.resize(count);
00165 k.resize(count);
00166
00167
00168
00169 for (int i = count-1; i >= 0; i--) {
00170
00171 if (!getline(fs, line).good())
00172 return false;
00173
00174 if (!boost::regex_search(line, m, sample_expr))
00175 return false;
00176
00177
00178
00179 wl[i] = tolambda(lambda_first + (lambda_last - lambda_first) * i / (float)count);
00180 n[i] = boost::lexical_cast<float>(m[1]);
00181 k[i] = boost::lexical_cast<float>(m[2]);
00182 }
00183
00184 return true;
00185 }
00186
00187 bool ReadLuxpopData(std::ifstream &fs, vector<float> &wl, vector<float> &n, vector<float> &k) {
00188
00189 string line;
00190
00191 boost::smatch m;
00192
00193
00194 boost::regex sample_expr("(\\d*\\.?\\d+|\\d+\\.)\\s+(\\d*\\.?\\d+|\\d+\\.?)\\s+(\\d*\\.?\\d+|\\d+\\.)");
00195
00196 wl.clear();
00197 n.clear();
00198 k.clear();
00199
00200
00201 while (getline(fs, line).good()) {
00202
00203
00204 if (line.length() > 0 && line[0] == ';')
00205 continue;
00206
00207 if (!boost::regex_search(line, m, sample_expr))
00208 return false;
00209
00210
00211 wl.push_back(boost::lexical_cast<float>(m[1]) * 0.1);
00212 n.push_back(boost::lexical_cast<float>(m[2]));
00213 k.push_back(boost::lexical_cast<float>(m[3]));
00214 }
00215
00216 return fs.eof();
00217 }
00218
00219 const float SopraSamples = 56;
00220 const float SopraWavelengths[] = {
00221 298.7570554, 302.4004341, 306.1337728, 309.960445, 313.8839949, 317.9081487, 322.036826,
00222 326.2741526, 330.6244747, 335.092373, 339.6826795, 344.4004944, 349.2512056, 354.2405086,
00223 359.374429, 364.6593471, 370.1020239, 375.7096303, 381.4897785, 387.4505563, 393.6005651,
00224 399.9489613, 406.5055016, 413.2805933, 420.2853492, 427.5316483, 435.0322035, 442.8006357,
00225 450.8515564, 459.2006593, 467.8648226, 476.8622231, 486.2124627, 495.936712, 506.0578694,
00226 516.6007417, 527.5922468, 539.0616435, 551.0407911, 563.5644455, 576.6705953, 590.4008476,
00227 604.8008683, 619.92089, 635.8162974, 652.5483053, 670.1847459, 688.8009889, 708.4810171,
00228 729.3186941, 751.4192606, 774.9011125, 799.8979226, 826.5611867, 855.0632966, 885.6012714 };
00229
00230 const float AmorphousCarbonSamples = 15;
00231 const float AmorphousCarbonWavelengths[] = {
00232 247.96, 309.95, 326.263, 344.389, 364.647, 387.438, 413.267, 442.786, 476.846, 516.583,
00233 563.545, 619.9, 688.778, 774.875, 885.571 };
00234 const float AmorphousCarbonN[] = {
00235 1.73, 1.84, 1.9, 1.94, 2, 2.06, 2.11, 2.17, 2.24, 2.3, 2.38, 2.43, 2.43, 2.33, 2.24 };
00236 const float AmorphousCarbonK[] = {
00237 0.712, 0.808, 0.91, 0.92, 0.92, 0.91, 0.9, 0.89, 0.88, 0.87, 0.82, 0.75, 0.7, 0.71 };
00238
00239 const float SilverN[] = {
00240 1.519, 1.496, 1.4325, 1.323, 1.142062, 0.932, 0.719062, 0.526, 0.388125, 0.294, 0.253313,
00241 0.238, 0.221438, 0.209, 0.194813, 0.186, 0.192063, 0.2, 0.198063, 0.192, 0.182, 0.173, 0.172625,
00242 0.173, 0.166688, 0.16, 0.1585, 0.157, 0.151063, 0.144, 0.137313, 0.132, 0.13025, 0.13, 0.129938,
00243 0.13, 0.130063, 0.129, 0.124375, 0.12, 0.119313, 0.121, 0.1255, 0.131, 0.136125, 0.14, 0.140063,
00244 0.14, 0.144313, 0.148, 0.145875, 0.143, 0.142563, 0.145, 0.151938, 0.163 };
00245 const float SilverK[] = {
00246 1.08, 0.882, 0.761063, 0.647, 0.550875, 0.504, 0.554375, 0.663, 0.818563, 0.986, 1.120687,
00247 1.24, 1.34525, 1.44, 1.53375, 1.61, 1.641875, 1.67, 1.735, 1.81, 1.87875, 1.95, 2.029375, 2.11,
00248 2.18625, 2.26, 2.329375, 2.4, 2.47875, 2.56, 2.64, 2.72, 2.798125, 2.88, 2.97375, 3.07, 3.159375,
00249 3.25, 3.348125, 3.45, 3.55375, 3.66, 3.76625, 3.88, 4.010625, 4.15, 4.293125, 4.44, 4.58625, 4.74,
00250 4.908125, 5.09, 5.28875, 5.5, 5.720624, 5.95 };
00251
00252 const float GoldN[] = {
00253 1.795, 1.812, 1.822625, 1.83, 1.837125, 1.84, 1.83425, 1.824, 1.812, 1.798, 1.782,
00254 1.766, 1.7525, 1.74, 1.727625, 1.716, 1.705875, 1.696, 1.68475, 1.674, 1.666, 1.658, 1.64725,
00255 1.636, 1.628, 1.616, 1.59625, 1.562, 1.502125, 1.426, 1.345875, 1.242, 1.08675, 0.916, 0.7545,
00256 0.608, 0.49175, 0.402, 0.3455, 0.306, 0.267625, 0.236, 0.212375, 0.194, 0.17775, 0.166, 0.161,
00257 0.16, 0.160875, 0.164, 0.1695, 0.176, 0.181375, 0.188, 0.198125, 0.21 };
00258 const float GoldK[] = {
00259 1.920375, 1.92, 1.918875, 1.916, 1.911375, 1.904, 1.891375, 1.878, 1.86825, 1.86,
00260 1.85175, 1.846, 1.84525, 1.848, 1.852375, 1.862, 1.883, 1.906, 1.9225, 1.936, 1.94775, 1.956,
00261 1.959375, 1.958, 1.951375, 1.94, 1.9245, 1.904, 1.875875, 1.846, 1.814625, 1.796, 1.797375,
00262 1.84, 1.9565, 2.12, 2.32625, 2.54, 2.730625, 2.88, 2.940625, 2.97, 3.015, 3.06, 3.07, 3.15,
00263 3.445812, 3.8, 4.087687, 4.357, 4.610188, 4.86, 5.125813, 5.39, 5.63125, 5.88 };
00264
00265 const float CopperN[] = {
00266 1.400313, 1.38, 1.358438, 1.34, 1.329063, 1.325, 1.3325, 1.34, 1.334375, 1.325,
00267 1.317812, 1.31, 1.300313, 1.29, 1.281563, 1.27, 1.249062, 1.225, 1.2, 1.18, 1.174375, 1.175,
00268 1.1775, 1.18, 1.178125, 1.175, 1.172812, 1.17, 1.165312, 1.16, 1.155312, 1.15, 1.142812, 1.135,
00269 1.131562, 1.12, 1.092437, 1.04, 0.950375, 0.826, 0.645875, 0.468, 0.35125, 0.272, 0.230813, 0.214,
00270 0.20925, 0.213, 0.21625, 0.223, 0.2365, 0.25, 0.254188, 0.26, 0.28, 0.3 };
00271 const float CopperK[] = {
00272 1.662125, 1.687, 1.703313, 1.72, 1.744563, 1.77, 1.791625, 1.81, 1.822125, 1.834,
00273 1.85175, 1.872, 1.89425, 1.916, 1.931688, 1.95, 1.972438, 2.015, 2.121562, 2.21, 2.177188, 2.13,
00274 2.160063, 2.21, 2.249938, 2.289, 2.326, 2.362, 2.397625, 2.433, 2.469187, 2.504, 2.535875, 2.564,
00275 2.589625, 2.605, 2.595562, 2.583, 2.5765, 2.599, 2.678062, 2.809, 3.01075, 3.24, 3.458187, 3.67,
00276 3.863125, 4.05, 4.239563, 4.43, 4.619563, 4.817, 5.034125, 5.26, 5.485625, 5.717 };
00277
00278 const float AluminiumN[] = {
00279 0.273375, 0.28, 0.286813, 0.294, 0.301875, 0.31, 0.317875, 0.326, 0.33475, 0.344,
00280 0.353813, 0.364, 0.374375, 0.385, 0.39575, 0.407, 0.419125, 0.432, 0.445688, 0.46, 0.474688, 0.49,
00281 0.506188, 0.523, 0.540063, 0.558, 0.577313, 0.598, 0.620313, 0.644, 0.668625, 0.695, 0.72375, 0.755,
00282 0.789, 0.826, 0.867, 0.912, 0.963, 1.02, 1.08, 1.15, 1.22, 1.3, 1.39, 1.49, 1.6, 1.74, 1.91, 2.14,
00283 2.41, 2.63, 2.8, 2.74, 2.58, 2.24 };
00284 const float AluminiumK[] = {
00285 3.59375, 3.64, 3.689375, 3.74, 3.789375, 3.84, 3.894375, 3.95, 4.005, 4.06, 4.11375,
00286 4.17, 4.23375, 4.3, 4.365, 4.43, 4.49375, 4.56, 4.63375, 4.71, 4.784375, 4.86, 4.938125, 5.02,
00287 5.10875, 5.2, 5.29, 5.38, 5.48, 5.58, 5.69, 5.8, 5.915, 6.03, 6.15, 6.28, 6.42, 6.55, 6.7, 6.85,
00288 7, 7.15, 7.31, 7.48, 7.65, 7.82, 8.01, 8.21, 8.39, 8.57, 8.62, 8.6, 8.45, 8.31, 8.21, 8.21 };
00289
00290 void IORFromName(const string name, vector<float> &wl, vector<float> &n, vector<float> &k) {
00291
00292 float const* sw;
00293 float const* sn;
00294 float const* sk;
00295 int ns = 0;
00296
00297 if (name == "amorphous carbon") {
00298 ns = AmorphousCarbonSamples;
00299 sw = AmorphousCarbonWavelengths;
00300 sn = AmorphousCarbonN;
00301 sk = AmorphousCarbonK;
00302 } else if (name == "silver") {
00303 ns = SopraSamples;
00304 sw = SopraWavelengths;
00305 sn = SilverN;
00306 sk = SilverK;
00307 } else if (name == "gold") {
00308 ns = SopraSamples;
00309 sw = SopraWavelengths;
00310 sn = GoldN;
00311 sk = GoldK;
00312 } else if (name == "copper") {
00313 ns = SopraSamples;
00314 sw = SopraWavelengths;
00315 sn = CopperN;
00316 sk = CopperK;
00317 } else {
00318 if (name != "aluminium") {
00319
00320 string msg = "Metal '" + name + "' not found, using default (" + DEFAULT_METAL + ").";
00321 luxError(LUX_NOERROR, LUX_WARNING, msg.c_str());
00322 }
00323 ns = SopraSamples;
00324 sw = SopraWavelengths;
00325 sn = AluminiumN;
00326 sk = AluminiumK;
00327 }
00328
00329 wl.clear();
00330 n.clear();
00331 k.clear();
00332
00333 for (int i = 0; i < ns; i++) {
00334 wl.push_back(sw[i]);
00335 n.push_back(sn[i]);
00336 k.push_back(sk[i]);
00337 }
00338 }
00339
00340
00341 int IORFromFile(const string filename, vector<float> &wl, vector<float> &n, vector<float> &k) {
00342
00343 std::ifstream f;
00344
00345 f.open(filename.c_str());
00346
00347 if (!f.is_open())
00348 return -1;
00349
00350
00351 if (!ReadSOPRAData(f, wl, n, k)) {
00352 if (!ReadLuxpopData(f, wl, n, k))
00353 return 0;
00354 }
00355
00356 f.close();
00357
00358 return 1;
00359 }
00360
00361 Material *Metal::CreateMaterial(const Transform &xform, const TextureParams &tp) {
00362
00363 string metalname = tp.FindString("name");
00364
00365 if (metalname == "")
00366 metalname = DEFAULT_METAL;
00367
00368 vector<float> s_wl;
00369 vector<float> s_n;
00370 vector<float> s_k;
00371
00372
00373
00374 int result = IORFromFile(metalname, s_wl, s_n, s_k);
00375 switch (result) {
00376 case 0: {
00377 string msg = "Error loading data file '" + metalname + "'. Using default (" + DEFAULT_METAL + ").";
00378 luxError(LUX_NOERROR, LUX_WARNING, msg.c_str());
00379 metalname = DEFAULT_METAL;
00380 }
00381 case -1:
00382 IORFromName(metalname, s_wl, s_n, s_k);
00383 break;
00384 case 1:
00385 break;
00386 }
00387
00388 boost::shared_ptr<SPD > n (new IrregularSPD(&s_wl[0], &s_n[0], s_wl.size()) );
00389 boost::shared_ptr<SPD > k (new IrregularSPD(&s_wl[0], &s_k[0], s_wl.size()) );
00390
00391 boost::shared_ptr<Texture<float> > uroughness = tp.GetFloatTexture("uroughness", .1f);
00392 boost::shared_ptr<Texture<float> > vroughness = tp.GetFloatTexture("vroughness", .1f);
00393 boost::shared_ptr<Texture<float> > bumpMap = tp.GetFloatTexture("bumpmap");
00394
00395
00396
00397 CompositingParams cP;
00398 FindCompositingParams(tp, &cP);
00399
00400 return new Metal(n, k, uroughness, vroughness, bumpMap, cP);
00401 }
00402
00403 static DynamicLoader::RegisterMaterial<Metal> r("metal");