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