Skip to content
This repository was archived by the owner on May 3, 2020. It is now read-only.

Commit d6eaed9

Browse files
Updated sources
1 parent 8d23b33 commit d6eaed9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+5202
-793
lines changed

.gitlab-ci.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ variables:
5252
- cd Tests/
5353
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"$PWD/Submodules"
5454
- chmod +x Binaries/TraycerTests
55-
- ./Binaries/TraycerTests
55+
- cd Binaries/
56+
- ./TraycerTests
5657
artifacts:
5758
when: on_success
5859
expire_in: 2h

.travis.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,6 @@ install:
3939
- sudo zip -r Traycer:${TRAVIS_OS_NAME}-${TRAVIS_OSX_IMAGE}.zip Traycer
4040

4141
script:
42-
- ./Tests/TraycerTests
42+
- cd Tests/
43+
- ./TraycerTests
4344
- curl -T Traycer*.zip ftp://${FTP_USERNAME}:${FTP_PASSWORD}@${FTP_HOSTNAME}/Traycer_Releases/latest/osx/

Application/main.cpp

+79-280
Original file line numberDiff line numberDiff line change
@@ -1,295 +1,94 @@
1-
#include <cstdio>
2-
#include <cstdlib>
3-
#include <memory>
4-
#include <vector>
5-
#include <utility>
6-
#include <cstdint>
71
#include <iostream>
82
#include <fstream>
9-
#include <cmath>
10-
#include <limits>
11-
#include <random>
123

