portal luminaire, support for adjustments when importing from COLLADA, bugfixes

metadata
Wenzel Jakob 2010-08-13 14:53:52 +02:00
parent b8ff508576
commit fa1789be6d
11 changed files with 488 additions and 37 deletions

View File

@ -409,7 +409,7 @@ if hasCollada:
if env.has_key('COLLADALIB'):
colladaEnv.Append(LIBS=env['COLLADALIB'])
colladaConverter = colladaEnv.StaticObject('src/collada/converter.cpp')
colladaEnv.Program('mtsimport', darwinStub + ['src/collada/main.cpp', colladaConverter])
colladaEnv.Program('mtsimport', darwinStub + ['src/collada/main.cpp', colladaConverter] + resources)
if hasQt:
qtEnv = mainEnv.Clone()
@ -529,6 +529,7 @@ plugins += env.SharedLibrary('plugins/spot', ['src/luminaires/spot.cpp'])
plugins += env.SharedLibrary('plugins/point', ['src/luminaires/point.cpp'])
plugins += env.SharedLibrary('plugins/collimated', ['src/luminaires/collimated.cpp'])
plugins += env.SharedLibrary('plugins/directional', ['src/luminaires/directional.cpp'])
plugins += env.SharedLibrary('plugins/portal', ['src/luminaires/portal.cpp'])
# Integrators
plugins += env.SharedLibrary('plugins/direct', ['src/integrators/direct/direct.cpp'])

View File

@ -133,10 +133,11 @@ Passing strings is very straightforward:
\end{xml}
\subsubsection{Color spectra}
There are several different ways of passing color spectra to objects, which can be used interchangeably.
The most basic one is to supply linear RGB values as floating-point triplets or hex values
The most basic one is to supply linear RGB or sRGB values as floating-point triplets or hex values
\begin{xml}
<rgb name="spectrumProperty" value="0.2, 0.8, 0.4"/>
<rgb name="spectrumProperty" value="#f9aa34"/>
<srgb name="spectrumProperty" value="0.4, 0.3, 0.2"/>
<srgb name="spectrumProperty" value="#f9aa34"/>
\end{xml}
When Mitsuba is compiled with the default settings, it internally uses linear RGB to represent colors, so
these values are directly used. The renderer can also be configured to sample the color spectrum using a specified

View File

@ -22,6 +22,7 @@
<xsd:element name="string" type="string"/>
<xsd:element name="spectrum" type="string"/>
<xsd:element name="rgb" type="string"/>
<xsd:element name="srgb" type="string"/>
<xsd:element name="blackbody" type="blackbody"/>
</xsd:choice>
</xsd:complexType>
@ -40,6 +41,7 @@
<xsd:element name="string" type="string"/>
<xsd:element name="spectrum" type="string"/>
<xsd:element name="rgb" type="string"/>
<xsd:element name="srgb" type="string"/>
<xsd:element name="blackbody" type="blackbody"/>
</xsd:choice>
<xsd:attribute name="type" type="xsd:string" use="required"/>
@ -83,6 +85,7 @@
<xsd:extension base="object">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="texture" type="object"/>
<xsd:element name="luminaire" type="luminaire"/>
</xsd:choice>
</xsd:extension>
</xsd:complexContent>
@ -97,7 +100,7 @@
<xsd:element name="bsdf" type="bsdf"/>
<xsd:element name="subsurface" type="object"/>
<xsd:element name="ref" type="reference"/>
<xsd:element name="luminaire" type="object"/>
<xsd:element name="luminaire" type="luminaire"/>
</xsd:choice>
</xsd:extension>
</xsd:complexContent>

View File

