How to adjust the graphics quality

In our 3D game, I want to add the option to change the quality of the graphics. As an example, let this setting only affect the shadows:

  • HIGH: shadows with blur.
  • MEDIUM: shadows without blur.
  • LOW: no shadows.

As a coder, the easiest hypothetical way is to define #define NO_SHADOWS (for “LOW”) somewhere at the very start of the game. And this definition would affect the code of all fragment shaders of 3D models.

But in Defold engine I think this is not possible and I need to make 3 sets of all game materials with 3 different shaders. From Lua code, I will need to track the names of all the model components and their game object IDs to be able to switch their materials. I see this as a huge piece of code and quite a lot of manual work.

Maybe I’m missing some easy way to do this? What’s the best way to implement this?

5 Likes

You can use render constants to branch inside the shaders.

3 Likes

I am sure you implement this feature of game quality in gui element then once option selected send message to render to use the function that have the implementation of the equivalent render quality.
I would be nice if you speak here about your experience in using defold in 3d game , me i had created transpiler python to lua to use it in scripting it remains the 3d stuffs and i struggled to make something works as i want

Use render predicate constants in the render script?

This is exactly how I switch the “quality” now, i.e. in the fragment shaders:

uniform lowp vec4 quality;

void main()
{
    if (quality.x == 0.0) {
        // LOW
    } else if (quality.x <= 0.5) {
        // MEDIUM
    } else {
        // HIGH
    }
}

That kind of branching (on a uniform value) works well even on low-end mobile GPUs like Mali-T830 and PowerVR GE8100. I measured the rendering performance in milliseconds per frame and the GPUs handled branching very efficiently, to within a tenth of a millisecond. But, these branches can still end up making the shader programs larger since the instructions for all branches need to be included, and the compiler will still need to allocate enough registers to handle all branches. Right? These can potentially cause the performance to suffer a lot.

Plus, I do not have the extra man hours to test the game on all the current GPU models and we can only hope that branching works just as well everywhere :grinning:

So, in simple terms, the rendering works like this now:

for-loop-over-pixels
    if low then
        --
    elseif medium then
        --
    elseif high then
        --
    end
end

I want it to be like this:

if low then
    for-loop-over-pixels
elseif medium then
    for-loop-over-pixels
elseif high then
    for-loop-over-pixels
end

For example, my question can be easily solved by adding user-defined preprocessor macros to the Defold materials to use conditional checks to keep the needed pieces of GLSL code.

But, since Defold does not yet have this option, I am looking for other effective ways.

try to use render.enable_material(my_pretty_low_quality_material") before render.draw()

I’ve added a sample: https://github.com/Dragosha/defold-light-and-shadows/blob/main/rendercam/rendercam.render_script

html5 demo:
https://dragosha.com/defold/Light_and_Shadows/

6 Likes

I think @jhonny.goransson has been thinking about similar issues.

Also, now that we have shader includes it is possible to share code between materials for different qualities. But I’m not sure if multiple materials (one per quality) is the best approach… :thinking:

2 Likes