Many changes & fixes...

- shader updates are delayed by .25 seconds to avouid UI freeze
- fixed GraphNode initialization upon loading
- started obsoleting get_source_rgb and get_source_f functions
- updated colorize node to use gradient
- image node can now be loaded/saved
- removed iqnoise node
- rewrote perlin shader to support a seed parameter (seed is calculated from the node's position, so just move it to reseed)
- Added voronoi noise node
- updated code to use % formats instead of concatenating strings (should solve type problems in shaders)
- reworked the context menu (now has submenus)
- fixes in the gradient editor
This commit is contained in:
RodZill4 2018-07-28 09:37:51 +02:00
parent 46adb434bf
commit 10ea905090
25 changed files with 571 additions and 571 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
.import
generated_image.png
generated_image.png

View File

@ -1,6 +1,8 @@
tool
extends GraphEdit
signal graph_changed
func _ready():
pass
@ -14,6 +16,12 @@ func remove_node(node):
if c.from == node or c.to == node:
disconnect_node(c.from, c.from_port, c.to, c.to_port)
func send_changed_signal():
$Timer.start()
func do_send_changed_signal():
emit_signal("graph_changed")
func generate_shader(node, shader_type = 0):
var code
if shader_type == 1:
@ -45,6 +53,6 @@ func generate_shader(node, shader_type = 0):
else:
shader_code += "COLOR = vec4(1.0);\n"
shader_code += "}\n"
print("GENERATED SHADER:\n"+shader_code)
#print("GENERATED SHADER:\n"+shader_code)
code += shader_code
return code

View File

@ -6,6 +6,7 @@ var material = null
func _ready():
material = ShaderMaterial.new()
material.shader = Shader.new()
material.shader.set_code("shader_type spatial;\nvoid fragment() {\n ALBEDO=vec3(0.5);\n}\n")
$Objects/Cube.set_surface_material(0, material)
$Objects/Cylinder.set_surface_material(0, material)
$AnimationPlayer.play("rotate")

View File

@ -22,24 +22,32 @@ func initialize_properties(object_list):
set(o.name, o.color)
o.connect("color_changed", self, "_on_color_changed", [ o.name ])
func get_seed():
return int(offset.x)*3+int(offset.y)*5
func update_property_widgets():
for o in property_widgets:
if o is LineEdit:
o.text = str(get(o.name))
elif o is SpinBox:
o.value = get(o.name)
elif o is ColorPickerButton:
o.color = get(o.name)
func update_shaders():
get_parent().send_changed_signal()
func _on_text_changed(new_text, variable):
set(variable, float(new_text))
get_parent().get_parent().generate_shader()
update_shaders()
func _on_value_changed(new_value, variable):
set(variable, new_value)
get_parent().get_parent().generate_shader()
update_shaders()
func _on_color_changed(new_color, variable):
set(variable, new_color)
get_parent().get_parent().generate_shader()
update_shaders()
func get_source(index = 0):
for c in get_parent().get_children():
@ -51,7 +59,7 @@ func get_source(index = 0):
func get_source_f(source):
var rv
if source.has("rgb"):
rv = "dot("+source.rgb+", vec3(1.0, 1.0, 1.0))"
rv = "dot("+source.rgb+", vec3(1.0))/3.0"
elif source.has("f"):
rv = source.f
else:
@ -69,7 +77,12 @@ func get_source_rgb(source):
return rv
func get_shader_code(uv):
return _get_shader_code(uv)
var rv = _get_shader_code(uv)
if !rv.has("f") && rv.has("rgb"):
rv.f = "(dot("+rv.rgb+", vec3(1.0))/3.0)"
if !rv.has("rgb") && rv.has("f"):
rv.rgb = "vec3("+rv.f+")"
return rv
func get_textures():
var list = {}
@ -107,10 +120,9 @@ func serialize():
return data
func deserialize(data):
print("deserialize: "+name)
offset = Vector2(data.node_position.x, data.node_position.y)
for w in property_widgets:
var v = w.name
set(v, deserialize_element(data[v]))
print(" "+v+" = "+str(deserialize_element(data[v])))
var variable = w.name
var value = deserialize_element(data[variable])
set(variable, value)
update_property_widgets()

View File

@ -22,10 +22,10 @@ func _get_shader_code(uv):
var src0_code = src0.get_shader_code(uv)
var src1_code = src1.get_shader_code(uv)
var src2_code = { defs="", code="" }
var amount_str = str(amount)
var amount_str = "%.9f" % amount
if src2 != null:
src2_code = src2.get_shader_code(uv)
amount_str = str(src2_code.f)
amount_str = src2_code.f
if generated_variants.empty():
rv.defs = src0_code.defs+src1_code.defs+src2_code.defs
var variant_index = generated_variants.find(uv)

View File

@ -6,10 +6,6 @@ var color1
func _ready():
set_slot(0, true, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
initialize_properties([ $color0, $color1 ])
func color_to_string(c):
return "vec3("+str(c.r)+","+str(c.g)+","+str(c.b)+")"
func _get_shader_code(uv):
var rv = { defs="", code="" }
@ -18,15 +14,20 @@ func _get_shader_code(uv):
return rv
var src_code = src.get_shader_code(uv)
if generated_variants.empty():
rv.defs = src_code.defs;
rv.defs = src_code.defs+$Control.get_shader(name+"_gradient");
var variant_index = generated_variants.find(uv)
if variant_index == -1:
variant_index = generated_variants.size()
generated_variants.append(uv)
rv.code = src_code.code+"vec3 "+name+"_"+str(variant_index)+"_rgb = mix("+color_to_string(color0)+", "+color_to_string(color1)+", "+get_source_f(src_code)+");\n"
rv.f = get_source_f(src_code)
rv.code = src_code.code+"vec3 "+name+"_"+str(variant_index)+"_rgb = "+name+"_gradient("+src_code.f+");\n"
rv.rgb = name+"_"+str(variant_index)+"_rgb"
return rv
func _get_state_variables():
return [ "color0", "color1" ]
func serialize():
var data = .serialize()
data.gradient = $Control.serialize()
return data
func deserialize(data):
$Control.deserialize(data.gradient)
.deserialize(data)

View File

@ -1,7 +1,7 @@
[gd_scene load_steps=3 format=2]
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/procedural_material/nodes/colorize.gd" type="Script" id=1]
[ext_resource path="res://addons/procedural_material/widgets/gradient_editor.tscn" type="PackedScene" id=2]
[sub_resource type="Theme" id=1]
@ -14,8 +14,8 @@ anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 1.0
margin_top = 4.0
margin_right = 98.0
margin_bottom = 74.0
margin_right = 133.0
margin_bottom = 63.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
@ -36,71 +36,18 @@ slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
slot/0/right_enabled = true
slot/0/right_type = 0
slot/0/right_color = Color( 0.5, 0.5, 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 )
script = ExtResource( 1 )
_sections_unfolded = [ "Theme" ]
[node name="color0" type="ColorPickerButton" parent="." index="0"]
[node name="Control" parent="." index="0" instance=ExtResource( 2 )]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 24.0
margin_right = 81.0
margin_bottom = 44.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
text = "0"
flat = false
align = 1
color = Color( 0, 0, 0, 1 )
edit_alpha = true
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="color1" type="ColorPickerButton" parent="." index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 44.0
margin_right = 81.0
margin_bottom = 64.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
text = "0"
flat = false
align = 1
color = Color( 1, 1, 1, 1 )
edit_alpha = true
_sections_unfolded = [ "Caret", "Placeholder" ]
margin_right = 136.0
margin_bottom = 54.0
[connection signal="close_request" from="." to="." method="queue_free"]
[connection signal="updated" from="Control" to="." method="update_shaders"]

View File

@ -39,3 +39,12 @@ func _on_TextureButton_pressed():
dialog.add_filter("*.jpg;JPG image")
dialog.connect("file_selected", self, "set_texture")
dialog.popup_centered()
func serialize():
var data = .serialize()
data.file_path = file_path
return data
func deserialize(data):
set_texture(data.file_path)
.deserialize(data)

View File

@ -6,7 +6,7 @@
[sub_resource type="Theme" id=1]
[node name="Image" type="GraphNode"]
[node name="Image" type="GraphNode" index="0"]
anchor_left = 0.0
anchor_top = 0.0

View File

@ -1,22 +0,0 @@
tool
extends "res://addons/procedural_material/node_base.gd"
var subdivide
var u
var v
func _ready():
set_slot(0, false, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
initialize_properties([ $GridContainer/subdivide, $GridContainer/u, $GridContainer/v ])
func _get_shader_code(uv):
var rv = { defs="", code="" }
if generated_variants.empty():
rv.defs = "float "+name+"_f(vec2 uv) { return iqnoise(uv, "+str(subdivide)+", "+str(u)+", "+str(v)+"); }\n"
var variant_index = generated_variants.find(uv)
if variant_index == -1:
variant_index = generated_variants.size()
generated_variants.append(uv)
rv.code = "float "+name+"_"+str(variant_index)+"_f = "+name+"_f("+uv+");\n"
rv.f = name+"_"+str(variant_index)+"_f"
return rv

View File

@ -1,198 +0,0 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/procedural_material/nodes/iqnoise.gd" type="Script" id=1]
[sub_resource type="Theme" id=1]
[node name="IQNoise" type="GraphNode" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 1.0
margin_top = 2.0
margin_right = 161.0
margin_bottom = 111.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
theme = SubResource( 1 )
title = "IQNoise"
offset = Vector2( 0, 0 )
show_close = true
resizable = false
selected = false
comment = false
overlay = 0
slot/0/left_enabled = false
slot/0/left_type = 0
slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
slot/0/right_enabled = true
slot/0/right_type = 0
slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
script = ExtResource( 1 )
_sections_unfolded = [ "Theme" ]
[node name="GridContainer" type="GridContainer" parent="." index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 24.0
margin_right = 144.0
margin_bottom = 104.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
columns = 2
[node name="Label1" type="Label" parent="GridContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 5.0
margin_right = 66.0
margin_bottom = 19.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "Subdivide:"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="subdivide" type="LineEdit" parent="GridContainer" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 70.0
margin_right = 128.0
margin_bottom = 24.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 1
size_flags_horizontal = 1
size_flags_vertical = 1
text = "8"
focus_mode = 2
context_menu_enabled = true
placeholder_alpha = 0.6
caret_blink = false
caret_blink_speed = 0.65
caret_position = 0
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="Label2" type="Label" parent="GridContainer" index="2"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 33.0
margin_right = 66.0
margin_bottom = 47.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "U:"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="u" type="LineEdit" parent="GridContainer" index="3"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 70.0
margin_top = 28.0
margin_right = 128.0
margin_bottom = 52.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 1
size_flags_horizontal = 1
size_flags_vertical = 1
text = "0.5"
focus_mode = 2
context_menu_enabled = true
placeholder_alpha = 0.6
caret_blink = false
caret_blink_speed = 0.65
caret_position = 0
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="Label3" type="Label" parent="GridContainer" index="4"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 61.0
margin_right = 66.0
margin_bottom = 75.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "V:"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="v" type="LineEdit" parent="GridContainer" index="5"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 70.0
margin_top = 56.0
margin_right = 128.0
margin_bottom = 80.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 1
size_flags_horizontal = 1
size_flags_vertical = 1
text = "0.5"
focus_mode = 2
context_menu_enabled = true
placeholder_alpha = 0.6
caret_blink = false
caret_blink_speed = 0.65
caret_position = 0
_sections_unfolded = [ "Caret", "Placeholder" ]
[connection signal="close_request" from="." to="." method="queue_free"]

View File

@ -33,12 +33,12 @@ slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
slot/0/right_enabled = false
slot/0/right_type = 0
slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
slot/1/left_enabled = false
slot/1/left_enabled = true
slot/1/left_type = 0
slot/1/left_color = Color( 1, 1, 1, 1 )
slot/1/left_color = Color( 0.5, 0.5, 1, 1 )
slot/1/right_enabled = false
slot/1/right_type = 0
slot/1/right_color = Color( 1, 1, 1, 1 )
slot/1/right_color = Color( 0.5, 0.5, 1, 1 )
script = ExtResource( 1 )
_sections_unfolded = [ "Theme" ]

View File

@ -13,7 +13,7 @@ func _ready():
func _get_shader_code(uv):
var rv = { defs="", code="" }
if generated_variants.empty():
rv.defs = "float "+name+"_f(vec2 uv) { return perlin(uv, vec2("+str(scale_x)+", "+str(scale_y)+"), "+str(iterations)+", "+str(persistance)+"); }\n"
rv.defs = "float "+name+"_f(vec2 uv) { return perlin(uv, vec2(%f, %f), %d, %.9f, %d); }\n" % [ scale_x, scale_y, iterations, persistance, get_seed() ]
var variant_index = generated_variants.find(uv)
if variant_index == -1:
variant_index = generated_variants.size()
@ -21,3 +21,6 @@ func _get_shader_code(uv):
rv.code = "float "+name+"_"+str(variant_index)+"_f = "+name+"_f("+uv+");\n"
rv.f = name+"_"+str(variant_index)+"_f"
return rv
func _on_offset_changed():
update_shaders()

View File

@ -5,7 +5,7 @@
[sub_resource type="Theme" id=1]
[node name="Perlin" type="GraphNode" index="0"]
[node name="Perlin" type="GraphNode"]
anchor_left = 0.0
anchor_top = 0.0
@ -249,4 +249,6 @@ _sections_unfolded = [ "Caret", "Placeholder" ]
[connection signal="close_request" from="." to="." method="queue_free"]
[connection signal="offset_changed" from="." to="." method="_on_offset_changed"]

View File

@ -16,7 +16,7 @@ func _get_shader_code(uv):
rv.uv = name+"_uv("+uv+")"
var src_code = src.get_shader_code(rv.uv)
if !generated:
rv.defs = src_code.defs+"vec2 "+name+"_uv(vec2 uv) { return transform(uv, "+str(3.1415928*rotate/180.0)+", "+str(scale)+"); }\n"
rv.defs = src_code.defs+"vec2 "+name+"_uv(vec2 uv) { return transform(uv, %.9f, %.9f); }\n" % [ 3.1415928*rotate/180.0, scale ]
generated = true
rv.code = src_code.code;
if src_code.has("f"):

View File

@ -0,0 +1,25 @@
tool
extends "res://addons/procedural_material/node_base.gd"
var scale_x
var scale_y
var intensity
func _ready():
set_slot(0, false, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
initialize_properties([ $HBoxContainer1/scale_x, $HBoxContainer2/scale_y, $HBoxContainer3/intensity ])
func _get_shader_code(uv):
var rv = { defs="", code="" }
if generated_variants.empty():
rv.defs = "vec4 "+name+"_xyzw(vec2 uv) { return voronoi(uv, vec2(%f, %f), %.9f, %d); }\n" % [ scale_x, scale_y, intensity, get_seed() ]
var variant_index = generated_variants.find(uv)
if variant_index == -1:
variant_index = generated_variants.size()
generated_variants.append(uv)
rv.code = "vec4 "+name+"_"+str(variant_index)+"_xyzw = "+name+"_xyzw("+uv+");\n"
rv.f = name+"_"+str(variant_index)+"_xyzw.z"
return rv
func _on_offset_changed():
update_shaders()

View File

@ -0,0 +1,256 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/procedural_material/nodes/voronoi.gd" type="Script" id=1]
[sub_resource type="Theme" id=1]
[node name="Voronoi" type="GraphNode" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 1.0
margin_top = 2.0
margin_right = 172.0
margin_bottom = 105.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
theme = SubResource( 1 )
title = "Voronoi"
offset = Vector2( 0, 0 )
show_close = true
resizable = false
selected = false
comment = false
overlay = 0
slot/0/left_enabled = false
slot/0/left_type = 0
slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
slot/0/right_enabled = true
slot/0/right_type = 0
slot/0/right_color = Color( 0.5, 0.5, 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 )
script = ExtResource( 1 )
_sections_unfolded = [ "Theme" ]
[node name="HBoxContainer1" type="HBoxContainer" parent="." index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 24.0
margin_right = 155.0
margin_bottom = 48.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 1
alignment = 0
_sections_unfolded = [ "Size Flags" ]
[node name="Label1" type="Label" parent="HBoxContainer1" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 5.0
margin_right = 61.0
margin_bottom = 19.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 4
text = "Scale X:"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Anchor", "Size Flags" ]
[node name="scale_x" type="SpinBox" parent="HBoxContainer1" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 65.0
margin_right = 139.0
margin_bottom = 24.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 8
size_flags_vertical = 1
min_value = 0.0
max_value = 32.0
step = 1.0
page = 0.0
value = 4.0
exp_edit = false
rounded = false
editable = true
prefix = ""
suffix = ""
_sections_unfolded = [ "Anchor", "Caret", "Focus", "Grow Direction", "Hint", "Margin", "Mouse", "Placeholder", "Rect", "Size Flags" ]
[node name="HBoxContainer2" type="HBoxContainer" parent="." index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 48.0
margin_right = 155.0
margin_bottom = 72.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
alignment = 0
[node name="Label2" type="Label" parent="HBoxContainer2" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 5.0
margin_right = 61.0
margin_bottom = 19.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 4
text = "Scale Y:"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Size Flags" ]
[node name="scale_y" type="SpinBox" parent="HBoxContainer2" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 65.0
margin_right = 139.0
margin_bottom = 24.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 8
size_flags_vertical = 1
min_value = 0.0
max_value = 32.0
step = 1.0
page = 0.0
value = 4.0
exp_edit = false
rounded = false
editable = true
prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder", "Size Flags" ]
[node name="HBoxContainer3" type="HBoxContainer" parent="." index="2"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 73.0
margin_right = 155.0
margin_bottom = 97.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
alignment = 0
[node name="Label3" type="Label" parent="HBoxContainer3" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 5.0
margin_right = 61.0
margin_bottom = 19.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 4
text = "Intensity:"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Size Flags" ]
[node name="intensity" type="SpinBox" parent="HBoxContainer3" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 65.0
margin_right = 139.0
margin_bottom = 24.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 8
size_flags_vertical = 1
min_value = 0.0
max_value = 3.0
step = 0.05
page = 0.0
value = 1.0
exp_edit = false
rounded = false
editable = true
prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder", "Size Flags" ]
[connection signal="close_request" from="." to="." method="queue_free"]
[connection signal="offset_changed" from="." to="." method="_on_offset_changed"]

View File

@ -24,7 +24,7 @@ func _get_shader_code(uv):
var src1_code3 = src1.get_shader_code(uv+"-vec2(0.0, 0.01)")
rv.defs = src1_code0.defs
rv.code = src1_code0.code+src1_code1.code+src1_code2.code+src1_code3.code
rv.code += "vec2 "+name+"_"+str(variant_index)+"_uv = "+uv+"+"+str(amount)+"*vec2("+get_source_f(src1_code0)+"-"+get_source_f(src1_code1)+", "+get_source_f(src1_code2)+"-"+get_source_f(src1_code3)+");\n"
rv.code += "vec2 "+name+"_"+str(variant_index)+"_uv = "+uv+"+%.9f*vec2((%s)-(%s), (%s)-(%s));\n" % [ amount, src1_code0.f, src1_code1.f, src1_code2.f, src1_code3.f ]
var src0_code = src0.get_shader_code(name+"_"+str(variant_index)+"_uv")
rv.defs += src0_code.defs
rv.code += src0_code.code

View File

@ -1,6 +1,7 @@
tool
extends Container
var popup_menu = null
var popup_position = Vector2(0, 0)
var selected_node = null
@ -11,31 +12,52 @@ const MENU = [
{ command="load_texture", description="Load texture" },
{ command="save_texture", description="Save texture" },
{ command="export_texture", description="Export texture" },
{ name="image", description="Image" },
{ name="sine", description="Sine" },
{ name="bricks", description="Bricks" },
{ name="iqnoise", description="IQ Noise" },
{ name="perlin", description="Perlin noise" },
{ name="transform", description="Transform" },
{ name="warp", description="Warp" },
{ name="colorize", description="Colorize" },
{ name="normal_map", description="Normal Map" },
{ name="blend", description="Blend" }
{ submenu="generator", description="Generator" },
{ name="image", description="Image", in_submenu="generator" },
{ name="sine", description="Sine", in_submenu="generator" },
{ name="bricks", description="Bricks", in_submenu="generator" },
{ name="perlin", description="Perlin noise", in_submenu="generator" },
{ name="voronoi", description="Voronoi Noise", in_submenu="generator" },
{ submenu="filter", description="Filter" },
{ name="colorize", description="Colorize", in_submenu="filter" },
{ name="blend", description="Blend", in_submenu="filter" },
{ name="transform", description="Transform", in_submenu="filter" },
{ name="warp", description="Warp", in_submenu="filter" },
{ name="normal_map", description="Normal Map", in_submenu="filter" }
]
func _ready():
# Duplicate the material we'll modify and store the shaders
preview_material = $Container/ViewportContainer/MaterialPreview.material
$Container/ViewportContainer/SelectedPreview.material = $Container/ViewportContainer/SelectedPreview.material.duplicate(true)
texture_preview_material = $Container/ViewportContainer/SelectedPreview.material
preview_material = $Preview/ViewportContainer/MaterialPreview.material
$Preview/ViewportContainer/SelectedPreview.material = $Preview/ViewportContainer/SelectedPreview.material.duplicate(true)
texture_preview_material = $Preview/ViewportContainer/SelectedPreview.material
$GraphEdit.add_valid_connection_type(0, 0)
$GraphEdit/PopupMenu.clear()
# create or update popup menu
if popup_menu != null:
popup_menu.queue_free()
popup_menu = create_menu()
$GraphEdit.add_child(popup_menu)
func create_menu(in_submenu = null):
var menu = PopupMenu.new()
menu.connect("id_pressed", self, "_on_PopupMenu_id_pressed")
for i in MENU.size():
$GraphEdit/PopupMenu.add_item(MENU[i].description, i)
if MENU[i].has("in_submenu"):
if in_submenu != MENU[i].in_submenu:
continue
elif in_submenu != null:
continue
if MENU[i].has("submenu"):
var submenu = create_menu(MENU[i].submenu)
menu.add_child(submenu)
menu.add_submenu_item(MENU[i].description, submenu.get_name())
else:
menu.add_item(MENU[i].description, i)
return menu
func _on_GraphEdit_popup_request(position):
popup_position = position
$GraphEdit/PopupMenu.popup(Rect2(position, $GraphEdit/PopupMenu.rect_size))
popup_menu.popup(Rect2(position, popup_menu.rect_size))
func _on_PopupMenu_id_pressed(id):
var node_type = null
@ -45,6 +67,13 @@ func _on_PopupMenu_id_pressed(id):
node_type = load("res://addons/procedural_material/nodes/"+MENU[id].name+".tscn")
if node_type != null:
var node = node_type.instance()
var i = 0
while true:
var name = MENU[id].name+"_"+str(i)
if !$GraphEdit.has_node(name):
node.set_name(name)
break
i += 1
$GraphEdit.add_child(node)
node.offset = ($GraphEdit.scroll_offset + popup_position - $GraphEdit.rect_global_position) / $GraphEdit.zoom
@ -125,7 +154,7 @@ func export_texture():
func setup_material(shader_material, textures, shader_code):
for k in textures.keys():
print("Setting param "+k+" to "+str(textures[k]))
#print("Setting param "+k+" to "+str(textures[k]))
shader_material.set_shader_param(k+"_tex", textures[k])
shader_material.shader.code = shader_code
@ -135,6 +164,7 @@ func generate_shader():
setup_material(texture_preview_material, selected_node.get_textures(), $GraphEdit.generate_shader(selected_node))
func _on_GraphEdit_node_selected(node):
selected_node = node
setup_material(texture_preview_material, selected_node.get_textures(), $GraphEdit.generate_shader(selected_node))
if selected_node != node:
selected_node = node
setup_material(texture_preview_material, selected_node.get_textures(), $GraphEdit.generate_shader(selected_node))

File diff suppressed because one or more lines are too long

View File

@ -1,19 +1,16 @@
float hash1(vec2 p) {
float q = dot(p,vec2(127.1,311.7));
return fract(sin(q)*43758.5453);
float rand(vec2 x) {
return fract(sin(dot(x, vec2(13.9898, 8.141))) * 43758.5453);
}
vec2 hash2(vec2 p) {
vec2 q = vec2( dot(p,vec2(127.1,311.7)),
dot(p,vec2(269.5,183.3)) );
return fract(sin(q)*43758.5453);
vec2 rand2(vec2 x) {
return fract(sin(vec2(dot(x, vec2(13.9898, 8.141)),
dot(x, vec2(3.4562, 17.398)))) * 43758.5453);
}
vec3 hash3(vec2 p) {
vec3 q = vec3( dot(p,vec2(127.1,311.7)),
dot(p,vec2(269.5,183.3)),
dot(p,vec2(419.2,371.9)) );
return fract(sin(q)*43758.5453);
vec3 rand3(vec2 x) {
return fract(sin(vec3(dot(x, vec2(13.9898, 8.141)),
dot(x, vec2(3.4562, 17.398)),
dot(x, vec2(13.254, 5.867)))) * 43758.5453);
}
float sine(vec2 uv, float count, float sharpness) {
@ -51,68 +48,54 @@ float colored_bricks(vec2 uv, vec2 count, float offset) {
return fract(x/3.0+y/7.0);
}
float iqnoise(vec2 uv, float s, float u, float v) {
uv *= s;
vec2 p = floor(uv);
vec2 f = fract(uv);
float k = 1.0+63.0*pow(1.0-v,4.0);
float va = 0.0;
float wt = 0.0;
for( int j=-2; j<=2; j++ )
for( int i=-2; i<=2; i++ )
{
vec2 g = vec2( float(i),float(j) );
vec3 o = hash3( p + g )*vec3(u,u,1.0);
vec2 r = g - f + o.xy;
float d = dot(r,r);
float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );
va += o.z*ww;
wt += ww;
float perlin(vec2 uv, vec2 size, int iterations, float persistence, int seed) {
uv += vec2(float(seed)*0.1234567);
float rv = 0.0;
float coef = 1.0;
float acc = 0.0;
for (int i = 0; i < iterations; ++i) {
vec2 step = vec2(1.0)/size;
float f0 = rand(floor(fract(uv)*size));
float f1 = rand(floor(fract(uv+vec2(step.x, 0.0))*size));
float f2 = rand(floor(fract(uv+vec2(0.0, step.y))*size));
float f3 = rand(floor(fract(uv+vec2(step.x, step.y))*size));
vec2 mixval = fract(uv*size);
mixval = 0.5*(1.0-cos(3.1415928*mixval));
rv += coef * mix(mix(f0, f1, mixval.x), mix(f2, f3, mixval.x), mixval.y);
acc += coef;
size *= 2.0;
coef *= persistence;
}
return va/wt;
return rv / acc;
}
float perlin_old(vec2 uv, vec2 scale, int iterations, float turbulence) {
float f = 0.0;
float c = 1.0;
float m = 0.0;
for(int i = 0; i < iterations; i++) {
vec2 uv2 = scale * mod(uv, vec2(1.0, 1.0));
vec2 uv2_floor = floor(uv2);
vec2 uv2_fract = fract(uv2);
f += c * ( (1.0 - uv2_fract.x) * ((1.0 - uv2_fract.y) * hash1(uv2_floor) + uv2_fract.y * hash1(uv2_floor+vec2(0.0, 1.0)))
+ uv2_fract.x * ((1.0 - uv2_fract.y) * hash1(uv2_floor+vec2(1.0, 0.0)) + uv2_fract.y * hash1(uv2_floor+vec2(1.0, 1.0))));
m += c;
scale *= 2.0;
c *= turbulence;
}
return f/m;
}
vec4 voronoi(vec2 uv, vec2 size, float intensity, int seed) {
uv += vec2(float(seed)*0.1234567);
uv *= size;
float best_distance0 = 1.0;
float best_distance1 = 1.0;
vec2 point0;
vec2 point1;
vec2 p0 = floor(uv);
for (int dx = -1; dx < 2; ++dx) {
for (int dy = -1; dy < 2; ++dy) {
vec2 d = vec2(float(dx), float(dy));
vec2 p = p0+d;
p += rand2(mod(p, size));
float distance = length((uv - p) / size);
if (best_distance0 > distance) {
best_distance1 = best_distance0;
best_distance0 = distance;
point1 = point0;
point0 = p;
} else if (best_distance1 > distance) {
best_distance1 = distance;
point1 = p;
}
}
}
float edge_distance = dot(uv - 0.5*(point0+point1), normalize(point0-point1));
float noise(vec2 p, vec2 freq ){
vec2 unit = vec2(1.0)/freq;
vec2 ij = floor(p/unit);
vec2 xy = mod(p,unit)/unit;
float a = hash1((ij+vec2(0.0,0.0)));
float b = hash1((ij+vec2(1.0,0.0)));
float c = hash1((ij+vec2(0.0,1.0)));
float d = hash1((ij+vec2(1.0,1.0)));
return mix(mix(a, b, xy.x), mix(c, d, xy.x), xy.y);
}
float perlin(vec2 p, vec2 scale, int iterations, float persistance) {
float n = 0.0;
float normK = 0.0;
vec2 f = scale;
float amp = 1.0;
for (int i = 0; i<iterations; i++){
n += amp*noise(p, f);
f*=2.0;
normK += amp;
amp*=persistance;
}
return n/normK;
return vec4(point0, best_distance0*length(size)*intensity, edge_distance);
}

View File

@ -1,3 +1,4 @@
tool
extends Control
class GradientCursor:
@ -29,6 +30,8 @@ class GradientCursor:
return true
return false
signal updated
func _ready():
$Gradient.material = $Gradient.material.duplicate(true)
add_cursor(0, Color(0, 0, 0))
@ -81,13 +84,13 @@ func get_color(x):
# get_color_in_shader
func gcis(color):
return "vec3(%.1f,%.1f,%.1f)" % [color.r, color.g, color.b]
return "vec3(%.9f,%.9f,%.9f)" % [color.r, color.g, color.b]
func get_shader(name):
var array = get_sorted_cursors()
var shader
shader = "vec3 "+name+"(float x) {\n"
shader += " if (x < %.1f) {\n" % array[0].get_position()
shader += " if (x < %.9f) {\n" % array[0].get_position()
shader += " return "+gcis(array[0].color)+";\n"
for i in range(array.size()-1):
var p0 = array[i].get_position()
@ -95,7 +98,7 @@ func get_shader(name):
var p1mp0 = array[i+1].get_position()-p0
var c1mc0 = array[i+1].color-c0
if p1mp0 > 0:
shader += " } else if (x < %.1f) {\n" % array[i+1].get_position()
shader += " } else if (x < %.9f) {\n" % array[i+1].get_position()
shader += " return %s+x*%s;\n" % [gcis(c0-c1mc0*(p0/p1mp0)), gcis(c1mc0/p1mp0)]
shader += " }\n"
shader += " return "+gcis(array[array.size()-1].color)+";\n"
@ -106,8 +109,9 @@ func update_shader():
var shader
shader = "shader_type canvas_item;\n"
shader += get_shader("gradient")
shader += "void fragment() { COLOR = vec4(gradient((UV.x-%.1f)*%.1f), 1.0); }" % [ 0.5*GradientCursor.WIDTH/rect_size.x, (rect_size.x-GradientCursor.WIDTH)/rect_size.x ]
shader += "void fragment() { COLOR = vec4(gradient((UV.x-%.9f)*%.9f), 1.0); }" % [ float(GradientCursor.WIDTH)*0.5/float(rect_size.x), rect_size.x/(rect_size.x-GradientCursor.WIDTH) ]
$Gradient.material.shader.set_code(shader)
emit_signal("updated")
func serialize():
var rv = []
@ -117,6 +121,7 @@ func serialize():
func deserialize(v):
for c in get_sorted_cursors():
queue_free(c)
remove_child(c)
c.free()
for i in v:
add_cursor(i.pos*(rect_size.x-GradientCursor.WIDTH), Color(i.r, i.g, i.b))

View File

@ -33,7 +33,7 @@ margin_left = 24.0
margin_top = 14.0
margin_right = 144.0
margin_bottom = 44.0
rect_min_size = Vector2( 100, 30 )
rect_min_size = Vector2( 120, 30 )
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
@ -89,8 +89,8 @@ anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 4.0
margin_top = 4.0
margin_right = 302.0
margin_bottom = 462.0
margin_right = 4.0
margin_bottom = 4.0
rect_scale = Vector2( 0.75, 0.75 )
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false

View File

@ -1,14 +0,0 @@
tool
extends ColorRect
func _ready():
pass
func _on_gui_input(ev):
if ev is InputEventMouseButton && ev.button_index == 1 && ev.doubleclick:
var dialog = ColorPicker.new()
add_child(dialog)
elif ev is InputEventMouseMotion && (ev.button_mask & 1) != 0:
rect_position.x += ev.relative.x
rect_position.x = min(max(0, rect_position.x), get_parent().rect_size.x-rect_size.x)

View File

@ -1 +1 @@
{"connections":[{"from":"Perlin","from_port":0,"to":"Colorize2","to_port":0},{"from":"Perlin","from_port":0,"to":"Colorize","to_port":0},{"from":"Warp","from_port":0,"to":"Blend","to_port":2},{"from":"Colorize","from_port":0,"to":"Blend","to_port":0},{"from":"Colorize2","from_port":0,"to":"Blend","to_port":1},{"from":"Perlin2","from_port":0,"to":"Warp","to_port":1},{"from":"Blend","from_port":0,"to":"Material","to_port":0},{"from":"Warp","from_port":0,"to":"NormalMap","to_port":0},{"from":"Bricks","from_port":0,"to":"Warp","to_port":0},{"from":"NormalMap","from_port":0,"to":"Material","to_port":1}],"nodes":[{"color0":{"a":1,"b":0,"g":0,"r":1,"type":"Color"},"color1":{"a":1,"b":0.061523,"g":0.461907,"r":0.875,"type":"Color"},"name":"Colorize2","node_position":{"x":120.75943,"y":-319},"type":"colorize"},{"color0":{"a":1,"b":0,"g":0,"r":0,"type":"Color"},"color1":{"a":1,"b":1,"g":1,"r":1,"type":"Color"},"name":"Colorize","node_position":{"x":116.759399,"y":-431},"type":"colorize"},{"amount":0.2,"name":"Warp","node_position":{"x":124,"y":-199},"type":"warp"},{"amount":0.5,"name":"NormalMap","node_position":{"x":310.416809,"y":-124.375488},"type":"normal_map"},{"name":"Material","node_position":{"x":528,"y":-285},"type":"material"},{"iterations":7,"name":"Perlin","node_position":{"x":-149,"y":-455},"persistance":1,"scale_x":8,"scale_y":9,"type":"perlin"},{"iterations":6,"name":"Perlin2","node_position":{"x":-141.24057,"y":-86.125458},"persistance":0.4,"scale_x":4,"scale_y":4,"type":"perlin"},{"bevel":0.1,"columns":3,"mortar":0.1,"name":"Bricks","node_position":{"x":-147.327362,"y":-292.797089},"row_offset":0.5,"rows":6,"type":"bricks"},{"amount":0.5,"name":"Blend","node_position":{"x":326.759399,"y":-306},"type":"blend"}]}
{"connections":[{"from":"Bricks","from_port":0,"to":"Warp","to_port":0},{"from":"Perlin","from_port":0,"to":"Warp","to_port":1},{"from":"Perlin2","from_port":0,"to":"Colorize2","to_port":0},{"from":"Perlin2","from_port":0,"to":"Colorize","to_port":0},{"from":"Colorize","from_port":0,"to":"Blend","to_port":0},{"from":"Colorize2","from_port":0,"to":"Blend","to_port":1},{"from":"Warp","from_port":0,"to":"Colorize3","to_port":0},{"from":"Colorize3","from_port":0,"to":"Blend","to_port":2},{"from":"Blend","from_port":0,"to":"Material","to_port":0},{"from":"Warp","from_port":0,"to":"NormalMap","to_port":0},{"from":"NormalMap","from_port":0,"to":"Material","to_port":1}],"nodes":[{"iterations":6,"name":"Perlin","node_position":{"x":254,"y":317},"persistance":0.35,"scale_x":4,"scale_y":4,"type":"perlin"},{"iterations":7,"name":"Perlin2","node_position":{"x":258,"y":-32},"persistance":0.9,"scale_x":8,"scale_y":8,"type":"perlin"},{"name":"Material","node_position":{"x":981,"y":-13},"type":"material"},{"amount":0.4,"name":"Blend","node_position":{"x":803,"y":-23.75},"type":"blend"},{"bevel":0.6,"columns":3,"mortar":0.05,"name":"Bricks","node_position":{"x":260,"y":132},"row_offset":0.5,"rows":6,"type":"bricks"},{"amount":0.5,"name":"Warp","node_position":{"x":504,"y":199.75},"type":"warp"},{"amount":0.5,"name":"NormalMap","node_position":{"x":820,"y":269},"type":"normal_map"},{"gradient":[{"b":0.001994,"g":0.150751,"pos":0,"r":0.382813},{"b":0.001994,"g":0.067447,"pos":1,"r":0.382813}],"name":"Colorize2","node_position":{"x":540,"y":46.25},"type":"colorize"},{"gradient":[{"b":0.299479,"g":0.299479,"pos":0,"r":0.299479},{"b":0.127604,"g":0.127604,"pos":1,"r":0.127604}],"name":"Colorize","node_position":{"x":540,"y":-18.75},"type":"colorize"},{"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":0.072727,"r":1}],"name":"Colorize3","node_position":{"x":649,"y":136},"type":"colorize"}]}