Personal Projects

Graphics

PLANETARY WEATHER




Here we go.
I spent the past two weeks (as of November, 28th 2021) working on real-time planetary volumetric clouds. It's an old dream of mine (one that I started to tackle during my PhD thesis yet without success at the time).
Early results look good. Here are some compressed video footage. The planet radius is 1700 km:

Orbital view - timelapse (x6).

Cumulonimbus formation/dissipation - timelapse.

Fly by...


The videos above showcase a variety of cloud genres, including stratocumulus, cumulus humilis and congestus, altostratus and cirrus, along with a recent attempt at modeling cumulonimbus clouds. It is the result of hard attempts at finding techniques to push that GPU really, in order to achieve interactive cloudscapes rendering over an entire planet. The global input data results from a novel type weather simulation (see paragraph and video below), so cyclonic regions are present. But, the real-time performance is impacted by the difficulty to produce heterogeneity of cloud shapes, different cloud types, and also to advect the clouds, ie., to animate them consistently according to the global wind field. This means, elongation of the clusters of clouds along with their individual movement across the globe and the convection (vertical) movement. Using procedural noise functions as a basis, one can't really achieve this directly (and for "free")... If you translate noise, you can only do so using uniform warping, otherwise as time passes and thus as the divergence grows, the result will soon be riddled with severe artifacts. Anyway, at the cost of a bit of performance, I can now advect noise properly using an abritrarily varying vector field (that is, the wind field). The total frame time though is still not that good, due to lots of texture cache misses, but LOD decoupling could help.

The video below is a nice rendering of the frames produced by the simulation I was mentionning above. It is a fluid sim across the sphere, although of a novel type since I designed it to allow full control of where the lows and highs (ie., cyclonic and anticyclonic regions) are located at each timestep. There is also cloud microphysics (evaporation, condensation, sublimation, precipitation ,etc.). Not everything is working neatly atm, as I only spent 3 weeks on that prototype. But I like it nonetheless.





Software

ORB CRAFTER

Most of 2021 was dedicated to developing my commercial project Orb Crafter : a map making tool for PC (Windows, Linux), aimed at tabletop gamers and map enthusiasts. The specialty of the software lies in a clever and semi-automated handling of large scale worlds (planets) and thus world maps, with switchable world projections, automatic extraction of hires regional maps, and then export to image formats at arbitrarily high resolutions.

I've put up a website for the project, to expose the main design elements along with a devlog : https://www.orbcrafter.com. In a nutshell, the tool is currenly still being developed (about 70% completion) as of August 2021, it is written in C++ against my own custom game/multimedia engine (CARGO), and relies almost exclusively on the GPU (through OpenGL 4.x) to generate content and to implement user edits (brushes, river curves, etc.).



