{"id":26364852,"url":"https://github.com/lightandlight/3d-graphics-fundamentals","last_synced_at":"2025-03-16T19:28:30.741Z","repository":{"id":189247059,"uuid":"663848259","full_name":"LightAndLight/3d-graphics-fundamentals","owner":"LightAndLight","description":"Learning 3D graphics fundamentals","archived":false,"fork":false,"pushed_at":"2024-08-10T00:29:07.000Z","size":1156,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-08-11T00:52:09.097Z","etag":null,"topics":["graphics","rust","wgpu"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LightAndLight.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-07-08T08:59:18.000Z","updated_at":"2024-08-11T00:52:09.098Z","dependencies_parsed_at":"2023-08-19T00:39:40.591Z","dependency_job_id":null,"html_url":"https://github.com/LightAndLight/3d-graphics-fundamentals","commit_stats":null,"previous_names":["lightandlight/3d-graphics-fundamentals"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAndLight%2F3d-graphics-fundamentals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAndLight%2F3d-graphics-fundamentals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAndLight%2F3d-graphics-fundamentals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAndLight%2F3d-graphics-fundamentals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LightAndLight","download_url":"https://codeload.github.com/LightAndLight/3d-graphics-fundamentals/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243919135,"owners_count":20368837,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphics","rust","wgpu"],"created_at":"2025-03-16T19:28:30.384Z","updated_at":"2025-03-16T19:28:30.732Z","avatar_url":"https://github.com/LightAndLight.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Realtime 3D Graphics Fundamentals\n\n\u003cimg src=\"./screenshot.png\"\u003e\n\nThe intent behind this project was to use a 3D graphics API to render more than [just a\ntriangle](https://vkguide.dev/docs/chapter_2), and learn some of the classic realistic\nrealtime rendering techniques. The main features I ended up with are:\n\n* Physically-based shading\n* High-dynamic rendering with automatic exposure and tone mapping\n* Directional lights\n  * With a shadow map fitted to the view frustum\n* Point lights\n  * With omnidirectional shadow maps\n* HDRI skybox\n\nI'm very happy with the progress I made over the ~6 weeks I spent on this. I feel like I've broken\nthrough some conceptual barriers regarding computer graphics and graphics APIs. I'm better able to\nuse the GPU as a creative tool because I'm more familiar with the computing platform it offers and\nthe current 3D graphics API paradigm.\n\n## Issues / future work\n\nLearning more about computer graphics has meant realising that some of the\nfundamentals aren't enough for creating realistic / physically plausible images.\nI'm wrapping up this project because I feel like I've achieved everything I set out to,\nand that means leaving it with a bunch of issues I couldn't have anticipated\nwhen I started.\n\n### Shadows\n\nThe most obvious issue in the screenshot is the directional light's shadow map resolution. The\ncamera frustum is quite large which lowers the effective resolution of the shadow map, leading to\nvery blocky shadows. Less obvious, but related, is extreme projective aliasing of shadows at\nglancing angles. For the screenshot I chose a far plane and light direction that made this issue\nless visible. Cascaded shadow maps seem like the next step toward improving the shadows. I'm also\ncurious whether one can then go from cascades (subdividing the view frustum along the Z axis) to\nclusters (subdividing view frustum along X, Y, and Z, ala clustered shading) to get even more\nprecise use of shadow map resolution.\n\n### Environment lighting\n\nThe HDRI skybox doesn't actually cast light onto the scene.\nThe black spheres are black because they aren't reflecting any of the sky's light.\nThe shadows are pure black for the same reason. With that amount and colour of ambient light, the shadows\nshould be lighter and tinted blue.\n\nI would try improve environment lighting by handling specular and diffuse reflections separately.\nThe first step for specular reflections would be to reflect the skybox correctly. Each black sphere\nshould become a metallic sky-reflecting ball. I think I can do that without bringing in any new\nconcepts.\nNext is to have the rest of the scene contribute to specular reflections, which seems to be where\nthe topic opens up. I think I'd start by playing with manually placed local reflection probes, and\nmaybe screen space reflections.\n\nFor diffuse environment reflections, I'd try creating an [irradiance\nmap](https://learnopengl.com/PBR/IBL/Diffuse-irradiance) from the HDRI.\nThen I'd look to irradiance probes to capture how ambient light changes in response to the scene.\nThey seem really complicated, though.\n\n### Test scenes\n\nI'd love to be able to render common test scenes, such as [Crytek's\nSponza](https://www.cryengine.com/marketplace/product/crytek/sponza-sample-scene) ([super\nsponza?](https://www.intel.com/content/www/us/en/developer/topic-technology/graphics-research/samples.html))\nor the [Amazon Lumberyard bistro](https://developer.nvidia.com/orca/amazon-lumberyard-bistro). They\nseem like the easiest way to get a realistic realtime scene so that I can check the quality and\nefficiency of my rendering.\n\n## A note on code quality\n\nSince my goal was to learn realtime rendering, I chose to reduce my emphasis on writing good code. I\nfelt that it would be too easy for me to get distracted by software architecture (something more\nfamiliar to me), at the expense of learning computer graphics. I biased toward repeating similar\ncode and hard-coding things, rather than creating abstractions. As a result, I\ndo not consider this code \"production quality\" - please keep that in mind if you read it.\n\n## The rest of this document \n\n\u003c!-- no toc --\u003e\n* [Goals](#goals) - I tracked my feature progress here.\n* [Stretch goals](#stretch-goals) - Features that seemed cool but not \"fundamental\"; probably out of my reach this time around. \n* [For fun](#for-fun) - Features and ideas that weren't important for getting the renderer working,\n  but seemed useful in a real world renderer, or just fun to build.\n* [Resources](#resources) - The reference materials I relied on to figure all this out.\n\n## Goals\n\n* Remember GPU programming\n  * [x] Basic render pass\n  * [x] 2D rendering\n* Render simple 3D objects in perspective\n  * [x] Camera and perspective\n  * [x] `.obj` model rendering (vertex positions)\n  * [x] Per-object transformation matrix\n  * [x] Depth testing\n  * [x] Compute vertex normals when missing from `.obj` files\n* Shade objects using physically-based techniques\n  * [x] Include vertex normals\n  * [x] Punctual and directional lights with diffuse reflectance\n  * [x] Specular reflectance for dielectric materials\n  * [x] Per-object material parameters (color, roughness)\n  * [x] Metallic materials\n  * [x] Physical light units, manual exposure\n  * [x] Tone mapping\n  * [x] Automatic exposure using average scene luminance\n* Shadow mapping\n  * [x] Basic shadow map for directional lights\n  * [x] Omnidirectional shadow mapping (point lights)\n  * [x] Light frustum fitting\n* Environment mapping / image-based lighting\n  * [x] HDRI skybox\n* Use GPU-driven techniques as much as possible\n  * [x] Per-object transformation matrices stored in a single GPU buffer\n* [x] [`egui`](https://github.com/emilk/egui#-egui-an-easy-to-use-gui-in-pure-rust) integration\n* [x] Auto-resize screen\n\n## Stretch goals\n\n* [ ] Anti-aliasing\n* [ ] Ambient occlusion\n* [ ] Bloom\n* [ ] Area lights\n* [ ] Histogram-based auto-exposure\n* [ ] Parallax occlusion mapping\n* [ ] Virtual/adaptive shadow maps\n* [ ] `draw_indirect`\n\n## For fun\n\n* [ ] Parse-less on-disk model format with a program that converts to / from `.obj`\n  \n  To load meshes straight from `mmap`ped files.\n\n* [ ] Render the depth buffer on screen\n* Performance improvements\n  * [ ] Indexed draws\n\n\n## Resources\n\n* Graphics programming on GPUs\n  * \u003chttps://zdgeier.com/wgpuintro.html\u003e - `wgpu` / `WGSL`\n  * \u003chttps://sotrh.github.io/learn-wgpu/\u003e - `wgpu` / `WGSL`\n  * \u003chttps://vkguide.dev/\u003e - `vulkan` / `GLSL`\n  * \u003chttps://learnopengl.com/\u003e `opengl` / `GLSL`\n* Normal calculation\n  * \u003chttps://computergraphics.stackexchange.com/questions/4031/programmatically-generating-vertex-normals\u003e\n  * \u003chttps://iquilezles.org/articles/normals/\u003e\n* Physically based shading\n  * \u003chttps://interplayoflight.wordpress.com/2013/12/30/readings-on-physically-based-rendering/\u003e -\n    PBS literature master list \n  * \u003chttps://developer.nvidia.com/gpugems/gpugems3/part-iv-image-effects/chapter-24-importance-being-linear\u003e\n  * \u003chttps://renderwonk.com/blog/index.php/archive/adventures-with-gamma-correct-rendering/https://renderwonk.com/blog/index.php/archive/adventures-with-gamma-correct-rendering/\u003e\n  * \u003chttps://blog.selfshadow.com/publications/\u003e - SIGGRAPH's \"Physically Based Shading in Theory and\n    Practise\" series\n    * \u003chttps://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf\u003e -\n      Very clear introduction to physically based shading fundamentals\n  * \u003chttps://www.realtimerendering.com/\u003e\n    * Chapter 9 - Physically Based Shading\n  * \u003chttps://google.github.io/filament/Filament.html\u003e - explanations of physically based rendering\n    in the context of Google's [Filament](https://google.github.io/filament/) engine\n  * Production implementations\n    * Blender - \u003chttps://github.com/blender/blender/blob/main/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl\u003e\n    * Disney - \u003chttps://github.com/wdas/brdf/blob/main/src/brdfs/disney.brdf\u003e\n* HDR rendering\n  * Exposure\n    * \u003chttps://en.wikipedia.org/wiki/Film_speed\u003e\n    * \u003chttps://en.wikipedia.org/wiki/Exposure_(photography)\u003e\n    * \u003chttps://en.wikipedia.org/wiki/Exposure_value\u003e\n    * \u003chttps://en.wikipedia.org/wiki/Sunny_16_rule\u003e\n    * \u003chttps://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/\u003e\n    * \u003chttps://placeholderart.wordpress.com/2014/11/21/implementing-a-physically-based-camera-manual-exposure/\u003e\n  * Tone mapping\n    * \u003chttps://seenaburns.com/dynamic-range/\u003e\n    * \u003chttps://64.github.io/tonemapping/\u003e\n    * \u003chttp://filmicworlds.com/blog/filmic-tonemapping-operators/\u003e\n    * \u003chttp://filmicworlds.com/blog/why-a-filmic-curve-saturates-your-blacks/\u003e\n    * \u003chttp://filmicworlds.com/blog/filmic-tonemapping-with-piecewise-power-curves/\u003e\n    * \u003chttp://duikerresearch.com/2015/09/filmic-tonemapping-for-real-time-rendering/\u003e\n* Shadow mapping\n  * \u003chttps://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping\u003e\n  * \u003chttps://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-12-omnidirectional-shadow-mapping\u003e\n    * Cube map face selection\n      * \u003chttps://stackoverflow.com/questions/6980530/selecting-the-face-of-a-cubemap-in-glsl\u003e\n      * \u003chttps://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/\u003e\n  * Projection fitting\n    * \u003chttps://learn.microsoft.com/en-us/windows/win32/dxtecharts/common-techniques-to-improve-shadow-depth-maps#techniques-to-improve-shadow-maps\u003e\n    * \u003chttps://gamedev.stackexchange.com/questions/73851/how-do-i-fit-the-camera-frustum-inside-directional-light-space\u003e\n    * \u003chttps://www.gamedev.net/forums/topic/591684-xna-40---shimmering-shadow-maps/\u003e\n* Depth buffer precision / logarithmic depth buffers\n  * \u003chttps://outerra.blogspot.com/2009/08/logarithmic-z-buffer.html\u003e\n  * \u003chttps://www.gamedev.net/blog/73/entry-2006307-tip-of-the-day-logarithmic-zbuffer-artifacts-fix/\u003e\n  * \u003chttps://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html\u003e\n  * \u003chttps://outerra.blogspot.com/2013/07/logarithmic-depth-buffer-optimizations.html\u003e\n  * \u003chttp://web.archive.org/web/20201113123351/https://thxforthefish.com/posts/reverse_z/\u003e\n* Test models\n  * \u003chttps://github.com/alecjacobson/common-3d-test-models\u003e\n  * \u003chttp://graphics.stanford.edu/data/3Dscanrep/\u003e\n  * \u003chttps://www.cc.gatech.edu/projects/large_models/index.html\u003e\n\n    (change `www-static` to `www` on downloads)\n  * [Utah teapot](https://en.wikipedia.org/wiki/Utah_teapot)\n    * \u003chttps://graphics.stanford.edu/courses/cs148-10-summer/as3/code/as3/teapot.obj\u003e\n    * \u003chttps://graphics.cs.utah.edu/courses/cs6620/fall2013/prj05/teapot.obj\u003e\n  * [Stanford bunny](https://en.wikipedia.org/wiki/Stanford_bunny)\n    * \u003chttps://graphics.stanford.edu/~mdfisher/Data/Meshes/bunny.obj\u003e\n* `.obj` parser: \u003chttps://crates.io/crates/tobj\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightandlight%2F3d-graphics-fundamentals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flightandlight%2F3d-graphics-fundamentals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightandlight%2F3d-graphics-fundamentals/lists"}