added an environment luminaire, changed the sky.cpp implementation so that it forwards to envmap.cpp
parent
e379ffda42
commit
8e448eaf6c
|
@ -9,6 +9,9 @@
|
||||||
<!-- Test the environment map luminaire -->
|
<!-- Test the environment map luminaire -->
|
||||||
<luminaire type="envmap">
|
<luminaire type="envmap">
|
||||||
<string name="filename" value="data/tests/envmap.exr"/>
|
<string name="filename" value="data/tests/envmap.exr"/>
|
||||||
|
<transform name="toWorld">
|
||||||
|
<rotate x="1" angle="40"/>
|
||||||
|
</transform>
|
||||||
</luminaire>
|
</luminaire>
|
||||||
|
|
||||||
<!-- Make sure that the scene actually contains something -->
|
<!-- Make sure that the scene actually contains something -->
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 196 KiB |
Binary file not shown.
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 200 KiB |
|
@ -55,17 +55,17 @@ public:
|
||||||
* Returns false if the computed position is not visible through
|
* Returns false if the computed position is not visible through
|
||||||
* the film's crop window
|
* the film's crop window
|
||||||
*/
|
*/
|
||||||
virtual bool positionToSample(const Point &p, Point2 &sample) const = 0;
|
virtual bool positionToSample(const Point &p, Point2 &sample) const;
|
||||||
|
|
||||||
/// Does generateRay() expect a proper lens sample?
|
/// Does generateRay() expect a proper lens sample?
|
||||||
virtual bool needsLensSample() const = 0;
|
virtual bool needsLensSample() const;
|
||||||
|
|
||||||
/// Does generateRay() expect a proper time sample?
|
/// Does generateRay() expect a proper time sample?
|
||||||
inline bool needsTimeSample() const { return m_shutterOpenTime > 0; }
|
inline bool needsTimeSample() const { return m_shutterOpenTime > 0; }
|
||||||
|
|
||||||
/// Return the time value of the shutter opening event
|
/// Return the time value of the shutter opening event
|
||||||
inline Float getShutterOpen() const { return m_shutterOpen; }
|
inline Float getShutterOpen() const { return m_shutterOpen; }
|
||||||
|
|
||||||
/// Return the length, for which the shutter remains open
|
/// Return the length, for which the shutter remains open
|
||||||
inline Float getShutterOpenTime() const { return m_shutterOpenTime; }
|
inline Float getShutterOpenTime() const { return m_shutterOpenTime; }
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ public:
|
||||||
* Calculate the pixel area density at a position on the image plane.
|
* Calculate the pixel area density at a position on the image plane.
|
||||||
* Returns zero for cameras with an infinitesimal sensor (e.g. pinhole cameras).
|
* Returns zero for cameras with an infinitesimal sensor (e.g. pinhole cameras).
|
||||||
*/
|
*/
|
||||||
virtual Float areaDensity(const Point2 &p) const = 0;
|
virtual Float areaDensity(const Point2 &p) const;
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
@ -175,6 +175,10 @@ public:
|
||||||
/// Return the properties of this camera
|
/// Return the properties of this camera
|
||||||
inline const Properties &getProperties() const { return m_properties; }
|
inline const Properties &getProperties() const { return m_properties; }
|
||||||
|
|
||||||
|
/** \brief Configure the object (called _once_ after construction
|
||||||
|
and addition of all child ConfigurableObjects. */
|
||||||
|
virtual void configure();
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ public:
|
||||||
* \brief Return an estimate of the total amount of power emitted
|
* \brief Return an estimate of the total amount of power emitted
|
||||||
* by this luminaire.
|
* by this luminaire.
|
||||||
*/
|
*/
|
||||||
virtual Spectrum getPower() const = 0;
|
virtual Spectrum getPower() const;
|
||||||
|
|
||||||
/// Is this luminaire intersectable (e.g. can it be encountered by a tracing a ray)?
|
/// Is this luminaire intersectable (e.g. can it be encountered by a tracing a ray)?
|
||||||
inline bool isIntersectable() const { return m_intersectable; }
|
inline bool isIntersectable() const { return m_intersectable; }
|
||||||
|
@ -194,7 +194,7 @@ public:
|
||||||
* Sampling is ideally done with respect to solid angle at \c p.
|
* Sampling is ideally done with respect to solid angle at \c p.
|
||||||
*/
|
*/
|
||||||
virtual void sample(const Point &p,
|
virtual void sample(const Point &p,
|
||||||
LuminaireSamplingRecord &lRec, const Point2 &sample) const = 0;
|
LuminaireSamplingRecord &lRec, const Point2 &sample) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Calculate the solid angle density for generating this sample
|
* \brief Calculate the solid angle density for generating this sample
|
||||||
|
@ -204,7 +204,7 @@ public:
|
||||||
* are considered in the query. Otherwise, they are left out.
|
* are considered in the query. Otherwise, they are left out.
|
||||||
*/
|
*/
|
||||||
virtual Float pdf(const Point &p,
|
virtual Float pdf(const Point &p,
|
||||||
const LuminaireSamplingRecord &lRec, bool delta) const = 0;
|
const LuminaireSamplingRecord &lRec, bool delta) const;
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
@ -225,7 +225,7 @@ public:
|
||||||
* of the spatial and directional sampling densities.
|
* of the spatial and directional sampling densities.
|
||||||
*/
|
*/
|
||||||
virtual void sampleEmission(EmissionRecord &eRec,
|
virtual void sampleEmission(EmissionRecord &eRec,
|
||||||
const Point2& areaSample, const Point2 &dirSample) const = 0;
|
const Point2& areaSample, const Point2 &dirSample) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Sample only the spatial part of the emission sampling strategy
|
* \brief Sample only the spatial part of the emission sampling strategy
|
||||||
|
@ -239,7 +239,7 @@ public:
|
||||||
* spatially dependent emittance component will be stored in \c eRec.
|
* spatially dependent emittance component will be stored in \c eRec.
|
||||||
*/
|
*/
|
||||||
virtual void sampleEmissionArea(EmissionRecord &lRec,
|
virtual void sampleEmissionArea(EmissionRecord &lRec,
|
||||||
const Point2 &sample) const = 0;
|
const Point2 &sample) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Sample only the directional part of the emission sampling strategy
|
* \brief Sample only the directional part of the emission sampling strategy
|
||||||
|
@ -252,7 +252,7 @@ public:
|
||||||
* component of the radiant emittance obtained in \ref sampleEmissionArea.
|
* component of the radiant emittance obtained in \ref sampleEmissionArea.
|
||||||
*/
|
*/
|
||||||
virtual Spectrum sampleEmissionDirection(EmissionRecord &lRec,
|
virtual Spectrum sampleEmissionDirection(EmissionRecord &lRec,
|
||||||
const Point2 &sample) const = 0;
|
const Point2 &sample) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Given an emitted particle, populate the emission record with the
|
* \brief Given an emitted particle, populate the emission record with the
|
||||||
|
@ -261,13 +261,13 @@ public:
|
||||||
* When \c delta is set to true, only components with a Dirac delta density
|
* When \c delta is set to true, only components with a Dirac delta density
|
||||||
* are considered in the query. Otherwise, they are left out.
|
* are considered in the query. Otherwise, they are left out.
|
||||||
*/
|
*/
|
||||||
virtual void pdfEmission(EmissionRecord &eRec, bool delta) const = 0;
|
virtual void pdfEmission(EmissionRecord &eRec, bool delta) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Evaluate the spatial component of the radiant emittance at a
|
* \brief Evaluate the spatial component of the radiant emittance at a
|
||||||
* point on the luminaire (ignoring any directional variations).
|
* point on the luminaire (ignoring any directional variations).
|
||||||
*/
|
*/
|
||||||
virtual Spectrum evalArea(const EmissionRecord &eRec) const = 0;
|
virtual Spectrum evalArea(const EmissionRecord &eRec) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Evaluate the directional emission distribution of this light source
|
* \brief Evaluate the directional emission distribution of this light source
|
||||||
|
@ -275,7 +275,7 @@ public:
|
||||||
*
|
*
|
||||||
* This function is normalized so that it integrates to one.
|
* This function is normalized so that it integrates to one.
|
||||||
*/
|
*/
|
||||||
virtual Spectrum evalDirection(const EmissionRecord &eRec) const = 0;
|
virtual Spectrum evalDirection(const EmissionRecord &eRec) const;
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
|
@ -2,5 +2,6 @@ Import('env', 'plugins')
|
||||||
|
|
||||||
plugins += env.SharedLibrary('perspective', ['perspective.cpp'])
|
plugins += env.SharedLibrary('perspective', ['perspective.cpp'])
|
||||||
plugins += env.SharedLibrary('orthographic', ['orthographic.cpp'])
|
plugins += env.SharedLibrary('orthographic', ['orthographic.cpp'])
|
||||||
|
plugins += env.SharedLibrary('environment', ['environment.cpp'])
|
||||||
|
|
||||||
Export('plugins')
|
Export('plugins')
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
This file is part of Mitsuba, a physically based rendering system.
|
||||||
|
|
||||||
|
Copyright (c) 2007-2011 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mitsuba/render/camera.h>
|
||||||
|
#include <mitsuba/core/statistics.h>
|
||||||
|
|
||||||
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static StatsCounter cameraRays("General", "Camera ray generations");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple environment camera model
|
||||||
|
* - based on the version in PBRT
|
||||||
|
*/
|
||||||
|
class EnvironmentCamera : public Camera {
|
||||||
|
public:
|
||||||
|
EnvironmentCamera(const Properties &props)
|
||||||
|
: Camera(props) { }
|
||||||
|
|
||||||
|
EnvironmentCamera(Stream *stream, InstanceManager *manager)
|
||||||
|
: Camera(stream, manager) {
|
||||||
|
configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
|
Camera::serialize(stream, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void configure() {
|
||||||
|
Camera::configure();
|
||||||
|
Vector2i filmSize = m_film->getSize();
|
||||||
|
m_invResolution = Point2(
|
||||||
|
1.0f / filmSize.x,
|
||||||
|
1.0f / filmSize.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cartesian-to-spherical coordinate mapping with
|
||||||
|
* v=0 => Y=1
|
||||||
|
*/
|
||||||
|
Vector squareToSphereY(Float u, Float v) const {
|
||||||
|
Float cosTheta = std::cos(v * M_PI),
|
||||||
|
sinTheta = std::sin(v * M_PI),//std::sqrt(1-cosTheta*cosTheta),
|
||||||
|
phi = u * 2 * M_PI,
|
||||||
|
cosPhi = std::cos(phi), sinPhi = std::sin(phi);
|
||||||
|
return Vector(
|
||||||
|
sinTheta * sinPhi, cosTheta, -sinTheta*cosPhi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Corresponding reverse mapping */
|
||||||
|
Point2 sphereToSquareY(const Vector &d) const {
|
||||||
|
Float u = std::atan2(d.x,-d.z) * (0.5f * INV_PI),
|
||||||
|
v = std::acos(std::max((Float) -1.0f,
|
||||||
|
std::min((Float) 1.0f, d.y))) / M_PI;
|
||||||
|
if (u < 0)
|
||||||
|
u += 1;
|
||||||
|
return Point2(u, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateRay(const Point2 &dirSample, const Point2 &lensSample,
|
||||||
|
Float timeSample, Ray &ray) const {
|
||||||
|
++cameraRays;
|
||||||
|
|
||||||
|
Float u = dirSample.x * m_invResolution.x,
|
||||||
|
v = dirSample.y * m_invResolution.y;
|
||||||
|
|
||||||
|
Vector direction = squareToSphereY(u, v);
|
||||||
|
Point2 uvPrime = sphereToSquareY(direction);
|
||||||
|
|
||||||
|
if ((std::abs(uvPrime.x-u) > Epsilon || std::abs(uvPrime.y-v)>Epsilon) && u < 1 && v < 1 && u > 0 && v > 0)
|
||||||
|
cout << uvPrime.toString() << " vs " << u << ", " << v << endl;
|
||||||
|
|
||||||
|
/* Construct ray in camera space */
|
||||||
|
Ray localRay(Point(0.0f), direction,
|
||||||
|
m_shutterOpen + m_shutterOpenTime * timeSample);
|
||||||
|
|
||||||
|
/* Transform into world space */
|
||||||
|
m_cameraToWorld(localRay, ray);
|
||||||
|
}
|
||||||
|
|
||||||
|
MTS_DECLARE_CLASS()
|
||||||
|
private:
|
||||||
|
Point2 m_invResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
MTS_IMPLEMENT_CLASS_S(EnvironmentCamera, false, Camera)
|
||||||
|
MTS_EXPORT_PLUGIN(EnvironmentCamera, "Environment camera");
|
||||||
|
MTS_NAMESPACE_END
|
|
@ -56,6 +56,23 @@ void Camera::setParent(ConfigurableObject *parent) {
|
||||||
// the camera subtree needs to be serialized by itself.
|
// the camera subtree needs to be serialized by itself.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Camera::configure() {
|
||||||
|
if (m_film == NULL) {
|
||||||
|
/* Instantiate an EXR film by default */
|
||||||
|
m_film = static_cast<Film*> (PluginManager::getInstance()->
|
||||||
|
createObject(MTS_CLASS(Film), Properties("exrfilm")));
|
||||||
|
m_film->configure();
|
||||||
|
}
|
||||||
|
if (m_sampler == NULL) {
|
||||||
|
/* No sampler has been selected - load an independent filter with 4 samples/pixel by default */
|
||||||
|
Properties props("independent");
|
||||||
|
props.setInteger("sampleCount", 4);
|
||||||
|
m_sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
||||||
|
createObject(MTS_CLASS(Sampler), props));
|
||||||
|
m_sampler->configure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Point Camera::getPosition(const Point2 &sample) const {
|
Point Camera::getPosition(const Point2 &sample) const {
|
||||||
return m_position; // default impl.
|
return m_position; // default impl.
|
||||||
}
|
}
|
||||||
|
@ -107,6 +124,22 @@ void Camera::addChild(const std::string &name, ConfigurableObject *child) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Camera::positionToSample(const Point &p, Point2 &sample) const {
|
||||||
|
Log(EError, "%s::positionToSample(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float Camera::areaDensity(const Point2 &p) const {
|
||||||
|
Log(EError, "%s::areaDensity(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Camera::needsLensSample() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ProjectiveCamera::ProjectiveCamera(Stream *stream, InstanceManager *manager)
|
ProjectiveCamera::ProjectiveCamera(Stream *stream, InstanceManager *manager)
|
||||||
: Camera(stream, manager) {
|
: Camera(stream, manager) {
|
||||||
m_cameraToScreen = Transform(stream);
|
m_cameraToScreen = Transform(stream);
|
||||||
|
@ -124,21 +157,7 @@ ProjectiveCamera::ProjectiveCamera(const Properties &props) : Camera(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectiveCamera::configure() {
|
void ProjectiveCamera::configure() {
|
||||||
if (m_film == NULL) {
|
Camera::configure();
|
||||||
/* Instantiate an EXR film by default */
|
|
||||||
m_film = static_cast<Film*> (PluginManager::getInstance()->
|
|
||||||
createObject(MTS_CLASS(Film), Properties("exrfilm")));
|
|
||||||
m_film->configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_sampler == NULL) {
|
|
||||||
/* No sampler has been selected - load an independent filter with 4 samples/pixel by default */
|
|
||||||
Properties props("independent");
|
|
||||||
props.setInteger("sampleCount", 4);
|
|
||||||
m_sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
|
||||||
createObject(MTS_CLASS(Sampler), props));
|
|
||||||
m_sampler->configure();
|
|
||||||
}
|
|
||||||
m_aspect = (Float) m_film->getSize().x / (Float) m_film->getSize().y;
|
m_aspect = (Float) m_film->getSize().x / (Float) m_film->getSize().y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,61 @@ Luminaire *Luminaire::getElement(int i) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Luminaire::sampleEmission(EmissionRecord &eRec,
|
||||||
|
const Point2& areaSample, const Point2 &dirSample) const {
|
||||||
|
Log(EError, "%s::areaDensity(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Luminaire::sampleEmissionArea(EmissionRecord &lRec,
|
||||||
|
const Point2 &sample) const {
|
||||||
|
Log(EError, "%s::sampleEmissionArea(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Spectrum Luminaire::sampleEmissionDirection(EmissionRecord &lRec,
|
||||||
|
const Point2 &sample) const {
|
||||||
|
Log(EError, "%s::sampleEmissionDirection(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Luminaire::pdfEmission(EmissionRecord &eRec, bool delta) const {
|
||||||
|
Log(EError, "%s::pdfEmission(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Spectrum Luminaire::evalArea(const EmissionRecord &eRec) const {
|
||||||
|
Log(EError, "%s::evalArea(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Spectrum Luminaire::evalDirection(const EmissionRecord &eRec) const {
|
||||||
|
Log(EError, "%s::evalDirection(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Luminaire::sample(const Point &p,
|
||||||
|
LuminaireSamplingRecord &lRec, const Point2 &sample) const {
|
||||||
|
Log(EError, "%s::sample(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Float Luminaire::pdf(const Point &p,
|
||||||
|
const LuminaireSamplingRecord &lRec, bool delta) const {
|
||||||
|
Log(EError, "%s::pdf(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Spectrum Luminaire::getPower() const {
|
||||||
|
Log(EError, "%s::getPower(): not implemented!",
|
||||||
|
getClass()->getName().c_str());
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
std::string EmissionRecord::toString() const {
|
std::string EmissionRecord::toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "EmissionRecord[" << std::endl
|
oss << "EmissionRecord[" << std::endl
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
#include <mitsuba/hw/gputexture.h>
|
#include <mitsuba/hw/gputexture.h>
|
||||||
#include <mitsuba/hw/gpuprogram.h>
|
#include <mitsuba/hw/gpuprogram.h>
|
||||||
|
|
||||||
//#define SAMPLE_UNIFORMLY 1
|
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,10 +37,17 @@ class EnvMapLuminaire : public Luminaire {
|
||||||
public:
|
public:
|
||||||
EnvMapLuminaire(const Properties &props) : Luminaire(props) {
|
EnvMapLuminaire(const Properties &props) : Luminaire(props) {
|
||||||
m_intensityScale = props.getFloat("intensityScale", 1);
|
m_intensityScale = props.getFloat("intensityScale", 1);
|
||||||
m_path = Thread::getThread()->getFileResolver()->resolve(props.getString("filename"));
|
ref<Bitmap> bitmap;
|
||||||
Log(EInfo, "Loading environment map \"%s\"", m_path.leaf().c_str());
|
|
||||||
ref<Stream> is = new FileStream(m_path, FileStream::EReadOnly);
|
if (props.hasProperty("bitmap")) {
|
||||||
ref<Bitmap> bitmap = new Bitmap(Bitmap::EEXR, is);
|
bitmap = reinterpret_cast<Bitmap *>(props.getData("bitmap").ptr);
|
||||||
|
m_path = "<unknown>";
|
||||||
|
} else {
|
||||||
|
m_path = Thread::getThread()->getFileResolver()->resolve(props.getString("filename"));
|
||||||
|
Log(EInfo, "Loading environment map \"%s\"", m_path.leaf().c_str());
|
||||||
|
ref<Stream> is = new FileStream(m_path, FileStream::EReadOnly);
|
||||||
|
bitmap = new Bitmap(Bitmap::EEXR, is);
|
||||||
|
}
|
||||||
|
|
||||||
m_mipmap = MIPMap::fromBitmap(bitmap, MIPMap::ETrilinear,
|
m_mipmap = MIPMap::fromBitmap(bitmap, MIPMap::ETrilinear,
|
||||||
MIPMap::ERepeat, 0.0f, Spectrum::EIlluminant);
|
MIPMap::ERepeat, 0.0f, Spectrum::EIlluminant);
|
||||||
|
@ -97,9 +102,11 @@ public:
|
||||||
void configure() {
|
void configure() {
|
||||||
int mipMapLevel = std::min(3, m_mipmap->getLevels()-1);
|
int mipMapLevel = std::min(3, m_mipmap->getLevels()-1);
|
||||||
m_pdfResolution = m_mipmap->getLevelResolution(mipMapLevel);
|
m_pdfResolution = m_mipmap->getLevelResolution(mipMapLevel);
|
||||||
m_pdfInvResolution = Vector2(1.0f / m_pdfResolution.x, 1.0f / m_pdfResolution.y);
|
m_pdfInvResolution = Vector2(1.0f / m_pdfResolution.x,
|
||||||
|
1.0f / m_pdfResolution.y);
|
||||||
|
|
||||||
Log(EDebug, "Creating a %ix%i sampling density", m_pdfResolution.x, m_pdfResolution.y);
|
Log(EDebug, "Creating a %ix%i sampling density",
|
||||||
|
m_pdfResolution.x, m_pdfResolution.y);
|
||||||
const Spectrum *coarseImage = m_mipmap->getImageData(mipMapLevel);
|
const Spectrum *coarseImage = m_mipmap->getImageData(mipMapLevel);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
m_pdf = DiscretePDF(m_pdfResolution.x * m_pdfResolution.y);
|
m_pdf = DiscretePDF(m_pdfResolution.x * m_pdfResolution.y);
|
||||||
|
@ -133,35 +140,45 @@ public:
|
||||||
return m_average * m_surfaceArea * M_PI;
|
return m_average * m_surfaceArea * M_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sample an emission direction
|
||||||
Vector sampleDirection(Point2 sample, Float &pdf, Spectrum &value) const {
|
Vector sampleDirection(Point2 sample, Float &pdf, Spectrum &value) const {
|
||||||
#if defined(SAMPLE_UNIFORMLY)
|
|
||||||
pdf = 1.0f / (4*M_PI);
|
|
||||||
Vector d = squareToSphere(sample);
|
|
||||||
value = Le(-d);
|
|
||||||
return d;
|
|
||||||
#else
|
|
||||||
int idx = m_pdf.sampleReuse(sample.x, pdf);
|
int idx = m_pdf.sampleReuse(sample.x, pdf);
|
||||||
int row = idx / m_pdfResolution.x;
|
int row = idx / m_pdfResolution.x;
|
||||||
int col = idx - m_pdfResolution.x * row;
|
int col = idx - m_pdfResolution.x * row;
|
||||||
Float x = col + sample.x, y = row + sample.y;
|
Float x = col + sample.x, y = row + sample.y;
|
||||||
value = m_mipmap->triangle(0, x * m_pdfInvResolution.x, y * m_pdfInvResolution.y)
|
value = m_mipmap->triangle(0, x * m_pdfInvResolution.x,
|
||||||
* m_intensityScale;
|
y * m_pdfInvResolution.y) * m_intensityScale;
|
||||||
Float theta = m_pdfPixelSize.y * y, phi = m_pdfPixelSize.x * x - M_PI;
|
Float theta = m_pdfPixelSize.y * y,
|
||||||
Float sinTheta = std::sin(theta), cosTheta = std::cos(theta);
|
phi = m_pdfPixelSize.x * x;
|
||||||
Float sinPhi = std::sin(phi), cosPhi = std::cos(phi);
|
|
||||||
|
/* Spherical-to-cartesian coordinate mapping with
|
||||||
|
theta=0 => Y=1 */
|
||||||
|
Float cosTheta = std::cos(theta),
|
||||||
|
sinTheta = std::sqrt(1-cosTheta*cosTheta),
|
||||||
|
cosPhi = std::cos(phi),
|
||||||
|
sinPhi = std::sin(phi);
|
||||||
|
|
||||||
|
Vector sampledDirection(sinTheta * sinPhi,
|
||||||
|
cosTheta, -sinTheta*cosPhi);
|
||||||
pdf = pdf / (m_pdfPixelSize.x * m_pdfPixelSize.y * sinTheta);
|
pdf = pdf / (m_pdfPixelSize.x * m_pdfPixelSize.y * sinTheta);
|
||||||
|
|
||||||
return m_luminaireToWorld(Vector(
|
return m_luminaireToWorld(-sampledDirection);
|
||||||
-sinTheta * sinPhi, -cosTheta, sinTheta*cosPhi));
|
}
|
||||||
#endif
|
|
||||||
|
Point2 fromSphere(const Vector &d) const {
|
||||||
|
Float u = std::atan2(d.x,-d.z) * (0.5f * INV_PI),
|
||||||
|
v = std::acos(std::max((Float) -1.0f,
|
||||||
|
std::min((Float) 1.0f, d.y))) * INV_PI;
|
||||||
|
if (u < 0)
|
||||||
|
u += 1;
|
||||||
|
return Point2(u, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Spectrum Le(const Vector &direction) const {
|
inline Spectrum Le(const Vector &direction) const {
|
||||||
const Vector d = m_worldToLuminaire(direction);
|
Point2 uv = fromSphere(m_worldToLuminaire(direction));
|
||||||
const Float u = .5f * (1 + std::atan2(d.x,-d.z) / M_PI);
|
|
||||||
const Float v = std::acos(std::max((Float) -1.0f,
|
return m_mipmap->triangle(0, uv.x, uv.y)
|
||||||
std::min((Float) 1.0f, d.y))) / M_PI;
|
* m_intensityScale;
|
||||||
return m_mipmap->triangle(0, u, v) * m_intensityScale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Spectrum Le(const Ray &ray) const {
|
inline Spectrum Le(const Ray &ray) const {
|
||||||
|
@ -183,21 +200,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Float pdf(const Point &p, const LuminaireSamplingRecord &lRec, bool delta) const {
|
Float pdf(const Point &p, const LuminaireSamplingRecord &lRec, bool delta) const {
|
||||||
#if defined(SAMPLE_UNIFORMLY)
|
const Vector d = m_worldToLuminaire(-lRec.d);
|
||||||
return 1.0f / (4*M_PI);
|
Point2 xy = fromSphere(d);
|
||||||
#else
|
xy.x *= m_pdfResolution.x;
|
||||||
const Vector d = m_worldToLuminaire(-lRec.d);
|
xy.y *= m_pdfResolution.y;
|
||||||
const Float x = .5f * (1 + std::atan2(d.x,-d.z) / M_PI) * m_pdfResolution.x;
|
int xPos = std::min(std::max((int) std::floor(xy.x), 0), m_pdfResolution.x-1);
|
||||||
const Float y = std::acos(std::max((Float) -1.0f, std::min((Float) 1.0f, d.y)))
|
int yPos = std::min(std::max((int) std::floor(xy.y), 0), m_pdfResolution.y-1);
|
||||||
/ M_PI * m_pdfResolution.y;
|
|
||||||
int xPos = std::min(std::max((int) std::floor(x), 0), m_pdfResolution.x-1);
|
|
||||||
int yPos = std::min(std::max((int) std::floor(y), 0), m_pdfResolution.y-1);
|
|
||||||
|
|
||||||
Float pdf = m_pdf[xPos + yPos * m_pdfResolution.x];
|
Float pdf = m_pdf[xPos + yPos * m_pdfResolution.x];
|
||||||
Float sinTheta = std::sqrt(std::max((Float) Epsilon, 1-d.y*d.y));
|
Float sinTheta = std::sqrt(std::max((Float) Epsilon, 1-d.y*d.y));
|
||||||
|
|
||||||
return pdf / (m_pdfPixelSize.x * m_pdfPixelSize.y * sinTheta);
|
return pdf / (m_pdfPixelSize.x * m_pdfPixelSize.y * sinTheta);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -386,7 +399,9 @@ public:
|
||||||
<< endl
|
<< endl
|
||||||
<< "vec3 " << evalName << "_background(vec3 wo) {" << endl
|
<< "vec3 " << evalName << "_background(vec3 wo) {" << endl
|
||||||
<< " vec3 d = normalize((" << evalName << "_worldToLuminaire * vec4(wo, 0.0)).xyz);" << endl
|
<< " vec3 d = normalize((" << evalName << "_worldToLuminaire * vec4(wo, 0.0)).xyz);" << endl
|
||||||
<< " float u = 0.5 * (1.0 + atan(d.x, -d.z) * 0.318309);" << endl
|
<< " float u = atan(d.x, -d.z) * 0.15915;" << endl
|
||||||
|
<< " if (u < 0.0)" << endl
|
||||||
|
<< " u += 1.0;" << endl
|
||||||
<< " float v = acos(max(-1.0, min(1.0, d.y))) * 0.318309;" << endl
|
<< " float v = acos(max(-1.0, min(1.0, d.y))) * 0.318309;" << endl
|
||||||
// The following is not very elegant, but necessary to trick GLSL
|
// The following is not very elegant, but necessary to trick GLSL
|
||||||
// into doing correct texture filtering across the u=0 to u=1 seam.
|
// into doing correct texture filtering across the u=0 to u=1 seam.
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <mitsuba/render/scene.h>
|
#include <mitsuba/render/scene.h>
|
||||||
#include <mitsuba/core/util.h>
|
|
||||||
#include <mitsuba/core/bitmap.h>
|
#include <mitsuba/core/bitmap.h>
|
||||||
#include <mitsuba/core/fstream.h>
|
#include <mitsuba/core/plugin.h>
|
||||||
|
|
||||||
#define SAMPLE_UNIFORMLY 1
|
#define SAMPLE_UNIFORMLY 1
|
||||||
|
|
||||||
|
@ -141,6 +140,15 @@ MTS_NAMESPACE_BEGIN
|
||||||
* and the moon dominate. The model also currently does not handle cloudy skies.
|
* and the moon dominate. The model also currently does not handle cloudy skies.
|
||||||
* The implementation in Mitsuba is based on code by Preetham et al. It was
|
* The implementation in Mitsuba is based on code by Preetham et al. It was
|
||||||
* ported by Tom Kazimiers.
|
* ported by Tom Kazimiers.
|
||||||
|
*
|
||||||
|
* \begin{xml}[caption={Rotating the sky luminaire for scenes that use $Z$ as
|
||||||
|
* the ``up'' direction}, label=lst:sky-up]
|
||||||
|
* <luminaire type="sky">
|
||||||
|
* <transform name="toWorld">
|
||||||
|
* <rotate x="1" angle="90"/>
|
||||||
|
* </transform>
|
||||||
|
* </luminaire>
|
||||||
|
* \end{xml}
|
||||||
*/
|
*/
|
||||||
class SkyLuminaire : public Luminaire {
|
class SkyLuminaire : public Luminaire {
|
||||||
public:
|
public:
|
||||||
|
@ -151,12 +159,6 @@ public:
|
||||||
*/
|
*/
|
||||||
SkyLuminaire(const Properties &props)
|
SkyLuminaire(const Properties &props)
|
||||||
: Luminaire(props) {
|
: Luminaire(props) {
|
||||||
/* Transformation from the luminaire's local coordinates to
|
|
||||||
* world coordiantes */
|
|
||||||
m_luminaireToWorld =
|
|
||||||
props.getTransform("toWorld", Transform());
|
|
||||||
m_worldToLuminaire = m_luminaireToWorld.inverse();
|
|
||||||
|
|
||||||
m_scale = props.getFloat("scale", Float(1.0));
|
m_scale = props.getFloat("scale", Float(1.0));
|
||||||
m_turbidity = props.getFloat("turbidity", Float(3.0));
|
m_turbidity = props.getFloat("turbidity", Float(3.0));
|
||||||
if (m_turbidity < 1 || m_turbidity > 30)
|
if (m_turbidity < 1 || m_turbidity > 30)
|
||||||
|
@ -242,7 +244,6 @@ public:
|
||||||
|
|
||||||
m_zenithL = (4.0453f * m_turbidity - 4.9710f) * std::tan(chi)
|
m_zenithL = (4.0453f * m_turbidity - 4.9710f) * std::tan(chi)
|
||||||
- 0.2155f * m_turbidity + 2.4192f;
|
- 0.2155f * m_turbidity + 2.4192f;
|
||||||
cout << toString() << endl;
|
|
||||||
|
|
||||||
/* Evaluate quadratic polynomials to find the Perez sky
|
/* Evaluate quadratic polynomials to find the Perez sky
|
||||||
* model coefficients for the x, y and luminance components */
|
* model coefficients for the x, y and luminance components */
|
||||||
|
@ -263,12 +264,20 @@ public:
|
||||||
m_perezY[2] = -0.00792f * m_turbidity + 0.21023f;
|
m_perezY[2] = -0.00792f * m_turbidity + 0.21023f;
|
||||||
m_perezY[3] = -0.04405f * m_turbidity - 1.65369f;
|
m_perezY[3] = -0.04405f * m_turbidity - 1.65369f;
|
||||||
m_perezY[4] = -0.01092f * m_turbidity + 0.05291f;
|
m_perezY[4] = -0.01092f * m_turbidity + 0.05291f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCompound() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Luminaire *getElement(int i) {
|
||||||
|
if (i != 0)
|
||||||
|
return NULL;
|
||||||
int thetaBins = m_resolution, phiBins = m_resolution*2;
|
int thetaBins = m_resolution, phiBins = m_resolution*2;
|
||||||
|
|
||||||
ref<Bitmap> bitmap = new Bitmap(phiBins, thetaBins, 128);
|
ref<Bitmap> bitmap = new Bitmap(phiBins, thetaBins, 128);
|
||||||
bitmap->clear();
|
|
||||||
Point2 factor(M_PI / thetaBins, (2*M_PI) / phiBins);
|
Point2 factor(M_PI / thetaBins, (2*M_PI) / phiBins);
|
||||||
|
float *target = bitmap->getFloatData();
|
||||||
for (int i=0; i<thetaBins; ++i) {
|
for (int i=0; i<thetaBins; ++i) {
|
||||||
Float theta = (i+.5f)*factor.x;
|
Float theta = (i+.5f)*factor.x;
|
||||||
for (int j=0; j<phiBins; ++j) {
|
for (int j=0; j<phiBins; ++j) {
|
||||||
|
@ -276,18 +285,31 @@ public:
|
||||||
Spectrum s = getSkySpectralRadiance(theta, phi) * m_scale;
|
Spectrum s = getSkySpectralRadiance(theta, phi) * m_scale;
|
||||||
Float r, g, b;
|
Float r, g, b;
|
||||||
s.toLinearRGB(r, g, b);
|
s.toLinearRGB(r, g, b);
|
||||||
bitmap->getFloatData()[(j+i*phiBins)*4 + 0] = r;
|
*target++ = r; *target++ = g;
|
||||||
bitmap->getFloatData()[(j+i*phiBins)*4 + 1] = g;
|
*target++ = b; *target++ = 1;
|
||||||
bitmap->getFloatData()[(j+i*phiBins)*4 + 2] = b;
|
|
||||||
bitmap->getFloatData()[(j+i*phiBins)*4 + 3] = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Instantiate a nested envmap plugin */
|
||||||
|
Properties props("envmap");
|
||||||
|
Properties::Data bitmapData;
|
||||||
|
bitmapData.ptr = (uint8_t *) bitmap.get();
|
||||||
|
bitmapData.size = sizeof(Bitmap);
|
||||||
|
props.setData("bitmap", bitmapData);
|
||||||
|
props.setTransform("toWorld", m_luminaireToWorld);
|
||||||
|
props.setFloat("samplingWeight", m_samplingWeight);
|
||||||
|
Luminaire *luminaire = static_cast<Luminaire *>(
|
||||||
|
PluginManager::getInstance()->createObject(
|
||||||
|
MTS_CLASS(Luminaire), props));
|
||||||
|
luminaire->configure();
|
||||||
|
return luminaire;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector toSphere(Float theta, Float phi) const {
|
Vector toSphere(Float theta, Float phi) const {
|
||||||
/* Spherical-to-cartesian coordinate mapping with
|
/* Spherical-to-cartesian coordinate mapping with
|
||||||
theta=0 => Y=1 */
|
theta=0 => Y=1 */
|
||||||
Float cosTheta = std::cos(theta), sinTheta = std::sin(theta),
|
Float cosTheta = std::cos(theta),
|
||||||
|
sinTheta = std::sqrt(1-cosTheta*cosTheta),
|
||||||
cosPhi = std::cos(phi), sinPhi = std::sin(phi);
|
cosPhi = std::cos(phi), sinPhi = std::sin(phi);
|
||||||
return m_luminaireToWorld(Vector(
|
return m_luminaireToWorld(Vector(
|
||||||
sinTheta * sinPhi, cosTheta, -sinTheta*cosPhi));
|
sinTheta * sinPhi, cosTheta, -sinTheta*cosPhi));
|
||||||
|
@ -340,149 +362,6 @@ public:
|
||||||
m_phiS = sunPos.y;
|
m_phiS = sunPos.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void preprocess(const Scene *scene) {
|
|
||||||
/* Get the scene's bounding sphere and slightly enlarge it */
|
|
||||||
m_bsphere = scene->getBSphere();
|
|
||||||
m_bsphere.radius *= 1.01f;
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum getPower() const {
|
|
||||||
/* TODO */
|
|
||||||
return m_average * (M_PI * 4 * M_PI
|
|
||||||
* m_bsphere.radius * m_bsphere.radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Spectrum Le(const Vector &direction) const {
|
|
||||||
/* Compute sky light radiance for direction */
|
|
||||||
Vector d = normalize(m_worldToLuminaire(direction));
|
|
||||||
const Point2 sphCoords = fromSphere(d);
|
|
||||||
return getSkySpectralRadiance(sphCoords.x, sphCoords.y) * m_scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Spectrum Le(const Ray &ray) const {
|
|
||||||
return Le(normalize(ray.d));
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum Le(const LuminaireSamplingRecord &lRec) const {
|
|
||||||
return Le(-lRec.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sample(const Point &p, LuminaireSamplingRecord &lRec,
|
|
||||||
const Point2 &sample) const {
|
|
||||||
lRec.d = sampleDirection(sample, lRec.pdf, lRec.value);
|
|
||||||
lRec.sRec.p = p - lRec.d * (2 * m_bsphere.radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sample(const Intersection &its, LuminaireSamplingRecord &lRec,
|
|
||||||
const Point2 &sample) const {
|
|
||||||
SkyLuminaire::sample(its.p, lRec, sample);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Float pdf(const Point &p, const LuminaireSamplingRecord &lRec, bool delta) const {
|
|
||||||
#if defined(SAMPLE_UNIFORMLY)
|
|
||||||
return 1.0f / (4 * M_PI);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Float pdf(const Intersection &its, const LuminaireSamplingRecord &lRec, bool delta) const {
|
|
||||||
return SkyLuminaire::pdf(its.p, lRec, delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the tricky bit - we want to sample a ray that
|
|
||||||
* has uniform density over the set of all rays passing
|
|
||||||
* through the scene.
|
|
||||||
* For more detail, see "Using low-discrepancy sequences and
|
|
||||||
* the Crofton formula to compute surface areas of geometric models"
|
|
||||||
* by Li, X. and Wang, W. and Martin, R.R. and Bowyer, A.
|
|
||||||
* (Computer-Aided Design vol 35, #9, pp. 771--782)
|
|
||||||
*/
|
|
||||||
void sampleEmission(EmissionRecord &eRec,
|
|
||||||
const Point2 &sample1, const Point2 &sample2) const {
|
|
||||||
Assert(eRec.type == EmissionRecord::ENormal);
|
|
||||||
/* Chord model - generate the ray passing through two uniformly
|
|
||||||
distributed points on a sphere containing the scene */
|
|
||||||
Vector d = squareToSphere(sample1);
|
|
||||||
eRec.sRec.p = m_bsphere.center + d * m_bsphere.radius;
|
|
||||||
eRec.sRec.n = Normal(-d);
|
|
||||||
Point p2 = m_bsphere.center + squareToSphere(sample2) * m_bsphere.radius;
|
|
||||||
eRec.d = p2 - eRec.sRec.p;
|
|
||||||
Float length = eRec.d.length();
|
|
||||||
|
|
||||||
if (length == 0) {
|
|
||||||
eRec.value = Spectrum(0.0f);
|
|
||||||
eRec.pdfArea = eRec.pdfDir = 1.0f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
eRec.d /= length;
|
|
||||||
eRec.pdfArea = 1.0f / (4 * M_PI * m_bsphere.radius * m_bsphere.radius);
|
|
||||||
eRec.pdfDir = INV_PI * dot(eRec.sRec.n, eRec.d);
|
|
||||||
eRec.value = Le(-eRec.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sampleEmissionArea(EmissionRecord &eRec, const Point2 &sample) const {
|
|
||||||
if (eRec.type == EmissionRecord::ENormal) {
|
|
||||||
Vector d = squareToSphere(sample);
|
|
||||||
eRec.sRec.p = m_bsphere.center + d * m_bsphere.radius;
|
|
||||||
eRec.sRec.n = Normal(-d);
|
|
||||||
eRec.pdfArea = 1.0f / (4 * M_PI * m_bsphere.radius * m_bsphere.radius);
|
|
||||||
eRec.value = Spectrum(M_PI);
|
|
||||||
} else {
|
|
||||||
/* Preview mode, which is more suitable for VPL-based rendering: approximate
|
|
||||||
the infinitely far-away source with set of diffuse point sources */
|
|
||||||
const Float radius = m_bsphere.radius * 1.5f;
|
|
||||||
Vector d = squareToSphere(sample);
|
|
||||||
eRec.sRec.p = m_bsphere.center + d * radius;
|
|
||||||
eRec.sRec.n = Normal(-d);
|
|
||||||
eRec.pdfArea = 1.0f / (4 * M_PI * radius * radius);
|
|
||||||
eRec.value = Le(d) * M_PI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum sampleEmissionDirection(EmissionRecord &eRec, const Point2 &sample) const {
|
|
||||||
Float radius = m_bsphere.radius;
|
|
||||||
if (eRec.type == EmissionRecord::EPreview)
|
|
||||||
radius *= 1.5f;
|
|
||||||
Point p2 = m_bsphere.center + squareToSphere(sample) * radius;
|
|
||||||
eRec.d = p2 - eRec.sRec.p;
|
|
||||||
Float length = eRec.d.length();
|
|
||||||
|
|
||||||
if (length == 0.0f) {
|
|
||||||
eRec.pdfDir = 1.0f;
|
|
||||||
return Spectrum(0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
eRec.d /= length;
|
|
||||||
eRec.pdfDir = INV_PI * dot(eRec.sRec.n, eRec.d);
|
|
||||||
if (eRec.type == EmissionRecord::ENormal)
|
|
||||||
return Le(-eRec.d) * INV_PI;
|
|
||||||
else
|
|
||||||
return Spectrum(INV_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum evalDirection(const EmissionRecord &eRec) const {
|
|
||||||
if (eRec.type == EmissionRecord::ENormal)
|
|
||||||
return Le(-eRec.d) * INV_PI;
|
|
||||||
else
|
|
||||||
return Spectrum(INV_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum evalArea(const EmissionRecord &eRec) const {
|
|
||||||
Assert(eRec.type == EmissionRecord::ENormal);
|
|
||||||
return Spectrum(M_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum f(const EmissionRecord &eRec) const {
|
|
||||||
if (eRec.type == EmissionRecord::ENormal)
|
|
||||||
return Le(-eRec.d) * INV_PI;
|
|
||||||
else
|
|
||||||
return Spectrum(INV_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pdfEmission(EmissionRecord &eRec, bool delta) const {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "SkyLuminaire[" << endl
|
oss << "SkyLuminaire[" << endl
|
||||||
|
@ -493,20 +372,6 @@ public:
|
||||||
<< "]";
|
<< "]";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBackgroundLuminaire() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector sampleDirection(Point2 sample, Float &pdf, Spectrum &value) const {
|
|
||||||
#if defined(SAMPLE_UNIFORMLY)
|
|
||||||
pdf = 1.0f / (4*M_PI);
|
|
||||||
Vector d = squareToSphere(sample);
|
|
||||||
value = Le(-d);
|
|
||||||
return d;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Calculates the angle between two spherical cooridnates. All
|
* Calculates the angle between two spherical cooridnates. All
|
||||||
|
@ -586,9 +451,9 @@ private:
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
protected:
|
protected:
|
||||||
Spectrum m_average;
|
/* Environment map resolution */
|
||||||
BSphere m_bsphere;
|
|
||||||
int m_resolution;
|
int m_resolution;
|
||||||
|
/* Constant scale factor applied to the model */
|
||||||
Float m_scale;
|
Float m_scale;
|
||||||
/* The turbidity of the sky ranges normally from 1 to 30.
|
/* The turbidity of the sky ranges normally from 1 to 30.
|
||||||
For clear skies values in range [2,6] are useful. */
|
For clear skies values in range [2,6] are useful. */
|
||||||
|
@ -606,6 +471,6 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(SkyLuminaire, false, Luminaire)
|
MTS_IMPLEMENT_CLASS_S(SkyLuminaire, false, Luminaire)
|
||||||
MTS_EXPORT_PLUGIN(SkyLuminaire, "Sky luminaire");
|
MTS_EXPORT_PLUGIN(SkyLuminaire, "Preetham sky luminaire");
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
||||||
|
|
|
@ -554,13 +554,13 @@ public:
|
||||||
LuminaireAdapter adapter(luminaire, sampler);
|
LuminaireAdapter adapter(luminaire, sampler);
|
||||||
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, 1);
|
ref<ChiSquare> chiSqr = new ChiSquare(thetaBins, 2*thetaBins, 1);
|
||||||
chiSqr->setLogLevel(EDebug);
|
chiSqr->setLogLevel(EDebug);
|
||||||
chiSqr->dumpTables("test.m");
|
|
||||||
|
|
||||||
// Initialize the tables used by the chi-square test
|
// Initialize the tables used by the chi-square test
|
||||||
chiSqr->fill(
|
chiSqr->fill(
|
||||||
boost::bind(&LuminaireAdapter::generateSample, &adapter),
|
boost::bind(&LuminaireAdapter::generateSample, &adapter),
|
||||||
boost::bind(&LuminaireAdapter::pdf, &adapter, _1, _2)
|
boost::bind(&LuminaireAdapter::pdf, &adapter, _1, _2)
|
||||||
);
|
);
|
||||||
|
chiSqr->dumpTables("test.m");
|
||||||
|
|
||||||
// (the following assumes that the distribution has 1 parameter, e.g. exponent value)
|
// (the following assumes that the distribution has 1 parameter, e.g. exponent value)
|
||||||
ChiSquare::ETestResult result = chiSqr->runTest(SIGNIFICANCE_LEVEL);
|
ChiSquare::ETestResult result = chiSqr->runTest(SIGNIFICANCE_LEVEL);
|
||||||
|
|
Loading…
Reference in New Issue