Skip to content

Commit 39cf9df

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

File tree

2 files changed

+279
-0
lines changed

2 files changed

+279
-0
lines changed

tutorials/2d/drawable_textures.rst

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