More refactoring on rtexture generation

This commit is contained in:
Rodolphe Suescun 2019-08-17 17:35:48 +02:00
parent b614ab50ed
commit e9a21454c1
19 changed files with 533 additions and 262 deletions

View File

@ -9,7 +9,7 @@ class OutputPort:
func _init(g : MMGenBase, o : int): func _init(g : MMGenBase, o : int):
generator = g generator = g
output_index = o output_index = o
"""
func get_shader(): func get_shader():
return generator.get_shader(output_index) return generator.get_shader(output_index)
@ -18,19 +18,43 @@ class OutputPort:
func get_globals(): func get_globals():
return generator.get_globals() return generator.get_globals()
"""
func to_str(): func to_str():
return generator.name+"("+str(output_index)+")" return generator.name+"("+str(output_index)+")"
var position : Vector2 = Vector2(0, 0) var position : Vector2 = Vector2(0, 0)
var parameters = {} var parameters = {}
func _ready():
init_parameters()
func init_parameters():
for p in get_parameter_defs():
print(p)
if !parameters.has(p.name):
if p.has("default"):
parameters[p.name] = MMType.deserialize_value(p.default)
else:
print("No default value for parameter "+p.name)
func get_seed(): func get_seed():
return 0 return 0
func get_type(): func get_type():
return "generic" return "generic"
func get_type_name():
return "Unnamed"
func get_parameter_defs():
return []
func get_input_defs():
return []
func get_output_defs():
return []
func get_source(input_index : int): func get_source(input_index : int):
return get_parent().get_port_source(name, input_index) return get_parent().get_port_source(name, input_index)
@ -39,7 +63,7 @@ func get_input_shader(input_index : int):
if source != null: if source != null:
return source.get_shader() return source.get_shader()
func get_shader(output_index : int, context = MMGenContext.new()): func get_shader(output_index : int, context):
return get_shader_code("UV", output_index, context); return get_shader_code("UV", output_index, context);
# this will need an output index for switch # this will need an output index for switch
@ -48,14 +72,25 @@ func get_globals():
for i in range(10): for i in range(10):
var source = get_source(i) var source = get_source(i)
if source != null: if source != null:
var source_list = source.get_globals() var source_list = source.generator.get_globals()
for g in source_list: for g in source_list:
if list.find(g) == -1: if list.find(g) == -1:
list.append(g) list.append(g)
return list return list
func get_shader_code(uv, slot = 0, context = MMGenContext.new()): func render(output_index : int, renderer : MMGenRenderer, size : int):
var rv = _get_shader_code(uv, slot, context) var context : MMGenContext = MMGenContext.new(renderer)
var source = get_shader_code("UV", output_index, context)
if source == null:
return false
var shader : String = renderer.generate_shader(source)
var status = renderer.render_shader(shader, {}, 1024)
while status is GDScriptFunctionState:
status = yield(status, "completed")
return status
func get_shader_code(uv : String, output_index : int, context : MMGenContext):
var rv = _get_shader_code(uv, output_index, context)
if rv != null: if rv != null:
if !rv.has("f"): if !rv.has("f"):
if rv.has("rgb"): if rv.has("rgb"):
@ -74,5 +109,5 @@ func get_shader_code(uv, slot = 0, context = MMGenContext.new()):
rv.globals = get_globals() rv.globals = get_globals()
return rv return rv
func _get_shader_code(uv : String, output_index : int, context = MMGenContext.new()): func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
return null return null

View File

@ -1,2 +1,22 @@
tool
extends MMGenBase extends MMGenBase
class_name MMGenBuffer class_name MMGenBuffer
func _ready():
if !parameters.has("size"):
parameters.size = 4
func get_type():
return "buffer"
func get_type_name():
return "Buffer"
func get_parameter_defs():
return [ { name="size", type="size", first=4, last=11, default=4 } ]
func get_input_defs():
return [ ]
func get_output_defs():
return [ ]

View File

@ -1,8 +1,13 @@
tool
extends Object extends Object
class_name MMGenContext class_name MMGenContext
var renderer : MMGenRenderer
var variants : Dictionary = {} var variants : Dictionary = {}
func _init(r : MMGenRenderer):
renderer = r
func has_variant(generator): func has_variant(generator):
return variants.has(generator) return variants.has(generator)

View File

@ -1,2 +1,3 @@
tool
extends MMGenBase extends MMGenBase
class_name MMGenConvolution class_name MMGenConvolution

View File

@ -4,10 +4,15 @@ class_name MMGenGraph
var connections = [] var connections = []
func get_type():
return "graph"
func get_port_source(gen_name: String, input_index: int) -> OutputPort: func get_port_source(gen_name: String, input_index: int) -> OutputPort:
for c in connections: for c in connections:
if c.to == gen_name and c.to_port == input_index: if c.to == gen_name and c.to_port == input_index:
return OutputPort.new(get_node(c.from), c.from_port) var src_gen = get_node(c.from)
if src_gen != null:
return OutputPort.new(get_node(c.from), c.from_port)
return null return null
func connect_children(from, from_port : int, to, to_port : int): func connect_children(from, from_port : int, to, to_port : int):

