diff --git a/src/luminaires/sun.cpp b/src/luminaires/sun.cpp new file mode 100644 index 00000000..8764a27c --- /dev/null +++ b/src/luminaires/sun.cpp @@ -0,0 +1,193 @@ +/* + This file is part of Mitsuba, a physically based rendering system. + + Copyright (c) 2007-2010 by Wenzel Jakob and others. + + Mitsuba is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License Version 3 + as published by the Free Software Foundation. + + Mitsuba is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include "sun.h" + +MTS_NAMESPACE_BEGIN + +/*!\plugin{sun}{Sun luminaire} + * \parameters{ + * \parameter{turbidity}{\Float}{ + * This parameter determines the amount of scattering particles (or + * `haze') in the atmosphere. Smaller values ($\sim 2$) produce a + * clear blue sky, larger values ($\sim 8$) lead to an overcast sky, + * and a very high values ($\sim 20$) cause a color shift towards + * orange and red. \default{3} + * } + * \parameter{day}{\Integer}{Solar day used to compute the sun's position. + * Must be in the range between 1 and 365. \default{180}} + * \parameter{time}{\Float}{Fractional time used to compute the sun's + * position. A time of 4:15 PM corresponds to 16.25. \default{15.00}} + * \parameter{latitude, longitude}{\Float}{ + * These two parameters specify the oberver's latitude and longitude + * in degrees, which are required to compute the sun's position. + * \default{35.6894, 139.6917 --- Tokyo, Japan} + * } + * \parameter{standardMeridian}{\Integer}{Denotes the + * standard meridian of the time zone for finding + * the sun's position \default{135 --- Japan standard time} + * } + * \parameter{sunDirection}{\Vector}{Allows to manually + * override the sun direction in world space. When this value + * is provided, parameters pertaining to the computation + * of the sun direction (\code{day, time, latitude, longitude,} + * and \code{standardMeridian}) are unnecessary. \default{none} + * } + * \parameter{resolution}{\Integer}{Specifies the resolution of the precomputed + * image that is used to represent the sun environment map + * \default{256}} + * \parameter{sunScale}{\Float}{ + * This parameter can be used to scale the the amount of illumination + * emitted by the sun luminaire, for instance to change its units. To + * switch from photometric ($\nicefrac{W}{m^2\cdot sr}$) + * to arbitrary but convenient units in the $[0,1]$ range, set + * this parameter to \code{1e-5}. \default{1} + * } + * } + */ +class SunLuminaire : public Luminaire { +public: + SunLuminaire(const Properties &props) + : Luminaire(props) { + m_scale = props.getFloat("sunScale", 1.0f); + m_resolution = props.getInteger("resolution", 512); + Point2 sunPos = configureSunPosition(props); + m_sunTheta = sunPos.x; + m_sunDir = toSphere(sunPos.x, sunPos.y); + m_sunDiskScale = props.getFloat("sunDiskScale", 15.0f); + m_turbidity = props.getFloat("turbidity", 3.0f); + } + + SunLuminaire(Stream *stream, InstanceManager *manager) + : Luminaire(stream, manager) { + m_scale = stream->readFloat(); + m_sunDiskScale = stream->readFloat(); + m_sunTheta = stream->readFloat(); + m_turbidity = stream->readFloat(); + m_resolution = stream->readInt(); + m_sunDir = Vector(stream); + configure(); + } + + void serialize(Stream *stream, InstanceManager *manager) const { + Luminaire::serialize(stream, manager); + stream->writeFloat(m_scale); + stream->writeFloat(m_sunDiskScale); + stream->writeFloat(m_sunTheta); + stream->writeFloat(m_turbidity); + stream->writeInt(m_resolution); + m_sunDir.serialize(stream); + } + + void configure() { + m_sunDiskTheta = 0.0046333f; + Float sunDiskSA = 2*M_PI * (1-std::cos(m_sunDiskTheta)); + m_sunDiskTheta *= m_sunDiskScale; + Float sunDiskSAScaled = 2*M_PI * (1-std::cos(m_sunDiskTheta)); + + m_intensity = computeSunRadiance(m_sunTheta, m_turbidity) + * m_scale * sunDiskSA/sunDiskSAScaled; + } + + bool isCompound() const { + return true; + } + + Luminaire *getElement(int i) { + if (i != 0) + return NULL; + int thetaBins = m_resolution, phiBins = m_resolution*2; + + ref bitmap = new Bitmap(phiBins, thetaBins, 128); + Point2 factor(M_PI / thetaBins, (2*M_PI) / phiBins); + float *target = bitmap->getFloatData(); + for (int i=0; i( + PluginManager::getInstance()->createObject( + MTS_CLASS(Luminaire), props)); + luminaire->configure(); + return luminaire; + } + + Spectrum Le(const Ray &ray) const { + Float theta = unitAngle(ray.d, m_sunDir); + + if (theta < m_sunDiskTheta) + return m_intensity * smoothStep(m_sunDiskTheta, 0, theta); + else + return Spectrum(0.0f); + } + + std::string toString() const { + std::ostringstream oss; + oss << "SunLuminaire[" << endl + << " sunDir = " << m_sunDir.toString() << "," << endl + << " sunDiskScale = " << m_sunDiskScale << "," << endl + << " sunScale = " << m_scale << endl + << "]"; + return oss.str(); + } + + MTS_DECLARE_CLASS() +protected: + /* Environment map resolution */ + int m_resolution; + /* Constant scale factor applied to the model */ + Float m_scale; + /* Direction of the sun in luminaire-space */ + Vector m_sunDir; + /* Angle cutoff for the sun disk */ + Float m_sunDiskTheta; + /* Sun disk region scale factors */ + Float m_sunDiskScale; + /* The turbidity of the sky ranges normally from 1 to 30. + For clear skies values in range [2,6] are useful. */ + Float m_turbidity; + /* Intensity of the sun disk */ + Spectrum m_intensity; + /* Elevation in radians */ + Float m_sunTheta; +}; + +MTS_IMPLEMENT_CLASS_S(SunLuminaire, false, Luminaire) +MTS_EXPORT_PLUGIN(SunLuminaire, "Preetham sky luminaire"); +MTS_NAMESPACE_END +