Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

C# 스타일 가이드

이 스타일 가이드는 우아한 셰이더를 작성하기 위한 규칙을 나열합니다. 목표는 깨끗하고 읽기 쉬운 코드 작성을 장려하고 프로젝트, 토론 및 튜토리얼 전반에 걸쳐 일관성을 촉진하는 것입니다. 바라건대 이 가이드는 자동 서식 툴의 개발도 지원할 것입니다.

Godot 셰이더 언어는 C 스타일 언어 및 GLSL에 가깝기 때문에 이 가이드는 Godot의 자체 GLSL 형식에서 영감을 받았습니다. Godot의 소스 코드 `여기 <https://github.com/godotengine/godot/blob/master/drivers/gles3/shaders/>`__에서 GLSL 파일의 예를 볼 수 있습니다.

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

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

참고

Godot의 내장 스크립트 편집기는 기본적으로 많은 규정을 사용합니다. 그것이 당신을 돕도록 하세요.

이 가이드라인을 기반으로 한 전체 클래스 예제입니다:

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

uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
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) 문자를 사용합니다. CRLF나 CR은 사용하지 않습니다 (편집기 기본 설정)

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

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

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

들여쓰기

들여쓰기 너비는 블록 바깥보다 한 칸 더 커야 됩니다.

좋음:

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

줄 바꿈 및 공백 줄

일반적인 들여쓰기 규칙으로, The 'Allman Style'에 따라 제어문과 관련된 중괄호를 다음 줄에 놓으면서, 같은 높이의 들여쓰기를 하기를 권장합니다:

좋음:

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

나쁨:

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

공백 줄(Blank lines)

함수와 클래스 정의를 두 개의 공백 줄로 묶습니다:

void do_something() {
    // ...
}

void fragment() {
    // ...
}

논리 섹션을 분리하기 위해 함수 안에 하나의 공백 줄을 사용합니다.

줄 길이

코드 한 줄은 100 문자 이내로 유지합니다.

가능하다면 80 문자 이내로 유지해보세요. 이렇게 하면 작은 화면에서도 코드를 읽기 쉽고, 외부 텍스트 편집기에서 양쪽에 두 스크립트가 열려있는 화면에서도 읽기 쉽습니다. 예를 들어 서로 다른 코드 개정판을 볼 때가 있죠.

한 줄에 하나의 명령문

한 줄에 여러 명령문을 결합하지 마십시오.

좋음:

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

주석 간격

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

좋음:

// This is a comment.
//return;

나쁨:

//This is a comment.
// return;

주석이 한 줄에 들어갈 수 있는 경우 여러 줄 주석 구문을 사용하지 마세요.

/* This is another comment. */

참고

스크립트 편집기에서 선택한 코드를 주석으로 바꾸려면 <kbd>Ctrl</kbd> <kbd>K</kbd>를 누르세요. 누르면 선택한 줄의 처음 부분에 # 기호가 생깁니다.

문서의 구조

유니폼 위의 문서 설명에는 두 개의 별표(/**)와 모든 줄에 후속 별표가 있는 다음 형식을 사용합니다.

/**
 * This is a documentation comment.
 * These lines will appear in the inspector when hovering the shader parameter
 * named "Something".
 * You can use [b]BBCode[/b] [i]formatting[/i] in the comment.
 */
uniform int something = 1;

이러한 설명은 검사기에서 속성을 가리키면 나타납니다. 검사기에 주석이 표시되지 않도록 하려면 대신 표준 주석 구문(// ... 또는 앞에 별표가 하나만 있는 /* ... */)을 사용하십시오.

공백

연산자와 쉼표 뒤에는 한 칸을 띄어주세요. 그리고 딕셔너리 참조와 함수 호출에는 띄어쓰기를 피하세요.

좋음:

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;

부동 소수점 숫자 (실수)

정수 부분과 소수 부분 모두에 대해 항상 하나 이상의 숫자를 지정하십시오. 이렇게 하면 부동 소수점 숫자와 정수를 쉽게 구별할 수 있을 뿐만 아니라 1보다 큰 숫자와 1보다 작은 숫자를 구별하는 것이 더 쉬워집니다.

좋음:

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

나쁨:

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

벡터의 합

벡터에 색상이 포함된 경우 벡터의 멤버에 액세스할 때 r, g, ba``를 사용하세요. 벡터에 색상 이외의 내용이 포함된 경우 ``x, y, z``w``를 사용하세요. 이를 통해 코드를 읽는 사람들은 기본 데이터가 나타내는 내용을 더 잘 이해할 수 있습니다.

좋음:

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;

전처리기 지시문

x.attribute 지시문은 CONSTANT__CASE로 작성해야 합니다. 지시문은 함수 내에 중첩되어 있더라도 앞에 들여쓰기 없이 작성해야 합니다.

셰이더 오류가 콘솔에 인쇄될 때 들여쓰기의 자연스러운 흐름을 유지하려면 #if, #ifdef 또는 #ifndef 블록 내에 들여쓰기를 추가해서는 안 됩니다:

좋음:

#define HEIGHTMAP_ENABLED

void fragment() {
    vec2 position = vec2(1.0, 2.0);

#ifdef HEIGHTMAP_ENABLED
    sample_heightmap(position);
#endif
}

나쁨:

#define heightmap_enabled

void fragment() {
    vec2 position = vec2(1.0, 2.0);

    #ifdef heightmap_enabled
        sample_heightmap(position);
    #endif
}

자동으로 서식 적용

셰이더 파일 형식을 자동으로 지정하려면 구문이 C 스타일 언어에 충분히 가깝기 때문에 하나 이상의 .gdshader 파일에 `clang-format <https://clang.llvm.org/docs/ClangFormat.html>`__을 사용할 수 있습니다.

그러나 clang-format의 기본 스타일은 이 스타일 가이드를 따르지 않으므로 이 파일을 프로젝트 루트 폴더에 ``.clang-format``로 저장해야 합니다.

BasedOnStyle: LLVM
AlignAfterOpenBracket: DontAlign
AlignOperands: DontAlign
AlignTrailingComments:
  Kind: Never
  OverEmptyLines: 0
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortFunctionsOnASingleLine: Inline
BreakConstructorInitializers: AfterColon
ColumnLimit: 0
ContinuationIndentWidth: 8
IndentCaseLabels: true
IndentWidth: 4
InsertBraces: true
KeepEmptyLinesAtTheStartOfBlocks: false
RemoveSemicolon: true
SpacesInLineCommentPrefix:
  Minimum: 0 # We want a minimum of 1 for comments, but allow 0 for disabled code.
  Maximum: -1
TabWidth: 4
UseTab: Always

프로젝트 루트에 있는 동안 터미널에서 ``clang-format -i path/to/shader.gdshader``를 호출하여 단일 셰이더 파일을 형식화하거나 ``clang-format -i path/to/folder/*.gdshader``를 호출하여 폴더의 모든 셰이더 형식을 지정할 수 있습니다.

코드 순서

제안하는 GDScript 코드 구조는 다음과 같습니다:

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

코드를 위에서 아래로 쉽게 읽을 수 있도록 순서를 최적화했으며, 코드를 처음 읽는 개발자가 어떻게 작동하는지 이해하고 변수 선언 순서와 관련된 오류를 방지할 수 있습니다.

이 코드 순서는 네 가지 규칙을 따릅니다:

  1. 속성과 시그널이 첫 번째로 옵니다. 그 뒤는 메서드가 나옵니다.

  2. "공개"가 "비공개" 앞에 옵니다. 셰이더 언어의 맥락에서 "공개"는 사용자가 쉽게 조정할 수 있는 것(유니폼)을 의미합니다.

지역 변수(Local Variables)

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