View File

@ -43,6 +43,7 @@ func generate_material(renderer : MMGenRenderer):
var status = renderer.render_shader(shader, {}, 512) var status = renderer.render_shader(shader, {}, 512)
while status is GDScriptFunctionState: while status is GDScriptFunctionState:
status = yield(status, "completed") status = yield(status, "completed")
print("Render status: "+str(status))
renderer.get_texture().get_data().save_png("res://test.png") renderer.get_texture().get_data().save_png("res://test.png")
material.albedo_texture = load("res://test.png") material.albedo_texture = load("res://test.png")
return material return material

View File

@ -2,21 +2,26 @@ tool
extends MMGenBase extends MMGenBase
class_name MMGenShader class_name MMGenShader
var model_data = null var shader_model : Dictionary = {}
var generated_variants = [] var generated_variants = []
func set_model_data(data: Dictionary): func get_type():
model_data = data return "shader"
for p in model_data.parameters:
if !parameters.has(p.name) and p.has("default"):
parameters[p.name] = MMType.deserialize_value(p.default)
func initialize(data: Dictionary): func get_type_name():
if data.has("name"): if shader_model.has("name"):
name = data.name return shader_model.name
if data.has("parameters"): return .get_type_name()
for p in data.parameters.keys():
parameters[p] = data.parameters[p] func get_parameter_defs():
if shader_model == null or !shader_model.has("parameters"):
return []
else:
return shader_model.parameters
func set_shader_model(data: Dictionary):
shader_model = data
init_parameters()
func find_keyword_call(string, keyword): func find_keyword_call(string, keyword):
var search_string = "$%s(" % keyword var search_string = "$%s(" % keyword
@ -49,7 +54,8 @@ func replace_input(string, context, input, type, src, default):
if src == null: if src == null:
src_code = subst(default, "(%s)" % uv) src_code = subst(default, "(%s)" % uv)
else: else:
src_code = src.get_shader_code(uv) print(src.to_str())
src_code = src.generator.get_shader_code(uv, src.output_index, context)
src_code.string = src_code[type] src_code.string = src_code[type]
required_defs += src_code.defs required_defs += src_code.defs
required_code += src_code.code required_code += src_code.code
@ -84,8 +90,8 @@ func subst(string, context, uv = ""):
string = replace_variable(string, "seed", str(get_seed())) string = replace_variable(string, "seed", str(get_seed()))
if uv != "": if uv != "":
string = replace_variable(string, "uv", "("+uv+")") string = replace_variable(string, "uv", "("+uv+")")
if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY: if shader_model.has("parameters") and typeof(shader_model.parameters) == TYPE_ARRAY:
for p in model_data.parameters: for p in shader_model.parameters:
if !p.has("name") or !p.has("type"): if !p.has("name") or !p.has("type"):
continue continue
var value = parameters[p.name] var value = parameters[p.name]
@ -102,9 +108,9 @@ func subst(string, context, uv = ""):
value_string = p.name+"_gradient_fct" value_string = p.name+"_gradient_fct"
if value_string != null: if value_string != null:
string = replace_variable(string, p.name, value_string) string = replace_variable(string, p.name, value_string)
if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY: if shader_model.has("inputs") and typeof(shader_model.inputs) == TYPE_ARRAY:
for i in range(model_data.inputs.size()): for i in range(shader_model.inputs.size()):
var input = model_data.inputs[i] var input = shader_model.inputs[i]
var source = get_source(i) var source = get_source(i)
var result = replace_input(string, context, input.name, input.type, source, input.default) var result = replace_input(string, context, input.name, input.type, source, input.default)
string = result.string string = result.string
@ -112,18 +118,16 @@ func subst(string, context, uv = ""):
required_code += result.code required_code += result.code
return { string=string, defs=required_defs, code=required_code } return { string=string, defs=required_defs, code=required_code }
func _get_shader_code(uv, slot = 0, context = MMGenContext.new()): func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
if context == null:
context = {}
var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ] var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ]
var rv = { defs="", code="" } var rv = { defs="", code="" }
var variant_string = uv+","+str(slot) var variant_string = uv+","+str(output_index)
if model_data != null and model_data.has("outputs") and model_data.outputs.size() > slot: if shader_model != null and shader_model.has("outputs") and shader_model.outputs.size() > output_index:
var output = model_data.outputs[slot] var output = shader_model.outputs[output_index]
rv.defs = "" rv.defs = ""
if model_data.has("instance") && !context.has_variant(self): if shader_model.has("instance") && !context.has_variant(self):
rv.defs += subst(model_data.instance, context).string rv.defs += subst(shader_model.instance, context).string
for p in model_data.parameters: for p in shader_model.parameters:
if p.type == "gradient": if p.type == "gradient":
var g = parameters[p.name] var g = parameters[p.name]
if !(g is MMGradient): if !(g is MMGradient):
@ -139,14 +143,14 @@ func _get_shader_code(uv, slot = 0, context = MMGenContext.new()):
var subst_output = subst(output[t.field], context, uv) var subst_output = subst(output[t.field], context, uv)
rv.defs += subst_output.defs rv.defs += subst_output.defs
rv.code += subst_output.code rv.code += subst_output.code
rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, slot, variant_index, t.field, subst_output.string ] rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, output_index, variant_index, t.field, subst_output.string ]
for t in output_info: for t in output_info:
if output.has(t.field): if output.has(t.field):
rv[t.field] = "%s_%d_%d_%s" % [ name, slot, variant_index, t.field ] rv[t.field] = "%s_%d_%d_%s" % [ name, output_index, variant_index, t.field ]
return rv return rv
func get_globals(): func get_globals():
var list = .get_globals() var list = .get_globals()
if typeof(model_data) == TYPE_DICTIONARY and model_data.has("global") and list.find(model_data.global) == -1: if typeof(shader_model) == TYPE_DICTIONARY and shader_model.has("global") and list.find(shader_model.global) == -1:
list.append(model_data.global) list.append(shader_model.global)
return list return list

