Accumulated changes since the v.0.1.1. release
* constant.cpp, src/libhw/vpl.cpp: Support for image environment sources and spot lights in the real-time preview. * mitsuba.cpp: Ability to run the 'mitsuba' execubable in arbitrary locations on OSX while ensuring that it still finds all plugins etc. * mtsimport: COLLADA importer support for ambient lights and 'polylist' meshes. * scene.cpp: Create a default camera when none is specified in the XML file. * constant.cpp, src/libhw/vpl.cpp: Support for rendering constant environment sources in the real-time preview. * glwidget.cpp, mainwindow.cpp: Support for Drag & Drop * glwidget.cpp, mainwindow.cpp: The Mitsuba user interface now also doubles as an EXR viewer / tonemapper. Drag an EXR file onto the UI or open it using the File menu, and the image opens in a new tab. Afterwards, it is possible to export the image as a tonemapped 8-bit PNG image.metadata
parent
6f326a1f87
commit
be412e8313
|
@ -6,6 +6,7 @@ Mitsuba.app
|
|||
.*moc_.*\.cc$
|
||||
.*qrc_.*\.cc$
|
||||
.*\.dylib$
|
||||
\.DS_Store
|
||||
sconf_temp
|
||||
mitsuba
|
||||
mtsgui
|
||||
|
|
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
|||
2010-08-05 Wenzel Jakob <wenzel@cs.cornell.edu>
|
||||
|
||||
* constant.cpp, src/libhw/vpl.cpp: Support for image environment
|
||||
sources and spot lights in the real-time preview.
|
||||
|
||||
2010-08-03 Wenzel Jakob <wenzel@cs.cornell.edu>
|
||||
|
||||
* mitsuba.cpp: Ability to run the 'mitsuba' execubable in arbitrary
|
||||
locations on OSX while ensuring that it still finds all plugins etc.
|
||||
|
||||
* mtsimport: COLLADA importer support for ambient lights and 'polylist' meshes.
|
||||
|
||||
* scene.cpp: Create a default camera when none is specified in the XML file.
|
||||
|
||||
* constant.cpp, src/libhw/vpl.cpp: Support for rendering constant environment
|
||||
sources in the real-time preview.
|
||||
|
||||
2010-07-21 Wenzel Jakob <wenzel@cs.cornell.edu>
|
||||
|
||||
* glwidget.cpp, mainwindow.cpp: Support for Drag & Drop
|
||||
|
||||
* glwidget.cpp, mainwindow.cpp: The Mitsuba user interface now also
|
||||
doubles as an EXR viewer / tonemapper. Drag an EXR file onto the
|
||||
UI or open it using the File menu, and the image opens in a new
|
||||
tab. Afterwards, it is possible to export the image as a tonemapped
|
||||
8-bit PNG image.
|
||||
|
||||
2010-07-19 Wenzel Jakob <wenzel@cs.cornell.edu>
|
||||
|
||||
* include/mitsuba/mitsuba.h: First semi-official external release 0.1.1
|
||||
|
|
|
@ -2,6 +2,7 @@ import SCons
|
|||
import sys
|
||||
import glob
|
||||
import os
|
||||
import fnmatch
|
||||
|
||||
if not os.path.exists('config.py'):
|
||||
print 'A configuration file must be selected! Have a look at \"README\"'
|
||||
|
@ -142,7 +143,7 @@ if not conf.CheckCXXHeader('dae.h'):
|
|||
hasCollada = False
|
||||
print 'COLLADA DOM is missing: not building the COLLADA importer'
|
||||
if not conf.CheckCXXHeader('boost/math/distributions/students_t.hpp'):
|
||||
print 'Boost is missing (install libboost1.37-dev and libboost-math1.37-dev)!'
|
||||
print 'Boost is missing (install libboost1.40-dev and libboost-math1.40-dev)!'
|
||||
Exit(1)
|
||||
if sys.platform == 'win32':
|
||||
if not (conf.CheckCHeader(['windows.h', 'GL/gl.h']) and conf.CheckCHeader(['windows.h', 'GL/glu.h']) and conf.CheckCHeader(['windows.h', 'GL/gl.h', 'GL/glext.h'])):
|
||||
|
@ -469,6 +470,7 @@ plugins += env.SharedLibrary('plugins/serialized', ['src/shapes/serialized.cpp']
|
|||
plugins += env.SharedLibrary('plugins/sphere', ['src/shapes/sphere.cpp'])
|
||||
plugins += env.SharedLibrary('plugins/cylinder', ['src/shapes/cylinder.cpp'])
|
||||
plugins += env.SharedLibrary('plugins/hair', ['src/shapes/hair.cpp'])
|
||||
#plugins += env.SharedLibrary('plugins/group', ['src/shapes/group.cpp'])
|
||||
|
||||
# Samplers
|
||||
plugins += env.SharedLibrary('plugins/independent', ['src/samplers/independent.cpp'])
|
||||
|
@ -671,7 +673,9 @@ elif sys.platform == 'darwin':
|
|||
installTargets += env.Install('Mitsuba.app/Contents/Resources/PreviewSettings.nib', 'tools/darwin/PreviewSettings.nib/keyedobjects.nib')
|
||||
installTargets += env.Install('Mitsuba.app/Contents/Resources', 'tools/darwin/qt.conf')
|
||||
installTargets += env.Install('Mitsuba.app/Contents/Frameworks/BWToolkitFramework.framework/Versions/A', 'tools/darwin/BWToolkitFramework.framework/Versions/A/BWToolkitFramework')
|
||||
installTargets += env.Install('Mitsuba.app/Contents/Frameworks/BWToolkitFramework.framework', 'tools/darwin/BWToolkitFramework.framework/Versions/A/Resources')
|
||||
for file in os.listdir('tools/darwin/BWToolkitFramework.framework/Versions/A/Resources'):
|
||||
if fnmatch.fnmatch(file, '*.pdf') or fnmatch.fnmatch(file, '*.tiff') or fnmatch.fnmatch(file, '*.tif') or fnmatch.fnmatch(file, '*.png') or fnmatch.fnmatch(file, '*.rtf') or fnmatch.fnmatch(file, '*.plist'):
|
||||
installTargets += env.Install('Mitsuba.app/Contents/Frameworks/BWToolkitFramework.framework/Resources', 'tools/darwin/BWToolkitFramework.framework/Versions/A/Resources/' + file)
|
||||
|
||||
if dist:
|
||||
if sys.platform == 'win32':
|
||||
|
|
|
@ -67,8 +67,10 @@ public:
|
|||
enum EWrapType {
|
||||
/// Clamp the coordinates to [0, 1]
|
||||
EClamp = 0,
|
||||
/// Clamp the coordinates to [2n, 1-2n] (Avoids edge artifacts)
|
||||
/// Similar to EClamp, but prevents mixing at the edges
|
||||
EClampToEdge,
|
||||
/// Similar to EClamp
|
||||
EClampToBorder,
|
||||
/// Modulo 1 operation (default)
|
||||
ERepeat,
|
||||
/// Mirror the coordinates at the edges
|
||||
|
|
|
@ -25,12 +25,15 @@ public:
|
|||
void init();
|
||||
|
||||
/// Generate the shadow map for a particular VPL
|
||||
bool setVPL(const VPL &vpl);
|
||||
void setVPL(const VPL &vpl);
|
||||
|
||||
/// Prepare for rendering a material with BSDF 'bsdf' illuminated by VPL 'vpl'.
|
||||
void configure(const VPL &vpl, const BSDF *bsdf,
|
||||
const Luminaire *luminaire, const Point &camPos);
|
||||
|
||||
/// Draw the background if there is an environment luminaire
|
||||
void drawBackground(const Transform &clipToWorld, const Point &camPos);
|
||||
|
||||
/// Release bound resources
|
||||
void unbind();
|
||||
|
||||
|
@ -229,6 +232,8 @@ private:
|
|||
std::map<std::string, ProgramAndConfiguration> m_programs;
|
||||
ProgramAndConfiguration m_current;
|
||||
VPLProgramConfiguration m_targetConfig;
|
||||
ref<GPUProgram> m_backgroundProgram;
|
||||
VPLDependencyNode m_backgroundDependencies;
|
||||
};
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -81,7 +81,7 @@ MTS_NAMESPACE_BEGIN
|
|||
*/
|
||||
class MTS_EXPORT_RENDER KDTree : public Object {
|
||||
public:
|
||||
/// Construct a new, unbuilt kd-tree
|
||||
/// Construct a new kd-tree in an unbuilt state
|
||||
KDTree();
|
||||
|
||||
/// Add geometry to the kd-tree
|
||||
|
|
|
@ -172,12 +172,17 @@ public:
|
|||
|
||||
struct MTS_EXPORT_RENDER EmissionRecord {
|
||||
public:
|
||||
enum ESamplingType {
|
||||
ENormal,
|
||||
EPreview
|
||||
};
|
||||
|
||||
/// Construct a luminaire sampling record that can be used to query a luminaire
|
||||
inline EmissionRecord(const Luminaire *luminaire,
|
||||
const ShapeSamplingRecord &sRec, const Vector &d)
|
||||
: luminaire(luminaire), sRec(sRec), d(d) { }
|
||||
: luminaire(luminaire), type(ENormal), sRec(sRec), d(d) { }
|
||||
|
||||
inline EmissionRecord() : luminaire(NULL) { }
|
||||
inline EmissionRecord() : luminaire(NULL), type(ENormal) { }
|
||||
|
||||
/// Return a string representation
|
||||
std::string toString() const;
|
||||
|
@ -185,6 +190,8 @@ public:
|
|||
/// Associated luminaire
|
||||
const Luminaire *luminaire;
|
||||
|
||||
ESamplingType type;
|
||||
|
||||
/// Data record of the associated shape sample
|
||||
ShapeSamplingRecord sRec;
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@
|
|||
<xsd:element name="scale" type="scale"/>
|
||||
<xsd:element name="matrix" type="matrix"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="translate">
|
||||
<xsd:attribute name="x" type="doubleType"/>
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
* - Arbitrary polygonal meshes
|
||||
* - Lambert and Phong materials (allowed to be textured)
|
||||
* - Cameras
|
||||
* - Spot and Point lights
|
||||
* - Spot and Point and Ambient lights
|
||||
*
|
||||
* When exporting from Maya/FBX, be sure to have it convert all NURBS surfaces into
|
||||
* When exporting using Maya/FBX, be sure to have it convert all NURBS surfaces into
|
||||
* "Software Render Meshes". Triangulation is not required (the code below does this
|
||||
* automatically for arbitrary polygonal meshes). The Light and camera export options
|
||||
* should be activated, since they are off by default. While modeling the scene, it is
|
||||
|
@ -183,7 +183,7 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os,
|
|||
result->offsetToType[offset] = ENormal;
|
||||
result->typeToOffset[ENormal] = offset;
|
||||
} else if (!strcmp(inputs[i]->getSemantic(), "TEXCOORD")) {
|
||||
SAssert(accessor->getStride() == 2);
|
||||
SAssert(accessor->getStride() == 2 || accessor->getStride() == 3);
|
||||
if (result->typeToOffset[EUV] == -1) {
|
||||
result->hasUVs = true;
|
||||
result->offsetToType[offset] = EUV;
|
||||
|
@ -294,9 +294,11 @@ void writeGeometry(std::string id, int geomIndex, std::string matID, Transform t
|
|||
|
||||
os << "\t<shape id=\"" << id << "\" type=\"serialized\">" << endl;
|
||||
os << "\t\t<string name=\"filename\" value=\"" << filename.c_str() << "\"/>" << endl;
|
||||
if (!transform.isIdentity()) {
|
||||
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;
|
||||
}
|
||||
os << "\t\t<ref name=\"bsdf\" id=\"" << matID << "\"/>" << endl;
|
||||
os << "\t</shape>" << endl << endl;
|
||||
}
|
||||
|
@ -368,6 +370,46 @@ void loadGeometry(std::string nodeName, Transform transform, std::ostream &os, d
|
|||
delete data;
|
||||
++geomIndex;
|
||||
}
|
||||
|
||||
domPolylist_Array &polylistArray = mesh->getPolylist_array();
|
||||
for (size_t i=0; i<polylistArray.getCount(); ++i) {
|
||||
domPolylist *polylist = polylistArray[i];
|
||||
domInputLocalOffset_Array &inputs = polylist->getInput_array();
|
||||
VertexData *data = fetchVertexData(transform, os, vertInputs, inputs);
|
||||
domListOfUInts &vcount = polylist->getVcount()->getValue();
|
||||
domListOfUInts &indexArray = polylist->getP()->getValue();
|
||||
int posOffset = data->typeToOffset[EPosition], indexOffset = 0;
|
||||
tess_data.clear();
|
||||
tess_nSources = data->nSources;
|
||||
|
||||
for (size_t j=0; j<vcount.getCount(); ++j) {
|
||||
size_t vertexCount = vcount.get(i);
|
||||
|
||||
domUint *temp = new domUint[vertexCount * data->nSources];
|
||||
for (size_t l = 0; l<vertexCount * data->nSources; ++l)
|
||||
temp[l] = indexArray.get(indexOffset++);
|
||||
|
||||
gluTessBeginPolygon(tess, NULL);
|
||||
gluTessBeginContour(tess);
|
||||
|
||||
for (size_t k=0; k<vertexCount*data->nSources; k+=data->nSources)
|
||||
gluTessVertex(tess, &data->glPos[temp[k+posOffset]*3], (GLvoid *) (k+temp));
|
||||
|
||||
gluTessEndContour(tess);
|
||||
gluTessEndPolygon(tess);
|
||||
delete[] temp;
|
||||
}
|
||||
|
||||
if (polylist->getMaterial() == NULL)
|
||||
SLog(EError, "No material reference specified!");
|
||||
|
||||
if (matLookupTable.find(polylist->getMaterial()) == matLookupTable.end())
|
||||
SLog(EError, "Referenced material could not be found!");
|
||||
|
||||
writeGeometry(xmlName, geomIndex, matLookupTable[polylist->getMaterial()], transform, os, data);
|
||||
delete data;
|
||||
++geomIndex;
|
||||
}
|
||||
}
|
||||
|
||||
void loadMaterialParam(std::ostream &os, const std::string &name, StringMap &idToTexture,
|
||||
|
@ -511,9 +553,15 @@ void loadLight(Transform transform, std::ostream &os, domLight &light) {
|
|||
os << "\t\t</transform>" << endl;
|
||||
os << "\t</luminaire>" << endl << endl;
|
||||
}
|
||||
if (!point && !spot) {
|
||||
SLog(EWarn, "Encountered an unknown light type!");
|
||||
domLight::domTechnique_common::domAmbient *ambient = light.getTechnique_common()->getAmbient().cast();
|
||||
if (ambient) {
|
||||
domFloat3 &color = ambient->getColor()->getValue();
|
||||
os << "\t<luminaire id=\"" << light.getId() << "\" type=\"constant\">" << endl;
|
||||
os << "\t\t<rgb name=\"intensity\" value=\"" << color[0]*intensity << " " << color[1]*intensity << " " << color[2]*intensity << "\"/>" << endl;
|
||||
os << "\t</luminaire>" << endl << endl;
|
||||
}
|
||||
if (!point && !spot && !ambient)
|
||||
SLog(EWarn, "Encountered an unknown light type!");
|
||||
}
|
||||
|
||||
void loadImage(std::ostream &os, domImage &image, StringMap &idToTexture, StringMap &fileToId) {
|
||||
|
@ -667,6 +715,8 @@ void loadNode(Transform transform, std::ostream &os, domNode &node) {
|
|||
matLookupTable[instMat->getSymbol()] = material->getId();
|
||||
}
|
||||
|
||||
if (!geom)
|
||||
SLog(EError, "Could not find a referenced geometry object!");
|
||||
loadGeometry(node.getName(), transform, os, *geom, matLookupTable);
|
||||
}
|
||||
|
||||
|
@ -675,6 +725,8 @@ void loadNode(Transform transform, std::ostream &os, domNode &node) {
|
|||
for (size_t i=0; i<instanceLights.getCount(); ++i) {
|
||||
domInstance_light *inst = instanceLights[i];
|
||||
domLight *light = daeSafeCast<domLight>(inst->getUrl().getElement());
|
||||
if (!light)
|
||||
SLog(EError, "Could not find a referenced light!");
|
||||
loadLight(transform, os, *light);
|
||||
}
|
||||
|
||||
|
@ -683,6 +735,8 @@ void loadNode(Transform transform, std::ostream &os, domNode &node) {
|
|||
for (size_t i=0; i<instanceCameras.getCount(); ++i) {
|
||||
domInstance_camera *inst = instanceCameras[i];
|
||||
domCamera *camera = daeSafeCast<domCamera>(inst->getUrl().getElement());
|
||||
if (camera == NULL)
|
||||
SLog(EError, "Could not find a referenced camera!");
|
||||
loadCamera(transform, os, *camera);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,11 @@ public:
|
|||
|
||||
/// Draw the full scene using additive blending and shadow maps
|
||||
void drawShadowedScene(const Scene *scene, const VPL &vpl) {
|
||||
const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>(scene->getCamera());
|
||||
Point2 jitter(0.5f - m_random->nextFloat(), 0.5f - m_random->nextFloat());
|
||||
m_renderer->setCamera(static_cast<const ProjectiveCamera *>(scene->getCamera()), jitter);
|
||||
Transform projectionTransform = camera->getGLProjectionTransform(jitter);
|
||||
m_renderer->setCamera(projectionTransform.getMatrix(), camera->getViewTransform().getMatrix());
|
||||
Transform clipToWorld = camera->getViewTransform().inverse() * projectionTransform.inverse();
|
||||
const std::vector<TriMesh *> meshes = scene->getMeshes();
|
||||
Point camPos = scene->getCamera()->getPosition();
|
||||
|
||||
|
@ -45,6 +48,7 @@ public:
|
|||
m_shaderManager->unbind();
|
||||
}
|
||||
m_renderer->endDrawingMeshes();
|
||||
m_shaderManager->drawBackground(clipToWorld, camPos);
|
||||
}
|
||||
|
||||
void preprocess(const Scene *scene, RenderQueue *queue, const RenderJob *job,
|
||||
|
@ -130,8 +134,7 @@ public:
|
|||
m_renderer->setDepthMask(true);
|
||||
m_renderer->setDepthTest(true);
|
||||
m_renderer->setBlendMode(Renderer::EBlendNone);
|
||||
if (!m_shaderManager->setVPL(vpl))
|
||||
continue;
|
||||
m_shaderManager->setVPL(vpl);
|
||||
|
||||
m_framebuffer->activateTarget();
|
||||
m_framebuffer->clear();
|
||||
|
|
|
@ -445,6 +445,7 @@ void Bitmap::savePNG(Stream *stream) const {
|
|||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
Log(EError, "Error writing the PNG file");
|
||||
}
|
||||
|
||||
png_set_write_fn(png_ptr, stream, (png_rw_ptr) png_write_data, (png_flush_ptr) png_flush_data);
|
||||
// png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
|
||||
png_set_compression_level(png_ptr, 5);
|
||||
|
|
|
@ -238,10 +238,12 @@ std::string getFQDN() {
|
|||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
int retVal = getaddrinfo(getHostName().c_str(), NULL, &hints, &addrInfo);
|
||||
if (addrInfo == NULL || retVal != 0)
|
||||
SLog(EError, "Could not retrieve the computer's fully "
|
||||
if (addrInfo == NULL || retVal != 0) {
|
||||
SLog(EWarn, "Could not retrieve the computer's fully "
|
||||
"qualified domain name: could not resolve host address \"%s\"!",
|
||||
getHostName().c_str());
|
||||
return getHostName();
|
||||
}
|
||||
|
||||
char fqdn[NI_MAXHOST];
|
||||
retVal = getnameinfo(addrInfo->ai_addr, sizeof(struct sockaddr_in),
|
||||
|
@ -249,12 +251,13 @@ std::string getFQDN() {
|
|||
if (retVal != 0) {
|
||||
freeaddrinfo(addrInfo);
|
||||
#if defined(WIN32)
|
||||
SLog(EError, "Could not retrieve the computer's fully "
|
||||
SLog(EWarn, "Could not retrieve the computer's fully "
|
||||
"qualified domain name: error %i!", WSAGetLastError());
|
||||
#else
|
||||
SLog(EError, "Could not retrieve the computer's fully "
|
||||
SLog(EWarn, "Could not retrieve the computer's fully "
|
||||
"qualified domain name: error %i!", gai_strerror(retVal));
|
||||
#endif
|
||||
return getHostName();
|
||||
}
|
||||
|
||||
freeaddrinfo(addrInfo);
|
||||
|
|
|
@ -276,6 +276,7 @@ void GLRenderer::drawTriMesh(const TriMesh *mesh) {
|
|||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, dataType, sizeof(Vertex),
|
||||
vertices + sizeof(Float) * 6);
|
||||
|
||||
/* Pass 'dpdu' as second set of texture coordinates */
|
||||
glClientActiveTexture(GL_TEXTURE1);
|
||||
glTexCoordPointer(3, dataType, sizeof(Vertex),
|
||||
|
@ -367,14 +368,15 @@ void GLRenderer::blitTexture(const GPUTexture *tex, bool flipVertically,
|
|||
if (flipVertically)
|
||||
std::swap(upperLeft.y, lowerRight.y);
|
||||
|
||||
const Float zDepth = -1.0f; // just before the far plane
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(upperLeft.x, upperLeft.y);
|
||||
glVertex3f(upperLeft.x, upperLeft.y, zDepth);
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(lowerRight.x, upperLeft.y);
|
||||
glVertex3f(lowerRight.x, upperLeft.y, zDepth);
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(lowerRight.x, lowerRight.y);
|
||||
glVertex3f(lowerRight.x, lowerRight.y, zDepth);
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(upperLeft.x, lowerRight.y);
|
||||
glVertex3f(upperLeft.x, lowerRight.y, zDepth);
|
||||
glEnd();
|
||||
} else if (tex->getType() == GPUTexture::ETextureCubeMap) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -457,15 +459,16 @@ void GLRenderer::blitQuad(bool flipVertically) {
|
|||
glOrtho(0, scrSize.x, scrSize.y, 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
const Float zDepth = -1.0f;
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0f, flipVertically ? 1.0f : 0.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
glVertex3f(0.0f, 0.0f, zDepth);
|
||||
glTexCoord2f(1.0f, flipVertically ? 1.0f : 0.0f);
|
||||
glVertex2f(scrSize.x, 0.0f);
|
||||
glVertex3f(scrSize.x, 0.0f, zDepth);
|
||||
glTexCoord2f(1.0f, flipVertically ? 0.0f : 1.0f);
|
||||
glVertex2f(scrSize.x, scrSize.y);
|
||||
glVertex3f(scrSize.x, scrSize.y, zDepth);
|
||||
glTexCoord2f(0.0f, flipVertically ? 0.0f : 1.0f);
|
||||
glVertex2f(0.0f, scrSize.y);
|
||||
glVertex3f(0.0f, scrSize.y, zDepth);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
|
|
@ -331,6 +331,7 @@ void GLTexture::configureTexture() {
|
|||
switch (getWrapType()) {
|
||||
case EClamp: wrap = GL_CLAMP; break;
|
||||
case EClampToEdge: wrap = GL_CLAMP_TO_EDGE; break;
|
||||
case EClampToBorder: wrap = GL_CLAMP_TO_BORDER; break;
|
||||
case ERepeat: wrap = GL_REPEAT; break;
|
||||
case EMirroredRepeat: wrap = GL_MIRRORED_REPEAT_ARB; break;
|
||||
default: Log(EError, "Invalid texture wrap type specified"); return;
|
||||
|
|
|
@ -132,6 +132,7 @@ static const char *toString(GPUTexture::EWrapType wrap) {
|
|||
switch (wrap) {
|
||||
case GPUTexture::EClamp: return "clamp";
|
||||
case GPUTexture::EClampToEdge: return "clampToEdge";
|
||||
case GPUTexture::EClampToBorder: return "clampToBorder";
|
||||
case GPUTexture::ERepeat: return "repeat";
|
||||
case GPUTexture::EMirroredRepeat: return "mirroredRepeat";
|
||||
default: SLog(EError, "Invalid texture wrap type"); return NULL;
|
||||
|
|
|
@ -106,12 +106,47 @@ void VPLShaderManager::init() {
|
|||
if (shader != NULL && !shader->isComplete())
|
||||
m_renderer->unregisterShaderForResource(meshes[i]->getBSDF());
|
||||
}
|
||||
|
||||
for (size_t i=0; i<luminaires.size(); ++i)
|
||||
m_renderer->registerShaderForResource(luminaires[i]);
|
||||
|
||||
if (m_scene->hasBackgroundLuminaire() &&
|
||||
m_renderer->getShaderForResource(m_scene->getBackgroundLuminaire()) != NULL) {
|
||||
Shader *shader = m_renderer->getShaderForResource(m_scene->getBackgroundLuminaire());
|
||||
m_backgroundDependencies = VPLDependencyNode(shader);
|
||||
int id = 0;
|
||||
std::ostringstream oss;
|
||||
std::string evalName = m_backgroundDependencies.recursiveGenerateCode(oss, id);
|
||||
|
||||
m_backgroundProgram = m_renderer->createGPUProgram("Background program");
|
||||
m_backgroundProgram->setSource(GPUProgram::EVertexProgram,
|
||||
"uniform mat4 clipToWorld;\n"
|
||||
"varying vec3 d;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = ftransform();\n"
|
||||
" vec4 tmp = clipToWorld * (gl_ModelViewProjectionMatrix * gl_Vertex);\n"
|
||||
" d = tmp.xyz/tmp.w;"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
oss << "varying vec3 d;" << endl
|
||||
<< "uniform vec3 camPos;" << endl
|
||||
<< "void main() {" << endl
|
||||
<< " gl_FragColor.rgb = " << evalName << "_background(normalize(d - camPos));" << endl
|
||||
<< " gl_FragColor.a = 1.0;" << endl
|
||||
<< "}" << endl;
|
||||
|
||||
m_backgroundProgram->setSource(GPUProgram::EFragmentProgram, oss.str());
|
||||
m_backgroundProgram->init();
|
||||
|
||||
id = 0;
|
||||
m_backgroundDependencies.recursiveResolve(m_backgroundProgram, id);
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
bool VPLShaderManager::setVPL(const VPL &vpl) {
|
||||
void VPLShaderManager::setVPL(const VPL &vpl) {
|
||||
Point p = vpl.its.p + vpl.its.shFrame.n * 0.01;
|
||||
Intersection its;
|
||||
|
||||
|
@ -154,8 +189,12 @@ bool VPLShaderManager::setVPL(const VPL &vpl) {
|
|||
nearClip = std::min(nearClip, (Float) 0.001f);
|
||||
farClip = std::min(farClip * 1.5f, m_maxClipDist);
|
||||
|
||||
if (farClip < 0 || nearClip >= farClip)
|
||||
return false;
|
||||
if (farClip < 0 || nearClip >= farClip) {
|
||||
/* Unable to find any surface - just default values based on the scene size */
|
||||
nearClip = 1e-3 * m_scene->getBSphere().radius;
|
||||
farClip = 1e3 * m_scene->getBSphere().radius;
|
||||
m_minDist = 0;
|
||||
}
|
||||
|
||||
m_nearClip = nearClip;
|
||||
m_invClipRange = 1/(farClip-nearClip);
|
||||
|
@ -221,8 +260,6 @@ bool VPLShaderManager::setVPL(const VPL &vpl) {
|
|||
m_altShadowProgram->unbind();
|
||||
}
|
||||
m_shadowMap->releaseTarget();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminaire *luminaire, const Point &camPos) {
|
||||
|
@ -319,6 +356,8 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminai
|
|||
<< " vec3 wi = vec3(dot(S, nCamVec)," << endl
|
||||
<< " dot(T, nCamVec)," << endl
|
||||
<< " dot(N, nCamVec));" << endl
|
||||
<< " if (wi.z < 0)" << endl
|
||||
<< " discard;" << endl
|
||||
<< " vec3 vplWo = -vec3(dot(vplS, nLightVec)," << endl
|
||||
<< " dot(vplT, nLightVec)," << endl
|
||||
<< " dot(vplN, nLightVec));" << endl
|
||||
|
@ -331,7 +370,7 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminai
|
|||
oss << " * " << vplEvalName << "_dir(vplWo)" << endl;
|
||||
if (vpl.type == ESurfaceVPL || (vpl.type == ELuminaireVPL
|
||||
&& (vpl.luminaire->getType() & Luminaire::EOnSurface)))
|
||||
oss << " * vplPower * shadow * abs(cosTheta(wo)*cosTheta(vplWo)) / (d*d)";
|
||||
oss << " * vplPower * shadow * abs(cosTheta(wo) * cosTheta(vplWo)) / (d*d)";
|
||||
else
|
||||
oss << " * vplPower * shadow * abs(cosTheta(wo)) / (d*d)";
|
||||
if (luminaire != NULL) {
|
||||
|
@ -343,6 +382,7 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminai
|
|||
}
|
||||
oss << " gl_FragColor.a = 1.0;" << endl
|
||||
<< "}" << endl;
|
||||
|
||||
program->setSource(GPUProgram::EFragmentProgram, oss.str());
|
||||
program->init();
|
||||
|
||||
|
@ -389,6 +429,20 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminai
|
|||
m_targetConfig.bind(program, config, textureUnitOffset);
|
||||
}
|
||||
|
||||
void VPLShaderManager::drawBackground(const Transform &clipToWorld, const Point &camPos) {
|
||||
if (m_backgroundProgram == NULL)
|
||||
return;
|
||||
int textureUnitOffset = 0;
|
||||
m_backgroundProgram->bind();
|
||||
m_backgroundDependencies.recursiveBind(m_backgroundProgram,
|
||||
m_backgroundDependencies, textureUnitOffset);
|
||||
m_backgroundProgram->setParameter("clipToWorld", clipToWorld, false);
|
||||
m_backgroundProgram->setParameter("camPos", camPos, false);
|
||||
m_renderer->blitQuad(false);
|
||||
m_backgroundProgram->unbind();
|
||||
m_backgroundDependencies.recursiveUnbind();
|
||||
}
|
||||
|
||||
void VPLShaderManager::unbind() {
|
||||
if (m_current.program && m_current.program->isBound()) {
|
||||
m_targetConfig.unbind();
|
||||
|
@ -407,6 +461,11 @@ void VPLShaderManager::cleanup() {
|
|||
if (m_shadowMap)
|
||||
m_shadowMap->cleanup();
|
||||
|
||||
if (m_backgroundProgram) {
|
||||
m_backgroundProgram->cleanup();
|
||||
m_backgroundProgram = NULL;
|
||||
}
|
||||
|
||||
const std::vector<TriMesh *> meshes = m_scene->getMeshes();
|
||||
const std::vector<Luminaire *> luminaires = m_scene->getLuminaires();
|
||||
|
||||
|
|
|
@ -79,14 +79,16 @@ void ProjectiveCamera::configure() {
|
|||
/* Instantiate an EXR film by default */
|
||||
m_film = static_cast<Film*> (PluginManager::getInstance()->
|
||||
createObject(Film::m_theClass, 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("samplesPerPixel", 4);
|
||||
props.setInteger("sampleCount", 4);
|
||||
m_sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
||||
createObject(Sampler::m_theClass, props));
|
||||
m_sampler->configure();
|
||||
}
|
||||
m_aspect = (Float) m_film->getSize().x / (Float) m_film->getSize().y;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,6 @@ void KDTree::rayIntersectPacket(const Ray *rays, Intersection *its) const {
|
|||
const uint32_t shapeIndex = its4.shapeIndex.i[i];
|
||||
const uint32_t primIndex = its4.primIndex.i[i];
|
||||
const Shape *shape = m_shapes[shapeIndex];
|
||||
it.shape = shape;
|
||||
|
||||
if (EXPECT_TAKEN(primIndex != KNoTriangleFlag)) {
|
||||
const TriMesh *triMesh = static_cast<const TriMesh *>(m_shapes[shapeIndex]);
|
||||
|
@ -166,6 +165,7 @@ void KDTree::rayIntersectPacket(const Ray *rays, Intersection *its) const {
|
|||
it.geoFrame.t = cross(it.shFrame.n, it.shFrame.s);
|
||||
it.wi = it.toLocal(-rayD);
|
||||
it.hasUVPartials = false;
|
||||
it.shape = shape;
|
||||
} else {
|
||||
/* Non-triangle shape: intersect again to fill in details */
|
||||
shape->rayIntersect(rays[i], it);
|
||||
|
|
|
@ -221,8 +221,6 @@ bool KDTree::rayIntersect(const Ray &ray, Intersection &its) const {
|
|||
unsigned int shapeIndex, primIndex;
|
||||
if (rayIntersect(ray, its, mint, maxt, false, shapeIndex, primIndex)) {
|
||||
const Shape *shape = m_shapes[shapeIndex];
|
||||
its.shape = shape;
|
||||
|
||||
if (EXPECT_NOT_TAKEN(its.t < mint || its.t > maxt)) // double-check without epsilons
|
||||
return false;
|
||||
|
||||
|
@ -266,6 +264,8 @@ bool KDTree::rayIntersect(const Ray &ray, Intersection &its) const {
|
|||
its.dpdu = v0.dpdu * b.x + v1.dpdu * b.y + v2.dpdu * b.z;
|
||||
its.dpdv = v0.dpdv * b.x + v1.dpdv * b.y + v2.dpdv * b.z;
|
||||
its.geoFrame.n = faceNormal;
|
||||
its.shape = shape;
|
||||
|
||||
coordinateSystem(its.geoFrame.n, its.geoFrame.s, its.geoFrame.t);
|
||||
its.shFrame.n = normalize(v0.n * b.x + v1.n * b.y + v2.n * b.z);
|
||||
its.shFrame.s = normalize(its.dpdu - its.shFrame.n
|
||||
|
|
|
@ -89,6 +89,7 @@ void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *work
|
|||
} else {
|
||||
EmissionRecord eRec(m_vpl.luminaire,
|
||||
ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), toIts);
|
||||
eRec.type = EmissionRecord::EPreview;
|
||||
value += m_vpl.P * bsdfVal * m_vpl.luminaire->f(eRec) *
|
||||
((m_vpl.luminaire->getType() == Luminaire::EOnSurface ?
|
||||
(Float) 1 : dot(m_vpl.its.shFrame.n, toIts)) / (length*length));
|
||||
|
@ -331,6 +332,7 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe
|
|||
} else {
|
||||
EmissionRecord eRec(m_vpl.luminaire,
|
||||
ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), wi);
|
||||
eRec.type = EmissionRecord::EPreview;
|
||||
vplWeight = m_vpl.luminaire->f(eRec) * m_vpl.P;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,12 +176,33 @@ void Scene::wakeup(std::map<std::string, SerializableObject *> ¶ms) {
|
|||
}
|
||||
|
||||
void Scene::configure() {
|
||||
if (m_integrator == NULL)
|
||||
Log(EError, "No integrator has been specified!");
|
||||
if (m_camera == NULL)
|
||||
Log(EError, "No camera has been specified!");
|
||||
if (m_integrator == NULL) {
|
||||
/* Create a direct integrator by default */
|
||||
m_integrator = static_cast<Integrator *> (PluginManager::getInstance()->
|
||||
createObject(Integrator::m_theClass, Properties("direct")));
|
||||
m_integrator->configure();
|
||||
}
|
||||
if (m_camera == NULL) {
|
||||
Properties props("perspective");
|
||||
/* Create a perspective camera with 45deg. FOV, which can see the whole scene */
|
||||
AABB aabb;
|
||||
for (size_t i=0; i<m_shapes.size(); ++i)
|
||||
aabb.expandBy(m_shapes[i]->getAABB());
|
||||
Point center = aabb.getCenter();
|
||||
Vector extents = aabb.getExtents();
|
||||
Float maxExtents = std::max(extents.x, extents.y);
|
||||
Float distance = maxExtents/(2.0f * std::tan(45 * .5f * M_PI/180));
|
||||
|
||||
props.setTransform("toWorld", Transform::translate(Vector(center.x, center.y, aabb.getMinimum().x - distance)));
|
||||
props.setFloat("fov", 45.0f);
|
||||
|
||||
m_camera = static_cast<Camera *> (PluginManager::getInstance()->createObject(Camera::m_theClass, props));
|
||||
m_camera->configure();
|
||||
m_sampler = m_camera->getSamplerX();
|
||||
}
|
||||
|
||||
if (m_media.size() > 1)
|
||||
Log(EError, "Scenes are currently restricted to at most one medium.");
|
||||
Log(EError, "Scenes are currently restricted to at most one participating medium.");
|
||||
|
||||
m_integrator->configureSampler(m_sampler);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDept
|
|||
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
||||
createObject(Sampler::m_theClass, Properties("halton")));
|
||||
EmissionRecord eRec;
|
||||
eRec.type = EmissionRecord::EPreview;
|
||||
Ray ray;
|
||||
Intersection its;
|
||||
Spectrum weight, bsdfVal;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <mitsuba/render/scene.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -9,7 +10,7 @@ class ConstantLuminaire : public Luminaire {
|
|||
public:
|
||||
ConstantLuminaire(const Properties &props) : Luminaire(props) {
|
||||
m_intensity = props.getSpectrum("intensity", 1.0f);
|
||||
m_type = EDiffuseDirection | EOnSurface;
|
||||
m_type = EOnSurface;
|
||||
}
|
||||
|
||||
ConstantLuminaire(Stream *stream, InstanceManager *manager)
|
||||
|
@ -26,7 +27,7 @@ public:
|
|||
void preprocess(const Scene *scene) {
|
||||
/* Get the scene's bounding sphere and slightly enlarge it */
|
||||
m_bsphere = scene->getBSphere();
|
||||
m_bsphere.radius *= 1.01f;
|
||||
m_bsphere.radius *= 2.0f;
|
||||
m_surfaceArea = m_bsphere.radius * m_bsphere.radius * M_PI;
|
||||
}
|
||||
|
||||
|
@ -87,6 +88,7 @@ public:
|
|||
*/
|
||||
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);
|
||||
|
@ -109,15 +111,23 @@ public:
|
|||
}
|
||||
|
||||
void sampleEmissionArea(EmissionRecord &eRec, const Point2 &sample) const {
|
||||
Float radius = m_bsphere.radius;
|
||||
if (eRec.type == EmissionRecord::EPreview) {
|
||||
/* This is more suitable for VPL-based rendering */
|
||||
radius *= 10;
|
||||
}
|
||||
Vector d = squareToSphere(sample);
|
||||
eRec.sRec.p = m_bsphere.center + d * m_bsphere.radius;
|
||||
eRec.sRec.p = m_bsphere.center + d * radius;
|
||||
eRec.sRec.n = Normal(-d);
|
||||
eRec.pdfArea = 1.0f / (4 * M_PI * m_bsphere.radius * m_bsphere.radius);
|
||||
eRec.pdfArea = 1.0f / (4 * M_PI * radius * radius);
|
||||
eRec.P = m_intensity * M_PI;
|
||||
}
|
||||
|
||||
Spectrum sampleEmissionDirection(EmissionRecord &eRec, const Point2 &sample) const {
|
||||
Point p2 = m_bsphere.center + squareToSphere(sample) * m_bsphere.radius;
|
||||
Float radius = m_bsphere.radius;
|
||||
if (eRec.type == EmissionRecord::EPreview)
|
||||
radius *= 10;
|
||||
Point p2 = m_bsphere.center + squareToSphere(sample) * radius;
|
||||
eRec.d = p2 - eRec.sRec.p;
|
||||
Float length = eRec.d.length();
|
||||
|
||||
|
@ -132,6 +142,7 @@ public:
|
|||
}
|
||||
|
||||
void pdfEmission(EmissionRecord &eRec) const {
|
||||
Assert(eRec.type == EmissionRecord::ENormal);
|
||||
Float dp = dot(eRec.sRec.n, eRec.d);
|
||||
if (dp > 0)
|
||||
eRec.pdfDir = INV_PI * dp;
|
||||
|
@ -161,12 +172,54 @@ public:
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
Shader *createShader(Renderer *renderer) const;
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
Spectrum m_intensity;
|
||||
BSphere m_bsphere;
|
||||
};
|
||||
|
||||
// ================ Hardware shader implementation ================
|
||||
|
||||
class ConstantLuminaireShader : public Shader {
|
||||
public:
|
||||
ConstantLuminaireShader(Renderer *renderer, const Spectrum &intensity)
|
||||
: Shader(renderer, ELuminaireShader), m_emittance(intensity * M_PI) {
|
||||
}
|
||||
|
||||
void resolve(const GPUProgram *program, const std::string &evalName, std::vector<int> ¶meterIDs) const {
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_emittance", false));
|
||||
}
|
||||
|
||||
void generateCode(std::ostringstream &oss, const std::string &evalName,
|
||||
const std::vector<std::string> &depNames) const {
|
||||
oss << "uniform vec3 " << evalName << "_emittance;" << endl
|
||||
<< endl
|
||||
<< "vec3 " << evalName << "_dir(vec3 wo) {" << endl
|
||||
<< " return vec3(0.31831);" << endl
|
||||
<< "}" << endl
|
||||
<< endl
|
||||
<< "vec3 " << evalName << "_background(vec3 wo) {" << endl
|
||||
<< " return " << evalName << "_emittance * 0.31831;" << endl
|
||||
<< "}" << endl;
|
||||
}
|
||||
|
||||
void bind(GPUProgram *program, const std::vector<int> ¶meterIDs,
|
||||
int &textureUnitOffset) const {
|
||||
program->setParameter(parameterIDs[0], m_emittance);
|
||||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
Spectrum m_emittance;
|
||||
};
|
||||
|
||||
Shader *ConstantLuminaire::createShader(Renderer *renderer) const {
|
||||
return new ConstantLuminaireShader(renderer, m_intensity);
|
||||
}
|
||||
|
||||
MTS_IMPLEMENT_CLASS_S(ConstantLuminaire, false, Luminaire)
|
||||
MTS_IMPLEMENT_CLASS(ConstantLuminaireShader, false, Shader)
|
||||
MTS_EXPORT_PLUGIN(ConstantLuminaire, "Constant background luminaire");
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include <mitsuba/render/mipmap.h>
|
||||
#include <mitsuba/core/mstream.h>
|
||||
#include <mitsuba/core/sched.h>
|
||||
#include <mitsuba/hw/gputexture.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -161,6 +163,7 @@ public:
|
|||
*/
|
||||
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);
|
||||
|
@ -183,15 +186,29 @@ public:
|
|||
}
|
||||
|
||||
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.P = 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 * 10;
|
||||
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.P = Le(d) * M_PI;
|
||||
}
|
||||
}
|
||||
|
||||
Spectrum sampleEmissionDirection(EmissionRecord &eRec, const Point2 &sample) const {
|
||||
Point p2 = m_bsphere.center + squareToSphere(sample) * m_bsphere.radius;
|
||||
Float radius = m_bsphere.radius;
|
||||
if (eRec.type == EmissionRecord::EPreview)
|
||||
radius *= 10;
|
||||
Point p2 = m_bsphere.center + squareToSphere(sample) * radius;
|
||||
eRec.d = p2 - eRec.sRec.p;
|
||||
Float length = eRec.d.length();
|
||||
|
||||
|
@ -202,10 +219,14 @@ public:
|
|||
|
||||
eRec.d /= length;
|
||||
eRec.pdfDir = INV_PI * dot(eRec.sRec.n, eRec.d);
|
||||
return Le(-eRec.d) * INV_PI; /// XXX perhaps make this normalized?
|
||||
if (eRec.type == EmissionRecord::ENormal)
|
||||
return Le(-eRec.d) * INV_PI;
|
||||
else
|
||||
return Spectrum(INV_PI);
|
||||
}
|
||||
|
||||
void pdfEmission(EmissionRecord &eRec) const {
|
||||
Assert(eRec.type == EmissionRecord::ENormal);
|
||||
Float dp = dot(eRec.sRec.n, eRec.d);
|
||||
if (dp > 0)
|
||||
eRec.pdfDir = INV_PI * dp;
|
||||
|
@ -215,10 +236,14 @@ public:
|
|||
}
|
||||
|
||||
Spectrum f(const EmissionRecord &eRec) const {
|
||||
if (eRec.type == EmissionRecord::ENormal)
|
||||
return Le(-eRec.d) * INV_PI;
|
||||
else
|
||||
return Spectrum(INV_PI);
|
||||
}
|
||||
|
||||
Spectrum fArea(const EmissionRecord &eRec) const {
|
||||
Assert(eRec.type == EmissionRecord::ENormal);
|
||||
return M_PI;
|
||||
}
|
||||
|
||||
|
@ -237,6 +262,8 @@ public:
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
Shader *createShader(Renderer *renderer) const;
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
Spectrum m_average;
|
||||
|
@ -247,6 +274,80 @@ private:
|
|||
ref<MemoryStream> m_stream;
|
||||
};
|
||||
|
||||
// ================ Hardware shader implementation ================
|
||||
|
||||
class EnvMapLuminaireShader : public Shader {
|
||||
public:
|
||||
EnvMapLuminaireShader(Renderer *renderer, const std::string &filename, ref<Bitmap> bitmap,
|
||||
Float intensityScale, const Transform &worldToLuminaire) : Shader(renderer, ELuminaireShader) {
|
||||
m_gpuTexture = renderer->createGPUTexture(filename, bitmap);
|
||||
m_gpuTexture->setWrapType(GPUTexture::ERepeat);
|
||||
m_gpuTexture->setMaxAnisotropy(8);
|
||||
m_gpuTexture->init();
|
||||
/* Release the memory on the host side */
|
||||
m_gpuTexture->setBitmap(0, NULL);
|
||||
m_intensityScale = intensityScale;
|
||||
m_worldToLuminaire = worldToLuminaire;
|
||||
}
|
||||
|
||||
void cleanup(Renderer *renderer) {
|
||||
m_gpuTexture->cleanup();
|
||||
}
|
||||
|
||||
void resolve(const GPUProgram *program, const std::string &evalName, std::vector<int> ¶meterIDs) const {
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_texture", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_intensityScale", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_worldToLuminaire", false));
|
||||
}
|
||||
|
||||
void generateCode(std::ostringstream &oss, const std::string &evalName,
|
||||
const std::vector<std::string> &depNames) const {
|
||||
oss << "uniform sampler2D " << evalName << "_texture;" << endl
|
||||
<< "uniform float " << evalName << "_intensityScale;" << endl
|
||||
<< "uniform mat4 " << evalName << "_worldToLuminaire;" << endl
|
||||
<< endl
|
||||
<< "vec3 " << evalName << "_dir(vec3 wo) {" << endl
|
||||
<< " return vec3(0.318309);" << endl
|
||||
<< "}" << endl
|
||||
<< endl
|
||||
<< "vec3 " << evalName << "_background(vec3 wo) {" << 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 v = acos(max(-1.0, min(1.0, d.y))) * 0.318309;" << endl
|
||||
// The following is not very elegant, but necessary to trick GLSL
|
||||
// into doing correct texture filtering across the u=0 to u=1 seam.
|
||||
<< " if (u < 0.1)" << endl
|
||||
<< " return texture2D(" << evalName << "_texture, vec2(u+1.0, v)).rgb * " << evalName << "_intensityScale;" << endl
|
||||
<< " else"
|
||||
<< " return texture2D(" << evalName << "_texture, vec2(u, v)).rgb * " << evalName << "_intensityScale;" << endl
|
||||
<< "}" << endl;
|
||||
}
|
||||
|
||||
void bind(GPUProgram *program, const std::vector<int> ¶meterIDs,
|
||||
int &textureUnitOffset) const {
|
||||
m_gpuTexture->bind(textureUnitOffset++);
|
||||
program->setParameter(parameterIDs[0], m_gpuTexture.get());
|
||||
program->setParameter(parameterIDs[1], m_intensityScale);
|
||||
program->setParameter(parameterIDs[2], m_worldToLuminaire);
|
||||
}
|
||||
|
||||
void unbind() const {
|
||||
m_gpuTexture->unbind();
|
||||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
ref<GPUTexture> m_gpuTexture;
|
||||
Float m_intensityScale;
|
||||
Transform m_worldToLuminaire;
|
||||
};
|
||||
|
||||
Shader *EnvMapLuminaire::createShader(Renderer *renderer) const {
|
||||
return new EnvMapLuminaireShader(renderer, m_filename, m_mipmap->getBitmap(),
|
||||
m_intensityScale, m_worldToLuminaire);
|
||||
}
|
||||
|
||||
MTS_IMPLEMENT_CLASS_S(EnvMapLuminaire, false, Luminaire)
|
||||
MTS_IMPLEMENT_CLASS(EnvMapLuminaireShader, false, Shader)
|
||||
MTS_EXPORT_PLUGIN(EnvMapLuminaire, "Environment map luminaire");
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -120,10 +120,7 @@ public:
|
|||
|
||||
void generateCode(std::ostringstream &oss, const std::string &evalName,
|
||||
const std::vector<std::string> &depNames) const {
|
||||
oss << "vec3 " << evalName << "_area(vec2 uv) {" << endl
|
||||
<< " return vec3(0.0); /* Won't ever be used */ " << endl
|
||||
<< "}" << endl << endl
|
||||
<< "vec3 " << evalName << "_dir(vec3 wo) {" << endl
|
||||
oss << "vec3 " << evalName << "_dir(vec3 wo) {" << endl
|
||||
<< " return vec3(0.079577);" << endl
|
||||
<< "}" << endl;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <mitsuba/render/scene.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -27,6 +28,7 @@ public:
|
|||
m_texture = new ConstantTexture(
|
||||
props.getSpectrum("texture", Spectrum(1.0f)));
|
||||
m_uvFactor = std::tan(m_beamWidth/2);
|
||||
m_invTransitionWidth = 1.0 / (m_cutoffAngle - m_beamWidth);
|
||||
}
|
||||
|
||||
SpotLuminaire(Stream *stream, InstanceManager *manager)
|
||||
|
@ -39,6 +41,7 @@ public:
|
|||
m_cosCutoffAngle = std::cos(m_cutoffAngle);
|
||||
m_position = m_luminaireToWorld(Point(0, 0, 0));
|
||||
m_uvFactor = std::tan(m_beamWidth/2);
|
||||
m_invTransitionWidth = 1.0 / (m_cutoffAngle - m_beamWidth);
|
||||
}
|
||||
|
||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||
|
@ -66,6 +69,9 @@ public:
|
|||
Vector localDir = m_worldToLuminaire(d);
|
||||
const Float cosTheta = localDir.z;
|
||||
|
||||
if (cosTheta < m_cosCutoffAngle)
|
||||
return Spectrum(0.0f);
|
||||
|
||||
if (m_texture->getClass() != ConstantTexture::m_theClass) {
|
||||
Intersection its;
|
||||
its.hasUVPartials = false;
|
||||
|
@ -74,17 +80,12 @@ public:
|
|||
result *= m_texture->getValue(its);
|
||||
}
|
||||
|
||||
if (cosTheta < m_cosCutoffAngle)
|
||||
return Spectrum(0.0f);
|
||||
if (cosTheta > m_cosBeamWidth)
|
||||
return result;
|
||||
return result * ((m_cutoffAngle - std::acos(cosTheta))
|
||||
/ (m_cutoffAngle - m_beamWidth));
|
||||
return result * ((m_cutoffAngle - std::acos(cosTheta)) * m_invTransitionWidth);
|
||||
}
|
||||
|
||||
Spectrum Le(const LuminaireSamplingRecord &lRec) const {
|
||||
if (lRec.sRec.p == m_position)
|
||||
return m_intensity * falloffCurve(lRec.d);
|
||||
return Spectrum(0.0f);
|
||||
}
|
||||
|
||||
|
@ -171,15 +172,100 @@ public:
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
Shader *createShader(Renderer *renderer) const;
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
Spectrum m_intensity;
|
||||
ref<Texture> m_texture;
|
||||
Float m_beamWidth, m_cutoffAngle, m_uvFactor;
|
||||
Float m_cosBeamWidth, m_cosCutoffAngle;
|
||||
Float m_cosBeamWidth, m_cosCutoffAngle, m_invTransitionWidth;
|
||||
Point m_position;
|
||||
};
|
||||
|
||||
// ================ Hardware shader implementation ================
|
||||
|
||||
class SpotLuminaireShader : public Shader {
|
||||
public:
|
||||
SpotLuminaireShader(Renderer *renderer, Transform worldToLuminaire,
|
||||
Float invTransitionWidth, Float cutoffAngle, Float cosCutoffAngle,
|
||||
Float cosBeamWidth, Float uvFactor, const Texture *texture)
|
||||
: Shader(renderer, ELuminaireShader), m_worldToLuminaire(worldToLuminaire),
|
||||
m_invTransitionWidth(invTransitionWidth), m_cutoffAngle(cutoffAngle),
|
||||
m_cosCutoffAngle(cosCutoffAngle), m_cosBeamWidth(cosBeamWidth),
|
||||
m_uvFactor(uvFactor), m_texture(texture) {
|
||||
m_textureShader = renderer->registerShaderForResource(m_texture.get());
|
||||
}
|
||||
|
||||
bool isComplete() const {
|
||||
return m_textureShader.get() != NULL;
|
||||
}
|
||||
|
||||
void cleanup(Renderer *renderer) {
|
||||
renderer->unregisterShaderForResource(m_texture.get());
|
||||
}
|
||||
|
||||
void putDependencies(std::vector<Shader *> &deps) {
|
||||
deps.push_back(m_textureShader.get());
|
||||
}
|
||||
|
||||
void generateCode(std::ostringstream &oss, const std::string &evalName,
|
||||
const std::vector<std::string> &depNames) const {
|
||||
oss << "uniform float " << evalName << "_invTransitionWidth;" << endl
|
||||
<< "uniform float " << evalName << "_cutoffAngle;" << endl
|
||||
<< "uniform float " << evalName << "_cosCutoffAngle;" << endl
|
||||
<< "uniform float " << evalName << "_cosBeamWidth;" << endl
|
||||
<< "uniform float " << evalName << "_uvFactor;" << endl
|
||||
<< "uniform mat4 " << evalName << "_worldToLuminaire;" << endl
|
||||
<< "vec3 " << evalName << "_dir(vec3 wo) {" << endl
|
||||
<< " vec3 localDir = (" << evalName << "_worldToLuminaire * vec4(wo, 0)).xyz;" << endl
|
||||
<< " float cosTheta = localDir.z;" << endl
|
||||
<< " if (cosTheta < " << evalName << "_cosCutoffAngle)" << endl
|
||||
<< " return vec3(0.0);" << endl
|
||||
<< " vec2 uv = 0.5 + (localDir.xy / localDir.z * " << evalName << "_uvFactor);" << endl
|
||||
<< " vec3 color = " << depNames[0] << "(uv);" << endl
|
||||
<< " if (cosTheta > " << evalName << "_cosBeamWidth)" << endl
|
||||
<< " return color;" << endl
|
||||
<< " return color * ((" << evalName << "_cutoffAngle - acos(cosTheta))" << endl
|
||||
<< " * " << evalName << "_invTransitionWidth);" << endl
|
||||
<< "}" << endl;
|
||||
}
|
||||
|
||||
void resolve(const GPUProgram *program, const std::string &evalName, std::vector<int> ¶meterIDs) const {
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_worldToLuminaire", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_invTransitionWidth", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_cutoffAngle", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_cosCutoffAngle", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_cosBeamWidth", false));
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_uvFactor", false));
|
||||
}
|
||||
|
||||
void bind(GPUProgram *program, const std::vector<int> ¶meterIDs, int &textureUnitOffset) const {
|
||||
program->setParameter(parameterIDs[0], m_worldToLuminaire);
|
||||
program->setParameter(parameterIDs[1], m_invTransitionWidth);
|
||||
program->setParameter(parameterIDs[2], m_cutoffAngle);
|
||||
program->setParameter(parameterIDs[3], m_cosCutoffAngle);
|
||||
program->setParameter(parameterIDs[4], m_cosBeamWidth);
|
||||
program->setParameter(parameterIDs[5], m_uvFactor);
|
||||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
Transform m_worldToLuminaire;
|
||||
Float m_invTransitionWidth;
|
||||
Float m_cutoffAngle, m_cosCutoffAngle;
|
||||
Float m_cosBeamWidth, m_uvFactor;
|
||||
ref<const Texture> m_texture;
|
||||
ref<Shader> m_textureShader;
|
||||
};
|
||||
|
||||
Shader *SpotLuminaire::createShader(Renderer *renderer) const {
|
||||
return new SpotLuminaireShader(renderer, m_worldToLuminaire,
|
||||
m_invTransitionWidth, m_cutoffAngle, m_cosCutoffAngle,
|
||||
m_cosBeamWidth, m_uvFactor, m_texture.get());
|
||||
}
|
||||
|
||||
MTS_IMPLEMENT_CLASS(SpotLuminaireShader, false, Shader)
|
||||
MTS_IMPLEMENT_CLASS_S(SpotLuminaire, false, Luminaire)
|
||||
MTS_EXPORT_PLUGIN(SpotLuminaire, "Spot light");
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -358,6 +358,13 @@ int main(int argc, char **argv) {
|
|||
resolver->addPath("/usr/share/mitsuba");
|
||||
#endif
|
||||
|
||||
#if defined(__OSX__)
|
||||
MTS_AUTORELEASE_BEGIN()
|
||||
FileResolver *resolver = FileResolver::getInstance();
|
||||
resolver->addPath(__ubi_bundlepath());
|
||||
MTS_AUTORELEASE_END()
|
||||
#endif
|
||||
|
||||
/* Initialize Xerces-C */
|
||||
try {
|
||||
XMLPlatformUtils::Initialize();
|
||||
|
|
|
@ -33,6 +33,7 @@ GLWidget::GLWidget(QWidget *parent) :
|
|||
m_didSetCursor = false;
|
||||
m_ignoreResizeEvents = false;
|
||||
m_ignoreScrollEvents = false;
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
GLWidget::~GLWidget() {
|
||||
|
@ -243,17 +244,16 @@ void GLWidget::initializeGL() {
|
|||
void GLWidget::setScene(SceneContext *context) {
|
||||
if (m_movementTimer->isActive())
|
||||
m_movementTimer->stop();
|
||||
|
||||
bool contextSwitch = m_context != NULL && context != NULL;
|
||||
m_preview->setSceneContext(context, contextSwitch, false);
|
||||
m_context = context;
|
||||
|
||||
if (context && context->scene == NULL)
|
||||
context = NULL;
|
||||
m_preview->setSceneContext(context, true, false);
|
||||
m_framebufferChanged = true;
|
||||
m_mouseButtonDown = false;
|
||||
m_leftKeyDown = m_rightKeyDown = m_upKeyDown = m_downKeyDown = false;
|
||||
updateGeometry();
|
||||
updateScrollBars();
|
||||
if (!contextSwitch)
|
||||
resetPreview();
|
||||
}
|
||||
|
||||
void GLWidget::refreshScene() {
|
||||
|
@ -280,7 +280,7 @@ void GLWidget::setShadowMapResolution(int res) {
|
|||
}
|
||||
|
||||
void GLWidget::setPreviewMethod(EPreviewMethod method) {
|
||||
if (method != m_context->clamping) {
|
||||
if (method != m_context->previewMethod) {
|
||||
m_context->previewMethod = method;
|
||||
resetPreview();
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ void GLWidget::downloadFramebuffer() {
|
|||
bool createdFramebuffer = false;
|
||||
|
||||
makeCurrent();
|
||||
if (m_framebuffer == NULL || true ||
|
||||
if (m_framebuffer == NULL ||
|
||||
m_framebuffer->getBitmap() != m_context->framebuffer) {
|
||||
if (m_framebuffer)
|
||||
m_framebuffer->cleanup();
|
||||
|
@ -376,9 +376,8 @@ void GLWidget::downloadFramebuffer() {
|
|||
QSize GLWidget::sizeHint() const {
|
||||
QSize minimumSize(440, 170);
|
||||
if (m_context) {
|
||||
Vector2i size = m_context->scene->getCamera()->getFilm()->getSize();
|
||||
return QSize(std::max(minimumSize.width(), size.x),
|
||||
std::max(minimumSize.height(), size.y));
|
||||
return QSize(std::max(minimumSize.width(), m_context->framebuffer->getWidth()),
|
||||
std::max(minimumSize.height(), m_context->framebuffer->getHeight()));
|
||||
} else {
|
||||
return minimumSize;
|
||||
}
|
||||
|
@ -391,7 +390,7 @@ void GLWidget::focusOutEvent(QFocusEvent *event) {
|
|||
}
|
||||
|
||||
void GLWidget::timerImpulse() {
|
||||
if (!m_context) {
|
||||
if (!m_context || !m_context->scene) {
|
||||
m_movementTimer->stop();
|
||||
return;
|
||||
}
|
||||
|
@ -429,6 +428,8 @@ void GLWidget::timerImpulse() {
|
|||
}
|
||||
|
||||
void GLWidget::resetPreview() {
|
||||
if (!m_context || !m_context->scene)
|
||||
return;
|
||||
bool motion = m_leftKeyDown || m_rightKeyDown ||
|
||||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown;
|
||||
m_preview->setSceneContext(m_context, false, motion);
|
||||
|
@ -497,7 +498,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
rel = event->pos() - m_mousePos;
|
||||
m_mousePos = event->pos();
|
||||
|
||||
if (!m_context || !m_mouseButtonDown || rel == QPoint(0,0))
|
||||
if (!m_context || !m_context->scene || !m_mouseButtonDown || rel == QPoint(0,0))
|
||||
return;
|
||||
|
||||
// if (m_ignoreMouseEvent == rel) {
|
||||
|
@ -526,15 +527,14 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
Transform trafo = Transform::rotate(Vector(0,1,0), yaw)
|
||||
* Transform::rotate(Vector(1,0,0), pitch)
|
||||
* camera->getViewTransform();
|
||||
direction = trafo.inverse()(Vector(0,0,1));
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0) {
|
||||
direction = trafo.inverse()(Vector(0,0,1));
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, m_context->up));
|
||||
} else {
|
||||
direction = trafo.inverse()(Vector(0,0,1));
|
||||
p.z = -p.z; direction.z = -direction.z;
|
||||
camera->setInverseViewTransform(Transform::scale(Vector(1,1,-1)) *
|
||||
Transform::lookAt(p, p+direction, -m_context->up));
|
||||
Transform::lookAt(p, p+direction, m_context->up));
|
||||
}
|
||||
didMove = true;
|
||||
}
|
||||
|
@ -549,10 +549,10 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
} else {
|
||||
p.z = -p.z; direction.z = -direction.z;
|
||||
camera->setInverseViewTransform(Transform::scale(Vector(1,1,-1)) *
|
||||
Transform::lookAt(p, p+direction, -m_context->up));
|
||||
Transform::lookAt(p, p+direction, m_context->up));
|
||||
}
|
||||
|
||||
camera->setFov(std::min(std::max(1.0f, camera->getFov() + fovChange), 100.0f));
|
||||
camera->setFov(std::min(std::max((Float) 1.0f, camera->getFov() + fovChange), (Float) 100.0f));
|
||||
camera->configure();
|
||||
|
||||
didMove = true;
|
||||
|
@ -638,7 +638,7 @@ void exportPNG(const char *name, GPUTexture *buffer, bool downsample) {
|
|||
if (ch == 3)
|
||||
value = 1;
|
||||
else
|
||||
value = std::pow(value, 1/2.2f);
|
||||
value = std::pow(value, (Float) (1/2.2f));
|
||||
target[(x + y*size.x)*4 + ch] = (uint8_t) std::min(std::max((int) (value* 255), 0), 255);
|
||||
}
|
||||
}
|
||||
|
@ -761,6 +761,10 @@ void GLWidget::paintGL() {
|
|||
Float logLuminance, maxLuminance, unused;
|
||||
m_luminanceBuffer[target]->getPixel(0, 0).toLinearRGB(logLuminance, maxLuminance, unused);
|
||||
logLuminance = std::exp(logLuminance / (size.x*size.y));
|
||||
if (std::isnan(logLuminance) || std::isinf(logLuminance)) {
|
||||
SLog(EWarn, "Could not determine the average log-luminance, since the image contains NaNs/infs/negative values");
|
||||
logLuminance = 1;
|
||||
}
|
||||
|
||||
buffer->bind();
|
||||
m_reinhardTonemap->bind();
|
||||
|
@ -898,6 +902,20 @@ void GLWidget::onScroll() {
|
|||
updateGL();
|
||||
}
|
||||
|
||||
void GLWidget::dragEnterEvent(QDragEnterEvent *event) {
|
||||
if (event->mimeData()->hasFormat("text/uri-list")) {
|
||||
event->setDropAction(Qt::CopyAction);
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
|
||||
void GLWidget::dropEvent(QDropEvent *event) {
|
||||
QList<QUrl> urls = event->mimeData()->urls();
|
||||
for (int i=0; i<urls.size(); ++i)
|
||||
emit loadFileRequest(urls[i].toLocalFile());
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void GLWidget::resumePreview() {
|
||||
m_preview->resume();
|
||||
}
|
||||
|
|
|
@ -37,11 +37,13 @@ public:
|
|||
void setScrollBars(QScrollBar *hScroll, QScrollBar *vScroll);
|
||||
inline void ignoreResizeEvents(bool value) { m_ignoreResizeEvents = value; }
|
||||
void updateScrollBars();
|
||||
|
||||
signals:
|
||||
void beginRendering();
|
||||
void stopRendering();
|
||||
void quit();
|
||||
void statusMessage(const QString &status);
|
||||
void loadFileRequest(const QString &fileName);
|
||||
|
||||
public slots:
|
||||
void timerImpulse();
|
||||
|
@ -71,6 +73,8 @@ protected:
|
|||
void resetPreview();
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
|
||||
/* Masquerade QGLWidget as a GL device for libhw */
|
||||
#if defined(WIN32)
|
||||
|
|
|
@ -488,14 +488,14 @@ void MainWindow::onProgressMessage(const RenderJob *job, const QString &name,
|
|||
}
|
||||
void MainWindow::on_actionOpen_triggered() {
|
||||
QFileDialog *dialog = new QFileDialog(this, Qt::Sheet);
|
||||
dialog->setNameFilter(tr("Mitsuba scenes (*.xml)"));
|
||||
dialog->setNameFilter(tr("Mitsuba scenes (*.xml);;EXR images (*.exr)"));
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->setAcceptMode(QFileDialog::AcceptOpen);
|
||||
dialog->setViewMode(QFileDialog::Detail);
|
||||
dialog->setWindowModality(Qt::WindowModal);
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
dialog->restoreState(settings.value("fileDialogState").toByteArray());
|
||||
connect(dialog, SIGNAL(finished(int)), this, SLOT(onFileDialogClose(int)));
|
||||
connect(dialog, SIGNAL(finished(int)), this, SLOT(onOpenDialogClose(int)));
|
||||
m_currentChild = dialog;
|
||||
// prevent a tab drawing artifact on Qt/OSX
|
||||
m_activeWindowHack = true;
|
||||
|
@ -504,7 +504,7 @@ void MainWindow::on_actionOpen_triggered() {
|
|||
m_activeWindowHack = false;
|
||||
}
|
||||
|
||||
void MainWindow::onFileDialogClose(int reason) {
|
||||
void MainWindow::onOpenDialogClose(int reason) {
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
QFileDialog *dialog = static_cast<QFileDialog *>(sender());
|
||||
m_currentChild = NULL;
|
||||
|
@ -534,7 +534,6 @@ void MainWindow::onClearRecent() {
|
|||
}
|
||||
|
||||
SceneContext *MainWindow::loadScene(const QString &qFileName) {
|
||||
/* Prepare for parsing scene descriptions */
|
||||
ref<FileResolver> resolver = FileResolver::getInstance();
|
||||
std::string filename = resolver->resolveAbsolute(qFileName.toStdString());
|
||||
std::string filePath = resolver->pathFromFile(filename);
|
||||
|
@ -644,14 +643,15 @@ void MainWindow::updateUI() {
|
|||
|
||||
SceneContext *context = hasTab ? m_context[index] : NULL;
|
||||
bool isRendering = hasTab ? context->renderJob != NULL : false;
|
||||
bool isInactiveScene = hasTab ? context->renderJob == NULL : false;
|
||||
bool hasScene = hasTab && context->scene != NULL;
|
||||
bool isInactiveScene = (hasTab && hasScene) ? context->renderJob == NULL : false;
|
||||
|
||||
ui->actionStop->setEnabled(isRendering);
|
||||
ui->actionRender->setEnabled(isInactiveScene);
|
||||
ui->actionRefresh->setEnabled(isInactiveScene);
|
||||
ui->actionRenderSettings->setEnabled(isInactiveScene);
|
||||
ui->actionSave->setEnabled(hasTab);
|
||||
ui->actionSaveAs->setEnabled(hasTab);
|
||||
ui->actionSave->setEnabled(hasScene);
|
||||
ui->actionSaveAs->setEnabled(hasScene);
|
||||
ui->actionExportImage->setEnabled(hasTab);
|
||||
ui->actionClose->setEnabled(hasTab);
|
||||
ui->actionDuplicateTab->setEnabled(hasTab);
|
||||
|
@ -910,7 +910,6 @@ void MainWindow::on_actionPreviewSettings_triggered() {
|
|||
connect(&d, SIGNAL(reinhardBurnChanged(Float)), ui->glView, SLOT(setReinhardBurn(Float)));
|
||||
connect(&d, SIGNAL(previewMethodChanged(EPreviewMethod)), ui->glView, SLOT(setPreviewMethod(EPreviewMethod)));
|
||||
connect(&d, SIGNAL(toneMappingMethodChanged(EToneMappingMethod)), ui->glView, SLOT(setToneMappingMethod(EToneMappingMethod)));
|
||||
d.setWindowModality(Qt::NonModal);
|
||||
d.setMaximumSize(d.minimumSize());
|
||||
d.exec();
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
|
@ -1241,6 +1240,7 @@ void MainWindow::on_actionExportImage_triggered() {
|
|||
source += 4;
|
||||
}
|
||||
}
|
||||
temp->setGamma(ctx->srgb ? -1 : ctx->gamma);
|
||||
temp->save(format, fs);
|
||||
}
|
||||
}
|
||||
|
@ -1252,29 +1252,42 @@ void MainWindow::on_actionSave_triggered() {
|
|||
}
|
||||
|
||||
void MainWindow::on_actionSaveAs_triggered() {
|
||||
QFileDialog *dialog = new QFileDialog(this, tr("Save as .."),
|
||||
"", tr("Mitsuba scenes (*.xml)"));
|
||||
|
||||
m_currentChild = dialog;
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->setViewMode(QFileDialog::Detail);
|
||||
dialog->setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog->restoreState(settings.value("fileDialogState").toByteArray());
|
||||
dialog->setWindowModality(Qt::WindowModal);
|
||||
connect(dialog, SIGNAL(finished(int)), this, SLOT(onSaveAsDialogClose(int)));
|
||||
m_currentChild = dialog;
|
||||
// prevent a tab drawing artifact on Qt/OSX
|
||||
m_activeWindowHack = true;
|
||||
dialog->show();
|
||||
qApp->processEvents();
|
||||
m_activeWindowHack = false;
|
||||
}
|
||||
|
||||
void MainWindow::onSaveAsDialogClose(int reason) {
|
||||
int currentIndex = ui->tabBar->currentIndex();
|
||||
SceneContext *context = m_context[currentIndex];
|
||||
|
||||
QFileDialog dialog(this, tr("Save as .."),
|
||||
"", tr("Mitsuba scenes (*.xml)"));
|
||||
|
||||
m_currentChild = &dialog;
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.restoreState(settings.value("fileDialogState").toByteArray());
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
QFileDialog *dialog = static_cast<QFileDialog *>(sender());
|
||||
m_currentChild = NULL;
|
||||
QString fileName = dialog.selectedFiles().value(0);
|
||||
settings.setValue("fileDialogState", dialog.saveState());
|
||||
if (reason == QDialog::Accepted) {
|
||||
m_currentChild = NULL;
|
||||
QString fileName = dialog->selectedFiles().value(0);
|
||||
settings.setValue("fileDialogState", dialog->saveState());
|
||||
saveScene(this, context, fileName);
|
||||
context->fileName = fileName;
|
||||
context->shortName = QFileInfo(fileName).fileName();
|
||||
ui->tabBar->setTabText(currentIndex, context->shortName);
|
||||
addRecentFile(fileName);
|
||||
}
|
||||
m_currentChild = NULL;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionNavigationControls_triggered() {
|
||||
|
@ -1398,6 +1411,9 @@ void MainWindow::onWorkBegin(const RenderJob *job, const RectangularWorkUnit *wu
|
|||
emit updateView();
|
||||
}
|
||||
|
||||
void MainWindow::on_glView_loadFileRequest(const QString &string) {
|
||||
loadFile(string);
|
||||
}
|
||||
|
||||
void MainWindow::onWorkEnd(const RenderJob *job, const ImageBlock *block) {
|
||||
int ox = block->getOffset().x, oy = block->getOffset().y,
|
||||
|
@ -1501,6 +1517,7 @@ QString ServerConnection::toString() const {
|
|||
}
|
||||
|
||||
SceneContext::SceneContext(SceneContext *ctx) {
|
||||
if (ctx->scene) {
|
||||
scene = new Scene(ctx->scene);
|
||||
ref<PluginManager> pluginMgr = PluginManager::getInstance();
|
||||
ref<PinholeCamera> oldCamera = static_cast<PinholeCamera *>(ctx->scene->getCamera());
|
||||
|
@ -1547,6 +1564,11 @@ SceneContext::SceneContext(SceneContext *ctx) {
|
|||
scene->setSampler(sampler);
|
||||
scene->configure();
|
||||
sceneResID = ctx->sceneResID;
|
||||
Scheduler::getInstance()->retainResource(sceneResID);
|
||||
} else {
|
||||
sceneResID = -1;
|
||||
renderJob = NULL;
|
||||
}
|
||||
fileName = ctx->fileName;
|
||||
shortName = ctx->shortName;
|
||||
movementScale = ctx->movementScale;
|
||||
|
@ -1554,10 +1576,8 @@ SceneContext::SceneContext(SceneContext *ctx) {
|
|||
renderJob = NULL;
|
||||
cancelled = false;
|
||||
progress = 0.0f;
|
||||
framebuffer = new Bitmap(ctx->framebuffer->getWidth(),
|
||||
ctx->framebuffer->getHeight(), 128);
|
||||
framebuffer->clear();
|
||||
mode = EPreview;
|
||||
framebuffer = ctx->framebuffer->clone();
|
||||
mode = ctx->renderJob ? EPreview : ctx->mode;
|
||||
gamma = ctx->gamma;
|
||||
exposure = ctx->exposure;
|
||||
clamping = ctx->clamping;
|
||||
|
@ -1571,11 +1591,10 @@ SceneContext::SceneContext(SceneContext *ctx) {
|
|||
scrollOffset = ctx->scrollOffset;
|
||||
reinhardKey = ctx->reinhardKey;
|
||||
reinhardBurn = ctx->reinhardBurn;
|
||||
Scheduler::getInstance()->retainResource(sceneResID);
|
||||
}
|
||||
|
||||
SceneContext::~SceneContext() {
|
||||
if (sceneResID != -1)
|
||||
if (scene && sceneResID != -1)
|
||||
Scheduler::getInstance()->unregisterResource(sceneResID);
|
||||
if (previewBuffer.buffer) {
|
||||
previewBuffer.buffer->disassociate();
|
||||
|
@ -1586,6 +1605,9 @@ SceneContext::~SceneContext() {
|
|||
}
|
||||
|
||||
int SceneContext::detectPathLength() const {
|
||||
if (!scene)
|
||||
return 2;
|
||||
|
||||
const Integrator *integrator = scene->getIntegrator();
|
||||
int extraDepth = 0;
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ private slots:
|
|||
bool on_tabBar_tabCloseRequested(int index);
|
||||
void on_tabBar_tabMoved(int from, int to);
|
||||
void on_tabBar_customContextMenuRequested(const QPoint &pt);
|
||||
void on_glView_loadFileRequest(const QString &string);
|
||||
void onOpenRecent();
|
||||
void onClearRecent();
|
||||
void onWorkBegin(const RenderJob *job, const RectangularWorkUnit *wu, int worker);
|
||||
|
@ -125,7 +126,8 @@ private slots:
|
|||
void updateUI();
|
||||
void updateStatus();
|
||||
void onPreviewSettingsClose();
|
||||
void onFileDialogClose(int reason);
|
||||
void onOpenDialogClose(int reason);
|
||||
void onSaveAsDialogClose(int reason);
|
||||
void onRenderSettingsClose(int reason);
|
||||
|
||||
private:
|
||||
|
|
|
@ -117,18 +117,21 @@ void PreviewThread::setSceneContext(SceneContext *context, bool swapContext, boo
|
|||
m_queueCV->wait();
|
||||
}
|
||||
|
||||
if (swapContext) {
|
||||
if (swapContext && m_context) {
|
||||
m_context->vpls = m_vpls;
|
||||
m_context->previewBuffer = temp[0];
|
||||
m_context->previewBuffer.buffer->disassociate();
|
||||
m_recycleQueue.push_back(PreviewQueueEntry(m_queueEntryIndex++));
|
||||
}
|
||||
|
||||
/* Put back all buffers */
|
||||
for (size_t i=swapContext? 1 : 0; i<temp.size(); ++i)
|
||||
for (size_t i=1; i<temp.size(); ++i)
|
||||
m_recycleQueue.push_back(temp[i]);
|
||||
} else {
|
||||
for (size_t i=0; i<temp.size(); ++i)
|
||||
m_recycleQueue.push_back(temp[i]);
|
||||
}
|
||||
|
||||
if (swapContext && context->previewBuffer.vplSampleOffset > 0) {
|
||||
if (swapContext && context && context->previewBuffer.vplSampleOffset > 0) {
|
||||
/* Resume from a stored state */
|
||||
m_vplSampleOffset = context->previewBuffer.vplSampleOffset;
|
||||
m_vpls = context->vpls;
|
||||
|
@ -155,7 +158,6 @@ void PreviewThread::setSceneContext(SceneContext *context, bool swapContext, boo
|
|||
m_vplSampleOffset = 0;
|
||||
m_vpls.clear();
|
||||
m_accumBuffer = NULL;
|
||||
swapContext = false;
|
||||
}
|
||||
|
||||
if (m_context != context)
|
||||
|
@ -323,8 +325,6 @@ void PreviewThread::run() {
|
|||
m_timer->reset();
|
||||
}
|
||||
|
||||
int unsuccessfulAttempts = 0;
|
||||
while (true) {
|
||||
if (m_vpls.empty())
|
||||
m_vplSampleOffset = generateVPLs(m_context->scene, m_vplSampleOffset,
|
||||
1, m_context->pathLength, m_vpls);
|
||||
|
@ -332,16 +332,7 @@ void PreviewThread::run() {
|
|||
VPL vpl = m_vpls.front();
|
||||
m_vpls.pop_front();
|
||||
|
||||
if (rtrtRenderVPL(target, vpl)) {
|
||||
break;
|
||||
} else {
|
||||
if (unsuccessfulAttempts++ > 50) {
|
||||
Log(EError, "Something is fishy about this scene -- unable to "
|
||||
" render 50 VPLs in a row, disabling the preview feature.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtrtRenderVPL(target, vpl);
|
||||
} else {
|
||||
if (m_shaderManager == NULL || m_shaderManager->getScene() != m_context->scene) {
|
||||
if (m_shaderManager) {
|
||||
|
@ -370,8 +361,6 @@ void PreviewThread::run() {
|
|||
m_timer->reset();
|
||||
}
|
||||
|
||||
int unsuccessfulAttempts = 0;
|
||||
while (true) {
|
||||
if (m_vpls.empty())
|
||||
m_vplSampleOffset = generateVPLs(m_context->scene, m_vplSampleOffset,
|
||||
1, m_context->pathLength, m_vpls);
|
||||
|
@ -379,15 +368,8 @@ void PreviewThread::run() {
|
|||
VPL vpl = m_vpls.front();
|
||||
m_vpls.pop_front();
|
||||
|
||||
if (oglRenderVPL(target, vpl)) {
|
||||
break;
|
||||
} else {
|
||||
if (unsuccessfulAttempts++ > 50) {
|
||||
Log(EError, "Something is fishy about this scene -- unable to "
|
||||
" render 50 VPLs in a row, disabling the preview feature.");
|
||||
}
|
||||
}
|
||||
}
|
||||
oglRenderVPL(target, vpl);
|
||||
|
||||
if (m_useSync)
|
||||
target.sync->init();
|
||||
}
|
||||
|
@ -454,11 +436,10 @@ void PreviewThread::run() {
|
|||
MTS_AUTORELEASE_END()
|
||||
}
|
||||
|
||||
bool PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||
void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||
const std::vector<TriMesh *> meshes = m_context->scene->getMeshes();
|
||||
|
||||
if (!m_shaderManager->setVPL(vpl))
|
||||
return false;
|
||||
m_shaderManager->setVPL(vpl);
|
||||
|
||||
Point2 jitter(.5f, .5f);
|
||||
if (!m_motion)
|
||||
|
@ -467,8 +448,11 @@ bool PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
m_mutex->lock();
|
||||
const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>
|
||||
(m_context->scene->getCamera());
|
||||
m_renderer->setCamera(camera->getGLProjectionTransform(jitter).getMatrix(),
|
||||
m_camViewTransform.getMatrix());
|
||||
Transform projectionTransform = camera->getGLProjectionTransform(jitter);
|
||||
m_renderer->setCamera(projectionTransform.getMatrix(), m_camViewTransform.getMatrix());
|
||||
Transform clipToWorld = m_camViewTransform.inverse()
|
||||
* Transform::scale(Vector(1, 1, -1)) * projectionTransform.inverse();
|
||||
|
||||
target.vplSampleOffset = m_vplSampleOffset;
|
||||
Point camPos = m_camPos;
|
||||
m_mutex->unlock();
|
||||
|
@ -482,8 +466,9 @@ bool PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
m_renderer->drawTriMesh(meshes[j]);
|
||||
m_shaderManager->unbind();
|
||||
}
|
||||
m_framebuffer->releaseTarget();
|
||||
m_renderer->endDrawingMeshes();
|
||||
m_shaderManager->drawBackground(clipToWorld, camPos);
|
||||
m_framebuffer->releaseTarget();
|
||||
|
||||
target.buffer->activateTarget();
|
||||
m_renderer->setDepthMask(false);
|
||||
|
@ -521,10 +506,9 @@ bool PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
m_renderer->finish();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||
void PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||
Float nearClip = std::numeric_limits<Float>::infinity(),
|
||||
farClip = -std::numeric_limits<Float>::infinity();
|
||||
|
||||
|
@ -549,11 +533,15 @@ bool PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
}
|
||||
}
|
||||
|
||||
if (nearClip >= farClip)
|
||||
return false;
|
||||
|
||||
Float minDist = nearClip + (farClip - nearClip) * m_context->clamping;
|
||||
|
||||
if (nearClip >= farClip) {
|
||||
/* Unable to find any surface - just default values based on the scene size */
|
||||
nearClip = 1e-3 * m_context->scene->getBSphere().radius;
|
||||
farClip = 1e3 * m_context->scene->getBSphere().radius;
|
||||
minDist = 0;
|
||||
}
|
||||
|
||||
Point2 jitter(.5f, .5f);
|
||||
if (!m_motion)
|
||||
jitter = Point2(m_random->nextFloat(), m_random->nextFloat());
|
||||
|
@ -574,6 +562,4 @@ bool PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
target.vplSampleOffset = m_vplSampleOffset;
|
||||
m_raysPerSecond += m_previewProc->getRayCount();
|
||||
m_accumBuffer = target.buffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -55,9 +55,9 @@ protected:
|
|||
/// Virtual destructure
|
||||
virtual ~PreviewThread();
|
||||
/// Render a single VPL using OpenGL
|
||||
bool oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
|
||||
void oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
|
||||
/// Render a single VPL using real-time coherent ray tracing
|
||||
bool rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
|
||||
void rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
|
||||
private:
|
||||
ref<Session> m_session;
|
||||
ref<Device> m_device, m_parentDevice;
|
||||
|
|
|
@ -110,12 +110,9 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement camera = findUniqueChild(root, "camera");
|
||||
if (camera.isNull()) {
|
||||
QMessageBox::critical(parent, parent->tr("Unable to save"),
|
||||
parent->tr("Unable to save changes: could not find the camera descriptor in "
|
||||
"<b>%1</b>. If you are using include files, make sure that the camera "
|
||||
"descriptor is located within the main scene file.").arg(ctx->fileName),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
camera = doc.createElement("camera");
|
||||
camera.setAttribute("type", "perspective");
|
||||
root.insertAfter(camera, QDomNode());
|
||||
}
|
||||
const PinholeCamera *sceneCamera = static_cast<const PinholeCamera *>(ctx->scene->getCamera());
|
||||
|
||||
|
@ -130,6 +127,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
QDomElement cameraTransform = findUniqueChild(camera, "transform");
|
||||
if (cameraTransform.isNull()) {
|
||||
cameraTransform = doc.createElement("transform");
|
||||
cameraTransform.setAttribute("name", "toWorld");
|
||||
camera.insertBefore(cameraTransform, QDomNode());
|
||||
}
|
||||
|
||||
|
@ -142,7 +140,10 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
Point t, p = sceneCamera->getInverseViewTransform()(Point(0,0,0));
|
||||
|
||||
if (sceneCamera->getViewTransform().det3x3() > 0) {
|
||||
p.z = -p.z; direction.z = -direction.z; u = -u;
|
||||
p.z = -p.z; direction.z = -direction.z;
|
||||
QDomElement scale = doc.createElement("scale");
|
||||
cameraTransform.insertAfter(scale, lookAt);
|
||||
scale.setAttribute("z", "-1");
|
||||
}
|
||||
t = p + direction;
|
||||
|
||||
|
@ -178,12 +179,9 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement film = findUniqueChild(camera, "film");
|
||||
if (film.isNull()) {
|
||||
QMessageBox::critical(parent, parent->tr("Unable to save"),
|
||||
parent->tr("Unable to save changes: could not find the film descriptor in "
|
||||
"<b>%1</b>. If you are using include files, make sure that the film "
|
||||
"descriptor is located within the main scene file.").arg(ctx->fileName),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
film = doc.createElement("film");
|
||||
film.setAttribute("type", "exrfilm");
|
||||
camera.insertAfter(film, QDomNode());
|
||||
}
|
||||
QDomElement widthProperty = findProperty(film, "width");
|
||||
QDomElement heightProperty = findProperty(film, "height");
|
||||
|
|
|
@ -14,9 +14,35 @@ SceneLoader::~SceneLoader() {
|
|||
void SceneLoader::run() {
|
||||
FileResolver::setInstance(m_resolver);
|
||||
SAXParser* parser = new SAXParser();
|
||||
std::string lowerCase = m_filename;
|
||||
for(size_t i=0; i<m_filename.size();++i)
|
||||
lowerCase[i] = std::tolower(m_filename[i]);
|
||||
|
||||
SceneHandler *handler = new SceneHandler();
|
||||
m_result = new SceneContext();
|
||||
try {
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
m_result->srgb = settings.value("preview_sRGB", true).toBool();
|
||||
m_result->gamma = (Float) settings.value("preview_gamma", 2.2).toDouble();
|
||||
m_result->reinhardKey = (Float) settings.value("preview_reinhardKey", 0.18).toDouble();
|
||||
m_result->reinhardBurn = (Float) settings.value("preview_reinhardBurn", 0.0).toDouble();
|
||||
m_result->exposure = (Float) settings.value("preview_exposure", 0).toDouble();
|
||||
m_result->shadowMapResolution = settings.value("preview_shadowMapResolution", 256).toInt();
|
||||
m_result->clamping = (Float) settings.value("preview_clamping", 0.1f).toDouble();
|
||||
m_result->previewMethod = (EPreviewMethod) settings.value("preview_previewMethod", EOpenGL).toInt();
|
||||
m_result->toneMappingMethod = (EToneMappingMethod) settings.value("preview_toneMappingMethod", EGamma).toInt();
|
||||
|
||||
if (endsWith(lowerCase, ".exr")) {
|
||||
/* This is an image, not a scene */
|
||||
ref<FileStream> fs = new FileStream(m_filename, FileStream::EReadOnly);
|
||||
ref<Bitmap> bitmap = new Bitmap(Bitmap::EEXR, fs);
|
||||
|
||||
m_result->mode = ERender;
|
||||
m_result->framebuffer = bitmap;
|
||||
m_result->fileName = QString(m_filename.c_str());
|
||||
m_result->shortName = QFileInfo(m_filename.c_str()).fileName();
|
||||
m_result->pathLength = 2;
|
||||
} else {
|
||||
std::string schemaPath = m_resolver->resolveAbsolute("schema/scene.xsd");
|
||||
|
||||
/* Check against the 'scene.xsd' XML Schema */
|
||||
|
@ -64,18 +90,8 @@ void SceneLoader::run() {
|
|||
m_result->shortName = QFileInfo(m_filename.c_str()).fileName();
|
||||
m_result->up = camera->getInverseViewTransform()(Vector(0, 1, 0));
|
||||
m_result->scrollOffset = Vector2i(0, 0);
|
||||
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
m_result->srgb = settings.value("preview_sRGB", true).toBool();
|
||||
m_result->gamma = (Float) settings.value("preview_gamma", 2.2).toDouble();
|
||||
m_result->reinhardKey = (Float) settings.value("preview_reinhardKey", 0.18).toDouble();
|
||||
m_result->reinhardBurn = (Float) settings.value("preview_reinhardBurn", 0.0).toDouble();
|
||||
m_result->exposure = (Float) settings.value("preview_exposure", 0).toDouble();
|
||||
m_result->shadowMapResolution = settings.value("preview_shadowMapResolution", 256).toInt();
|
||||
m_result->clamping = (Float) settings.value("preview_clamping", 0.1f).toDouble();
|
||||
m_result->pathLength = m_result->detectPathLength();
|
||||
m_result->previewMethod = (EPreviewMethod) settings.value("preview_previewMethod", EOpenGL).toInt();
|
||||
m_result->toneMappingMethod = (EToneMappingMethod) settings.value("preview_toneMappingMethod", EGamma).toInt();
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
m_error = e.what();
|
||||
delete m_result;
|
||||
|
|
|
@ -122,6 +122,7 @@ public:
|
|||
its.shFrame = its.geoFrame;
|
||||
its.wi = its.toLocal(-ray.d);
|
||||
its.hasUVPartials = false;
|
||||
its.shape = this;
|
||||
|
||||
/* Intersection refinement step */
|
||||
Vector2 localDir(normalize(Vector2(local.x, local.y)));
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
phi += 2*M_PI;
|
||||
its.uv.x = theta / M_PI;
|
||||
its.uv.y = phi / (2*M_PI);
|
||||
its.shape = this;
|
||||
Float zrad = std::sqrt(local.x*local.x + local.y*local.y);
|
||||
|
||||
its.geoFrame.n = Normal(normalize(its.p - m_center));
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* Gamma-corrected bitmap texture using the JPG file format
|
||||
* Gamma-corrected bitmap texture using the JPG or PNG file format
|
||||
*/
|
||||
class LDRTexture : public Texture {
|
||||
public:
|
||||
|
@ -233,6 +233,7 @@ public:
|
|||
m_gpuTexture->setWrapType(GPUTexture::ERepeat);
|
||||
m_gpuTexture->setMaxAnisotropy(8);
|
||||
m_gpuTexture->init();
|
||||
/* Release the memory on the host side */
|
||||
m_gpuTexture->setBitmap(0, NULL);
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,10 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
tar --exclude-vcs -czvf mitsuba-$1.tar.gz --transform "s,^,mitsuba-$1/," ChangeLog README SConstruct \
|
||||
tar --exclude-vcs -czvf mitsuba-$1.tar.gz ChangeLog README SConstruct \
|
||||
config include/ schema/ src/bsdfs/ src/cameras/ src/collada/ src/films/ src/libcore/ src/libhw/ \
|
||||
src/librender/ src/luminaires/ src/medium/ src/mitsuba/ src/phase/ src/qtgui/ src/rfilters/ src/samplers/ \
|
||||
src/shapes/ src/subsurface/ src/textures/ src/utils/ src/volume/ src/integrators/direct src/integrators/misc \
|
||||
src/integrators/path src/integrators/photonmapper src/integrators/vpl tools/boost tools/darwin \
|
||||
tools/build.sh tools/scons-1.2.0 tools/windows tools/linux/*.sh tools/linux/mitsuba.desktop tools/qt4.py \
|
||||
tools/build.bat
|
||||
|
||||
tools/build.bat setpath.sh
|
||||
|
|
Loading…
Reference in New Issue