diff --git a/doc/images/bsdf_hk_1.jpg b/doc/images/bsdf_hk_1.jpg index 3e98d8b3..42773654 100644 Binary files a/doc/images/bsdf_hk_1.jpg and b/doc/images/bsdf_hk_1.jpg differ diff --git a/src/luminaires/SConscript b/src/luminaires/SConscript index 5999bba2..13b3b3ca 100644 --- a/src/luminaires/SConscript +++ b/src/luminaires/SConscript @@ -8,6 +8,7 @@ plugins += env.SharedLibrary('point', ['point.cpp']) plugins += env.SharedLibrary('collimated', ['collimated.cpp']) plugins += env.SharedLibrary('directional', ['directional.cpp']) plugins += env.SharedLibrary('sky', ['sky.cpp']) +plugins += env.SharedLibrary('sun', ['sun.cpp']) plugins += env.SharedLibrary('sunsky', ['sunsky.cpp']) Export('plugins') diff --git a/src/luminaires/envmap.cpp b/src/luminaires/envmap.cpp index 31602b04..3377ec93 100644 --- a/src/luminaires/envmap.cpp +++ b/src/luminaires/envmap.cpp @@ -128,6 +128,8 @@ public: } m_pdfPixelSize = Vector2(2 * M_PI / m_pdfResolution.x, M_PI / m_pdfResolution.y); m_pdf.build(); + if (m_pdf.getOriginalSum() == 0) + Log(EError, "Error -- environment map does not contain any nonzero pixels!"); } void preprocess(const Scene *scene) { diff --git a/src/luminaires/sky.cpp b/src/luminaires/sky.cpp index a5705d16..a872544b 100644 --- a/src/luminaires/sky.cpp +++ b/src/luminaires/sky.cpp @@ -164,8 +164,8 @@ class SkyLuminaire : public Luminaire { public: SkyLuminaire(const Properties &props) : Luminaire(props) { - m_intensityScale = props.getFloat("intensityScale", Float(1.0)); - m_turbidity = props.getFloat("turbidity", Float(3.0)); + m_intensityScale = props.getFloat("intensityScale", 1.0f); + m_turbidity = props.getFloat("turbidity", 3.0f); if (m_turbidity < 1 || m_turbidity > 30) Log(EError, "The turbidity parameter must be in the range [1,30]!"); @@ -288,6 +288,11 @@ public: return luminaire; } + Spectrum Le(const Ray &ray) const { + Point2 coords = fromSphere(ray.d); + return getSkySpectralRadiance(coords.x, coords.y) * m_intensityScale; + } + std::string toString() const { std::ostringstream oss; oss << "SkyLuminaire[" << endl diff --git a/src/luminaires/sun.h b/src/luminaires/sun.h index d7a10003..64e073e2 100644 --- a/src/luminaires/sun.h +++ b/src/luminaires/sun.h @@ -75,8 +75,8 @@ Point2 configureSunPosition(Float lat, Float lon, int stdMrd, -solarAzimuth); } -Point2 configureSunPosition(const Vector& sunDir, const Transform &luminaireToWorld) { - return fromSphere(normalize(luminaireToWorld(sunDir))); +Point2 configureSunPosition(const Vector& sunDir, const Transform &worldToLuminaire) { + return fromSphere(normalize(worldToLuminaire(sunDir))); } Point2 configureSunPosition(const Properties &props) { @@ -90,7 +90,7 @@ Point2 configureSunPosition(const Properties &props) { return configureSunPosition( props.getVector("sunDirection"), - props.getTransform("toWorld", Transform())); + props.getTransform("toWorld", Transform()).inverse()); } else { Float lat = props.getFloat("latitude", 35.6894f); Float lon = props.getFloat("longitude", 139.6917f); @@ -108,6 +108,126 @@ Point2 configureSunPosition(const Properties &props) { } } +/* All data lifted from MI */ +/* Units are either [] or cm^-1. refer when in doubt MI */ + +// k_o Spectrum table from pg 127, MI. +Float k_oWavelengths[64] = { + 300, 305, 310, 315, 320, 325, 330, 335, 340, 345, + 350, 355, 445, 450, 455, 460, 465, 470, 475, 480, + 485, 490, 495, 500, 505, 510, 515, 520, 525, 530, + 535, 540, 545, 550, 555, 560, 565, 570, 575, 580, + 585, 590, 595, 600, 605, 610, 620, 630, 640, 650, + 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, + 760, 770, 780, 790, +}; + +Float k_oAmplitudes[65] = { + 10.0, 4.8, 2.7, 1.35, .8, .380, .160, .075, .04, .019, .007, + .0, .003, .003, .004, .006, .008, .009, .012, .014, .017, + .021, .025, .03, .035, .04, .045, .048, .057, .063, .07, + .075, .08, .085, .095, .103, .110, .12, .122, .12, .118, + .115, .12, .125, .130, .12, .105, .09, .079, .067, .057, + .048, .036, .028, .023, .018, .014, .011, .010, .009, + .007, .004, .0, .0 +}; + +// k_g Spectrum table from pg 130, MI. +Float k_gWavelengths[4] = { + 759, 760, 770, 771 +}; + +Float k_gAmplitudes[4] = { + 0, 3.0, 0.210, 0 +}; + +// k_wa Spectrum table from pg 130, MI. +Float k_waWavelengths[13] = { + 689, 690, 700, 710, 720, + 730, 740, 750, 760, 770, + 780, 790, 800 +}; + +Float k_waAmplitudes[13] = { + 0, 0.160e-1, 0.240e-1, 0.125e-1, + 0.100e+1, 0.870, 0.610e-1, 0.100e-2, + 0.100e-4, 0.100e-4, 0.600e-3, + 0.175e-1, 0.360e-1 +}; + +Float solWavelengths[38] = { + 380, 390, 400, 410, 420, 430, 440, 450, + 460, 470, 480, 490, 500, 510, 520, 530, + 540, 550, 560, 570, 580, 590, 600, 610, + 620, 630, 640, 650, 660, 670, 680, 690, + 700, 710, 720, 730, 740, 750 +}; + +Float solAmplitudes[38] = { + 165.5, 162.3, 211.2, 258.8, 258.2, + 242.3, 267.6, 296.6, 305.4, 300.6, + 306.6, 288.3, 287.1, 278.2, 271.0, + 272.3, 263.6, 255.0, 250.6, 253.1, + 253.5, 251.3, 246.3, 241.7, 236.8, + 232.1, 228.2, 223.4, 219.7, 215.3, + 211.0, 207.3, 202.4, 198.7, 194.3, + 190.7, 186.3, 182.6 +}; + +Spectrum computeSunRadiance(Float theta, Float turbidity) { + InterpolatedSpectrum k_oCurve(k_oWavelengths, k_oAmplitudes, 64); + InterpolatedSpectrum k_gCurve(k_gWavelengths, k_gAmplitudes, 4); + InterpolatedSpectrum k_waCurve(k_waWavelengths, k_waAmplitudes, 13); + InterpolatedSpectrum solCurve(solWavelengths, solAmplitudes, 38); + Float data[91], wavelengths[91]; // (800 - 350) / 5 + 1 + + Float beta = 0.04608365822050f * turbidity - 0.04586025928522f; + + Float m = 1.0f/(std::cos(theta) + 0.15f*std::pow(93.885f-theta/M_PI*180.0f, (Float) -1.253f)); // Relative Optical Mass + + Float lambda; + int i; + for(i = 0, lambda = 350; i < 91; i++, lambda+=5) { + // Rayleigh Scattering + // Results agree with the graph (pg 115, MI) */ + Float tauR = std::exp(-m * 0.008735f * std::pow(lambda/1000.0f, (Float) -4.08)); + + // Aerosal (water + dust) attenuation + // beta - amount of aerosols present + // alpha - ratio of small to large particle sizes. (0:4,usually 1.3) + // Results agree with the graph (pg 121, MI) + const Float alpha = 1.3f; + Float tauA = exp(-m * beta * std::pow(lambda/1000.0f, -alpha)); // lambda should be in um + + // Attenuation due to ozone absorption + // lOzone - amount of ozone in cm(NTP) + // Results agree with the graph (pg 128, MI) + const Float lOzone = .35f; + Float tauO = std::exp(-m * k_oCurve.eval(lambda) * lOzone); + + // Attenuation due to mixed gases absorption + // Results agree with the graph (pg 131, MI) + Float tauG = std::exp(-1.41f * k_gCurve.eval(lambda) * m / std::pow(1 + 118.93f + * k_gCurve.eval(lambda) * m, (Float) 0.45f)); + + // Attenuation due to water vapor absorbtion + // w - precipitable water vapor in centimeters (standard = 2) + // Results agree with the graph (pg 132, MI) + const Float w = 2.0; + Float tauWA = std::exp(-0.2385f * k_waCurve.eval(lambda) * w * m / + std::pow(1 + 20.07f * k_waCurve.eval(lambda) * w * m, 0.45f)); + + data[i] = 100.0f * solCurve.eval(lambda) * tauR * tauA * tauO * tauG * tauWA; + wavelengths[i] = lambda; + } + InterpolatedSpectrum interpolated(wavelengths, data, 91); + Spectrum discretized; + discretized.fromContinuousSpectrum(interpolated); + discretized *= 300; + return discretized; +} + + MTS_NAMESPACE_END #endif /* __SUN_H */ diff --git a/src/luminaires/sunsky.cpp b/src/luminaires/sunsky.cpp index 4c94b368..ad71e119 100644 --- a/src/luminaires/sunsky.cpp +++ b/src/luminaires/sunsky.cpp @@ -18,6 +18,9 @@ #include #include +#include +#include +#include "sun.h" MTS_NAMESPACE_BEGIN @@ -80,38 +83,64 @@ public: : Luminaire(_props) { Properties props(_props); props.setPluginName("sun"); - m_sun = static_cast( + ref sun = static_cast( PluginManager::getInstance()->createObject( MTS_CLASS(Luminaire), props)); + sun->configure(); props.setPluginName("sky"); - m_sky = static_cast( + ref sky = static_cast( PluginManager::getInstance()->createObject( MTS_CLASS(Luminaire), props)); + sky->configure(); + + int resolution = props.getInteger("resolution", 512); + int thetaBins = resolution, phiBins = resolution*2; - /* Avoid unused parameter warnings */ - std::vector propNames; - props.putPropertyNames(propNames); - for (size_t i=0; i bitmap = new Bitmap(phiBins, thetaBins, 128); + Point2 factor(M_PI / thetaBins, (2*M_PI) / phiBins); + float *target = bitmap->getFloatData(); + for (int i=0; iLe(ray) + sky->Le(ray); + Float r, g, b; + s.toLinearRGB(r, g, b); + *target++ = r; *target++ = g; + *target++ = b; *target++ = 1; + } + } + + /* Instantiate a nested envmap plugin */ + Properties envProps("envmap"); + Properties::Data bitmapData; + bitmapData.ptr = (uint8_t *) bitmap.get(); + bitmapData.size = sizeof(Bitmap); + envProps.setData("bitmap", bitmapData); + envProps.setTransform("toWorld", m_luminaireToWorld); + envProps.setFloat("samplingWeight", m_samplingWeight); + m_luminaire = static_cast( + PluginManager::getInstance()->createObject( + MTS_CLASS(Luminaire), envProps)); + ref fs = new FileStream("test.exr", FileStream::ETruncReadWrite); + bitmap->save(Bitmap::EEXR, fs); } SunSkyLuminaire(Stream *stream, InstanceManager *manager) : Luminaire(stream, manager) { - m_sun = static_cast(manager->getInstance(stream)); - m_sky = static_cast(manager->getInstance(stream)); + m_luminaire = static_cast(manager->getInstance(stream)); } void serialize(Stream *stream, InstanceManager *manager) { Luminaire::serialize(stream, manager); - manager->serialize(stream, m_sun.get()); - manager->serialize(stream, m_sky.get()); + manager->serialize(stream, m_luminaire.get()); } void configure() { Luminaire::configure(); - m_sun->configure(); - m_sky->configure(); + m_luminaire->configure(); } bool isCompound() const { @@ -120,18 +149,14 @@ public: Luminaire *getElement(int i) { if (i == 0) - return m_sun; - else if (i == 1) - return m_sky; + return m_luminaire; else return NULL; } MTS_DECLARE_CLASS() private: - Properties m_props; - ref m_sun; - ref m_sky; + ref m_luminaire; }; MTS_IMPLEMENT_CLASS_S(SunSkyLuminaire, false, Luminaire)