I am a software developer who is enthusiastic about many subjects, including algorithms, computer graphics, analog/digital electronics, science, and engineering.
I use this space to organize my thoughts on various subjects, which may be incomplete or inaccurate, but may still have value for those willing to excercise a bit of skepticism.
Source code for all demos can be found here.
Strafe jumping is a movement technique developed in some of the earliest first-person games which involves continuously adjusting your angle of acceleration to bypass in-game speed limits. Originally considered a bug or defect, it has been adopted by both players and game developers to provide an additional element of skill and depth to these games. Strafe jumping may be considered an early example of emergent gameplay in modern 3D games.
This web application enables any player to learn this skill quickly and easily.
A small application to determine a display’s approximate transfer curve using a series of test patterns.
Scroll up or down to match brightness, then click to move onto the next pattern.
Results will be displayed in a graph with ideal sRGB and Rec. 709/2020 curves for reference.
One of the most powerfully expressive features of modern C++ is the lambda, often used with its std::function wrapper. These functional tools are readily employed in writing generic, reusable code. As asynchronous computing becomes more and more important to make the most of our multi-threaded CPU and GPU resources, these functors also find use in asynchronous event handlers and task distribution/scheduling systems.
What is the cost of all these function objects? The ability to capture arbitrary data in the fixed-size std::function implies that, at some point, we must incur a heap allocation. I would expect, however, that the majority of captures should be relatively small, in which case the obvious optimization is to provide a small, fixed-size storage area within the functor itself to enable stack allocation within these limits. Some quick searching appears to support this (see Futher Reading below), but at what point does this degrade to heap allocation in practice, and just how bad is it?
In this post I’ll analyze the performance characteristics of functors of varying capture sizes to determine under what conditions we begin to observe performance degredation. It is worth noting that the performance we’re measuring is that of std::function, rather than C++ lambdas theselves. C++ lambdas’ types are unspecified, meaning they may not have the same limitations and performance characteristics as std::functions on their own, but they’re also generally less useful for defining interfaces.
A bidirectional reflectance distrubtion function is a function which relates incident irradiance to outgoing radiance. The BRDF generally varies with view direction, light direction, wavelength, and material properties.
For the purposes of this post, I’ve chosen a microfacet model consisting of an Oren-Nayar diffuse term and Cook-Torrence specular term (GGX distribution). It should be noted that these two terms are not strictly compatible – they use different microfacet distributions and roughness values. Alternative diffuse models include those by Burly (“Disney diffuse”) and Gotanda (a numerically-integrated, curve-fitted microfacet model).
Rather than directly storing the BRDF f_\text{r}, we store the BRDF product function f_\text{r}^*=f_\text{r}\cos\theta_i, which takes into account the proportion of light received by a surface from a given angle.
In my earlier post, I outlined the process for generating an environment map for radiance due to atmospheric scatter (i.e. drawing skies). This isn’t particularly useful on its own, so in the next few posts I’ll explore spherical harmonics lighting.
The primary advantage of spherical harmonics is that it greatly simplifies evaluation of environmental lighting. SH lighting reduces the lighting integral (convolution of radiance with a BRDF) to a single dot product. Spherical harmonics are also a very compact storage format for radiance, irradiance, occlusion, distribution functions, etc. and an essential building block for more sophisticated indirect lighting algorithms, such as Precomputed Radiance Transfer (PRT) or Light Propagation Volumes.
The trade-off is a reduction in precision for low-order SH representations and ringing artifacts. Some common operations also become more difficult in spherical harmonics. Multiplication, for example, becomes more complex, making it more difficult to apply visiblity to a SH environment or gather occlusion from multiple SH sources.
Spherical Harmonics are a set of basis functions over the unit sphere. Much like the Fourier or cosine transforms, spherical harmonics allow us to represent a function in terms of its frequency components.
The following is an interactive visualization of the first three bands of real spherical harmonics.
This will (hopefully) be the first post in a series documenting my implementation of a physically-based renderer in WebGL. I am not a physicist, so what follows is my best attempt at an informal overview for graphics programmers. Corrections are welcome.
Also consider skipping to the results :D
Perhaps the most important aspect of photorealistic rendering in games and other real-time applications is plausable environmental lighting. Simple ambient lighting, which is constant in color and intensity for all directions, fails to capture subtle lighting cues present in the real world. The first step, then, in producing photorealistic results is often the creation or acquisition of environment maps. For dynamic outdoor scenes, this necessitates a parametric model of atmospheric scattering which can be adjusted based on time of day.
The appearence of Earth’s sky is due to the scattering of light within the atmosphere. Light from the sun travels through the Earth’s atmosphere where it has some probability of scattering. Some of this light is scattered towards the observer. Two types of scattering occur; Rayleigh scattering, due to small particles or ‘dry air’ (nitrogen/oxygen), and Mie scattering, due to larger particulates such as water vapor. Rayleigh scattering gives the sky its color due to its strong wavelength dependence (proportional to \lambda^{-4}). Blue light scatters more quickly than red light, causing the sky to appear blue. Mie scattering is also dependent on the ratio of wavelength to particle size, but water vapor particles have enough size variation that this wavelength dependence becomes negligible for our purposes. Mie scattering appears as atmospheric haze.
I wrote this graphing program a while ago (2011?) to test WebGL. At the time, WebGL had only just been released and was still experimental in the browsers which supported it.
Graphy plots complex functions of two real values (x and y). The green surface represents the real part of the result, while the red surface represents the imaginary part. A hatching effect is used as a simple order-independent transparency (OIT) solution.