I know custom renderers are quite way off, but figured it wouldn’t hurt to start this discussion thread to get some theory about what I intend to do with them.
My idea is to create a renderer that limits overdraw to necessary minimum. I mean, when dealing with objects that use transparent materials, overdraw is kinda necessary, but why would I need to draw entirety of Mexico, if camera is blocked by a huge, non-transparent, wall (paid by Mexicans) so player wouldn’t see any of that anyway?
This kind of renderer would make things faster to render since even with frustum culling, overdraw happens.
How would I go about this? I’ve thought about dividing the viewport into small 100 pixels (or smaller if resolution isn’t dividable by 100) sections then see what objects are in each section and if they are blocked by a non-transparent object that is big enough to make objects behind in not visible (i.e. no need to render them), then render the section (including any transparent objects in front of the proverbial wall) and after all sections are rendered combine them and put to the screen. But how would I go about such detection?
sections then see what objects are in each section and if they are blocked by a non-transparent
Doing that will introduce performance penalty that most likely will greatly outweigh any performance gain.
GPU already has optimizations to reduce cost of drawing objects that are hidden behind something else or are outside of camera’s field of view.
Generally you just want opaque shaders, these won’t overdraw in most cases, bit you still pay a vert processing hit and a draw call hit so you’ll want to cull regardless. Your post seems keen on reinventing the wheel
But if you wanted to knock yourself out, you’re basically referring to a technique called “tiled”, which can refer to shader technique or compute shader job. Basically you deal with blocks of pixels at a time. Some mobiles GPUs do this in hardware, and some renderers use a technique called “tile deferred”.
@Eric5h5 True, but occlusion culling doesn’t work in dynamic context where changes can happen to the world by either player or due to happenings in the game. At least not the way it was implemented in Unity.
//edit: Also thanks for killing this thread. Nobody reads this section.
Also, this is already what modern video cards do. If something is opaque (or more specifically writes to the zbuffer) subsequent objects are tested to see if they’re behind something that’s already been drawn, and if they are they never run the fragment shader for that pixel.
You rang? In itself there is nothing wrong with a bit of overdraw, although yes with forward rendering you can do a depth pre-pass to reject “invisible” pixels although some seem to miss that there is a performance offset for the pre-pass that can add additional overhead dependant on the vertex count. So as with EVERYTHING in games, it depends…!
Deferred rendering was slated to resolve this issue, as materials are firstly added to the G-buffer and lit in a seperate path therefore again not lighting the additional invisible pixels.
Although if you’re bandwidth limited, you may find that deferred rendering can end up just as expensive. In what I’m working on “that I can’t mention” I’m going down the FR+ path and instead of explaining it, I’ll just copy and paste this:
“The idea behind forward+ instead of putting material properties into a G-Buffer and applying lighting to those properties, you figure a list of lights that affect a pixel (or group of pixels). Then you do a normal forward rendering pass, where each pixel being shaded loops over the list of lights, and computes the final reflectance. The most common way to do this is to use a compute shader that computes lists of lights per screen-space tile, where each tile is something like 16x16 pixels in size. With forward+ you typically also have a depth prepass before computing your tile lighting lists. Having depth information lets you do a better job of culling lights, and it also ensures that you don’t have overdraw during your main forward pass.”
Transparent objects are generally drawn back to front, but opaque objects are first drawn front to back to enable early z rejection of other opaque and transparent shaders.
Front to back opaque rendering isn’t perfect though as it’s sorted by mesh and not by triangle (or by pixel) so sometimes there’s some overdraw even with early z rejection which is where there deferred or pre pass deferred @ mentioned comes into play. They don’t get rid of over draw either (both deferred methods actually have more over draw than forward), but rather try to make over draw as cheap as possible by deferring the more expensive operations to when overdraw can be avoided.
That article also talks about early stencil rejection which RedLynx has used as part of a front to back premultiplied particle rendering system in the Trials console games. That means they can do early rejection of transparencies from both z depth and nearly opaque transparent areas.
They released a paper on it years ago that I can’t track down but it’s talked about briefly on this page:
The way Unity’s forward render works is friendly for older hardware but means each additional per pixel light requires an additional layer of over draw. Valve’s recently “vr renderer” plugin takes advantage of modern GPUs’ better handling of if statements and loops, as do the various forward+ techniques (there are many implementations of it) to reduce overdraw as much as possible.