Godot shader language style guide

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.

Guias de estilo não são regras. Às vezes, você talvez não poderá aplicar algumas das diretrizes abaixo. Quando isso acontecer, use seu melhor julgamento, e peça opiniões de outros desenvolvedores.

Em geral, manter seu código consistente em seus projetos e em seu time é mais importante que seguir este guia à risca.

Nota

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.shader

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;
}

Formatação

Codificação e caracteres especiais

Indentação

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

Bom:

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

Ruim:

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

Use 2 níveis de indentação para distinguir linhas contínuas de blocos de código regulares.

Bom:

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

Ruim:

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.

Bom:

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

Ruim:

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

Linhas em branco

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.

Tamanho de linha

Mantenha linhas individuais de código abaixo de 100 caracteres.

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.

Uma declaração por linha

Never combine multiple statements on a single line.

Bom:

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

Ruim:

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

A única exceção a essa regra é o operador ternário:

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

Espaçamento de comentários

Comentários normais devem começar com um espaço, ao contrário de código que você desativa usando um comentário. Isso ajuda a diferenciar comentários em texto de código desativado.

Bom:

// This is a comment.
//return;

Ruim:

//This is a comment.
// return;

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

/* This is another comment. */

Nota

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.

Espaço em branco

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

Bom:

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

Ruim:

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

Não use espaços para alinhas expressões verticalmente:

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.

Bom:

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

Ruim:

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.

Bom:

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

Ruim:

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

Convenções de nomes

Estas convenções de nomeação seguem o estilo do Godot Engine. Quebrá-las fará com que o seu código fique diferente das convenções de nomeação embutidas, o que deixa o seu código inconsistente.

Funções e variáveis

Use snake_case para nomear funções e variáveis:

void some_function() {
     float some_variable = 0.5;
}

Constantes

Utilize CONSTANT_CASE, com todas as letras maiúsculas e um sublinhado para separas as palavras:

const float GOLDEN_RATIO = 1.618;

Ordem do código

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

Otimizamos essa ordem pra deixar o código mais fácil de ler de cima pra baixo, para ajudar desenvolvedores lendo o código pela primeira vez a entender como ele funciona, e para evitar erros referentes à ordem da declaração de variáveis.

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).

Local variables

Declare local variables as close as possible to their first use. This makes it easier to follow the code, without having to scroll too much to find where the variable was declared.