All in all, I've invested 6 months of my time on the project. Here is a short-list of some technical problems I had to solve :
  • First things first, I had to design a novel and fast method to generate world maps (ie., the world Wizard) bearing tectonic features, including cordilleras, rifts and islands arcs. The solution I came up with was to first create a 3D partition of the surface of the planet into warped Voronoi cells, each representing a "proto-plate" (for lack of term) - and second, to dispatch a compute shader against each pixel of the map to perform a parallelized functional resolution of the final topography: the main parameter being the local distance to the border of the proto-plate, enabling the generation of the continental coast (possibly by shrinking the proto-plate), the potential local cordillera or the islands arc (if the plate is oceanic). The GPU implementation runs real fast, and thus allows real-time tweaking of the parameters in the interface.

  • For the user convenience, and because it is an industry standard, I had to code the Undo/Redo functionality. I found that a well kown design pattern called Command could do the job. I've implemented it, for the first time, and it went well, albeit with substantial work. I also added a slight optimization: the code distinguishes between heavy ops (wizards) and light ops (brushes) to skip otherwise unnecessary traversal and replay of all the command history (since a heavy op performs a complete resurfacing of the planet).

  • The user can save his/her Projects, which are containers for a set of N maps (at least 1 worldmap and N-1 regional maps derived from it). I came to the conclusion that the only efficient way of serializing potentially N large images, all coming with editable information (text labels, symbols, etc.), was to simply and directly serialize the command history of each map into a blob, and to forget entirely about "images". In practice, it turns out to be real efficient to serialize (because of the compacity of the parametric representation) and the GPU can indeed replay the history pretty fast when loading a map from a Project. Moreover, another significant advantage can be taken out of this model: which is the possibility to export at arbitrarily high resolution any of the map (to PNG, JPEG, etc.). There is in fact but one caveat with this approach: I will have to keep track of versioning, meaning the versions of the individual commands, since the software can and will evolve with each release/update (we don't want old maps to look different then).

  • One major feature of Orb Crafter is to allow for multiscale editing. In a nutshell, given a world map, the user should be able to select a region of it and to work in high res on it. Not an easy task. But, since we can re-create the world map at arbitrarily high resolution (see previous bullet), half of the work is already done. What's left is to project the spherical (planetary) data of the world map onto the selected (planar) region, placed tangentially to the sphere at some longitude/latitude central point. With a bit of 3D euclidean geometry it's not that hard, I just had to copy paste the bulk of the shader code written for world map commands (wizards, brushes...) and to place them in a new set of shaders tasked with the recreation of the world restricted to the selected region. There was only one problem, and it was the 32 bits floating point precision on the GPU side when I had to deal with polar coordinates (due to imprecisions in the cos and sin shader instructions) - so I had to find my mathematical way around spherical coordinates.

  • Finally, once extraction and replay of the world commands were implemented, I had to face the daunting task of generating new details in the regional maps - details not present in the world map that is. Local procedural generation could be a solution if it weren't for the coherence problem of having, say, two adjacent or overlapping regional maps which would definitely need to share the same local features... So my proposal was to paste and blend precomputed DEMs (Digital Elevation Models, or heightmaps) of size 256x256km, each placed randomly at one vertex of a spherical Delaunay triangulation (of precision ~80km) covering the whole planet. Each DEM lies tangentially to the sphere and is randomly rotated and translated, to avoid visual repetitions. The final blend is barycentric within each triangle of the Delaunay thing. At the price of somewhat tedious book-keeping of the data structures (CPU) and buffers involved (GPU), the intersection of a pixel of the regional map with the Delaunay triangulation is precomputed in order to speed up the final GPU terrain generation. Note: what's nice with the DEM approach is, it is fast to resolve on the GPU (texture fetches) and you can offer convenient painting capas to the user, you just need to paint the topographic mask and the GPU automatically enhances the final terrain by pasting the detailed DEMs (one can paint classic alpine mountains or hills, but also volcanoes, etc., anything that can be stored as heightmaps really).



PHANTOM STARS

Circa 2015, whilst in university, I started to program my own little graphics things. The first convincing prototype to come up was a volumetric procedural spiral galaxy. Many iterations occurred since, and the results kept getting better, to the point where I thought of giving scope and purpose to the prototype: hence the project Phantom Stars. It is meant to be a full-fledged II video game.

Development of the custom game engine started early 2019. Many core functionalities have been laid out (see next section), like memory management, GUI stack, logging, profiling, localization, etc.

Despite good progress on the engine, the game, Phantom Stars, is still a graphics prototype, as no gameplay feature has been implemented yet. Here are some screenshots taken recently (as of July 2020).





Here is quick technical/design view on the project :
  • Galactic Model. The setting is constrained to a unique spiral galaxy, about 100,000 light-years in diameter. The galaxy is customizable by the player since the model is generated from a set of parameters. Internally, the galaxy is modeled by a RGBA volume - the RGB triplet gives the stellar luminosity of star fields, and the A channel is simply the opacity of the interstellar medium (ISM), ie. massive clouds of gas and dust. A compute shader is in charge of computing each of the volume layers. Spiral warping is applied to a cross-shaped domain to yield the spiral arms, while the galactic bulge is an ellipsoid. Local light in each texel of the volume results from distributions of star fields: either yielding a kind of "diffuse" light on average of young stars (Pop I) in the spiral arms (blue light) or older metal-poor stars (Pop II) near the bulge and in the disk halo (orange light), or yielding a direct "spot-like" emission of hyper/super giant stars, either blue (main sequence massive stars of class O) or red (red giant branch, luminous dying stars). The code relies on numerous coherent noises (simplex noise), combining more than 200 octaves for each texel, coupled with hash functions to distribute the massive stars. The volume is rendered in real-time by raycasting the intersection with the galactic bounding box and then raymarching with accumulation of luminosity and opacity of the model.

  • Local Space Model. The player can visualize the so-called Local Space, ie. a randomly chosen 1000 light-years cube of space (a galactic sector) anywhere in the galaxy. The entire galaxy is subdivided into voxels of size 32^3 light-years, one such sector is therefore a collection of about 30x30x30 voxels. A sequence of compute shaders is dispatched : the first one samples the galaxy at the center of each voxel (to yield ISM density, pop I & II stellar densities, presence of giant stars by type, etc.), the second compute shader generates the "seeds" of the local stellar systems (which boils down to the total mass of the system, and its category) present in each voxel according to probabilities tied to the local star field densities, and, lastly, the third compute job generates the detailed profile of each star system (multiplicity, ie. from 1 to 7 stars bound in orbit within the system, and the details of each star, so mass and age from which I can derive temperature, luminosity, radius, etc., by using conventional astrophysical laws for main sequence stars and exotic bodies like neutron stars, white dwarves, etc.). For each voxel, the most luminous star systems are registered in order to illuminate the surrounding ISM (gas), the latter being distributed according to the galactic sampling. To give some numbers, in the vicinity of the spiral arms such a sector of space yields about 200,000 star systems, and near the bulge about 5 times more can be generated - note that I had to artificially lower the stellar density (compared to real data) near the bulge to keep decent performances. Concerning rendering: each system and each ISM primitive are rendered as billboards (screen facing quads), each with transparency, the color of a star system is given by its average temperature (this is a weigthed average over its individual stars) - I rely on a realistic RGB table of star colors according to their classification. The size of each point-sprite depends on the distance to the camera and on the system' absolute magnitude (again, using a physical law).

  • Star Systems and Planets. Whereas the last two models above (galaxy/local space) make heavy use of the GPU, here the modeling is performed on the CPU. Given the global characteristics of a star system generated previously (ie. its stars and galactic position), I first compute the orbital characteristics of the stars (1 to max. 7). Using common astrophysical knowledge (ie. orbits are hierarchical against pairs of stars), the Keplerian (elliptical) orbits are computed such that, given a timestamp t, I can derive the actual 3D position of each star. Then the algorithm decides the presence of planets. A simplified evolution scenario is applied to the system, which randomly places planetary embryos given the frost line within the young system (so either rocky cores or icy cores), and then make them grow by accretion followed by random migration within the protodisk, which yields ejections, collisions and orbital changes. After this simulation, we are left with a set of N planets, defined by orbits, mass and type (rocky, icy, gaseous). Each of the surviving planet is then detailed by another algorithm, to yield the final, current characteristics of the body : mass, density, size, orbit (excentricity, inclination, tidal locking, ...), amount of input radiation from the stars (so temperature at the atmospheric boundary, given global albedo), differenciation of the planet core and magnetosphere, possible atmosphere, geological characteristics, hydro/cryo sphere, etc.. For rocky planets, rendering is performed - once a cubemap is precomputed (by a compute shader) to model the actual terrain (main colors, craters, topography, according to the planet characteristics) - by raymarching the atmosphere (if any) using only single-scattering and then intersecting the terrain. Some custom antialiasing solution is performed to ensure a nice spherical shape of the planets. Beyond these, I also attempted to add other features, like: planetary clouds (which are almost ok) and also exploration of the planetary surface in real-time (this feature being largely experimental, and probably not required for the final gameplay).

  • Future Gameplay. In Phantom Stars, the player will be able to lead an organization (a corporation, or a crime syndicate), evolving in a dystopian interstellar society (of limited size compared to the galaxy as a whole). He/she will be able to:
    • Explore space: by surveying the stars from a distance and from outposts, then dispatching probes and explorer ships in order to create new space lanes and getting in situ info and visualization of the planets/systems of interest.
    • Engage in industrial activities on newly colonized planets that prove to be inhabitable (or at least prove to be compatible with human activity, so gravity, temperature, atmosphere and protective magnetosphere, are things that matter), and that harbour interesting resources (metals, water, rare earths, etc.). The construction and operation of complexes, bases, outposts, along with cargo and supply routes will require good logistics skills from the player as is common in 4X games.
    • Dispatch agents in known space on various missions: infiltration of opposing organizations, hacking, sabotage, assassination and kidnapping, etc. Investigation and more generally commerce of information will be paramount in the game... To allow for this, I have began to design and implement a novel data paradigm (structures and algorithms) that operates across code modules and that will yield a dynamic and semantic view of the universe. I won't discuss more about this feature, but my big hope is: to prove that it can actually work, that it can offer a richer and smarter gameplay to the player, and to - why not ?- end up giving nice GDC talks in the distant future ! ;)
    • Manage budgets and departments, create and manage Operations with timelines, legal or illegal. Shadow ops will be possible, far from the administration oversight, but risky.
    • Engage in (tactical) warfare: mainly space fleet battles.
    • Discover and learn more about the lore, world issues and to make important yet not so easy choices (with moral dilemas implied)...

    To conclude, true fans will have recognized in this list most of the features of an old PC game from LucasArts... Star Wars Rebellion. But that's no surprise as I am a true fan of this game and more generally of George Lucas' universe - and I've been wanting to propose for a long time a thoroughly extended, richer, visually more realistic version of this old game... To be continued!



THE CARGO ENGINE

Cargo is this multimedia engine that I have developed over the years (most of the work had been laid down in 2019) in order to prototype things and also carry on with the development of full-fledged client applications like Orb Crafter. Internally it is architectured as a bundle of custom modules operating alongside an organized extension of low level C-like open source libraries performing various duties. Windowing and inputs are managed by GLFW3 (and SDL2 before that, but I found GLFW to be a bit more practical for certain things - unicode Text Input for instance). For rendering and 3D, OpenGL4.6 runs the show (via the Glad loader). For text rendering, I'm relying for now on Freetype2, but I'm thinking about porting the code to stbtt and signed distance field fonts (since I have successfully tested and implemented this for project Orb Crafter). Image formats, loading and saving is performed by FreeImage, whereas the math lib is GLM (being used to GLSL, this is a nice handy way to write math code).

Apart from these, other modules have been written by myself. Here is a quick list:
  • Strings and Localization : All character strings that will end up on screen and more generally presented to the user are encoded in UTF8 and are constructed using a custom class cargo::String. Moreover, I have developed a tool for Localizing client apps, that allows to register all of these strings (the tool being itself developed against Cargo). The strings are organized in Categories, each Category being a semantic group of N text elements, each element can be specified and entered in each of the supported languages of the final application. One can add other languages later on in development. Each language defines a bunch of global strings (for instance, the decimal separator, '.' in English or ',' in French). The tool offers a convenient (automated) way to export: one meta localization file (ie. a description of supported languages and affiliated global strings), one big file storing all localized strings, and one c++ header file which defines macros and constants used for efficient referencing in the client code of any of the localized strings (themselves stored in one big memory block at runtime).

  • Rendering : A c++ wrapper encapsulates OpenGL in a generic way. This effort lies mid-way between a mere boost in productivity when it comes to writing 3D/compute code, and a full abstraction of the graphics API. Still, I think it will prove difficult to use the same architecture for, say, a Vulkan abstraction, since its modern coding paradigm diverges thoroughly from the simple state machine thing that OpenGL offers. Nonetheless, this wrapper proves very handy, I can declare, setup or use my GPU resources with one line of code or so, and I can work shader magic very rapidly, bypassing all of the OpenGL boiler plate code, which is just fine to iterate on development.

  • Memory : After some network investigation, I've come across all sorts of nice looking snippets for low-level custom memory management - yet riddled with bugs. So I endeavored to clean them up and assemble them into a module that would allow to get rid of malloc, new, delete, etc. (for performance and tracking purposes). All in all there is now an interface called Allocator coming with concrete classes StackAllocator, PoolAllocator and FreeListAllocator - all implemented in low-level C (using pointer arithmetics and type casting) and allowing for precise and efficient allocation/freeing of memory blocks. A bunch of macros filter allocations/deallocations and optionally allow for tracking memory usage on the client side. Variadic templates allow for abritrary constructors to be called by the client.

  • Logging : The logging module is totally custom. Handy variadic macros offer message registration capabilities to the client, ie. each message can be filled with the values of common types (string, float, int, ...). The log manager dispatches by default and asynchronously the messages to a Logger which records them sequentially into a text file. Each line is formated by log level, timestamp, source file, source line, etc.. This default logger is in reality a separate process, launched by the engine at startup, and the latter communicates with it via a NamedPipe (using only Win32 calls for now). This scheme allows for keeping track of messages even if the main application crashes, the logger remaining active until a certain timeout value is met.

    Sample messages (formating):
    2021-08-27 22:18:55 | INFO    | Engine.cpp              at line    91 | [sysinfo] Total Memory MB = 16312
    2021-08-27 22:18:55 | INFO    | Memory.cpp              at line    54 | Reserved memory by the engine = 32 MegaBytes
    2021-08-27 22:18:55 | INFO    | backend_glfw.cpp        at line   289 | Detected monitor #0: Generic PnP Monitor (primary)
    2021-08-27 22:18:56 | INFO    | backend_glfw.cpp        at line   290 | Monitor #0, current mode: 1920 x 1080 x 24 (16:9) (8 8 8) 60 Hz
    			
  • GUI and Inputs : I've implemented from-scratch the complete architecture that deals with the graphical interface. All rendering of the interface (widgets) happens on the GPU, a unique shader is put to work to render either shapes (rect, roundrect, ellipsis), or icons and text, or images. The client can use the following widgets for now: Widget (base class but instanciable, represents a generic container shape on screen with mouse input capas), Button, Slider, RangeSlider, RadioButtonGroup, Canvas (points, lines and NURBS curves), Label, TextField, List, ComboBox, ScrollPane and TabbedPane - along with support classes like Tooltip, Layout, Stage, Layer (the GUI is organized in fullscreen layers for each Stage) and Event. Overall, the GUI module was a thorough piece of effort to implement: quality text rendering, many types of widgets, unicode text input, events dispatching, stage architecture with widget registration and traversal, etc..

  • Disk Resources : I have developed yet another tool to correctly handle all the assets of a client application: CargoPack. This executable reads a XML resource file that the user provides and that references all disk assets (with naming and attribution), and then loads them into memory, applies a preprocessing if need be (for instance, obfuscating all GLSL assets), packs all the loaded/transformed assets into N binary files of roughly equal size, and finally produces a meta file to be consumed by the engine at runtime (this is a registration of all named/attributed assets) so it can load assets (synchronously, asynchronously) on demand. Besides pure assets, CargoPack also packs and registers the client app' Configuration, via a user entered text file (Key/Value), which allows to define custom globals at runtime (this is opaque to the final users of the app, as are all assets).

  • Utils : Hash functions, timers, coherent noises (Simplex, Worley, etc.), NURBS curves and surfaces, ... etc.!

To wrap this up: it was very satisfying (and quite an adventure) to write all of the above modules. Still, some things are missing: I'm thinking about scripting capabilities (Lua, or other), more precise profiling of client code (for now it is just a simple solution based on what the streamer The Cherno proposed), and completion of the Audio module (for now, a simple wrapper over RtAudio, adjoined with DSP modules that I could gather from the net (reverb, EQ, delay, compressor, ...)), and other things not envisioned yet but that could prove useful in the future.



RPG

GUERRE ASTRALE (TTRPG)

A long term running project, "Guerre astrale" is a tabletop RPG with a custom set of rules and an hand-crafted universe. The theme is classic heroic-fantasy, albeit tinted by elements borrowed from Lovecraft and some oriental philosophical systems (like taoism). For those of you interested there is a dedicated website wwww.guerre-astrale.fr, but beware, it is entirely written in french.


I painted these hi-res maps using Photoshop.



Music

TECHNO

I produce electronic music when I get the chance to, and especially Techno (under the moniker of Yankee Charlie).
Here are some recent tracks:
Yankee Charlie ยท Status EP
2020