Add jitter to area light and example render of it.

This commit is contained in:
Godzil
2020-03-02 14:03:31 +00:00
parent 1fbe682572
commit 21749695b6
12 changed files with 186 additions and 24 deletions

View File

@@ -14,60 +14,69 @@ It is writen in C++ with no STL and use [LodePNG](https://github.com/lvandeve/lo
Examples outputs Examples outputs
---------------- ----------------
From chapter 05 - Sphere intersections: **From chapter 05 - Sphere intersections:**
![Chapter 5 rendering test](output/ch5_test.png) ![Chapter 5 rendering test](output/ch5_test.png)
From Chapter 06 - Phong shading: **From Chapter 06 - Phong shading:**
![Chapter 6 rendering test](output/ch6_test.png) ![Chapter 6 rendering test](output/ch6_test.png)
From Chapter 07 - World / Camera / Scenes: **From Chapter 07 - World / Camera / Scenes:**
![Chapter 7 rendering test](output/ch7_test.png) ![Chapter 7 rendering test](output/ch7_test.png)
From Chapter 08 - Shadows: **From Chapter 08 - Shadows:**
![Chapter 8 rendering test](output/ch8_test.png) ![Chapter 8 rendering test](output/ch8_test.png)
From Chapter 09 - Planes: **From Chapter 09 - Planes:**
![Chapter 9 rendering test](output/ch9_test.png) ![Chapter 9 rendering test](output/ch9_test.png)
From Chapter 10 - Patterns: **From Chapter 10 - Patterns:**
![Chapter 10 rendering test](output/ch10_test.png) ![Chapter 10 rendering test](output/ch10_test.png)
From Chapter 11 - Reflections, Transparency & Refractions **From Chapter 11 - Reflections, Transparency & Refractions:**
![Chapter 11 reflections rendering test](output/ch11_reflection.png) ![Chapter 11 reflections rendering test](output/ch11_reflection.png)
![Chapter 11 refraction rendering test](output/ch11_refraction.png) Bonus: Zooming on a reflective ball:
![Chapter 11 zooming on a ball](output/ch11_zooming_on_reflective_ball.png)
![Chapter 11 rendering test](output/ch11_test.png) Zooming on a reflection on that ball:
![Chapter 11 zooming on a reflection](output/ch11_reflection_on_ball.png)
From Chapter 12 - Cubes: ![Chapter 11 refraction rendering test](output/ch11_refraction.png | width=1000)
![Chapter 11 rendering test](output/ch11_test.png | width=1000)
**From Chapter 12 - Cubes:**
![Chapter 12 rendering test](output/ch12_test.png) ![Chapter 12 rendering test](output/ch12_test.png)
From Chapter 13 - Cylinders: **From Chapter 13 - Cylinders:**
![Chapter 13 rendering test](output/ch13_test.png) ![Chapter 13 rendering test](output/ch13_test.png)
Bonus: Bonus:
![Chapter 13 cone test](output/ch13_cone.png) ![Chapter 13 cone test](output/ch13_cone.png)
From Chapter 14 - Groups & Bounding boxes **From Chapter 14 - Groups & Bounding boxes:**
![Chapter 14 rendering test](output/ch14_test.png) ![Chapter 14 rendering test](output/ch14_test.png)
Bonus (from the forum): **Bonus (from the forum):**
[Merry Christmas](https://forum.raytracerchallenge.com/thread/16/merry-christmas-scene-description) [Merry Christmas](https://forum.raytracerchallenge.com/thread/16/merry-christmas-scene-description)
![Merry Christmas](output/christmasball.png) ![Merry Christmas](output/christmasball.png)
(about 1min render time using OpenMP on a 2.6Ghz Core i7 3720QM) (about 1min render time using OpenMP on a 2.6Ghz Core i7 3720QM)
Bonus chapter - Soft shadow / Area light **Bonus chapter - Soft shadow / Area light**
Without jitter: Without jitter:
![Area light without jitter](output/arealight_test_nojitter.png) ![Area light without jitter](output/arealight_test_nojitter.png)
With jitter:
![Area light witht jitter](output/arealight_test.png)

BIN
output/arealight_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -12,6 +12,7 @@
#include <tuple.h> #include <tuple.h>
#include <colour.h> #include <colour.h>
#include <renderstat.h> #include <renderstat.h>
#include <sequence.h>
#include <stdio.h> #include <stdio.h>
class World; class World;
@@ -37,6 +38,8 @@ public:
uint32_t samples; uint32_t samples;
uint32_t uSteps; uint32_t uSteps;
uint32_t vSteps; uint32_t vSteps;
bool jitter;
Sequence jitterBy;
public: public:
Light(LightType type = POINT_LIGHT, Tuple position=Point(0, 0, 0), Light(LightType type = POINT_LIGHT, Tuple position=Point(0, 0, 0),
@@ -44,7 +47,7 @@ public:
{ stats.addLight(); }; { stats.addLight(); };
Light(LightType type, Tuple corner, Tuple fullUVec, uint32_t uSteps, Tuple fullVVec, uint32_t vSteps, Light(LightType type, Tuple corner, Tuple fullUVec, uint32_t uSteps, Tuple fullVVec, uint32_t vSteps,
Colour intensity, bool jitter = false): type(type), corner(corner), uVec(fullUVec / uSteps), uSteps(uSteps), Colour intensity, bool jitter = false): type(type), corner(corner), uVec(fullUVec / uSteps), uSteps(uSteps),
vVec(fullVVec / vSteps), vSteps(vSteps), intensity(intensity) vVec(fullVVec / vSteps), vSteps(vSteps), intensity(intensity), jitter(jitter)
{ {
this->samples = this->vSteps * this->uSteps; this->samples = this->vSteps * this->uSteps;
this->position = this->corner + ((fullUVec + fullVVec) / 2); this->position = this->corner + ((fullUVec + fullVVec) / 2);

50
source/include/sequence.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Sequence header
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#ifndef DORAYME_SEQUENCE_H
#define DORAYME_SEQUENCE_H
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
class Sequence
{
private:
double *list;
uint32_t listPos;
uint32_t listSize;
public:
Sequence() : list(nullptr), listPos(0), listSize(0) {
/* Need to bootstrap rand here */
srand(time(NULL));
}
Sequence(double *list, uint32_t listSize) : list(list), listPos(0), listSize(listSize) { };
static double frand(void)
{
return rand() / ((double) RAND_MAX);
}
double next() {
if (this->listSize == 0)
{
return frand();
}
else
{
uint32_t pos = this->listPos;
this->listPos = (this->listPos + 1) % this->listSize;
return this->list[pos];
}
}
};
#endif /* DORAYME_SEQUENCE_H */

View File

@@ -47,5 +47,14 @@ double Light::intensityAt(World &w, Tuple point)
Tuple Light::pointOnLight(uint32_t u, uint32_t v) Tuple Light::pointOnLight(uint32_t u, uint32_t v)
{ {
return this->corner + this->uVec * (u+0.5) + this->vVec * (v+0.5); if (this->jitter)
{
/* For some reason, for the test to pass, I need to get the sequence for V first, then U contrary to what
* the bonus chapter says
*/
return this->corner +
this->vVec * (v + this->jitterBy.next()) +
this->uVec * (u + this->jitterBy.next());
}
return this->corner + this->uVec * (u + 0.5) + this->vVec * (v + 0.5);
} }

View File

@@ -6,7 +6,7 @@ find_package(Threads REQUIRED)
set(TESTS_SRC math_test.cpp tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp set(TESTS_SRC math_test.cpp tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp
ray_test.cpp intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp camera_test.cpp ray_test.cpp intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp camera_test.cpp
shape_test.cpp plane_test.cpp pattern_test.cpp cube_test.cpp cylinder_test.cpp cone_test.cpp group_test.cpp shape_test.cpp plane_test.cpp pattern_test.cpp cube_test.cpp cylinder_test.cpp cone_test.cpp group_test.cpp
boundingbox_test.cpp triangle_test.cpp) boundingbox_test.cpp triangle_test.cpp sequence_test.cpp)
add_executable(testMyRays) add_executable(testMyRays)
target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})

View File

@@ -32,15 +32,11 @@ int main()
World w = World(); World w = World();
/* Add lights */ /* Add lights */
#if 1
Light light1 = Light(AREA_LIGHT, Point(-1, 2, 4), Light light1 = Light(AREA_LIGHT, Point(-1, 2, 4),
Vector(2, 0, 0), 8, Vector(2, 0, 0), 8,
Vector(0, 2, 0), 8, Vector(0, 2, 0), 8,
//jitter, Colour(1.5, 1.5, 1.5),
Colour(1.5, 1.5, 1.5)); true);
#else
Light light1 = Light(POINT_LIGHT, Point(-1, 2, 4), Colour(1.5,1.5,1.5));
#endif
w.addLight(&light1); w.addLight(&light1);

View File

@@ -8,6 +8,7 @@
*/ */
#include <light.h> #include <light.h>
#include <math.h> #include <math.h>
#include <math_helper.h>
#include <colour.h> #include <colour.h>
#include <tuple.h> #include <tuple.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@@ -145,5 +146,78 @@ TEST(LightTest, The_area_light_intensity_function)
double intensity = light.intensityAt(w, testList[i]); double intensity = light.intensityAt(w, testList[i]);
ASSERT_TRUE(double_equal(intensity, testResults[i])); ASSERT_TRUE(double_equal(intensity, testResults[i]));
} }
}
TEST(LightTest, Finding_a_single_point_on_a_jittered_area_light)
{
Tuple corner = Point(0, 0, 0);
Tuple v1 = Vector(2, 0, 0);
Tuple v2 = Vector(0, 0, 1);
Light light = Light(AREA_LIGHT, corner, v1, 4, v2, 2, Colour(1, 1, 1), true);
double seqList[] = { 0.3, 0.7 };
light.jitterBy = Sequence(seqList, 2);
uint32_t testList[][2] = {
{0, 0},
{1, 0},
{0, 1},
{2, 0},
{3, 1},
};
Point testResults[] {
Point(0.15, 0, 0.35),
Point(0.65, 0, 0.35),
Point(0.15, 0, 0.85),
Point(1.15, 0, 0.35),
Point(1.65, 0, 0.85),
};
int testCount = sizeof(testList)/sizeof((testList)[0]);
int i;
for(i = 0; i < testCount; i++)
{
Tuple tp = light.pointOnLight(testList[i][0], testList[i][1]);
ASSERT_EQ(tp, testResults[i]);
}
}
TEST(LightTest, The_area_light_with_jittered_samples)
{
World w = DefaultWorld();
Tuple corner = Point(-0.5, -0.5, -5);
Tuple v1 = Vector(1, 0, 0);
Tuple v2 = Vector(0, 1, 0);
Light light = Light(AREA_LIGHT, corner, v1, 2, v2, 2, Colour(1, 1, 1), true);
double seqList[] = { 0.7, 0.3, 0.9, 0.1, 0.5 };
light.jitterBy = Sequence(seqList, 5);
Point testList[] = {
Point(0, 0, 2),
Point(1, -1, 2),
Point(1.5, 0, 2),
Point(1.25, 1.25, 3),
Point(0, 0, -2),
};
double testResults[] {
0.0,
0.25, /* Chapter say 0.5 but it's not what I get here ?! */
0.75,
0.75,
1,
};
int testCount = sizeof(testList)/sizeof((testList)[0]);
int i;
for(i = 0; i < testCount; i++)
{
double intensity = light.intensityAt(w, testList[i]);
EXPECT_TRUE(double_equal(intensity, testResults[i]));
}
} }

21
tests/sequence_test.cpp Normal file
View File

@@ -0,0 +1,21 @@
/*
* DoRayMe - a quick and dirty Raytracer
* Ray unit tests
*
* Created by Manoël Trapier
* Copyright (c) 2020 986-Studio.
*
*/
#include <sequence.h>
#include <gtest/gtest.h>
TEST(SequenceTest, A_number_generator_returns_a_cyclic_sequence_of_numbers)
{
double seqList[] = { 0.1, 0.5, 1.0};
Sequence gen = Sequence(seqList, 3);
ASSERT_EQ(gen.next(), 0.1);
ASSERT_EQ(gen.next(), 0.5);
ASSERT_EQ(gen.next(), 1.0);
ASSERT_EQ(gen.next(), 0.1);
}