better medium integration + a two-sided BRDF adapter

metadata
Wenzel Jakob 2011-03-29 23:47:20 +02:00
parent cd6d3f8a65
commit 77bcff3550
20 changed files with 367 additions and 116 deletions

View File

@ -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()

View File

@ -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<shape id="Exterior-mesh_0" type="serialized">\n')
self.out.write('\t\t\t<string name="filename" value="matpreview.serialized"/>\n')
self.out.write('\t\t\t<integer name="shapeIndex" value="1"/>\n')
self.out.write('\t\t\t<transform name="toWorld">\n')
self.out.write('\t\t\t\t<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"/>\n')
self.out.write('\t\t\t</transform>\n')
self.out.write('\t\t\t<ref id="%s-material" name="bsdf"/>\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<luminaire type="area">\n')
self.out.write('\t\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
% (lamp.color.r*mult, lamp.color.g*mult, lamp.color.b*mult))
self.out.write('\t\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.samplingWeight)
self.out.write('\t\t\t</luminaire>\n')
self.out.write('\t\t</shape>\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<prepend id="%s-camera">\n' % translate_id(camera.name))
self.out.write('\t\t<float name="shutterOpen" value="%f"/>\n' % shutterOpen)
self.out.write('\t\t<float name="shutterClose" value="%f"/>\n' % shutterClose)
self.out.write('\t</prepend>\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]

View File

@ -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);
}

View File

@ -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);

View File

@ -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) */

View File

@ -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)) {

View File

@ -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')

193
src/bsdfs/twosided.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/hw/gpuprogram.h>
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<BSDF *>(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; i<m_nestedBRDF->getComponentCount(); ++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<BSDF *>(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<BSDF> 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<Shader *> &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<std::string> &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<Shader> 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

View File

@ -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!");
}

View File

@ -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

View File

@ -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];

View File

@ -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;
}

View File

@ -470,7 +470,7 @@
</action>
<action name="actionSceneDescription">
<property name="text">
<string>Describe Scene..</string>
<string>Scene Information ..</string>
</property>
</action>
</widget>

View File

@ -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; i<m_samplerNode->childCount(); ++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; i<m_integratorNode->childCount(); ++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; i<m_samplerNode->childCount(); ++i) {
TreeItem *treeItem = m_samplerNode->child(i);
if (samplerProps.hasProperty(treeItem->getName().toStdString()))
m_samplerNode->setProperty(treeItem->getName().toStdString(), samplerProps);
}
}
ui->treeView->expandAll();
dataChanged();

View File

@ -1044,19 +1044,16 @@
</plugin>
<plugin type="sampler" name="independent" readableName="Independent sampler" show="true" className="IndependentSampler" extends="Sampler">
<descr>Independent sample generator - returns independent uniformly distributed random numbers on <tt>[0,1)</tt> and <tt>[0, 1)x[0, 1)</tt>.</descr>
<param name="sampleCount" readableName="Samples per pixel" type="integer" default="1">Number of generated samples / samples per pixel.</param>
<descr>Independent sample generator - computes independent uniformly distributed random numbers without any kind of stratification.</descr>
<param name="sampleCount" readableName="Samples per pixel" type="integer" default="4">Number of samples per pixel</param>
</plugin>
<plugin type="sampler" name="stratified" readableName="Stratified sampler" show="true" className="StratifiedSampler" extends="Sampler">
<descr>
Stratified sample generator. Given a resolution <tt>R</tt> and a depth <tt>D</tt>, it
generates <tt>R*R</tt> samples, each of which can be queried for up to <tt>D</tt> 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 <tt>R*R</tt> samples. When
the maximum depth is exceeded, this implementation reverts to independent sampling.
<descr>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.
</descr>
<param name="resolution" readableName="Stratification resolution" type="integer" default="2">Stratification resolution of the sample space. The default results in 2x2=4 samples per pixel</param>
<param name="sampleCount" readableName="Samples per pixel" type="integer" default="4">Number of samples per pixel (will be rounded up to the next perfect square)</param>
<param name="depth" readableName="Stratification depth" type="integer" default="3">Depth, up to which which stratified samples are guaranteed to be available.</param>
</plugin>
@ -1066,7 +1063,7 @@
Provides samples up to a specified depth, after which independent
sampling takes over.
</descr>
<param name="sampleCount" readableName="Samples per pixel" type="integer" default="4">Number of generated samples / samples per pixel</param>
<param name="sampleCount" readableName="Samples per pixel" type="integer" default="4">Number of samples per pixel (will be rounded up to the next power of two)</param>
<param name="depth" readableName="Depth" type="integer" default="3">Depth, up to which which low discrepancy samples are guaranteed to be available.</param>
</plugin>

View File

@ -49,6 +49,9 @@
<pointsize>8</pointsize>
</font>
</property>
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;

View File

@ -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();
}

View File

@ -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; i<m_depth; i++) {
m_samples1D[i] = new Float[(size_t) m_sampleCount];
m_samples2D[i] = new Point2[(size_t) m_sampleCount];
m_samples1D[i] = new Float[m_sampleCount];
m_samples2D[i] = new Point2[m_sampleCount];
}
m_random = new Random();
@ -90,8 +90,8 @@ public:
sampler->m_samples1D = new Float*[m_depth];
sampler->m_samples2D = new Point2*[m_depth];
for (int i=0; i<m_depth; i++) {
sampler->m_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; i<m_req1D.size(); ++i)
sampler->request2DArray(m_req1D[i]);

View File

@ -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; i<m_depth; i++) {
m_permutations1D[i] = new unsigned int[m_sampleCount];
m_permutations2D[i] = new unsigned int[m_sampleCount];
m_permutations1D[i] = new uint32_t[m_sampleCount];
m_permutations2D[i] = new uint32_t[m_sampleCount];
}
m_invResolution = 1 / (Float) m_resolution;
@ -60,11 +71,11 @@ public:
m_depth = stream->readInt();
m_resolution = stream->readInt();
m_random = static_cast<Random *>(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; i<m_depth; i++) {
m_permutations1D[i] = new unsigned int[m_sampleCount];
m_permutations2D[i] = new unsigned int[m_sampleCount];
m_permutations1D[i] = new uint32_t[m_sampleCount];
m_permutations2D[i] = new uint32_t[m_sampleCount];
}
m_invResolution = 1.0f / m_resolution;
m_invResolutionSquare = 1.0f / m_sampleCount;
@ -96,11 +107,11 @@ public:
sampler->m_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; i<m_depth; i++) {
sampler->m_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; i<m_req1D.size(); ++i)
sampler->request2DArray(m_req1D[i]);
@ -112,11 +123,11 @@ public:
void generate() {
for (int i=0; i<m_depth; i++) {
for (size_t j=0; j<m_sampleCount; j++)
m_permutations1D[i][j] = (unsigned int) j;
m_permutations1D[i][j] = (uint32_t) j;
m_random->shuffle(&m_permutations1D[i][0], &m_permutations1D[i][m_sampleCount]);
for (size_t j=0; j<m_sampleCount; j++)
m_permutations2D[i][j] = (unsigned int) j;
m_permutations2D[i][j] = (uint32_t) j;
m_random->shuffle(&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;
};

View File

@ -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());