Godot shader language style guide

Dieser Style Guide listet Konventionen zum Schreiben von elegantem GDScript. Das Ziel ist, einen dazu zu ermutigen, sauberen und lesbaren Code zu schreiben und die Konsistenz aller Projekte, Diskussionen und Anleitungen zu fördern. Hoffentlich wird dies auch die Entwicklung von Auto-Formatierungswerkzeugen ankurbeln.

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.

Styleguides sind nicht als harte Regelbücher gedacht. Manchmal können Sie einige der folgenden Richtlinien möglicherweise nicht anwenden. In diesem Fall urteilen Sie selbst was wohl am besten wäre und fragen Sie andere Entwickler nach Erkenntnissen.

Im Allgemeinen ist es wichtiger, Ihren Code in Ihren Projekten und in Ihrem Team konsistent zu halten, als diesem Leitfaden blind zu folgen.

Bemerkung

Der in Godot integrierte Shader-Editor verwendet standardmäßig viele dieser Konventionen. Nutzen Sie ihn.

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

Formatierung

Kodierung und Sonderzeichen

  • Benutze Line Feed (LF) für Zeilenumbrüche, nicht CRLF oder CR. (Standardeinstellung im Editor)
  • Benutze ein Line Feed am Ende jeder Datei. (Standardeinstellung im Editor)
  • Verwenden Sie die UTF-8-Codierung ohne ein byte order mark. (Editor Standard)
  • Benutze Tabs anstelle von Leerzeichen für Einrückungen. (Standardeinstellung im Editor)

Einrückungen

Jede Einrückungsstufe sollte um eins größer sein als die des umgebenden Blocks.

Gut:

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

Schlecht:

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

Rücke 2 Ebenen ein, um fortgesetzte Zeilen von regulären Codeblöcken zu unterscheiden.

Gut:

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

Schlecht:

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

Zeilenumbrüche und Leerzeilen

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.

Gut:

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

Schlecht:

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

Leere Zeilen

Vor und nach einer Funktion bzw. Klassendefinition sollte eine Leerzeile sein (und nur eine):

void do_something() {
    // ...
}

void fragment() {
    // ...
}

Verwenden Sie eine (und nur eine) Leerzeile innerhalb von Funktionen, um logische Abschnitte zu trennen.

Zeilenlänge

Halten Sie einzelne Codezeilen unter 100 Zeichen.

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.

Eine Anweisung pro Zeile

Never combine multiple statements on a single line.

Gut:

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

Schlecht:

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

Die einzige Ausnahme dieser Regel ist der Tenär Operator:

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

Leerzeichen bei Kommentaren

Kommentare sollten mit einem Leerzeichen beginnen, aber kein Code der auskommentiert wird (inaktiv). Dies hilft Kommentare von inaktivem Code zu unterscheiden.

Gut:

// This is a comment.
//return;

Schlecht:

//This is a comment.
// return;

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

/* This is another comment. */

Bemerkung

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.

Leerzeichen

Setze immer ein Leerzeichen um Operatoren und nach Kommas. Vermeide auch zusätzliche Leerzeichen in Funktionsaufrufen.

Gut:

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

Schlecht:

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

Benutze keine Leerzeichen um Ausdrücke vertikal auszurichten (um "Spalten" zu erzeugen.):

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

Fließkommazahlen (reell)

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.

Gut:

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

Schlecht:

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

Zugriff auf Vektorelemente

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.

Gut:

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

Schlecht:

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

Benennungsrichtlinien

Diese Benennungsrichtlinien folgen dem Godot Engine Style. Bei Nichtbeachtung wird dein Code mit den eingebauten Bennennungsrichtlinien kollidieren, was zu inkonsistentem Code führt.

Funktionen und Variablen

Nutze snake_case um Funktionen und Variablen zu benennen:

void some_function() {
     float some_variable = 0.5;
}

Konstanten

Verwende CONSTANT_CASE, alles in Großbuchstaben, mit einem Unterstrich zur Worttrennung: const MAX_SPEED = 200:

const float GOLDEN_RATIO = 1.618;

Code Reihenfolge

Wir empfehlen Shader-Code auf diese Weise aufzubauen:

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

Wir haben die Reihenfolge optimiert, um das Lesen des Codes von oben nach unten zu vereinfachen, Entwicklern das erste Lesen des Codes zu erleichtern und Fehler im Zusammenhang mit der Reihenfolge der Variablendeklarationen zu vermeiden.

Diese Code-Reihenfolge folgt zwei Faustregeln:

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

Lokale Variablen

Deklarieren Sie lokale Variablen so nah wie möglich am Platz ihrer ersten Verwendung. Dies erleichtert das Lesen des Codes, ohne zu viel scrollen zu müssen, um herauszufinden, wo die Variable deklariert wurde.