testcase support -- see 'test_samplers.cpp' for an example
parent
e0b52ef022
commit
1c60e7368d
28
SConstruct
28
SConstruct
|
@ -277,6 +277,12 @@ env.Append(LIBPATH=['src/libcore'])
|
||||||
# Rendering-specific library
|
# Rendering-specific library
|
||||||
renderEnv = env.Clone()
|
renderEnv = env.Clone()
|
||||||
renderEnv.Append(CPPDEFINES = {'MTS_BUILD_MODULE' : 'MTS_MODULE_RENDER'} )
|
renderEnv.Append(CPPDEFINES = {'MTS_BUILD_MODULE' : 'MTS_MODULE_RENDER'} )
|
||||||
|
if renderEnv.has_key('XERCESINCLUDE'):
|
||||||
|
renderEnv.Append(CPPPATH=renderEnv['XERCESINCLUDE'])
|
||||||
|
if renderEnv.has_key('XERCESLIBDIR'):
|
||||||
|
renderEnv.Append(LIBPATH=renderEnv['XERCESLIBDIR'])
|
||||||
|
if renderEnv.has_key('XERCESLIB'):
|
||||||
|
renderEnv.Append(LIBS=renderEnv['XERCESLIB'])
|
||||||
librender = renderEnv.SharedLibrary('src/librender/mitsuba-render', [
|
librender = renderEnv.SharedLibrary('src/librender/mitsuba-render', [
|
||||||
'src/librender/bsdf.cpp', 'src/librender/camera.cpp',
|
'src/librender/bsdf.cpp', 'src/librender/camera.cpp',
|
||||||
'src/librender/film.cpp', 'src/librender/integrator.cpp',
|
'src/librender/film.cpp', 'src/librender/integrator.cpp',
|
||||||
|
@ -295,7 +301,8 @@ librender = renderEnv.SharedLibrary('src/librender/mitsuba-render', [
|
||||||
'src/librender/preview.cpp', 'src/librender/photonmap.cpp',
|
'src/librender/preview.cpp', 'src/librender/photonmap.cpp',
|
||||||
'src/librender/gatherproc.cpp', 'src/librender/mipmap3d.cpp',
|
'src/librender/gatherproc.cpp', 'src/librender/mipmap3d.cpp',
|
||||||
'src/librender/volume.cpp', 'src/librender/vpl.cpp',
|
'src/librender/volume.cpp', 'src/librender/vpl.cpp',
|
||||||
'src/librender/shader.cpp'
|
'src/librender/shader.cpp', 'src/librender/shandler.cpp',
|
||||||
|
'src/librender/util.cpp'
|
||||||
])
|
])
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
|
@ -353,12 +360,6 @@ env['SHLIBPREFIX']=''
|
||||||
|
|
||||||
# Environment with Xerces + wxWidgets
|
# Environment with Xerces + wxWidgets
|
||||||
mainEnv = env.Clone()
|
mainEnv = env.Clone()
|
||||||
if mainEnv.has_key('XERCESINCLUDE'):
|
|
||||||
mainEnv.Append(CPPPATH=mainEnv['XERCESINCLUDE'])
|
|
||||||
if mainEnv.has_key('XERCESLIBDIR'):
|
|
||||||
mainEnv.Append(LIBPATH=mainEnv['XERCESLIBDIR'])
|
|
||||||
if mainEnv.has_key('XERCESLIB'):
|
|
||||||
mainEnv.Append(LIBS=mainEnv['XERCESLIB'])
|
|
||||||
if mainEnv.has_key('GLLIB'):
|
if mainEnv.has_key('GLLIB'):
|
||||||
mainEnv.Append(LIBS=mainEnv['GLLIB'])
|
mainEnv.Append(LIBS=mainEnv['GLLIB'])
|
||||||
if mainEnv.has_key('GLLIBDIR'):
|
if mainEnv.has_key('GLLIBDIR'):
|
||||||
|
@ -374,12 +375,11 @@ darwinStub = []
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
resources += [env.RES('tools/windows/mitsuba_res.rc'),
|
resources += [env.RES('tools/windows/mitsuba_res.rc'),
|
||||||
env.StaticObject('src/mitsuba/getopt.c')]
|
env.StaticObject('src/mitsuba/getopt.c')]
|
||||||
shandler = mainEnv.StaticObject('src/mitsuba/shandler.cpp')
|
|
||||||
|
|
||||||
# Build the command-line+GUI interface
|
# Build the command-line+GUI interface
|
||||||
mainEnv.Program('mtssrv', resources + ['src/mitsuba/mtssrv.cpp'])
|
mainEnv.Program('mtssrv', resources + ['src/mitsuba/mtssrv.cpp'])
|
||||||
mainEnv.Program('mitsuba', resources + ['src/mitsuba/mitsuba.cpp', shandler])
|
mainEnv.Program('mitsuba', resources + ['src/mitsuba/mitsuba.cpp'])
|
||||||
mainEnv.Program('mtsutil', resources + ['src/mitsuba/mtsutil.cpp', shandler])
|
mainEnv.Program('mtsutil', resources + ['src/mitsuba/mtsutil.cpp'])
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
mainEnv_osx = mainEnv.Clone();
|
mainEnv_osx = mainEnv.Clone();
|
||||||
|
@ -388,7 +388,6 @@ if sys.platform == 'darwin':
|
||||||
mainEnv_osx['CXXFLAGS'].append('-fno-strict-aliasing');
|
mainEnv_osx['CXXFLAGS'].append('-fno-strict-aliasing');
|
||||||
darwinStub += [mainEnv_osx.StaticObject('src/mitsuba/darwin_stub.mm')]
|
darwinStub += [mainEnv_osx.StaticObject('src/mitsuba/darwin_stub.mm')]
|
||||||
|
|
||||||
env.Program('src/utils/utils_test', ['src/utils/utils_test.cpp'])
|
|
||||||
env.Program('src/utils/joinrgb', ['src/utils/joinrgb.cpp'])
|
env.Program('src/utils/joinrgb', ['src/utils/joinrgb.cpp'])
|
||||||
env.Program('src/utils/ttest', ['src/utils/ttest.cpp'])
|
env.Program('src/utils/ttest', ['src/utils/ttest.cpp'])
|
||||||
env.Program('src/utils/createvol', ['src/utils/createvol.cpp'])
|
env.Program('src/utils/createvol', ['src/utils/createvol.cpp'])
|
||||||
|
@ -433,7 +432,7 @@ if hasQt:
|
||||||
qtInterfaces = [qtEnv.Uic4(uic) for uic in scanFiles('src/qtgui', ['*.ui'])]
|
qtInterfaces = [qtEnv.Uic4(uic) for uic in scanFiles('src/qtgui', ['*.ui'])]
|
||||||
qtResources = [qtEnv.Qrc(qrc) for qrc in scanFiles('src/qtgui', ['*.qrc'])]
|
qtResources = [qtEnv.Qrc(qrc) for qrc in scanFiles('src/qtgui', ['*.qrc'])]
|
||||||
|
|
||||||
qtgui_files = scanFiles('src/qtgui', ['*.cpp']) + qtResources + shandler + resources
|
qtgui_files = scanFiles('src/qtgui', ['*.cpp']) + qtResources + resources
|
||||||
|
|
||||||
if hasCollada:
|
if hasCollada:
|
||||||
qtgui_files += converter_objects
|
qtgui_files += converter_objects
|
||||||
|
@ -599,6 +598,11 @@ plugins += env.SharedLibrary('plugins/vpl', ['src/integrators/vpl/vpl.cpp'])
|
||||||
# pathvertex_mlt, path_mlt
|
# pathvertex_mlt, path_mlt
|
||||||
#])
|
#])
|
||||||
|
|
||||||
|
# Testcases
|
||||||
|
for plugin in glob.glob('src/tests/test_*.cpp'):
|
||||||
|
name = os.path.basename(plugin)
|
||||||
|
plugins += env.SharedLibrary('plugins/' + name[0:len(name)-4], plugin)
|
||||||
|
|
||||||
installTargets = []
|
installTargets = []
|
||||||
|
|
||||||
# Windows build?
|
# Windows build?
|
||||||
|
|
|
@ -36,17 +36,14 @@ MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class ROT13Encoder : public Utility {
|
class ROT13Encoder : public Utility {
|
||||||
public:
|
public:
|
||||||
ROT13Encoder(UtilityServices *us) : Utility(us) { }
|
|
||||||
|
|
||||||
int run(int argc, char **argv) {
|
int run(int argc, char **argv) {
|
||||||
cout << "Hello world!" << endl;
|
cout << "Hello world!" << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_UTILITY()
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS(ROT13Encoder, false, Utility)
|
|
||||||
MTS_EXPORT_UTILITY(ROT13Encoder, "Perform a ROT13 encryption of a string")
|
MTS_EXPORT_UTILITY(ROT13Encoder, "Perform a ROT13 encryption of a string")
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
\end{cpp}
|
\end{cpp}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class Utility;
|
class Utility;
|
||||||
class UtilityServices;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract plugin class -- can represent loadable configurable objects
|
* Abstract plugin class -- can represent loadable configurable objects
|
||||||
|
@ -15,7 +14,7 @@ class UtilityServices;
|
||||||
*/
|
*/
|
||||||
class MTS_EXPORT_CORE Plugin {
|
class MTS_EXPORT_CORE Plugin {
|
||||||
typedef void *(*CreateInstanceFunc)(const Properties &props);
|
typedef void *(*CreateInstanceFunc)(const Properties &props);
|
||||||
typedef void *(*CreateUtilityFunc)(UtilityServices *us);
|
typedef void *(*CreateUtilityFunc)();
|
||||||
typedef char *(*GetDescriptionFunc)();
|
typedef char *(*GetDescriptionFunc)();
|
||||||
public:
|
public:
|
||||||
/// Load a plugin from the supplied path
|
/// Load a plugin from the supplied path
|
||||||
|
@ -31,7 +30,7 @@ public:
|
||||||
ConfigurableObject *createInstance(const Properties &props) const;
|
ConfigurableObject *createInstance(const Properties &props) const;
|
||||||
|
|
||||||
/// Return an utility instance (if this is an utility plugin)
|
/// Return an utility instance (if this is an utility plugin)
|
||||||
Utility *createUtility(UtilityServices *us) const;
|
Utility *createUtility() const;
|
||||||
|
|
||||||
/// Return a description of this plugin
|
/// Return a description of this plugin
|
||||||
std::string getDescription() const;
|
std::string getDescription() const;
|
||||||
|
|
|
@ -36,6 +36,9 @@ extern MTS_EXPORT_CORE std::string toUpperCase(const std::string &string);
|
||||||
/// Trim spaces (' ', '\n', '\r', '\t') from the ends of a string
|
/// Trim spaces (' ', '\n', '\r', '\t') from the ends of a string
|
||||||
extern MTS_EXPORT_CORE std::string trim(const std::string& str);
|
extern MTS_EXPORT_CORE std::string trim(const std::string& str);
|
||||||
|
|
||||||
|
/// Determines whether a string starts with the string given as second parameter
|
||||||
|
extern MTS_EXPORT_CORE bool startsWith(const std::string& str, const std::string& start);
|
||||||
|
|
||||||
/// Determines whether a string ends with the string given as second parameter
|
/// Determines whether a string ends with the string given as second parameter
|
||||||
extern MTS_EXPORT_CORE bool endsWith(const std::string& str, const std::string& end);
|
extern MTS_EXPORT_CORE bool endsWith(const std::string& str, const std::string& end);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
XERCES_CPP_NAMESPACE_USE
|
XERCES_CPP_NAMESPACE_USE
|
||||||
using namespace mitsuba;
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XML parser for mitsuba scene files. Uses Xerces-C and SAX
|
* XML parser for mitsuba scene files. Uses Xerces-C and SAX
|
||||||
|
@ -72,4 +72,6 @@ private:
|
||||||
bool m_isIncludedFile;
|
bool m_isIncludedFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MTS_NAMESPACE_END
|
||||||
|
|
||||||
#endif /* __SHANDLER_H */
|
#endif /* __SHANDLER_H */
|
|
@ -1,10 +1,45 @@
|
||||||
#if !defined(__TESTCASE_H)
|
#if !defined(__TESTCASE_H)
|
||||||
#define __TESTCASE_H
|
#define __TESTCASE_H
|
||||||
|
|
||||||
#include <mitsuba/mitsuba.h>
|
#include <mitsuba/render/util.h>
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/** \brief Base class of all testcases. Implementations of this
|
||||||
|
* interface can be executed using the 'mtsutil' command. The execution
|
||||||
|
* order is as follows: after initializaiton using init(), any tests
|
||||||
|
* declared using the MTS_DECLARE_TEST() macro are executed. Finally,
|
||||||
|
* the shutdown() method is called. See the files in 'mitsuba/src/tests'
|
||||||
|
* for examples.
|
||||||
|
*/
|
||||||
|
class MTS_EXPORT_RENDER TestCase : public Utility {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Perform any required initializations. The default
|
||||||
|
* implementation simply returns
|
||||||
|
*/
|
||||||
|
virtual void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute any required shutdown code. The default
|
||||||
|
* implementation simply returns
|
||||||
|
*/
|
||||||
|
virtual void shutdown();
|
||||||
|
|
||||||
|
/// Return the number of executed testcases
|
||||||
|
inline int getExecuted() const { return m_executed; }
|
||||||
|
|
||||||
|
/// Return the number of successfully executed testcases
|
||||||
|
inline int getSucceeded() const { return m_succeeded; }
|
||||||
|
|
||||||
|
MTS_DECLARE_CLASS()
|
||||||
|
protected:
|
||||||
|
/// Virtual destructor
|
||||||
|
virtual ~TestCase() { }
|
||||||
|
protected:
|
||||||
|
int m_executed, m_succeeded;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The test supervisor is used when rendering a collection of testcases in the
|
* The test supervisor is used when rendering a collection of testcases in the
|
||||||
* form of scenes with analytic solutions. Reference output is compared against
|
* form of scenes with analytic solutions. Reference output is compared against
|
||||||
|
@ -40,4 +75,40 @@ private:
|
||||||
|
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
||||||
|
#define EXECUTE_GUARDED(name) \
|
||||||
|
try { \
|
||||||
|
Log(EInfo, "Executing test \"%s\" ..", #name); \
|
||||||
|
m_executed++;\
|
||||||
|
name();\
|
||||||
|
m_succeeded++;\
|
||||||
|
} catch (std::exception &e) {\
|
||||||
|
Log(EInfo, "Testcase failed with error: %s", e.what());\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MTS_BEGIN_TESTCASE() \
|
||||||
|
MTS_DECLARE_CLASS() \
|
||||||
|
int run(int argc, char **argv) {\
|
||||||
|
init(); \
|
||||||
|
Log(EInfo, "Executing testcase \"%s\" ..", getClass()->getName().c_str()); \
|
||||||
|
m_executed = m_succeeded = 0;
|
||||||
|
|
||||||
|
#define MTS_DECLARE_TEST(name) \
|
||||||
|
EXECUTE_GUARDED(name)
|
||||||
|
|
||||||
|
#define MTS_END_TESTCASE()\
|
||||||
|
shutdown();\
|
||||||
|
return 0;\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MTS_EXPORT_TESTCASE(name, descr) \
|
||||||
|
MTS_IMPLEMENT_CLASS(name, false, TestCase) \
|
||||||
|
extern "C" { \
|
||||||
|
void MTS_EXPORT *CreateUtility() { \
|
||||||
|
return new name(); \
|
||||||
|
} \
|
||||||
|
const char MTS_EXPORT *GetDescription() { \
|
||||||
|
return descr; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __TESTCASE_H */
|
#endif /* __TESTCASE_H */
|
||||||
|
|
|
@ -5,24 +5,12 @@
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains functionality provided to utility plugins,
|
|
||||||
* such as loading a scene from an XML file.
|
|
||||||
*/
|
|
||||||
class MTS_EXPORT_RENDER UtilityServices {
|
|
||||||
public:
|
|
||||||
virtual ref<Scene> loadScene(const std::string &filename) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief Abstract utility class -- can be used to implement
|
/** \brief Abstract utility class -- can be used to implement
|
||||||
* loadable utility plugins that perform various actions. They
|
* loadable utility plugins that perform various actions. They
|
||||||
* can be started using the 'mtsutil' launcher.
|
* can be started using the 'mtsutil' launcher.
|
||||||
*/
|
*/
|
||||||
class MTS_EXPORT_RENDER Utility : public Object {
|
class MTS_EXPORT_RENDER Utility : public Object {
|
||||||
public:
|
public:
|
||||||
inline Utility(UtilityServices *services)
|
|
||||||
: m_utilityServices(services) { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the utility. The supplied <tt>argc</tt>
|
* Run the utility. The supplied <tt>argc</tt>
|
||||||
* and <tt>argv</tt> parameters contain any
|
* and <tt>argv</tt> parameters contain any
|
||||||
|
@ -38,17 +26,17 @@ protected:
|
||||||
virtual ~Utility() { }
|
virtual ~Utility() { }
|
||||||
|
|
||||||
/// Load a scene
|
/// Load a scene
|
||||||
inline ref<Scene> loadScene(const std::string &fname) {
|
ref<Scene> loadScene(const std::string &fname);
|
||||||
return m_utilityServices->loadScene(fname);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
UtilityServices *m_utilityServices;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MTS_DECLARE_UTILITY() \
|
||||||
|
MTS_DECLARE_CLASS()
|
||||||
|
|
||||||
#define MTS_EXPORT_UTILITY(name, descr) \
|
#define MTS_EXPORT_UTILITY(name, descr) \
|
||||||
|
MTS_IMPLEMENT_CLASS(name, false, Utility) \
|
||||||
extern "C" { \
|
extern "C" { \
|
||||||
void MTS_EXPORT *CreateUtility(UtilityServices *us) { \
|
void MTS_EXPORT *CreateUtility() { \
|
||||||
return new name(us); \
|
return new name(); \
|
||||||
} \
|
} \
|
||||||
const char MTS_EXPORT *GetDescription() { \
|
const char MTS_EXPORT *GetDescription() { \
|
||||||
return descr; \
|
return descr; \
|
||||||
|
|
|
@ -76,8 +76,8 @@ ConfigurableObject *Plugin::createInstance(const Properties &props) const {
|
||||||
return (ConfigurableObject *) m_createInstance(props);
|
return (ConfigurableObject *) m_createInstance(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utility *Plugin::createUtility(UtilityServices *us) const {
|
Utility *Plugin::createUtility() const {
|
||||||
return (Utility *) m_createUtility(us);
|
return (Utility *) m_createUtility();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Plugin::getDescription() const {
|
std::string Plugin::getDescription() const {
|
||||||
|
|
|
@ -177,6 +177,10 @@ bool endsWith(const std::string& str, const std::string& end) {
|
||||||
return (pos == str.size() - end.size()) && str.length() >= end.length();
|
return (pos == str.size() - end.size()) && str.length() >= end.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool startsWith(const std::string& str, const std::string& start) {
|
||||||
|
return str.find(start) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void * __restrict allocAligned(size_t size) {
|
void * __restrict allocAligned(size_t size) {
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
return _aligned_malloc(size, L1_CACHE_LINE_SIZE);
|
return _aligned_malloc(size, L1_CACHE_LINE_SIZE);
|
||||||
|
|
|
@ -635,5 +635,4 @@ std::string Scene::toString() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(Scene, false, ConfigurableObject)
|
MTS_IMPLEMENT_CLASS_S(Scene, false, ConfigurableObject)
|
||||||
MTS_IMPLEMENT_CLASS(Utility, true, Object)
|
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include <mitsuba/core/platform.h>
|
#include <mitsuba/core/platform.h>
|
||||||
#include <xercesc/parsers/SAXParser.hpp>
|
#include <xercesc/parsers/SAXParser.hpp>
|
||||||
#include "shandler.h"
|
#include <mitsuba/render/shandler.h>
|
||||||
|
|
||||||
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
SceneHandler::SceneHandler() : m_isIncludedFile(false) {
|
SceneHandler::SceneHandler() : m_isIncludedFile(false) {
|
||||||
m_pluginManager = PluginManager::getInstance();
|
m_pluginManager = PluginManager::getInstance();
|
||||||
|
@ -399,3 +401,4 @@ void SceneHandler::fatalError(const SAXParseException& e) {
|
||||||
transcode(e.getMessage()).c_str());
|
transcode(e.getMessage()).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MTS_NAMESPACE_END
|
|
@ -5,6 +5,9 @@
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
void TestCase::init() { }
|
||||||
|
void TestCase::shutdown() { }
|
||||||
|
|
||||||
struct Sample {
|
struct Sample {
|
||||||
Float value;
|
Float value;
|
||||||
Float variance;
|
Float variance;
|
||||||
|
@ -169,4 +172,5 @@ void TestSupervisor::printSummary() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS(TestSupervisor, false, Object)
|
MTS_IMPLEMENT_CLASS(TestSupervisor, false, Object)
|
||||||
|
MTS_IMPLEMENT_CLASS(TestCase, false, Utility)
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <mitsuba/core/platform.h>
|
||||||
|
#include <xercesc/parsers/SAXParser.hpp>
|
||||||
|
#include <mitsuba/render/util.h>
|
||||||
|
#include <mitsuba/render/shandler.h>
|
||||||
|
|
||||||
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
ref<Scene> Utility::loadScene(const std::string &filename) {
|
||||||
|
/* Prepare for parsing scene descriptions */
|
||||||
|
FileResolver *resolver = FileResolver::getInstance();
|
||||||
|
SAXParser* parser = new SAXParser();
|
||||||
|
std::string schemaPath = resolver->resolveAbsolute("schema/scene.xsd");
|
||||||
|
|
||||||
|
/* Check against the 'scene.xsd' XML Schema */
|
||||||
|
parser->setDoSchema(true);
|
||||||
|
parser->setValidationSchemaFullChecking(true);
|
||||||
|
parser->setValidationScheme(SAXParser::Val_Always);
|
||||||
|
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
|
||||||
|
|
||||||
|
std::map<std::string, std::string> parameters;
|
||||||
|
SceneHandler *handler = new SceneHandler(parameters);
|
||||||
|
parser->setDoNamespaces(true);
|
||||||
|
parser->setDocumentHandler(handler);
|
||||||
|
parser->setErrorHandler(handler);
|
||||||
|
|
||||||
|
parser->parse(filename.c_str());
|
||||||
|
ref<Scene> scene = handler->getScene();
|
||||||
|
|
||||||
|
delete parser;
|
||||||
|
delete handler;
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTS_IMPLEMENT_CLASS(Utility, true, Object)
|
||||||
|
MTS_NAMESPACE_END
|
|
@ -5,9 +5,9 @@
|
||||||
#include <mitsuba/core/sshstream.h>
|
#include <mitsuba/core/sshstream.h>
|
||||||
#include <mitsuba/core/shvector.h>
|
#include <mitsuba/core/shvector.h>
|
||||||
#include <mitsuba/render/renderjob.h>
|
#include <mitsuba/render/renderjob.h>
|
||||||
|
#include <mitsuba/render/shandler.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "shandler.h"
|
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
#include "getopt.h"
|
#include "getopt.h"
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
#include <mitsuba/core/shvector.h>
|
#include <mitsuba/core/shvector.h>
|
||||||
#include <mitsuba/render/util.h>
|
#include <mitsuba/render/util.h>
|
||||||
#include <mitsuba/render/renderjob.h>
|
#include <mitsuba/render/renderjob.h>
|
||||||
|
#include <mitsuba/render/shandler.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "shandler.h"
|
|
||||||
|
|
||||||
#if !defined(WIN32)
|
#if !defined(WIN32)
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
@ -24,36 +24,6 @@
|
||||||
|
|
||||||
using namespace mitsuba;
|
using namespace mitsuba;
|
||||||
|
|
||||||
class UtilityServicesImpl : public UtilityServices {
|
|
||||||
public:
|
|
||||||
ref<Scene> loadScene(const std::string &filename) {
|
|
||||||
/* Prepare for parsing scene descriptions */
|
|
||||||
FileResolver *resolver = FileResolver::getInstance();
|
|
||||||
SAXParser* parser = new SAXParser();
|
|
||||||
std::string schemaPath = resolver->resolveAbsolute("schema/scene.xsd");
|
|
||||||
|
|
||||||
/* Check against the 'scene.xsd' XML Schema */
|
|
||||||
parser->setDoSchema(true);
|
|
||||||
parser->setValidationSchemaFullChecking(true);
|
|
||||||
parser->setValidationScheme(SAXParser::Val_Always);
|
|
||||||
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
|
|
||||||
|
|
||||||
std::map<std::string, std::string> parameters;
|
|
||||||
SceneHandler *handler = new SceneHandler(parameters);
|
|
||||||
parser->setDoNamespaces(true);
|
|
||||||
parser->setDocumentHandler(handler);
|
|
||||||
parser->setErrorHandler(handler);
|
|
||||||
|
|
||||||
parser->parse(filename.c_str());
|
|
||||||
ref<Scene> scene = handler->getScene();
|
|
||||||
|
|
||||||
delete parser;
|
|
||||||
delete handler;
|
|
||||||
|
|
||||||
return scene;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void help() {
|
void help() {
|
||||||
cout << "Mitsuba version " MTS_VERSION ", Copyright (c) " MTS_YEAR " Wenzel Jakob" << endl;
|
cout << "Mitsuba version " MTS_VERSION ", Copyright (c) " MTS_YEAR " Wenzel Jakob" << endl;
|
||||||
cout << "Usage: mtsutil [mtsutil options] <utility name> [arguments]" << endl;
|
cout << "Usage: mtsutil [mtsutil options] <utility name> [arguments]" << endl;
|
||||||
|
@ -74,6 +44,7 @@ void help() {
|
||||||
cout << " -s file Connect to additional Mitsuba servers specified in a file" << endl;
|
cout << " -s file Connect to additional Mitsuba servers specified in a file" << endl;
|
||||||
cout << " with one name per line (same format as in -c)" << endl<< endl;
|
cout << " with one name per line (same format as in -c)" << endl<< endl;
|
||||||
cout << " -n name Assign a node name to this instance (Default: host name)" << endl << endl;
|
cout << " -n name Assign a node name to this instance (Default: host name)" << endl << endl;
|
||||||
|
cout << " -t Execute all testcases" << endl << endl;
|
||||||
cout << " -v Be more verbose" << endl << endl;
|
cout << " -v Be more verbose" << endl << endl;
|
||||||
|
|
||||||
FileResolver *resolver = FileResolver::getInstance();
|
FileResolver *resolver = FileResolver::getInstance();
|
||||||
|
@ -140,6 +111,7 @@ int ubi_main(int argc, char **argv) {
|
||||||
bool quietMode = false;
|
bool quietMode = false;
|
||||||
ELogLevel logLevel = EInfo;
|
ELogLevel logLevel = EInfo;
|
||||||
FileResolver *resolver = FileResolver::getInstance();
|
FileResolver *resolver = FileResolver::getInstance();
|
||||||
|
bool testCaseMode = false;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
help();
|
help();
|
||||||
|
@ -148,7 +120,7 @@ int ubi_main(int argc, char **argv) {
|
||||||
|
|
||||||
optind = 1;
|
optind = 1;
|
||||||
/* Parse command-line arguments */
|
/* Parse command-line arguments */
|
||||||
while ((optchar = getopt(argc, argv, "a:c:s:n:p:qhv")) != -1) {
|
while ((optchar = getopt(argc, argv, "a:c:s:n:p:qhvt")) != -1) {
|
||||||
switch (optchar) {
|
switch (optchar) {
|
||||||
case 'a': {
|
case 'a': {
|
||||||
std::vector<std::string> paths = tokenize(optarg, ";");
|
std::vector<std::string> paths = tokenize(optarg, ";");
|
||||||
|
@ -159,6 +131,9 @@ int ubi_main(int argc, char **argv) {
|
||||||
case 'c':
|
case 'c':
|
||||||
networkHosts = networkHosts + std::string(";") + std::string(optarg);
|
networkHosts = networkHosts + std::string(";") + std::string(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
testCaseMode = true;
|
||||||
|
break;
|
||||||
case 's': {
|
case 's': {
|
||||||
std::ifstream is(optarg);
|
std::ifstream is(optarg);
|
||||||
if (is.fail())
|
if (is.fail())
|
||||||
|
@ -261,6 +236,66 @@ int ubi_main(int argc, char **argv) {
|
||||||
|
|
||||||
scheduler->start();
|
scheduler->start();
|
||||||
|
|
||||||
|
if (testCaseMode) {
|
||||||
|
std::vector<std::string> dirPaths = resolver->resolveAllAbsolute("plugins");
|
||||||
|
std::set<std::string> seen;
|
||||||
|
int executed = 0, succeeded = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<dirPaths.size(); ++i) {
|
||||||
|
std::string dirPath = dirPaths[i];
|
||||||
|
|
||||||
|
#if !defined(WIN32)
|
||||||
|
DIR *directory;
|
||||||
|
struct dirent *dirinfo;
|
||||||
|
|
||||||
|
if ((directory = opendir(dirPath.c_str())) == NULL)
|
||||||
|
SLog(EInfo, "Could not open plugin directory");
|
||||||
|
|
||||||
|
while ((dirinfo = readdir(directory)) != NULL) {
|
||||||
|
std::string fname(dirinfo->d_name);
|
||||||
|
if (!endsWith(fname, ".dylib") && !endsWith(fname, ".so"))
|
||||||
|
continue;
|
||||||
|
std::string fullName = dirPath + "/" + fname;
|
||||||
|
#else
|
||||||
|
HANDLE hFind;
|
||||||
|
WIN32_FIND_DATA findFileData;
|
||||||
|
|
||||||
|
if ((hFind = FindFirstFile((dirPath + "\\*.dll").c_str(), &findFileData)) == INVALID_HANDLE_VALUE)
|
||||||
|
SLog(EInfo, "Could not open plugin directory");
|
||||||
|
|
||||||
|
do {
|
||||||
|
std::string fname = findFileData.cFileName;
|
||||||
|
std::string fullName = dirPath + "\\" + fname;
|
||||||
|
#endif
|
||||||
|
std::string shortName = fname.substr(0, strrchr(fname.c_str(), '.') - fname.c_str());
|
||||||
|
if (!startsWith(shortName, "test_") || seen.find(shortName) != seen.end())
|
||||||
|
continue;
|
||||||
|
seen.insert(shortName);
|
||||||
|
Plugin plugin(shortName, fullName);
|
||||||
|
if (!plugin.isUtility())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ref<Utility> utility = plugin.createUtility();
|
||||||
|
|
||||||
|
TestCase *testCase = static_cast<TestCase *>(utility.get());
|
||||||
|
if (!utility->getClass()->derivesFrom(TestCase::m_theClass))
|
||||||
|
SLog(EError, "This is not a test case!");
|
||||||
|
|
||||||
|
if (testCase->run(argc-optind, argv+optind) != 0)
|
||||||
|
SLog(EError, "Testcase unexpectedly returned with a nonzero value.");
|
||||||
|
|
||||||
|
executed += testCase->getExecuted();
|
||||||
|
succeeded += testCase->getSucceeded();
|
||||||
|
#if !defined(WIN32)
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
} while (FindNextFile(hFind, &findFileData));
|
||||||
|
FindClose(hFind);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SLog(EError, "Ran %i tests, %i succeeded, %i failed.", executed, succeeded, executed-succeeded);
|
||||||
|
} else {
|
||||||
if (argc <= optind) {
|
if (argc <= optind) {
|
||||||
std::cerr << "A utility name must be supplied!" << endl;
|
std::cerr << "A utility name must be supplied!" << endl;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -287,10 +322,10 @@ int ubi_main(int argc, char **argv) {
|
||||||
SLog(EError, "This plugin does not implement the 'Utility' interface!");
|
SLog(EError, "This plugin does not implement the 'Utility' interface!");
|
||||||
Statistics::getInstance()->logPlugin(argv[optind], plugin->getDescription());
|
Statistics::getInstance()->logPlugin(argv[optind], plugin->getDescription());
|
||||||
|
|
||||||
UtilityServices *utilityServices = new UtilityServicesImpl();
|
ref<Utility> utility = plugin->createUtility();
|
||||||
Utility *utility = plugin->createUtility(utilityServices);
|
|
||||||
|
|
||||||
return utility->run(argc-optind, argv+optind);
|
return utility->run(argc-optind, argv+optind);
|
||||||
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
|
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>377</width>
|
<width>377</width>
|
||||||
<height>480</height>
|
<height>500</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -455,7 +455,7 @@ movements while navigating in the realt-time preview.</string>
|
||||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
<string><!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">
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
p, li { white-space: pre-wrap; }
|
p, li { white-space: pre-wrap; }
|
||||||
</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;">
|
</style></head><body>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This option specifies the camera behavior when navigating within the realtime preview.</p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This option specifies the camera behavior when navigating within the realtime preview.</p>
|
||||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through (Fix yaw)</span>: Always yaw around a fixed &quot;up&quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.</p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through (Fix yaw)</span>: Always yaw around a fixed &quot;up&quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.</p>
|
||||||
|
@ -476,7 +476,7 @@ p, li { white-space: pre-wrap; }
|
||||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
<string><!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">
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
p, li { white-space: pre-wrap; }
|
p, li { white-space: pre-wrap; }
|
||||||
</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;">
|
</style></head><body>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This option specifies the camera behavior when navigating within the realtime preview.</p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This option specifies the camera behavior when navigating within the realtime preview.</p>
|
||||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through (Fix yaw)</span>: Always yaw around a fixed &quot;up&quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.</p>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through (Fix yaw)</span>: Always yaw around a fixed &quot;up&quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.</p>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <xercesc/parsers/SAXParser.hpp>
|
#include <xercesc/parsers/SAXParser.hpp>
|
||||||
#include "glwidget.h"
|
#include "glwidget.h"
|
||||||
#include "sceneloader.h"
|
#include "sceneloader.h"
|
||||||
#include "../mitsuba/shandler.h"
|
#include <mitsuba/render/shandler.h>
|
||||||
|
|
||||||
SceneLoader::SceneLoader(FileResolver *resolver, const std::string &filename)
|
SceneLoader::SceneLoader(FileResolver *resolver, const std::string &filename)
|
||||||
: Thread("load"), m_resolver(resolver), m_filename(filename) {
|
: Thread("load"), m_resolver(resolver), m_filename(filename) {
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include <mitsuba/render/testcase.h>
|
||||||
|
#include <mitsuba/core/plugin.h>
|
||||||
|
|
||||||
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class TestSamplers : public TestCase {
|
||||||
|
public:
|
||||||
|
MTS_BEGIN_TESTCASE()
|
||||||
|
MTS_DECLARE_TEST(test01_Halton)
|
||||||
|
MTS_DECLARE_TEST(test02_Hammersley)
|
||||||
|
MTS_DECLARE_TEST(test03_radicalInverseIncr)
|
||||||
|
MTS_END_TESTCASE()
|
||||||
|
|
||||||
|
void test01_Halton() {
|
||||||
|
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
||||||
|
createObject(Sampler::m_theClass, Properties("halton")));
|
||||||
|
|
||||||
|
/* MATLAB: p = haltonset(5); net(p,5) */
|
||||||
|
Float comparison[] = {
|
||||||
|
0, 0, 0, 0, 0,
|
||||||
|
0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
|
||||||
|
0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
|
||||||
|
0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
|
||||||
|
0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
|
||||||
|
};
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
sampler->generate();
|
||||||
|
for (int i=0; i<5; ++i) {
|
||||||
|
for (int j=0; j<5; ++j)
|
||||||
|
Assert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
|
||||||
|
sampler->advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test02_Hammersley() {
|
||||||
|
Properties props("hammersley");
|
||||||
|
props.setInteger("sampleCount", 5);
|
||||||
|
|
||||||
|
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
||||||
|
createObject(Sampler::m_theClass, props));
|
||||||
|
|
||||||
|
Float comparison[] = {
|
||||||
|
0.0, 0, 0, 0, 0, 0,
|
||||||
|
1.0/5.0, 0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
|
||||||
|
2.0/5.0, 0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
|
||||||
|
3.0/5.0, 0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
|
||||||
|
4.0/5.0, 0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
|
||||||
|
};
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
sampler->generate();
|
||||||
|
for (int i=0; i<5; ++i) {
|
||||||
|
for (int j=0; j<6; ++j)
|
||||||
|
Assert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
|
||||||
|
sampler->advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test03_radicalInverseIncr() {
|
||||||
|
Float x = 0.0f;
|
||||||
|
|
||||||
|
for (int i=0; i<20; ++i) {
|
||||||
|
Assert(x == radicalInverse(2, i));
|
||||||
|
x = radicalInverseIncremental(2, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MTS_EXPORT_TESTCASE(TestSamplers, "Testcase for Sampler implementations")
|
||||||
|
|
||||||
|
MTS_NAMESPACE_END
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include <mitsuba/render/testcase.h>
|
||||||
|
#include <mitsuba/core/shvector.h>
|
||||||
|
|
||||||
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class TestSphericalHarmonics : public TestCase {
|
||||||
|
public:
|
||||||
|
MTS_BEGIN_TESTCASE()
|
||||||
|
MTS_DECLARE_TEST(test01_shRotation)
|
||||||
|
MTS_DECLARE_TEST(test02_shSampler)
|
||||||
|
MTS_END_TESTCASE()
|
||||||
|
|
||||||
|
void test01_shRotation() {
|
||||||
|
/* Generate a random SH expansion, rotate it and
|
||||||
|
spot-check 100 times against the original */
|
||||||
|
|
||||||
|
ref<Random> random = new Random();
|
||||||
|
int bands = 8;
|
||||||
|
|
||||||
|
SHVector vec1(bands);
|
||||||
|
for (int l=0; l<bands; ++l)
|
||||||
|
for (int m=-l; m<=l; ++m)
|
||||||
|
vec1(l, m) = random->nextFloat();
|
||||||
|
|
||||||
|
Vector axis(squareToSphere(Point2(random->nextFloat(), random->nextFloat())));
|
||||||
|
Transform trafo = Transform::rotate(axis, random->nextFloat()*360);
|
||||||
|
Transform inv = trafo.inverse();
|
||||||
|
SHRotation rot(vec1.getBands());
|
||||||
|
|
||||||
|
SHVector::rotation(trafo, rot);
|
||||||
|
SHVector vec2(bands);
|
||||||
|
|
||||||
|
rot(vec1, vec2);
|
||||||
|
|
||||||
|
for (int i=0; i<100; ++i) {
|
||||||
|
Vector dir1(squareToSphere(Point2(random->nextFloat(), random->nextFloat()))), dir2;
|
||||||
|
trafo(dir1, dir2);
|
||||||
|
|
||||||
|
Float value1 = vec1.eval(dir2);
|
||||||
|
Float value2 = vec2.eval(dir1);
|
||||||
|
Assert(std::abs(value1-value2) < Epsilon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClampedCos {
|
||||||
|
Vector axis;
|
||||||
|
ClampedCos(Vector axis) : axis(axis) { }
|
||||||
|
Float operator()(const Vector &w) const { return std::max((Float) 0, dot(w, axis)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
void test02_shSampler() {
|
||||||
|
/* Draw 100 samples from a SH expansion of a clamped cosine-shaped
|
||||||
|
distribution and verify the returned probabilities */
|
||||||
|
int bands = 13, numSamples = 100, depth = 12;
|
||||||
|
|
||||||
|
Vector v = normalize(Vector(1, 2, 3));
|
||||||
|
ref<Random> random = new Random();
|
||||||
|
SHVector clampedCos = SHVector(bands);
|
||||||
|
clampedCos.project(ClampedCos(v), numSamples);
|
||||||
|
//Float clampedCosError = clampedCos.l2Error(ClampedCos(v), numSamples);
|
||||||
|
clampedCos.normalize();
|
||||||
|
|
||||||
|
//cout << "Projection error = " << clampedCosError << endl;
|
||||||
|
//cout << "Precomputing mip-maps" << endl;
|
||||||
|
ref<SHSampler> sampler = new SHSampler(bands, depth);
|
||||||
|
//cout << "Done: "<< sampler->toString() << endl;
|
||||||
|
Float accum = 0;
|
||||||
|
int nsamples = 100, nInAvg = 0;
|
||||||
|
for (int i=0; i<=nsamples; ++i) {
|
||||||
|
Point2 sample(random->nextFloat(), random->nextFloat());
|
||||||
|
Float pdf1 = sampler->warp(clampedCos, sample);
|
||||||
|
Float pdf2 = dot(v, sphericalDirection(sample.x, sample.y))/M_PI;
|
||||||
|
Float relerr = std::abs(pdf1-pdf2)/pdf2;
|
||||||
|
if (pdf2 > 0.01) {
|
||||||
|
accum += relerr; ++nInAvg;
|
||||||
|
Assert(relerr < 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert(accum / nInAvg < 0.01);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MTS_EXPORT_TESTCASE(TestSphericalHarmonics, "Testcase for Spherical Harmonics code")
|
||||||
|
MTS_NAMESPACE_END
|
|
@ -5,8 +5,6 @@ MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class AddImages : public Utility {
|
class AddImages : public Utility {
|
||||||
public:
|
public:
|
||||||
AddImages(UtilityServices *us) : Utility(us) { }
|
|
||||||
|
|
||||||
int run(int argc, char **argv) {
|
int run(int argc, char **argv) {
|
||||||
if (argc != 6) {
|
if (argc != 6) {
|
||||||
cout << "Add the weighted pixel values of two EXR images to produce a new one" << endl;
|
cout << "Add the weighted pixel values of two EXR images to produce a new one" << endl;
|
||||||
|
@ -53,9 +51,8 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_UTILITY()
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS(AddImages, false, Utility)
|
|
||||||
MTS_EXPORT_UTILITY(AddImages, "Generate linear combinations of EXR images")
|
MTS_EXPORT_UTILITY(AddImages, "Generate linear combinations of EXR images")
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -1,611 +0,0 @@
|
||||||
#include <mitsuba/mitsuba.h>
|
|
||||||
#include <mitsuba/core/plugin.h>
|
|
||||||
#include <mitsuba/render/scene.h>
|
|
||||||
#include <mitsuba/render/photonmap.h>
|
|
||||||
#include <mitsuba/core/wavelet.h>
|
|
||||||
#include <mitsuba/core/shvector.h>
|
|
||||||
#include <mitsuba/core/grid.h>
|
|
||||||
#include "../medium/maxexp.h"
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
using namespace mitsuba;
|
|
||||||
|
|
||||||
void testHalton() {
|
|
||||||
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
|
||||||
createObject(Sampler::m_theClass, Properties("halton")));
|
|
||||||
|
|
||||||
/* MATLAB: p = haltonset(5); net(p,5) */
|
|
||||||
Float comparison[] = {
|
|
||||||
0, 0, 0, 0, 0,
|
|
||||||
0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
|
|
||||||
0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
|
|
||||||
0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
|
|
||||||
0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
|
|
||||||
};
|
|
||||||
|
|
||||||
int pos = 0;
|
|
||||||
sampler->generate();
|
|
||||||
for (int i=0; i<5; ++i) {
|
|
||||||
for (int j=0; j<5; ++j)
|
|
||||||
SAssert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
|
|
||||||
sampler->advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testHammersley() {
|
|
||||||
Properties props("hammersley");
|
|
||||||
props.setInteger("sampleCount", 5);
|
|
||||||
|
|
||||||
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
|
||||||
createObject(Sampler::m_theClass, props));
|
|
||||||
|
|
||||||
Float comparison[] = {
|
|
||||||
0.0, 0, 0, 0, 0, 0,
|
|
||||||
1.0/5.0, 0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
|
|
||||||
2.0/5.0, 0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
|
|
||||||
3.0/5.0, 0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
|
|
||||||
4.0/5.0, 0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
|
|
||||||
};
|
|
||||||
|
|
||||||
int pos = 0;
|
|
||||||
sampler->generate();
|
|
||||||
for (int i=0; i<5; ++i) {
|
|
||||||
for (int j=0; j<6; ++j)
|
|
||||||
SAssert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
|
|
||||||
sampler->advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testRadicalInverseIncr() {
|
|
||||||
Float x = 0.0f;
|
|
||||||
|
|
||||||
for (int i=0; i<20; ++i) {
|
|
||||||
SAssert(x == radicalInverse(2, i));
|
|
||||||
x = radicalInverseIncremental(2, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testSpotLuminaire() {
|
|
||||||
Properties props("spot");
|
|
||||||
props.setFloat("beamWidth", 20);
|
|
||||||
props.setFloat("cutoffAngle", 25);
|
|
||||||
ref<Luminaire> spot = static_cast<Luminaire *> (PluginManager::getInstance()->
|
|
||||||
createObject(Luminaire::m_theClass, props));
|
|
||||||
ref<Random> random = new Random();
|
|
||||||
|
|
||||||
Spectrum power;
|
|
||||||
EmissionRecord eRec;
|
|
||||||
const int nSamples = 1000000;
|
|
||||||
for (int i=0; i<nSamples; ++i) {
|
|
||||||
Point2 areaSample(random->nextFloat(), random->nextFloat());
|
|
||||||
Point2 dirSample(random->nextFloat(), random->nextFloat());
|
|
||||||
spot->sampleEmission(eRec, areaSample, dirSample);
|
|
||||||
power += eRec.P / (eRec.pdfArea*eRec.pdfDir);
|
|
||||||
}
|
|
||||||
power /= (Float) nSamples;
|
|
||||||
cout << "Estimated power: " << power.toString() << endl;
|
|
||||||
cout << "Actual power: " << spot->getPower().toString() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testHG1() {
|
|
||||||
Properties props("hg");
|
|
||||||
props.setFloat("g", .8);
|
|
||||||
|
|
||||||
ref<PhaseFunction> hg = static_cast<PhaseFunction *> (PluginManager::getInstance()->
|
|
||||||
createObject(PhaseFunction::m_theClass, props));
|
|
||||||
ref<Random> random = new Random();
|
|
||||||
|
|
||||||
Float sum = 0;
|
|
||||||
Vector dir1(0, 0, 1);
|
|
||||||
const int nSamples = 100000;
|
|
||||||
MediumSamplingRecord mRec;
|
|
||||||
for (int i=0; i<nSamples; ++i) {
|
|
||||||
Vector dir2(squareToSphere(Point2(random->nextFloat(), random->nextFloat())));
|
|
||||||
sum += hg->f(mRec, dir2, dir2)[0];
|
|
||||||
}
|
|
||||||
sum *= (4 * M_PI) / nSamples;
|
|
||||||
|
|
||||||
cout << sum << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testHG2() {
|
|
||||||
const int res = 8;
|
|
||||||
Float buf[res][res];
|
|
||||||
Properties props("hg");
|
|
||||||
props.setFloat("g", -.2);
|
|
||||||
MediumSamplingRecord mRec;
|
|
||||||
|
|
||||||
ref<PhaseFunction> hg = static_cast<PhaseFunction *> (PluginManager::getInstance()->
|
|
||||||
createObject(PhaseFunction::m_theClass, props));
|
|
||||||
ref<Random> random = new Random();
|
|
||||||
|
|
||||||
const Vector dir1(0, 0, 1);
|
|
||||||
memset(buf, 0, sizeof(Float)*res*res);
|
|
||||||
Vector dir2;
|
|
||||||
PhaseFunction::ESampledType sampledType;
|
|
||||||
|
|
||||||
const int nSamples = 10000000;
|
|
||||||
for (int i=0; i<nSamples; ++i) {
|
|
||||||
Point2 sample(random->nextFloat(), random->nextFloat());
|
|
||||||
hg->sample(mRec, dir1, dir2, sampledType, sample);
|
|
||||||
Float pdf = hg->f(mRec, dir1, dir2)[0];
|
|
||||||
Float dir2Phi = (std::atan2(dir2.y, dir2.x) + (Float) M_PI) / (2 * (Float) M_PI);
|
|
||||||
Float dir2CosTheta = (dir2.z + 1) / (Float) 2;
|
|
||||||
|
|
||||||
int pos1 = std::max(0, std::min((int) (dir2Phi * res), res-1));
|
|
||||||
int pos2 = std::max(0, std::min((int) (dir2CosTheta* res), res-1));
|
|
||||||
buf[pos1][pos2] += 1/pdf;
|
|
||||||
|
|
||||||
}
|
|
||||||
cout << "A=[";
|
|
||||||
for (int y=0; y<res; ++y) {
|
|
||||||
for (int x=0; x<res; ++x)
|
|
||||||
cout << buf[y][x] / nSamples << " ";
|
|
||||||
cout << ";" << endl;
|
|
||||||
}
|
|
||||||
cout << "];" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testMATLAB() {
|
|
||||||
int count = 256;
|
|
||||||
int dim1 = 17, dim2 = 19;
|
|
||||||
cout << "x=[";
|
|
||||||
for (int i=1; i<=count; ++i) {
|
|
||||||
cout << radicalInverse(dim1, i);
|
|
||||||
if (i+1<=count)
|
|
||||||
cout << " ";
|
|
||||||
}
|
|
||||||
cout << "];" << endl;
|
|
||||||
cout << "y=[";
|
|
||||||
for (int i=1; i<=count; ++i) {
|
|
||||||
cout << radicalInverse(dim2, i);
|
|
||||||
if (i+1<=count)
|
|
||||||
cout << " ";
|
|
||||||
}
|
|
||||||
cout << "];" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Float sample(Float *sigma, int n, Float u, Float &prob) {
|
|
||||||
SAssert(n >= 2);
|
|
||||||
Float cdf[4], intervalStart[3];
|
|
||||||
cdf[0] = 0;
|
|
||||||
|
|
||||||
/* Requires the coefficients to be sorted in descending order */
|
|
||||||
for (int i=0; i<n; ++i) {
|
|
||||||
/* Integrate max(f_1(t), .., f_n(t)) on [0, \infty]*/
|
|
||||||
Float lower = (i==0) ? -1 : -std::pow((sigma[i]/sigma[i-1]),
|
|
||||||
-sigma[i] / (sigma[i]-sigma[i-1]));
|
|
||||||
Float upper = (i==n-1) ? 0 : -std::pow((sigma[i+1]/sigma[i]),
|
|
||||||
-sigma[i] / (sigma[i+1]-sigma[i]));
|
|
||||||
cdf[i+1] = cdf[i] + (upper - lower);
|
|
||||||
|
|
||||||
/* Store the interval covered by each f_i */
|
|
||||||
intervalStart[i] = (i == 0) ? 0
|
|
||||||
: std::log(sigma[i]/sigma[i-1]) / (sigma[i]-sigma[i-1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Turn into a discrete CDF and keep the normalization factor */
|
|
||||||
Float normFactor = cdf[n];
|
|
||||||
for (int i=0; i<=n; ++i)
|
|
||||||
cdf[i] /= normFactor;
|
|
||||||
|
|
||||||
/* Find the f_i for this sample */
|
|
||||||
Float *lowerBound = std::lower_bound(&cdf[0], &cdf[n+1], u);
|
|
||||||
int index = std::max(0, (int) (lowerBound - &cdf[0]) - 1);
|
|
||||||
SAssert(index >= 0 && index < n);
|
|
||||||
|
|
||||||
/* Sample according to f_i */
|
|
||||||
Float t = -std::log(std::exp(-intervalStart[index] * sigma[index])
|
|
||||||
- normFactor * (u - cdf[index])) / sigma[index];
|
|
||||||
|
|
||||||
/* Compute the probability of this sample */
|
|
||||||
prob = sigma[index] * std::exp(-sigma[index] * t) / normFactor;
|
|
||||||
|
|
||||||
/* CDF computation
|
|
||||||
Float *lowerBound = std::lower_bound(&intervalStart[0], &intervalStart[n], t);
|
|
||||||
int index = std::max(0, (int) (lowerBound - &intervalStart[0]) - 1);
|
|
||||||
Float lower = (index==0) ? -1 : -std::pow((sigma[index]/sigma[index-1]),
|
|
||||||
-sigma[index] / (sigma[index]-sigma[index-1]));
|
|
||||||
Float upper = -std::exp(-sigma[index] * t);
|
|
||||||
Float integral = cdf[index] + (upper - lower) / normFactor;
|
|
||||||
*/
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testVariance() {
|
|
||||||
ref<Random> random = new Random();
|
|
||||||
Spectrum mean, meanSqr, variance;
|
|
||||||
Spectrum sigmaT;
|
|
||||||
sigmaT[0] = 0.7014;
|
|
||||||
sigmaT[1] = 1.2225;
|
|
||||||
sigmaT[2] = 1.9142;
|
|
||||||
int nSamples = 100000;
|
|
||||||
|
|
||||||
for (int chan=0; chan<3; ++chan) {
|
|
||||||
cout << "Sampling with respect to channel " << chan << endl;
|
|
||||||
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
|
|
||||||
for (int i=0; i<nSamples; ++i) {
|
|
||||||
Float desiredAttenuation = 1-random->nextFloat();
|
|
||||||
|
|
||||||
Float t = -std::log(desiredAttenuation)/sigmaT[chan];
|
|
||||||
Float prob = sigmaT[chan] * std::exp(-sigmaT[chan] * t);
|
|
||||||
Spectrum value = (sigmaT * (-t)).exp() / prob;
|
|
||||||
|
|
||||||
Spectrum delta = value - mean;
|
|
||||||
mean += delta / (Float) (i+1);
|
|
||||||
meanSqr += delta * (value - mean);
|
|
||||||
variance = meanSqr / (Float) i;
|
|
||||||
}
|
|
||||||
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
|
|
||||||
cout << "Mean : " << mean.toString() << endl;
|
|
||||||
cout << "Sample variance : " << variance.toString() << endl << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "Random sampling test" << endl;
|
|
||||||
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
|
|
||||||
for (int i=0; i<nSamples; ++i) {
|
|
||||||
Float desiredAttenuation = 1-random->nextFloat();
|
|
||||||
int chan = random->nextInteger(3);
|
|
||||||
|
|
||||||
Float t = -std::log(desiredAttenuation)/sigmaT[chan];
|
|
||||||
Spectrum prob = sigmaT * (-sigmaT * t).exp();
|
|
||||||
Spectrum value = (sigmaT * (-t)).exp() / (prob[chan]);
|
|
||||||
|
|
||||||
Spectrum delta = value - mean;
|
|
||||||
mean += delta / (Float) (i+1);
|
|
||||||
meanSqr += delta * (value - mean);
|
|
||||||
variance = meanSqr / (Float) i;
|
|
||||||
}
|
|
||||||
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
|
|
||||||
cout << "Mean : " << mean.toString() << endl;
|
|
||||||
cout << "Sample variance : " << variance.toString() << endl << endl;
|
|
||||||
|
|
||||||
cout << "Single sample test" << endl;
|
|
||||||
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
|
|
||||||
for (int i=0; i<nSamples; ++i) {
|
|
||||||
Float desiredAttenuation = 1-random->nextFloat();
|
|
||||||
int chan = random->nextInteger(3);
|
|
||||||
|
|
||||||
Float t = -std::log(desiredAttenuation)/sigmaT[chan];
|
|
||||||
Spectrum prob = sigmaT * (-sigmaT * t).exp();
|
|
||||||
Float weight = prob[chan] / (prob[0] + prob[1] + prob[2]);
|
|
||||||
Spectrum value = (sigmaT * (-t)).exp() / (prob[chan] * 1/(Float) 3) * weight;
|
|
||||||
|
|
||||||
Spectrum delta = value - mean;
|
|
||||||
mean += delta / (Float) (i+1);
|
|
||||||
meanSqr += delta * (value - mean);
|
|
||||||
variance = meanSqr / (Float) i;
|
|
||||||
}
|
|
||||||
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
|
|
||||||
cout << "Mean : " << mean.toString() << endl;
|
|
||||||
cout << "Sample variance : " << variance.toString() << endl << endl;
|
|
||||||
|
|
||||||
|
|
||||||
cout << "New distribution test" << endl;
|
|
||||||
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
|
|
||||||
Float extinction[] = {1.9142, 1.2225, 0.7014};
|
|
||||||
for (int i=0; i<nSamples; ++i) {
|
|
||||||
Float prob;
|
|
||||||
Float t = sample(extinction, 3, random->nextFloat(), prob);
|
|
||||||
|
|
||||||
Spectrum value = (sigmaT * (-t)).exp() / prob;
|
|
||||||
|
|
||||||
Spectrum delta = value - mean;
|
|
||||||
mean += delta / (Float) (i+1);
|
|
||||||
meanSqr += delta * (value - mean);
|
|
||||||
variance = meanSqr / (Float) i;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
|
|
||||||
cout << "Mean : " << mean.toString() << endl;
|
|
||||||
cout << "Sample variance : " << variance.toString() << endl << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testPhotonMap() {
|
|
||||||
int nPhotons = 3000000;
|
|
||||||
ref<PhotonMap> map = new PhotonMap(nPhotons);
|
|
||||||
Spectrum power;
|
|
||||||
ref<Random> random = new Random();
|
|
||||||
power.fromLinearRGB(1, 2, 3);
|
|
||||||
power *= M_PI;
|
|
||||||
|
|
||||||
bool storePhoton(const Point &pos, const Vector &dir, const Spectrum &power);
|
|
||||||
for (int i=0; i<nPhotons; ++i) {
|
|
||||||
Point2 disk = squareToDisk(Point2(random->nextFloat(), random->nextFloat()));
|
|
||||||
map->storePhoton(Point(disk.x,disk.y,0), Normal(0,0,1), Vector(0, 0, -1), power, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
map->setScale(1/(Float) nPhotons);
|
|
||||||
map->balance();
|
|
||||||
|
|
||||||
for (int i=1; i<10; ++i) {
|
|
||||||
Point2 disk = squareToDisk(Point2(random->nextFloat(), random->nextFloat())) * .2;
|
|
||||||
|
|
||||||
cout << map->estimateIrradiance(Point(disk.x, disk.y, 0), Normal(0, 0, 1), .3, 10000).toString() << endl;
|
|
||||||
cout << map->estimateIrradianceFiltered(Point(disk.x, disk.y, 0), Normal(0, 0, 1), .3, 10000).toString() << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testMaxExp() {
|
|
||||||
std::vector<Float> sigmaT;
|
|
||||||
sigmaT.push_back(0.7014);
|
|
||||||
sigmaT.push_back(1.2225);
|
|
||||||
sigmaT.push_back(1.9142);
|
|
||||||
|
|
||||||
MaxExpDist dist(sigmaT);
|
|
||||||
|
|
||||||
for (int i=0; i<9; ++i) {
|
|
||||||
Float U=.01f + i/10.0f, t, pdf, cdf;
|
|
||||||
t = dist.sample(U, pdf);
|
|
||||||
cdf = dist.cdf(t);
|
|
||||||
|
|
||||||
cout << "Sampled U=" << U << " => t = " << t << ", pdf=" << pdf << ", cdf=" << cdf << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testHeterogeneous() {
|
|
||||||
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
|
||||||
createObject(Sampler::m_theClass, Properties("independent")));
|
|
||||||
|
|
||||||
Properties props("heterogeneous");
|
|
||||||
props.setString("filename", "scenes/cornell/smoke-density.65.vol");
|
|
||||||
props.setSpectrum("sigmaS", Spectrum(2.62));
|
|
||||||
props.setSpectrum("sigmaA", Spectrum(.05f));
|
|
||||||
props.setString("strategy", "standard");
|
|
||||||
props.setFloat("sizeMultiplier", 10);
|
|
||||||
ref<Medium> standardMedium = static_cast<Medium *> (PluginManager::getInstance()->
|
|
||||||
createObject(Medium::m_theClass, props));
|
|
||||||
standardMedium->configure();
|
|
||||||
|
|
||||||
props = Properties("heterogeneous");
|
|
||||||
props.setString("filename", "scenes/cornell/smoke-density.65.vol");
|
|
||||||
props.setString("strategy", "coleman");
|
|
||||||
props.setSpectrum("sigmaS", Spectrum(2.62));
|
|
||||||
props.setSpectrum("sigmaA", Spectrum(.05f));
|
|
||||||
props.setFloat("sizeMultiplier", 10);
|
|
||||||
ref<Medium> colemanMedium = static_cast<Medium *> (PluginManager::getInstance()->
|
|
||||||
createObject(Medium::m_theClass, props));
|
|
||||||
colemanMedium->configure();
|
|
||||||
|
|
||||||
Ray ray(Point(0, 1, .4), Vector(1, 0, 0));
|
|
||||||
|
|
||||||
MediumSamplingRecord mRec;
|
|
||||||
|
|
||||||
std::ofstream distr("distr.m");
|
|
||||||
int res = 300000, failures = 0;
|
|
||||||
|
|
||||||
distr << "samplesStandard=[" << endl;
|
|
||||||
for (int i=0; i<res; ++i) {
|
|
||||||
if (standardMedium->sampleDistance(ray, std::numeric_limits<Float>::infinity(), mRec, sampler)) {
|
|
||||||
// distr << mRec.t << " ";
|
|
||||||
distr << mRec.sigmaS[0] * mRec.attenuation[0] / mRec.pdf << " " << endl;
|
|
||||||
} else {
|
|
||||||
++failures;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
distr << "];" << endl;
|
|
||||||
cout << failures/(Float)res << endl;
|
|
||||||
failures = 0;
|
|
||||||
cout << failures/(Float)res << endl;
|
|
||||||
distr << "samplesColeman=[" << endl;
|
|
||||||
for (int i=0; i<res; ++i) {
|
|
||||||
if (colemanMedium->sampleDistance(ray, std::numeric_limits<Float>::infinity(), mRec, sampler)) {
|
|
||||||
// distr << mRec.t << " ";
|
|
||||||
distr << mRec.sigmaS[0] * mRec.attenuation[0] / mRec.pdf << " " << endl;
|
|
||||||
} else {
|
|
||||||
++failures;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
distr << "];" << endl;
|
|
||||||
distr << "hist(samplesStandard, 300);" << endl;
|
|
||||||
distr << "title('Standard');" << endl;
|
|
||||||
distr << "figure;" << endl;
|
|
||||||
distr << "hist(samplesColeman, 300);" << endl;
|
|
||||||
distr.close();
|
|
||||||
cout << failures/(Float)res << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testWavelet() {
|
|
||||||
ref<FileStream> stream = new FileStream("cat.png", FileStream::EReadOnly);
|
|
||||||
ref<Bitmap> bitmap = new Bitmap(Bitmap::EPNG, stream);
|
|
||||||
|
|
||||||
ref<Wavelet2D> wavelet = new Wavelet2D(bitmap);
|
|
||||||
cout << "2D compression ratio: " << wavelet->compress(.015) << endl;
|
|
||||||
ref<SparseWavelet2D> sw = wavelet->toSparseWavelet();
|
|
||||||
ref<FileStream> stream3 = new FileStream("cat2.raw", FileStream::ETruncReadWrite);
|
|
||||||
sw->serialize(stream3, NULL);
|
|
||||||
stream3->close();
|
|
||||||
ref<FileStream> stream4 = new FileStream("cat2.raw", FileStream::EReadOnly);
|
|
||||||
ref<SparseWavelet2D> sw2 = new SparseWavelet2D(stream4, NULL);
|
|
||||||
ref<Wavelet2D> wavelet2 = new Wavelet2D(sw2);
|
|
||||||
ref<Bitmap> bitmap2 = new Bitmap(bitmap->getWidth(), bitmap->getHeight(), 8);
|
|
||||||
|
|
||||||
wavelet2->decode(bitmap2);
|
|
||||||
|
|
||||||
size_t nEntries = 512*512;
|
|
||||||
Float mean = 0, sqrError = 0;
|
|
||||||
for (size_t i=0; i<nEntries; ++i) {
|
|
||||||
mean += bitmap->getData()[i] / (255.0f * nEntries);
|
|
||||||
sqrError += std::pow(bitmap->getData()[i]/(255.0f)-bitmap2->getData()[i]/(255.0f), 2)/nEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "Mean: " << mean << ", error:" << std::sqrt(sqrError)/mean<< endl;
|
|
||||||
|
|
||||||
ref<FileStream> stream2 = new FileStream("cat2.png", FileStream::ETruncReadWrite);
|
|
||||||
bitmap2->save(Bitmap::EPNG, stream2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testLineIntegral() {
|
|
||||||
ref<FileStream> stream = new FileStream("cat.png", FileStream::EReadOnly);
|
|
||||||
ref<Bitmap> bitmap = new Bitmap(Bitmap::EPNG, stream);
|
|
||||||
|
|
||||||
Point2 start(0.121, 0.566);
|
|
||||||
Point2 end(0.815, 0.318);
|
|
||||||
|
|
||||||
Vector2 dir = Vector2(end-start);
|
|
||||||
|
|
||||||
for (int i=3; i<18; ++i) {
|
|
||||||
size_t nsteps = (int) std::ldexp((Float) 1, i);
|
|
||||||
uint8_t *data = bitmap->getData();
|
|
||||||
double accum = 0;
|
|
||||||
for (size_t i=0; i<nsteps; ++i) {
|
|
||||||
Vector2 p = (start + dir * (i / (Float) (nsteps-1)));
|
|
||||||
p *= 512;
|
|
||||||
int x = (int) p.x, y = (int) p.y;
|
|
||||||
|
|
||||||
accum += data[x+512*y] / 255.0f;
|
|
||||||
}
|
|
||||||
accum /= nsteps;
|
|
||||||
accum *= dir.length();
|
|
||||||
|
|
||||||
printf("%i steps=%f\n", (int) nsteps, accum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testLineIntegralWavelet() {
|
|
||||||
ref<FileStream> stream = new FileStream("cat.png", FileStream::EReadOnly);
|
|
||||||
ref<Bitmap> bitmap = new Bitmap(Bitmap::EPNG, stream);
|
|
||||||
ref<Wavelet2D> wavelet = new Wavelet2D(bitmap);
|
|
||||||
ref<SparseWavelet2D> sparse = wavelet->toSparseWavelet();
|
|
||||||
|
|
||||||
Point2 start(0.121, 0.566);
|
|
||||||
Point2 end(0.815, 0.318);
|
|
||||||
start*=512; end *= 512;
|
|
||||||
|
|
||||||
cout << sparse->lineIntegral(start, end) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testSHRotation() {
|
|
||||||
ref<Random> random = new Random();
|
|
||||||
int bands = 8;
|
|
||||||
|
|
||||||
SHVector vec1(bands);
|
|
||||||
for (int l=0; l<bands; ++l)
|
|
||||||
for (int m=-l; m<=l; ++m)
|
|
||||||
vec1(l, m) = random->nextFloat();
|
|
||||||
|
|
||||||
Vector axis(squareToSphere(Point2(random->nextFloat(), random->nextFloat())));
|
|
||||||
Transform trafo = Transform::rotate(axis, random->nextFloat()*360);
|
|
||||||
Transform inv = trafo.inverse();
|
|
||||||
SHRotation rot(vec1.getBands());
|
|
||||||
|
|
||||||
SHVector::rotation(trafo, rot);
|
|
||||||
SHVector vec2(bands);
|
|
||||||
|
|
||||||
rot(vec1, vec2);
|
|
||||||
|
|
||||||
for (int i=0; i<100; ++i) {
|
|
||||||
Vector dir1(squareToSphere(Point2(random->nextFloat(), random->nextFloat()))), dir2;
|
|
||||||
trafo(dir1, dir2);
|
|
||||||
|
|
||||||
Float value1 = vec1.eval(dir2);
|
|
||||||
Float value2 = vec2.eval(dir1);
|
|
||||||
SAssert(std::abs(value1-value2) < Epsilon);
|
|
||||||
}
|
|
||||||
cout << "Passed." << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ClampedCos {
|
|
||||||
Vector axis;
|
|
||||||
ClampedCos(Vector axis) : axis(axis) { }
|
|
||||||
Float operator()(const Vector &w) const { return std::max((Float) 0, dot(w, axis)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
void testSHSampler() {
|
|
||||||
int bands = 25, numSamples = 100, depth = 12;
|
|
||||||
|
|
||||||
Vector v = normalize(Vector(1, 2, 3));
|
|
||||||
ref<Random> random = new Random();
|
|
||||||
SHVector clampedCos = SHVector(bands);
|
|
||||||
clampedCos.project(ClampedCos(v), numSamples);
|
|
||||||
Float clampedCosError = clampedCos.l2Error(ClampedCos(v), numSamples);
|
|
||||||
clampedCos.normalize();
|
|
||||||
|
|
||||||
cout << "Projection error = " << clampedCosError << endl;
|
|
||||||
cout << "Precomputing mip-maps" << endl;
|
|
||||||
ref<SHSampler> sampler = new SHSampler(bands, depth);
|
|
||||||
cout << "Done: "<< sampler->toString() << endl;
|
|
||||||
Float accum = 0;
|
|
||||||
int nsamples = 100;
|
|
||||||
for (int i=0; i<=nsamples; ++i) {
|
|
||||||
Point2 sample(random->nextFloat(), random->nextFloat());
|
|
||||||
Float pdf1 = sampler->warp(clampedCos, sample);
|
|
||||||
Float pdf2 = dot(v, sphericalDirection(sample.x, sample.y))/M_PI;
|
|
||||||
Float relerr = std::abs(pdf1-pdf2)/pdf2;
|
|
||||||
accum += relerr;
|
|
||||||
SAssert(relerr < 0.04);
|
|
||||||
}
|
|
||||||
SAssert(accum / nsamples < 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GridFunctor {
|
|
||||||
Float operator()(Float value, Float length) const {
|
|
||||||
cout << "functor(value=" << value << ", length=" << length << ")" << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void testGrid() {
|
|
||||||
Grid<Float> grid(Vector3i(3, 3, 1), AABB(Point(10, 0, 0), Point(11,1,1)));
|
|
||||||
Ray ray(Point(10 + 1.0f/6.0f, .5, .5), Vector(1, 0, 0), 0, 2.0f/3.0f);
|
|
||||||
|
|
||||||
grid(0, 1, 0) = 1;
|
|
||||||
grid(1, 1, 0) = 2;
|
|
||||||
grid(2, 1, 0) = 3;
|
|
||||||
|
|
||||||
SAssert(std::abs(grid.lookup(Point(10 + 1.0/3.0f, .5, .5))-1.5) < 1e-6);
|
|
||||||
|
|
||||||
GridFunctor functor;
|
|
||||||
grid.rasterize(ray, functor);
|
|
||||||
|
|
||||||
cout << "Expected: functor(value=1, length=" << 1.0f/6.0f << ")" << endl;
|
|
||||||
cout << "Expected: functor(value=2, length=" << 1.0f/3.0f << ")" << endl;
|
|
||||||
cout << "Expected: functor(value=3, length=" << 1.0f/6.0f << ")" << endl;
|
|
||||||
|
|
||||||
SAssert(grid(0,1,0) == 0);
|
|
||||||
SAssert(grid(1,1,0) == 0);
|
|
||||||
SAssert(grid(2,1,0) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
Class::staticInitialization();
|
|
||||||
Thread::staticInitialization();
|
|
||||||
Logger::staticInitialization();
|
|
||||||
Spectrum::staticInitialization();
|
|
||||||
SHVector::staticInitialization();
|
|
||||||
try {
|
|
||||||
/*
|
|
||||||
testHalton();
|
|
||||||
testHammersley();
|
|
||||||
testRadicalInverseIncr();
|
|
||||||
testSpotLuminaire();
|
|
||||||
testHG1();
|
|
||||||
testHG2();
|
|
||||||
testVariance();
|
|
||||||
testPhotonMap();
|
|
||||||
testMaxExp();
|
|
||||||
testHeterogeneous();
|
|
||||||
testLineIntegral();
|
|
||||||
testLineIntegralWavelet();
|
|
||||||
testWaveletBasic();
|
|
||||||
testWavelet();
|
|
||||||
testWavelet3D();
|
|
||||||
testGrid();
|
|
||||||
testSHRotation();
|
|
||||||
testSHSampler();
|
|
||||||
*/
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
|
|
||||||
exit(-1);
|
|
||||||
} catch (...) {
|
|
||||||
std::cerr << "Caught a critical exeption of unknown type! " << std::endl;
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
SHVector::staticShutdown();
|
|
||||||
Spectrum::staticShutdown();
|
|
||||||
Logger::staticShutdown();
|
|
||||||
Thread::staticShutdown();
|
|
||||||
Class::staticShutdown();
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue