mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-01-04 14:11:02 +03:00
355
tutorials/shaders/shaders_style_guide.rst
Normal file
355
tutorials/shaders/shaders_style_guide.rst
Normal file
@@ -0,0 +1,355 @@
|
||||
.. _doc_shaders_style_guide:
|
||||
|
||||
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 <https://github.com/godotengine/godot/blob/master/drivers/gles2/shaders/copy.glsl>`__.
|
||||
|
||||
Style guides aren't meant as hard rulebooks. At times, you may not be able to
|
||||
apply some of the guidelines below. When that happens, use your best judgment,
|
||||
and ask fellow developers for insights.
|
||||
|
||||
In general, keeping your code consistent in your projects and within your team is
|
||||
more important than following this guide to a tee.
|
||||
|
||||
.. note:: 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:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
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
|
||||
----------
|
||||
|
||||
Encoding and special characters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Use line feed (**LF**) characters to break lines, not CRLF or CR. *(editor default)*
|
||||
* Use one line feed character at the end of each file. *(editor default)*
|
||||
* Use **UTF-8** encoding without a `byte order mark <https://en.wikipedia.org/wiki/Byte_order_mark>`_. *(editor default)*
|
||||
* Use **Tabs** instead of spaces for indentation. *(editor default)*
|
||||
|
||||
Indentation
|
||||
~~~~~~~~~~~
|
||||
|
||||
Each indent level should be one tab greater than the block containing it.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment() {
|
||||
COLOR = vec3(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment() {
|
||||
COLOR = vec3(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
Use 2 indent levels to distinguish continuation lines from
|
||||
regular code blocks.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
vec2 st = vec2(
|
||||
atan(NORMAL.x, NORMAL.z),
|
||||
acos(NORMAL.y));
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
vec2 st = vec2(
|
||||
atan(NORMAL.x, NORMAL.z),
|
||||
acos(NORMAL.y));
|
||||
|
||||
|
||||
Line breaks and blank lines
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For a general indentation rule, follow
|
||||
`the "1TBS Style" <https://en.wikipedia.org/wiki/Indentation_style#Variant:_1TBS_(OTBS)>`_
|
||||
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.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment() {
|
||||
if (true) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment()
|
||||
{
|
||||
if (true)
|
||||
// ...
|
||||
}
|
||||
|
||||
Blank lines
|
||||
~~~~~~~~~~~
|
||||
|
||||
Surround function definitions with one (and only one) blank line:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void do_something() {
|
||||
// ...
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
// ...
|
||||
}
|
||||
|
||||
Use one (and only one) blank line inside functions to separate logical sections.
|
||||
|
||||
Line length
|
||||
~~~~~~~~~~~
|
||||
|
||||
Keep individual lines of code under 100 characters.
|
||||
|
||||
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.
|
||||
|
||||
One statement per line
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Never combine multiple statements on a single line.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment() {
|
||||
ALBEDO = vec3(1.0);
|
||||
EMISSION = vec3(1.0);
|
||||
}
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment() {
|
||||
ALBEDO = vec3(1.0); EMISSION = vec3(1.0);
|
||||
}
|
||||
|
||||
The only exception to that rule is the ternary operator:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment() {
|
||||
bool should_be_white = true;
|
||||
ALBEDO = should_be_white ? vec3(1.0) : vec3(0.0);
|
||||
}
|
||||
|
||||
Comment spacing
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Regular comments should start with a space, but not code that you comment out.
|
||||
This helps differentiate text comments from disabled code.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
// This is a comment.
|
||||
//return;
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
//This is a comment.
|
||||
// return;
|
||||
|
||||
Don't use multiline comment syntax if your comment can fit on a single line:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
/* This is another comment. */
|
||||
|
||||
.. note::
|
||||
|
||||
In the shader editor, to make the selected code a comment (or uncomment it),
|
||||
press :kbd:`Ctrl + K`. This feature adds or removes ``//`` at the start of
|
||||
the selected lines.
|
||||
|
||||
Whitespace
|
||||
~~~~~~~~~~
|
||||
|
||||
Always use one space around operators and after commas. Also, avoid extraneous spaces
|
||||
in function calls.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
COLOR.r = 5.0;
|
||||
COLOR.r = COLOR.g + 0.1;
|
||||
COLOR.b = some_function(1.0, 2.0);
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
COLOR.r=5.0;
|
||||
COLOR.r = COLOR.g+0.1;
|
||||
COLOR.b = some_function (1.0,2.0);
|
||||
|
||||
Don't use spaces to align expressions vertically:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
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.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void fragment() {
|
||||
ALBEDO.rgb = vec3(5.0, 0.1, 0.2);
|
||||
}
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
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.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
COLOR.rgb = vec3(5.0, 0.1, 0.2);
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
COLOR.xyz = vec3(5.0, 0.1, 0.2);
|
||||
|
||||
Naming conventions
|
||||
------------------
|
||||
|
||||
These naming conventions follow the Godot Engine style. Breaking these will make
|
||||
your code clash with the built-in naming conventions, leading to inconsistent
|
||||
code.
|
||||
|
||||
Functions and variables
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use snake\_case to name functions and variables:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
void some_function() {
|
||||
float some_variable = 0.5;
|
||||
}
|
||||
|
||||
Constants
|
||||
~~~~~~~~~
|
||||
|
||||
Write constants with CONSTANT\_CASE, that is to say in all caps with an
|
||||
underscore (\_) to separate words:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
const float GOLDEN_RATIO = 1.618;
|
||||
|
||||
Code order
|
||||
----------
|
||||
|
||||
We suggest to organize shader code this way:
|
||||
|
||||
.. code-block:: glsl
|
||||
|
||||
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
|
||||
|
||||
We optimized the order to make it easy to read the code from top to bottom, to
|
||||
help developers reading the code for the first time understand how it works, and
|
||||
to avoid errors linked to the order of variable declarations.
|
||||
|
||||
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
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Declare local variables as close as possible to their first use. This makes it
|
||||
easier to follow the code, without having to scroll too much to find where the
|
||||
variable was declared.
|
||||
Reference in New Issue
Block a user