Optimized gradient parameters (passed as floats when possible)

This commit is contained in:
RodZill4 2020-03-26 08:56:55 +01:00
parent 8da80e163c
commit 9ab8820598
6 changed files with 89 additions and 46 deletions

View File

@ -114,14 +114,37 @@ func get_parameter(n : String):
else:
return get_parameter_def(n).default
class CustomGradientSorter:
static func compare(a, b) -> bool:
return a.pos < b.pos
func set_parameter(n : String, v) -> void:
var old_value = parameters[n] if parameters.has(n) else null
parameters[n] = v
emit_signal("parameter_changed", n, v)
if is_inside_tree():
var parameter_def : Dictionary = get_parameter_def(n)
if parameter_def.has("type") and parameter_def.type == "float":
get_tree().call_group("preview", "on_float_parameter_changed", "p_o%s_%s" % [ str(get_instance_id()), n ], v)
else:
if parameter_def.has("type"):
if parameter_def.type == "float":
var parameter_name = "p_o%s_%s" % [ str(get_instance_id()), n ]
get_tree().call_group("preview", "on_float_parameter_changed", parameter_name, v)
return
elif parameter_def.type == "gradient":
if v.interpolation == old_value.interpolation && v.points.size() == old_value.points.size():
# convert from old format
for i in range(old_value.points.size()):
if old_value.points[i].has("v"):
var old = old_value.points[i]
old_value.points[i] = { pos=old.v, r=old.c.r, g=old.c.g, b=old.c.b, a=old.c.a }
old_value.points.sort_custom(CustomGradientSorter, "compare")
v.points.sort_custom(CustomGradientSorter, "compare")
for i in range(old_value.points.size()):
for f in [ "pos", "r", "g", "b", "a" ]:
if v.points[i][f] != old_value.points[i][f]:
var parameter_name = "p_o%s_%s_%d_%s" % [ str(get_instance_id()), n, i, f ]
get_tree().call_group("preview", "on_float_parameter_changed", parameter_name, v.points[i][f])
return
print("regenerating shader")
source_changed(0)
func notify_output_change(output_index : int) -> void:

View File

@ -200,7 +200,7 @@ func subst(string : String, context : MMGenContext, uv : String = "") -> Diction
elif p.type == "color":
value_string = "vec4(%.9f, %.9f, %.9f, %.9f)" % [ value.r, value.g, value.b, value.a ]
elif p.type == "gradient":
value_string = genname+"_p_"+p.name+"_gradient_fct"
value_string = genname+"_"+p.name+"_gradient_fct"
elif p.type == "boolean":
value_string = "true" if value else "false"
else:
@ -258,7 +258,10 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
if !(g is MMGradient):
g = MMGradient.new()
g.deserialize(parameters[p.name])
rv.defs += g.get_shader(genname+"_p_"+p.name+"_gradient_fct")
var params = g.get_shader_params(genname+"_"+p.name)
for sp in params.keys():
rv.defs += "uniform float "+sp+" = "+str(params[sp])+";\n"
rv.defs += g.get_shader(genname+"_"+p.name)
# Generate functions for inputs
if shader_model.has("inputs"):
for i in range(shader_model.inputs.size()):

View File

