1<!DOCTYPE html> 2<html lang="en" > 3<head> 4<meta charset="utf-8"/> 5 6<title>Blog | Moments in Graphics</title> 7 8<link rel="icon" href="./Media/Logo/Logo32.png" sizes="32x32" /> 9<link rel="icon" href="./Media/Logo/Logo192.png" sizes="192x192" /> 10<link rel="apple-touch-icon-precomposed" href="./Media/Logo/Logo180.png" /> 11<meta name="msapplication-TileImage" content="./Media/Logo/Logo270.png" /> 12 13<meta name="viewport" content="width=490"> 14 15<link rel="alternate" type="application/rss+xml" title="Moments in Graphics" href="./RSS.xml"> 16 17<meta name="keywords" content="homepage,index,article list,Moments in Graphics" /> 18 19<style> 20@font-face{ 21 font-family: "Linux Libertine Mono"; 22 src: url("./Dependencies/Fonts/LibertineWOFF/LinLibertine_M.woff") format("woff"), 23 url("./Dependencies/Fonts/LibertineTTF/LinLibertine_Mah.ttf") format("truetype"); 24 font-weight: normal; 25 font-style: normal; 26} 27 28@font-face{ 29 font-family: "Linux Libertine"; 30 src: url("./Dependencies/Fonts/LibertineWOFF/LinLibertine_R.woff") format("woff"), 31 url("./Dependencies/Fonts/LibertineTTF/LinLibertine_Rah.ttf") format("truetype"); 32 font-weight: normal; 33 font-style: normal; 34} 35@font-face{ 36 font-family: "Linux Libertine"; 37 src: url("./Dependencies/Fonts/LibertineWOFF/LinLibertine_RB.woff") format("woff"), 38 url("./Dependencies/Fonts/LibertineTTF/LinLibertine_RBah.ttf") format("truetype"); 39 font-weight: bold; 40 font-style: normal; 41} 42@font-face{ 43 font-family: "Linux Libertine"; 44 src: url("./Dependencies/Fonts/LibertineWOFF/LinLibertine_RI.woff") format("woff"), 45 url("./Dependencies/Fonts/LibertineTTF/LinLibertine_RIah.ttf") format("truetype"); 46 font-weight: normal; 47 font-style: italic; 48} 49@font-face{ 50 font-family: "Linux Libertine"; 51 src: url("./Dependencies/Fonts/LibertineWOFF/LinLibertine_RBI.woff") format("woff"), 52 url("./Dependencies/Fonts/LibertineTTF/LinLibertine_RBIah.ttf") format("truetype"); 53 font-weight: bold; 54 font-style: italic; 55} 56 57@font-face{ 58 font-family: "Linux Biolinum"; 59 src: url("./Dependencies/Fonts/LibertineWOFF/LinBiolinum_R.woff") format("woff"), 60 url("./Dependencies/Fonts/LibertineTTF/LinBiolinum_Rah.ttf") format("truetype"); 61 font-weight: normal; 62 font-style: normal; 63} 64@font-face{ 65 font-family: "Linux Biolinum"; 66 src: url("./Dependencies/Fonts/LibertineWOFF/LinBiolinum_RB.woff") format("woff"), 67 url("./Dependencies/Fonts/LibertineTTF/LinBiolinum_RBah.ttf") format("truetype"); 68 font-weight: bold; 69 font-style: normal; 70} 71@font-face{ 72 font-family: "Linux Biolinum"; 73 src: url("./Dependencies/Fonts/LibertineWOFF/LinBiolinum_RI.woff") format("woff"), 74 url("./Dependencies/Fonts/LibertineTTF/LinBiolinum_RIah.ttf") format("truetype"); 75 font-weight: normal; 76 font-style: italic; 77} 78@font-face{ 79 font-family: "Linux Biolinum"; 80 src: url("./Dependencies/Fonts/LibertineWOFF/LinBiolinum_RBI.woff") format("woff"), 81 url("./Dependencies/Fonts/LibertineTTF/LinBiolinum_RBIah.ttf") format("truetype"); 82 font-weight: bold; 83 font-style: italic; 84} 85 86body{ 87 margin: 10px 0px 20px 0px; 88 padding: 0px; 89} 90.main-header{ 91 padding: 0px; 92 margin: 0px; 93 border-bottom-style: solid; 94 border-bottom-width: 4px; 95 border-bottom-color: #000000; 96} 97@media screen{ 98 .main-header-content-wrapper{ 99 margin: 10px auto 0px auto; 100 text-align: left; 101 width: 100%; 102 min-width: 50px; 103 max-width: 474px; 104 } 105} 106@media print{ 107 .main-header-content-wrapper{ 108 text-align: left; 109 width: 100%; 110 } 111} 112.main-blog-title{ 113 font-family: "Linux Biolinum",Arial,sans-serif; 114 font-weight: bold; 115 font-size: 22px; 116} 117.main-blog-subtitle{ 118 font-family: "Linux Biolinum",Arial,sans-serif; 119 font-size: 18px; 120 margin-bottom: 19px; 121} 122@media screen{ 123 .main-navigation-bar{ 124 text-align: left; 125 padding: 0px 0px 0px 0px; 126 } 127} 128@media print{ 129 .main-navigation-bar{ 130 display: none; 131 } 132} 133.main-navigation-button{ 134 font-family: "Linux Biolinum",Arial,sans-serif; 135 font-weight: bold; 136 font-size: 22px; 137 text-decoration: none; 138 border-radius: 8px 8px 0px 0px; 139 background-color: #F0F0F0; 140 margin: 0px 2px 0px 0px; 141 padding: 4px 10px 4px 10px; 142 display: inline-block; 143} 144.main-navigation-button:hover{ 145 background-color: #E0E0E0; 146} 147.main-navigation-button-active{ 148 color: #FFFFFF; 149 background-color: #000000; 150} 151.main-navigation-button-active:hover{ 152 background-color: #303030; 153} 154 155.index-title-link{ 156 text-decoration: none; 157} 158.publication-title-link{ 159 text-decoration: none; 160} 161 162.float-with-caption{ 163 margin: 20px 0px 30px 0px; 164 padding: 0px; 165} 166.publication-date{ 167 margin: 7px 0px 0px 0px; 168 padding: 0px; 169 font-size: 16px; 170 font-family: "Linux Libertine",Times,serif; 171 color: #444444; 172} 173 174.main-footer{ 175 padding: 0px; 176 margin: 30px 0px 0px 0px; 177} 178@media screen{ 179 .main-footer-content-wrapper{ 180 margin: 0px auto 0px auto; 181 padding: 0px 0px 10px 0px; 182 width: 100%; 183 min-width: 50px; 184 max-width: 474px; 185 } 186} 187@media print{ 188 .main-footer-content-wrapper{ 189 padding: 0px 0px 10px 0px; 190 width: 100%; 191 } 192} 193.main-footer-adjacent-links{ 194 font-family: "Linux Libertine",Times,serif; 195 font-size: 18px; 196} 197@media screen{ 198 .main-footer-external-links{ 199 padding: 25px 0px 0px 0px; 200 font-family: "Linux Libertine",Times,serif; 201 font-size: 18px; 202 line-height: 1.5; 203 } 204} 205@media print{ 206 .main-footer-external-links{ 207 display: none; 208 } 209} 210.link-separator{ 211 margin: 0px 5px 0px 5px; 212} 213 214@media screen{ 215 article{ 216 width: 100%; 217 min-width: 50px; 218 max-width: 474px; 219 text-align: justify;
220 text-justify: inter-word; 221 margin-left: auto; 222 margin-right: auto; 223 } 224} 225@media print{ 226 article{ 227 width: 100%; 228 text-align: justify; 229 text-justify: inter-word; 230 } 231} 232img{ 233 max-width: 100%; 234 display: inline-block; 235} 236video{ 237 max-width: 100%; 238 display: inline-block; 239} 240h1,h2,h3,h4,h5,h6{ 241 font-family: "Linux Biolinum",Arial,sans-serif; 242 font-weight: bold; 243 margin: 30px 0px 2px 0px; 244 text-align: left; 245} 246h1{font-size: 26px;} 247h2{font-size: 24px;} 248h3{font-size: 22px;} 249p,div,dl,li,table{ 250 font-family: "Linux Libertine",Times,serif; 251 font-size: 18px; 252} 253p{ 254 margin: 18px 0px 18px 0px; 255} 256a:link{color: #2274A0;} 257a:visited{color: #105070;} 258a:hover{color: #2F2F2F;} 259a:active{color: #0F0F0F;} 260code{ 261 font-family: "Linux Libertine Mono",Courier,monospace; 262 font-size: 16px; 263} 264pre{ 265 box-sizing: border-box; 266 width: 100%; 267 border: 1px solid #CCCCCC; 268 padding: 5px; 269 overflow: auto; 270 background: #FCFCFC; 271} 272ul{ 273 margin: 0px; 274 padding: 0px 0px 0px 28px; 275} 276li{margin: 12px 0px 12px 0px;} 277dt{ 278 font-family: "Linux Libertine",Times,serif; 279 font-weight: bold; 280 margin: 18px 0px 5px 0px; 281} 282table{ 283 width: 100%; 284} 285</style> 286 287 288 289</head> 290 291<body> 292 293<header class="main-header"> 294 <div class="main-header-content-wrapper"> 295 <div class="main-blog-title"> 296 Moments in Graphics 297 </div> 298 <div class="main-blog-subtitle"> 299 A blog by Christoph Peters 300 </div> 301 <div class="main-navigation-bar"> 302 <a href="./index.html"><span class="main-navigation-button main-navigation-button-active">Blog</span></a> 303 <a href="./Publications.html"><span class="main-navigation-button">Publications</span></a> 304 <a href="./About.html"><span class="main-navigation-button">About</span></a> 305 </div> 306 </div> 307</header> 308 309<main> 310<article> 311 312<a href="CameraRays.html" class="index-title-link"> 313<h1 id="Computing_Camera_Rays">Computing Camera Rays</h1> 314 315 316<div class="publication-date">Published 2026-06-20</div></a> 317<p>We are in a transition period, where ray tracing and rasterization coexist. 318Typical real-time rendering pipelines still use rasterization (often with deferred shading) for primary visibility and then trace rays for shadows, reflections or global illumination. 319Though, we are getting to the point where one can seriously consider to ditch rasterization and to use ray tracing for primary visibility as well, at least on some platforms. 320Then you need to compute camera rays, characterized by ray origin, ray direction and ray length, in a way that is consistent with what you would otherwise do for rasterization. 321In rasterization, you commonly use a world to clip space transformation matrix, also known as view-projection matrix to specify the camera. 322In this blog post, I will derive how to compute camera rays based on such a matrix. <a href="CameraRays.html">Read more...</a></p> 323 324<a href="SpectralRendering3Results.html" class="index-title-link"> 325<h1 id="Spectral_rendering_part_3_Spectral_vs_RGB">Spectral rendering, part 3: Spectral vs. RGB</h1> 326 327 328<div class="publication-date">Published 2025-11-20</div></a> 329<p>Now that we have a spectral renderer, it is time to see if it was worth the effort. 330I hope you agree with my reasoning in <a href="SpectralRendering1Spectra.html#RGB_rendering">part 1</a>, that RGB rendering does not match the physical reality, but does it really matter? 331We will now compare RGB rendering to spectral rendering using my <a href="https://github.com/MomentsInGraphics/path_tracer/tree/spectral">spectral path tracer</a>. 332In the process, we will look at various types of light sources. 333RGB rendering simply multiplies RGB triples of illuminants and textures component-wise to arrive at the linear RGB color displayed on screen. 334Spectral rendering uses proper illuminant spectra (mostly from <a href="https://lspdd.org">LSPDD.org</a>) and reflectance spectra that are upsampled from sRGB using <a href="SpectralRendering1Spectra.html#Fourier_sRGB">Fourier sRGB</a>. <a href="SpectralRendering3Results.html">Read more...</a></p> 335 336<a href="SpectralRendering2Rendering.html" class="index-title-link"> 337<h1 id="Spectral_rendering_part_2_Real_time_rendering">Spectral rendering, part 2: Real-time rendering</h1> 338 339 340<div class="publication-date">Published 2025-11-13</div></a> 341<p>Based on the insights from <a href="SpectralRendering1Spectra.html">part 1</a>, we have the means to define illuminant and reflectance spectra for our scene data. 342Then the color of a pixel arises from an <a href="SpectralRendering1Spectra.html#Problem_statement">integral over a product of spectra</a>.
343The main goal of this blog post is to find efficient ways to evaluate such integrals using Monte Carlo integration and importance sampling. 344Additionally, we discuss how to define a BRDF based on known reflectance spectra, how to implement that and look at results. 345I have extended my <a href="https://github.com/MomentsInGraphics/path_tracer">educational path tracer</a> to support both <a href="https://github.com/MomentsInGraphics/path_tracer/tree/spectral">spectral and RGB rendering</a>. 346You can take a look at this code to see specifics of how all of this is implemented (see the links at the bottom). <a href="SpectralRendering2Rendering.html">Read more...</a></p> 347 348<a href="SpectralRendering1Spectra.html" class="index-title-link"> 349<h1 id="Spectral_rendering_part_1_Spectra">Spectral rendering, part 1: Spectra</h1> 350 351 352<div class="publication-date">Published 2025-11-06</div></a> 353<p>In my <a href="Radiometry2Photometry.html">previous blog post</a>, I explained spectral radiometric quantities and a few basics of spectral rendering. 354In this blog post series, we dive into much more detail on spectral rendering. 355I present a specific way to implement it in a <a href="https://github.com/MomentsInGraphics/path_tracer/tree/spectral">real-time path tracer</a> and demonstrate what advantages it brings compared to RGB rendering. 356RGB rendering is still by far the most common way to do rendering. 357Colors just get multiplied component-wise, i.e. red times red, green times green and blue times blue. 358That is a poor approximation of our physical reality. 359In practice many of the issues that this causes are covered up by manual color grading. 360Spectral rendering offers more accurate color reproduction, more independence of the choice of color spaces, support for unusual light spectra and all that at a rather negligible computational cost. 361It is not an obscenely expensive theoretical avenue for offline rendering, but a viable addition to real-time renderers (rasterizers and path tracers alike) that can be made to work with existing assets. 362If you do not believe me, maybe these posts can change that. 363It does not hurt to read the <a href="RadiometryOverview.html">series on radiometry</a> first, but in principle, this series is self-contained. 364This first part focuses on what kinds of spectra we need to specify a scene and how we can get them. <a href="SpectralRendering1Spectra.html">Read more...</a></p> 365 366<a href="SpectralRenderingOverview.html" class="index-title-link"> 367<h1 id="Spectral_rendering_Overview">Spectral rendering: Overview</h1> 368 369 370<div class="publication-date">Published 2025-11-05</div></a> 371<p>Rather than treating colors as RGB triples, spectral rendering uses spectra, which specify an intensity for each wavelength. 372This blog post series describes how spectral rendering can be implemented at a relatively low overhead (as compared to RGB rendering) and why that is beneficial. <a href="SpectralRenderingOverview.html">Read more...</a></p> 373 374<a href="Radiometry2Photometry.html" class="index-title-link"> 375<h1 id="Radiometry_part_2_Spectra_and_photometry">Radiometry, part 2: Spectra and photometry</h1> 376 377 378<div class="publication-date">Published 2025-01-19</div></a> 379<p>The radiometric quantities introduced in <a href="Radiometry1Backwards.html">part 1 of this series</a> are completely color-blind. That is an obvious drawback for rendering. Thus far, our notion is that radiance is a single number, not a color. A fairly common practice in rendering is to have separate radiance values for red, green and blue. If your scene happens to be lit exclusively by light sources with only three wavelengths and does not exhibit <a href="https://en.wikipedia.org/wiki/Fluorescence">fluorescence</a>, that is a physically accurate approach. Unfortunately, real scenes are not that simple. In this post, we describe the physical reality more completely. We consider spectral versions of all radiometric quantities. Then we take a look at human perception of color and brightness, which leads to photometric quantities. Next, we figure out how to handle that efficiently in a renderer. And finally I rant a bit about all the confusion that surrounds this subject. <a href="Radiometry2Photometry.html">Read more...</a></p> 380 381<a href="Radiometry1Backwards.html" class="index-title-link"> 382<h1 id="Radiometry_part_1_I_got_it_backwards">Radiometry, part 1: I got it backwards</h1> 383 384 385<div class="publication-date">Published 2025-01-12</div></a> 386<p>Radiometric quantities are crucial for physically-based rendering. These physical quantities enable us to formulate how much light there is in a scene, where it is and which way it is going. In the end, rendering is all about figuring out what light reaches a camera and how. Without radiometry, there is no way to formalize this problem. For example, the <a href="ToyRenderer4RayTracing.html#The_rendering_equation">rendering equation</a>, which is the backbone of modern rendering, is formulated in terms of radiance (a radiometric quantity). When you write a path tracer, there are two common sources of errors that result in bias. One is an insufficient understanding of Monte Carlo integration and probability theory when it comes to advanced <a href="ToyRenderer4RayTracing.html">importance sampling strategies</a>. The other is that you are not even trying to compute the right integral because of a flawed understanding of radiometry. There is a common way to explain radiometry by arguing in terms of differential quantities and limits. I always foun
386d that a bit confusing. Thus, we take a completely different route here. We start with the most important quantity for rendering, radiance, and use integrals to work our way towards all the other quantities. <a href="Radiometry1Backwards.html">Read more...</a></p> 387 388<a href="RadiometryOverview.html" class="index-title-link"> 389<h1 id="Radiometry_Overview">Radiometry: Overview</h1> 390 391 392<div class="publication-date">Published 2025-01-11</div></a> 393<p>Physically-based rendering requires physical quantities, specifically radiometric and photometric quantities. They are at the foundation of the rendering equation. Without a solid understanding, you cannot properly describe what you are trying to compute in your renderer, let alone compute it correctly and efficiently. In this short blog post series, I describe these concepts in ways that are a bit off the beaten path. Hopefully, that will help some of you to gain a better understanding. Note that the link to part 2 will be broken until that post becomes available: <a href="RadiometryOverview.html">Read more...</a></p> 394 395<a href="PathTracingLectures.html" class="index-title-link"> 396<h1 id="Path_tracing_lectures">Path tracing lectures</h1> 397 398 399<div class="publication-date">Published 2024-12-19</div></a> 400<p>Earlier this year, I prepared <a href="https://www.tudelft.nl/ewi/over-de-faculteit/afdelingen/intelligent-systems/computer-graphics-and-visualization/education/path-tracing-lecture">lectures on path tracing</a> for master students at <a href="https://graphics.tudelft.nl/">TU Delft</a>. We decided to make recorded versions of these lectures available to the general public. I also wrote a simple Vulkan <a href="https://github.com/MomentsInGraphics/path_tracer">path tracer</a> for illustrations in the lectures, which is open source now. You can watch the lectures on YouTube (113 minutes) to learn about basic principles of path tracing and all the importance sampling strategies that go into the path tracer. Then you can dig into the code to see how they are implemented. The first lecture is similar in scope to part 2 of my <a href="PathTracingWorkshop.html">path tracing workshop</a>. It ends with a naive path tracer. Part 2 dives into importance sampling strategies that achieve considerably lower noise at the same computational cost: BRDF importance sampling, light sampling and the combination of these two strategies using multiple importance sampling and next-event estimation. These contents are similar to what I had in mind for part 3 of the path tracing workshop. <a href="PathTracingLectures.html">Read more...</a></p> 401 402<a href="GPUPolynomialRoots.html" class="index-title-link"> 403<h1 id="Finding_Real_Polynomial_Roots_on_GPUs">Finding Real Polynomial Roots on GPUs</h1> 404 405 406<div class="publication-date">Published 2023-10-31</div></a> 407<p>A recent <a href="VMV2023.html">paper of mine</a> performs an intersection test in a ray tracing <a href="https://www.shadertoy.com/view/dlGSDV">shader</a>. To this end, I had to compute all real roots of a polynomial of moderately high degree (10 to 26). Overall, computing polynomial roots is an extremely well-studied problem where many highly accurate and reliable methods are available <a href="#_Press2007">[Press2007]</a>. However, implementations of such methods on GPUs are rarely found. After experimenting a bit with different options, I ended up implementing a recent polynomial solver proposed by Cem Yuksel <a href="#_Yuksel2022">[Yuksel2022]</a>. I wrote my implementation from scratch in GLSL. A naive implementation has many nested loops or recursions and accesses arrays using loop counters. That is a recipe for register spilling, which is devastating to the performance of the shader. After a bit of puzzling, I ended up with an implementation that avoids this problem entirely. You can take a look at my implementation on <a href="https://www.shadertoy.com/view/dlGSDV">Shadertoy</a> and read on to learn more about how it works, why register spilling is an issue and how I resolved it. <a href="GPUPolynomialRoots.html">Read more...</a></p> 408 409<a href="PathTracingWorkshop.html" class="index-title-link"> 410<h1 id="Path_tracing_workshop">Path tracing workshop</h1> 411 412 413<div class="publication-date">Published 2022-12-20, updated 2024-11-05, 2024-12-17</div></a> 414<p>Now that GPUs have ray tracing units, real-time path tracing is coming into reach. Applications beyond movie rendering and baking embrace it, and therefore more people need to know about it. At
414<a href="https://www.intel.com/content/www/us/en/developer/topic-technology/graphics-research/overview.html">Intel</a>, I recently offered a path tracing workshop to educate a broad audience of engineers on basics of the topic. I am happy to announce that we decided to make this workshop publicly available. If you know a few math and programming basics, you can watch 76 minutes of videos and solve some <a href="https://www.shadertoy.com/playlist/NfjSRy">exercises on ShaderToy</a> as you go. In the end, you will have written your own ray tracer and a path tracer on top of it! I simplified things as much as possible, but you will really write all key aspects of the path tracer and understand why they work. <a href="PathTracingWorkshop.html">Read more...</a></p> 415 416<a href="ToyRenderer5Animations.html" class="index-title-link"> 417<h1 id="My_toy_renderer_part_5_Animations">My toy renderer, part 5: Animations</h1> 418 419 420<div class="publication-date">Published 2022-06-01</div></a> 421<p>I was not planning to have a fifth part in this <a href="ToyRendererOverview.html">series about my toy renderer</a> but there were some interesting changes for our <a href="I3D2022.html">paper on vertex-blend attribute compression</a>. The renderer now supports animations with linear vertex-blend animation (also known as skinning). That means there is a skeleton consisting of animated bones and those influence the mesh. I had to export these animations from Blender to my renderer and I wanted to <a href="ToyRenderer1KeepItSimple.html">keep it simple</a>. Thus, the Blender exporter just dumps all bone transforms for each frame into one big texture that vertex shaders read directly. And as for other parts of <a href="ToyRenderer2SceneManagement.html">the file format</a>, there is some reasonable compression. <a href="ToyRenderer5Animations.html">Read more...</a></p> 422 423<a href="FMA.html" class="index-title-link"> 424<h1 id="fma_A_faster_more_accurate_instruction">fma: A faster, more accurate instruction</h1> 425 426 427<div class="publication-date">Published 2021-12-01</div></a> 428<p>When people look at my shader code, one of the most frequently asked questions is why I use the GLSL <a href="https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/fma.xhtml"><code>fma</code></a> instruction (or its HLSL equivalent <a href="https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/mad"><code>mad</code></a>) so frequently. In spite of the punny title of this post, <code>fma</code> actually stands for fused multiply-add, i.e. it implements the formula <code>fma(a,b,c)=a*b+c</code>. It is faster than separate multiplication and addition because on most CPUs and GPUs it counts as one instruction. It also introduces less rounding error. The real question is whether you should rely on the compiler to use it as appropriate or not. This post explains why I don't and shows a few neat numerical tricks that benefit from <code>fma</code>. <a href="FMA.html">Read more...</a></p> 429 430<a href="MatplotlibSlides.html" class="index-title-link"> 431<h1 id="Matplotlib_slides">Matplotlib slides</h1> 432 433 434<div class="publication-date">Published 2021-08-07</div></a> 435<p>I used to make my slides in <a href="https://products.office.com/en-us/powerpoint">Powerpoint</a>. For my presentations at <a href="Siggraph2021.html">SIGGRAPH 2021</a> and <a href="HPG2021.html">HPG 2021</a>, I tried something different. The whole slide deck is one big interactive <a href="https://matplotlib.org/">matplotlib</a> plot. Every bit is scripted in Python. They feature lots of animated and interactive plots. I am satisfied with how this experiment worked out. Lazily hacking together slides works better with Powerpoint but if you want a high-quality presentation with the best possible illustrations of mathematical concepts, this approach makes sense. This blog post provides some details about how I did it. <a href="MatplotlibSlides.html">Read more...</a></p> 436 437<a href="PolyhedralLights.html" class="index-title-link"> 438<h1 id="Shading_with_polyhedral_lights">Shading with polyhedral lights</h1> 439 440 441<div class="publication-date">Published 2021-07-28</div></a> 442<p>In the past winter term at <a href="https://cg.ivd.kit.edu/">Karlsruhe Institute of Technology</a>, I had the pleasure of supervising Bastian Urbach's bachelor thesis. His topic has been the generalization of methods for shading with polygonal lights to polyhedral lights. He has been highly motivated and creative. The result is an efficie
442nt method for GPU-accelerated real-time shading with convex or non-convex polyhedral lights (see <a href="#Neon">Figure 1</a>). Shading itself works either through linearly transformed cosines <a href="#_Heitz2016">[Heitz2016]</a> or through Monte Carlo integration. And it's implemented in <a href="https://unity.com/">Unity</a>. Both the <a href="https://bastian.urbach.one/rtswplusd/">bachelor thesis and the implementation</a> are now freely available on Bastian's blog. If that sounds interesting, go ahead and read his short blog post or the whole thesis. It's much like a concurrent work published recently at EGSR <a href="#_Aakash2021">[Aakash2021]</a> but there are pros and cons for both techniques. The blog post discusses those as well. <a href="PolyhedralLights.html">Read more...</a></p> 443 444<a href="ToyRenderer4RayTracing.html" class="index-title-link"> 445<h1 id="My_toy_renderer_part_4_Ray_tracing">My toy renderer, part 4: Ray tracing</h1> 446 447 448<div class="publication-date">Published 2021-07-25</div></a> 449<p>Part 4 of this <a href="ToyRendererOverview.html">series about my toy renderer</a> is all about ray traced shadows. In particular, I discuss direct lighting with <a href="Siggraph2021.html">polygonal</a> and <a href="HPG2021.html">linear lights</a> for diffuse and specular surfaces. I have described the corresponding methods in two recent research papers but this post is written with a broader audience in mind. While the papers focus on the mathematical derivation of the algorithms, this post starts with some basics of physically-based rendering and explains in detail why there is a need for these algorithms and how they can be used in a renderer. <a href="ToyRenderer4RayTracing.html">Read more...</a></p> 450 451<a href="ToyRenderer3RenderingBasics.html" class="index-title-link"> 452<h1 id="My_toy_renderer_part_3_Rendering_basics">My toy renderer, part 3: Rendering basics</h1> 453 454 455<div class="publication-date">Published 2021-07-16</div></a> 456<p>Part 3 of this <a href="ToyRendererOverview.html">series about my toy renderer</a> covers some basic techniques for rendering. My renderer does nothing fundamentally new on this front but some choices are a bit exotic. It is ultimately about real-time ray tracing, so everything should play nicely with that. Besides I want it to be slick and fast. Disregarding <a href="https://github.com/ocornut/imgui">dear ImGui</a>, the whole thing only makes two draw calls per frame. It uses a visibility buffer <a href="#_Burns2013">[Burns2013]</a> and the same reflectance model for all surfaces <a href="#_Lagarde2015">[Lagarde2015]</a>. A 3D table of linearly transformed cosines <a href="#_Heitz2016">[Heitz2016]</a> approximates this reflectance model when needed. It almost has a <a href="https://www.shadertoy.com/">Shadertoy</a> vibe since the bulk of all work happens in a single fragment shader for the shading pass. To get stratified random numbers, it uses a recent work <a href="#_Ahmed2020">[Ahmed2020]</a> for 2D <a href="Siggraph2021.html">polygonal lights</a> and <a href="BlueNoise.html">my blue noise textures</a> for 1D <a href="HPG2021.html">linear lights</a>. <a href="ToyRenderer3RenderingBasics.html">Read more...</a></p> 457 458<a href="ToyRenderer2SceneManagement.html" class="index-title-link"> 459<h1 id="My_toy_renderer_part_2_Scene_management">My toy renderer, part 2: Scene management</h1> 460 461 462<div class="publication-date">Published 2021-07-02</div></a> 463<p>Part 2 of this <a href="ToyRendererOverview.html">series about my toy renderer</a> is all about scene data. The requirements are fairly lax, since I only care about static triangle meshes. For the most part, I want to be able to render the <a href="https://developer.nvidia.com/orca">ORCA assets</a> and a couple of scenes from <a href="https://blendswap.com">Blendswap</a>. However, I emphasized how much long compile times harm productivity in the <a href="ToyRenderer1KeepItSimple.html">previous post</a>. All of that applies equally to load times since they interrupt work in a similar way. I want to be able to load huge scenes within seconds and I want to render them quickly. Besides results must be reproducible. <a href="ToyRenderer2SceneManagement.html">Read more...</a></p> 464 465<a href="ToyRenderer1KeepItSimple.html" class="index-title-link">
466<h1 id="My_toy_renderer_part_1_Keep_it_simple">My toy renderer, part 1: Keep it simple</h1> 467 468 469<div class="publication-date">Published 2021-06-25</div></a> 470<p>Part 1 of this <a href="ToyRendererOverview.html">series about my toy renderer</a> covers the most fundamental design decisions. Over the years, I have written many renderers and for a long time their complexity kept growing. This time, I took the opposite route. I wanted to maximize the fraction of code that implements crucial functionality rather than wasting my time on bloaty infrastructure. The code that I wrote (excluding shaders) has 7575 lines at 345 kB. Not exactly a 4k intro but much smaller than any other real-time renderer I have used before. It takes ca. one second to compile and link and startup is also quick. <a href="ToyRenderer1KeepItSimple.html">Read more...</a></p> 471 472<a href="ToyRendererOverview.html" class="index-title-link"> 473<h1 id="My_toy_renderer_Overview">My toy renderer: Overview</h1> 474 475 476<div class="publication-date">Published 2021-06-24, updated 2022-06-01</div></a> 477<p>Alongside my <a href="Siggraph2021.html">latest</a> <a href="HPG2021.html">papers</a> I released the underlying renderer as open source. It is a real-time deferred renderer with ray traced shadows based on <a href="https://www.vulkan.org/">Vulkan</a> and written in C. As I wrote it, I had the liberty to try some unconventional designs and techniques. So I did, because that is an excellent way to learn new things. It also became the basis for our work on <a href="I3D2022.html">vertex-blend attribute compression</a>. <a href="ToyRendererOverview.html">Read more...</a></p> 478 479<a href="LinearlyTransformedSH.html" class="index-title-link"> 480<h1 id="Linearly_Transformed_Spherical_Harmonics_Expansions">Linearly Transformed Spherical Harmonics Expansions</h1> 481 482 483<div class="publication-date">Published 2020-12-02</div></a> 484<p>In my job at the <a href="https://cg.ivd.kit.edu">Karlsruhe Institute of Technology</a>, I usually supervise two bachelor or master theses per term (four per year). By handing out topics that have a sufficiently narrow scope but tap directly into current rendering research, I try to pass on my passion for this subject. <a href="LinearlyTransformedSH.html">Read more...</a></p> 485 486<a href="UsingLyX.html" class="index-title-link"> 487<h1 id="Using_LyX_to_write_ACM_and_Eurographics_articles">Using LyX to write ACM and Eurographics articles</h1> 488 489 490<div class="publication-date">Published 2019-11-11</div></a> 491<p>If you are familiar with <a href="./Publications.html">my work</a>, you may be surprised to hear that I barely ever write documents in LaTeX. All of my first author papers, as well as my bachelor, master and PhD thesis are written entirely in <a href="https://www.lyx.org/">LyX</a>. LyX is a text editor that generates LaTeX code for you. I appreciate it because it helps me get through the creative process of writing without distraction and aids my mathematical research through its excellent formula editor. <a href="UsingLyX.html">Read more...</a></p> 492 493<a href="MetaPost2.html" class="index-title-link"> 494<h1 id="Redesign_of_the_blog">Redesign of the blog</h1> 495 496 497<div class="publication-date">Published 2019-08-27</div></a> 498<p>Over the past year, I have gotten dissatisfied with the <a href="MetaPost.html">setup of my blog</a>. Discoverability of posts was not particularly good, maintenance work began to outgrow the work for new content and I grew tired of the Wordpress layout. Rather than fixing each issue individually, I decided to turn the whole thing into a static HTML page generated by my own set of Python scripts. The resulting redesign will hopefully make it easier for you to find the posts you care about and to read them without distraction and for me to create them. The following post discusses the changes in more detail. <a href="MetaPost2.html">Read more...</a></p> 499 500<a href="SphericalCapMIS.html" class="index-title-link"> 501<h1 id="Sampling_projected_spherical_caps_with_multiple_importance_sampling">Sampling projected spherical caps with multiple importance sampling</h1> 502 503 504<div class="publication-date">
504Published 2019-06-10</div></a> 505<p>This blog post answers a question that <a href="http://www.davidovic.cz/">Tomáš Davidovič</a> from <a href="https://www.wetafx.co.nz/">Weta Digital</a> had about the recently published <a href="./I3D2019.html">projected solid angle sampling for spherical caps</a>. In Monte Carlo rendering, it is very common to combine several sampling techniques through multiple importance sampling. In this case, any of the sampling techniques may produce a sample and then you need to compute the probability density for producing this sample with each of the other techniques. <a href="SphericalCapMIS.html">Read more...</a></p> 506 507<a href="MissingTMBOITCode.html" class="index-title-link"> 508<h1 id="A_brief_postscript_on_moment_based_order_independent_transparency">A brief postscript on moment-based order-independent transparency</h1> 509 510 511<div class="publication-date">Published 2018-08-23</div></a> 512<p>Back in May, we published <a href="./I3D2018.html">moment-based order-independent transparency</a> (MBOIT) at the <a href="http://i3dsymposium.github.io/2018/">Symposium on Interactive 3D Graphics and Games 2018</a>. This brief post follows up on two things; a similar but independent work and some missing code. <a href="MissingTMBOITCode.html">Read more...</a></p> 513 514<a href="DissertationAnnouncement.html" class="index-title-link"> 515<h1 id="My_dissertation_is_available_now">My dissertation is available now</h1> 516 517 518<div class="publication-date">Published 2017-12-31</div></a> 519<p>My dissertation has been published digitially and is now available in its entirety as a <a href="http://hss.ulb.uni-bonn.de/2017/4918/4918.htm">free download</a>. Most results have been published before through my papers at <a href="./I3D2015.html">i3D 2015</a>, <a href="./SiggraphAsia2015.html">SIGGRAPH Asia 2015</a> and <a href="./JCGT2017.html">JCGT</a>. Though, there is some entirely new material. Since I spent a lot of time writing it, there better be somebody to read parts of it. Below I'll try to wet your appetite. <a href="DissertationAnnouncement.html">Read more...</a></p> 520 521<a href="HPG2017Demo.html" class="index-title-link"> 522<h1 id="Demo_with_non_linearly_quantized_moment_shadow_maps_and_more">Demo with non-linearly quantized moment shadow maps and more</h1> 523 524 525<div class="publication-date">Published 2017-09-05</div></a> 526<p>My recent paper on <a href="./HPG2017.html">non-linearly quantized moment shadow maps</a> promises an executable demo. Preparing that took a little longer than expected but to make up for the delay, the demo has plenty of new features. Most notably it now uses <a href="https://github.com/ocornut/imgui">dear imgui</a> and includes the <a href="./BlueNoise.html">applications of blue noise</a> I blogged about earlier. Rather than showing off the new technique only, this demo is an extension of earlier demos, so it also features soft shadows, single scattering and shadows for translucent occluders. <a href="HPG2017Demo.html">Read more...</a></p> 527 528<a href="JCGTAnnouncement.html" class="index-title-link"> 529<h1 id="JCGT_extension_out_now">JCGT extension out now</h1> 530 531 532<div class="publication-date">Published 2017-03-30, updated 2017-09-04</div></a> 533<p>The invited extension of our i3D 2016 paper is now <a href="http://www.jcgt.org/published/0006/01/03/">published in the Journal of Computer Graphics Techniques</a>. It discusses techniques for real-time soft shadows, single scattering and shadows for translucent occluders with some novel improvements. All of these techniques are based on moment shadow mapping and the paper also introduces improvements to moment shadow mapping itself. <a href="JCGTAnnouncement.html">Read more...</a></p> 534 535<a href="3DBlueNoise.html" class="index-title-link"> 536<h1 id="The_problem_with_3D_blue_noise">The problem with 3D blue noise</h1> 537 538 539<div class="publication-date">Published 2017-01-31, updated 2017-02-10</div></a> 540<p>After the <a href="./BlueNoise.html">previous blog post</a> several readers (namely <a href="https://twitter.com/CasualEffects">Morgan McGuire</a>, <a href="https://twitter.com/pixelmager">Mikkel Gjoel</a> and <a href="https://twitter.com/BartWronsk">Bart Wronski</a>) expressed interest in 3D blue noise. Thus, this blog post provides a database of such blue noise textures. It also explains why you might <em>not</em> want to use it. The post relies on concepts introduced in the <a href="./BlueNoise.html">previous post</a> so you should read this one first. <a href="3DBlueNoise.html">Read more...</a></p> 541 542<a href="BlueNoise.html" class="index-title-link"> 543<h1 id="Free_blue_noise_textures">Free blue noise textures</h1> 544 545 546<div class="publication-date">Published 2016-12-22, updated 2016-12-23, 2017-01-31</div></a> 547<p>Dithering is almost as old as computer graphics but recently it has received quite a lot of attention among game developers. To name two examples out of many, <a href="https://twitter.com/pixelmager">Mikkel Gjoel</a> spoke about its use in <a href="http://www.gdcvault.com/play/1023002/Low-Complexity-High-Fidelity-INSIDE">Inside at GDC 2016</a> and <a href="https://bartwronski.com/2016/10/30/dithering-in-games-mini-series/">Bart Wronski wrote a blog post series</a> about it. This attention is well-deserved. <a href="BlueNoise.html">Read more...</a></p> 548 549<a href="JCGT2016Demo.html" class="index-title-link"> 550<h1 id="New_shadow_demo_with_documented_HLSL_code">New shadow demo with documented HLSL code</h1> 551 552 553<div class="publication-date">Published 2016-09-25, updated 2016-09-29</div></a> 554<p>It's time to deliver on a recent promise. <a href="./I3D2015.html">Moment shadow mapping</a> and its <a href="./I3D2016.html">applications</a> have seen quite a few minor but useful improvements lately. The <a href="./GDCEurope2016.html">GDCE 2016 lecture</a> covered some of them but only marginally. This post provides a brand-new <a href="Media/JCGT2016Demo/MSMDemoV2.zip">release of my shadow mapping demo</a> with documented shader code including all these improvements. <a href="JCGT2016Demo.html">Read more...</a></p> 555 556<a href="CubicRoots.html" class="index-title-link"> 557<h1 id="How_to_solve_a_cubic_equation_revisited">How to solve a cubic equation, revisited</h1> 558 559 560<div class="publication-date">Published 2016-09-10</div></a> 561<p>This post covers a little gem worth sharing: The fastest solution to cubic equations with three real roots that I am aware of. It is also fairly robust and I implemented it in HLSL. It is based on the work by Jim Blinn <a href="#_Blinn07b">[Blinn07b]</a> but tweaked for double speed. <a href="CubicRoots.html">Read more...</a></p> 562 563<a href="MetaPost.html" class="index-title-link"> 564<h1 id="Using_Markdeep_for_a_WordPress_blog">Using Markdeep for a WordPress blog</h1> 565 566 567<div class="publication-date">Published 2016-08-20, updated 2016-12-23</div></a> 568<p>In response to <a href="https://twitter.com/CasualEffects/status/765239091986333696">Morgan McGuire's request</a> this post will explain how I set up this blog using his handy <a href="https://casual-effects.c
568om/markdeep/">Markdeep</a>, <a href="http://mathjax.org/">MathJax</a> and <a href="http://wordpress.org/">Wordpress</a>. The blog is hosted on my rented server and when you request a page it usually won't make connections to any other hosts to keep you from being tracked. Most of this post is specific to Markdeep, so you may also find it useful if you have no plans to use Wordpress. <a href="MetaPost.html">Read more...</a></p> 569 570<a href="FirstPost.html" class="index-title-link"> 571<h1 id="Of_posts_to_come">Of posts to come</h1> 572 573 574<div class="publication-date">Published 2016-08-11</div></a> 575<p>I've got a blog now and you're reading its first post. This is not the place to tell you what the blog is all <a href="./About.html">about</a> or to ramble about past <a href="./Publications.html">publications</a> (though, you can download all of them <a href="./Publications.html">here</a>, including code and demos). I'd rather look into the future and tell you what to expect. <a href="FirstPost.html">Read more...</a></p> 576 577 578 579</article> 580</main> 581 582<footer class="main-footer"> 583 <div class="main-footer-content-wrapper"> 584 <div class="main-footer-adjacent-links"> 585 586 </div> 587 <div class="main-footer-external-links"> 588 <a href="https://mastodon.gamedev.place/@MomentsInGraphics">Mastodon</a> 589 <span class="link-separator">|</span> 590 <a href="https://bsky.app/profile/momentsingraphics.bsky.social">Bluesky</a> 591 <span class="link-separator">|</span> 592 <a href="https://x.com/MomentsInCG">X</a> 593 <span class="link-separator">|</span> 594 <a href="https://www.tudelft.nl/ewi/over-de-faculteit/afdelingen/intelligent-systems/computer-graphics-and-visualization/people/christoph-peters">TU Delft</a> 595 <span class="link-separator">|</span> 596 <a href="https://cg.ivd.kit.edu/peters/staff_index.php">KIT</a> 597 <span class="link-separator">|</span> 598 <a href="https://cg.cs.uni-bonn.de/person/dr-christoph-peters">Uni Bonn</a> 599 <span class="link-separator">|</span> 600 <a href="./RSS.xml">RSS</a> 601 <br> 602 <img src="Media/SocialButtons/NewContact.png" alt="Contact" style="width: 223px; height: 21px;"/> 603 </div> 604 </div> 605</footer> 606 607</body> 608 609</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.