Godots Shader-Sprache Stil-Richtlinien

Diese Stil-Richtlinien listen Konventionen zum Schreiben von elegantem GDScript auf. Das Ziel ist Sie 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.

Da die Godot-Shader-Sprache den Sprachen im C-Stil und GLSL nahe kommt, ist dieses Handbuch von Godots eigener GLSL-Formatierung inspiriert. Sie können sich ein Beispiel einer GLSL-Datei im Quellcode von Godot hier ansehen.

Stil-Richtlinien 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.

Hier ist ein vollständiges Shader-Beispiel, das auf diesen Richtlinien basiert:

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

  • Benutzen Sie Line Feed (LF) für Zeilenumbrüche, nicht CRLF oder CR. (Standardeinstellung im Editor)
  • Benutzen Sie ein Line Feed am Ende jeder Datei. (Standardeinstellung im Editor)
  • Verwenden Sie die UTF-8-Codierung ohne ein byte order mark. (Editor Standard)
  • Benutzen Sie 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.

Falls möglich versuchen Sie Zeilen unter 80 Zeichen zu halten. Dies hilft beim Lesen des Codes auf kleinen Displays und mit zwei nebeneinander geöffneten Shadern in einem externen Texteditor. Zum Beispiel bei der Betrachtung einer Unterschieds-Revision.

Eine Anweisung pro Zeile

Kombinieren Sie niemals mehrere Anweisungen in einer einzigen Zeile.

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;

Verwenden Sie keine mehrzeilige Kommentarsyntax, wenn Ihr Kommentar in eine einzelne Zeile passt:

/* This is another comment. */

Bemerkung

Drücken Sie im Shader-Editor Strg + K um den ausgewählten Code zu einem Kommentar zu machen (oder den Kommentar zu entfernen). Diese Funktion fügt am Anfang der ausgewählten Zeilen // hinzu oder entfernt sie.

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

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

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

Fließkommazahlen (reell)

Geben Sie immer mindestens eine Ziffer für den Vorkommateil und den Nachkommateil an. Dies erleichtert die Unterscheidung von Gleitkommazahlen von ganzen Zahlen sowie die Unterscheidung von Zahlen größer als 1 von Zahlen kleiner als 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 Ihr 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. Zuerst Metadaten und Eigenschaften, gefolgt von Methoden.
  2. "Public" steht vor "private". Im Kontext einer Shader-Sprache bezieht sich "public" auf das, was vom Benutzer leicht angepasst werden kann (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.