... e [Atmosphere](#atmosphere) further down). The texture is planar mapped and blended based on the normal.
![enter image description here][4]
# Parallax mapping
This is where it all started for me. Someone showed me the Oliveira and Policarpo papers and decided I wanted to implement it. It took a few of these other demos before I started to understand the maths but I got there in the end. It was the first taste of outside the box thinking that realtime rendering can be done a different way (ok, so my knowledge of graphics history was limited back then too, what with only knowing about the mainstream gpu + raster triangles).
![enter image description here][5]
![enter image description here][6]
The geometry in the first image comes entirely from this heightmap. Rendered directly.
![enter image description here][7]
# Particle systems
![enter image description here][8]
![enter image description here][9]
# Transparency
Depth peeling involves rendering the geometry multiple times and capturing one layer of depth at a time. This false coloring shows the total depth.
![enter image description here][10]
I actually started out with order independent transparency. See [the research section here](https://www.heuristic42.com/users/4/pknowles/). Although I did implement depth peeling as a comparison at one stage. It's just so much faster when you have per-pixel atomics.
![enter image description here][11]
![enter image description here][12]
I tried re-rendering the object after capturing multiple layers from each X+Y+Z directions. I eventually came back to this idea in my phd thesis, but it's a really tough problem to solve. At the time I'd seen the "true impostors" paper and really wanted to extend it for more complex kinds of geometry.
![enter image description here][13]
![enter image description here][14]
I also noted that the same data structure holds color from hidden surfaces. Perfect for depth of field. Simply drawing it as blurry transparent points sort of works, but "alpha" in alpha transparency is a statistical surface coverage and for a correct defocal blur you need to actually compute visibility. So that explains why you can see through objects here:
![enter image description here][15]
# Interior mapping
![enter image description here][16]
# Portal rendering
OK, planar reflections, but it's done with recursive matrix transforms and stenciling. All I need to do to have portals is adjust the matrix transform so it's not a straight reflection. Each mirror and even mirror-within-mirror is rendering the whole bunny again. I do have clipping volumes I could be applying but the only thing taking advantage of it is the scissor rect.
![enter image description here][17]
![enter image description here][18]
# Deferred lighting
![enter image description here][19]
![enter image description here][20]
# Irregular shadow maps
Perfect per-pixel hard shadows. Normal shadow mapping needs to pre-compute surface depth from the perspective of the light source. This is often inefficient as the frequency of the samples never perfectly matches what the camera is looking at. The irregular z-buffer stores arbitrary points in a uniform grid rather than a single depth per grid, like a depth buffer. Irregular shadow maps compute depth for each camera pixel rather than arbitrarily on the regular grid of a shadow map.
![enter image description here][21]
## Irregular soft shadows
Taking this a step further I realised you could do it the other way around and store lists of triangles per-pixel. Then you could compute the overlap of the triangle and a spherical light source for soft shadows!!! It works well until you have multiple occluders (that's why the screenshot is so simple).
![enter image description here][22]
# Depth of field
Depth of field from a single image is hard to do well. Maybe these days with some deep learning it could go ok. To be physically accurate you need information from hidden surfaces, potentially full-screen circular blurs and HDR. This is a full 2D kernel blur based on a difference in depth. It was slow and of course something always looks wrong.
![enter image description here][23]
![enter image description here][24]
# Grid based smoke
![enter image description here][25]
# Variance shadow mapping
Variance shadow maps apply a blur to the shadow "strength". It's not really soft shadows as they don't get softer with distance, but it avoids the square edges and sharpness from regular shadow maps. The ugly points are the light positions.
![enter image description here][26]
![enter image description here][27]
Also, this is _fast_! If you have enough lights, you don't even need ambient occlusion :)
![enter image description here][28]
Not that it looks great, but this is my first ever shadow map.
![enter image description here][29]
# Motion blur
Just camera motion..
![enter image description here][30]
Adding animated objects. You can see this is using the method of using the previous and current frames + velocity vectors.
![enter image description here][31]
This one was a CUDA implementation. IIRC I was going for a scatter blur rather than gather and in the early days of CUDA, that was the only thing that could do it.
![enter image description here][32]
# Reflections
Planar and non-planar, using a cube map.
![enter image description here][33]
# HDR + Bloom
![enter image description here][34]
# Ambient occlusion
Yes, screen space (SSAO).
![enter image description here][35]
# Non-linear projections
Or rather, re-projecting a rectilinear rasterization.
![enter image description here][36]
# Procedural wood texture
![enter image description here][37]
![enter image description here][38]
![enter image description here][39]
# Volumetric lighting
I started with the cheap image-based one, which is more expensive than I'd have thought and doesn't look as nice.
![enter image description here][40]
Finally, using a shadow map and marching through it.
![enter image description here][41]
# Caustics
So caustics were cool, but for some reason I jumped straight to volumetric caustics because it didn't feel right to have one without the other. By far the best was drawing line primitives and blurring them. I would compute the refraction direction in a shader. Then probably ray marched a shadow map to find the end point and a place to splat some point lights for the surface caustics. Caustics are in the [Boids](#boids) demo too.
![enter image description here][42]
![enter image description here][43]
![enter image description here][44]
![enter image description here][45]
I also tried splatting polygons instead of points, but that was looking pretty messy.
![enter image description here][46]
# Animated procedural tree
![enter image description here][47]
# Procedural terrain texturing
Inspired by terragen.
![enter image description here][48]
# Lens flare
![enter image description here][49]
# Atmosphere
![enter image description here][50]
![enter image description here][51]
![enter image description here][52]
# Boids
Also includes some refraction and caustics.
![enter image description here][53]
![enter image description here][54]
# Mandlebrot shader
![enter image description here][55]
[1]: https://img.heuristic42.com/img/00d9793ca255.png
[2]: https://img.heuristic42.com/img/d48e84808ce5.png
[3]: https://img.heuristic42.com/img/1f1b76808467.png
[4]: https://img.heuristic42.com/img/72337238f515.png
[5]: https://img.heuristic42.com/img/a48d7798cf6a.png
[6]: https://img.heuristic42.com/img/fffdcc9cc9d5.png
[7]: https://img.heuristic42.com/img/2abff6098b09.png
[8]: https://img.heuristic42.com/img/ff7071d724a4.png
[9]: https://img.heuristic42.com/img/2ebd25398f5d.png
[10]: https://img.heuristic42.com/img/9cd08a714061.png
[11]: https://img.heuristic42.com/img/f80611e88986.png
[12]: https://img.heuristic42.com/img/870e40f8bb36.png
[13]: https://img.heuristic42.com/img/c84dc54b078d.png
[14]: https://img.heuristic42.com/img/ff7768e9e65d.png
[15]: https://img.heuristic42.com/img/c118c5296e7c.png
[16]: https://img.heuristic42.com/img/212362e2f6d1.png
[17]: https://img.heuristic42.com/img/c8433b31202d.png
[18]: https://img.heuristic42.com/img/626c6ca1fb94.png
[19]: https://img.heuristic42.com/img/0791d033c4d4.jpg
[20]: https://img.heuristic42.com/img/3260d85add1e.png
[21]: https://img.heuristic42.com/img/2254e0af1aa0.png
[22]: https://img.heuristic42.com/img/c564ff66c3b5.png
[23]: https://img.heuristic42.com/img/8276e1aecd2b.png
[24]: https://img.heuristic42.com/img/d8eb574888c6.png
[25]: https://img.heuristic42.com/img/3c86e5ece921.png
[26]: https://img.heuristic42.com/img/588f66d83cfc.png
[27]: https://img.heuristic42.com/img/bf12efaf2962.png
[28]: https://img.heuristic42.com/img/7f0e2e25345b.png
[29]: https://img.heuristic42.com/img/ed0d5bfc269e.png
[30]: https://img.heuristic42.com/img/e73e75d685eb.png
[31]: https://img.heuristic42.com/img/1befb01c7083.png
[32]: https://img.heuristic42.com/img/29fac3c8cce3.png
[33]: https://img.heuristic42.com/img/2bc0e9ac6920.png
[34]: https://img.heuristic42.com/img/44dd34fa2951.png
[35]: https://img.heuristic42.com/img/25e6a4656103.png
[36]: https://img.heuristic42.com/img/77658b6d3b81.png
[37]: https://img.heuristic42.com/img/3d294ef618fd.png
[38]: https://img.heuristic42.com/img/0f1d5518b224.png
[39]: https://img.heuristic42.com/img/c39c6d3221d4.png
[40]: https://img.heuristic42.com/img/c89d9a5c00c3.png
[41]: https://img.heuristic42.com/img/c785df08e498.png
[42]: https://img.heuristic42.com/img/4ca0e61e0499.png
[43]: https://img.heuristic42.com/img/3b817bf9d74f.png
[44]: https://img.heuristic42.com/img/e12bd50e5cfe.png
[45]: https://img.heuristic42.com/img/618beaba6758.png
[46]: https://img.heuristic42.com/img/eb03440a6169.png
[47]: https://img.heuristic42.com/img/54baf910b4ee.png
[48]: https://img.heuristic42.com/img/43dd9cc296e7.png
[49]: https://img.heuristic42.com/img/2cf807a4a139.png
[50]: https://img.heuristic42.com/img/2aa98fb76f94.png
[51]: https://img.heuristic42.com/img/811b250663a7.png
[52]: https://img.heuristic42.com/img/83cc91f9e457.png
[53]: https://img.heuristic42.com/img/967d6484691a.png
[54]: https://img.heuristic42.com/img/7f0f5b8b55ef.png
[55]: https://img.heuristic42.com/img/ed7bfeaf12d5.pnghttps://www.heuristic42.com/blog/48/my-first-graphics-demos/#atmosphere) further down). The texture is planar mapped and blended based on the normal.
![enter image description here][4]
# Parallax mapping
This is where it all started for me. Someone showed me the Oliveira and Policarpo papers and decided I wanted to implement it. It took a few of these other demos before I started to understand the maths but I got there in the end. It was the first taste of outside the box thinking that realtime rendering can be done a different way (ok, so my knowledge of graphics history was limited back then too, what with only knowing about the mainstream gpu + raster triangles).
![enter image description here][5]
![enter image description here][6]
The geometry in the first image comes entirely from this heightmap. Rendered directly.
![enter image description here][7]
# Particle systems
![enter image description here][8]
![enter image description here][9]
# Transparency
Depth peeling involves rendering the geometry multiple times and capturing one layer of depth at a time. This false coloring shows the total depth.
![enter image description here][10]
I actually started out with order independent transparency. See [the research section here](https://www.heuristic42.com/users/4/pknowles/). Although I did implement depth peeling as a comparison at one stage. It's just so much faster when you have per-pixel atomics.
![enter image description here][11]
![enter image description here][12]
I tried re-rendering the object after capturing multiple layers from each X+Y+Z directions. I eventually came back to this idea in my phd thesis, but it's a really tough problem to solve. At the time I'd seen the "true impostors" paper and really wanted to extend it for more complex kinds of geometry.
![enter image description here][13]
![enter image description here][14]
I also noted that the same data structure holds color from hidden surfaces. Perfect for depth of field. Simply drawing it as blurry transparent points sort of works, but "alpha" in alpha transparency is a statistical surface coverage and for a correct defocal blur you need to actually compute visibility. So that explains why you can see through objects here:
![enter image description here][15]
# Interior mapping
![enter image description here][16]
# Portal rendering
OK, planar reflections, but it's done with recursive matrix transforms and stenciling. All I need to do to have portals is adjust the matrix transform so it's not a straight reflection. Each mirror and even mirror-within-mirror is rendering the whole bunny again. I do have clipping volumes I could be applying but the only thing taking advantage of it is the scissor rect.
![enter image description here][17]
![enter image description here][18]
# Deferred lighting
![enter image description here][19]
![enter image description here][20]
# Irregular shadow maps
Perfect per-pixel hard shadows. Normal shadow mapping needs to pre-compute surface depth from the perspective of the light source. This is often inefficient as the frequency of the samples never perfectly matches what the camera is looking at. The irregular z-buffer stores arbitrary points in a uniform grid rather than a single depth per grid, like a depth buffer. Irregular shadow maps compute depth for each camera pixel rather than arbitrarily on the regular grid of a shadow map.
![enter image description here][21]
## Irregular soft shadows
Taking this a step further I realised you could do it the other way around and store lists of triangles per-pixel. Then you could compute the overlap of the triangle and a spherical light source for soft shadows!!! It works well until you have multiple occluders (that's why the screenshot is so simple).
![enter image description here][22]
# Depth of field
Depth of field from a single image is hard to do well. Maybe these days with some deep learning it could go ok. To be physically accurate you need information from hidden surfaces, potentially full-screen circular blurs and HDR. This is a full 2D kernel blur based on a difference in depth. It was slow and of course something always looks wrong.
![enter image description here][23]
![enter image description here][24]
# Grid based smoke
![enter image description here][25]
# Variance shadow mapping
Variance shadow maps apply a blur to the shadow "strength". It's not really soft shadows as they don't get softer with distance, but it avoids the square edges and sharpness from regular shadow maps. The ugly points are the light positions.
![enter image description here][26]
![enter image description here][27]
Also, this is _fast_! If you have enough lights, you don't even need ambient occlusion :)
![enter image description here][28]
Not that it looks great, but this is my first ever shadow map.
![enter image description here][29]
# Motion blur
Just camera motion..
![enter image description here][30]
Adding animated objects. You can see this is using the method of using the previous and current frames + velocity vectors.
![enter image description here][31]
This one was a CUDA implementation. IIRC I was going for a scatter blur rather than gather and in the early days of CUDA, that was the only thing that could do it.
![enter image description here][32]
# Reflections
Planar and non-planar, using a cube map.
![enter image description here][33]
# HDR + Bloom
![enter image description here][34]
# Ambient occlusion
Yes, screen space (SSAO).
![enter image description here][35]
# Non-linear projections
Or rather, re-projecting a rectilinear rasterization.
![enter image description here][36]
# Procedural wood texture
![enter image description here][37]
![enter image description here][38]
![enter image description here][39]
# Volumetric lighting
I started with the cheap image-based one, which is more expensive than I'd have thought and doesn't look as nice.
![enter image description here][40]
Finally, using a shadow map and marching through it.
![enter image description here][41]
# Caustics
So caustics were cool, but for some reason I jumped straight to volumetric caustics because it didn't feel right to have one without the other. By far the best was drawing line primitives and blurring them. I would compute the refraction direction in a shader. Then probably ray marched a shadow map to find the end point and a place to splat some point lights for the surface caustics. Caustics are in the [Boids](https://www.heuristic42.com/blog/48/my-first-graphics-demos/#boids) demo too.
![enter image description here][42]
![enter image description here][43]
![enter image description here][44]
![enter image description here][45]
I also tried splatting polygons instead of points, but that was looking pretty messy.
![enter image description here][46]
# Animated procedural tree
![enter image description here][47]
# Procedural terrain texturing
Inspired by terragen.
![enter image description here][48]
# Lens flare
![enter image description here][49]
# Atmosphere
![enter image description here][50]
![enter image description here][51]
![enter image description here][52]
# Boids
Also includes some refraction and caustics.
![enter image description here][53]
![enter image description here][54]
# Mandlebrot shader
![enter image description here][55]
[1]: https://img.heuristic42.com/img/00d9793ca255.png
[2]: https://img.heuristic42.com/img/d48e84808ce5.png
[3]: https://img.heuristic42.com/img/1f1b76808467.png
[4]: https://img.heuristic42.com/img/72337238f515.png
[5]: https://img.heuristic42.com/img/a48d7798cf6a.png
[6]: https://img.heuristic42.com/img/fffdcc9cc9d5.png
[7]: https://img.heuristic42.com/img/2abff6098b09.png
[8]: https://img.heuristic42.com/img/ff7071d724a4.png
[9]: https://img.heuristic42.com/img/2ebd25398f5d.png
[10]: https://img.heuristic42.com/img/9cd08a714061.png
[11]: https://img.heuristic42.com/img/f80611e88986.png
[12]: https://img.heuristic42.com/img/870e40f8bb36.png
[13]: https://img.heuristic42.com/img/c84dc54b078d.png
[14]: https://img.heuristic42.com/img/ff7768e9e65d.png
[15]: https://img.heuristic42.com/img/c118c5296e7c.png
[16]: https://img.heuristic42.com/img/212362e2f6d1.png
[17]: https://img.heuristic42.com/img/c8433b31202d.png
[18]: https://img.heuristic42.com/img/626c6ca1fb94.png
[19]: https://img.heuristic42.com/img/0791d033c4d4.jpg
[20]: https://img.heuristic42.com/img/3260d85add1e.png
[21]: https://img.heuristic42.com/img/2254e0af1aa0.png
[22]: https://img.heuristic42.com/img/c564ff66c3b5.png
[23]: https://img.heuristic42.com/img/8276e1aecd2b.png
[24]: https://img.heuristic42.com/img/d8eb574888c6.png
[25]: https://img.heuristic42.com/img/3c86e5ece921.png
[26]: https://img.heuristic42.com/img/588f66d83cfc.png
[27]: https://img.heuristic42.com/img/bf12efaf2962.png
[28]: https://img.heuristic42.com/img/7f0e2e25345b.png
[29]: https://img.heuristic42.com/img/ed0d5bfc269e.png
[30]: https://img.heuristic42.com/img/e73e75d685eb.png
[31]: https://img.heuristic42.com/img/1befb01c7083.png
[32]: https://img.heuristic42.com/img/29fac3c8cce3.png
[33]: https://img.heuristic42.com/img/2bc0e9ac6920.png
[34]: https://img.heuristic42.com/img/44dd34fa2951.png
[35]: https://img.heuristic42.com/img/25e6a4656103.png
[36]: https://img.heuristic42.com/img/77658b6d3b81.png
[37]: https://img.heuristic42.com/img/3d294ef618fd.png
[38]: https://img.heuristic42.com/img/0f1d5518b224.png
[39]: https://img.heuristic42.com/img/c39c6d3221d4.png
[40]: https://img.heuristic42.com/img/c89d9a5c00c3.png
[41]: https://img.heuristic42.com/img/c785df08e498.png
[42]: https://img.heuristic42.com/img/4ca0e61e0499.png
[43]: https://img.heuristic42.com/img/3b817bf9d74f.png
[44]: https://img.heuristic42.com/img/e12bd50e5cfe.png
[45]: https://img.heuristic42.com/img/618beaba6758.png
[46]: https://img.heuristic42.com/img/eb03440a6169.png
[47]: https://img.heuristic42.com/img/54baf910b4ee.png
[48]: https://img.heuristic42.com/img/43dd9cc296e7.png
[49]: https://img.heuristic42.com/img/2cf807a4a139.png
[50]: https://img.heuristic42.com/img/2aa98fb76f94.png
[51]: https://img.heuristic42.com/img/811b250663a7.png
[52]: https://img.heuristic42.com/img/83cc91f9e457.png
[53]: https://img.heuristic42.com/img/967d6484691a.png
[54]: https://img.heuristic42.com/img/7f0f5b8b55ef.png
[55]: https://img.heuristic42.com/img/ed7bfeaf12d5.png
... e [Atmosphere](#atmosphere) further down). The texture is planar mapped and blended based on the normal.
![enter image description here][4]
# Parallax mapping
This is where it all started for me. Someone showed me the Oliveira and Policarpo papers and decided I wanted to implement it. It took a few of these other demos before I started to understand the maths but I got there in the end. It was the first taste of outside the box thinking that realtime rendering can be done a different way (ok, so my knowledge of graphics history was limited back then too, what with only knowing about the mainstream gpu + raster triangles).
![enter image description here][5]
![enter image description here][6]
The geometry in the first image comes entirely from this heightmap. Rendered directly.
![enter image description here][7]
# Particle systems
![enter image description here][8]
![enter image description here][9]
# Transparency
Depth peeling involves rendering the geometry multiple times and capturing one layer of depth at a time. This false coloring shows the total depth.
![enter image description here][10]
I actually started out with order independent transparency. See [the research section here](https://www.heuristic42.com/users/4/pknowles/). Although I did implement depth peeling as a comparison at one stage. It's just so much faster when you have per-pixel atomics.
![enter image description here][11]
![enter image description here][12]
I tried re-rendering the object after capturing multiple layers from each X+Y+Z directions. I eventually came back to this idea in my phd thesis, but it's a really tough problem to solve. At the time I'd seen the "true impostors" paper and really wanted to extend it for more complex kinds of geometry.
![enter image description here][13]
![enter image description here][14]
I also noted that the same data structure holds color from hidden surfaces. Perfect for depth of field. Simply drawing it as blurry transparent points sort of works, but "alpha" in alpha transparency is a statistical surface coverage and for a correct defocal blur you need to actually compute visibility. So that explains why you can see through objects here:
![enter image description here][15]
# Interior mapping
![enter image description here][16]
# Portal rendering
OK, planar reflections, but it's done with recursive matrix transforms and stenciling. All I need to do to have portals is adjust the matrix transform so it's not a straight reflection. Each mirror and even mirror-within-mirror is rendering the whole bunny again. I do have clipping volumes I could be applying but the only thing taking advantage of it is the scissor rect.
![enter image description here][17]
![enter image description here][18]
# Deferred lighting
![enter image description here][19]
![enter image description here][20]
# Irregular shadow maps
Perfect per-pixel hard shadows. Normal shadow mapping needs to pre-compute surface depth from the perspective of the light source. This is often inefficient as the frequency of the samples never perfectly matches what the camera is looking at. The irregular z-buffer stores arbitrary points in a uniform grid rather than a single depth per grid, like a depth buffer. Irregular shadow maps compute depth for each camera pixel rather than arbitrarily on the regular grid of a shadow map.
![enter image description here][21]
## Irregular soft shadows
Taking this a step further I realised you could do it the other way around and store lists of triangles per-pixel. Then you could compute the overlap of the triangle and a spherical light source for soft shadows!!! It works well until you have multiple occluders (that's why the screenshot is so simple).
![enter image description here][22]
# Depth of field
Depth of field from a single image is hard to do well. Maybe these days with some deep learning it could go ok. To be physically accurate you need information from hidden surfaces, potentially full-screen circular blurs and HDR. This is a full 2D kernel blur based on a difference in depth. It was slow and of course something always looks wrong.
![enter image description here][23]
![enter image description here][24]
# Grid based smoke
![enter image description here][25]
# Variance shadow mapping
Variance shadow maps apply a blur to the shadow "strength". It's not really soft shadows as they don't get softer with distance, but it avoids the square edges and sharpness from regular shadow maps. The ugly points are the light positions.
![enter image description here][26]
![enter image description here][27]
Also, this is _fast_! If you have enough lights, you don't even need ambient occlusion :)
![enter image description here][28]
Not that it looks great, but this is my first ever shadow map.
![enter image description here][29]
# Motion blur
Just camera motion..
![enter image description here][30]
Adding animated objects. You can see this is using the method of using the previous and current frames + velocity vectors.
![enter image description here][31]
This one was a CUDA implementation. IIRC I was going for a scatter blur rather than gather and in the early days of CUDA, that was the only thing that could do it.
![enter image description here][32]
# Reflections
Planar and non-planar, using a cube map.
![enter image description here][33]
# HDR + Bloom
![enter image description here][34]
# Ambient occlusion
Yes, screen space (SSAO).
![enter image description here][35]
# Non-linear projections
Or rather, re-projecting a rectilinear rasterization.
![enter image description here][36]
# Procedural wood texture
![enter image description here][37]
![enter image description here][38]
![enter image description here][39]
# Volumetric lighting
I started with the cheap image-based one, which is more expensive than I'd have thought and doesn't look as nice.
![enter image description here][40]
Finally, using a shadow map and marching through it.
![enter image description here][41]
# Caustics
So caustics were cool, but for some reason I jumped straight to volumetric caustics because it didn't feel right to have one without the other. By far the best was drawing line primitives and blurring them. I would compute the refraction direction in a shader. Then probably ray marched a shadow map to find the end point and a place to splat some point lights for the surface caustics. Caustics are in the [Boids](#boids) demo too.
![enter image description here][42]
![enter image description here][43]
![enter image description here][44]
![enter image description here][45]
I also tried splatting polygons instead of points, but that was looking pretty messy.
![enter image description here][46]
# Animated procedural tree
![enter image description here][47]
# Procedural terrain texturing
Inspired by terragen.
![enter image description here][48]
# Lens flare
![enter image description here][49]
# Atmosphere
![enter image description here][50]
![enter image description here][51]
![enter image description here][52]
# Boids
Also includes some refraction and caustics.
![enter image description here][53]
![enter image description here][54]
# Mandlebrot shader
![enter image description here][55]
[1]: https://img.heuristic42.com/img/00d9793ca255.png
[2]: https://img.heuristic42.com/img/d48e84808ce5.png
[3]: https://img.heuristic42.com/img/1f1b76808467.png
[4]: https://img.heuristic42.com/img/72337238f515.png
[5]: https://img.heuristic42.com/img/a48d7798cf6a.png
[6]: https://img.heuristic42.com/img/fffdcc9cc9d5.png
[7]: https://img.heuristic42.com/img/2abff6098b09.png
[8]: https://img.heuristic42.com/img/ff7071d724a4.png
[9]: https://img.heuristic42.com/img/2ebd25398f5d.png
[10]: https://img.heuristic42.com/img/9cd08a714061.png
[11]: https://img.heuristic42.com/img/f80611e88986.png
[12]: https://img.heuristic42.com/img/870e40f8bb36.png
[13]: https://img.heuristic42.com/img/c84dc54b078d.png
[14]: https://img.heuristic42.com/img/ff7768e9e65d.png
[15]: https://img.heuristic42.com/img/c118c5296e7c.png
[16]: https://img.heuristic42.com/img/212362e2f6d1.png
[17]: https://img.heuristic42.com/img/c8433b31202d.png
[18]: https://img.heuristic42.com/img/626c6ca1fb94.png
[19]: https://img.heuristic42.com/img/0791d033c4d4.jpg
[20]: https://img.heuristic42.com/img/3260d85add1e.png
[21]: https://img.heuristic42.com/img/2254e0af1aa0.png
[22]: https://img.heuristic42.com/img/c564ff66c3b5.png
[23]: https://img.heuristic42.com/img/8276e1aecd2b.png
[24]: https://img.heuristic42.com/img/d8eb574888c6.png
[25]: https://img.heuristic42.com/img/3c86e5ece921.png
[26]: https://img.heuristic42.com/img/588f66d83cfc.png
[27]: https://img.heuristic42.com/img/bf12efaf2962.png
[28]: https://img.heuristic42.com/img/7f0e2e25345b.png
[29]: https://img.heuristic42.com/img/ed0d5bfc269e.png
[30]: https://img.heuristic42.com/img/e73e75d685eb.png
[31]: https://img.heuristic42.com/img/1befb01c7083.png
[32]: https://img.heuristic42.com/img/29fac3c8cce3.png
[33]: https://img.heuristic42.com/img/2bc0e9ac6920.png
[34]: https://img.heuristic42.com/img/44dd34fa2951.png
[35]: https://img.heuristic42.com/img/25e6a4656103.png
[36]: https://img.heuristic42.com/img/77658b6d3b81.png
[37]: https://img.heuristic42.com/img/3d294ef618fd.png
[38]: https://img.heuristic42.com/img/0f1d5518b224.png
[39]: https://img.heuristic42.com/img/c39c6d3221d4.png
[40]: https://img.heuristic42.com/img/c89d9a5c00c3.png
[41]: https://img.heuristic42.com/img/c785df08e498.png
[42]: https://img.heuristic42.com/img/4ca0e61e0499.png
[43]: https://img.heuristic42.com/img/3b817bf9d74f.png
[44]: https://img.heuristic42.com/img/e12bd50e5cfe.png
[45]: https://img.heuristic42.com/img/618beaba6758.png
[46]: https://img.heuristic42.com/img/eb03440a6169.png
[47]: https://img.heuristic42.com/img/54baf910b4ee.png
[48]: https://img.heuristic42.com/img/43dd9cc296e7.png
[49]: https://img.heuristic42.com/img/2cf807a4a139.png
[50]: https://img.heuristic42.com/img/2aa98fb76f94.png
[51]: https://img.heuristic42.com/img/811b250663a7.png
[52]: https://img.heuristic42.com/img/83cc91f9e457.png
[53]: https://img.heuristic42.com/img/967d6484691a.png
[54]: https://img.heuristic42.com/img/7f0f5b8b55ef.png
[55]: https://img.heuristic42.com/img/ed7bfeaf12d5.pnghttps://www.heuristic42.com/blog/48/my-first-graphics-demos/#atmosphere) further down). The texture is planar mapped and blended based on the normal.
![enter image description here][4]
# Parallax mapping
This is where it all started for me. Someone showed me the Oliveira and Policarpo papers and decided I wanted to implement it. It took a few of these other demos before I started to understand the maths but I got there in the end. It was the first taste of outside the box thinking that realtime rendering can be done a different way (ok, so my knowledge of graphics history was limited back then too, what with only knowing about the mainstream gpu + raster triangles).
![enter image description here][5]
![enter image description here][6]
The geometry in the first image comes entirely from this heightmap. Rendered directly.
![enter image description here][7]
# Particle systems
![enter image description here][8]
![enter image description here][9]
# Transparency
Depth peeling involves rendering the geometry multiple times and capturing one layer of depth at a time. This false coloring shows the total depth.
![enter image description here][10]
I actually started out with order independent transparency. See [the research section here](https://www.heuristic42.com/users/4/pknowles/). Although I did implement depth peeling as a comparison at one stage. It's just so much faster when you have per-pixel atomics.
![enter image description here][11]
![enter image description here][12]
I tried re-rendering the object after capturing multiple layers from each X+Y+Z directions. I eventually came back to this idea in my phd thesis, but it's a really tough problem to solve. At the time I'd seen the "true impostors" paper and really wanted to extend it for more complex kinds of geometry.
![enter image description here][13]
![enter image description here][14]
I also noted that the same data structure holds color from hidden surfaces. Perfect for depth of field. Simply drawing it as blurry transparent points sort of works, but "alpha" in alpha transparency is a statistical surface coverage and for a correct defocal blur you need to actually compute visibility. So that explains why you can see through objects here:
![enter image description here][15]
# Interior mapping
![enter image description here][16]
# Portal rendering
OK, planar reflections, but it's done with recursive matrix transforms and stenciling. All I need to do to have portals is adjust the matrix transform so it's not a straight reflection. Each mirror and even mirror-within-mirror is rendering the whole bunny again. I do have clipping volumes I could be applying but the only thing taking advantage of it is the scissor rect.
![enter image description here][17]
![enter image description here][18]
# Deferred lighting
![enter image description here][19]
![enter image description here][20]
# Irregular shadow maps
Perfect per-pixel hard shadows. Normal shadow mapping needs to pre-compute surface depth from the perspective of the light source. This is often inefficient as the frequency of the samples never perfectly matches what the camera is looking at. The irregular z-buffer stores arbitrary points in a uniform grid rather than a single depth per grid, like a depth buffer. Irregular shadow maps compute depth for each camera pixel rather than arbitrarily on the regular grid of a shadow map.
![enter image description here][21]
## Irregular soft shadows
Taking this a step further I realised you could do it the other way around and store lists of triangles per-pixel. Then you could compute the overlap of the triangle and a spherical light source for soft shadows!!! It works well until you have multiple occluders (that's why the screenshot is so simple).
![enter image description here][22]
# Depth of field
Depth of field from a single image is hard to do well. Maybe these days with some deep learning it could go ok. To be physically accurate you need information from hidden surfaces, potentially full-screen circular blurs and HDR. This is a full 2D kernel blur based on a difference in depth. It was slow and of course something always looks wrong.
![enter image description here][23]
![enter image description here][24]
# Grid based smoke
![enter image description here][25]
# Variance shadow mapping
Variance shadow maps apply a blur to the shadow "strength". It's not really soft shadows as they don't get softer with distance, but it avoids the square edges and sharpness from regular shadow maps. The ugly points are the light positions.
![enter image description here][26]
![enter image description here][27]
Also, this is _fast_! If you have enough lights, you don't even need ambient occlusion :)
![enter image description here][28]
Not that it looks great, but this is my first ever shadow map.
![enter image description here][29]
# Motion blur
Just camera motion..
![enter image description here][30]
Adding animated objects. You can see this is using the method of using the previous and current frames + velocity vectors.
![enter image description here][31]
This one was a CUDA implementation. IIRC I was going for a scatter blur rather than gather and in the early days of CUDA, that was the only thing that could do it.
![enter image description here][32]
# Reflections
Planar and non-planar, using a cube map.
![enter image description here][33]
# HDR + Bloom
![enter image description here][34]
# Ambient occlusion
Yes, screen space (SSAO).
![enter image description here][35]
# Non-linear projections
Or rather, re-projecting a rectilinear rasterization.
![enter image description here][36]
# Procedural wood texture
![enter image description here][37]
![enter image description here][38]
![enter image description here][39]
# Volumetric lighting
I started with the cheap image-based one, which is more expensive than I'd have thought and doesn't look as nice.
![enter image description here][40]
Finally, using a shadow map and marching through it.
![enter image description here][41]
# Caustics
So caustics were cool, but for some reason I jumped straight to volumetric caustics because it didn't feel right to have one without the other. By far the best was drawing line primitives and blurring them. I would compute the refraction direction in a shader. Then probably ray marched a shadow map to find the end point and a place to splat some point lights for the surface caustics. Caustics are in the [Boids](https://www.heuristic42.com/blog/48/my-first-graphics-demos/#boids) demo too.
![enter image description here][42]
![enter image description here][43]
![enter image description here][44]
![enter image description here][45]
I also tried splatting polygons instead of points, but that was looking pretty messy.
![enter image description here][46]
# Animated procedural tree
![enter image description here][47]
# Procedural terrain texturing
Inspired by terragen.
![enter image description here][48]
# Lens flare
![enter image description here][49]
# Atmosphere
![enter image description here][50]
![enter image description here][51]
![enter image description here][52]
# Boids
Also includes some refraction and caustics.
![enter image description here][53]
![enter image description here][54]
# Mandlebrot shader
![enter image description here][55]
[1]: https://img.heuristic42.com/img/00d9793ca255.png
[2]: https://img.heuristic42.com/img/d48e84808ce5.png
[3]: https://img.heuristic42.com/img/1f1b76808467.png
[4]: https://img.heuristic42.com/img/72337238f515.png
[5]: https://img.heuristic42.com/img/a48d7798cf6a.png
[6]: https://img.heuristic42.com/img/fffdcc9cc9d5.png
[7]: https://img.heuristic42.com/img/2abff6098b09.png
[8]: https://img.heuristic42.com/img/ff7071d724a4.png
[9]: https://img.heuristic42.com/img/2ebd25398f5d.png
[10]: https://img.heuristic42.com/img/9cd08a714061.png
[11]: https://img.heuristic42.com/img/f80611e88986.png
[12]: https://img.heuristic42.com/img/870e40f8bb36.png
[13]: https://img.heuristic42.com/img/c84dc54b078d.png
[14]: https://img.heuristic42.com/img/ff7768e9e65d.png
[15]: https://img.heuristic42.com/img/c118c5296e7c.png
[16]: https://img.heuristic42.com/img/212362e2f6d1.png
[17]: https://img.heuristic42.com/img/c8433b31202d.png
[18]: https://img.heuristic42.com/img/626c6ca1fb94.png
[19]: https://img.heuristic42.com/img/0791d033c4d4.jpg
[20]: https://img.heuristic42.com/img/3260d85add1e.png
[21]: https://img.heuristic42.com/img/2254e0af1aa0.png
[22]: https://img.heuristic42.com/img/c564ff66c3b5.png
[23]: https://img.heuristic42.com/img/8276e1aecd2b.png
[24]: https://img.heuristic42.com/img/d8eb574888c6.png
[25]: https://img.heuristic42.com/img/3c86e5ece921.png
[26]: https://img.heuristic42.com/img/588f66d83cfc.png
[27]: https://img.heuristic42.com/img/bf12efaf2962.png
[28]: https://img.heuristic42.com/img/7f0e2e25345b.png
[29]: https://img.heuristic42.com/img/ed0d5bfc269e.png
[30]: https://img.heuristic42.com/img/e73e75d685eb.png
[31]: https://img.heuristic42.com/img/1befb01c7083.png
[32]: https://img.heuristic42.com/img/29fac3c8cce3.png
[33]: https://img.heuristic42.com/img/2bc0e9ac6920.png
[34]: https://img.heuristic42.com/img/44dd34fa2951.png
[35]: https://img.heuristic42.com/img/25e6a4656103.png
[36]: https://img.heuristic42.com/img/77658b6d3b81.png
[37]: https://img.heuristic42.com/img/3d294ef618fd.png
[38]: https://img.heuristic42.com/img/0f1d5518b224.png
[39]: https://img.heuristic42.com/img/c39c6d3221d4.png
[40]: https://img.heuristic42.com/img/c89d9a5c00c3.png
[41]: https://img.heuristic42.com/img/c785df08e498.png
[42]: https://img.heuristic42.com/img/4ca0e61e0499.png
[43]: https://img.heuristic42.com/img/3b817bf9d74f.png
[44]: https://img.heuristic42.com/img/e12bd50e5cfe.png
[45]: https://img.heuristic42.com/img/618beaba6758.png
[46]: https://img.heuristic42.com/img/eb03440a6169.png
[47]: https://img.heuristic42.com/img/54baf910b4ee.png
[48]: https://img.heuristic42.com/img/43dd9cc296e7.png
[49]: https://img.heuristic42.com/img/2cf807a4a139.png
[50]: https://img.heuristic42.com/img/2aa98fb76f94.png
[51]: https://img.heuristic42.com/img/811b250663a7.png
[52]: https://img.heuristic42.com/img/83cc91f9e457.png
[53]: https://img.heuristic42.com/img/967d6484691a.png
[54]: https://img.heuristic42.com/img/7f0f5b8b55ef.png
[55]: https://img.heuristic42.com/img/ed7bfeaf12d5.png