| ... | ... |
@@ -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 |
} |