BA Digital Games thesis · Cologne Game Lab, TH Köln · supervised by Prof. Dr. Jonas Zimmer
Carpets are hard to render in real time: millions of thin, dense fibers, strong self-shadowing and anisotropic highlights. Games usually fake them with a flat normal-mapped texture.
I implemented two higher-fidelity techniques in the same Unity framework and compared them on two carpet types, shaggy cut-pile and loop-pile, for visual realism, GPU performance and memory.
Each vertex of a flat base mesh spawns one yarn, using a density parameter calibrated per carpet type. Following Wu and Yuksel (2017), each yarn is a hierarchy of helices: plies spiral around the yarn axis, and fibers migrate around each ply.
Geometry is generated on the GPU through hardware tessellation and geometry shaders. No fiber data is stored: every attribute comes from a stable per-vertex seed, which also keeps fibers from shimmering as the camera moves.
A custom per-pixel shading model tuned for textiles:
The hull shader picks tessellation factors from a screen-space projection of the fiber radius, scaling each fiber from 64 segments up close down to 4 at distance. Core fibers keep more detail than surface hair fibers.
Unity caps geometry shader output at about 1024 vertices per invocation, so each invocation emits one fiber segment and tessellation spreads the work across invocations.
The second technique stacks 64 offset copies of the base mesh. Shell slices are generated from a single carpet texture with the histogram-based depth method of Ukaji et al. (2012) and stored in one 2D texture array, instead of 64 separate bindings.
The shader alpha-tests with a taper curve and tip fade, adds rim light that grows with shell depth, combines depth- and density-based occlusion, and casts shadows through a matching shadow-caster pass.
Both renderers ran under an identical camera and a fixed 45° directional light, switched by a script so that comparisons stayed fair, then were compared against reference photographs.
Fibers reproduce the chaotic tufts and separated tips of shag carpet very closely. Shells hold up well at normal viewing distance but flatten in extreme close-ups and at grazing angles.
Top row rendered (fiber left, shell right); bottom row reference photos by Francesca Tosolini and Alireza Akhlaghi on Unsplash.
RTX 3070 (8 GB), 1920×1080, 4× MSAA. Frames per second, higher is better.
| Method | Close-up (0.5 m) | Room view (3 m) | VRAM |
|---|---|---|---|
| Fiber · shaggy | 52 | 1414 | <1 MB |
| Fiber · loop | 32 | 709 | <1 MB |
| Shell · shaggy | 288 | 1063 | 22 MB |
| Shell · loop | 140 | 1005 | 19 MB |
Up close, shells win easily because the fiber renderer has to draw a huge number of small primitives. At medium and long range the result flips: the fiber renderer's dynamic LOD sheds geometry faster than the shells' basic LOD. In a worst-case stress test (screen filled with carpet, no LOD) fibers fell to about 19 fps (shag) and 10 fps (loop), which shows why the LOD matters.
Neither technique wins everywhere, so the thesis recommends a hybrid: shell texturing for large carpet areas and short, dense loop pile, and procedural fibers for hero objects or when the camera gets close. Natural next steps are compute-based culling and mesh shaders for fiber generation.
Loop carpet reference photos by Daniel Sturgess and Wolfgang Hasselmann on Unsplash.