19 #include <nori/scene.h>
20 #include <nori/bsdf.h>
21 #include <nori/camera.h>
22 #include <nori/integrator.h>
23 #include <nori/sampler.h>
24 #include <hypothesis.h>
66 m_significanceLevel = propList.
getFloat(
"significanceLevel", 0.01f);
69 std::vector<std::string> angles = tokenize(propList.
getString(
"angles",
""));
70 for (
auto angle : angles)
71 m_angles.push_back(toFloat(angle));
74 std::vector<std::string> distances = tokenize(propList.
getString(
"distances",
""));
75 for (
auto distance : distances)
76 m_distances.push_back(toFloat(distance));
79 std::vector<std::string> references = tokenize(propList.
getString(
"references",
""));
80 for (
auto angle : references)
81 m_references.push_back(toFloat(angle));
84 m_sampleCount = propList.
getInteger(
"sampleCount", 100000);
88 for (
auto bsdf : m_bsdfs)
90 for (
auto emitter : m_emitters)
92 for (
auto scene : m_scenes)
99 m_bsdfs.push_back(
static_cast<BSDF *
>(obj));
103 m_emitters.push_back(
static_cast<Emitter *
>(obj));
108 m_scenes.push_back(
static_cast<Scene *
>(obj));
112 throw NoriException(
"StudentsTTest::addChild(<%s>) is not supported!",
119 int total = 0, passed = 0;
122 if (!m_bsdfs.empty()) {
123 if (m_references.size() != m_bsdfs.size() * m_angles.size())
124 throw NoriException(
"Specified a different number of angles and reference values! %d != %d x %d",
125 m_references.size(), m_bsdfs.size(), m_angles.size());
126 if (!m_emitters.empty() || !m_scenes.empty())
127 throw NoriException(
"Cannot test BSDFs, emitters, and scenes at the same time!");
131 for (
auto bsdf : m_bsdfs) {
132 for (
float angle : m_angles) {
133 float reference = m_references[ctr++];
135 cout <<
"------------------------------------------------------" << endl;
136 cout <<
"Testing (angle=" << angle <<
"): " << bsdf->toString() << endl;
141 cout <<
"Drawing " << m_sampleCount <<
" samples .. " << endl;
142 double mean=0, variance = 0;
143 for (
int k=0; k<m_sampleCount; ++k) {
144 Point2f sample(random.nextFloat(), random.nextFloat());
145 double result = (double) bsdf->sample(bRec, sample).getLuminance();
149 double delta = result - mean;
150 mean += delta / (double) (k+1);
151 variance += delta * (result - mean);
153 variance /= m_sampleCount - 1;
154 std::pair<bool, std::string>
155 result = hypothesis::students_t_test(mean, variance, reference,
156 m_sampleCount, m_significanceLevel, (
int) m_references.size());
160 cout << result.second << endl;
163 }
else if (!m_emitters.empty()) {
164 if (m_references.size() != m_emitters.size() * m_distances.size())
165 throw NoriException(
"Specified a different number of distances and reference values! %d != %d x %d",
166 m_references.size(), m_emitters.size(), m_distances.size());
167 if (!m_bsdfs.empty() || !m_scenes.empty())
168 throw NoriException(
"Cannot test BSDFs, emitters, and scenes at the same time!");
172 for (
auto emitter : m_emitters) {
173 for (
float distance : m_distances) {
174 float reference = m_references[ctr++];
176 cout <<
"------------------------------------------------------" << endl;
177 cout <<
"Testing (distance=" << distance <<
"): " << emitter->toString() << endl;
183 cout <<
"Drawing " << m_sampleCount <<
" samples .. " << endl;
184 double mean=0, variance = 0;
185 bool fields_correct =
true;
186 bool eval_correct =
true;
187 bool pdf_correct =
true;
189 for (
int k=0; k<m_sampleCount; ++k) {
190 Point2f sample(random.nextFloat(), random.nextFloat());
191 double result = (double) emitter->sample(lRec, sample).getLuminance();
197 return (a - b).squaredNorm() < 1e-5f;
199 if (!vectorEqual(ref, lRec.
ref)) {
200 fields_correct =
false;
201 reason =
"`ref` is incorrect";
203 else if (!vectorEqual(wi, lRec.
wi)) {
204 fields_correct =
false;
205 reason =
"`wi` is incorrect";
208 fields_correct =
false;
209 reason =
"`shadowRay.o` or `shadowRay.d` is incorrect";
212 fields_correct =
false;
213 reason =
"`shadowRay.maxt` - `shadowRay.mint` should equal to the distance between `ref` and `p`";
218 double delta = result - mean;
219 mean += delta / (double) (k+1);
220 variance += delta * (result - mean);
223 variance /= m_sampleCount - 1;
224 std::pair<bool, std::string>
225 result = hypothesis::students_t_test(mean, variance, reference,
226 m_sampleCount, m_significanceLevel, (
int) m_references.size());
228 cout << result.second << endl;
231 cout <<
"The return of `sample` method is incorrect" << endl;
234 if (!fields_correct) {
235 cout <<
"EmitterQueryRecord fields are not set correctly during sampling: " << reason << endl;
239 cout <<
"Either `eval` method is wrongly implemented or `pdf` field is incorrectly set" << endl;
243 cout <<
"Either `pdf` method is wrongly implemented or `pdf` field is incorrectly set" << endl;
251 if (m_references.size() != m_scenes.size())
252 throw NoriException(
"Specified a different number of scenes and reference values!");
253 if (!m_bsdfs.empty() || !m_emitters.empty())
254 throw NoriException(
"Cannot test BSDFs, emitters, and scenes at the same time!");
260 for (
auto scene : m_scenes) {
261 const Integrator *integrator = scene->getIntegrator();
262 const Camera *camera = scene->getCamera();
263 float reference = m_references[ctr++];
265 cout <<
"------------------------------------------------------" << endl;
266 cout <<
"Testing scene: " << scene->toString() << endl;
269 cout <<
"Generating " << m_sampleCount <<
" paths.. " << endl;
271 double mean = 0, variance = 0;
272 for (
int k=0; k<m_sampleCount; ++k) {
280 value *= integrator->
Li(scene, sampler, ray);
285 double delta = result - mean;
286 mean += delta / (double) (k+1);
287 variance += delta * (result - mean);
289 variance /= m_sampleCount - 1;
291 std::pair<bool, std::string>
292 result = hypothesis::students_t_test(mean, variance, reference,
293 m_sampleCount, m_significanceLevel, (
int) m_references.size());
297 cout << result.second << endl;
300 cout <<
"Passed " << passed <<
"/" << total <<
" tests." << endl;
302 if (passed < total) {
303 throw std::runtime_error(
"Failed some of the tests");
310 " significanceLevel = %f,\n"
320 std::vector<BSDF *> m_bsdfs;
321 std::vector<Emitter *> m_emitters;
322 std::vector<Scene *> m_scenes;
323 std::vector<float> m_angles;
324 std::vector<float> m_distances;
325 std::vector<float> m_references;
326 float m_significanceLevel;
Superclass of all bidirectional scattering distribution functions.
Generic camera interface.
const Vector2i & getOutputSize() const
Return the size of the output image in pixels.
virtual Color3f sampleRay(Ray3f &ray, const Point2f &samplePosition, const Point2f &apertureSample) const =0
Importance sample a ray according to the camera's response function.
Superclass of all emitters.
Abstract integrator (i.e. a rendering technique)
virtual Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const =0
Sample the incident radiance along a ray.
Simple exception class, which stores a human-readable error description.
static NoriObject * createInstance(const std::string &name, const PropertyList &propList)
Construct an instance from the class of the given name.
Base class of all objects.
static std::string classTypeName(EClassType type)
Turn a class type into a human-readable string.
virtual EClassType getClassType() const =0
Return the type of object (i.e. Mesh/BSDF/etc.) provided by this instance.
This is an associative container used to supply the constructors of NoriObject subclasses with parame...
float getFloat(const std::string &name) const
Get a float property, and throw an exception if it does not exist.
std::string getString(const std::string &name) const
Get a string property, and throw an exception if it does not exist.
int getInteger(const std::string &name) const
Get an integer property, and throw an exception if it does not exist.
Abstract sample generator.
virtual Point2f next2D()=0
Retrieve the next two component values from the current sample.
Main scene data structure.
virtual void activate() override
Invoke a series of t-tests on the provided input.
virtual void addChild(NoriObject *obj) override
Add a child object to the current instance.
virtual EClassType getClassType() const override
Return the type of object (i.e. Mesh/BSDF/etc.) provided by this instance.
virtual std::string toString() const override
Return a brief string summary of the instance (for debugging purposes)
Convenience data structure used to pass multiple parameters to the evaluation and sampling routines i...
Represents a linear RGB color value.
float getLuminance() const
Return the associated luminance.
Data record for conveniently querying and sampling the direct illumination technique implemented by a...
Vector3f wi
Direction between the hit point and the emitter point.
Point3f ref
Origin point from which we sample the emitter.
Ray3f shadowRay
Shadow ray.
Point3f p
Sampled point on the emitter.
VectorType d
Ray direction.
Scalar mint
Minimum position on the ray segment.
Scalar maxt
Maximum position on the ray segment.