Browse code

Add basics

Robert Cranston authored on 25/10/2023 03:01:42
Showing 4 changed files

1 1
new file mode 100644
... ...
@@ -0,0 +1,5 @@
1
+[
2
+    { "include": ["@<glm/detail/.*>",                           "private", "<glm/glm.hpp>", "public"] },
3
+    { "include": ["@<glm/ext/(matrix|vector)_(float|u?int).*>", "private", "<glm/glm.hpp>", "public"] },
4
+]
5
+
... ...
@@ -5,6 +5,8 @@ A [C++11][]/[GLM][] toy [raytracer][].
5 5
 The primary goal is to provide a clear, modular base to try out different
6 6
 experiments on.
7 7
 
8
+![](doc/01_basics.tga)
9
+
8 10
 [`raytracer`]: https://git.rcrnstn.net/rcrnstn/raytracer
9 11
 [C++11]: https://en.wikipedia.org/wiki/C++11
10 12
 [GLM]: https://glm.g-truc.net
11 13
new file mode 100644
12 14
Binary files /dev/null and b/doc/01_basics.tga differ
13 15
new file mode 100644
... ...
@@ -0,0 +1,185 @@
1
+/// Includes
2
+
3
+#include <array>
4
+#include <cstdlib>
5
+#include <fstream>
6
+#include <iostream>
7
+#include <limits>
8
+#include <vector>
9
+
10
+#define GLM_FORCE_SWIZZLE
11
+#define GLM_FORCE_INTRINSICS // For `GLM_SWIZZLE_OPERATOR`.
12
+#include <glm/glm.hpp>
13
+// #include <glm/gtx/io.hpp> // For `operator<<(std::ostream &)`.
14
+
15
+/// Namespaces
16
+
17
+using namespace glm;
18
+
19
+/// Constants
20
+
21
+auto const infinity = std::numeric_limits<float>::infinity();
22
+
23
+/// Types
24
+
25
+//// Ray
26
+struct Ray
27
+{
28
+    vec3 origin;
29
+    vec3 direction;
30
+};
31
+
32
+//// Trace
33
+struct Trace
34
+{
35
+    float distance;
36
+    explicit operator bool() const
37
+    {
38
+        return distance < infinity;
39
+    }
40
+};
41
+
42
+//// Sphere
43
+struct Sphere
44
+{
45
+    vec3  center;
46
+    float radius;
47
+    Trace trace(Ray const & ray) const
48
+    {
49
+        auto const offs = center - ray.origin;
50
+        auto const proj = dot(offs, ray.direction);
51
+        if (proj < 0.0F)
52
+            return {infinity}; // Past.
53
+        auto const perp2 = dot(offs, offs) - proj * proj;
54
+        auto const over2 = radius * radius - perp2;
55
+        if (over2 < 0.0F)
56
+            return {infinity}; // Miss.
57
+        auto const dist = proj - sqrt(over2);
58
+        if (dist < 0.0F)
59
+            return {infinity}; // Inside.
60
+        return {dist}; // Hit.
61
+    }
62
+};
63
+
64
+//// Shapes
65
+using Shapes = std::vector<Sphere>;
66
+
67
+//// Scene
68
+struct Scene
69
+{
70
+    Shapes shapes;
71
+    Trace trace(Ray const & ray) const
72
+    {
73
+        auto nearest = Trace{infinity};
74
+        for (auto const & shape : shapes)
75
+        {
76
+            auto const trace = shape.trace(ray);
77
+            if (trace.distance < nearest.distance)
78
+                nearest = trace;
79
+        }
80
+        return nearest;
81
+    }
82
+};
83
+
84
+//// Camera
85
+struct Camera
86
+{
87
+    uvec2 size;
88
+    Ray ray(vec4 const & frag_coord) const
89
+    {
90
+        auto const point = vec3(
91
+            (2.0F * vec2(frag_coord.xy) - vec2(size)) / float(size.y),
92
+            -1.0F
93
+        );
94
+        auto const origin    = vec3(0.0F);
95
+        auto const direction = normalize(point);
96
+        return Ray{origin, direction};
97
+    }
98
+};
99
+
100
+//// Framebuffer
101
+struct Framebuffer
102
+{
103
+    uvec2               size;
104
+    std::vector<u8vec4> color;
105
+    explicit Framebuffer(uvec2 const & size_)
106
+    :
107
+        size{size_},
108
+        color((std::size_t)(size_.x * size_.y))
109
+    {}
110
+    template<typename Shader>
111
+    void render(Shader const & shader)
112
+    {
113
+        auto const begin = uvec2(0);
114
+        auto const end   = size;
115
+        for (auto y = begin.y; y < end.y; ++y)
116
+        for (auto x = begin.x; x < end.x; ++x)
117
+        {
118
+            auto const index      = size.x * y + x;
119
+            auto const frag_coord = vec4(vec2(x, y) + 0.5F, 0.0F, 1.0F);
120
+            auto const frag_color = vec4(shader(frag_coord).bgra);
121
+            color[index] = clamp(frag_color, 0.0F, 1.0F) * 255.0F + 0.5F;
122
+        }
123
+    }
124
+    void write_tga(char const * path) const
125
+    {
126
+        auto header = std::array<uint8_t, 18>{
127
+            0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128
+            (uint8_t)(size.x >> 0U),
129
+            (uint8_t)(size.x >> 8U),
130
+            (uint8_t)(size.y >> 0U),
131
+            (uint8_t)(size.y >> 8U),
132
+            32, 0,
133
+        };
134
+        auto ostream = std::ofstream(path, std::ios::binary);
135
+        write(ostream, header);
136
+        write(ostream, color);
137
+    }
138
+    template<typename Collection>
139
+    void write(std::ostream & ostream, Collection const & collection) const
140
+    {
141
+        ostream.write(
142
+            (char const *)            collection.data(),
143
+            (std::streamsize)(sizeof(*collection.data()) * collection.size())
144
+        );
145
+    }
146
+};
147
+
148
+/// Main
149
+
150
+int main(int argc, char const * argv[])
151
+{
152
+    //// Arguments
153
+    if (argc != 2)
154
+    {
155
+        std::cerr << "Usage: raytracer <path>" << std::endl;
156
+        return EXIT_FAILURE;
157
+    }
158
+    auto const * path = argv[1]; // NOLINT
159
+    //// Configure
160
+    auto size        = uvec2(640, 480);
161
+    auto framebuffer = Framebuffer(size);
162
+    auto camera      = Camera{size};
163
+    auto scene       = Scene{
164
+        { // shapes
165
+            Sphere{{   6.0F,  -4.0F,  -24.0F}, 12.0F},
166
+            Sphere{{   2.0F,   6.0F,  -16.0F},  8.0F},
167
+            Sphere{{  -4.0F,   0.0F,  -10.0F},  4.0F},
168
+            Sphere{{   0.0F,  -4.0F,   -6.0F},  1.0F},
169
+            Sphere{{  -1.1F,   0.8F,   -1.1F},  0.2F},
170
+            Sphere{{-110.0F, -80.0F, -110.0F}, 20.0F},
171
+        },
172
+    };
173
+    //// Render
174
+    framebuffer.render([&](vec4 const & frag_coord)
175
+    {
176
+        auto const ray   = camera.ray(frag_coord);
177
+        auto const trace = scene.trace(ray);
178
+        auto const rgb   = vec3(1.0F / (1.0F + trace.distance));
179
+        auto const alpha = (bool)trace;
180
+        return vec4(rgb, alpha);
181
+    });
182
+    //// Finalize
183
+    framebuffer.write_tga(path);
184
+    return EXIT_SUCCESS;
185
+}