PageSourceSearch

https://momentsingraphics.de/

html momentsingraphics.de collected 2026-10-02 04:18:49 UTC 42,125 bytes, 609 lines download raw bytes

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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&#225;&#353; Davidovi&#269;</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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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&nbsp;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.