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.

由于Godot的着色器语言与C风格语言和GLSL很接近,所以本指南的灵感来自于Godot自己的GLSL格式。你可以在Godot的源代码中查看一个GLSL文件的例子 这里<https://github.com/godotengine/godot/blob/master/drivers/gles2/shaders/copy.glsl> __。

风格指南并不是硬性的规则手册。有时,您可能无法应用下面的一些准则。当这种情况发生时,使用你最好的判断,并询问其他开发人员的见解。

一般来说,在项目和团队中保持代码的一致性比遵循本指南进行tee更为重要。

注解

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

格式

编码和特殊字符

  • 使用换行符(LF)来换行,而不是 CRLFCR。(编辑默认)

  • 在每个文件的末尾使用一个换行符。(编辑器默认设置)

  • 使用不带 字节顺序标记(BOM)UTF-8 编码。(编辑默认)

  • 使用 Tabs 代替制表符进行缩进(称为“软制表符”)。(编辑默认)

缩进

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

良好的

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

糟糕的

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

使用2个缩进级别来区分续行与常规代码块。

良好的

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

糟糕的

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

换行符和空白行

对于一般的缩进规则,请遵循 “1TBS样式” <https://en.wikipedia.org/wiki/Indentation_style#Variant:_1TBS_(OTBS)>,建议将与控制语句关联的括号放在同一行上。 始终对语句使用大括号,即使它们只占一行。 这使它们更易于重构,并避免在向``if``语句或类似语句中添加更多行时出错。

良好的

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

糟糕的

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

空白行

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.

Line length(可能是字符长度)

把每行代码控制在100个字符以内。

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.

一条语句一行

切勿在一行中合并多个语句。

良好的

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

糟糕的

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

该规则的唯一例外是三元运算符:

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

注释间距

普通注释开头应该留一个空格,但如果是为了停用代码而将其注释掉则不需要留。这样可以用来区分文本注释和停用的代码。

良好的

// This is a comment.
//return;

糟糕的

//This is a comment.
// return;

如果你的注释可以容纳在单行上,就不要使用多行注释语法:

/* This is another comment. */

注解

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.

空格

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

良好的

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

糟糕的

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

不要使用空格垂直对齐表达式:

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

Floating-point numbers

在整数和小数部分请始终指定至少一个数字,这样可以更容易区分浮点和整数,以及区分大于1和小于1的数字。这样可以更容易区分浮点数和整数,以及区分大于1和小于1的数字。

良好的

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

糟糕的

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

Accessing vector members

如果向量包含颜色,在访问向量成员时使用 rgba 。如果向量中不包含颜色,则使用 xyzw 。这可以让那些阅读你的代码的人更好地理解基础数据的含义。

良好的

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

糟糕的

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

命名约定

这些命名约定遵循 Godot 引擎风格。打破这些都会使你的代码与内置的命名约定冲突,导致风格不一致的代码。

函数与变量

使用蛇形命名法(snake_case)来命名函数与变量:

void some_function() {
     float some_variable = 0.5;
}

常量

使用 CONSTANT_CASE,全部大写,用下划线(_)分隔单词 :

const float GOLDEN_RATIO = 1.618;

代码顺序

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

我们优化了顺序,使从上到下阅读代码变得容易,帮助第一次阅读代码的开发人员了解代码的工作原理,并避免与变量声明顺序相关的错误。

This code order follows two rules of thumb:

  1. Metadata and properties first, followed by methods.

  2. "公共 " 优先在 "私有 " 之前。在着色器语言的语境中,"公共 " 指的是易于由用户调整的东西(uniforms)。

局部变量

声明局部变量的位置离首次使用它的位置越近越好。这让人更容易跟上代码的思路,而不需要上下翻找该变量的声明位置。