| ... | ... |
@@ -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) |
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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); |
| 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 |
+} |