Merge pull request #100 from RodZill4/dev-levels

Added tones node
This commit is contained in:
Rodz Labs 2020-03-27 21:09:01 +01:00 committed by GitHub
commit 1d53b938de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 698 additions and 10 deletions

View File

@ -53,6 +53,9 @@ func toggle_editable() -> bool:
func is_template() -> bool: func is_template() -> bool:
return model != null return model != null
func get_template_name() -> bool:
return model
func is_editable() -> bool: func is_editable() -> bool:
return false return false

View File

@ -0,0 +1,122 @@
{
"name": "levels",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
"in_max": {
"a": 1,
"b": 1,
"g": 1,
"r": 1,
"type": "Color"
},
"in_mid": {
"a": 0.5,
"b": 0.5,
"g": 0.5,
"r": 0.5,
"type": "Color"
},
"in_min": {
"a": 0,
"b": 0,
"g": 0,
"r": 0,
"type": "Color"
},
"out_max": {
"a": 1,
"b": 1,
"g": 1,
"r": 1,
"type": "Color"
},
"out_min": {
"a": 0,
"b": 0,
"g": 0,
"r": 0,
"type": "Color"
}
},
"shader_model": {
"code": "",
"global": "vec4 adjust_levels(vec4 input, vec4 in_min, vec4 in_mid, vec4 in_max, vec4 out_min, vec4 out_max) {\n\tinput = clamp((input-in_min)/(in_max-in_min), 0.0, 1.0);\n\tin_mid = (in_mid-in_min)/(in_max-in_min);\n\tvec4 dark = step(in_mid, input);\n\tinput = 0.5*mix(input/(in_mid), 1.0+(input-in_mid)/(1.0-in_mid), dark);\n\treturn out_min+input*(out_max-out_min);\n}\n",
"inputs": [
{
"default": "vec4(1.0)",
"label": "",
"name": "input",
"type": "rgba"
}
],
"instance": "",
"name": "Levels",
"outputs": [
{
"rgba": "adjust_levels($input($uv), $in_min, $in_mid, $in_max, $out_min, $out_max)",
"type": "rgba"
}
],
"parameters": [
{
"default": {
"a": 0,
"b": 0,
"g": 0,
"r": 0
},
"label": "",
"name": "in_min",
"type": "color"
},
{
"default": {
"a": 0.498039,
"b": 0.498039,
"g": 0.498039,
"r": 0.498039
},
"label": "",
"name": "in_mid",
"type": "color"
},
{
"default": {
"a": 1,
"b": 1,
"g": 1,
"r": 1
},
"label": "",
"name": "in_max",
"type": "color"
},
{
"default": {
"a": 1,
"b": 0,
"g": 0,
"r": 0
},
"label": "",
"name": "out_min",
"type": "color"
},
{
"default": {
"a": 1,
"b": 1,
"g": 1,
"r": 1
},
"label": "",
"name": "out_max",
"type": "color"
}
]
},
"type": "shader"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,38 @@
Tones node
~~~~~~~~~~
The **Tones** node provides an easy interface to adjust the tones of its input. It can be applied
homogeneously to the R, G and B channels, or separately on R, G, B and A.
The nodes shows an histogram of all channels of its input, and 3 cursors to modify the input
adjustment at the top, and 2 cursors to modify the output adjustment.
.. image:: images/node_filter_tones.png
:align: center
Inputs
++++++
The **Tones** node requires an RGBA input texture.
Outputs
+++++++
The **Tones** node provides a single RGBA texture.
Parameters
++++++++++
At the top of the node, a control can be used to select the active channel (Luminance, Red,
Green, Blue and Alpha).
The button can be used to adjust automatically the Tones to the node's input to obtain better
contrast.
The 3 cursors at the top of the histogram can be used to select the input colors that will be
remapped to black (value = 0 for single channel), mid-grey (value = 0.5) and white (value = 1).
Values between those defined by cursors are interpolated linearly, and all values are clamped
between 0 and 1.
The 2 bottom cursors define the output color for black (value = 0 for single channel) and
white (value = 1).

View File

