Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Průvodce styly shaderů

This style guide lists conventions to write elegant shaders. The goal is to encourage writing clean, readable code and promote consistency across projects, discussions, and tutorials. Hopefully, this will also support the development of auto-formatting tools.

Since the Godot shader language is close to C-style languages and GLSL, this guide is inspired by Godot's own GLSL formatting. You can view an example of a GLSL file in Godot's source code here.

Průvodci stylem nejsou zamýšleny jako striktní pravidla. Občas se může stát, že některé z níže uvedených pokynů nebudete moci použít. V takovém případě se řiďte vlastním úsudkem a požádejte kolegy vývojáře o radu.

Obecně platí, že udržování konzistentního kódu v projektech a v týmu je důležitější než dodržování tohoto návodu do puntíku.

Poznámka

Godot's built-in shader editor uses a lot of these conventions by default. Let it help you.

Here is a complete shader example based on these guidelines:

shader_type canvas_item;
// Screen-space shader to adjust a 2D scene's brightness, contrast
// and saturation. Taken from
// https://github.com/godotengine/godot-demo-projects/blob/master/2d/screen_space_shaders/shaders/BCS.gdshader

uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
uniform float brightness = 0.8;
uniform float contrast = 1.5;
uniform float saturation = 1.8;

void fragment() {
    vec3 c = textureLod(screen_texture, SCREEN_UV, 0.0).rgb;

    c.rgb = mix(vec3(0.0), c.rgb, brightness);
    c.rgb = mix(vec3(0.5), c.rgb, contrast);
    c.rgb = mix(vec3(dot(vec3(1.0), c.rgb) * 0.33333), c.rgb, saturation);

    COLOR.rgb = c;
}

Formátování

Kódování a speciální znaky

  • Pro zalomení řádků používejte znaky pro posuv řádku (LF), nikoli CRLF nebo CR. (výchozí nastavení editoru)

  • Na konci každého souboru použijte jeden znak posuvu řádku. (výchozí nastavení editoru)

  • Použijte kódování UTF-8 bez značky pořadí bajtů <https://en.wikipedia.org/wiki/Byte_order_mark>`_. (výchozí nastavení editoru)

  • Pro odsazení použijte místo mezer Tabulátory. (výchozí nastavení editoru)

Odsazení

Each indent level should be one tab greater than the block containing it.

Dobré:

void fragment() {
    COLOR = vec3(1.0, 1.0, 1.0);
}

Špatné:

void fragment() {
        COLOR = vec3(1.0, 1.0, 1.0);
}

K odlišení pokračovaní řádků od běžných bloků kódu použijte 2 úrovně odsazení.

Dobré:

vec2 st = vec2(
        atan(NORMAL.x, NORMAL.z),
        acos(NORMAL.y));

Špatné:

vec2 st = vec2(
    atan(NORMAL.x, NORMAL.z),
    acos(NORMAL.y));

Line breaks and blank lines

For a general indentation rule, follow the "1TBS Style" which recommends placing the brace associated with a control statement on the same line. Always use braces for statements, even if they only span one line. This makes them easier to refactor and avoids mistakes when adding more lines to an if statement or similar.

Dobré:

void fragment() {
    if (true) {
        // ...
    }
}

Špatné:

void fragment()
{
    if (true)
        // ...
}

Prázdné řádky

Surround function definitions with one (and only one) blank line:

void do_something() {
    // ...
}

void fragment() {
    // ...
}

Use one (and only one) blank line inside functions to separate logical sections.

Délka řádku

Udržujte jednotlivé řádky kódu pod 100 znaků.

If you can, try to keep lines under 80 characters. This helps to read the code on small displays and with two shaders opened side-by-side in an external text editor. For example, when looking at a differential revision.

Jeden příkaz na řádek

Never combine multiple statements on a single line.

Dobré:

void fragment() {
    ALBEDO = vec3(1.0);
    EMISSION = vec3(1.0);
}

Špatné:

void fragment() {
    ALBEDO = vec3(1.0); EMISSION = vec3(1.0);
}

Jedinou výjimkou z tohoto pravidla je ternární operátor:

