More nodes and load/save

Added basic colorize and blend nodes
Started implementing loading and saving texture graphs (most nodes need an update to support this)
This commit is contained in:
RodZill4 2018-07-22 23:25:05 +02:00
parent 6c615aeb02
commit 9443940d9a
22 changed files with 481 additions and 89 deletions

View File

@ -0,0 +1,38 @@
tool
extends "res://addons/procedural_material/node_base.gd"
var amount = 0.0
func _ready():
set_slot(0, true, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
set_slot(1, true, 0, Color(0.5, 0.5, 1), false, 0, Color(0.5, 0.5, 1))
set_slot(2, true, 0, Color(0.5, 0.5, 1), false, 0, Color(0.5, 0.5, 1))
initialize_properties([ $amount ])
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="", uv=null, rgb=null, f=null }
var src0 = get_source(0)
var src1 = get_source(1)
var src2 = get_source(2)
if src0 == null or src1 == null:
return rv
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)
if src2 != null:
src2_code = src2.get_shader_code(uv)
amount_str = str(src2_code.f)
if !generated:
rv.defs = src0_code.defs+src1_code.defs+src2_code.defs
rv.code = src0_code.code+src1_code.code+src2_code.code
rv.code += "vec3 "+name+"_rgb = mix("+get_source_rgb(src0_code)+", "+get_source_rgb(src1_code)+", "+amount_str+");\n"
generated = true
rv.rgb = name+"_rgb"
return rv
func _get_state_variables():
return [ "amount" ]

View File

