Browse code

Add edge anti-aliasing

Robert Cranston authored on 27/10/2023 11:08:47
Showing 1 changed files
... ...
@@ -56,6 +56,7 @@ struct Trace
56 56
 {
57 57
     float    distance;
58 58
     Material material;
59
+    vec3     miss;
59 60
 };
60 61
 
61 62
 //// Circle
... ...
@@ -69,15 +70,20 @@ struct Circle
69 70
         auto const offs = center - ray.origin;
70 71
         auto const proj = dot(offs, ray.direction);
71 72
         if (proj < 0.0F) // Past.
72
-            return {infinity, {}};
73
+            return {infinity, {}, {}};
73 74
         auto const perp2 = dot(offs, offs) - proj * proj;
74 75
         auto const pene2 = radius * radius - perp2;
75 76
         if (pene2 < 0.0F) // Miss.
76
-            return {infinity, {}};
77
+        {
78
+            auto const poin = ray.point(proj);
79
+            auto const rati = 1.0F - radius * inversesqrt(perp2);
80
+            auto const miss = rati * (center - poin);
81
+            return {proj, material, miss};
82
+        }
77 83
         auto const dist = proj - sqrt(pene2);
78 84
         if (dist < 0.0F) // Inside.
79
-            return {infinity, {}};
80
-        return {dist, material};
85
+            return {infinity, {}, {}};
86
+        return {dist, material, vec3(0.0F)};
81 87
     }
82 88
 };
83 89
 
... ...
@@ -91,7 +97,7 @@ struct Scene
91 97
     Shapes   shapes;
92 98
     Trace trace(Ray const & ray) const
93 99
     {
94
-        auto nearest = Trace{infinity, background};
100
+        auto nearest = Trace{infinity, background, {}};
95 101
         for (auto const & shape : shapes)
96 102
         {
97 103
             auto const trace = shape.trace(ray);
... ...
@@ -122,6 +128,16 @@ struct Camera
122 128
         auto const direction = normalize(world.xyz() - position);
123 129
         return Ray{position, direction};
124 130
     }
131
+    vec2 project(uvec2 const & size, vec3 const & point) const
132
+    {
133
+        auto const aspect   = (float)size.x / (float)size.y;
134
+        auto const viewport = uvec4(0, 0, size);
135
+        auto const up       = vec3(0.0F, 1.0F, 0.0F);
136
+        auto const view     = glm::lookAt(position, target, up);
137
+        auto const proj     = glm::perspective(fovy, aspect, near, far);
138
+        auto const window   = glm::project(point, view, proj, viewport);
139
+        return window.xy();
140
+    }
125 141
 };
126 142
 
127 143
 //// ACES
... ...
@@ -220,6 +236,15 @@ int main(int argc, char const * argv[])
220 236
         {
221 237
             auto trace = scene.trace(ray);
222 238
             auto color = trace.material.color;
239
+            if (trace.miss != vec3(0.0F))
240
+            {
241
+                auto const point = ray.point(trace.distance);
242
+                auto const dist  = distance(
243
+                    camera.project(size, point),
244
+                    camera.project(size, point + trace.miss)
245
+                );
246
+                color.a *= 1.0F - clamp(dist, 0.0F, 1.0F);
247
+            }
223 248
             rgb   += color.rgb() * color.a * trans;
224 249
             trans *= 1.0F - color.a;
225 250
             if (trace.distance == infinity || trans == 0.0F)
Browse code

Add transparency

Robert Cranston authored on 27/10/2023 11:08:02
Showing 1 changed files
... ...
@@ -25,6 +25,7 @@ using namespace glm;
25 25
 /// Constants
26 26
 
27 27
 auto const infinity = std::numeric_limits<float>::infinity();
28
+auto const delta    = 0.001F;
28 29
 
29 30
 
30 31
 /// Types
... ...
@@ -34,12 +35,20 @@ struct Ray
34 35
 {
35 36
     vec3 origin;
36 37
     vec3 direction;
38
+    vec3 point(float distance) const
39
+    {
40
+        return origin + direction * distance;
41
+    }
42
+    Ray resumed(float distance)
43
+    {
44
+        return {point(distance), direction};
45
+    }
37 46
 };
38 47
 
39 48
 //// Material
40 49
 struct Material
41 50
 {
42
-    vec3 color;
51
+    vec4 color;
43 52
 };
44 53
 
45 54
 //// Trace
... ...
@@ -191,24 +200,34 @@ int main(int argc, char const * argv[])
191 200
     };
