RayTracer 1.0
Ray tracing is a technique used to generate realistic digital images by simulating the inverse path of light. Our goal is to create a program able to generate an image from a file describing the scene.
 
Loading...
Searching...
No Matches
Main Class Reference

#include <Main.hpp>

Public Member Functions

void printHelp ()
 
void parseArguments (int argc, char **argv, std::string &file, bool &isDebug)
 
void debug_config (const Config::Scene &cfg)
 
void calculPPM (const Config::Scene &cfg, Display &display)
 

Detailed Description

Definition at line 13 of file Main.hpp.

Member Function Documentation

◆ calculPPM()

void Main::calculPPM ( const Config::Scene & cfg,
Display & display )

Definition at line 85 of file main.cpp.

86{
87 RayTracer::Scene scene;
88
89 float aspect = static_cast<float>(cfg.camera.width) / cfg.camera.height;
90 float scale = std::tan((cfg.camera.fieldOfView * 0.5f) * M_PI / 180.0f);
91 Math::Vector3D bs{2.0f * scale * aspect, 0.0f, 0.0f};
92 Math::Vector3D ls{0.0f, 2.0f * scale, 0.0f};
93 Math::Point3D origin{
94 cfg.camera.position.x - bs.x * 0.5f,
95 cfg.camera.position.y - ls.y * 0.5f,
96 cfg.camera.position.z - 1.0f
97 };
98
99 scene.setCamera(
100 RayTracer::Camera(
101 cfg.camera.position,
102 RayTracer::Rectangle3D(origin, bs, ls)
103 )
104 );
105
106 scene.setAmbientLight(
107 std::make_unique<RayTracer::AmbientLight>(
108 static_cast<float>(cfg.ambient)
109 )
110 );
111
112 // Add lights
113 for (const auto &d : cfg.directionals) {
114 scene.addLight(
115 std::make_unique<RayTracer::DirectionalLight>(
116 d.direction,
117 static_cast<float>(cfg.diffuse)
118 )
119 );
120 }
121
122 // Add point lights
123 for (const auto &p : cfg.points) {
124 scene.addLight(
125 std::make_unique<RayTracer::PointLight>(
126 p.position,
127 static_cast<float>(cfg.diffuse)
128 )
129 );
130 }
131
132 for (const auto &s : cfg.spheres) {
133 scene.addObject(
134 std::make_shared<RayTracer::Sphere>(
135 s.center,
136 s.radius,
137 std::make_shared<RayTracer::FlatColor>(s.color)
138 )
139 );
140 }
141
142 for (const auto &p : cfg.planes) {
143 Math::Vector3D normal{0.0f, 0.0f, 0.0f};
144 if (p.axis == 'X') normal.x = 1.0f;
145 else if (p.axis == 'Y') normal.y = 1.0f;
146 else normal.z = 1.0f;
147
148 Math::Point3D pt{0.0f, 0.0f, 0.0f};
149 if (p.axis == 'X') pt.x = p.position;
150 else if (p.axis == 'Y') pt.y = p.position;
151 else pt.z = p.position;
152
153 scene.addObject(
154 std::make_shared<RayTracer::Plane>(
155 pt,
156 normal,
157 std::make_shared<RayTracer::FlatColor>(p.color)
158 )
159 );
160 }
161
162 int w = cfg.camera.width;
163 int h = cfg.camera.height;
164 // std::cout << "P3\n" << w << " " << h << "\n255\n";
165
166 for (int y = 0; y < h; ++y) {
167 for (int x = 0; x < w; ++x) {
168 double u = (x + 0.5) / w;
169 double v = (y + 0.5) / h;
170 RayTracer::Ray ray = scene.getCamera().ray(u, v);
171
172 Color finalColor(0, 0, 0);
173 double closest_t = std::numeric_limits<double>::max();
174 std::shared_ptr<RayTracer::IPrimitive> closestObject = nullptr;
175 Math::Point3D hitPoint;
176 Math::Vector3D normal;
177
178 for (const auto &obj : scene.getObjects()) {
179 double t;
180 Math::Point3D pt;
181 Math::Vector3D n;
182 if (obj->intersect(ray, t, pt, n) && t < closest_t) {
183 closest_t = t;
184 closestObject = obj;
185 hitPoint = pt;
186 normal = n;
187 }
188 }
189
190 if (closestObject) {
191 // Start with ambient
192 if (scene.getAmbient()) {
193 finalColor = scene.getAmbient()->illuminate(ray, *closestObject, hitPoint);
194 }
195 // Lighting
196 for (const auto &light : scene.getLights()) {
197 if (auto *dirLight = dynamic_cast<RayTracer::DirectionalLight *>(light.get())) {
198 Math::Vector3D lightDir = dirLight->getDirection() * -1.0;
199 lightDir = lightDir / lightDir.length();
200
201 // Shadow ray
202 const double bias = 1e-4;
203 Math::Point3D shadowOrigin = hitPoint + normal * bias;
204 RayTracer::Ray shadowRay(shadowOrigin, lightDir);
205 bool shadowed = false;
206
207 for (const auto &obj : scene.getObjects()) {
208 if (obj != closestObject) {
209 double tTmp;
210 Math::Point3D tmpPt;
211 Math::Vector3D tmpN;
212 if (obj->intersect(shadowRay, tTmp, tmpPt, tmpN)) {
213 shadowed = true;
214 break;
215 }
216 }
217 }
218 if (!shadowed) {
219 double diff = std::max(0.0, normal.dot(lightDir));
220 Color lightColor = light->illuminate(ray, *closestObject, hitPoint);
221 finalColor.r = std::min(finalColor.r + static_cast<int>(lightColor.r * diff), 255);
222 finalColor.g = std::min(finalColor.g + static_cast<int>(lightColor.g * diff), 255);
223 finalColor.b = std::min(finalColor.b + static_cast<int>(lightColor.b * diff), 255);
224 }
225
226 } else if (auto *pLight = dynamic_cast<RayTracer::PointLight *>(light.get())) {
227 Math::Vector3D lightDir = pLight->getPosition() - hitPoint;
228 double dist = lightDir.length();
229 lightDir = lightDir / dist;
230
231 const double bias = 1e-4;
232 Math::Point3D shadowOrig = hitPoint + normal * bias;
233 RayTracer::Ray shadowRay(shadowOrig, lightDir);
234 bool inShadow = false;
235 for (const auto &obj : scene.getObjects()) {
236 if (obj != closestObject) {
237 double tTmp;
238 Math::Point3D tmpPt;
239 Math::Vector3D tmpN;
240 if (obj->intersect(shadowRay, tTmp, tmpPt, tmpN) && tTmp < dist) {
241 inShadow = true;
242 break;
243 }
244 }
245 }
246 if (!inShadow) {
247 double diff = std::max(0.0, normal.dot(lightDir));
248 Color c = light->illuminate(ray, *closestObject, hitPoint);
249 finalColor.r = std::min(finalColor.r + static_cast<int>(c.r * diff), 255);
250 finalColor.g = std::min(finalColor.g + static_cast<int>(c.g * diff), 255);
251 finalColor.b = std::min(finalColor.b + static_cast<int>(c.b * diff), 255);
252 }
253 }
254 }
255 }
256
257 display.pushPixel(x, y, Display::Pixel(finalColor.r, finalColor.g, finalColor.b));
258 // std::cout << pixel.toPPM() << "\n";
259 }
260 }
261 display.notifyDone();
262}
int r
Definition Color.hpp:13
int g
Definition Color.hpp:13
int b
Definition Color.hpp:13
Math::Point3D position
std::vector< Plane > planes
std::vector< Point > points
std::vector< Sphere > spheres
std::vector< Directional > directionals
void notifyDone()
Definition Display.cpp:26
void pushPixel(int x, int y, const Pixel &px)
Definition Display.cpp:19
double length() const
Definition Math3D.cpp:15
double dot(const Vector3D &o) const
Definition Math3D.cpp:20

