mirror of
https://github.com/Relintai/material-maker.git
synced 2024-12-23 21:16:54 +01:00
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:
parent
6c615aeb02
commit
9443940d9a
38
addons/procedural_material/blend.gd
Normal file
38
addons/procedural_material/blend.gd
Normal 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" ]
|
122
addons/procedural_material/blend.tscn
Normal file
122
addons/procedural_material/blend.tscn
Normal 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"]
|
||||
|
||||
|
@ -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
|
@ -12,11 +12,15 @@ func _ready():
|
||||
initialize_properties([ $GridContainer/rows, $GridContainer/columns, $GridContainer/row_offset, $GridContainer/mortar, $GridContainer/bevel ])
|
||||
|
||||
func get_shader_code(uv):
|
||||
var rv = { defs="", code="", rgb=null, f=null }
|
||||
if !generated:
|
||||
rv.defs = "float "+name+"_f(vec2 uv) { return bricks(uv, vec2("+str(rows)+", "+str(columns)+"), "+str(row_offset)+", "+str(mortar)+", "+str(bevel)+"); }\n"
|
||||
generated = true
|
||||
rv.f = name+"_f("+uv+")"
|
||||
var rv = { defs="", code="" }
|
||||
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(max(0.001, bevel))+"); }\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
|
||||
|
||||
func _get_state_variables():
|
||||
|
@ -11,10 +11,9 @@ anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 251.0
|
||||
margin_top = 121.0
|
||||
margin_right = 405.0
|
||||
margin_bottom = 286.0
|
||||
margin_left = 1.0
|
||||
margin_right = 155.0
|
||||
margin_bottom = 165.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
|
29
addons/procedural_material/colorize.gd
Normal file
29
addons/procedural_material/colorize.gd
Normal 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" ]
|
@ -1,20 +1,20 @@
|
||||
[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]
|
||||
|
||||
|
||||
[node name="Boolean" type="GraphNode" index="0"]
|
||||
[node name="Colorize" type="GraphNode" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 329.0
|
||||
margin_top = 117.0
|
||||
margin_right = 462.0
|
||||
margin_bottom = 279.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
|
||||
@ -22,7 +22,7 @@ mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
theme = SubResource( 1 )
|
||||
title = "Boolean"
|
||||
title = "Colorize"
|
||||
offset = Vector2( 0, 0 )
|
||||
show_close = true
|
||||
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_type = 0
|
||||
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_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_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 )
|
||||
_sections_unfolded = [ "Theme" ]
|
||||
|
||||
[node name="OptionButton" type="OptionButton" parent="." index="0"]
|
||||
[node name="color0" type="ColorPickerButton" parent="." index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
@ -62,16 +62,17 @@ mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
action_mode = 0
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "0"
|
||||
flat = false
|
||||
align = 0
|
||||
items = [ ]
|
||||
selected = -1
|
||||
align = 1
|
||||
color = Color( 0, 0, 0, 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_top = 0.0
|
||||
@ -89,14 +90,15 @@ mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
action_mode = 0
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "0"
|
||||
flat = false
|
||||
align = 0
|
||||
items = [ ]
|
||||
selected = -1
|
||||
align = 1
|
||||
color = Color( 1, 1, 1, 1 )
|
||||
edit_alpha = true
|
||||
_sections_unfolded = [ "Caret", "Placeholder" ]
|
||||
|
||||
[connection signal="close_request" from="." to="." method="queue_free"]
|
||||
|
@ -10,7 +10,7 @@ func _ready():
|
||||
initialize_properties([ $GridContainer/subdivide, $GridContainer/u, $GridContainer/v ])
|
||||
|
||||
func get_shader_code(uv):
|
||||
var rv = { defs="", code="", rgb=null, f=null }
|
||||
var rv = { defs="", code="" }
|
||||
if !generated:
|
||||
rv.defs = "float "+name+"_f(vec2 uv) { return iqnoise(uv, "+str(subdivide)+", "+str(u)+", "+str(v)+"); }\n"
|
||||
generated = true
|
||||
|
@ -92,7 +92,7 @@ mouse_filter = 0
|
||||
mouse_default_cursor_shape = 1
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
text = "3"
|
||||
text = "8"
|
||||
focus_mode = 2
|
||||
context_menu_enabled = true
|
||||
placeholder_alpha = 0.6
|
||||
|
@ -14,12 +14,11 @@ func get_shader_code(uv):
|
||||
var src_code = src.get_shader_code("UV")
|
||||
rv.code += src_code.defs
|
||||
rv.code += "void fragment() {\n"
|
||||
rv.code += src_code.code+"\n"
|
||||
if src_code.rgb != null:
|
||||
rv.code += "vec3 "+name+"_rgb = "+src_code.rgb+"\n"
|
||||
rv.code += "COLOR = vec4("+name+"_rgb.r, "+name+"_rgb.g, "+name+"_rgb.b, 1.0);"
|
||||
elif src_code.f != null:
|
||||
rv.code += "float "+name+"_f = "+src_code.f+";\n"
|
||||
rv.code += "COLOR = vec4("+name+"_f, "+name+"_f, "+name+"_f, 1.0);"
|
||||
rv.code += "\n}\n"
|
||||
rv.code += src_code.code
|
||||
rv.code += "vec3 "+name+"_rgb = "+get_source_rgb(src_code)+";\n"
|
||||
rv.code += "COLOR = vec4("+name+"_rgb, 1.0);\n"
|
||||
rv.code += "}\n"
|
||||
return rv
|
||||
|
||||
func _get_state_variables():
|
||||
return [ ]
|
||||
|
@ -2,20 +2,38 @@ tool
|
||||
extends GraphNode
|
||||
|
||||
var generated = false
|
||||
var generated_variants = []
|
||||
|
||||
var property_widgets = []
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
print("ready: "+name)
|
||||
|
||||
func initialize_properties(object_list):
|
||||
property_widgets = object_list
|
||||
for o in object_list:
|
||||
if o is LineEdit:
|
||||
set(o.name, float(o.text))
|
||||
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):
|
||||
set(variable, float(new_text))
|
||||
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):
|
||||
for c in get_parent().get_children():
|
||||
if c != self && c is GraphNode:
|
||||
@ -23,6 +41,43 @@ func get_source(index = 0):
|
||||
return c
|
||||
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():
|
||||
get_parent().remove_node(self.name)
|
||||
.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()
|
||||
|
@ -9,7 +9,7 @@ func _ready():
|
||||
initialize_properties([ $GridContainer/iterations, $GridContainer/turbulence ])
|
||||
|
||||
func get_shader_code(uv):
|
||||
var rv = { defs="", code="", rgb=null, f=null }
|
||||
var rv = { defs="", code="" }
|
||||
if !generated:
|
||||
rv.defs = "float "+name+"_f(vec2 uv) { return perlin(uv, "+str(iterations)+", "+str(turbulence)+"); }\n"
|
||||
generated = true
|
||||
|
@ -4,12 +4,16 @@ extends Container
|
||||
var popup_position = Vector2(0, 0)
|
||||
|
||||
const MENU = [
|
||||
{ command="load_texture", description="Load texture" },
|
||||
{ command="save_texture", description="Save texture" },
|
||||
{ name="sine", description="Sine" },
|
||||
{ name="boolean", description="Boolean" },
|
||||
{ name="bricks", description="Bricks" },
|
||||
{ name="iqnoise", description="IQ 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():
|
||||
@ -24,11 +28,14 @@ func _on_GraphEdit_popup_request(position):
|
||||
|
||||
func _on_PopupMenu_id_pressed(id):
|
||||
var node_type = null
|
||||
node_type = load("res://addons/procedural_material/"+MENU[id].name+".tscn")
|
||||
if node_type != null:
|
||||
var node = node_type.instance()
|
||||
$GraphEdit.add_child(node)
|
||||
node.set_begin(popup_position)
|
||||
if MENU[id].has("command"):
|
||||
call(MENU[id].command)
|
||||
elif MENU[id].has("name"):
|
||||
node_type = load("res://addons/procedural_material/"+MENU[id].name+".tscn")
|
||||
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):
|
||||
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)
|
||||
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():
|
||||
var code = ""
|
||||
var file = File.new()
|
||||
@ -47,8 +105,9 @@ func generate_shader():
|
||||
for c in $GraphEdit.get_children():
|
||||
if c is GraphNode:
|
||||
c.generated = false
|
||||
c.generated_variants = []
|
||||
var shader_code = $GraphEdit/Material.get_shader_code("UV")
|
||||
print("GENERATED SHADER:\n"+shader_code.code)
|
||||
code += shader_code.code
|
||||
#print(code)
|
||||
$Preview.material.shader.set_code(code)
|
||||
|
||||
|
@ -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 f3 = 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) {
|
||||
@ -100,11 +100,12 @@ float perlin(vec2 uv, int iterations, float turbulence) {
|
||||
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() {
|
||||
|
||||
float Material_f = Sine_f(UV);
|
||||
COLOR = vec4(Material_f, Material_f, Material_f, 1.0);
|
||||
float Bricks_0_f = Bricks_f(UV);
|
||||
vec3 Colorize_rgb = mix(vec3(0.882813,0.134491,0.134491), vec3(0.882813,0.446795,0.062073), Bricks_0_f);
|
||||
vec3 Material_rgb = Colorize_rgb;
|
||||
COLOR = vec4(Material_rgb, 1.0);
|
||||
}
|
||||
"
|
||||
_sections_unfolded = [ "Resource" ]
|
||||
@ -159,7 +160,7 @@ margin_left = 0.0
|
||||
margin_top = 0.0
|
||||
margin_right = 84.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"]
|
||||
|
||||
@ -180,7 +181,7 @@ mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
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
|
||||
_sections_unfolded = [ "Rect" ]
|
||||
|
||||
|
@ -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 f3 = 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) {
|
||||
|
@ -6,6 +6,7 @@ var sharpness = 1.0
|
||||
|
||||
func _ready():
|
||||
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):
|
||||
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):
|
||||
sharpness = float(new_text)
|
||||
get_parent().get_parent().generate_shader()
|
||||
|
||||
func _get_state_variables():
|
||||
return [ "waves", "sharpness" ]
|
||||
|
@ -43,7 +43,7 @@ slot/1/right_color = Color( 1, 1, 1, 1 )
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Theme" ]
|
||||
|
||||
[node name="Count" type="LineEdit" parent="." index="0"]
|
||||
[node name="waves" type="LineEdit" parent="." index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
@ -69,7 +69,7 @@ caret_blink_speed = 0.65
|
||||
caret_position = 0
|
||||
_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_top = 0.0
|
||||
@ -97,8 +97,8 @@ _sections_unfolded = [ "Caret", "Placeholder" ]
|
||||
|
||||
[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"]
|
||||
|
||||
|
||||
|
@ -5,9 +5,10 @@ var angle = 0.0
|
||||
|
||||
func _ready():
|
||||
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):
|
||||
var rv = { defs="", code="", uv=null, rgb=null, f=null }
|
||||
var rv = { defs="", code="", uv=null }
|
||||
var src = get_source()
|
||||
if src == null:
|
||||
return rv
|
||||
@ -15,9 +16,12 @@ func get_shader_code(uv):
|
||||
var src_code = src.get_shader_code(rv.uv)
|
||||
if !generated:
|
||||
rv.defs = src_code.defs+"vec2 "+name+"_uv(vec2 uv) { return rotate(uv, "+str(angle)+"); }\n"
|
||||
rv.code = src_code.code;
|
||||
generated = true
|
||||
rv.f = src_code.f
|
||||
rv.rgb = src_code.rgb
|
||||
if src_code.has("f"):
|
||||
rv.f = src_code.f
|
||||
if src_code.has("rgb"):
|
||||
rv.rgb = src_code.rgb
|
||||
return rv
|
||||
|
||||
func _on_Rotate_text_changed(new_text):
|
||||
|
@ -29,7 +29,7 @@ resizable = false
|
||||
selected = false
|
||||
comment = false
|
||||
overlay = 0
|
||||
slot/0/left_enabled = false
|
||||
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
|
||||
@ -38,7 +38,7 @@ slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Theme" ]
|
||||
|
||||
[node name="Rotate" type="LineEdit" parent="." index="0"]
|
||||
[node name="rotate" type="LineEdit" parent="." index="0"]
|
||||
|
||||
anchor_left = 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="text_changed" from="Rotate" to="." method="_on_Rotate_text_changed"]
|
||||
[connection signal="text_changed" from="rotate" to="." method="_on_Rotate_text_changed"]
|
||||
|
||||
|
||||
|
@ -1,5 +1,101 @@
|
||||
[gd_resource type="Environment" load_steps=2 format=2]
|
||||
|
||||
[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]
|
||||
|
||||
background_mode = 2
|
||||
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
BIN
examples/bricks.ptex
Normal file
Binary file not shown.
@ -11,6 +11,7 @@ config_version=3
|
||||
[application]
|
||||
|
||||
config/name="Procedural textures addon"
|
||||
run/main_scene="res://addons/procedural_material/pm_editor.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[editor_plugins]
|
||||
|
Loading…
Reference in New Issue
Block a user