@ -232,6 +232,18 @@ public:
return Spectrum(0.0f);
}
void addChild(const std::string &name, ConfigurableObject *child) {
if (child->getClass()->derivesFrom(Texture::m_theClass) && name == "diffuseReflectance") {
m_diffuseReflectance = static_cast<Texture *>(child);
m_usesRayDifferentials |= m_diffuseReflectance->usesRayDifferentials();
} else if (child->getClass()->derivesFrom(Texture::m_theClass) && name == "specularReflectance") {
m_specularReflectance = static_cast<Texture *>(child);
m_usesRayDifferentials |= m_specularReflectance->usesRayDifferentials();
} else {
BSDF::addChild(name, child);
}
}
void serialize(Stream *stream, InstanceManager *manager) const {
BSDF::serialize(stream, manager);

View File

@ -1,6 +1,20 @@
#define BOOST_FILESYSTEM_NO_LIB
#define BOOST_SYSTEM_NO_LIB
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMDocumentType.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMNodeIterator.hpp>
#include <xercesc/dom/DOMNodeList.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/framework/Wrapper4DOMInputSource.hpp>
#include <xercesc/framework/Wrapper4InputSource.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <mitsuba/mitsuba.h>
#include <mitsuba/render/trimesh.h>
#include <mitsuba/core/fresolver.h>
@ -19,6 +33,8 @@
#include <GL/glu.h>
#endif
XERCES_CPP_NAMESPACE_USE
#include "converter.h"
typedef std::map<std::string, std::string> StringMap;
@ -81,6 +97,86 @@ struct VertexData {
}
};
class ImporterDOMErrorHandler : public DOMErrorHandler {
public:
inline ImporterDOMErrorHandler() { }
bool handleError(const DOMError& domError) {
ELogLevel logLevel;
if (domError.getSeverity() == DOMError::DOM_SEVERITY_WARNING)
logLevel = EWarn;
else
logLevel = EError;
SLog(logLevel, "%s (line %i, char %i): %s",
XMLString::transcode(domError.getLocation()->getURI()),
domError.getLocation()->getLineNumber(),
domError.getLocation()->getColumnNumber(),
XMLString::transcode(domError.getMessage()));
return true;
}
};
void findRemovals(DOMNode *node, std::set<std::string> &removals) {
if (node) {
if (node->getNodeType() == DOMNode::ELEMENT_NODE && node->hasAttributes()) {
DOMNamedNodeMap *attributes = node->getAttributes();
for (size_t i=0; i<attributes->getLength(); ++i) {
DOMAttr *attribute = (DOMAttr*) attributes->item(i);
char *name = XMLString::transcode(attribute->getName());
char *value = XMLString::transcode(attribute->getValue());
if (strcmp(name, "id") == 0)
removals.insert(value);
XMLString::release(&name);
XMLString::release(&value);
}
}
for (DOMNode *child = node->getFirstChild(); child != 0; child=child->getNextSibling())
findRemovals(child, removals);
}
}
bool cleanupPass(DOMNode *node, const std::set<std::string> &removals) {
if (node) {
char *nodeName = XMLString::transcode(node->getNodeName());
if (strcmp(nodeName, "ref") == 0) {
XMLString::release(&nodeName);
return false;
}
if (node->getNodeType() == DOMNode::ELEMENT_NODE && node->hasAttributes()) {
DOMNamedNodeMap *attributes = node->getAttributes();
for (size_t i=0; i<attributes->getLength(); ++i) {
DOMAttr *attribute = (DOMAttr*) attributes->item(i);
char *name = XMLString::transcode(attribute->getName());
char *value = XMLString::transcode(attribute->getValue());
if (strcmp(name, "id") == 0 && removals.find(value) != removals.end()) {
XMLString::release(&name);
XMLString::release(&value);
return true; /* Remove this node */
}
XMLString::release(&name);
XMLString::release(&value);
}
XMLString::release(&nodeName);
}
DOMNode *child = node->getFirstChild();
while (child) {
DOMNode *next = child->getNextSibling();
bool doRemove = cleanupPass(child, removals);
if (doRemove)
node->removeChild(child);
child = next;
}
}
return false;
}
/* This code is not thread-safe for now */
GLUtesselator *tess = NULL;
std::vector<domUint> tess_data;
@ -383,7 +479,7 @@ void loadGeometry(std::string nodeName, Transform transform, std::ostream &os, d
}
}
void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &idToTexture,
void loadMaterialParam(ColladaConverter *cvt, std::ostream &os, const std::string &name, StringMap &idToTexture,
domCommon_color_or_texture_type *value, bool handleRefs) {
if (!value)
return;
@ -393,8 +489,11 @@ void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &idT
value->getTexture().cast();
if (color && !handleRefs) {
domFloat4 &colValue = color->getValue();
os << "\t\t<rgb name=\"" << name << "\" value=\""
<< colValue.get(0) << " " << colValue.get(1) << " "
if (cvt->m_srgb)
os << "\t\t<srgb name=\"" << name << "\" value=\"";
else
os << "\t\t<rgb name=\"" << name << "\" value=\"";
os << colValue.get(0) << " " << colValue.get(1) << " "
<< colValue.get(2) << "\"/>" << endl;
} else if (texture && handleRefs) {
if (idToTexture.find(texture->getTexture()) == idToTexture.end()) {
@ -406,7 +505,7 @@ void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &idT
}
}
void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &,
void loadMaterialParam(ColladaConverter *cvt, std::ostream &os, const std::string &name, StringMap &,
domCommon_float_or_param_type *value, bool handleRef) {
if (!value)
return;
@ -417,7 +516,7 @@ void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &,
}
}
void loadMaterial(std::ostream &os, domMaterial &mat, StringMap &_idToTexture) {
void loadMaterial(ColladaConverter *cvt, std::ostream &os, domMaterial &mat, StringMap &_idToTexture) {
SLog(EInfo, "Converting material \"%s\" ..", mat.getName());
StringMap idToTexture = _idToTexture;
@ -485,24 +584,24 @@ void loadMaterial(std::ostream &os, domMaterial &mat, StringMap &_idToTexture) {
}
if (isDiffuse) {
os << "\t<bsdf id=\"" << mat.getId() << "\" type=\"lambertian\">" << endl;
loadMaterialParam(os, "reflectance", idToTexture, diffuse, false);
loadMaterialParam(os, "reflectance", idToTexture, diffuse, true);
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, false);
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, true);
os << "\t</bsdf>" << endl << endl;
} else {
os << "\t<bsdf id=\"" << mat.getId() << "\" type=\"phong\">" << endl;
loadMaterialParam(os, "diffuseReflectance", idToTexture, diffuse, false);
loadMaterialParam(os, "specularReflectance", idToTexture, specular, false);
loadMaterialParam(os, "exponent", idToTexture, shininess, false);
loadMaterialParam(os, "diffuseReflectance", idToTexture, diffuse, true);
loadMaterialParam(os, "specularReflectance", idToTexture, specular, true);
loadMaterialParam(os, "exponent", idToTexture, shininess, true);
loadMaterialParam(cvt, os, "diffuseReflectance", idToTexture, diffuse, false);
loadMaterialParam(cvt, os, "specularReflectance", idToTexture, specular, false);
loadMaterialParam(cvt, os, "exponent", idToTexture, shininess, false);
loadMaterialParam(cvt, os, "diffuseReflectance", idToTexture, diffuse, true);
loadMaterialParam(cvt, os, "specularReflectance", idToTexture, specular, true);
loadMaterialParam(cvt, os, "exponent", idToTexture, shininess, true);
os << "\t</bsdf>" << endl << endl;
}
} else if (lambert) {
domCommon_color_or_texture_type* diffuse = lambert->getDiffuse();
os << "\t<bsdf id=\"" << mat.getId() << "\" type=\"lambertian\">" << endl;
loadMaterialParam(os, "reflectance", idToTexture, diffuse, false);
loadMaterialParam(os, "reflectance", idToTexture, diffuse, true);
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, false);
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, true);
os << "\t</bsdf>" << endl << endl;
} else {
SLog(EError, "Material type not supported! (must be Lambertian/Phong)");
@ -670,8 +769,9 @@ void loadCamera(Transform transform, std::ostream &os, domCamera &camera) {
os << "\t\t<transform name=\"toWorld\">" << endl;
os << "\t\t\t<matrix value=\"" << matrixValues.substr(0, matrixValues.length()-1) << "\"/>" << endl;
os << "\t\t</transform>" << endl << endl;
os << "\t\t<sampler type=\"stratified\"/>" << endl << endl;
os << "\t\t<sampler type=\"ldsampler\">" << endl;
os << "\t\t\t<integer name=\"sampleCount\" value=\"8\"/>" << endl;
os << "\t\t</sampler>" << endl << endl;
os << "\t\t<film type=\"exrfilm\">" << endl;
os << "\t\t\t<integer name=\"width\" value=\"" << xres << "\"/>" << endl;
os << "\t\t\t<integer name=\"height\" value=\"" << (int) (xres/aspect) << "\"/>" << endl;
@ -876,8 +976,8 @@ void ColladaConverter::convert(const std::string &inputFile,
domNode_Array &nodes = visualScene->getNode_array();
os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << endl;
os << "<!--" << endl;
os << "\tAutomatically converted from COLLADA" << endl;
os << "<!--" << endl << endl;
os << "\tAutomatically converted from COLLADA" << endl << endl;
os << "-->" << endl << endl;
os << "<scene>" << endl;
os << "\t<integrator type=\"direct\"/>" << endl << endl;
@ -896,7 +996,7 @@ void ColladaConverter::convert(const std::string &inputFile,
for (size_t i=0; i<libraryMaterials.getCount(); ++i) {
domMaterial_Array &materials = libraryMaterials[i]->getMaterial_array();
for (size_t j=0; j<materials.getCount(); ++j)
loadMaterial(os, *materials.get(j), idToTexture);
loadMaterial(this, os, *materials.get(j), idToTexture);
}
for (size_t i=0; i<nodes.getCount(); ++i)
@ -907,10 +1007,71 @@ void ColladaConverter::convert(const std::string &inputFile,
gluDeleteTess(tess);
delete dae;
if (adjustmentFile != "") {
SLog(EInfo, "Applying adjustments ..");
static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull };
DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(gLS);
DOMBuilder *parser = ((DOMImplementationLS*) impl)->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
ImporterDOMErrorHandler errorHandler;
parser->setErrorHandler(&errorHandler);
std::string xmlString = os.str();
MemBufInputSource* memBufIS = new MemBufInputSource((const XMLByte*) xmlString.c_str(),
xmlString.length(), "bufID", false);
Wrapper4InputSource *wrapper = new Wrapper4InputSource(memBufIS, false);
DOMDocument *doc = parser->parse(*wrapper);
DOMDocument *adj = parser->parseURI(adjustmentFile.c_str());
std::set<std::string> removals;
findRemovals(adj, removals);
cleanupPass(doc, removals);
DOMElement *docRoot = doc->getDocumentElement();
DOMElement *adjRoot = adj->getDocumentElement();
DOMNode *insertBeforeNode = NULL;
for (DOMNode *child = docRoot->getFirstChild(); child != 0; child=child->getNextSibling()) {
char *name = XMLString::transcode(child->getNodeName());
if (strcmp(name, "shape") == 0) {
insertBeforeNode = child;
break;
}
XMLString::release(&name);
}
if (insertBeforeNode == NULL) {
/* No shape node found, use the camera node instead */
for (DOMNode *child = docRoot->getFirstChild(); child != 0; child=child->getNextSibling()) {
char *name = XMLString::transcode(child->getNodeName());
if (strcmp(name, "camera") == 0) {
insertBeforeNode = child;
break;
}
XMLString::release(&name);
}
SAssertEx(insertBeforeNode != NULL, "Internal error while applying adjustments: cannot find shape/camera node");
}
for (DOMNode *child = adjRoot->getFirstChild(); child != 0; child=child->getNextSibling())
docRoot->insertBefore(doc->importNode(child, true), insertBeforeNode);
DOMWriter *serializer = ((DOMImplementationLS*)impl)->createDOMWriter();
serializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
serializer->setErrorHandler(&errorHandler);
XMLFormatTarget *target = new LocalFileFormatTarget(outputFile.c_str());
serializer->writeNode(target, *doc);
delete wrapper;
delete memBufIS;
delete serializer;
parser->release();
} else {
std::ofstream ofile(outputFile.c_str());
if (ofile.fail())
SLog(EError, "Could not write to \"%s\"!", outputFile.c_str());
ofile << os.str();
ofile.close();
}
}

View File

@ -4,7 +4,9 @@ using namespace mitsuba;
class ColladaConverter {
public:
inline ColladaConverter() { }
inline ColladaConverter() {
m_srgb = false;
}
void convert(const std::string &inputFile,
const std::string &outputDirectory,
@ -12,4 +14,8 @@ public:
const std::string &adjustmentFile);
virtual std::string locateResource(const std::string &resource) = 0;
void setSRGB(bool srgb) { m_srgb = srgb; }
public:
bool m_srgb;
};

View File

@ -29,10 +29,14 @@
* (e.g. using Lighting/shading -> Batch bake in Maya).
*/
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/dom/DOMException.hpp>
#include "converter.h"
#include <mitsuba/hw/glrenderer.h>
#include <mitsuba/core/fresolver.h>
XERCES_CPP_NAMESPACE_USE
class ConsoleColladaConverter : public ColladaConverter {
public:
inline ConsoleColladaConverter() {
@ -43,21 +47,57 @@ public:
}
};
int colladaMain(int argc, char **argv) {
if (argc < 3) {
cout << "Syntax: mtsimport <DAE source file URL> <XML destination file> [Adjustment file]" << endl
void help() {
cout << "COLLADA 1.4 Importer, Version " MTS_VERSION ", Copyright (c) " MTS_YEAR " Wenzel Jakob" << endl
<< "Syntax: mtsimport [options] <DAE source file> <XML destination file> [Adjustment file]" << endl
<< "Options/Arguments:" << endl
<< " -h Display this help text" << endl << endl
<< " -s Assume that colors are in sRGB space." << endl << endl
<< "Please see the documentation for more information." << endl;
}
int colladaMain(int argc, char **argv) {
bool srgb = false;
char optchar;
optind = 1;
while ((optchar = getopt(argc, argv, "sh")) != -1) {
switch (optchar) {
case 's':
srgb = true;
break;
case 'h':
default:
help();
return -1;
}
};
if (argc-optind < 2) {
help();
return -1;
}
ConsoleColladaConverter converter;
converter.convert(argv[1], "", argv[2], argc > 3 ? argv[3] : "");
converter.setSRGB(srgb);
converter.convert(argv[optind], "", argv[optind+1], argc > optind+2 ? argv[optind+2] : "");
return 0;
}
int ubi_main(int argc, char **argv) {
int retval;
/* Initialize Xerces-C */
try {
XMLPlatformUtils::Initialize();
} catch(const XMLException &toCatch) {
fprintf(stderr, "Error during Xerces initialization: %s",
XMLString::transcode(toCatch.getMessage()));
return -1;
}
/* Initialize the core framework */
Class::staticInitialization();
Statistics::staticInitialization();
@ -112,11 +152,21 @@ int ubi_main(int argc, char **argv) {
} catch (const std::exception &e) {
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
retval = -1;
} catch(const XMLException &toCatch) {
SLog(EError, "Caught a Xerces exception: %s",
XMLString::transcode(toCatch.getMessage()));
retval = -1;
} catch(const DOMException &toCatch) {
SLog(EError, "Caught a Xerces exception: %s",
XMLString::transcode(toCatch.getMessage()));
retval = -1;
} catch (...) {
std::cerr << "Caught a critical exeption of unknown type!" << endl;
retval = -1;
}
XMLPlatformUtils::Terminate();
/* Shutdown the core framework */
Spectrum::staticShutdown();
Logger::staticShutdown();

194
src/luminaires/portal.cpp Normal file
View File

@ -0,0 +1,194 @@
#include <mitsuba/render/scene.h>
#include <mitsuba/hw/gpuprogram.h>
MTS_NAMESPACE_BEGIN
/**
* Portal luminaire -- can be used to turn a surface into a
* portal that exposes luminaires behind it, such as an
* environment map. This is often necessary to make interior
* lighting work efficiently enough when using algorithms like
* path tracing or photon mapping.
*/
class PortalLuminaire : public Luminaire {
public:
PortalLuminaire(const Properties &props) : Luminaire(props), m_shape(NULL) {
AssertEx(m_luminaireToWorld.isIdentity(), "Error: non-identity transformation found. "
"Portal luminaires inherit their transformation from the associated shape!");
m_type = EDiffuseDirection | EOnSurface;
m_intersectable = true;
}
virtual ~PortalLuminaire() {
for (size_t i=0; i<m_luminaires.size(); ++i)
m_luminaires[i]->decRef();
}
PortalLuminaire(Stream *stream, InstanceManager *manager)
: Luminaire(stream, manager) {
m_shape = static_cast<Shape *>(manager->getInstance(stream));
int luminaireCount = stream->readInt();
for (int i=0; i<luminaireCount; ++i)
addChild("", static_cast<Luminaire *>(manager->getInstance(stream)));
configure();
}
void preprocess(const Scene *scene) {
for (size_t i=0; i<m_luminaires.size(); ++i)
m_luminaires[i]->preprocess(scene);
configure();
}
void serialize(Stream *stream, InstanceManager *manager) const {
Luminaire::serialize(stream, manager);
manager->serialize(stream, m_shape);
stream->writeInt((int) m_luminaires.size());
for (size_t i=0; i<m_luminaires.size(); ++i)
manager->serialize(stream, m_luminaires[i]);
}
void addChild(const std::string &name, ConfigurableObject *child) {
const Class *cClass = child->getClass();
if (cClass->derivesFrom(Luminaire::m_theClass)) {
Luminaire *luminaire = static_cast<Luminaire *>(child);
m_luminaires.push_back(luminaire);
luminaire->incRef();
} else {
Luminaire::addChild(name, child);
}
}
void setParent(ConfigurableObject *parent) {
ConfigurableObject::setParent(parent);
if (parent->getClass()->derivesFrom(Shape::m_theClass)) {
m_shape = static_cast<Shape *>(parent);
parent->configure();
m_surfaceArea = m_shape->getSurfaceArea();
} else {
Log(EError, "An portal light source must be child of a shape instance");
}
}
void configure() {
m_power = Spectrum(0.0f);
if (m_luminaires.size() == 0)
Log(EError, "Portal luminaire must have one or more child luminaires!");
for (size_t i=0; i<m_luminaires.size(); ++i) {
m_luminaires[i]->configure();
m_power += m_luminaires[i]->getPower();
}
}
Spectrum getPower() const {
return m_power;
}
Spectrum Le(const EmissionRecord &eRec) const {
Spectrum result(0.0f);
if (dot(eRec.d, eRec.sRec.n) <= 0)
return Spectrum(0.0f);
for (size_t i=0; i<m_luminaires.size(); ++i)
result += m_luminaires[i]->Le(Ray(eRec.sRec.p, -eRec.d));
return result;
}
Spectrum Le(const LuminaireSamplingRecord &lRec) const {
Spectrum result(0.0f);
if (dot(lRec.d, lRec.sRec.n) <= 0)
return Spectrum(0.0f);
for (size_t i=0; i<m_luminaires.size(); ++i)
result += m_luminaires[i]->Le(Ray(lRec.sRec.p, -lRec.d));
return result;
}
inline void sample(const Point &p, LuminaireSamplingRecord &lRec,
const Point2 &sample) const {
lRec.pdf = m_shape->sampleSolidAngle(lRec.sRec, p, sample);
lRec.d = p - lRec.sRec.p;
if (EXPECT_TAKEN(lRec.pdf > 0 && dot(lRec.d, lRec.sRec.n) > 0)) {
lRec.d = normalize(lRec.d);
lRec.Le = Le(lRec);
} else {
lRec.pdf = 0;
}
}
inline void sample(const Intersection &its, LuminaireSamplingRecord &lRec,
const Point2 &sample) const {
PortalLuminaire::sample(its.p, lRec, sample);
}
inline Float pdf(const Point &p, const LuminaireSamplingRecord &lRec) const {
return m_shape->pdfSolidAngle(lRec.sRec, p);
}
Float pdf(const Intersection &its, const LuminaireSamplingRecord &lRec) const {
return pdf(its.p, lRec);
}
void sampleEmission(EmissionRecord &eRec,
const Point2 &sample1, const Point2 &sample2) const {
eRec.pdfArea = m_shape->sampleArea(eRec.sRec, sample1);
Vector wo = squareToHemispherePSA(sample2);
eRec.pdfDir = Frame::cosTheta(wo) * INV_PI;
eRec.d = Frame(eRec.sRec.n).toWorld(wo);
eRec.P = Le(eRec);
}
void sampleEmissionArea(EmissionRecord &eRec, const Point2 &sample) const {
eRec.pdfArea = m_shape->sampleArea(eRec.sRec, sample);
eRec.P = 1.0f;
}
Spectrum fArea(const EmissionRecord &eRec) const {
return 1.0f;
}
Spectrum sampleEmissionDirection(EmissionRecord &eRec, const Point2 &sample) const {
Vector wo = squareToHemispherePSA(sample);
eRec.d = Frame(eRec.sRec.n).toWorld(wo);
eRec.pdfDir = Frame::cosTheta(wo) * INV_PI;
return Le(eRec);
}
Spectrum f(const EmissionRecord &eRec) const {
Float dp = dot(eRec.sRec.n, eRec.d);
if (dp > 0)
return Le(eRec);
else
return Spectrum(0.0f);
}
void pdfEmission(EmissionRecord &eRec) const {
Float dp = dot(eRec.sRec.n, eRec.d);
if (dp > 0)
eRec.pdfDir = dp * INV_PI;
else {
eRec.pdfDir = 0;
}
eRec.pdfArea = m_shape->pdfArea(eRec.sRec);
}
std::string toString() const {
return "PortalLuminaire[]";
}
MTS_DECLARE_CLASS()
private:
const Shape *m_shape;
Spectrum m_power;
std::vector<Luminaire *> m_luminaires;
};
MTS_IMPLEMENT_CLASS_S(PortalLuminaire, false, Luminaire)
MTS_EXPORT_PLUGIN(PortalLuminaire, "Portal luminaire");
MTS_NAMESPACE_END

View File

@ -236,6 +236,29 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
specValue.fromLinearRGB(value[0], value[1], value[2]);
context.parent->properties.setSpectrum(context.attributes["name"],
specValue);
} else if (name == "srgb") {
std::string valueStr = context.attributes["value"];
std::vector<std::string> tokens = tokenize(valueStr, ", ");
Float value[3];
if (tokens.size() == 1 && tokens[0].length() == 7 && tokens[0][0] == '#') {
char *end_ptr = NULL;
/* Parse HTML-style hexadecimal colors */
int encoded = strtol(tokens[0].c_str()+1, &end_ptr, 16);
if (*end_ptr != '\0')
SLog(EError, "Invalid sRGB value specified (in <%s>)", context.attributes["name"].c_str());
value[0] = ((encoded & 0xFF0000) >> 16) / 255.0f;
value[1] = ((encoded & 0x00FF00) >> 8) / 255.0f;
value[2] = (encoded & 0x0000FF) / 255.0f;
} else {
if (tokens.size() != 3)
SLog(EError, "Invalid RGB value specified");
for (int i=0; i<3; i++)
value[i] = parseFloat(name, tokens[i]);
}
Spectrum specValue;
specValue.fromSRGB(value[0], value[1], value[2]);
context.parent->properties.setSpectrum(context.attributes["name"],
specValue);
} else if (name == "blackbody") {
Float temperature = parseFloat(name, context.attributes["temperature"]);
BlackBodySpectrum *spec = new BlackBodySpectrum(temperature);

View File

@ -1,5 +1,5 @@
#include <QtGui/QtGui>
#include <xercesc/parsers/SAXParser.hpp>
#include <QtGui/QtGui>
#include <mitsuba/core/shvector.h>
#include <mitsuba/core/sched.h>
#if defined(__OSX__)