Skip to content

Commit 9441581

Browse files
committed
[WIP] Documentation for DrawableTextures
godotengine/godot#105701
1 parent e958d86 commit 9441581

File tree

4 files changed

+276
-0
lines changed

4 files changed

+276
-0
lines changed
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
.. _doc_drawable_textures:
2+
3+
DrawableTextures
4+
====================
5+
6+
DrawableTextures are a type of Texture2D with additional functions for modifying the texture via the GPU.
7+
8+
Basic Blit_Rect
9+
---------------
10+
11+
The most basic operation on a drawable texture is blit_rect() -
12+
Blitting (copying) the whole of one texture into the given rectangle on the ``DrawableTexture``.
13+
14+
.. code-block:: gdscript
15+
16+
texture.blit_rect(Rect2(20, 50, 60, 60), load("res://circle.svg"))
17+
texture.blit_rect(Rect2(20, 50, 60, 60), load("res://circle.svg"), Color.WHITE, 0)
18+
19+
The code above blits the circle texture into the rectangle (20, 50, 60, 60) on the ``DrawableTexture``.
20+
(20,50) is the top left corner of the rectangle being drawn to, and (60, 60) is its size.
21+
If you wanted to draw over the whole texture, simply match the Rect parameter to the ``DrawableTexture``'s size.
22+
23+
The next parameter in blit_rect() is an optional parameter, Modulate.
24+
This is a color that the output is multiplied by (in the default behavior).
25+
This can be used to recolor, or even mask the drawn output of blit_rect().
26+
Using a modulate of Color(0, 0, 1, 0) for example, will only draw to and update the Blue values of each pixel on the DrawableTexture.
27+
28+
blit_rect()'s 4th parameter, Mipmap, can specify a mipmap level to draw to.
29+
You only need to use this if you want very fine control over each mipmap layer.
30+
Keep in mind, you do not need to adjust the rectangle size - it is converted to a portion of the textures whole size.
31+
If you just want to update all the mipmap layers, you should draw to the texture, and then call generate_mipmaps() on it
32+
33+
Blend Modes & TextureBlit Shaders
34+
---------------------------------
35+
36+
The drawing process for blit_rect() and DrawableTextures is governed by a TextureBlit GDShader.
37+
Even when the user does not supply one, the engine has a default TextureBlit shader it uses.
38+
39+
.. code-block:: glsl
40+
41+
// Default Texture Blit shader.
42+
43+
shader_type texture_blit;
44+
render_mode blend_mix;
45+
46+
uniform sampler2D source_texture0 : hint_blit_source0;
47+
uniform sampler2D source_texture1 : hint_blit_source1;
48+
uniform sampler2D source_texture2 : hint_blit_source2;
49+
uniform sampler2D source_texture3 : hint_blit_source3;
50+
51+
void blit() {
52+
// Copies from each whole source texture to a rect on each output texture.
53+
COLOR0 = texture(source_texture0, UV) * MODULATE;
54+
COLOR1 = texture(source_texture1, UV) * MODULATE;
55+
COLOR2 = texture(source_texture2, UV) * MODULATE;
56+
COLOR3 = texture(source_texture3, UV) * MODULATE;
57+
}
58+
59+
The Blend_mode defines the how the output color value
60+
is blended with the current color of the pixel on the ``DrawableTexture``.
61+
While the engine defaults to Blend_Mix, these shaders also support
62+
blend_disabled, blend_sub, blend_add, and blend_mul.
63+
64+
If you just want to use a different blend_mode than the default,
65+
you can instantiate and pass in a new ``BlitMaterial`` in the GDScript code.
66+
67+
.. code-block:: gdscript
68+
69+
var myMat = BlitMaterial.new()
70+
myMat.blend_mode = BlitMaterial.BLEND_MODE_DISABLED
71+
texture.blit_rect(Rect2(0, 0, 200, 200), load("res://icon.svg"), Color.WHITE, 0, myMat)
72+
73+
If you want more complicated behavior, then you can write your own TextureBlit Shader!
74+
Create a new TextureBlit GDShader, write your Shader code, and load it into a material
75+
to pass to the function. The Material is passed as a function parameter rather than bound
76+
to the resource to make it easier to perform multiple different types of Draws to the same texture.
77+
78+
Blit_Rect Multi
79+
---------------
80+
81+
DrawableTextures also have a Blit_Rect multi function,
82+
to allow for up to 4 inputs and outputs in the same step.
83+
84+
.. code-block:: gdscript
85+
86+
texture.blit_rect_multi(Rect2(0, 0, 200, 200), [load("res://icon.svg"), load("res://circle.svg")], [otherDrawTex])
87+
88+
The default behavior of this is to just match each input and output in order
89+
which can be useful for, say, drawing to an Albedo, Normal, and Depth texture simultaneously.
90+
91+
Of course, this behavior too can be customized via the TextureBlit shader.
92+
In the GDShader, the extra outputs are written to via COLOR1, COLOR2, and COLOR3
93+
And the extra inputs can be read as uniforms with hint_blit_source1, hint_blit_source2, and hint_blit_source3
94+
95+
.. _doc_drawable_textures_example_1:
96+
97+
Example 1: Simple Painting
98+
--------------------------
99+
One of the most intuitive uses for DrawableTextures is for, well, drawing!
100+
Its easier than ever to set up a canvas the user can paint.
101+
For this example, were going to start a new project, and create
102+
a new UI Scene with a Control Node at its root.
103+
Next, you'll want to create a TextureRect Node which is going to be our user's canvas.
104+
Size it appropriately for your screen, and then attach a new GDScript to it.
105+
The start of this script should initialize the TextureRect's texture to a new DrawableTexture.
106+
107+
.. code-block:: gdscript
108+
109+
extends TextureRect
110+
111+
func _ready():
112+
texture = DrawableTexture2D.new()
113+
# Be Careful - if the dimensions of the Node != the setup size here
114+
# our draw call later will seem to happen at the wrong spot
115+
texture.setup(500, 500, DrawableTexture2D.DRAWABLE_FORMAT_RGBA8, false)
116+
117+
Next, we just need the TextureRect to respond to the player clicking and dragging as if they are painting!
118+
To do this, we can connect the _on_gui_input() Signal from the TextureRect to our script,
119+
and parse InputMouseButton and InputMouseMotion events
120+
121+
.. code-block:: gdscript
122+
123+
var drawing: bool = false
124+
125+
func _on_gui_input(event: InputEvent) -> void:
126+
if event is InputEventMouseButton:
127+
# Mouse click/unclick - start/stop drawing
128+
drawing = !drawing
129+
if event is InputEventMouseMotion and drawing:
130+
# Calculate rect to center our drawn rectangle on mouse position
131+
# instead of mouse at top left
132+
var p = event.position
133+
var rect: Rect2 = Rect2(p.x - 10, p.y - 10, 20, 20)
134+
texture.blit_rect(rect, null)
135+
136+
This should now draw black squares as you click and drag around the TextureRect.
137+
For more natural drawing, we probably want to be drawing a circle shape, and actually coloring it!
138+
We can adjust whats being drawn by using a Texture to copy from, and the modulate parameter.
139+
I downloaded a plain white circle texture, which I load as the Texture parameter in Blit_Rect,
140+
and use Red as my Modulate parameter.
141+
142+
.. code-block:: gdscript
143+
144+
if event is InputEventMouseMotion and drawing:
145+
# Calculate rect to center our drawn rectangle on mouse position
146+
# instead of mouse at top left
147+
var p = event.position
148+
var rect: Rect2 = Rect2(p.x - 10, p.y - 10, 20, 20)
149+
texture.blit_rect(rect, load("res://circle.svg"), Color.RED)
150+
151+
Now the drawing looks much more natural and colorful!
152+
To further customize this, you could connect a ColorPickerButton Node to the script
153+
to store a users Color choice for the Modulate Parameter of Blit_Rect.
154+
You could also store a Brush Size variable, give the user a way to adjust it,
155+
and incorporate it into the Rectangle calculation so the user can draw bigger or smaller strokes.
156+
157+
.. code-block:: gdscript
158+
159+
var drawing: bool = false
160+
var myColor: Color = Color.RED
161+
var mySize: float = 20.0
162+
163+
func _on_gui_input(event: InputEvent) -> void:
164+
if event is InputEventMouseButton:
165+
# Mouse click/unclick - start/stop drawing
166+
drawing = !drawing
167+
if event is InputEventMouseMotion and drawing:
168+
# Calculate rect to center our drawn rectangle on mouse position
169+
# instead of mouse at top left
170+
var p = event.position
171+
var rect: Rect2 = Rect2(p.x - mySize/2, p.y - mySize/2, mySize, mySize)
172+
texture.blit_rect(rect, load("res://circle.svg"), myColor)
173+
174+
func _on_color_picker_button_color_changed(color: Color) -> void:
175+
myColor = color
176+
177+
func _on_h_slider_value_changed(value: float) -> void:
178+
mySize = value

