Godot shader language style guide

Esta guía enumera las convenciones para escribir shaders elegantes. La meta es motivar la escritura de un código limpio y legible, y promover la consistencia entre proyectos, discusiones y tutoriales. Esto también puede ayudar al desarrollo de herramientas de autoformateo.

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.

Las guías de estilos no están hechas con la intención de ser tratadas como reglamento estricto. Algunas veces no serás capaz de utilizar algunos de los lineamientos indicados, cuando eso suceda utiliza tu mejor criterio y busca la opinión de otros desarrolladores.

En general, mantener tu código consistente en tus proyectos y entre todos los de tu equipo es más importante que seguir esta guía al pié de la letra.

Nota

El editor integrado de shaders de Godot usa muchas de estas convenciones por defecto. Deja que te ayude.

Aquí hay un ejemplo completo de shader basado en estas guías de estilo:

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

Formateando

Codificación y caracteres especiales

  • Utiliza caracteres de salto de línea (LF) para separar líneas, no CRLF o CR. (por defecto del editor)
  • Utiliza un carácter de salto de línea al final de cada archivo. (por defecto del editor)
  • Usa la codificación UTF-8 sin Marca de orden de bytes. *( por defecto del editor) *
  • Usa Tabs en lugar de espacios para la indentación. *(por defecto del editor) *

Indentación

Cada nivel de indentación deberá ser una tabulación mayor que el bloque que la contiene.

Bien:

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

Mal:

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

Use 2 niveles de Indentación para distinguir las lineas de continuación de bloques regulares de código.

Bien:

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

Mal:

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

Saltos de línea y líneas en blanco

Para una regla general de identación, sigue el estilo "1TBS" que recomienda poner el corchete asociado con una estructura de control en la misma línea. Siempre usa llaves para las sentencias, aunque sean de una sola línea. Esto hace más fácil el refactor y evita errores cuando se agrega más de una línea a una sentencia if o similar.

Bien:

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

Mal:

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

Lineas en blanco

Envuelva sus funciones y definiciones de clases por una linea vacía :

void do_something() {
    // ...
}

void fragment() {
    // ...
}

Utiliza una (y sólo una) linea vacía dentro de las funciones para separar secciones lógicas.

Longitud de línea

Mantiene líneas de código individuales por debajo de los 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.

Una declaración/instrucción por linea

Never combine multiple statements on a single line.

Bien:

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

Mal:

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

La única excepción a esta regla es el operador ternario:

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

Espaciado de comentarios

Comentarios normales deberían comenzar con un espacio, pero no el código comentado. Esto ayuda a diferenciar texto comentado de código deshabilitado.

Bien:

// This is a comment.
//return;

Mal:

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

Espacio en blanco

Utiliza siempre un espacio entre los operadores y después de las comas. Evita los espacios adicionales en las llamadas a funciones.

Bien:

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

Mal:

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

No uses espacios para alinear la verticalidad de las expresiones:

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

Números de coma flotante

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.

Bien:

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

Mal:

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

Accediendo a miembros de vectores

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.

Bien:

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

Mal:

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

Convenciones para la definición de nombres

Estas convenciones de nombres siguen el estilo de Godot Engine. Romperlas hará que tu código choque con las convenciones de nomenclaturas incorporadas, lo que crea un código inconsistente.

Funciones y Variables

Usa snake_case para nombrar funciones y variables:

void some_function() {
     float some_variable = 0.5;
}

Constantes

Escribe constantes en CONSTANT_CASE, todas en mayusculas con el símbolo de subrayado (_) para separar palabras:

const float GOLDEN_RATIO = 1.618;

Orden de 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

Optimizamos el orden para hacer más fácil leer el código desde arriba hacia abajo, para ayudar a que los desarrolladores que leen el código por primera vez entiendan cómo funciona y para evitar errores vinculados al orden de declaración de variables.

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

Variables locales

Declara las variables locales tan cerca como puedas de su primer uso. Esto hace que sea más fácil de seguir el código sin tener que desplazar el código demasiado para encontrar dónde fue declarada la variable.