View File

@ -32,28 +32,29 @@ func create_gen(data) -> MMGenBase:
if data.has("connections") and data.has("nodes"): if data.has("connections") and data.has("nodes"):
generator = MMGenGraph.new() generator = MMGenGraph.new()
add_to_gen_graph(generator, data.nodes, data.connections) add_to_gen_graph(generator, data.nodes, data.connections)
elif data.has("model_data"): elif data.has("shader_model"):
generator = MMGenShader.new() generator = MMGenShader.new()
generator.set_model_data(data.model_data) generator.set_shader_model(data.shader_model)
elif data.has("type"): elif data.has("type"):
if data.type == "material": if data.type == "material":
generator = MMGenMaterial.new() generator = MMGenMaterial.new()
elif data.type == "buffer":
generator = MMGenBuffer.new()
else: else:
var file = File.new() var file = File.new()
if file.open("res://addons/material_maker/library/"+data.type+".mml", File.READ) == OK: if file.open("res://addons/material_maker/library/"+data.type+".mml", File.READ) == OK:
var model_data = parse_json(file.get_as_text())
print("loaded description "+data.type+".mml") print("loaded description "+data.type+".mml")
generator = create_gen(model_data) generator = create_gen(parse_json(file.get_as_text()))
file.close() file.close()
elif file.open("res://addons/material_maker/nodes/"+data.type+".mmn", File.READ) == OK: elif file.open("res://addons/material_maker/nodes/"+data.type+".mmn", File.READ) == OK:
generator = MMGenShader.new() generator = MMGenShader.new()
var model_data = parse_json(file.get_as_text())
print("loaded description "+data.type+".mmn") print("loaded description "+data.type+".mmn")
generator.set_model_data(model_data) generator.set_shader_model(parse_json(file.get_as_text()))
file.close() file.close()
else: else:
print("Cannot find description for "+data.type) print("Cannot find description for "+data.type)
generator.name = data.type if generator != null:
generator.name = data.type
else: else:
print(data) print(data)
if generator != null: if generator != null:
@ -63,5 +64,6 @@ func create_gen(data) -> MMGenBase:
generator.position.x = data.node_position.x generator.position.x = data.node_position.x
generator.position.y = data.node_position.y generator.position.y = data.node_position.y
if data.has("parameters"): if data.has("parameters"):
generator.initialize(data) for p in data.parameters.keys():
generator.parameters[p] = data.parameters[p]
return generator return generator

View File

@ -68,6 +68,7 @@ func setup_material(shader_material, textures, shader_code):
func render_shader(shader, textures, render_size): func render_shader(shader, textures, render_size):
if rendering: if rendering:
print("Already rendering...")
return false return false
rendering = true rendering = true
if debug_path != null and debug_path != "": if debug_path != null and debug_path != "":

View File

@ -128,7 +128,7 @@ func get_free_name(type):
return node_name return node_name
i += 1 i += 1
func create_nodes(data, position = null): func create_nodes(data, position : Vector2 = Vector2(0, 0)):
if data == null: if data == null:
return return
if data.has("type"): if data.has("type"):
@ -136,6 +136,8 @@ func create_nodes(data, position = null):
if typeof(data.nodes) == TYPE_ARRAY and typeof(data.connections) == TYPE_ARRAY: if typeof(data.nodes) == TYPE_ARRAY and typeof(data.connections) == TYPE_ARRAY:
var loader = MMGenLoader.new() var loader = MMGenLoader.new()
var new_stuff = loader.add_to_gen_graph(generator, data.nodes, data.connections) var new_stuff = loader.add_to_gen_graph(generator, data.nodes, data.connections)
for g in new_stuff.generators:
g.position += position
update_graph(new_stuff.generators, new_stuff.connections) update_graph(new_stuff.generators, new_stuff.connections)
func load_file(filename): func load_file(filename):