@ -33,6 +33,9 @@ func add_point(v, c) -> void:
func sort() -> void:
if !sorted:
points.sort_custom(CustomSorter, "compare")
for i in range(points.size()-1):
if points[i].v+0.0000005 >= points[i+1].v:
points[i+1].v = points[i].v+0.000001
sorted = true
func get_color(x) -> Color:
@ -52,69 +55,81 @@ func get_color(x) -> Color:
else:
return Color(0.0, 0.0, 0.0, 1.0)
func get_shader_params(name) -> Dictionary:
sort()
var rv = {}
for i in range(points.size()):
rv["p_"+name+"_"+str(i)+"_pos"] = points[i].v
rv["p_"+name+"_"+str(i)+"_r"] = points[i].c.r
rv["p_"+name+"_"+str(i)+"_g"] = points[i].c.g
rv["p_"+name+"_"+str(i)+"_b"] = points[i].c.b
rv["p_"+name+"_"+str(i)+"_a"] = points[i].c.a
return rv
# get_color_in_shader
func gcis(color) -> String:
return "vec4(%.9f,%.9f,%.9f,%.9f)" % [color.r, color.g, color.b, color.a]
func pv(name : String, i : int) -> String:
return "p_"+name+"_"+str(i)+"_pos"
func pc(name : String, i : int) -> String:
return "vec4(p_"+name+"_"+str(i)+"_r,p_"+name+"_"+str(i)+"_g,p_"+name+"_"+str(i)+"_b,p_"+name+"_"+str(i)+"_a)"
func get_shader(name) -> String:
sort()
var shader
shader = "vec4 "+name+"(float x) {\n"
shader = "vec4 "+name+"_gradient_fct(float x) {\n"
match interpolation:
0:
if points.size() > 0:
shader += " if (x < %.9f) {\n" % (0.5*(points[0].v + points[1].v))
shader += " return "+gcis(points[0].c)+";\n"
shader += " if (x < 0.5*(%s+%s)) {\n" % [ pv(name, 0), pv(name, 1) ]
shader += " return "+pc(name, 0)+";\n"
var s = points.size()-1
for i in range(s):
if points[i+1].v-points[i].v > 0:
shader += " } else if (x < %.9f) {\n" % (0.5*(points[i].v + points[i+1].v))
shader += " return "+gcis(points[i].c)+";\n"
for i in range(1, s):
shader += " } else if (x < 0.5*(%s+%s)) {\n" % [ pv(name, i), pv(name, i+1) ]
shader += " return "+pc(name, i)+";\n"
shader += " }\n"
shader += " return "+gcis(points[s].c)+";\n"
shader += " return "+pc(name, s)+";\n"
else:
shader += " return vec4(0.0, 0.0, 0.0, 1.0);\n"
1, 2:
if points.size() > 0:
shader += " if (x < %.9f) {\n" % points[0].v
shader += " return "+gcis(points[0].c)+";\n"
shader += " if (x < %s) {\n" % pv(name, 0)
shader += " return "+pc(name, 0)+";\n"
var s = points.size()-1
for i in range(s):
var p1mp0 = points[i+1].v-points[i].v
if p1mp0 > 0:
shader += " } else if (x < %.9f) {\n" % points[i+1].v
shader += " } else if (x < %s) {\n" % pv(name, i+1)
var function = "(" if interpolation == 1 else "0.5-0.5*cos(3.14159265359*"
shader += " return mix(%s, %s, %s(x-%.9f)/%.9f));\n" % [ gcis(points[i].c), gcis(points[i+1].c), function, points[i].v, p1mp0 ]
shader += " return mix(%s, %s, %s(x-%s)/(%s-%s)));\n" % [ pc(name, i), pc(name, i+1), function, pv(name, i), pv(name, i+1), pv(name, i) ]
shader += " }\n"
shader += " return "+gcis(points[s].c)+";\n"
shader += " return "+pc(name, s)+";\n"
else:
shader += " return vec4(0.0, 0.0, 0.0, 1.0);\n"
3:
if points.size() > 0:
shader += " if (x < %.9f) {\n" % points[0].v
shader += " return "+gcis(points[0].c)+";\n"
shader += " if (x < %s) {\n" % pv(name, 0)
shader += " return "+pc(name, 0)+";\n"
var s = points.size()-1
for i in range(s):
var p1mp0 = points[i+1].v-points[i].v
if p1mp0 > 0:
shader += " } else if (x < %.9f) {\n" % points[i+1].v
var dx : String = "(x-%.9f)/%.9f" % [ points[i].v, p1mp0 ]
var b : String = "mix(%s, %s, %s)" % [ gcis(points[i].c), gcis(points[i+1].c), dx ]
if i > 0 and points[i-1].v < points[i].v:
var a : String = "mix(%s, %s, (x-%.9f)/%.9f)" % [ gcis(points[i-1].c), gcis(points[i].c), points[i-1].v, points[i].v-points[i-1].v ]
if i < s-1 and points[i+1].v < points[i+2].v:
var c : String = "mix(%s, %s, (x-%.9f)/%.9f)" % [ gcis(points[i+1].c), gcis(points[i+2].c), points[i+1].v, points[i+2].v-points[i+1].v ]
shader += " } else if (x < %s) {\n" % pv(name, i+1)
var dx : String = "(x-%s)/(%s-%s)" % [ pv(name, i), pv(name, i+1), pv(name, i) ]
var b : String = "mix(%s, %s, %s)" % [ pc(name, i), pc(name, i+1), dx ]
if i > 0:
var a : String = "mix(%s, %s, (x-%s)/(%s-%s))" % [ pc(name, i-1), pc(name, i), pv(name, i-1), pv(name, i), pv(name, i-1) ]
if i < s-1:
var c : String = "mix(%s, %s, (x-%s)/(%s-%s))" % [ pc(name, i+1), pc(name, i+2), pv(name, i+1), pv(name, i+2), pv(name, i+1) ]
var ac : String = "mix("+a+", "+c+", 0.5-0.5*cos(3.14159265359*"+dx+"))"
shader += " return 0.5*("+b+" + "+ac+");\n"
else:
shader += " return mix("+a+", "+b+", 0.5+0.5*"+dx+");\n"
elif i < s-1 and points[i+1].v < points[i+2].v:
var c : String = "mix(%s, %s, (x-%.9f)/%.9f)" % [ gcis(points[i+1].c), gcis(points[i+2].c), points[i+1].v, points[i+2].v-points[i+1].v ]
elif i < s-1:
var c : String = "mix(%s, %s, (x-%s)/(%s-%s))" % [ pc(name, i+1), pc(name, i+2), pv(name, i+1), pv(name, i+2), pv(name, i+1) ]
shader += " return mix("+c+", "+b+", 1.0-0.5*"+dx+");\n"
else:
shader += " return "+b+";\n"
shader += " }\n"
shader += " return "+gcis(points[s].c)+";\n"
shader += " return "+pc(name, s)+";\n"
else:
shader += " return vec4(0.0, 0.0, 0.0, 1.0);\n"
_:

View File

@ -109,7 +109,6 @@ func _on_gradient_changed(new_gradient, variable) -> void:
ignore_parameter_change = variable
generator.set_parameter(variable, MMType.serialize_value(new_gradient))
ignore_parameter_change = ""
update_shaders()
func create_parameter_control(p : Dictionary) -> Control:
var control = null

View File

@ -46,7 +46,7 @@ func on_parameter_changed(n : String, v) -> void:
var p = generator.get_parameter_def(n)
if p.has("type"):
match p.type:
"float":
"float", "gradient":
pass
_:
set_generator(generator, output)

View File

@ -147,8 +147,11 @@ func get_gradient_color(x) -> Color:
func update_shader() -> void:
var shader
shader = "shader_type canvas_item;\n"
shader += value.get_shader("gradient")
shader += "void fragment() { COLOR = gradient(UV.x); }"
var params = value.get_shader_params("")
for sp in params.keys():
shader += "uniform float "+sp+" = "+str(params[sp])+";\n"
shader += value.get_shader("")
shader += "void fragment() { COLOR = _gradient_fct(UV.x); }"
$Gradient.material.shader.set_code(shader)
emit_signal("updated", value)