@ -9,6 +9,7 @@ The filter nodes accept one or several inputs and generate one or several images
node_filter_invert node_filter_invert
node_filter_brightness_contrast node_filter_brightness_contrast
node_filter_adjust_hsv node_filter_adjust_hsv
node_filter_tones
node_filter_greyscale node_filter_greyscale
node_filter_colorize node_filter_colorize
node_filter_combine node_filter_combine

View File

@ -166,7 +166,7 @@ func clear_material() -> void:
func update_graph(generators, connections) -> Array: func update_graph(generators, connections) -> Array:
var rv = [] var rv = []
for g in generators: for g in generators:
var node = node_factory.create_node(g.get_type()) var node = node_factory.create_node(g.get_template_name() if g.is_template() else "", g.get_type())
if node != null: if node != null:
node.name = "node_"+g.name node.name = "node_"+g.name
add_node(node) add_node(node)

View File

@ -55,9 +55,9 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="40.459032" inkscape:zoom="7.152214"
inkscape:cx="12.31719" inkscape:cx="122.70346"
inkscape:cy="41.781829" inkscape:cy="36.247815"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="true" showgrid="true"
@ -605,5 +605,42 @@
sodipodi:end="0.0018129957" sodipodi:end="0.0018129957"
sodipodi:open="true" sodipodi:open="true"
d="m 15.411452,304.10377 a 7.4148879,7.4346347 0 0 1 -7.4502054,7.39166 7.4148879,7.4346347 0 0 1 -7.37939334,-7.46273 7.4148879,7.4346347 0 0 1 7.43561054,-7.40642 7.4148879,7.4346347 0 0 1 7.3941002,7.44808" /> d="m 15.411452,304.10377 a 7.4148879,7.4346347 0 0 1 -7.4502054,7.39166 7.4148879,7.4346347 0 0 1 -7.37939334,-7.46273 7.4148879,7.4346347 0 0 1 7.43561054,-7.40642 7.4148879,7.4346347 0 0 1 7.3941002,7.44808" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.85721886;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="rect908"
width="2.8650246"
height="9.0406466"
x="16.686302"
y="302.37292"
ry="0" />
<rect
ry="0"
y="297.67682"
x="20.606815"
height="13.736778"
width="2.8650253"
id="rect910"
style="opacity:1;fill:none;fill-opacity:1;stroke:#4e4e4e;stroke-width:0.85721886;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#a9a9a9;stroke-width:0.85721886;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="rect912"
width="2.8650246"
height="11.116821"
x="24.527328"
y="300.29675"
ry="0" />
<rect
ry="0"
y="304.64682"
x="28.447844"
height="6.7667418"
width="2.8650246"
id="rect914"
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.85721886;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" />
<path
inkscape:connector-curvature="0"
id="path4598-6-2"
d="m 23.868329,296.57635 -1.921422,2.02005 -1.696117,-2.29125 a 5.4420629,5.5494302 0 0 0 -1.121274,0.45417 l 0.351782,2.79921 -2.800271,-0.0759 a 5.4420629,5.5494302 0 0 0 -0.336482,1.1114 5.4420629,5.5494302 0 0 0 -0.01172,0.0755 l 2.348852,1.45452 -1.783847,2.16058 a 5.4420629,5.5494302 0 0 0 0.705845,1.02986 l 2.546602,-0.95339 0.540183,2.74829 a 5.4420629,5.5494302 0 0 0 1.239119,0.0834 l 0.851353,-2.6077 2.440798,1.2812 a 5.4420629,5.5494302 0 0 0 0.843823,-0.92816 l -1.472574,-2.31072 2.525556,-1.15689 a 5.4420629,5.5494302 0 0 0 -0.176525,-1.23851 l -2.720271,-0.26982 0.695042,-2.76445 a 5.4420629,5.5494302 0 0 0 -1.048452,-0.62144 z m -1.905851,3.7062 a 1.3605156,1.3873574 0 0 1 1.075273,1.62703 1.3605156,1.3873574 0 0 1 -1.595552,1.09649 1.3605156,1.3873574 0 0 1 -1.075275,-1.62703 1.3605156,1.3873574 0 0 1 1.595554,-1.09649 z"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.34617221;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -2289,6 +2289,50 @@
"tree_item": "Filter/AdjustHSV", "tree_item": "Filter/AdjustHSV",
"type": "adjust_hsv" "type": "adjust_hsv"
}, },
{
"collapsed": true,
"icon": "filter_tones",
"name": "tones",
"parameters": {
"in_max": {
"a": 1,
"b": 1,
"g": 1,
"r": 1,
"type": "Color"
},
"in_mid": {
"a": 0.5,
"b": 0.5,
"g": 0.5,
"r": 0.5,
"type": "Color"
},
"in_min": {
"a": 0,
"b": 0,
"g": 0,
"r": 0,
"type": "Color"
},
"out_max": {
"a": 1,
"b": 1,
"g": 1,
"r": 1,
"type": "Color"
},
"out_min": {
"a": 0,
"b": 0,
"g": 0,
"r": 0,
"type": "Color"
}
},
"tree_item": "Filter/Tones",
"type": "tones"
},
{ {
"collapsed": true, "collapsed": true,
"icon": "filter_greyscale", "icon": "filter_greyscale",

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

View File

@ -462,7 +462,7 @@ func make_selected_nodes_editable() -> void:
var selected_nodes = get_selected_nodes() var selected_nodes = get_selected_nodes()
if !selected_nodes.empty(): if !selected_nodes.empty():
for n in selected_nodes: for n in selected_nodes:
if n.generator.toggle_editable(): if n.generator.toggle_editable() and n.has_method("update_node"):
n.update_node() n.update_node()
func add_to_user_library() -> void: func add_to_user_library() -> void:

View File

@ -2,13 +2,16 @@ extends Node
var includes var includes
func create_node(type) -> Node: func create_node(model : String, type : String) -> Node:
var node_type = null
var node = null var node = null
var file_name = "res://material_maker/nodes/"+type+".tscn" var file_name = "res://material_maker/nodes/"+model+".tscn"
if ! ResourceLoader.exists(file_name):
file_name = "res://material_maker/nodes/"+type+".tscn"
if ResourceLoader.exists(file_name): if ResourceLoader.exists(file_name):
var node_type = load(file_name) node_type = load(file_name)
if node_type != null: if node_type != null:
node = node_type.instance() node = node_type.instance()
if node == null: if node == null:
node = preload("res://material_maker/nodes/generic.tscn").instance() node = preload("res://material_maker/nodes/generic.tscn").instance()
return node return node

View File

@ -0,0 +1,170 @@
extends MMGraphNodeBase
class Cursor:
extends Control
var color : Color
var top : bool = true
var position : float
const WIDTH : int = 8
const HEIGHT : int = 8
func _init(c, p, t = true):
color = c
position = p
top = t
func _ready() -> void:
rect_position.y = -2 if top else get_parent().rect_size.y+2-HEIGHT
set_value(position)
rect_size = Vector2(WIDTH, HEIGHT)
func _draw() -> void:
var polygon : PoolVector2Array
if top:
polygon = PoolVector2Array([Vector2(0, 0), Vector2(WIDTH/2, HEIGHT), Vector2(WIDTH, 0), Vector2(0, 0)])
else:
polygon = PoolVector2Array([Vector2(0, HEIGHT), Vector2(WIDTH/2, 0), Vector2(WIDTH, HEIGHT), Vector2(0, HEIGHT)])
var c = color
c.a = 1.0
draw_colored_polygon(polygon, c)
var outline_color = 0.0 if position > 0.5 else 1.0
draw_polyline(polygon, Color(outline_color, outline_color, outline_color), 1.0, true)
func _gui_input(ev) -> void:
if ev is InputEventMouseMotion && (ev.button_mask & 1) != 0:
rect_position.x += ev.relative.x
rect_position.x = min(max(-0.5*WIDTH, rect_position.x), get_parent().rect_size.x-0.5*WIDTH)
update_value((rect_position.x+0.5*WIDTH)/get_parent().rect_size.x)
func update_value(p : float) -> void:
if p != position:
set_value(p)
get_parent().get_parent().update_value(self, position)
update()
func set_value(v : float):
position = v
rect_position.x = position * get_parent().rect_size.x - 0.5*WIDTH
var cursor_in_min : Cursor
var cursor_in_mid : Cursor
var cursor_in_max : Cursor
var cursor_out_min : Cursor
var cursor_out_max : Cursor
func _ready() -> void:
var slot_color = mm_io_types.types["rgba"].color
var slot_type = mm_io_types.types["rgba"].slot_type
set_slot(0, true, slot_type, slot_color, true, slot_type, slot_color)
cursor_in_min = Cursor.new(Color(0.0, 0.0, 0.0), 0.0)
$Histogram.add_child(cursor_in_min)
cursor_in_mid = Cursor.new(Color(0.5, 0.5, 0.5), 0.5)
$Histogram.add_child(cursor_in_mid)
cursor_in_max = Cursor.new(Color(1.0, 1.0, 1.0), 1.0)
$Histogram.add_child(cursor_in_max)
cursor_out_min = Cursor.new(Color(0.0, 0.0, 0.0), 0.0, false)
$Histogram.add_child(cursor_out_min)
cursor_out_max = Cursor.new(Color(1.0, 1.0, 1.0), 1.0, false)
$Histogram.add_child(cursor_out_max)
func set_generator(g) -> void:
.set_generator(g)
generator.connect("parameter_changed", self, "on_parameter_changed")
_on_Mode_item_selected(0)
func on_parameter_changed(p, v) -> void:
if p == "__input_changed__":
var source = generator.get_source(0)
var result = source.generator.render(source.output_index, 128, true)
while result is GDScriptFunctionState:
result = yield(result, "completed")
result.copy_to_texture($Histogram.get_image_texture())
result.release()
func get_parameter(n : String) -> float:
var value = generator.get_parameter(n)
match $Bar/Mode.selected:
1:
return value.r
2:
return value.g
3:
return value.b
4:
return value.a
return (value.r+value.g+value.b)/3.0
func _on_Mode_item_selected(_id):
cursor_in_min.set_value(get_parameter("in_min"))
cursor_in_mid.set_value(get_parameter("in_mid"))
cursor_in_max.set_value(get_parameter("in_max"))
cursor_out_min.set_value(get_parameter("out_min"))
cursor_out_max.set_value(get_parameter("out_max"))
func set_parameter(n : String, v : float, d : float) -> void:
var value = generator.get_parameter(n)
match $Bar/Mode.selected:
0:
value.r = v
value.g = v
value.b = v
value.a = d
1:
value.r = v
2:
value.g = v
3:
value.b = v
4:
value.a = v
generator.set_parameter(n, value)
func update_value(control : Cursor, value : float) -> void:
match control:
cursor_in_min:
set_parameter("in_min", value, 0)
cursor_in_mid:
set_parameter("in_mid", value, 0.5)
cursor_in_max:
set_parameter("in_max", value, 1)
cursor_out_min:
set_parameter("out_min", value, 0)
cursor_out_max:
set_parameter("out_max", value, 1)
get_parent().send_changed_signal()
func _on_Auto_pressed():
var histogram = $Histogram.get_histogram_texture().get_data()
histogram.lock()
var in_min : int = -1
var in_mid : int = -1
var in_mid_value : float = 0
var in_max : int = -1
var histogram_size = histogram.get_size().x
for i in range(histogram_size):
var color : Color = histogram.get_pixel(i, 0)
var value : float
match $Bar/Mode.selected:
0:
value = (color.r+color.g+color.b)/3.0
1:
value = color.r
2:
value = color.g
3:
value = color.b
4:
value = color.a
if value > 0.0:
if in_min == -1:
in_min = i
in_max = i
if in_mid_value < value:
in_mid = i
in_mid_value = value
histogram.unlock()
cursor_in_min.update_value(in_min/(histogram_size-1))
cursor_in_mid.update_value(in_mid/(histogram_size-1))
cursor_in_max.update_value(in_max/(histogram_size-1))

View File

@ -0,0 +1,103 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://material_maker/nodes/tones.gd" type="Script" id=1]
[ext_resource path="res://material_maker/widgets/histogram/histogram.tscn" type="PackedScene" id=2]
[ext_resource path="res://material_maker/icons/icons.svg" type="Texture" id=3]
[sub_resource type="AtlasTexture" id=1]
flags = 4
atlas = ExtResource( 3 )
region = Rect2( 16, 80, 16, 16 )
[node name="Tones" type="GraphNode"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 2.75074
margin_top = 1.78928
margin_right = -1053.25
margin_bottom = -529.211
title = "Tones"
show_close = true
slot/0/left_enabled = true
slot/0/left_type = 0
slot/0/left_color = Color( 0, 0.396078, 1, 1 )
slot/0/right_enabled = true
slot/0/right_type = 0
slot/0/right_color = Color( 0, 0.415686, 1, 1 )
slot/1/left_enabled = false
slot/1/left_type = 0
slot/1/left_color = Color( 1, 1, 1, 1 )
slot/1/right_enabled = false
slot/1/right_type = 0
slot/1/right_color = Color( 1, 1, 1, 1 )
slot/2/left_enabled = false
slot/2/left_type = 0
slot/2/left_color = Color( 1, 1, 1, 1 )
slot/2/right_enabled = false
slot/2/right_type = 0
slot/2/right_color = Color( 1, 1, 1, 1 )
slot/3/left_enabled = false
slot/3/left_type = 0
slot/3/left_color = Color( 1, 1, 1, 1 )
slot/3/right_enabled = false
slot/3/right_type = 0
slot/3/right_color = Color( 1, 1, 1, 1 )
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Bar" type="HBoxContainer" parent="."]
margin_left = 16.0
margin_top = 24.0
margin_right = 208.0
margin_bottom = 44.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Mode" type="OptionButton" parent="Bar"]
margin_right = 172.0
margin_bottom = 20.0
size_flags_horizontal = 3
text = "Luminance"
items = [ "Luminance", null, false, 0, null, "Red", null, false, 1, null, "Green", null, false, 2, null, "Blue", null, false, 3, null, "Alpha", null, false, 4, null ]
selected = 0
[node name="Auto" type="TextureButton" parent="Bar"]
margin_left = 176.0
margin_top = 2.0
margin_right = 192.0
margin_bottom = 18.0
hint_tooltip = "Set levels automatically"
size_flags_vertical = 4
texture_normal = SubResource( 1 )
[node name="Spacer1" type="Control" parent="."]
margin_left = 16.0
margin_top = 45.0
margin_right = 208.0
margin_bottom = 49.0
rect_min_size = Vector2( 0, 4 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Histogram" parent="." instance=ExtResource( 2 )]
margin_left = 16.0
margin_top = 50.0
margin_right = 208.0
margin_bottom = 178.0
rect_min_size = Vector2( 192, 128 )
[node name="Spacer2" type="Control" parent="."]
margin_left = 16.0
margin_top = 179.0
margin_right = 208.0
margin_bottom = 183.0
rect_min_size = Vector2( 0, 4 )
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="item_selected" from="Bar/Mode" to="." method="_on_Mode_item_selected"]
[connection signal="pressed" from="Bar/Auto" to="." method="_on_Auto_pressed"]

View File

@ -0,0 +1,10 @@
extends Control
func update_histogram() -> void:
pass
func get_image_texture() -> ImageTexture:
return $ViewportImage/ColorRect.material.get_shader_param("tex")
func get_histogram_texture() -> ImageTexture:
return $Control.material.get_shader_param("tex")

View File

@ -0,0 +1,157 @@
[gd_scene load_steps=14 format=2]
[ext_resource path="res://material_maker/widgets/histogram/histogram.gd" type="Script" id=1]
[sub_resource type="Shader" id=1]
resource_local_to_scene = true
code = "shader_type canvas_item;
render_mode blend_disabled;
uniform sampler2D tex;
void fragment() {
COLOR = texture(tex, UV);
}
"
[sub_resource type="ImageTexture" id=2]
resource_local_to_scene = true
[sub_resource type="ShaderMaterial" id=3]
resource_local_to_scene = true
shader = SubResource( 1 )
shader_param/tex = SubResource( 2 )
[sub_resource type="Shader" id=4]
code = "shader_type canvas_item;
render_mode blend_disabled;
uniform sampler2D tex;
void fragment() {
vec4 sum = vec4(0.0);
for (int i = 0; i < 128; ++i) {
sum += step(abs(texture(tex, vec2(UV.x, float(i)/127.0))-UV.y), vec4(0.02));
}
COLOR = sum/255.0;
}
"
[sub_resource type="ViewportTexture" id=5]
viewport_path = NodePath("ViewportImage")
[sub_resource type="ShaderMaterial" id=6]
resource_local_to_scene = true
shader = SubResource( 4 )
shader_param/tex = SubResource( 5 )
[sub_resource type="Shader" id=7]
code = "shader_type canvas_item;
render_mode blend_disabled;
uniform sampler2D tex;
void fragment() {
vec4 sum = vec4(0.0);
for (int i = 0; i < 128; ++i) {
sum += texture(tex, vec2(float(i)/127.0, UV.x));
}
COLOR = sum/255.0;
}"
[sub_resource type="ViewportTexture" id=8]
viewport_path = NodePath("ViewportHistogram1")
[sub_resource type="ShaderMaterial" id=9]
resource_local_to_scene = true
shader = SubResource( 7 )
shader_param/tex = SubResource( 8 )
[sub_resource type="Shader" id=10]
code = "shader_type canvas_item;
uniform sampler2D tex;
render_mode blend_disabled;
void fragment() {
if (abs(fract(UV.y+0.05)) < 0.1) {
COLOR = vec4(vec3(UV.x), 1.0);
} else {
vec4 highest = vec4(0.0);
for (int i = 0; i < 128; ++i) {
highest = max(highest, texture(tex, vec2(float(i)/128.0, 0.0)));
}
vec4 value = step(vec4(0.95-UV.y)*highest/0.9, texture(tex, vec2(UV.x, 0.0)));
float alpha = step(0.1, dot(value, vec4(1.0)));
COLOR = vec4(mix(value.rgb, vec3(0.5), 0.3*value.a), alpha);
}
}"
[sub_resource type="ViewportTexture" id=11]
flags = 4
viewport_path = NodePath("ViewportHistogram2")
[sub_resource type="ShaderMaterial" id=12]
resource_local_to_scene = true
shader = SubResource( 10 )
shader_param/tex = SubResource( 11 )
[node name="Histogram" type="Control"]
margin_right = 64.0
margin_bottom = 64.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ViewportImage" type="Viewport" parent="."]
size = Vector2( 256, 256 )
transparent_bg = true
hdr = false
usage = 0
render_target_v_flip = true
render_target_update_mode = 3
[node name="ColorRect" type="ColorRect" parent="ViewportImage"]
material = SubResource( 3 )
margin_right = 256.0
margin_bottom = 128.0
rect_min_size = Vector2( 256, 256 )
[node name="ViewportHistogram1" type="Viewport" parent="."]
size = Vector2( 128, 128 )
own_world = true
transparent_bg = true
hdr = false
usage = 0
render_target_v_flip = true
render_target_update_mode = 3
[node name="ColorRect" type="ColorRect" parent="ViewportHistogram1"]
material = SubResource( 6 )
margin_right = 128.0
margin_bottom = 128.0
rect_min_size = Vector2( 128, 128 )
[node name="ViewportHistogram2" type="Viewport" parent="."]
size = Vector2( 128, 2 )
transparent_bg = true
disable_3d = true
keep_3d_linear = true
usage = 0
render_target_v_flip = true
render_target_update_mode = 3
[node name="ColorRect" type="ColorRect" parent="ViewportHistogram2"]
material = SubResource( 9 )
margin_right = 128.0
margin_bottom = 2.0
rect_min_size = Vector2( 128, 2 )
[node name="Control" type="ColorRect" parent="."]
material = SubResource( 12 )
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}