View File

@ -28,124 +28,156 @@
"tree_item":"Generators/Pattern", "tree_item":"Generators/Pattern",
"icon":"pattern", "icon":"pattern",
"type":"pattern", "type":"pattern",
"mix":0, "parameters":{
"x_scale":4, "mix":0,
"x_wave":0, "x_scale":4,
"y_scale":4, "x_wave":0,
"y_wave":0 "y_scale":4,
"y_wave":0
}
}, },
{ {
"tree_item": "Generators/Pattern/Checkerboard", "tree_item": "Generators/Pattern/Checkerboard",
"type": "pattern", "type": "pattern",
"icon": "checkerboard", "icon": "checkerboard",
"mix": 4, "parameters":{
"x_scale": 4, "mix": 4,
"x_wave": 2, "x_scale": 4,
"y_scale": 4, "x_wave": 2,
"y_wave": 2 "y_scale": 4,
"y_wave": 2
}
}, },
{ {
"tree_item":"Generators/Bricks", "tree_item":"Generators/Bricks",
"type":"bricks", "type":"bricks",
"icon":"bricks", "icon":"bricks",
"bevel":0.1, "parameters":{
"columns":3, "bevel":0.1,
"mortar":0.1, "columns":3,
"row_offset":0.5, "mortar":0.1,
"rows":6 "row_offset":0.5,
"rows":6
}
}, },
{ {
"tree_item": "Generators/Bricks/Tiles", "tree_item": "Generators/Bricks/Tiles",
"type": "bricks", "type": "bricks",
"icon": "tiles", "icon": "tiles",
"bevel": 0.05, "parameters":{
"columns": 4, "bevel": 0.05,
"mortar": 0.05, "columns": 4,
"row_offset": 0, "mortar": 0.05,
"rows": 4 "row_offset": 0,
"rows": 4
}
},
{
"tree_item": "Generators/Bricks/BasketWeave",
"type": "bricks",
"icon": "basketweave",
"parameters":{
"bevel": 0.05,
"columns": 2,
"mortar": 0.05,
"pattern": 3,
"repeat": 2,
"row_offset": 0,
"rows": 2
}
}, },
{ {
"tree_item": "Generators/Bricks/BasketWeave", "tree_item": "Generators/Bricks/HerringBone",
"type": "bricks", "type": "bricks",
"icon": "basketweave", "icon": "herringbone",
"bevel": 0.05, "parameters":{
"columns": 2, "bevel": 0.05,
"mortar": 0.05, "columns": 2,
"pattern": 3, "mortar": 0.05,
"repeat": 2, "pattern": 2,
"row_offset": 0, "repeat": 2,
"rows": 2 "row_offset": 0,
"rows": 2
}
}, },
{ {
"tree_item": "Generators/Bricks/HerringBone", "tree_item": "Generators/Bricks/SpanishBond",
"type": "bricks", "type": "bricks",
"icon": "herringbone", "icon": "spanishbond",
"bevel": 0.05, "parameters":{
"columns": 2, "bevel": 0.05,
"mortar": 0.05, "columns": 2,
"pattern": 2, "mortar": 0.05,
"repeat": 2, "pattern": 4,
"row_offset": 0, "repeat": 2,
"rows": 2 "row_offset": 0,
}, "rows": 2
{ }
"tree_item": "Generators/Bricks/SpanishBond",
"type": "bricks",
"icon": "spanishbond",
"bevel": 0.05,
"columns": 2,
"mortar": 0.05,
"pattern": 4,
"repeat": 2,
"row_offset": 0,
"rows": 2
}, },
{ {
"tree_item":"Generators/Noise", "tree_item":"Generators/Noise",
"type":"noise", "type":"noise",
"icon":"noise", "icon":"noise",
"size":4, "parameters":{
"density":0.5 "size":4,
"density":0.5
}
}, },
{ {
"tree_item":"Generators/Perlin Noise", "tree_item":"Generators/Perlin Noise",
"type":"perlin", "type":"perlin",
"icon":"perlin", "icon":"perlin",
"iterations":3, "parameters":{
"persistence":0.5, "iterations":3,
"scale_x":4, "persistence":0.5,
"scale_y":4 "scale_x":4,
"scale_y":4
}
}, },
{ {
"tree_item":"Generators/Voronoi Noise", "tree_item":"Generators/Voronoi Noise",
"type":"voronoi", "type":"voronoi",
"icon":"voronoi", "icon":"voronoi",
"intensity":1, "parameters":{
"scale_x":4, "intensity":1,
"scale_y":4 "scale_x":4,
"scale_y":4
}
},
{
"tree_item":"Filters/Buffer",
"type":"buffer"
}, },
{ {
"tree_item":"Filters/AdjustHSV", "tree_item":"Filters/AdjustHSV",
"type":"adjust_hsv", "type":"adjust_hsv",
"hue":0, "parameters":{
"saturation":1, "hue":0,
"value":1 "saturation":1,
"value":1
}
}, },
{ {
"tree_item":"Filters/Colorize", "tree_item":"Filters/Colorize",
"type":"colorize", "type":"colorize",
"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":1,"r":1}] "parameters":{
"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":1,"r":1}]
}
}, },
{ {
"tree_item":"Filters/Blend", "tree_item":"Filters/Blend",
"type":"blend", "type":"blend",
"amount":0.5, "parameters":{
"blend_type":0 "amount":0.5,
"blend_type":0
}
}, },
{ {
"tree_item":"Filters/Blur", "tree_item":"Filters/Blur",
"type":"blur", "type":"blur",
"sigma":1.0 "parameters":{
"sigma":1.0
}
}, },
{ {
"tree_item":"Filters/Combine", "tree_item":"Filters/Combine",
@ -158,45 +190,55 @@
{ {
"tree_item":"Filters/Emboss", "tree_item":"Filters/Emboss",
"type":"emboss", "type":"emboss",
"direction":0 "parameters":{
"direction":0
}
}, },
{ {
"tree_item":"Filters/Normal map", "tree_item":"Filters/Normal map",
"type":"normal_map", "type":"normal_map",
"amount":0.5 "parameters":{
"amount":0.5
}
}, },
{ {
"tree_item":"Filters/Transform", "tree_item":"Filters/Transform",
"type":"transform", "type":"transform",
"rotate":0, "parameters":{
"scale_x":1, "rotate":0,
"scale_y":1, "scale_x":1,
"translate_x":0, "scale_y":1,
"translate_y":0 "translate_x":0,
"translate_y":0
}
}, },
{ {
"tree_item":"Filters/Warp", "tree_item":"Filters/Warp",
"type":"warp", "type":"warp",
"amount":0.5 "parameters":{
"amount":0.5
}
}, },
{ {
"tree_item": "Filters/Colorize/Invert", "tree_item": "Filters/Colorize/Invert",
"type": "colorize", "type": "colorize",
"icon": "invert", "icon": "invert",
"gradient": [ "parameters":{
{ "gradient": [
"b": 1, {
"g": 1, "b": 1,
"pos": 0, "g": 1,
"r": 1 "pos": 0,
}, "r": 1
{ },
"b": 0, {
"g": 0, "b": 0,
"pos": 1, "g": 0,
"r": 0 "pos": 1,
} "r": 0
] }
]
}
}, },
{ {
"tree_item":"Miscellaneous/Comment", "tree_item":"Miscellaneous/Comment",

View File

@ -311,12 +311,10 @@ func update_preview_2d(node = null):
node = n node = n
break break
if node != null: if node != null:
var source = node.generator.get_shader(0) var status = node.generator.render(0, renderer, 1024)
if source != null: while status is GDScriptFunctionState:
var shader : String = renderer.generate_shader(source) status = yield(status, "completed")
var status = renderer.render_shader(shader, {}, 1024) if status:
while status is GDScriptFunctionState:
status = yield(status, "completed")
var image = renderer.get_texture().get_data() var image = renderer.get_texture().get_data()
var tex = ImageTexture.new() var tex = ImageTexture.new()
tex.create_from_image(image) tex.create_from_image(image)

View File

@ -15,4 +15,6 @@ func create_node(type):
var node_type = load("res://addons/material_maker/nodes/"+type+".tscn") var node_type = load("res://addons/material_maker/nodes/"+type+".tscn")
if node_type != null: if node_type != null:
node = node_type.instance() node = node_type.instance()
else:
node = preload("res://addons/material_maker/nodes/generic.tscn").instance()
return node return node

View File

@ -1,7 +1,7 @@
{ {
"name":"Bricks", "name":"Bricks",
"parameters":[ "parameters":[
{ "name":"pattern", "label":"", "type":"enum", "values":[ { "name":"pattern", "label":"", "type":"enum", "default":0, "values":[
{ "name":"Running bond", "value":"rb" }, { "name":"Running bond", "value":"rb" },
{ "name":"Running bond (2)", "value":"rb2" }, { "name":"Running bond (2)", "value":"rb2" },
{ "name":"HerringBone", "value":"hb" }, { "name":"HerringBone", "value":"hb" },

View File

@ -6,16 +6,16 @@ var controls = []
var uses_seed : bool = false var uses_seed : bool = false
var parameters = {}
var model_data = {}
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready(): func _ready():
pass # Replace with function body. pass # Replace with function body.
func set_generator(g): func set_generator(g):
generator = g generator = g
update_node(g.model_data) if g.get("shader_model") != null:
update_node(g.shader_model)
else:
update_node({})
func initialize_properties(): func initialize_properties():
for o in controls: for o in controls:
@ -70,13 +70,9 @@ func _on_gradient_changed(new_gradient, variable):
update_shaders() update_shaders()
func update_node(data): func update_node(data):
print("node_generic.update_node")
if typeof(data) != TYPE_DICTIONARY: if typeof(data) != TYPE_DICTIONARY:
return return
if !data.has("name"):
return
# Clean node # Clean node
parameters = {}
var custom_node_buttons = null var custom_node_buttons = null
for c in get_children(): for c in get_children():
if c.name != "CustomNodeButtons": if c.name != "CustomNodeButtons":
@ -85,71 +81,69 @@ func update_node(data):
else: else:
custom_node_buttons = c custom_node_buttons = c
# Rebuild node # Rebuild node
title = data.name title = generator.get_type_name()
model_data = data
uses_seed = false uses_seed = false
if model_data.has("instance") and model_data.instance.find("$(seed)"): if data.has("instance") and data.instance.find("$(seed)"):
uses_seed = true uses_seed = true
if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY: # Parameters
controls = [] print("Parameters")
var sizer = null controls = []
for p in model_data.parameters: var sizer = null
if !p.has("name") or !p.has("type"): for p in generator.get_parameter_defs():
continue if !p.has("name") or !p.has("type"):
var control = null continue
if p.type == "float": print(p.name)
if p.has("widget") and p.widget == "spinbox": var control = null
control = SpinBox.new() if p.type == "float":
else: if p.has("widget") and p.widget == "spinbox":
control = HSlider.new() control = SpinBox.new()
control.min_value = p.min else:
control.max_value = p.max control = HSlider.new()
control.step = 0 if !p.has("step") else p.step control.min_value = p.min
if p.has("default"): control.max_value = p.max
control.value = p.default control.step = 0 if !p.has("step") else p.step
control.rect_min_size.x = 80 if p.has("default"):
parameters[p.name] = 0.5*(p.min+p.max) control.value = p.default
elif p.type == "size": control.rect_min_size.x = 80
control = OptionButton.new() elif p.type == "size":
for i in range(p.first, p.last+1): control = OptionButton.new()
var s = pow(2, i) for i in range(p.first, p.last+1):
control.add_item("%dx%d" % [ s, s ]) var s = pow(2, i)
control.selected = 0 if !p.has("default") else p.default-p.first control.add_item("%dx%d" % [ s, s ])
elif p.type == "enum": control.selected = 0 if !p.has("default") else p.default-p.first
control = OptionButton.new() elif p.type == "enum":
for i in range(p.values.size()): control = OptionButton.new()
var value = p.values[i] for i in range(p.values.size()):
control.add_item(value.name) var value = p.values[i]
control.selected = 0 if !p.has("default") else p.default control.add_item(value.name)
elif p.type == "boolean": control.selected = 0 if !p.has("default") else p.default
control = CheckBox.new() elif p.type == "boolean":
elif p.type == "color": control = CheckBox.new()
control = ColorPickerButton.new() elif p.type == "color":
elif p.type == "gradient": control = ColorPickerButton.new()
control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance() elif p.type == "gradient":
if control != null: control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance()
var label = p.name if control != null:
control.name = label var label = p.name
controls.append(control) control.name = label
if p.has("label"): controls.append(control)
label = p.label if p.has("label"):
if sizer == null or label != "nonewline": label = p.label
sizer = HBoxContainer.new() if sizer == null or label != "nonewline":
sizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL sizer = HBoxContainer.new()
add_child(sizer) sizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
if label != "" && label != "nonewline": add_child(sizer)
var label_widget = Label.new() if label != "" && label != "nonewline":
label_widget.text = label var label_widget = Label.new()
label_widget.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL label_widget.text = label
sizer.add_child(label_widget) label_widget.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL sizer.add_child(label_widget)
sizer.add_child(control) control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
initialize_properties() sizer.add_child(control)
else: initialize_properties()
model_data.parameters = [] if data.has("inputs") and typeof(data.inputs) == TYPE_ARRAY:
if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY: for i in range(data.inputs.size()):
for i in range(model_data.inputs.size()): var input = data.inputs[i]
var input = model_data.inputs[i]
var enable_left = false var enable_left = false
var color_left = Color(0.5, 0.5, 0.5) var color_left = Color(0.5, 0.5, 0.5)
if typeof(input) == TYPE_DICTIONARY: if typeof(input) == TYPE_DICTIONARY:
@ -162,11 +156,9 @@ func update_node(data):
else: else:
enable_left = true enable_left = true
set_slot(i, enable_left, 0, color_left, false, 0, Color()) set_slot(i, enable_left, 0, color_left, false, 0, Color())
else: if data.has("outputs") and typeof(data.outputs) == TYPE_ARRAY:
model_data.inputs = [] for i in range(data.outputs.size()):
if model_data.has("outputs") and typeof(model_data.outputs) == TYPE_ARRAY: var output = data.outputs[i]
for i in range(model_data.outputs.size()):
var output = model_data.outputs[i]
var enable_right = false var enable_right = false
var color_right = Color(0.5, 0.5, 0.5) var color_right = Color(0.5, 0.5, 0.5)
if typeof(output) == TYPE_DICTIONARY: if typeof(output) == TYPE_DICTIONARY:
@ -179,7 +171,5 @@ func update_node(data):
elif output.has("f"): elif output.has("f"):
enable_right = true enable_right = true
set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right) set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right)
else:
model_data.outputs = []
if custom_node_buttons != null: if custom_node_buttons != null:
move_child(custom_node_buttons, get_child_count()-1) move_child(custom_node_buttons, get_child_count()-1)

View File

@ -51,4 +51,7 @@ func generate_material(ptex_filename: String) -> Material:
var generator = loader.load_gen(ptex_filename) var generator = loader.load_gen(ptex_filename)
add_child(generator) add_child(generator)
var material = generator.get_node("Material") var material = generator.get_node("Material")
return material.generate_material(renderer) var return_value = material.generate_material(renderer)
while return_value is GDScriptFunctionState:
return_value = yield(return_value, "completed")
return return_value

View File

@ -8,9 +8,6 @@ class CustomSorter:
var points = [ { v=0.0, c=Color(0.0, 0.0, 0.0, 0.0) }, { v=1.0, c=Color(1.0, 1.0, 1.0, 1.0) } ] var points = [ { v=0.0, c=Color(0.0, 0.0, 0.0, 0.0) }, { v=1.0, c=Color(1.0, 1.0, 1.0, 1.0) } ]
var sorted = true var sorted = true
func _ready():
pass
func to_string(): func to_string():
var rv = PoolStringArray() var rv = PoolStringArray()
for p in points: for p in points:
@ -39,17 +36,20 @@ func sort():
func get_color(x): func get_color(x):
sort() sort()
if x < points[0].v: if points.size() >0:
return points[0].c if x < points[0].v:
var s = points.size()-1 return points[0].c
for i in range(s): var s = points.size()-1
if x < points[i+1].v: for i in range(s):
var p0 = points[i].v if x < points[i+1].v:
var c0 = points[i].c var p0 = points[i].v
var p1 = points[i+1].v var c0 = points[i].c
var c1 = points[i+1].c var p1 = points[i+1].v
return c0 + (c1-c0) * (x-p0) / (p1-p0) var c1 = points[i+1].c
return points[s].c return c0 + (c1-c0) * (x-p0) / (p1-p0)
return points[s].c
else:
return Color(0.0, 0.0, 0.0, 1.0)
# get_color_in_shader # get_color_in_shader
func gcis(color): func gcis(color):
@ -59,19 +59,22 @@ func get_shader(name):
sort() sort()
var shader var shader
shader = "vec4 "+name+"(float x) {\n" shader = "vec4 "+name+"(float x) {\n"
shader += " if (x < %.9f) {\n" % points[0].v if points.size() > 0:
shader += " return "+gcis(points[0].c)+";\n" shader += " if (x < %.9f) {\n" % points[0].v
var s = points.size()-1 shader += " return "+gcis(points[0].c)+";\n"
for i in range(s): var s = points.size()-1
var p0 = points[i].v for i in range(s):
var c0 = points[i].c var p0 = points[i].v
var p1mp0 = points[i+1].v-p0 var c0 = points[i].c
var c1mc0 = points[i+1].c-c0 var p1mp0 = points[i+1].v-p0
if p1mp0 > 0: var c1mc0 = points[i+1].c-c0
shader += " } else if (x < %.9f) {\n" % points[i+1].v if p1mp0 > 0:
shader += " return %s+x*%s;\n" % [gcis(c0-c1mc0*(p0/p1mp0)), gcis(c1mc0/p1mp0)] shader += " } else if (x < %.9f) {\n" % points[i+1].v
shader += " }\n" shader += " return %s+x*%s;\n" % [gcis(c0-c1mc0*(p0/p1mp0)), gcis(c1mc0/p1mp0)]
shader += " return "+gcis(points[s].c)+";\n" shader += " }\n"
shader += " return "+gcis(points[s].c)+";\n"
else:
shader += " return vec4(0.0, 0.0, 0.0, 1.0);\n"
shader += "}\n" shader += "}\n"
return shader return shader
@ -89,7 +92,7 @@ func deserialize(v):
for i in v: for i in v:
if !i.has("a"): i.a = 1.0 if !i.has("a"): i.a = 1.0
add_point(i.pos, Color(i.r, i.g, i.b, i.a)) add_point(i.pos, Color(i.r, i.g, i.b, i.a))
elif typeof(v) == TYPE_DICTIONARY && v.has("type") && v.type == "Gradient": elif typeof(v) == TYPE_DICTIONARY and v.has("type") && v.type == "Gradient":
for i in v.points: for i in v.points:
if !i.has("a"): i.a = 1.0 if !i.has("a"): i.a = 1.0
add_point(i.pos, Color(i.r, i.g, i.b, i.a)) add_point(i.pos, Color(i.r, i.g, i.b, i.a))

BIN
test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

159
test.ptex
View File

@ -1 +1,158 @@
{"connections":[{"from":"bricks_0","from_port":0,"to":"custom_0","to_port":0},{"from":"custom_0","from_port":0,"to":"adjust_hsv_0","to_port":0},{"from":"adjust_hsv_0","from_port":0,"to":"Material","to_port":0}],"nodes":[{"name":"Material","node_position":{"x":143,"y":-210},"parameters":{"albedo_color":{"a":1,"b":1,"g":1,"r":1,"type":"Color"},"ao_light_affect":1,"depth_scale":1,"emission_energy":1,"metallic":1,"normal_scale":1,"resolution":1,"roughness":1},"type":"material"},{"model_data":{"global":"","inputs":[{"default":"0.0","label":"Input","name":"input","type":"f"}],"instance":"","name":"Colorize","outputs":[{"rgba":"$gradient($input($uv))"}],"parameters":[{"default":{"points":[{"a":1,"b":0,"g":0,"pos":0,"r":0},{"a":1,"b":1,"g":1,"pos":1,"r":1}],"type":"Gradient"},"label":"Gradient","name":"gradient","type":"gradient"}]},"name":"custom_0","node_position":{"x":-433,"y":-109.416656},"parameters":{"gradient":{"points":[{"a":1,"b":0,"g":0,"pos":0,"r":0},{"a":1,"b":0,"g":0,"pos":0.517045,"r":1},{"a":0,"b":1,"g":1,"pos":1,"r":1}],"type":"Gradient"}},"type":"custom"},{"name":"adjust_hsv_0","node_position":{"x":-135.541687,"y":-150.597229},"parameters":{"hue":0,"saturation":1,"value":1},"type":"adjust_hsv"},{"name":"bricks_0","node_position":{"x":-599,"y":-332},"parameters":{"bevel":0.209961,"columns":3,"mortar":0.116211,"pattern":0,"repeat":1,"row_offset":0.5,"rows":6},"type":"bricks"}]} {
"connections": [
{
"from": "bricks_0",
"from_port": 0,
"to": "custom_0",
"to_port": 0
},
{
"from": "custom_0",
"from_port": 0,
"to": "adjust_hsv_0",
"to_port": 0
},
{
"from": "adjust_hsv_0",
"from_port": 0,
"to": "Material",
"to_port": 0
}
],
"nodes": [
{
"name": "Material",
"node_position": {
"x": 143,
"y": -210
},
"parameters": {
"albedo_color": {
"a": 1,
"b": 1,
"g": 1,
"r": 1,
"type": "Color"
},
"ao_light_affect": 1,
"depth_scale": 1,
"emission_energy": 1,
"metallic": 1,
"normal_scale": 1,
"resolution": 1,
"roughness": 1
},
"type": "material"
},
{
"shader_model": {
"global": "",
"inputs": [
{
"default": "0.0",
"label": "Input",
"name": "input",
"type": "f"
}
],
"instance": "",
"name": "Colorize",
"outputs": [
{
"rgba": "$gradient($input($uv))"
}
],
"parameters": [
{
"default": {
"points": [
{
"a": 1,
"b": 0,
"g": 0,
"pos": 0,
"r": 0
},
{
"a": 1,
"b": 1,
"g": 1,
"pos": 1,
"r": 1
}
],
"type": "Gradient"
},
"label": "Gradient",
"name": "gradient",
"type": "gradient"
}
]
},
"name": "custom_0",
"node_position": {
"x": -433,
"y": -109.416656
},
"parameters": {
"gradient": {
"points": [
{
"a": 1,
"b": 0,
"g": 0,
"pos": 0,
"r": 0
},
{
"a": 1,
"b": 0,
"g": 0,
"pos": 0.517045,
"r": 1
},
{
"a": 0,
"b": 1,
"g": 1,
"pos": 1,
"r": 1
}
],
"type": "Gradient"
}
},
"type": "custom"
},
{
"name": "adjust_hsv_0",
"node_position": {
"x": -135.541687,
"y": -150.597229
},
"parameters": {
"hue": 0,
"saturation": 1,
"value": 1
},
"type": "adjust_hsv"
},
{
"name": "bricks_0",
"node_position": {
"x": -599,
"y": -332
},
"parameters": {
"bevel": 0.209961,
"columns": 3,
"mortar": 0.116211,
"pattern": 0,
"repeat": 1,
"row_offset": 0.5,
"rows": 6
},
"type": "bricks"
}
]
}