diff --git a/data/blender/mitsuba/core/__init__.py b/data/blender/mitsuba/core/__init__.py
index ac6866b0..b700421b 100644
--- a/data/blender/mitsuba/core/__init__.py
+++ b/data/blender/mitsuba/core/__init__.py
@@ -106,8 +106,6 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine):
output_dir = scene_path
else:
output_dir = os.path.dirname(scene_path)
- if output_dir[-1] != '/':
- output_dir += '/'
efutil.export_path = output_dir
os.chdir(output_dir)
@@ -245,4 +243,3 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine):
framebuffer_thread.kick(render_end=True)
framebuffer_thread.shutdown()
-
diff --git a/data/blender/mitsuba/export/__init__.py b/data/blender/mitsuba/export/__init__.py
index 7a2d289d..dc35972c 100644
--- a/data/blender/mitsuba/export/__init__.py
+++ b/data/blender/mitsuba/export/__init__.py
@@ -401,7 +401,13 @@ class MtsExporter:
if not hasattr(mat, 'name') or mat.name in self.exported_materials:
return
self.exported_materials += [mat.name]
- params = mat.mitsuba_material.get_params()
+ mmat = mat.mitsuba_material
+ params = mmat.get_params()
+ twosided = False
+
+ if mmat.twosided and mmat.type in ['lambertian', 'phong', 'ward',
+ 'mirror', 'roughmetal', 'microfacet', 'composite']:
+ twosided = True
for p in params:
if p.type == 'reference_material':
@@ -409,14 +415,22 @@ class MtsExporter:
elif p.type == 'reference_texture':
self.exportTexture(self.findTexture(p.value))
- self.openElement('bsdf', {'id' : '%s-material' % translate_id(mat.name), 'type' : mat.mitsuba_material.type})
+ if twosided:
+ self.openElement('bsdf', {'id' : '%s-material' % translate_id(mat.name), 'type' : 'twosided'})
+ self.openElement('bsdf', {'type' : mmat.type})
+ else:
+ self.openElement('bsdf', {'id' : '%s-material' % translate_id(mat.name), 'type' : mmat.type})
+
params.export(self)
self.closeElement()
+
+ if twosided:
+ self.closeElement()
def exportEmission(self, obj):
- mult = lamp.intensity
lamp = obj.data.materials[0].mitsuba_emission
name = translate_id(obj.data.name)
+ mult = lamp.intensity
self.openElement('append', { 'id' : '%s-mesh_0' % name})
self.openElement('luminaire', { 'id' : '%s-emission' % name, 'type' : 'area'})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.samplingWeight})
@@ -426,23 +440,21 @@ class MtsExporter:
self.closeElement()
def exportPreviewMesh(self, material):
- self.out.write('\t\t\n')
- self.out.write('\t\t\t\n')
- self.out.write('\t\t\t\n')
- self.out.write('\t\t\t\n')
- self.out.write('\t\t\t\t\n')
- self.out.write('\t\t\t\n')
- self.out.write('\t\t\t\n' % translate_id(material.name))
+ self.openElement('shape', {'id' : 'Exterior-mesh_0', 'type' : 'serialized'})
+ self.parameter('string', 'filename', {'value' : 'matpreview.serialized'})
+ self.parameter('integer', 'shapeIndex', {'value' : '1'})
+ self.openElement('transform', {'name' : 'toWorld'})
+ self.element('matrix', {'value' : '0.614046 0.614047 0 -1.78814e-07 -0.614047 0.614046 0 2.08616e-07 0 0 0.868393 1.02569 0 0 0 1'})
+ self.closeElement()
+ self.element('ref', {'name' : 'bsdf', 'id' : '%s-material' % translate_id(material.name)})
lamp = material.mitsuba_emission
if lamp and lamp.use_emission:
mult = lamp.intensity
- self.out.write('\t\t\t\n')
- self.out.write('\t\t\t\t\n'
- % (lamp.color.r*mult, lamp.color.g*mult, lamp.color.b*mult))
- self.out.write('\t\t\t\t\n' % lamp.samplingWeight)
- self.out.write('\t\t\t\n')
- self.out.write('\t\t\n')
- self.out.write('\n')
+ self.openElement('luminaire', {'type' : 'area'})
+ self.parameter('rgb', 'intensity', { 'value' : "%f %f %f"
+ % (lamp.color.r*mult, lamp.color.g*mult, lamp.color.b*mult)})
+ self.closeElement()
+ self.closeElement()
def exportCameraSettings(self, scene, camera):
if scene.mitsuba_integrator.motionblur:
@@ -450,10 +462,20 @@ class MtsExporter:
shuttertime = scene.mitsuba_integrator.shuttertime
shutterOpen = (scene.frame_current - shuttertime/2) * frameTime
shutterClose = (scene.frame_current + shuttertime/2) * frameTime
- self.out.write('\t\n' % translate_id(camera.name))
- self.out.write('\t\t\n' % shutterOpen)
- self.out.write('\t\t\n' % shutterClose)
- self.out.write('\t\n')
+ self.openElement('prepend', {'id' : '%s-camera' % translate_id(camera.name)})
+ self.parameter('float', 'shutterOpen', {'value' : str(shutterOpen)})
+ self.parameter('float', 'shutterClose', {'value' : str(shutterClose)})
+ self.closeElement()
+
+ def exportMedium(self, medium):
+ self.openElement('medium', {'id' : medium.name, 'type' : medium.type})
+ if medium.g == 0:
+ self.element('phase', {'type' : 'isotropic'})
+ else:
+ self.openElement('phase', {'type' : 'hg'})
+ self.parameter('float', 'g', {'value' : str(medium.g)})
+ self.closeElement()
+ self.closeElement()
def export(self, scene):
if scene.mitsuba_engine.binary_path == '':
@@ -463,7 +485,6 @@ class MtsExporter:
idx = 0
# Force scene update; NB, scene.update() doesn't work
scene.frame_set(scene.frame_current)
-
efutil.export_path = self.xml_filename
try:
os.mkdir(self.meshes_dir)
@@ -477,6 +498,8 @@ class MtsExporter:
self.writeHeader()
self.exportIntegrator(scene.mitsuba_integrator)
self.exportSampler(scene.mitsuba_sampler)
+ for medium in scene.mitsuba_media.media:
+ self.exportMedium(medium)
for obj in scene.objects:
if obj.type == 'LAMP':
self.exportLamp(obj, idx)
@@ -490,7 +513,7 @@ class MtsExporter:
idx = idx+1
self.writeFooter()
(width, height) = resolution(scene)
-
+
MtsLog("MtsBlend: Launching mtsimport")
command = ['mtsimport', '-r', '%dx%d' % (width, height),
'-n', '-l', 'pngfilm', self.dae_filename, self.xml_filename, self.adj_filename]
diff --git a/include/mitsuba/core/sfcurve.h b/include/mitsuba/core/sfcurve.h
index 4b46fcbe..bcbbf019 100644
--- a/include/mitsuba/core/sfcurve.h
+++ b/include/mitsuba/core/sfcurve.h
@@ -52,7 +52,7 @@ public:
m_points.reserve(m_size.x*m_size.y);
m_size = size; m_pos = PointType(0);
generate(
- log2i(std::max(m_size.x, m_size.y)),
+ log2i((uint32_t) std::max(m_size.x, m_size.y)),
ENorth, EEast, ESouth, EWest);
}
diff --git a/include/mitsuba/core/util.h b/include/mitsuba/core/util.h
index 34a51c31..e6634e27 100644
--- a/include/mitsuba/core/util.h
+++ b/include/mitsuba/core/util.h
@@ -104,17 +104,35 @@ extern MTS_EXPORT_CORE std::string formatString(const char *pFmt, ...);
/// Base-2 logarithm
extern MTS_EXPORT_CORE Float log2(Float value);
-/// Base-2 logarithm (integer version)
-extern MTS_EXPORT_CORE int log2i(int value);
+/// Base-2 logarithm (32-bit integer version)
+extern MTS_EXPORT_CORE int log2i(uint32_t value);
+
+/// Base-2 logarithm (64-bit integer version)
+extern MTS_EXPORT_CORE int log2i(uint64_t value);
/// Friendly modulo function (always positive)
extern MTS_EXPORT_CORE int modulo(int a, int b);
-/// Check if an integer is a power of two
-extern MTS_EXPORT_CORE bool isPowerOfTwo(unsigned int i);
+/// Check if an integer is a power of two (32 bit version)
+inline bool isPowerOfTwo(uint32_t i) {
+ return (i & (i-1)) == 0;
+}
+
+/// Check if an integer is a power of two (signed 32 bit version)
+inline bool isPowerOfTwo(int32_t i) {
+ return i > 0 && (i & (i-1)) == 0;
+}
+
+/// Check if an integer is a power of two (64 bit version)
+inline bool isPowerOfTwo(uint64_t i) {
+ return (i & (i-1)) == 0;
+}
/// Round an integer to the next power of two
-extern MTS_EXPORT_CORE unsigned int roundToPowerOfTwo(unsigned int i);
+extern MTS_EXPORT_CORE uint32_t roundToPowerOfTwo(uint32_t i);
+
+/// Round an integer to the next power of two (64 bit version)
+extern MTS_EXPORT_CORE uint64_t roundToPowerOfTwo(uint64_t i);
//// Windowed sinc filter (Lanczos envelope, tau=number of cycles)
extern MTS_EXPORT_CORE Float lanczosSinc(Float t, Float tau = 2);
diff --git a/include/mitsuba/render/gkdtree.h b/include/mitsuba/render/gkdtree.h
index 69294846..2f477d65 100644
--- a/include/mitsuba/render/gkdtree.h
+++ b/include/mitsuba/render/gkdtree.h
@@ -923,7 +923,7 @@ protected:
KDLog(EError, "The exact primitive threshold must be >= 0");
if (m_minMaxBins <= 1)
KDLog(EError, "The number of min-max bins must be > 2");
-
+
size_type primCount = cast()->getPrimitiveCount();
if (primCount == 0) {
KDLog(EWarn, "kd-tree contains no geometry!");
@@ -933,6 +933,9 @@ protected:
return;
}
+ if (primCount <= m_exactPrimThreshold)
+ m_parallelBuild = false;
+
BuildContext ctx(primCount, m_minMaxBins);
/* Establish an ad-hoc depth cutoff value (Formula from PBRT) */
diff --git a/include/mitsuba/render/skdtree.h b/include/mitsuba/render/skdtree.h
index 11f5e614..171d9c80 100644
--- a/include/mitsuba/render/skdtree.h
+++ b/include/mitsuba/render/skdtree.h
@@ -389,6 +389,7 @@ protected:
if (EXPECT_TAKEN(!vertexTangents)) {
its.shFrame = Frame(normalize(n0 * b.x + n1 * b.y + n2 * b.z));
+ its.dpdu = its.dpdv = Vector(0.0f);
} else {
const TangentSpace &t0 = vertexTangents[idx0];
const TangentSpace &t1 = vertexTangents[idx1];
@@ -403,6 +404,7 @@ protected:
}
} else {
its.shFrame = its.geoFrame;
+ its.dpdu = its.dpdv = Vector(0.0f);
}
if (EXPECT_TAKEN(vertexTexcoords)) {
diff --git a/src/bsdfs/SConscript b/src/bsdfs/SConscript
index 42f467a1..80979651 100644
--- a/src/bsdfs/SConscript
+++ b/src/bsdfs/SConscript
@@ -12,5 +12,6 @@ plugins += env.SharedLibrary('#plugins/microfacet', ['microfacet.cpp'])
plugins += env.SharedLibrary('#plugins/roughglass', ['roughglass.cpp'])
plugins += env.SharedLibrary('#plugins/roughmetal', ['roughmetal.cpp'])
plugins += env.SharedLibrary('#plugins/composite', ['composite.cpp'])
+plugins += env.SharedLibrary('#plugins/twosided', ['twosided.cpp'])
Export('plugins')
diff --git a/src/bsdfs/twosided.cpp b/src/bsdfs/twosided.cpp
new file mode 100644
index 00000000..e8d9bab4
--- /dev/null
+++ b/src/bsdfs/twosided.cpp
@@ -0,0 +1,193 @@
+/*
+ This file is part of Mitsuba, a physically based rendering system.
+
+ Copyright (c) 2007-2010 by Wenzel Jakob and others.
+
+ Mitsuba is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License Version 3
+ as published by the Free Software Foundation.
+
+ Mitsuba is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include
+#include
+#include
+
+MTS_NAMESPACE_BEGIN
+
+class TwoSidedBRDF : public BSDF {
+public:
+ TwoSidedBRDF(const Properties &props)
+ : BSDF(props) { }
+
+ TwoSidedBRDF(Stream *stream, InstanceManager *manager)
+ : BSDF(stream, manager) {
+ m_nestedBRDF = static_cast(manager->getInstance(stream));
+ configure();
+ }
+
+ virtual ~TwoSidedBRDF() {
+ if (m_type)
+ delete m_type;
+ }
+
+ void serialize(Stream *stream, InstanceManager *manager) const {
+ BSDF::serialize(stream, manager);
+
+ manager->serialize(stream, m_nestedBRDF.get());
+ }
+
+ void configure() {
+ if (!m_nestedBRDF)
+ Log(EError, "TwoSidedBRDF: A child BRDF instance is required");
+ m_combinedType = m_nestedBRDF->getType();
+ if (m_combinedType & BSDF::ETransmission)
+ Log(EError, "TwoSidedBRDF: only BRDF child instances (without "
+ "transmission) are supported");
+ m_usesRayDifferentials = m_nestedBRDF->usesRayDifferentials();
+ m_componentCount = m_nestedBRDF->getComponentCount();
+ m_type = new unsigned int[m_componentCount];
+ for (int i=0; igetComponentCount(); ++i)
+ m_type[i] = m_nestedBRDF->getType(i);
+ }
+
+ Spectrum getDiffuseReflectance(const Intersection &its) const {
+ return m_nestedBRDF->getDiffuseReflectance(its);
+ }
+
+ Spectrum f(const BSDFQueryRecord &bRec) const {
+ BSDFQueryRecord b(bRec);
+ if (b.wi.z < 0) {
+ b.wi.z *= -1;
+ b.wo.z *= -1;
+ }
+ return m_nestedBRDF->f(b);
+ }
+
+
+ Float pdf(const BSDFQueryRecord &bRec) const {
+ BSDFQueryRecord b(bRec);
+ if (b.wi.z < 0) {
+ b.wi.z *= -1;
+ b.wo.z *= -1;
+ }
+ return m_nestedBRDF->pdf(b);
+ }
+
+
+ Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
+ bool flip = false;
+ if (bRec.wi.z < 0) {
+ bRec.wi.z *= -1;
+ flip = true;
+ }
+ Spectrum result = m_nestedBRDF->sample(bRec, sample);
+ if (bRec.wi.z < 0 && !result.isZero()) {
+ bRec.wi.z *= -1;
+ bRec.wo.z *= -1;
+ flip = true;
+ }
+ return result;
+ }
+
+ Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const {
+ bool flip = false;
+ if (bRec.wi.z < 0) {
+ bRec.wi.z *= -1;
+ flip = true;
+ }
+ Spectrum result = m_nestedBRDF->sample(bRec, pdf, sample);
+ if (bRec.wi.z < 0 && !result.isZero()) {
+ bRec.wi.z *= -1;
+ bRec.wo.z *= -1;
+ flip = true;
+ }
+ return result;
+ }
+
+ void addChild(const std::string &name, ConfigurableObject *child) {
+ if (child->getClass()->derivesFrom(BSDF::m_theClass)) {
+ m_nestedBRDF = static_cast(child);
+ } else {
+ BSDF::addChild(name, child);
+ }
+ }
+
+ std::string toString() const {
+ std::ostringstream oss;
+ oss << "TwoSided[" << endl
+ << " nestedBRDF = " << indent(m_nestedBRDF->toString()) << endl
+ << "]";
+ return oss.str();
+ }
+
+
+ Shader *createShader(Renderer *renderer) const;
+
+ MTS_DECLARE_CLASS()
+protected:
+ ref m_nestedBRDF;
+};
+
+
+// ================ Hardware shader implementation ================
+
+class TwoSidedShader : public Shader {
+public:
+ TwoSidedShader(Renderer *renderer,
+ const BSDF *nestedBRDF) : Shader(renderer, EBSDFShader),
+ m_nestedBRDF(nestedBRDF) {
+ m_nestedBRDFShader = renderer->registerShaderForResource(nestedBRDF);
+ }
+
+ bool isComplete() const {
+ return m_nestedBRDFShader.get() != NULL;
+ }
+
+ void putDependencies(std::vector &deps) {
+ deps.push_back(m_nestedBRDFShader.get());
+ }
+
+ void cleanup(Renderer *renderer) {
+ renderer->unregisterShaderForResource(m_nestedBRDF);
+ }
+
+ void generateCode(std::ostringstream &oss,
+ const std::string &evalName,
+ const std::vector &depNames) const {
+ oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
+ << " if (wi.z <= 0.0) {" << endl
+ << " wi.z *= -1; wo.z *= -1;" << endl
+ << " }" << endl
+ << " return " << depNames[0] << "(uv, wi, wo);" << endl
+ << "}" << endl
+ << "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
+ << " if (wi.z <= 0.0) {" << endl
+ << " wi.z *= -1; wo.z *= -1;" << endl
+ << " }" << endl
+ << " return " << depNames[0] << "_diffuse(uv, wi, wo);" << endl
+ << "}" << endl;
+ }
+
+ MTS_DECLARE_CLASS()
+private:
+ const BSDF *m_nestedBRDF;
+ ref m_nestedBRDFShader;
+ bool m_complete;
+};
+
+Shader *TwoSidedBRDF::createShader(Renderer *renderer) const {
+ return new TwoSidedShader(renderer, m_nestedBRDF.get());
+}
+
+MTS_IMPLEMENT_CLASS(TwoSidedShader, false, Shader)
+MTS_IMPLEMENT_CLASS_S(TwoSidedBRDF, false, BSDF)
+MTS_EXPORT_PLUGIN(TwoSidedBRDF, "Two-sided BRDF adapter");
+MTS_NAMESPACE_END
diff --git a/src/converter/collada.cpp b/src/converter/collada.cpp
index 58da730c..6cf3b5d9 100644
--- a/src/converter/collada.cpp
+++ b/src/converter/collada.cpp
@@ -224,6 +224,7 @@ VertexData *fetchVertexData(Transform transform,
result->typeToOffset[EUV] = offset;
result->typeToOffsetInStream[EUV] = offsetInStream;
result->typeToCount[EUV] = size;
+ cout << "Got texture coordinates.." << endl;
} else {
SLog(EWarn, "Found multiple sets of texture coordinates - ignoring!");
}
diff --git a/src/libcore/util.cpp b/src/libcore/util.cpp
index 27a2550b..d3091795 100644
--- a/src/libcore/util.cpp
+++ b/src/libcore/util.cpp
@@ -244,7 +244,7 @@ bool enableFPExceptions() {
bool exceptionsWereEnabled = false;
#if defined(WIN32)
_clearfp();
- unsigned int cw = _controlfp(0, 0);
+ uint32_t cw = _controlfp(0, 0);
exceptionsWereEnabled = ~cw & (_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW);
cw &= ~(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW);
_controlfp(cw, _MCW_EM);
@@ -268,7 +268,7 @@ bool disableFPExceptions() {
bool exceptionsWereEnabled = false;
#if defined(WIN32)
_clearfp();
- unsigned int cw = _controlfp(0, 0);
+ uint32_t cw = _controlfp(0, 0);
exceptionsWereEnabled = ~cw & (_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW);
cw |= _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
_controlfp(cw, _MCW_EM);
@@ -288,7 +288,7 @@ bool disableFPExceptions() {
void restoreFPExceptions(bool oldState) {
bool currentState;
#if defined(WIN32)
- unsigned int cw = _controlfp(0, 0);
+ uint32_t cw = _controlfp(0, 0);
currentState = ~cw & (_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW);
#elif defined(__OSX__)
currentState = query_fpexcept_sse() != 0;
@@ -381,11 +381,18 @@ std::string formatString(const char *fmt, ...) {
return std::string(tmp);
}
-int log2i(int value) {
- int r = 0;
- while ((value >> r) != 0)
- r++;
- return r-1;
+int log2i(uint32_t value) {
+ int r = 0;
+ while ((value >> r) != 0)
+ r++;
+ return r-1;
+}
+
+int log2i(uint64_t value) {
+ int r = 0;
+ while ((value >> r) != 0)
+ r++;
+ return r-1;
}
int modulo(int a, int b) {
@@ -394,11 +401,7 @@ int modulo(int a, int b) {
}
/* Fast rounding & power-of-two test algorithms from PBRT */
-bool isPowerOfTwo(unsigned int i) {
- return (i & (i-1)) == 0;
-}
-
-unsigned int roundToPowerOfTwo(unsigned int i) {
+uint32_t roundToPowerOfTwo(uint32_t i) {
i--;
i |= i >> 1; i |= i >> 2;
i |= i >> 4; i |= i >> 8;
@@ -406,6 +409,13 @@ unsigned int roundToPowerOfTwo(unsigned int i) {
return i+1;
}
+uint64_t roundToPowerOfTwo(uint64_t i) {
+ i--;
+ i |= i >> 1; i |= i >> 2;
+ i |= i >> 4; i |= i >> 8;
+ i |= i >> 16; i |= i >> 32;
+ return i+1;
+}
// -----------------------------------------------------------------------
// Numerical utility functions
diff --git a/src/librender/mipmap.cpp b/src/librender/mipmap.cpp
index f1d03f93..ac2b5faf 100644
--- a/src/librender/mipmap.cpp
+++ b/src/librender/mipmap.cpp
@@ -32,8 +32,8 @@ MIPMap::MIPMap(int width, int height, Spectrum *pixels,
Spectrum *texture = pixels;
if (!isPowerOfTwo(width) || !isPowerOfTwo(height)) {
- m_width = roundToPowerOfTwo(width);
- m_height = roundToPowerOfTwo(height);
+ m_width = (int) roundToPowerOfTwo((uint32_t) width);
+ m_height = (int) roundToPowerOfTwo((uint32_t) height);
/* The texture needs to be up-sampled */
Spectrum *texture1 = new Spectrum[m_width*height];
@@ -87,7 +87,7 @@ MIPMap::MIPMap(int width, int height, Spectrum *pixels,
delete[] texture1;
}
- m_levels = 1 + log2i(std::max(width, height));
+ m_levels = 1 + log2i((uint32_t) std::max(width, height));
m_pyramid = new Spectrum*[m_levels];
m_pyramid[0] = texture;
m_levelWidth = new int[m_levels];
diff --git a/src/librender/trimesh.cpp b/src/librender/trimesh.cpp
index a338e8d9..33625e8d 100644
--- a/src/librender/trimesh.cpp
+++ b/src/librender/trimesh.cpp
@@ -285,7 +285,7 @@ void TriMesh::configure() {
}
if (hasBSDF() && ((m_bsdf->getType() & BSDF::EAnisotropicMaterial)
- || m_bsdf->usesRayDifferentials()) && !m_tangents)
+ || m_bsdf->usesRayDifferentials()) && !m_tangents)
computeTangentSpaceBasis();
}
@@ -546,10 +546,12 @@ void TriMesh::computeNormals() {
bool TriMesh::computeTangentSpaceBasis() {
int zeroArea = 0, zeroNormals = 0;
if (!m_texcoords) {
- if (hasBSDF() && m_bsdf->getType() & BSDF::EAnisotropicMaterial)
- Log(EError, "\"%s\": computeTangentSpace(): texture coordinates are required "
- "to generate tangent vectors. If you want to render with an anisotropic "
- "material, make sure that all assigned objects have texture coordinates.");
+ bool anisotropic = hasBSDF() && m_bsdf->getType() & BSDF::EAnisotropicMaterial;
+ if (anisotropic)
+ Log(EError, "\"%s\": computeTangentSpace(): texture coordinates "
+ "are required to generate tangent vectors. If you want to render with an anisotropic "
+ "material, please make sure that all associated shapes have valid texture coordinates.",
+ getName().c_str());
return false;
}
diff --git a/src/qtgui/mainwindow.ui b/src/qtgui/mainwindow.ui
index a827617f..273bf985 100644
--- a/src/qtgui/mainwindow.ui
+++ b/src/qtgui/mainwindow.ui
@@ -470,7 +470,7 @@
- Describe Scene..
+ Scene Information ..
diff --git a/src/qtgui/rendersettingsdlg.cpp b/src/qtgui/rendersettingsdlg.cpp
index 4a2e2d9d..8b3a38fd 100644
--- a/src/qtgui/rendersettingsdlg.cpp
+++ b/src/qtgui/rendersettingsdlg.cpp
@@ -183,17 +183,10 @@ void RenderSettingsDialog::onTreeSelectionChange(const QItemSelection &selected,
void RenderSettingsDialog::update() {
int index = ui->integratorBox->currentIndex();
- Properties integratorProps;
+ Properties integratorProps, samplerProps;
- int sampleCount = -1;
- if (sender() == ui->samplerBox) {
- Properties samplerProps;
+ if (sender() == ui->samplerBox)
m_samplerNode->putProperties(samplerProps);
- if (samplerProps.hasProperty("sampleCount"))
- sampleCount = samplerProps.getInteger("sampleCount");
- else if (samplerProps.hasProperty("resolution"))
- sampleCount = (int) std::pow((Float) samplerProps.getInteger("resolution"), (Float) 2);
- }
if (sender() == ui->integratorBox)
m_integratorNode->putProperties(integratorProps);
@@ -224,18 +217,6 @@ void RenderSettingsDialog::update() {
m_aiNode = m_model->updateClass(m_aiNode, "", "");
}
- if (sender() == ui->samplerBox && sampleCount != -1) {
- std::string samplerPlugin = getPluginName(ui->samplerBox);
- for (int i=0; ichildCount(); ++i) {
- TreeItem *treeItem = m_samplerNode->child(i);
- if (treeItem->getName() == "sampleCount") {
- treeItem->setValue(sampleCount);
- } else if (treeItem->getName() == "resolution") {
- treeItem->setValue((int) std::sqrt((Float) sampleCount));
- }
- }
- }
-
if (sender() == ui->integratorBox) {
for (int i=0; ichildCount(); ++i) {
TreeItem *treeItem = m_integratorNode->child(i);
@@ -243,6 +224,14 @@ void RenderSettingsDialog::update() {
m_integratorNode->setProperty(treeItem->getName().toStdString(), integratorProps);
}
}
+
+ if (sender() == ui->samplerBox) {
+ for (int i=0; ichildCount(); ++i) {
+ TreeItem *treeItem = m_samplerNode->child(i);
+ if (samplerProps.hasProperty(treeItem->getName().toStdString()))
+ m_samplerNode->setProperty(treeItem->getName().toStdString(), samplerProps);
+ }
+ }
ui->treeView->expandAll();
dataChanged();
diff --git a/src/qtgui/resources/docs.xml b/src/qtgui/resources/docs.xml
index 2673ae37..d503b2fc 100644
--- a/src/qtgui/resources/docs.xml
+++ b/src/qtgui/resources/docs.xml
@@ -1044,19 +1044,16 @@
- Independent sample generator - returns independent uniformly distributed random numbers on [0,1) and [0, 1)x[0, 1).
- Number of generated samples / samples per pixel.
+ Independent sample generator - computes independent uniformly distributed random numbers without any kind of stratification.
+ Number of samples per pixel
-
- Stratified sample generator. Given a resolution R and a depth D, it
- generates R*R samples, each of which can be queried for up to D 1-
- or 2-dimensional vectors by an integrator. The returned 1D/2D-vectors of a particular depth
- have the property of being stratified over all R*R samples. When
- the maximum depth is exceeded, this implementation reverts to independent sampling.
+ Stratified sample generator - computes stratified samples in 1 and 2 dimensions.
+ This only works up to a specified maximum depth, after which
+ the implementation falls back to independent sampling.
- Stratification resolution of the sample space. The default results in 2x2=4 samples per pixel
+ Number of samples per pixel (will be rounded up to the next perfect square)
Depth, up to which which stratified samples are guaranteed to be available.
@@ -1066,7 +1063,7 @@
Provides samples up to a specified depth, after which independent
sampling takes over.
- Number of generated samples / samples per pixel
+ Number of samples per pixel (will be rounded up to the next power of two)
Depth, up to which which low discrepancy samples are guaranteed to be available.
diff --git a/src/qtgui/sceneinfodlg.ui b/src/qtgui/sceneinfodlg.ui
index 7b43bbac..f94de6a3 100644
--- a/src/qtgui/sceneinfodlg.ui
+++ b/src/qtgui/sceneinfodlg.ui
@@ -49,6 +49,9 @@
8
+
+ QTextEdit::NoWrap
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
diff --git a/src/samplers/independent.cpp b/src/samplers/independent.cpp
index d5345627..710e5694 100644
--- a/src/samplers/independent.cpp
+++ b/src/samplers/independent.cpp
@@ -31,7 +31,7 @@ public:
IndependentSampler(const Properties &props) : Sampler(props) {
/* Number of samples per pixel when used with a sampling-based integrator */
- m_sampleCount = props.getSize("sampleCount", 1);
+ m_sampleCount = props.getSize("sampleCount", 4);
m_random = new Random();
}
diff --git a/src/samplers/ldsampler.cpp b/src/samplers/ldsampler.cpp
index 7837d40e..2fbc495f 100644
--- a/src/samplers/ldsampler.cpp
+++ b/src/samplers/ldsampler.cpp
@@ -27,8 +27,7 @@ MTS_NAMESPACE_BEGIN
*/
class LowDiscrepancySampler : public Sampler {
public:
- LowDiscrepancySampler() : Sampler(Properties()) {
- }
+ LowDiscrepancySampler() : Sampler(Properties()) { }
LowDiscrepancySampler(Stream *stream, InstanceManager *manager)
: Sampler(stream, manager) {
@@ -44,23 +43,24 @@ public:
}
LowDiscrepancySampler(const Properties &props) : Sampler(props) {
- /* Number of samples per pixel when used with a sampling-based integrator */
+ /* Sample count (will be rounded up to the next power of two) */
m_sampleCount = props.getSize("sampleCount", 4);
/* Depth, up to which which low discrepancy samples are guaranteed to be available. */
m_depth = props.getInteger("depth", 3);
- if (!isPowerOfTwo((int) m_sampleCount)) {
- m_sampleCount = roundToPowerOfTwo((int) m_sampleCount);
- Log(EWarn, "Sample count should be a power of two - rounding to %i", m_sampleCount);
+ if (!isPowerOfTwo((uint64_t) m_sampleCount)) {
+ m_sampleCount = (size_t) roundToPowerOfTwo((uint64_t) m_sampleCount);
+ Log(EWarn, "Sample count should be a power of two -- rounding to "
+ SIZE_T_FMT, m_sampleCount);
}
m_samples1D = new Float*[m_depth];
m_samples2D = new Point2*[m_depth];
for (int i=0; im_samples1D = new Float*[m_depth];
sampler->m_samples2D = new Point2*[m_depth];
for (int i=0; im_samples1D[i] = new Float[(size_t) m_sampleCount];
- sampler->m_samples2D[i] = new Point2[(size_t) m_sampleCount];
+ sampler->m_samples1D[i] = new Float[m_sampleCount];
+ sampler->m_samples2D[i] = new Point2[m_sampleCount];
}
for (size_t i=0; irequest2DArray(m_req1D[i]);
diff --git a/src/samplers/stratified.cpp b/src/samplers/stratified.cpp
index f830187e..3bb9e081 100644
--- a/src/samplers/stratified.cpp
+++ b/src/samplers/stratified.cpp
@@ -34,20 +34,31 @@ public:
}
StratifiedSampler(const Properties &props) : Sampler(props) {
- /* Stratification resolution of the sample space. Default: 2,
- resulting in 2x2=4 samples per pixel */
- m_resolution = props.getInteger("resolution", 2);
+ /* Sample count (will be rounded up to the next perfect square) */
+ size_t desiredSampleCount = props.getSize("sampleCount", 4);
+
+ size_t i = 1;
+ while (i * i < desiredSampleCount)
+ ++i;
+ m_sampleCount = i*i;
+
+ if (m_sampleCount != desiredSampleCount) {
+ Log(EWarn, "Sample count should be a perfect square -- rounding to "
+ SIZE_T_FMT, m_sampleCount);
+ }
+
+ m_resolution = (int) i;
/* Depth, up to which which stratified samples are guaranteed to be available. */
m_depth = props.getInteger("depth", 3);
m_sampleCount = m_resolution*m_resolution;
- m_permutations1D = new unsigned int*[m_depth];
- m_permutations2D = new unsigned int*[m_depth];
+ m_permutations1D = new uint32_t*[m_depth];
+ m_permutations2D = new uint32_t*[m_depth];
for (int i=0; ireadInt();
m_resolution = stream->readInt();
m_random = static_cast(manager->getInstance(stream));
- m_permutations1D = new unsigned int*[m_depth];
- m_permutations2D = new unsigned int*[m_depth];
+ m_permutations1D = new uint32_t*[m_depth];
+ m_permutations2D = new uint32_t*[m_depth];
for (int i=0; im_invResolutionSquare = m_invResolutionSquare;
sampler->m_random = new Random(m_random);
- sampler->m_permutations1D = new unsigned int*[m_depth];
- sampler->m_permutations2D = new unsigned int*[m_depth];
+ sampler->m_permutations1D = new uint32_t*[m_depth];
+ sampler->m_permutations2D = new uint32_t*[m_depth];
for (int i=0; im_permutations1D[i] = new unsigned int[m_sampleCount];
- sampler->m_permutations2D[i] = new unsigned int[m_sampleCount];
+ sampler->m_permutations1D[i] = new uint32_t[m_sampleCount];
+ sampler->m_permutations2D[i] = new uint32_t[m_sampleCount];
}
for (size_t i=0; irequest2DArray(m_req1D[i]);
@@ -112,11 +123,11 @@ public:
void generate() {
for (int i=0; ishuffle(&m_permutations1D[i][0], &m_permutations1D[i][m_sampleCount]);
for (size_t j=0; jshuffle(&m_permutations2D[i][0], &m_permutations2D[i][m_sampleCount]);
}
@@ -200,7 +211,7 @@ private:
int m_resolution;
int m_depth;
Float m_invResolution, m_invResolutionSquare;
- unsigned int **m_permutations1D, **m_permutations2D;
+ uint32_t **m_permutations1D, **m_permutations2D;
int m_sampleDepth1D, m_sampleDepth2D;
};
diff --git a/src/shapes/serialized.cpp b/src/shapes/serialized.cpp
index 206b50f5..f3ad8eba 100644
--- a/src/shapes/serialized.cpp
+++ b/src/shapes/serialized.cpp
@@ -38,7 +38,8 @@ public:
/// When the file contains multiple meshes, this index specifies which one to load
int shapeIndex = props.getInteger("shapeIndex", 0);
- m_name = (props.getID() != "unnamed") ? props.getID() : formatString("%s@%i", filePath.stem().c_str(), shapeIndex);
+ m_name = (props.getID() != "unnamed") ? props.getID()
+ : formatString("%s@%i", filePath.stem().c_str(), shapeIndex);
/* Load the geometry */
Log(EInfo, "Loading shape %i from \"%s\" ..", shapeIndex, filePath.leaf().c_str());