192 201
     auto const scene = Scene{
193 202
         // background
194
-        {vec3(0.2F, 0.2F, 0.5F)},
203
+        {vec4(0.2F, 0.2F, 0.5F, 0.5F)},
195 204
         // shapes
196 205
         {
197
-            {vec3( 2.0F, -1.0F, -10.0F), 3.0F, {vec3(1.0F, 0.0F, 0.0F)}},
198
-            {vec3( 1.0F,  2.0F,  -7.0F), 2.0F, {vec3(0.0F, 1.0F, 0.0F)}},
199
-            {vec3(-1.0F,  0.0F,  -4.0F), 1.0F, {vec3(0.0F, 0.0F, 1.0F)}},
200
-            {vec3( 0.0F, -1.0F,  -3.0F), 0.2F, {vec3(0.0F, 1.0F, 1.0F)}},
206
+            {vec3( 2.0F, -1.0F, -10.0F), 3.0F, {vec4(1.0F, 0.0F, 0.0F, 1.0F)}},
207
+            {vec3( 1.0F,  2.0F,  -7.0F), 2.0F, {vec4(0.0F, 1.0F, 0.0F, 1.0F)}},
208
+            {vec3(-1.0F,  0.0F,  -4.0F), 1.0F, {vec4(0.0F, 0.0F, 1.0F, 1.0F)}},
209
+            {vec3( 0.0F, -1.0F,  -3.0F), 0.2F, {vec4(0.0F, 1.0F, 1.0F, 0.5F)}},
201 210
         },
202 211
     };
203 212
     auto const tonemap = ACES{vec3(1.0F)};
204 213
     auto const output  = TGA{uvec2(640, 480), path};
205 214
     //// Render
206 215
     output.render([&](uvec2 const & size, uvec2 const & pixel) {
207
-        auto const ray   = camera.ray(size, pixel);
208
-        auto const trace = scene.trace(ray);
209
-        auto const rgb   = trace.material.color;
210
-        auto const srgb  = convertLinearToSRGB(tonemap.transform(rgb));
211
-        auto const alpha = 1.0F;
216
+        auto rgb   = vec3(0.0F); // Pre-multiplied alpha (opacity).
217
+        auto trans = 1.0F;       // 1 - alpha (opacity).
218
+        auto ray   = camera.ray(size, pixel);
219
+        while (true)
220
+        {
221
+            auto trace = scene.trace(ray);
222
+            auto color = trace.material.color;
223
+            rgb   += color.rgb() * color.a * trans;
224
+            trans *= 1.0F - color.a;
225
+            if (trace.distance == infinity || trans == 0.0F)
226
+                break;
227
+            ray = ray.resumed(trace.distance + delta);
228
+        }
229
+        auto const alpha = 1.0F - trans;
230
+        auto const srgb  = convertLinearToSRGB(tonemap.transform(rgb / alpha));
212 231
         return vec4(srgb, alpha);
213 232
     });
214 233
 }
Browse code

Add material color

Robert Cranston authored on 26/10/2023 09:31:01
Showing 1 changed files
... ...
@@ -36,31 +36,39 @@ struct Ray
36 36
     vec3 direction;
37 37
 };
38 38
 
39
+//// Material
40
+struct Material
41
+{
42
+    vec3 color;
43
+};
44
+
39 45
 //// Trace
40 46
 struct Trace
41 47
 {
42
-    float distance;
48
+    float    distance;
49
+    Material material;
43 50
 };
44 51
 
45 52
 //// Circle
46 53
 struct Circle
47 54
 {
48
-    vec3  center;
49
-    float radius;
55
+    vec3     center;
56
+    float    radius;
57
+    Material material;
50 58
     Trace trace(Ray const & ray) const
51 59
     {
52 60
         auto const offs = center - ray.origin;
53 61
         auto const proj = dot(offs, ray.direction);
54 62
         if (proj < 0.0F) // Past.
55
-            return {infinity};
63
+            return {infinity, {}};
56 64
         auto const perp2 = dot(offs, offs) - proj * proj;
57 65
         auto const pene2 = radius * radius - perp2;
58 66
         if (pene2 < 0.0F) // Miss.
59
-            return {infinity};
67
+            return {infinity, {}};
60 68
         auto const dist = proj - sqrt(pene2);
61 69
         if (dist < 0.0F) // Inside.
62
-            return {infinity};
63
-        return {dist};
70
+            return {infinity, {}};
71
+        return {dist, material};
64 72
     }
65 73
 };
66 74
 
... ...
@@ -70,10 +78,11 @@ using Shapes = std::vector<Circle>;
70 78
 //// Scene
71 79
 struct Scene