tutorials/rendering/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ Rendering
1717
multiple_resolutions
1818
jitter_stutter
1919
compositor
20+
drawable_textures

tutorials/shaders/shader_reference/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ Shading reference
1717
particle_shader
1818
sky_shader
1919
fog_shader
20+
texture_blit_shader
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
.. _doc_texture_blit_shader:
2+
3+
TextureBlit shaders
4+
==================
5+
6+
TextureBlit shaders are used to define the behavior of Blit calls on a DrawableTexture2D
7+
8+
TextureBlit shaders only have one processing function, the ``blit()`` function,
9+
which runs for every pixel of the source texture inside the rect given to ``blit_rect()``
10+
11+
Render modes
12+
------------
13+
14+
+---------------------------------+----------------------------------------------------------------------+
15+
| Render mode | Description |
16+
+=================================+======================================================================+
17+
| **blend_mix** | Mix blend mode (alpha is transparency), default. |
18+
+---------------------------------+----------------------------------------------------------------------+
19+
| **blend_add** | Additive blend mode. |
20+
+---------------------------------+----------------------------------------------------------------------+
21+
| **blend_sub** | Subtractive blend mode. |
22+
+---------------------------------+----------------------------------------------------------------------+
23+
| **blend_mul** | Multiplicative blend mode. |
24+
+---------------------------------+----------------------------------------------------------------------+
25+
| **blend_disabled** | Disable blending, values (including alpha) are written as-is. |
26+
+---------------------------------+----------------------------------------------------------------------+
27+
28+
Built-ins
29+
---------
30+
31+
Values marked as ``in`` are read-only. Values marked as ``out`` can optionally be written to and will
32+
not necessarily contain sensible values. Values marked as ``inout`` provide a sensible default
33+
value, and can optionally be written to. Samplers cannot be written to so they are not marked.
34+
35+
Global built-ins
36+
----------------
37+
38+
Global built-ins are available everywhere, including custom functions.
39+
40+
+-------------------+------------------------------------------------------------------------------------------+
41+
| Built-in | Description |
42+
+===================+==========================================================================================+
43+
| in float **TIME** | Global time since the engine has started, in seconds. It repeats after every ``3,600`` |
44+
| | seconds (which can be changed with the |
45+
| | :ref:`rollover<class_ProjectSettings_property_rendering/limits/time/time_rollover_secs>` |
46+
| | setting). It's affected by |
47+
| | :ref:`time_scale<class_Engine_property_time_scale>` but not by pausing. If you need a |
48+
| | ``TIME`` variable that is not affected by time scale, add your own |
49+
| | :ref:`global shader uniform<doc_shading_language_global_uniforms>` and update it each |
50+
| | frame. |
51+
+-------------------+------------------------------------------------------------------------------------------+
52+
| in float **PI** | A ``PI`` constant (``3.141592``). |
53+
| | A ratio of a circle's circumference to its diameter and amount of radians in half turn. |
54+
+-------------------+------------------------------------------------------------------------------------------+
55+
| in float **TAU** | A ``TAU`` constant (``6.283185``). |
56+
| | An equivalent of ``PI * 2`` and amount of radians in full turn. |
57+
+-------------------+------------------------------------------------------------------------------------------+
58+
| in float **E** | An ``E`` constant (``2.718281``). |
59+
| | Euler's number and a base of the natural logarithm. |
60+
+-------------------+------------------------------------------------------------------------------------------+
61+
62+
63+
Blit built-ins
64+
------------------
65+
66+
Source Textures
67+
~~~~~~~~~~~~~~~~~
68+
TextureBlit Shaders have up to 4 Source Textures bound as inputs.
69+
These can be accessed with a ``sampler2D``
70+
using ``hint_blit_source0``, ``hint_blit_source1``, ``hint_blit_source2``, and ``hint_blit_source3``.
71+
72+
+---------------------------------------------+---------------------------------------------------------------+
73+
| Built-in | Description |
74+
+=============================================+===============================================================+
75+
| in vec4 **FRAGCOORD** | Coordinate of pixel center. In screen space. ``xy`` specifies |
76+
| | position in viewport. Upper-left of the viewport is the |
77+
| | origin, ``(0.0, 0.0)``. |
78+
+---------------------------------------------+---------------------------------------------------------------+
79+
| in vec2 **UV** | UV from the ``vertex()`` function. |
80+
| | This is set to sample all of a source texture. |
81+
+---------------------------------------------+---------------------------------------------------------------+
82+
| in vec4 **MODULATE** | ``MODULATE`` color passed in by RenderingServer API |
83+
+---------------------------------------------+---------------------------------------------------------------+
84+
| out vec4 **COLOR0** | Output Color to blended with the DrawableTexture target. |
85+
| | Initialized to (0.0, 0.0, 0.0, 0.0) |
86+
+---------------------------------------------+---------------------------------------------------------------+
87+
| out vec4 **COLOR1** | Output Color to blended with an extra DrawableTexture target. |
88+
| | Initialized to (0.0, 0.0, 0.0, 0.0) |
89+
+---------------------------------------------+---------------------------------------------------------------+
90+
| out vec4 **COLOR2** | Output Color to blended with an extra DrawableTexture target. |
91+
| | Initialized to (0.0, 0.0, 0.0, 0.0) |
92+
+---------------------------------------------+---------------------------------------------------------------+
93+
| out vec4 **COLOR3** | Output Color to blended with an extra DrawableTexture target. |
94+
| | Initialized to (0.0, 0.0, 0.0, 0.0) |
95+
+---------------------------------------------+---------------------------------------------------------------+
96+

0 commit comments

Comments
 (0)