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