Skip to content

Commit 4cf4c8b

Browse files
Merge pull request #6 from TolyaTalamanov/at/raytracer-tool
Raytracer tool initial version
2 parents 1d9cd88 + 40d7835 commit 4cf4c8b

10 files changed

+111
-22
lines changed

CMakeLists.txt

+8-1
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,21 @@ set(SRC_FILES
3535

3636
set(Raytracer_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include/")
3737
add_library(${PROJECT_NAME} SHARED ${SRC_FILES})
38+
3839
# Set public API
3940
target_include_directories(${PROJECT_NAME}
4041
PUBLIC ${Raytracer_INCLUDE_DIR}
4142
PRIVATE "${PROJECT_SOURCE_DIR}/src")
4243
# Add dependencies
4344
find_package(PNG REQUIRED)
4445
find_package(JPEG REQUIRED)
45-
target_link_libraries(${PROJECT_NAME} ${PNG_LIBRARY} ${JPEG_LIBRARIES})
46+
target_link_libraries(${PROJECT_NAME} PRIVATE ${PNG_LIBRARY} ${JPEG_LIBRARIES})
47+
48+
find_package(OpenMP)
49+
if(OpenMP_CXX_FOUND)
50+
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
51+
endif()
52+
4653

4754
########################################
4855
# Add thirdparty

include/raytracer/geometry.hpp

+14-3
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,20 @@ class Triangle : public Object {
155155
std::optional<ExplicitNormals> has_normals;
156156
};
157157

158-
struct Scene {
159-
Objects objects;
160-
Lights lights;
158+
class Scene {
159+
public:
160+
Scene(Objects&& eobjects,
161+
Lights&& lights,
162+
std::vector<GeometricVertex>&& geom_vertices);
163+
164+
const Objects& GetObjects() const;
165+
const Lights& GetLights() const;
166+
const std::vector<GeometricVertex>& GetGeometricVertices() const;
167+
168+
private:
169+
Objects _objects;
170+
Lights _lights;
171+
std::vector<GeometricVertex> _geom_vertices;
161172
};
162173

163174
Vec3f Refract(const Vec3f& I, const Vec3f& N, double ior);

include/raytracer/raytracer.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
#include <raytracer/image.hpp>
22
#include <raytracer/options.hpp>
33
#include <raytracer/render.hpp>
4+
#include <raytracer/parser.hpp>

include/raytracer/render.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
#include <raytracer/options.hpp>
44
#include <raytracer/image.hpp>
55
#include <raytracer/datatypes.hpp>
6+
#include <raytracer/geometry.hpp>
67

78
Image Render(const std::string& filename, const CameraOptions& camera_options, const RenderOptions& render_options);
9+
Image Render(const Scene& scene, const CameraOptions& camera_options, const RenderOptions& render_options);

main.cpp

+35-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
#include <iostream>
2+
#include <chrono>
3+
4+
#include <raytracer/raytracer.hpp>
5+
6+
static Vec3f GetCenter(const Scene& scene) {
7+
Vec3f c{0, 0, 0};
8+
for (auto&& v : scene.GetGeometricVertices()) {
9+
c = c + Vec3f{v.x, v.y, v.z};
10+
}
11+
return c / scene.GetGeometricVertices().size();
12+
}
13+
14+
int main(int argc, const char** argv) {
15+
CameraOptions camera_opts(500, 500);
16+
RenderOptions render_opts{3};
17+
18+
const std::string obj_filename = argv[1];
19+
const auto scene = Parse(obj_filename);
20+
const auto center = GetCenter(scene);
21+
22+
std::cout << "Object center is: " << center << std::endl;
23+
24+
camera_opts.look_from = std::array<double, 3>{std::stod(argv[2]),
25+
std::stod(argv[3]),
26+
std::stod(argv[4])};
27+
camera_opts.look_to = std::array<double, 3>{center.x, center.y, center.z};
28+
29+
using namespace std::chrono;
30+
auto start = high_resolution_clock::now();
31+
auto image = Render(obj_filename, camera_opts, render_opts);
32+
auto end = high_resolution_clock::now();
33+
auto elapsed = duration_cast<milliseconds>(end-start).count();
34+
image.Write("output.png");
35+
36+
std::cout << "Elapsed time: " << elapsed << " ms" << std::endl;
237

3-
int main() {
4-
std::cout << "Raytracing sample application" << std::endl;
538
return 0;
639
}

src/builder.cpp

+3-6
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,11 @@ SceneBuilder& SceneBuilder::Add(const SphereElement& s) {
3838
}
3939

4040
SceneBuilder& SceneBuilder::Add(const FaceElement& f) {
41-
if (f.vertices.size() != 3u && f.vertices.size() != 4u) {
42-
throw std::logic_error("Only 3 or 4 vertex face elements are supported!");
43-
}
44-
4541
std::vector<int> indices;
4642
for (int i = 0; i < f.vertices.size(); ++i) {
4743
indices.push_back(GetNormalizedIndex(f.vertices[i].v, _state->geom_vertices.size()));
4844
}
4945

50-
// FIXME: 2 iteration maximum, reorganize this loop.
5146
for (int i = 0; i < f.vertices.size()-2; ++i) {
5247
std::array<GeometricVertex, 3> v = {_state->geom_vertices[indices[0 ]],
5348
_state->geom_vertices[indices[i+1]],
@@ -76,7 +71,9 @@ SceneBuilder& SceneBuilder::Add(const FaceElement& f) {
7671
}
7772

7873
Scene SceneBuilder::Finalize() {
79-
Scene scene{std::move(_state->objects), std::move(_state->lights)};
74+
Scene scene{std::move(_state->objects),
75+
std::move(_state->lights),
76+
std::move(_state->geom_vertices)};
8077
_state.reset(new State{});
8178
return scene;
8279
}

src/geometry.cpp

+25-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
#include <raytracer/geometry.hpp>
2-
#include <iostream>
2+
3+
Scene::Scene(Objects&& objects,
4+
Lights&& lights,
5+
std::vector<GeometricVertex>&& geom_vertices)
6+
: _objects(std::move(objects)),
7+
_lights(std::move(lights)),
8+
_geom_vertices(std::move(geom_vertices)) {
9+
}
10+
11+
const Objects& Scene::GetObjects() const {
12+
return _objects;
13+
}
14+
15+
const Lights& Scene::GetLights() const {
16+
return _lights;
17+
}
18+
19+
const std::vector<GeometricVertex>& Scene::GetGeometricVertices() const {
20+
return _geom_vertices;
21+
}
322

423
Vec3f Ray::at(double t) const {
524
return orig + dir * t;
@@ -127,7 +146,8 @@ std::optional<HitInfo> Triangle::intersect(const Ray& ray) {
127146
double t = v0v2.dot(qvec) * invDet;
128147
auto P = ray.at(t);
129148

130-
if (t < 0) {
149+
// FIXME: From where this nan appears ???
150+
if (t < 0 || std::isnan(t)) {
131151
return {};
132152
}
133153

@@ -262,7 +282,7 @@ Vec3f Trace(const Ray& ray,
262282
HitInfo info;
263283
double distance = std::numeric_limits<double>::max();
264284

265-
for (auto&& obj : scene.objects) {
285+
for (auto&& obj : scene.GetObjects()) {
266286
auto has_hit = obj->intersect(ray);
267287
if (!has_hit) {
268288
continue;
@@ -329,12 +349,12 @@ Vec3f Trace(const Ray& ray,
329349
Icomp += refrc * Tr;
330350
}
331351

332-
for (auto&& light : scene.lights) {
352+
for (auto&& light : scene.GetLights()) {
333353
Vec3f new_p = info.position + ((ray.orig - info.position).normalize() * 0.00001);
334354
Vec3f newp2light = (light.position - new_p).normalize();
335355

336356
bool no_intersect = false;
337-
for (const auto& obj : scene.objects) {
357+
for (const auto& obj : scene.GetObjects()) {
338358
auto has_hit = obj->intersect(Ray{new_p, newp2light});
339359
if (!has_hit) {
340360
continue;

src/parser.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <unordered_set>
22
#include <unordered_map>
3+
#include <iostream>
34

45
#include <cassert>
56

@@ -186,6 +187,9 @@ static void ParseNewmtl(Tokenizer* tokenizer,
186187
mtl.map_Ka = std::make_optional(ParseImageFile(tokenizer, dir));
187188
} else if (param == "map_bump") {
188189
mtl.map_bump = std::make_optional(ParseImageFile(tokenizer, dir));
190+
} else if (param == "bump") {
191+
std::cout << "Ignore bump parameter in mtl file" << std::endl;
192+
(void)ParseImageFile(tokenizer, dir);
189193
} else {
190194
throw std::logic_error("Unsupported newmtl parameter : " + param);
191195
}
@@ -312,9 +316,10 @@ Scene Parse(std::istream* stream, const std::string& mtldir) {
312316
throw std::logic_error("Next token after usemtl should be Tokenizer::String");
313317
}
314318

315-
auto it = materials.find(std::get<Tokenizer::String>(tok).str);
319+
const auto& mat_name = std::get<Tokenizer::String>(tok).str;
320+
auto it = materials.find(mat_name);
316321
if (it == materials.end()) {
317-
throw std::logic_error("Failed to find material with name: " + it->first);
322+
throw std::logic_error("Failed to find material with name: " + mat_name);
318323
}
319324
builder.UseMaterial(it->second);
320325
} else if (keyword == "S") {

src/render.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ static void postprocessing(Matf& mat) {
4545
}
4646
}
4747

48-
Image Render(const std::string& filename, const CameraOptions& camera_options,
48+
Image Render(const Scene& scene,
49+
const CameraOptions& camera_options,
4950
const RenderOptions& render_options) {
5051
int width = camera_options.screen_width;
5152
int height = camera_options.screen_height;
@@ -64,15 +65,14 @@ Image Render(const std::string& filename, const CameraOptions& camera_options,
6465
Image img(width, height);
6566
Matf mat(width, height);
6667

67-
const auto scene = Parse(filename);
68-
6968
double scale = std::tan(fov * 0.5);
7069
double ratio = width / static_cast<double>(height);
7170

7271
Vec3f forward = (from - to).normalize();
7372
Vec3f right = tmp.cross(forward).normalize();
7473
Vec3f up = forward.cross(right).normalize();
7574

75+
#pragma omp parallel for
7676
for (int j = 0; j < height; ++j) {
7777
for (int i = 0; i < width; ++i) {
7878
// FIXME: Should it be without static_cast ???
@@ -112,3 +112,9 @@ Image Render(const std::string& filename, const CameraOptions& camera_options,
112112

113113
return img;
114114
}
115+
116+
Image Render(const std::string& filename, const CameraOptions& camera_options,
117+
const RenderOptions& render_options) {
118+
const auto scene = Parse(filename);
119+
return Render(Parse(filename), camera_options, render_options);
120+
}

tests/test_tokenizer.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,10 @@ TEST(TokenizerTests, NextLineBeforeEnd) {
121121

122122
EXPECT_TRUE(t.IsEnd());
123123
}
124+
125+
TEST(TokenizerTests, ParseStringStartsWithNumber) {
126+
std::stringstream ss{"1212_foo"};
127+
Tokenizer t(&ss);
128+
129+
EXPECT_EQ("1212_foo", std::get<Tokenizer::String>(t.GetToken()).str);
130+
}

0 commit comments

Comments
 (0)