References RayTracer::Scene::addLight(), RayTracer::Scene::addObject(), Config::Scene::ambient, Color::b, Config::Scene::camera, Config::Scene::diffuse, Config::Scene::directionals, Math::Vector3D::dot(), Config::Camera::fieldOfView, Color::g, RayTracer::Scene::getAmbient(), RayTracer::Scene::getCamera(), RayTracer::Scene::getLights(), RayTracer::Scene::getObjects(), Config::Camera::height, Math::Vector3D::length(), Display::notifyDone(), Config::Scene::planes, Config::Scene::points, Config::Camera::position, Display::pushPixel(), Color::r, RayTracer::Camera::ray(), RayTracer::Scene::setAmbientLight(), RayTracer::Scene::setCamera(), Config::Scene::spheres, Config::Camera::width, Math::Point3D::x, Math::Vector3D::x, Math::Point3D::y, and Math::Point3D::z.

◆ debug_config()

void Main::debug_config ( const Config::Scene & cfg)

Definition at line 58 of file main.cpp.

59{
60 std::cout << "CAMERA:\n";
61 std::cout << "resolution: " << cfg.camera.width << " × " << cfg.camera.height << std::endl;
62 std::cout << "position = (" << cfg.camera.position.x << ", " << cfg.camera.position.y << ", " << cfg.camera.position.z << ")\n";
63 std::cout << "rotation = (" << cfg.camera.rotation.x << ", " << cfg.camera.rotation.y << ", " << cfg.camera.rotation.z << ")\n";
64 std::cout << "fieldOfView = " << cfg.camera.fieldOfView << std::endl << std::endl;
65
66 std::cout << "SPHERES:\n";
67 for (const auto &s : cfg.spheres) {
68 std::cout << "centre = (" << s.center.x << ", " << s.center.y << ", " << s.center.z << ")"
69 << " rayon = " << s.radius
70 << " couleur = (" << s.color.r << ", " << s.color.g << ", " << s.color.b << ")\n";
71 }
72
73 std::cout << "PLANES:\n";
74 for (const auto &p : cfg.planes) {
75 std::cout << "axe = '" << p.axis << "'"
76 << " position = " << p.position
77 << " couleur = (" << p.color.r << ", " << p.color.g << ", " << p.color.b << ")\n";
78 }
79
80 std::cout << "LIGHTS:\n";
81 std::cout << "ambient = " << cfg.ambient
82 << " diffuse = " << cfg.diffuse << "\n";
83}
Math::Vector3D rotation