13-
#include <Core/geometry.hpp>
14-
15-
const float kInfinity = std::numeric_limits<float>::max();
16-
std::random_device rd;
17-
std::mt19937 gen(rd());
18-
std::uniform_real_distribution<> dis(0, 1);
19-
20-
inline
21-
float clamp(const float &lo, const float &hi, const float &v)
22-
{ return std::max(lo, std::min(hi, v)); }
23-
24-
inline
25-
float deg2rad(const float &deg)
26-
{ return deg * M_PI / 180; }
27-
28-
inline
29-
Vec3f mix(const Vec3f &a, const Vec3f& b, const float &mixValue)
30-
{ return a * (1 - mixValue) + b * mixValue; }
31-
32-
struct Options
33-
{
34-
uint32_t width;
35-
uint32_t height;
36-
float fov;
37-
Matrix44f cameraToWorld;
38-
};
39-
40-
// [comment]
41-
// Object base class
42-
// [/comment]
43-
class Object
44-
{
45-
public:
46-
Object() : color(dis(gen), dis(gen), dis(gen)) {}
47-
virtual ~Object() {}
48-
// Method to compute the intersection of the object with a ray
49-
// Returns true if an intersection was found, false otherwise
50-
// See method implementation in children class for details
51-
virtual bool intersect(const Vec3f &, const Vec3f &, float &) const = 0;
52-
// Method to compute the surface data such as normal and texture coordnates at the intersection point.
53-
// See method implementation in children class for details
54-
virtual void getSurfaceData(const Vec3f &, Vec3f &, Vec2f &) const = 0;
55-
Vec3f color;
56-
};
57-
58-
// [comment]
59-
// Compute the roots of a quadratic equation
60-
// [/comment]
61-
bool solveQuadratic(const float &a, const float &b, const float &c, float &x0, float &x1)
62-
{
63-
float discr = b * b - 4 * a * c;
64-
if (discr < 0) return false;
65-
else if (discr == 0) {
66-
x0 = x1 = - 0.5 * b / a;
67-
}
68-
else {
69-
float q = (b > 0) ?
70-
-0.5 * (b + sqrt(discr)) :
71-
-0.5 * (b - sqrt(discr));
72-
x0 = q / a;
73-
x1 = c / q;
74-
}
75-
76-
return true;
77-
}
78-
79-
// [comment]
80-
// Sphere class. A sphere type object
81-
// [/comment]
82-
class Sphere : public Object
83-
{
84-
public:
85-
Sphere(const Vec3f &c, const float &r) : radius(r), radius2(r *r ), center(c) {}
86-
// [comment]
87-
// Ray-sphere intersection test
88-
//
89-
// \param orig is the ray origin
90-
//
91-
// \param dir is the ray direction
92-
//
93-
// \param[out] is the distance from the ray origin to the intersection point
94-
//
95-
// [/comment]
96-
bool intersect(const Vec3f &orig, const Vec3f &dir, float &t) const
97-
{
98-
float t0, t1; // solutions for t if the ray intersects
99-
#if 0
100-
// geometric solution
101-
Vec3f L = center - orig;
102-
float tca = L.dotProduct(dir);
103-
if (tca < 0) return false;
104-
float d2 = L.dotProduct(L) - tca * tca;
105-
if (d2 > radius2) return false;
106-
float thc = sqrt(radius2 - d2);
107-
t0 = tca - thc;
108-
t1 = tca + thc;
109-
#else
110-
// analytic solution
111-
Vec3f L = orig - center;
112-
float a = dir.dotProduct(dir);
113-
float b = 2 * dir.dotProduct(L);
114-
float c = L.dotProduct(L) - radius2;
115-
if (!solveQuadratic(a, b, c, t0, t1)) return false;
116-
#endif
117-
if (t0 > t1) std::swap(t0, t1);
118-
119-
if (t0 < 0) {
120-
t0 = t1; // if t0 is negative, let's use t1 instead
121-
if (t0 < 0) return false; // both t0 and t1 are negative
122-
}
123-
124-
t = t0;
125-
126-
return true;
127-
}
128-
// [comment]
129-
// Set surface data such as normal and texture coordinates at a given point on the surface
130-
//
131-
// \param Phit is the point ont the surface we want to get data on
132-
//
133-
// \param[out] Nhit is the normal at Phit
134-
//
135-
// \param[out] tex are the texture coordinates at Phit
136-
//
137-
// [/comment]
138-
void getSurfaceData(const Vec3f &Phit, Vec3f &Nhit, Vec2f &tex) const
139-
{
140-
Nhit = Phit - center;
141-
Nhit.normalize();
142-
// In this particular case, the normal is simular to a point on a unit sphere
143-
// centred around the origin. We can thus use the normal coordinates to compute
144-
// the spherical coordinates of Phit.
145-
// atan2 returns a value in the range [-pi, pi] and we need to remap it to range [0, 1]
146-
// acosf returns a value in the range [0, pi] and we also need to remap it to the range [0, 1]
147-
tex.x = (1 + atan2(Nhit.z, Nhit.x) / M_PI) * 0.5;
148-
tex.y = acosf(Nhit.y) / M_PI;
149-
}
150-
float radius, radius2;
151-
Vec3f center;
152-
};
153-
154-
// [comment]
155-
// Returns true if the ray intersects an object. The variable tNear is set to the closest intersection distance and hitObject
156-
// is a pointer to the intersected object. The variable tNear is set to infinity and hitObject is set null if no intersection
157-
// was found.
158-
// [/comment]
159-
bool trace(const Vec3f &orig, const Vec3f &dir, const std::vector<std::unique_ptr<Object>> &objects, float &tNear, const Object *&hitObject)
160-
{
161-
tNear = kInfinity;
162-
std::vector<std::unique_ptr<Object>>::const_iterator iter = objects.begin();
163-
for (; iter != objects.end(); ++iter) {
164-
float t = kInfinity;
165-
if ((*iter)->intersect(orig, dir, t) && t < tNear) {
166-
hitObject = iter->get();
167-
tNear = t;
168-
}
169-
}
170-
171-
return (hitObject != nullptr);
172-
}
173-
174-
// [comment]
175-
// Compute the color at the intersection point if any (returns background color otherwise)
176-
// [/comment]
177-
Vec3f castRay(
178-
const Vec3f &orig, const Vec3f &dir,
179-
const std::vector<std::unique_ptr<Object>> &objects)
180-
{
181-
Vec3f hitColor = 0;
182-
const Object *hitObject = nullptr; // this is a pointer to the hit object
183-
float t; // this is the intersection distance from the ray origin to the hit point
184-
if (trace(orig, dir, objects, t, hitObject)) {
185-
Vec3f Phit = orig + dir * t;
186-
Vec3f Nhit;
187-
Vec2f tex;
188-
hitObject->getSurfaceData(Phit, Nhit, tex);
189-
// Use the normal and texture coordinates to shade the hit point.
190-
// The normal is used to compute a simple facing ratio and the texture coordinate
191-
// to compute a basic checker board pattern
192-
float scale = 4;
193-
float pattern = (fmodf(tex.x * scale, 1) > 0.5) ^ (fmodf(tex.y * scale, 1) > 0.5);
194-
hitColor = std::max(0.f, Nhit.dotProduct(-dir)) * mix(hitObject->color, hitObject->color * 0.8, pattern);
4+
#include <Core/Camera.hpp>
5+
#include <Core/Constants.hpp>
6+
#include <Core/Parser.hpp>
7+
#include <Core/Renderer.hpp>
8+
#include <Core/Scene.hpp>
9+
#include <Lights/AmbientLight.hpp>
10+
#include <Lights/AreaLight.hpp>
11+
#include <Shapes/Sphere.hpp>
12+
13+
void Scene1(int width, int height, float fov, int samples);
14+
15+
int main(int argc, char * argv[]) {
16+
if(Parser::hasOption(argv, argv + argc, "--help")) {
17+
std::cout << "Usage: " << argv[0];
18+
std::cout << " [-s samples=" << DEFAULT_SAMPLES << "]";
19+
std::cout << " [-w width=" << DEFAULT_WIDTH << "]";
20+
std::cout << " [-h height=" << DEFAULT_HEIGHT << "]";
21+
std::cout << " [-f fov=" << DEFAULT_FOV << "]";
22+
std::cout << " [--help]" << std::endl;
23+
24+
return EXIT_SUCCESS;
19525
}
19626

197-
return hitColor;
198-
}
199-
200-
// [comment]
201-
// The main render function. This where we iterate over all pixels in the image, generate
202-
// primary rays and cast these rays into the scene. The content of the framebuffer is
203-
// saved to a file.
204-
// [/comment]
205-
void render(
206-
const Options &options,
207-
const std::vector<std::unique_ptr<Object>> &objects)
208-
{
209-
Vec3f *framebuffer = new Vec3f[options.width * options.height];
210-
Vec3f *pix = framebuffer;
211-
float scale = tan(deg2rad(options.fov * 0.5));
212-
float imageAspectRatio = options.width / (float)options.height;
213-
// [comment]
214-
// Don't forget to transform the ray origin (which is also the camera origin
215-
// by transforming the point with coordinates (0,0,0) to world-space using the
216-
// camera-to-world matrix.
217-
// [/comment]
218-
Vec3f orig;
219-
options.cameraToWorld.multVecMatrix(Vec3f(0), orig);
220-
for (uint32_t j = 0; j < options.height; ++j) {
221-
for (uint32_t i = 0; i < options.width; ++i) {
222-
// [comment]
223-
// Generate primary ray direction. Compute the x and y position
224-
// of the ray in screen space. This gives a point on the image plane
225-
// at z=1. From there, we simply compute the direction by normalized
226-
// the resulting vec3f variable. This is similar to taking the vector
227-
// between the point on the image plane and the camera origin, which
228-
// in camera space is (0,0,0):
229-
//
230-
// ray.dir = normalize(Vec3f(x,y,-1) - Vec3f(0));
231-
// [/comment]
232-
#ifdef MAYA_STYLE
233-
float x = (2 * (i + 0.5) / (float)options.width - 1) * scale;
234-
float y = (1 - 2 * (j + 0.5) / (float)options.height) * scale * 1 / imageAspectRatio;
235-
#else
236-
237-
float x = (2 * (i + 0.5) / (float)options.width - 1) * imageAspectRatio * scale;
238-
float y = (1 - 2 * (j + 0.5) / (float)options.height) * scale;
239-
#endif
240-
// [comment]
241-
// Don't forget to transform the ray direction using the camera-to-world matrix.
242-
// [/comment]
243-
Vec3f dir;
244-
options.cameraToWorld.multDirMatrix(Vec3f(x, y, -1), dir);
245-
dir.normalize();
246-
*(pix++) = castRay(orig, dir, objects);
247-
}
248-
}
27+
char * s = Parser::getOption(argv, argv + argc, "-s");
28+
char * w = Parser::getOption(argv, argv + argc, "-w");
29+
char * h = Parser::getOption(argv, argv + argc, "-h");
30+
char * f = Parser::getOption(argv, argv + argc, "-f");
24931

250-
// Save result to a PPM image (keep these flags if you compile under Windows)
251-
std::ofstream ofs("./out.ppm", std::ios::out | std::ios::binary);
252-
ofs << "P6\n" << options.width << " " << options.height << "\n255\n";
253-
for (uint32_t i = 0; i < options.height * options.width; ++i) {
254-
char r = (char)(255 * clamp(0, 1, framebuffer[i].x));
255-
char g = (char)(255 * clamp(0, 1, framebuffer[i].y));
256-
char b = (char)(255 * clamp(0, 1, framebuffer[i].z));
257-
ofs << r << g << b;
258-
}
32+
int samples = (s) ? std::atoi(s) : DEFAULT_SAMPLES;
33+
int width = (w) ? std::atoi(w) : DEFAULT_WIDTH;
34+
int height = (h) ? std::atoi(h) : DEFAULT_HEIGHT;
35+
float fov = (f) ? (float)(std::atoi(f)) : DEFAULT_FOV;
25936

260-
ofs.close();
37+
Scene1(width, height, fov, samples);
26138

262-
delete [] framebuffer;
39+
return EXIT_SUCCESS;
26340
}
26441

265-
// [comment]
266-
// In the main function of the program, we create the scene (create objects)
267-
// as well as set the options for the render (image widht and height etc.).
268-
// We then call the render function().
269-
// [/comment]
270-
int main(int argc, char **argv)
271-
{
272-
// creating the scene (adding objects and lights)
273-
std::vector<std::unique_ptr<Object>> objects;
42+
auto updateProgress = [](float progress) {
43+
int progressValue = (int)(progress * 100);
27444

275-
// generate a scene made of random spheres
276-
uint32_t numSpheres = 32;
277-
gen.seed(0);
278-
for (uint32_t i = 0; i < numSpheres; ++i) {
279-
Vec3f randPos((0.5 - dis(gen)) * 10, (0.5 - dis(gen)) * 10, (0.5 + dis(gen) * 10));
280-
float randRadius = (0.5 + dis(gen) * 0.5);
281-
objects.push_back(std::unique_ptr<Object>(new Sphere(randPos, randRadius)));
45+
std::cout << " |";
46+
for(int i = 0 ; i < 100 ; i += 2) {
47+
std::cout << (i < progressValue ? "=" : "-");
28248
}
49+
std::cout << "| " << progressValue << " %\r";
28350

284-
// setting up options
285-
Options options;
286-
options.width = 640;
287-
options.height = 480;
288-
options.fov = 51.52;
289-
options.cameraToWorld = Matrix44f(0.945519, 0, -0.325569, 0, -0.179534, 0.834209, -0.521403, 0, 0.271593, 0.551447, 0.78876, 0, 4.208271, 8.374532, 17.932925, 1);
290-
291-
// finally, render
292-
render(options, objects);
51+
std::cout.flush();
52+
};
29353

294-
return 0;
54+
void Scene1(int width, int height, float fov, int samples) {
55+
std::cout << "Generating scene..." << std::endl;
56+
std::clock_t t = std::clock();
57+
58+
Scene scene = Scene();
59+
60+
Sphere s0 = Sphere( Vector3(0, -10008, 20), 10000, Color(20, 120, 100), 0.2, 0.5, 0.0, 128.0, 0.0);
61+
Sphere s1 = Sphere( Vector3(0, 0, 20), 4, Color(165, 10, 14), 0.3, 0.8, 0.5, 128.0, 0.4);
62+
Sphere s2 = Sphere( Vector3(5, -1, 15), 2, Color(235, 179, 41), 0.4, 0.6, 0.4, 128.0, 0.4);
63+
Sphere s3 = Sphere( Vector3(5, 0, 25), 3, Color(6, 72, 111), 0.3, 0.8, 0.1, 128.0, 0.4);
64+
s3.setGlossiness(0.1);
65+
Sphere s4 = Sphere( Vector3(-3.5, -1, 10), 2, Color(8, 88, 56), 0.4, 0.6, 0.5, 64.0, 0.4);
66+
Sphere s5 = Sphere( Vector3(-5.5, 0, 15), 3, Color(51, 51, 51), 0.3, 0.8, 0.25, 32.0, 0.0);
67+
68+
scene.addObject( &s0 );
69+
scene.addObject( &s1 );
70+
scene.addObject( &s2 );
71+
scene.addObject( &s3 );
72+
scene.addObject( &s4 );
73+
scene.addObject( &s5 );
74+
75+
// Add light to scene
76+
scene.addAmbientLight ( AmbientLight( Vector3(1.0) ) );
77+
AreaLight l0 = AreaLight( Vector3(0, 20, 35), Vector3(1.4) );
78+
AreaLight l1 = AreaLight( Vector3(20, 20, 35), Vector3(1.8) );
79+
scene.addLight( &l0 );
80+
scene.addLight( &l1 );
81+
82+
// Add camera
83+
Camera camera = Camera( Vector3(0,0,-20), width, height, fov);
84+
camera.setPosition(Vector3(0, 20, -20));
85+
camera.setAngleX(30 * M_PI / 180.0);
86+
87+
// Create Renderer
88+
Renderer r = Renderer(width, height, scene, camera);
89+
r.render(samples, updateProgress);
90+
91+
t = std::clock() - t;
92+
std::cout << std::endl << "Scene complete." << std::endl << std::endl;
93+
std::cout << "Time ellpased: " << ((float)t) / CLOCKS_PER_SEC << " seconds." << std::endl;
29594
}

0 commit comments

Comments
 (0)