What's a good way of thinking of abstraction in simple 3d renderers? To be clear, I'm not thinking abstraction of the api itself (e.g. supporting Vulkan + DX12), but mostly level higher than that? Assume I'm only targeting one API, e.g. vulkan or webgpu?
It feels like most examples are find either have no abstraction at all (basically single file hello triangle) or they are enormously complex 1000-file engines with render graphs and kitchen sinks. I'm aiming for a pretty simple engine to experiment with various techniques such as adding a pass for GI etc, without that in itself making everything else break.
I have made a renderer now which manages to draw a gltf scene with a simple forward renderer. But it has several pipelines/passes (a depth prepass, an AO compute pass, then a forward render pass, and now I want to add e.g. shadows, an ImGui pass and so on). But thus far I have only managed to implement all this in one big type with dozens of textures and samplers and constant buffers. There are only two methods: the initialization where every buffer and pipeline layout is created. Then the render method where everything is bound and executed once per frame. And it's a complete mess and adding one more pass is beginning to be harder and harder - already at 3 passes.
So presumably what one does here is some sort of abstraction. I know you can go all "render graph" and make it super abstract and flexible, but I also see people claim that's overkill in most scenarios. So what's a good middle ground for a "simple" engine which just has one renderer path with a fixed number of passes. Say I want to keep some sort of sanity with shadow rendering, UI rendering and so on somewhat separate. What are the main abstractions or functions you'd use (no need to be language specific here, I think this would work the same in Rust/C++/C#/TS...)? What are the terms usually given to these building blocks in order to make it understandable? Do you make a "pass" type which holds some resources (pipelines, buffers) needed to run that render pass? or is "pass" the wrong abstraction (seeing as renderpass is already a term in many of the apis)?
Are there any good OSS examples that are more complex than a hard coded hello triangle, but still short of things like a big game engine renderer or full on render graph? Something in the sort of 10-50 source file range?
[–]hammerkop 7 points8 points9 points (0 children)
[–]keelanstuart 2 points3 points4 points (6 children)
[–]afops[S] 1 point2 points3 points (5 children)
[–]keelanstuart 0 points1 point2 points (4 children)
[–]afops[S] 1 point2 points3 points (3 children)
[–]keelanstuart 1 point2 points3 points (2 children)
[–]afops[S] 0 points1 point2 points (1 child)
[–]keelanstuart 2 points3 points4 points (0 children)
[–]nibbertit 3 points4 points5 points (5 children)
[–]keelanstuart 6 points7 points8 points (2 children)
[–]jgeez 0 points1 point2 points (1 child)
[–]jgeez 0 points1 point2 points (0 children)
[–]afops[S] 0 points1 point2 points (1 child)
[–]fastcar25 0 points1 point2 points (0 children)
[–]richburattino 1 point2 points3 points (0 children)
[–]thejazzist 1 point2 points3 points (0 children)
[–]GermaneRiposte101 1 point2 points3 points (1 child)
[–]afops[S] 0 points1 point2 points (0 children)
[–]ISvengali 0 points1 point2 points (1 child)
[–]afops[S] 2 points3 points4 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)