References Config::Scene::ambient, Config::Scene::camera, Config::Scene::diffuse, Config::Camera::fieldOfView, Config::Camera::height, Config::Scene::planes, Config::Camera::position, Config::Camera::rotation, Config::Scene::spheres, Config::Camera::width, Math::Point3D::x, Math::Vector3D::x, Math::Point3D::y, Math::Vector3D::y, Math::Point3D::z, and Math::Vector3D::z.

◆ parseArguments()

void Main::parseArguments ( int argc,
char ** argv,
std::string & file,
bool & isDebug )

Definition at line 32 of file main.cpp.

33{
34 if (argc == 2 && std::string(argv[1]) == "unitest")
35 std::exit(0);
36
37 if (argc == 2 && std::string(argv[1]) == "-help") {
38 printHelp();
39 std::exit(0);
40 }
41
42 if (argc == 3 && std::string(argv[2]) == "-d") {
43 file = argv[1];
44 isDebug = true;
45 return;
46 }
47
48 if (argc != 2) {
49 throw RayTracerException("USAGE: ./raytracer <SCENE_FILE>");
50 }
51
52 file = argv[1];
53 if (!is_valid_cfg(file)) {
54 throw RayTracerException("Error: SCENE_FILE must have .cfg extension");
55 }
56}
bool is_valid_cfg(const std::string &f)
Definition Utils.cpp:10
void printHelp()
Definition main.cpp:26

References is_valid_cfg(), and printHelp().

◆ printHelp()

void Main::printHelp ( )

Definition at line 26 of file main.cpp.

27{
28 std::cout << "USAGE: ./raytracer <SCENE_FILE>\n";
29 std::cout << " SCENE_FILE: scene configuration\n";
30}

The documentation for this class was generated from the following files: