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.
Checking the stable version of the documentation...
Guia de estilo de shaders
Este guia de estilo lista convenções para escrever de forma elegante os shaders. O objetivo é encorajar a escrita de código limpo e legível e promover a consistência entre projetos, discussões e tutoriais. Esperamos que isto também apoie o desenvolvimento de ferramentas de formatação automática.
Como a linguagem de shader do Godot é próxima de linguagens baseadas no estilo C e GLSL, este guia é inspirado na própria formatação GLSL do Godot. Você pode ver exemplos de arquivos GLSL no código-fonte do Godot aqui.
Guias de estilo não são regras. Às vezes, você talvez não poderá aplicar algumas das diretrizes abaixo. Quando isso acontecer, use seu melhor julgamento, e peça opiniões de outros desenvolvedores.
Em geral, manter seu código consistente em seus projetos e em seu time é mais importante que seguir este guia à risca.
Nota
O editor de shader integrado de Godot usa muitas dessas convenções por padrão. Deixa que te ajude.
Aqui está um exemplo completo de shader baseado nestas diretrizes:
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;
}
Formatação
Codificação e caracteres especiais
Use caracteres line feed (LF) para quebrar linhas, não CRLF ou CR. (padrão do editor)
Use um caractere line feed no final de cada arquivo. (padrão do editor)
Use a codificação UTF-8 sem uma marca de ordem de byte. (padrão do editor)
Use Tabs ao invés de espaços para indentação. (padrão do editor)
Recuo
Cada nível de indentação deve ser uma unidade maior que a do bloco que o contém.
Bom:
void fragment() {
COLOR = vec3(1.0, 1.0, 1.0);
}
Ruim:
void fragment() {
COLOR = vec3(1.0, 1.0, 1.0);
}
Use 2 níveis de indentação para distinguir linhas contínuas de blocos de código regulares.
Bom:
vec2 st = vec2(
atan(NORMAL.x, NORMAL.z),
acos(NORMAL.y));
Ruim:
vec2 st = vec2(
atan(NORMAL.x, NORMAL.z),
acos(NORMAL.y));
Quebras de linha e linhas em branco
Para uma regra geral de indentação, siga o "Estilo 1TBS", que recomenda colocar a chave associada a uma declaração de controle na mesma linha. Sempre use chaves para declarações, mesmo que ocupem apenas uma linha. Isso torna mais fácil refatorar e evita erros ao adicionar mais linhas a uma declaração if ou similar.
Bom:
void fragment() {
if (true) {
// ...
}
}
Ruim:
void fragment()
{
if (true)
// ...
}
Linhas em branco
Envolva as definições de função com uma (e apenas uma) linha em branco:
void do_something() {
// ...
}
void fragment() {
// ...
}
Use uma (e apenas uma) linha em branco dentro das funções para separar seções lógicas.
Tamanho de linha
Mantenha linhas individuais de código abaixo de 100 caracteres.
Se puder, tente manter as linhas com menos de 80 caracteres. Isso ajuda a ler o código em telas pequenas e com dois shaders abertos lado a lado em um editor de texto externo. Por exemplo, ao olhar para uma revisão diferencial.
Uma declaração por linha
Nunca combine múltiplas instruções em uma única linha.
Bom:
void fragment() {
ALBEDO = vec3(1.0);
EMISSION = vec3(1.0);
}
Ruim:
void fragment() {
ALBEDO = vec3(1.0); EMISSION = vec3(1.0);
}
A única exceção a essa regra é o operador ternário:
void fragment() {
bool should_be_white = true;
ALBEDO = should_be_white ? vec3(1.0) : vec3(0.0);
}
Comentários de documentação
Use o seguinte formato para comentários de documentação acima de uniforms, com dois asteriscos iniciais (/**) e asteriscos de acompanhamento em cada linha:
/**
* 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;
Esses comentários aparecerão ao passar o mouse sobre uma propriedade no inspetor. Se você não deseja que o comentário fique visível no inspetor, use a sintaxe de comentário padrão (// ... ou /* ... */ com apenas um asterisco inicial).
Espaço em branco
Use sempre um espaço ao redor dos operadores e depois das vírgulas. Além disso, evite espaços estranhos em chamadas de função.
Bom:
COLOR.r = 5.0;
COLOR.r = COLOR.g + 0.1;
COLOR.b = some_function(1.0, 2.0);
Ruim:
COLOR.r=5.0;
COLOR.r = COLOR.g+0.1;
COLOR.b = some_function (1.0,2.0);
Não use espaços para alinhas expressões verticalmente:
ALBEDO.r = 1.0;
EMISSION.r = 1.0;
Números de ponto flutuante (real)
Sempre especifique pelo menos um dígito para a parte inteira e fracionária. Isso torna mais fácil distinguir números de ponto flutuante de inteiros, bem como distinguir números maiores que 1 daqueles menores que 1.
Bom:
void fragment() {
ALBEDO.rgb = vec3(5.0, 0.1, 0.2);
}
Ruim:
void fragment() {
ALBEDO.rgb = vec3(5., .1, .2);
}
Acessando membros do vetor
Use r, g, b e a ao acessar os membros de um vetor se ele contiver uma cor. Se o vetor contiver qualquer outra coisa que não seja uma cor, use x, y, z e w. Isso permite que quem está lendo seu código entenda melhor o que os dados subjacentes representam.
Bom:
COLOR.rgb = vec3(5.0, 0.1, 0.2);
Ruim:
COLOR.xyz = vec3(5.0, 0.1, 0.2);
Convenções de nomes
Estas convenções de nomeação seguem o estilo do Godot Engine. Quebrá-las fará com que o seu código fique diferente das convenções de nomeação embutidas, o que deixa o seu código inconsistente.
Funções e variáveis
Use snake_case para nomear funções e variáveis:
void some_function() {
float some_variable = 0.5;
}
Constantes
Utilize CONSTANT_CASE, com todas as letras maiúsculas e um sublinhado para separas as palavras:
const float GOLDEN_RATIO = 1.618;
Diretivas de pré-processador
Pré-processador de shader directives should be written in CONSTANT_CASE. Directives should be written without any indentation before them, even if nested within a function.
Para preservar o fluxo natural de recuo quando os erros do shader são impressos no console, recuos extras não devem ser adicionados dentro de blocos #if, #ifdef ou #ifndef:
Bom:
#define HEIGHTMAP_ENABLED
void fragment() {
vec2 position = vec2(1.0, 2.0);
#ifdef HEIGHTMAP_ENABLED
sample_heightmap(position);
#endif
}
Ruim:
#define heightmap_enabled
void fragment() {
vec2 position = vec2(1.0, 2.0);
#ifdef heightmap_enabled
sample_heightmap(position);
#endif
}
Aplicando a formatação automaticamente
Para formatar arquivos de shader automaticamente, você pode usar o clang-format em um ou vários arquivos .gdshader, já que a sintaxe é próxima o suficiente de uma linguagem de estilo C.
No entanto, o estilo padrão no clang-format não segue este guia de estilo, então você precisa salvar este arquivo como .clang-format na pasta raiz do seu projeto:
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
Enquanto estiver na raiz do projeto, você pode chamar clang-format -i caminho/para/shader.gdshader em um terminal para formatar um único arquivo de shader, ou clang-format -i caminho/para/pasta/*.gdshader para formatar todos os shaders em uma pasta.
Ordem do código
Sugerimos organizar o código do shader desta forma:
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
Otimizamos essa ordem pra deixar o código mais fácil de ler de cima pra baixo, para ajudar desenvolvedores lendo o código pela primeira vez a entender como ele funciona, e para evitar erros referentes à ordem da declaração de variáveis.
Essa ordem de código segue duas regras gerais:
Metadados e propriedades primeiro, seguidos por métodos.
"Public" vem antes de "private". No contexto de uma linguagem de shader, "public" se refere ao que é facilmente ajustável pelo usuário (uniforms).
Variáveis locais
Declare variáveis locais o mais pŕoximo possível de seu primeiro uso. Isto torna mais fácil seguir o código, sem ter que rolar muito para encontrar onde a variável foi declarada.
Espaçamento de comentários
Comentários normais devem começar com um espaço, ao contrário de código que você desativa usando um comentário. Isso ajuda a diferenciar comentários em texto de código desativado.
Bom:
Ruim:
Não use a sintaxe de comentário multilinha se o seu comentário couber em uma única linha:
/* This is another comment. */Nota
No editor de shader, para fazer o código selecionado um comentário (ou descomentar), pressione Ctrl + K. Este recurso adiciona ou remove
//no início das linhas selecionadas.