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

스타일 가이드는 빡빡한 법전이 아닙니다. 아직은 아래의 가이드라인을 적용하지 못할 수도 있습니다. 그런 일이 발생하면 최선의 판단을 내리고 동료 개발자에게 통찰력을 요청하세요.

일반적으로 프로젝트와 팀 내에서 코드를 일관되게 유지하는 것이 이 가이드를 따라가는 것보다 더 중요합니다.

참고

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

서식(Formatting)

인코딩과 특수 문자

  • 줄 바꿈을 위해 라인 피드 (LF) 문자를 사용합니다. CRLF나 CR은 사용하지 않습니다 (편집기 기본 설정)

  • 각 파일의 끝에 하나의 라인 피드 문자를 사용합니다. (편집기 기본 설정)

  • 바이트 순서 표식 없이 UTF-8 인코딩을 사용합니다. (편집기 기본 설정)

  • 들여쓰기로 스페이스바 대신 Tab(탭) 키를 사용합니다. (편집기 기본 설정)

들여쓰기(Indentation)

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

줄 바꿈 및 공백 줄

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.

좋음:

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

나쁨:

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

공백 줄(Blank lines)

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.

줄 길이

코드 한 줄은 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.

한 줄에 하나의 명령문

Never combine multiple statements on a single line.

좋음:

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

나쁨:

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

유일한 예외라면 삼항(Ternary) 연산자일 것입니다:

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

주석(Comment) 간격

일반 주석은 공백으로 시작해야 하지만 주석을 달은 코드는 공백으로 시작하지 않아야 합니다. 이렇게 하면 텍스트 주석을 비활성화된 코드와 구분하는 데 도움이 됩니다.

좋음:

// This is a comment.
//return;

나쁨:

//This is a comment.
// return;

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

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

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.

좋음:

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

나쁨:

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.

좋음:

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. "Public" comes before "private". In a shader language's context, "public" refers to what's easily adjustable by the user (uniforms).

지역 변수(Local Variables)

지역 변수를 처음 사용할 때와 최대한 가깝게 선언하세요. 이렇게 하면 변수가 선언된 위치를 찾기 위해 너무 많이 스크롤하지 않고도 코드를 더 쉽게 따라갈 수 있습니다.