void fragment() {
     bool should_be_white = true;
     ALBEDO = should_be_white ? vec3(1.0) : vec3(0.0);
 }

Mezery mezi komentáři

Běžné komentáře by měly začínat mezerou, nikoli však kód, který zakomentováváte. To pomáhá odlišit textové komentáře od vypnutého kódu.

Dobré:

// This is a comment.
//return;

Špatné:

//This is a comment.
// return;

Don't use multiline comment syntax if your comment can fit on a single line:

/* This is another comment. */

Poznámka

In the shader editor, to make the selected code a comment (or uncomment it), press Ctrl + K. This feature adds or removes // at the start of the selected lines.

Mezery

Always use one space around operators and after commas. Also, avoid extraneous spaces in function calls.

Dobré:

COLOR.r = 5.0;
COLOR.r = COLOR.g + 0.1;
COLOR.b = some_function(1.0, 2.0);

Špatné:

COLOR.r=5.0;
COLOR.r = COLOR.g+0.1;
COLOR.b = some_function (1.0,2.0);

Nepoužívejte mezery k zarovnání výrazů na výšku:

ALBEDO.r   = 1.0;
EMISSION.r = 1.0;

Floating-point numbers

Always specify at least one digit for both the integer and fractional part. This makes it easier to distinguish floating-point numbers from integers, as well as distinguishing numbers greater than 1 from those lower than 1.

Dobré:

void fragment() {
    ALBEDO.rgb = vec3(5.0, 0.1, 0.2);
}

Špatné:

void fragment() {
    ALBEDO.rgb = vec3(5., .1, .2);
}

Accessing vector members

Use r, g, b, and a when accessing a vector's members if it contains a color. If the vector contains anything else than a color, use x, y, z, and w. This allows those reading your code to better understand what the underlying data represents.

Dobré:

COLOR.rgb = vec3(5.0, 0.1, 0.2);

Špatné:

COLOR.xyz = vec3(5.0, 0.1, 0.2);

Konvence pojmenování

Tyto konvence pojmenování odpovídají stylu Godot Engine. Jejich porušení způsobí, že váš kód bude v rozporu se zabudovanými konvencemi pro pojmenování, což povede k nekonzistentnímu kódu.

Funkce a proměnné

Pro pojmenování funkcí a proměnných použijte snake_case:

void some_function() {
     float some_variable = 0.5;
}

Konstanty

Zapisujte konstanty pomocí CONSTANT_CASE, tj. všemi velkými písmeny s podtržítkem (_) pro oddělení slov:

const float GOLDEN_RATIO = 1.618;

Preprocessor directives

Shader preprocessor directives should be written in CONSTANT__CASE. Directives should be written without any indentation before them, even if nested within a function.

To preserve the natural flow of indentation when shader errors are printed to the console, extra indentation should not be added within #if, #ifdef or #ifndef blocks:

Dobré:

#define HEIGHTMAP_ENABLED

void fragment() {
    vec2 position = vec2(1.0, 2.0);

#ifdef HEIGHTMAP_ENABLED
    sample_heightmap(position);
#endif
}

Špatné:

#define heightmap_enabled

void fragment() {
    vec2 position = vec2(1.0, 2.0);

    #ifdef heightmap_enabled
        sample_heightmap(position);
    #endif
}

Pořadí kódu

We suggest to organize shader code this way:

01. shader type declaration
02. render mode declaration
03. // docstring

04. uniforms
05. constants
06. varyings

07. other functions
08. vertex() function
09. fragment() function
10. light() function

Pořadí jsme optimalizovali tak, aby bylo snadné číst kód shora dolů, aby vývojáři, kteří čtou kód poprvé, pochopili, jak funguje, a aby se předešlo chybám souvisejícím s pořadím deklarace proměnných.

This code order follows two rules of thumb:

  1. Metadata and properties first, followed by methods.

  2. "Public" comes before "private". In a shader language's context, "public" refers to what's easily adjustable by the user (uniforms).

Lokální proměnné

Lokální proměnné deklarujte co nejblíže jejich prvnímu použití. To usnadňuje sledování kódu, aniž byste museli příliš rolovat, abyste našli místo, kde byla proměnná deklarována.