@ -0,0 +1,122 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/procedural_material/blend.gd" type="Script" id=1]
[sub_resource type="Theme" id=1]
[node name="Blend" type="GraphNode" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 618.0
margin_top = 148.0
margin_right = 751.0
margin_bottom = 310.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 = "Blend"
offset = Vector2( 0, 0 )
show_close = true
resizable = false
selected = false
comment = false
overlay = 0
slot/0/left_enabled = true
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="Label1" type="Label" 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 = 117.0
margin_bottom = 38.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 = "Source 1"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="Label2" type="Label" 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 = 38.0
margin_right = 117.0
margin_bottom = 52.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 = "Source 2"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="amount" type="LineEdit" 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 = 53.0
margin_right = 117.0
margin_bottom = 77.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
[connection signal="close_request" from="." to="." method="queue_free"]

View File

@ -1,21 +0,0 @@
tool
extends "res://addons/procedural_material/node_base.gd"
func _ready():
set_slot(0, true, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
set_slot(1, true, 0, Color(0.5, 0.5, 1), false, 0, Color(0.5, 0.5, 1))
func get_shader_code(uv):
var rv = { defs="", code="", uv=null, rgb=null, f=null }
var src0 = get_source(0)
var src1 = get_source(1)
if src0 == null || src1 == null:
return rv
var src0_code = src0.get_shader_code(uv)
var src1_code = src1.get_shader_code(uv)
if !generated:
rv.defs = src0_code.defs+src1_code.defs
rv.code = "float "+name+"_f = "+src0_code.f+"+"+src1_code.f+";\n"
generated = true
rv.f = name+"_f"
return rv

View File

@ -12,11 +12,15 @@ func _ready():
initialize_properties([ $GridContainer/rows, $GridContainer/columns, $GridContainer/row_offset, $GridContainer/mortar, $GridContainer/bevel ]) initialize_properties([ $GridContainer/rows, $GridContainer/columns, $GridContainer/row_offset, $GridContainer/mortar, $GridContainer/bevel ])
func get_shader_code(uv): func get_shader_code(uv):
var rv = { defs="", code="", rgb=null, f=null } var rv = { defs="", code="" }
if !generated: if generated_variants.empty():
rv.defs = "float "+name+"_f(vec2 uv) { return bricks(uv, vec2("+str(rows)+", "+str(columns)+"), "+str(row_offset)+", "+str(mortar)+", "+str(bevel)+"); }\n" rv.defs = "float "+name+"_f(vec2 uv) { return bricks(uv, vec2("+str(rows)+", "+str(columns)+"), "+str(row_offset)+", "+str(mortar)+", "+str(max(0.001, bevel))+"); }\n"
generated = true var variant_index = generated_variants.find(uv)
rv.f = name+"_f("+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 return rv
func _get_state_variables(): func _get_state_variables():

View File

@ -11,10 +11,9 @@ anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
anchor_right = 0.0 anchor_right = 0.0
anchor_bottom = 0.0 anchor_bottom = 0.0
margin_left = 251.0 margin_left = 1.0
margin_top = 121.0 margin_right = 155.0
margin_right = 405.0 margin_bottom = 165.0
margin_bottom = 286.0
rect_pivot_offset = Vector2( 0, 0 ) rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false rect_clip_content = false
mouse_filter = 1 mouse_filter = 1

View File

@ -0,0 +1,29 @@
tool
extends "res://addons/procedural_material/node_base.gd"
var color0
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="", uv=null, rgb=null, f=null }
var src = get_source()
if src == null:
return rv
var src_code = src.get_shader_code(uv)
if !generated:
rv.defs = src_code.defs;
rv.code = src_code.code+"vec3 "+name+"_rgb = mix("+color_to_string(color0)+", "+color_to_string(color1)+", "+src_code.f+");\n"
generated = true
rv.f = src_code.f
rv.rgb = name+"_rgb"
return rv
func _get_state_variables():
return [ "color0", "color1" ]

View File

@ -1,20 +1,20 @@
[gd_scene load_steps=3 format=2] [gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/procedural_material/boolean.gd" type="Script" id=1] [ext_resource path="res://addons/procedural_material/colorize.gd" type="Script" id=1]
[sub_resource type="Theme" id=1] [sub_resource type="Theme" id=1]
[node name="Boolean" type="GraphNode" index="0"] [node name="Colorize" type="GraphNode" index="0"]
anchor_left = 0.0 anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
anchor_right = 0.0 anchor_right = 0.0
anchor_bottom = 0.0 anchor_bottom = 0.0
margin_left = 329.0 margin_left = 618.0
margin_top = 117.0 margin_top = 148.0
margin_right = 462.0 margin_right = 751.0
margin_bottom = 279.0 margin_bottom = 310.0
rect_pivot_offset = Vector2( 0, 0 ) rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false rect_clip_content = false
mouse_filter = 1 mouse_filter = 1
@ -22,7 +22,7 @@ mouse_default_cursor_shape = 0
size_flags_horizontal = 1 size_flags_horizontal = 1
size_flags_vertical = 1 size_flags_vertical = 1
theme = SubResource( 1 ) theme = SubResource( 1 )
title = "Boolean" title = "Colorize"
offset = Vector2( 0, 0 ) offset = Vector2( 0, 0 )
show_close = true show_close = true
resizable = false resizable = false
@ -35,16 +35,16 @@ slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
slot/0/right_enabled = true slot/0/right_enabled = true
slot/0/right_type = 0 slot/0/right_type = 0
slot/0/right_color = Color( 0.5, 0.5, 1, 1 ) slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
slot/1/left_enabled = true slot/1/left_enabled = false
slot/1/left_type = 0 slot/1/left_type = 0
slot/1/left_color = Color( 0.5, 0.5, 1, 1 ) slot/1/left_color = Color( 1, 1, 1, 1 )
slot/1/right_enabled = false slot/1/right_enabled = false
slot/1/right_type = 0 slot/1/right_type = 0
slot/1/right_color = Color( 0.5, 0.5, 1, 1 ) slot/1/right_color = Color( 1, 1, 1, 1 )
script = ExtResource( 1 ) script = ExtResource( 1 )
_sections_unfolded = [ "Theme" ] _sections_unfolded = [ "Theme" ]
[node name="OptionButton" type="OptionButton" parent="." index="0"] [node name="color0" type="ColorPickerButton" parent="." index="0"]
anchor_left = 0.0 anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
@ -62,16 +62,17 @@ mouse_default_cursor_shape = 0
size_flags_horizontal = 1 size_flags_horizontal = 1
size_flags_vertical = 1 size_flags_vertical = 1
toggle_mode = false toggle_mode = false
action_mode = 0
enabled_focus_mode = 2 enabled_focus_mode = 2
shortcut = null shortcut = null
group = null group = null
text = "0"
flat = false flat = false
align = 0 align = 1
items = [ ] color = Color( 0, 0, 0, 1 )
selected = -1 edit_alpha = true
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="OptionButton2" type="OptionButton" parent="." index="1"] [node name="color1" type="ColorPickerButton" parent="." index="1"]
anchor_left = 0.0 anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
@ -89,14 +90,15 @@ mouse_default_cursor_shape = 0
size_flags_horizontal = 1 size_flags_horizontal = 1
size_flags_vertical = 1 size_flags_vertical = 1
toggle_mode = false toggle_mode = false
action_mode = 0
enabled_focus_mode = 2 enabled_focus_mode = 2
shortcut = null shortcut = null
group = null group = null
text = "0"
flat = false flat = false
align = 0 align = 1
items = [ ] color = Color( 1, 1, 1, 1 )
selected = -1 edit_alpha = true
_sections_unfolded = [ "Caret", "Placeholder" ]
[connection signal="close_request" from="." to="." method="queue_free"] [connection signal="close_request" from="." to="." method="queue_free"]

View File

@ -10,7 +10,7 @@ func _ready():
initialize_properties([ $GridContainer/subdivide, $GridContainer/u, $GridContainer/v ]) initialize_properties([ $GridContainer/subdivide, $GridContainer/u, $GridContainer/v ])
func get_shader_code(uv): func get_shader_code(uv):
var rv = { defs="", code="", rgb=null, f=null } var rv = { defs="", code="" }
if !generated: if !generated:
rv.defs = "float "+name+"_f(vec2 uv) { return iqnoise(uv, "+str(subdivide)+", "+str(u)+", "+str(v)+"); }\n" rv.defs = "float "+name+"_f(vec2 uv) { return iqnoise(uv, "+str(subdivide)+", "+str(u)+", "+str(v)+"); }\n"
generated = true generated = true

View File

@ -92,7 +92,7 @@ mouse_filter = 0
mouse_default_cursor_shape = 1 mouse_default_cursor_shape = 1
size_flags_horizontal = 1 size_flags_horizontal = 1
size_flags_vertical = 1 size_flags_vertical = 1
text = "3" text = "8"
focus_mode = 2 focus_mode = 2
context_menu_enabled = true context_menu_enabled = true
placeholder_alpha = 0.6 placeholder_alpha = 0.6

View File

@ -14,12 +14,11 @@ func get_shader_code(uv):
var src_code = src.get_shader_code("UV") var src_code = src.get_shader_code("UV")
rv.code += src_code.defs rv.code += src_code.defs
rv.code += "void fragment() {\n" rv.code += "void fragment() {\n"
rv.code += src_code.code+"\n" rv.code += src_code.code
if src_code.rgb != null: rv.code += "vec3 "+name+"_rgb = "+get_source_rgb(src_code)+";\n"
rv.code += "vec3 "+name+"_rgb = "+src_code.rgb+"\n" rv.code += "COLOR = vec4("+name+"_rgb, 1.0);\n"
rv.code += "COLOR = vec4("+name+"_rgb.r, "+name+"_rgb.g, "+name+"_rgb.b, 1.0);" rv.code += "}\n"
elif src_code.f != null: return rv
rv.code += "float "+name+"_f = "+src_code.f+";\n"
rv.code += "COLOR = vec4("+name+"_f, "+name+"_f, "+name+"_f, 1.0);" func _get_state_variables():
rv.code += "\n}\n" return [ ]
return rv

View File

@ -2,20 +2,38 @@ tool
extends GraphNode extends GraphNode
var generated = false var generated = false
var generated_variants = []
var property_widgets = []
func _ready(): func _ready():
pass print("ready: "+name)
func initialize_properties(object_list): func initialize_properties(object_list):
property_widgets = object_list
for o in object_list: for o in object_list:
if o is LineEdit: if o is LineEdit:
set(o.name, float(o.text)) set(o.name, float(o.text))
o.connect("text_changed", self, "_on_text_changed", [ o.name ]) o.connect("text_changed", self, "_on_text_changed", [ o.name ])
elif o is ColorPickerButton:
set(o.name, o.color)
o.connect("color_changed", self, "_on_color_changed", [ o.name ])
func update_property_widgets():
for o in property_widgets:
if o is LineEdit:
o.text = str(get(o.name))
elif o is ColorPickerButton:
o.color = get(o.name)
func _on_text_changed(new_text, variable): func _on_text_changed(new_text, variable):
set(variable, float(new_text)) set(variable, float(new_text))
get_parent().get_parent().generate_shader() get_parent().get_parent().generate_shader()
func _on_color_changed(new_color, variable):
set(variable, new_color)
get_parent().get_parent().generate_shader()
func get_source(index = 0): func get_source(index = 0):
for c in get_parent().get_children(): for c in get_parent().get_children():
if c != self && c is GraphNode: if c != self && c is GraphNode:
@ -23,6 +41,43 @@ func get_source(index = 0):
return c return c
return null return null
func get_source_rgb(source):
var rv
if source.has("rgb"):
rv = source.rgb
elif source.has("f"):
rv = "vec3("+source.f+")"
else:
rv = "***error***"
return rv
func queue_free(): func queue_free():
get_parent().remove_node(self.name) get_parent().remove_node(self.name)
.queue_free() .queue_free()
func serialize_element(e):
if typeof(e) == TYPE_COLOR:
return { type= "Color", r=e.r, g=e.g, b=e.b, a=e.a }
return e
func deserialize_element(e):
if typeof(e) == TYPE_DICTIONARY:
if e.type == "Color":
return Color(e.r, e.g, e.b, e.a)
return e
func serialize():
var type = get_script().resource_path
type = type.right(type.find_last("/")+1)
type = type.left(type.find_last("."))
var data = { name=name, type=type }
for v in _get_state_variables():
data[v] = serialize_element(get(v))
return data
func deserialize(data):
print("deserialize: "+name)
for v in _get_state_variables():
set(v, deserialize_element(data[v]))
print(" "+v+" = "+str(deserialize_element(data[v])))
update_property_widgets()

View File

@ -9,7 +9,7 @@ func _ready():
initialize_properties([ $GridContainer/iterations, $GridContainer/turbulence ]) initialize_properties([ $GridContainer/iterations, $GridContainer/turbulence ])
func get_shader_code(uv): func get_shader_code(uv):
var rv = { defs="", code="", rgb=null, f=null } var rv = { defs="", code="" }
if !generated: if !generated:
rv.defs = "float "+name+"_f(vec2 uv) { return perlin(uv, "+str(iterations)+", "+str(turbulence)+"); }\n" rv.defs = "float "+name+"_f(vec2 uv) { return perlin(uv, "+str(iterations)+", "+str(turbulence)+"); }\n"
generated = true generated = true

View File

@ -4,12 +4,16 @@ extends Container
var popup_position = Vector2(0, 0) var popup_position = Vector2(0, 0)
const MENU = [ const MENU = [
{ command="load_texture", description="Load texture" },
{ command="save_texture", description="Save texture" },
{ name="sine", description="Sine" }, { name="sine", description="Sine" },
{ name="boolean", description="Boolean" },
{ name="bricks", description="Bricks" }, { name="bricks", description="Bricks" },
{ name="iqnoise", description="IQ Noise" }, { name="iqnoise", description="IQ Noise" },
{ name="perlin", description="Perlin noise" }, { name="perlin", description="Perlin noise" },
{ name="transform", description="Transform" } { name="boolean", description="Boolean" },
{ name="transform", description="Transform" },
{ name="colorize", description="Colorize" },
{ name="blend", description="Blend" }
] ]
func _ready(): func _ready():
@ -24,11 +28,14 @@ func _on_GraphEdit_popup_request(position):
func _on_PopupMenu_id_pressed(id): func _on_PopupMenu_id_pressed(id):
var node_type = null var node_type = null
node_type = load("res://addons/procedural_material/"+MENU[id].name+".tscn") if MENU[id].has("command"):
if node_type != null: call(MENU[id].command)
var node = node_type.instance() elif MENU[id].has("name"):
$GraphEdit.add_child(node) node_type = load("res://addons/procedural_material/"+MENU[id].name+".tscn")
node.set_begin(popup_position) if node_type != null:
var node = node_type.instance()
$GraphEdit.add_child(node)
node.set_begin(popup_position)
func _on_GraphEdit_connection_request(from, from_slot, to, to_slot): func _on_GraphEdit_connection_request(from, from_slot, to, to_slot):
var disconnect = $GraphEdit.get_source(to, to_slot) var disconnect = $GraphEdit.get_source(to, to_slot)
@ -37,6 +44,57 @@ func _on_GraphEdit_connection_request(from, from_slot, to, to_slot):
$GraphEdit.connect_node(from, from_slot, to, to_slot) $GraphEdit.connect_node(from, from_slot, to, to_slot)
generate_shader(); generate_shader();
func load_texture():
var dialog = EditorFileDialog.new()
add_child(dialog)
dialog.access = EditorFileDialog.ACCESS_FILESYSTEM
dialog.mode = EditorFileDialog.MODE_OPEN_FILE
dialog.add_filter("*.ptex;Procedural texture file")
dialog.connect("file_selected", self, "load_file")
dialog.popup_centered()
func load_file(filename):
var file = File.new()
if file.open(filename, File.READ) != OK:
return
var data = file.get_var()
file.close()
$GraphEdit.clear_connections()
for c in $GraphEdit.get_children():
if c is GraphNode:
$GraphEdit.remove_child(c)
c.free()
for n in data.nodes:
var node_type = load("res://addons/procedural_material/"+n.type+".tscn")
if node_type != null:
var node = node_type.instance()
node.name = n.name
$GraphEdit.add_child(node)
node.deserialize(n)
for c in data.connections:
$GraphEdit.connect_node(c.from, c.from_port, c.to, c.to_port)
generate_shader()
func save_texture():
var dialog = EditorFileDialog.new()
add_child(dialog)
dialog.access = EditorFileDialog.ACCESS_FILESYSTEM
dialog.mode = EditorFileDialog.MODE_SAVE_FILE
dialog.add_filter("*.ptex;Procedural texture file")
dialog.connect("file_selected", self, "save_file")
dialog.popup_centered()
func save_file(filename):
var data = { nodes = [] }
for c in $GraphEdit.get_children():
if c is GraphNode:
data.nodes.append(c.serialize())
data.connections = $GraphEdit.get_connection_list()
var file = File.new()
if file.open(filename, File.WRITE) == OK:
file.store_var(data)
file.close()
func generate_shader(): func generate_shader():
var code = "" var code = ""
var file = File.new() var file = File.new()
@ -47,8 +105,9 @@ func generate_shader():
for c in $GraphEdit.get_children(): for c in $GraphEdit.get_children():
if c is GraphNode: if c is GraphNode:
c.generated = false c.generated = false
c.generated_variants = []
var shader_code = $GraphEdit/Material.get_shader_code("UV") var shader_code = $GraphEdit/Material.get_shader_code("UV")
print("GENERATED SHADER:\n"+shader_code.code)
code += shader_code.code code += shader_code.code
#print(code)
$Preview.material.shader.set_code(code) $Preview.material.shader.set_code(code)

View File

@ -49,7 +49,7 @@ float bricks(vec2 uv, vec2 count, float offset, float mortar, float bevel) {
float slope_y = 1.0/(bevel*count.y); float slope_y = 1.0/(bevel*count.y);
float f3 = fract_y*slope_y-off; float f3 = fract_y*slope_y-off;
float f4 = (1.0-fract_y)*slope_y-off; float f4 = (1.0-fract_y)*slope_y-off;
return min(min(f1, f2), min(f3, f4)); return max(0.0, min(1.0, min(min(f1, f2), min(f3, f4))));
} }
float colored_bricks(vec2 uv, vec2 count, float offset) { float colored_bricks(vec2 uv, vec2 count, float offset) {
@ -100,11 +100,12 @@ float perlin(vec2 uv, int iterations, float turbulence) {
return f/m; return f/m;
} }
float Sine_f(vec2 uv) { return sine(uv, 1, 1); } float Bricks_f(vec2 uv) { return bricks(uv, vec2(4, 8), 0.5, 0.1, 0.1); }
void fragment() { void fragment() {
float Bricks_0_f = Bricks_f(UV);
float Material_f = Sine_f(UV); vec3 Colorize_rgb = mix(vec3(0.882813,0.134491,0.134491), vec3(0.882813,0.446795,0.062073), Bricks_0_f);
COLOR = vec4(Material_f, Material_f, Material_f, 1.0); vec3 Material_rgb = Colorize_rgb;
COLOR = vec4(Material_rgb, 1.0);
} }
" "
_sections_unfolded = [ "Resource" ] _sections_unfolded = [ "Resource" ]
@ -159,7 +160,7 @@ margin_left = 0.0
margin_top = 0.0 margin_top = 0.0
margin_right = 84.0 margin_right = 84.0
margin_bottom = 43.0 margin_bottom = 43.0
_sections_unfolded = [ "Anchor", "Margin", "Mouse", "slot" ] _sections_unfolded = [ "Anchor", "Margin", "Mouse", "Theme", "slot" ]
[node name="PopupMenu" type="PopupMenu" parent="GraphEdit" index="1"] [node name="PopupMenu" type="PopupMenu" parent="GraphEdit" index="1"]
@ -180,7 +181,7 @@ mouse_default_cursor_shape = 0
size_flags_horizontal = 1 size_flags_horizontal = 1
size_flags_vertical = 1 size_flags_vertical = 1
popup_exclusive = false popup_exclusive = false
items = [ "Material", null, 0, false, false, 0, 0, null, "", false, "Sine", null, 0, false, false, 1, 0, null, "", false, "Boolean", null, 0, false, false, 2, 0, null, "", false, "Bricks", null, 0, false, false, 3, 0, null, "", false, "IQ Noise", null, 0, false, false, 4, 0, null, "", false, "Perlin noise", null, 0, false, false, 5, 0, null, "", false, "Transform", null, 0, false, false, 6, 0, null, "", false ] items = [ "Load texture", null, 0, false, false, 0, 0, null, "", false, "Save texture", null, 0, false, false, 1, 0, null, "", false, "Sine", null, 0, false, false, 2, 0, null, "", false, "Bricks", null, 0, false, false, 3, 0, null, "", false, "IQ Noise", null, 0, false, false, 4, 0, null, "", false, "Perlin noise", null, 0, false, false, 5, 0, null, "", false, "Boolean", null, 0, false, false, 6, 0, null, "", false, "Transform", null, 0, false, false, 7, 0, null, "", false, "Colorize", null, 0, false, false, 8, 0, null, "", false, "Blend", null, 0, false, false, 9, 0, null, "", false ]
hide_on_state_item_selection = false hide_on_state_item_selection = false
_sections_unfolded = [ "Rect" ] _sections_unfolded = [ "Rect" ]

View File

@ -41,7 +41,7 @@ float bricks(vec2 uv, vec2 count, float offset, float mortar, float bevel) {
float slope_y = 1.0/(bevel*count.y); float slope_y = 1.0/(bevel*count.y);
float f3 = fract_y*slope_y-off; float f3 = fract_y*slope_y-off;
float f4 = (1.0-fract_y)*slope_y-off; float f4 = (1.0-fract_y)*slope_y-off;
return min(min(f1, f2), min(f3, f4)); return max(0.0, min(1.0, min(min(f1, f2), min(f3, f4))));
} }
float colored_bricks(vec2 uv, vec2 count, float offset) { float colored_bricks(vec2 uv, vec2 count, float offset) {

View File

@ -6,6 +6,7 @@ var sharpness = 1.0
func _ready(): func _ready():
set_slot(0, false, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1)) set_slot(0, false, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
initialize_properties([ $waves, $sharpness ])
func get_shader_code(uv): func get_shader_code(uv):
var rv = { defs="", code="", rgb=null, f=null } var rv = { defs="", code="", rgb=null, f=null }
@ -22,3 +23,6 @@ func _on_Count_text_changed(new_text):
func _on_Sharpness_text_changed(new_text): func _on_Sharpness_text_changed(new_text):
sharpness = float(new_text) sharpness = float(new_text)
get_parent().get_parent().generate_shader() get_parent().get_parent().generate_shader()
func _get_state_variables():
return [ "waves", "sharpness" ]

View File

@ -43,7 +43,7 @@ slot/1/right_color = Color( 1, 1, 1, 1 )
script = ExtResource( 1 ) script = ExtResource( 1 )
_sections_unfolded = [ "Theme" ] _sections_unfolded = [ "Theme" ]
[node name="Count" type="LineEdit" parent="." index="0"] [node name="waves" type="LineEdit" parent="." index="0"]
anchor_left = 0.0 anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
@ -69,7 +69,7 @@ caret_blink_speed = 0.65
caret_position = 0 caret_position = 0
_sections_unfolded = [ "Caret", "Placeholder" ] _sections_unfolded = [ "Caret", "Placeholder" ]
[node name="Sharpness" type="LineEdit" parent="." index="1"] [node name="sharpness" type="LineEdit" parent="." index="1"]
anchor_left = 0.0 anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
@ -97,8 +97,8 @@ _sections_unfolded = [ "Caret", "Placeholder" ]
[connection signal="close_request" from="." to="." method="queue_free"] [connection signal="close_request" from="." to="." method="queue_free"]
[connection signal="text_changed" from="Count" to="." method="_on_Count_text_changed"] [connection signal="text_changed" from="waves" to="." method="_on_Count_text_changed"]
[connection signal="text_changed" from="Sharpness" to="." method="_on_Sharpness_text_changed"] [connection signal="text_changed" from="sharpness" to="." method="_on_Sharpness_text_changed"]

View File

@ -5,9 +5,10 @@ var angle = 0.0
func _ready(): func _ready():
set_slot(0, true, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1)) set_slot(0, true, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
initialize_properties([ $rotate ])
func get_shader_code(uv): func get_shader_code(uv):
var rv = { defs="", code="", uv=null, rgb=null, f=null } var rv = { defs="", code="", uv=null }
var src = get_source() var src = get_source()
if src == null: if src == null:
return rv return rv
@ -15,9 +16,12 @@ func get_shader_code(uv):
var src_code = src.get_shader_code(rv.uv) var src_code = src.get_shader_code(rv.uv)
if !generated: if !generated:
rv.defs = src_code.defs+"vec2 "+name+"_uv(vec2 uv) { return rotate(uv, "+str(angle)+"); }\n" rv.defs = src_code.defs+"vec2 "+name+"_uv(vec2 uv) { return rotate(uv, "+str(angle)+"); }\n"
rv.code = src_code.code;
generated = true generated = true
rv.f = src_code.f if src_code.has("f"):
rv.rgb = src_code.rgb rv.f = src_code.f
if src_code.has("rgb"):
rv.rgb = src_code.rgb
return rv return rv
func _on_Rotate_text_changed(new_text): func _on_Rotate_text_changed(new_text):

View File

@ -29,7 +29,7 @@ resizable = false
selected = false selected = false
comment = false comment = false
overlay = 0 overlay = 0
slot/0/left_enabled = false slot/0/left_enabled = true
slot/0/left_type = 0 slot/0/left_type = 0
slot/0/left_color = Color( 0.5, 0.5, 1, 1 ) slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
slot/0/right_enabled = true slot/0/right_enabled = true
@ -38,7 +38,7 @@ slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
script = ExtResource( 1 ) script = ExtResource( 1 )
_sections_unfolded = [ "Theme" ] _sections_unfolded = [ "Theme" ]
[node name="Rotate" type="LineEdit" parent="." index="0"] [node name="rotate" type="LineEdit" parent="." index="0"]
anchor_left = 0.0 anchor_left = 0.0
anchor_top = 0.0 anchor_top = 0.0
@ -66,6 +66,6 @@ _sections_unfolded = [ "Caret", "Placeholder" ]
[connection signal="close_request" from="." to="." method="queue_free"] [connection signal="close_request" from="." to="." method="queue_free"]
[connection signal="text_changed" from="Rotate" to="." method="_on_Rotate_text_changed"] [connection signal="text_changed" from="rotate" to="." method="_on_Rotate_text_changed"]

View File

@ -1,5 +1,101 @@
[gd_resource type="Environment" load_steps=2 format=2] [gd_resource type="Environment" load_steps=2 format=2]
[sub_resource type="ProceduralSky" id=1] [sub_resource type="ProceduralSky" id=1]
radiance_size = 4
sky_top_color = Color( 0.0470588, 0.454902, 0.976471, 1 )
sky_horizon_color = Color( 0.556863, 0.823529, 0.909804, 1 )
sky_curve = 0.25
sky_energy = 1.0
ground_bottom_color = Color( 0.101961, 0.145098, 0.188235, 1 )
ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 )
ground_curve = 0.01
ground_energy = 1.0
sun_color = Color( 1, 1, 1, 1 )
sun_latitude = 35.0
sun_longitude = 0.0
sun_angle_min = 1.0
sun_angle_max = 100.0
sun_curve = 0.05
sun_energy = 16.0
texture_size = 2
[resource] [resource]
background_mode = 2 background_mode = 2
background_sky = SubResource( 1 ) background_sky = SubResource( 1 )
background_sky_custom_fov = 0.0
background_color = Color( 0, 0, 0, 1 )
background_energy = 1.0
background_canvas_max_layer = 0
ambient_light_color = Color( 0, 0, 0, 1 )
ambient_light_energy = 1.0
ambient_light_sky_contribution = 1.0
fog_enabled = false
fog_color = Color( 0.5, 0.6, 0.7, 1 )
fog_sun_color = Color( 1, 0.9, 0.7, 1 )
fog_sun_amount = 0.0
fog_depth_enabled = true
fog_depth_begin = 10.0
fog_depth_curve = 1.0
fog_transmit_enabled = false
fog_transmit_curve = 1.0
fog_height_enabled = false
fog_height_min = 0.0
fog_height_max = 100.0
fog_height_curve = 1.0
tonemap_mode = 0
tonemap_exposure = 1.0
tonemap_white = 1.0
auto_exposure_enabled = false
auto_exposure_scale = 0.4
auto_exposure_min_luma = 0.05
auto_exposure_max_luma = 8.0
auto_exposure_speed = 0.5
ss_reflections_enabled = false
ss_reflections_max_steps = 64
ss_reflections_fade_in = 0.15
ss_reflections_fade_out = 2.0
ss_reflections_depth_tolerance = 0.2
ss_reflections_roughness = true
ssao_enabled = false
ssao_radius = 1.0
ssao_intensity = 1.0
ssao_radius2 = 0.0
ssao_intensity2 = 1.0
ssao_bias = 0.01
ssao_light_affect = 0.0
ssao_color = Color( 0, 0, 0, 1 )
ssao_quality = 0
ssao_blur = 3
ssao_edge_sharpness = 4.0
dof_blur_far_enabled = false
dof_blur_far_distance = 10.0
dof_blur_far_transition = 5.0
dof_blur_far_amount = 0.1
dof_blur_far_quality = 1
dof_blur_near_enabled = false
dof_blur_near_distance = 2.0
dof_blur_near_transition = 1.0
dof_blur_near_amount = 0.1
dof_blur_near_quality = 1
glow_enabled = false
glow_levels/1 = false
glow_levels/2 = false
glow_levels/3 = true
glow_levels/4 = false
glow_levels/5 = true
glow_levels/6 = false
glow_levels/7 = false
glow_intensity = 0.8
glow_strength = 1.0
glow_bloom = 0.0
glow_blend_mode = 2
glow_hdr_threshold = 1.0
glow_hdr_scale = 2.0
glow_bicubic_upscale = false
adjustment_enabled = false
adjustment_brightness = 1.0
adjustment_contrast = 1.0
adjustment_saturation = 1.0

BIN
examples/bricks.ptex Normal file

Binary file not shown.

View File

@ -11,6 +11,7 @@ config_version=3
[application] [application]
config/name="Procedural textures addon" config/name="Procedural textures addon"
run/main_scene="res://addons/procedural_material/pm_editor.tscn"
config/icon="res://icon.png" config/icon="res://icon.png"
[editor_plugins] [editor_plugins]