72 80
 {
73
-    Shapes shapes;
81
+    Material background;
82
+    Shapes   shapes;
74 83
     Trace trace(Ray const & ray) const
75 84
     {
76
-        auto nearest = Trace{infinity};
85
+        auto nearest = Trace{infinity, background};
77 86
         for (auto const & shape : shapes)
78 87
         {
79 88
             auto const trace = shape.trace(ray);
... ...
@@ -181,12 +190,14 @@ int main(int argc, char const * argv[])
181 190
         100.0F,                  // far
182 191
     };
183 192
     auto const scene = Scene{
193
+        // background
194
+        {vec3(0.2F, 0.2F, 0.5F)},
184 195
         // shapes
185 196
         {
186
-            {vec3( 2.0F, -1.0F, -10.0F), 3.0F},
187
-            {vec3( 1.0F,  2.0F,  -7.0F), 2.0F},
188
-            {vec3(-1.0F,  0.0F,  -4.0F), 1.0F},
189
-            {vec3( 0.0F, -1.0F,  -3.0F), 0.2F},
197
+            {vec3( 2.0F, -1.0F, -10.0F), 3.0F, {vec3(1.0F, 0.0F, 0.0F)}},
198
+            {vec3( 1.0F,  2.0F,  -7.0F), 2.0F, {vec3(0.0F, 1.0F, 0.0F)}},
199
+            {vec3(-1.0F,  0.0F,  -4.0F), 1.0F, {vec3(0.0F, 0.0F, 1.0F)}},
200
+            {vec3( 0.0F, -1.0F,  -3.0F), 0.2F, {vec3(0.0F, 1.0F, 1.0F)}},
190 201
         },
191 202
     };
192 203
     auto const tonemap = ACES{vec3(1.0F)};
... ...
@@ -195,7 +206,7 @@ int main(int argc, char const * argv[])
195 206
     output.render([&](uvec2 const & size, uvec2 const & pixel) {
196 207
         auto const ray   = camera.ray(size, pixel);
197 208
         auto const trace = scene.trace(ray);
198
-        auto const rgb   = vec3(min(trace.distance / 100.0F, 100.0F));
209
+        auto const rgb   = trace.material.color;
199 210
         auto const srgb  = convertLinearToSRGB(tonemap.transform(rgb));
200 211
         auto const alpha = 1.0F;
201 212
         return vec4(srgb, alpha);
Browse code

Add basics

Robert Cranston authored on 25/10/2023 03:01:42
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,203 @@
1
+/// Includes
2
+
3
+#include <array>
4
+#include <fstream>
5
+#include <iostream>
6
+#include <limits>
7
+#include <string>
8
+#include <vector>
9
+
10
+#define GLM_FORCE_SWIZZLE
11
+#include <glm/glm.hpp>
12
+#include <glm/fwd.hpp>
13
+#include <glm/ext/matrix_transform.hpp>  // https://glm.g-truc.net/0.9.9/api/a00247.html
14
+#include <glm/ext/matrix_clip_space.hpp> // https://glm.g-truc.net/0.9.9/api/a00243.html
15
+#include <glm/ext/matrix_projection.hpp> // https://glm.g-truc.net/0.9.9/api/a00245.html
16
+#include <glm/gtc/color_space.hpp>       // https://glm.g-truc.net/0.9.9/api/a00289.html
17
+// #include <glm/gtx/io.hpp>                // https://glm.g-truc.net/0.9.9/api/a00332.html
18
+
19
+
20
+/// Namespaces
21
+
22
+using namespace glm;
23
+
24
+
25
+/// Constants
26
+
27
+auto const infinity = std::numeric_limits<float>::infinity();
28
+
29
+
30
+/// Types
31
+
32
+//// Ray
33
+struct Ray
34
+{
35
+    vec3 origin;
36
+    vec3 direction;
37
+};
38
+
39
+//// Trace
40
+struct Trace
41
+{
42
+    float distance;
43
+};
44
+
45
+//// Circle
46
+struct Circle
47
+{
48
+    vec3  center;
49
+    float radius;
50
+    Trace trace(Ray const & ray) const
51
+    {
52
+        auto const offs = center - ray.origin;
53
+        auto const proj = dot(offs, ray.direction);
54
+        if (proj < 0.0F) // Past.
55
+            return {infinity};
56
+        auto const perp2 = dot(offs, offs) - proj * proj;
57
+        auto const pene2 = radius * radius - perp2;
58
+        if (pene2 < 0.0F) // Miss.
59
+            return {infinity};
60
+        auto const dist = proj - sqrt(pene2);
61
+        if (dist < 0.0F) // Inside.
62
+            return {infinity};
63
+        return {dist};
64
+    }
65
+};
66
+
67
+//// Shapes
68
+using Shapes = std::vector<Circle>;
69
+
70
+//// Scene
71
+struct Scene
72
+{
73
+    Shapes shapes;
74
+    Trace trace(Ray const & ray) const
75
+    {
76
+        auto nearest = Trace{infinity};
77
+        for (auto const & shape : shapes)
78
+        {
79
+            auto const trace = shape.trace(ray);
80
+            if (trace.distance < nearest.distance)
81
+                nearest = trace;
82
+        }
83
+        return nearest;
84
+    }
85
+};
86
+
87
+//// Camera
88
+struct Camera
89
+{
90
+    vec3  position;
91
+    vec3  target;
92
+    float fovy;
93
+    float near;
94
+    float far;
95
+    Ray ray(uvec2 const & size, uvec2 const & pixel) const
96
+    {
97
+        auto const aspect    = (float)size.x / (float)size.y;
98
+        auto const viewport  = uvec4(0, 0, size);
99
+        auto const window    = vec3(vec2(pixel) + 0.5F, 0.0F);
100
+        auto const up        = vec3(0.0F, 1.0F, 0.0F);
101
+        auto const view      = glm::lookAt(position, target, up);
102
+        auto const proj      = glm::perspective(fovy, aspect, near, far);
103
+        auto const world     = glm::unProject(window, view, proj, viewport);
104
+        auto const direction = normalize(world.xyz() - position);
105
+        return Ray{position, direction};
106
+    }
107
+};
108
+
109
+//// ACES
110
+struct ACES
111
+{
112
+    vec3 whitepoint;
113
+    vec3 transform(vec3 color) const
114
+    {
115
+        color /= whitepoint;
116
+        return
117
+            (color * (2.51F * color + 0.03F)) /
118
+            (color * (2.43F * color + 0.59F) + 0.14F);
119
+    }
120
+};
121
+
122
+//// TGA
123
+struct TGA
124
+{
125
+    uvec2       size;
126
+    std::string path;
127
+    template<typename ColorFunc>
128
+    void render(ColorFunc const & color_func) const
129
+    {
130
+        auto frame_size = size.x * size.y;
131
+        auto frame      = std::vector<u8vec4>(frame_size);
132
+        auto header     = std::array<u8, 18>{
133
+            0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134
+            (u8)(size.x >> 0U),
135
+            (u8)(size.x >> 8U),
136
+            (u8)(size.y >> 0U),
137
+            (u8)(size.y >> 8U),
138
+            32, 0,
139
+        };
140
+        for (auto y = 0U; y < size.y; ++y)
141
+        {
142
+            for (auto x = 0U; x < size.x; ++x)
143
+            {
144
+                auto const color = color_func(size, uvec2(x, y));
145
+                auto const index = y * size.x + x;
146
+                frame[index] = clamp(color.bgra(), 0.0F, 1.0F) * 255.0F + 0.5F;
147
+            }
148
+        }
149
+        auto ostream = std::ofstream(path, std::ios::binary);
150
+        write(ostream, header);
151
+        write(ostream, frame);
152
+    }
153
+    template<typename Collection>
154
+    void write(std::ostream & ostream, Collection const & collection) const
155
+    {
156
+        ostream.write(
157
+            (char const *)collection.data(),
158
+            (std::streamsize)(sizeof(*collection.data()) * collection.size())
159
+        );
160
+    }
161
+};
162
+
163
+
164
+/// Main
165
+
166
+int main(int argc, char const * argv[])
167
+{
168
+    //// Arguments
169
+    if (argc != 2)
170
+    {
171
+        std::cerr << "Usage: raytrace <path>" << std::endl;
172
+        return 0;
173
+    }
174
+    auto const * path = argv[1]; // NOLINT
175
+    //// Configure
176
+    auto const camera = Camera{
177
+        vec3(0.0F, 0.0F,  0.0F), // position
178
+        vec3(0.0F, 0.0F, -1.0F), // target
179
+        radians(45.0F),          // fovy
180
+        0.01F,                   // near
181
+        100.0F,                  // far
182
+    };
183
+    auto const scene = Scene{
184
+        // shapes
185
+        {
186
+            {vec3( 2.0F, -1.0F, -10.0F), 3.0F},
187
+            {vec3( 1.0F,  2.0F,  -7.0F), 2.0F},
188
+            {vec3(-1.0F,  0.0F,  -4.0F), 1.0F},
189
+            {vec3( 0.0F, -1.0F,  -3.0F), 0.2F},
190
+        },
191
+    };
192
+    auto const tonemap = ACES{vec3(1.0F)};
193
+    auto const output  = TGA{uvec2(640, 480), path};
194
+    //// Render
195
+    output.render([&](uvec2 const & size, uvec2 const & pixel) {
196
+        auto const ray   = camera.ray(size, pixel);
197
+        auto const trace = scene.trace(ray);
198
+        auto const rgb   = vec3(min(trace.distance / 100.0F, 100.0F));
199
+        auto const srgb  = convertLinearToSRGB(tonemap.transform(rgb));
200
+        auto const alpha = 1.0F;
201
+        return vec4(srgb, alpha);
202
+    });
203
+}