Added support for raymarching

- Added signed distance functions 2D and 2D input/output types
- Updated SDF2D nodes to used SDF2D inputs/outputs
- Added preview code for SDF2D and SDF3D
- Updates all SDF2D templates
- Added basic SDF3D nodes
This commit is contained in:
RodZill4 2019-12-15 12:41:00 +01:00
parent 2a51e3b726
commit e919507f06
27 changed files with 1243 additions and 90 deletions

View File

@ -37,6 +37,14 @@ var parameters = {}
var seed_locked : bool = false
var seed_value : int = 0
const PORT_TYPES : Dictionary = {
rgba = { type="vec4", paramdefs="vec2 uv", params="uv" },
rgb = { type="vec3", paramdefs="vec2 uv", params="uv" },
f = { type="float", paramdefs="vec2 uv", params="uv" },
sdf2d = { type="float", paramdefs="vec2 uv", params="uv" },
sdf3d = { type="float", paramdefs="vec3 p", params="p" }
}
func _ready() -> void:
init_parameters()
@ -151,14 +159,18 @@ func get_input_shader(input_index : int) -> Dictionary:
func get_shader(output_index : int, context) -> Dictionary:
return get_shader_code("UV", output_index, context)
func render(output_index : int, size : int) -> Object:
func render(output_index : int, size : int, preview : bool = false) -> Object:
var context : MMGenContext = MMGenContext.new()
var source = get_shader_code("UV", output_index, context)
var source = get_shader_code("uv", output_index, context)
while source is GDScriptFunctionState:
source = yield(source, "completed")
if source.empty():
source = { defs="", code="", textures={}, rgba="vec4(0.0)" }
var shader : String = mm_renderer.generate_shader(source)
var shader : String
if preview:
shader = mm_renderer.generate_preview_shader(source)
else:
shader = mm_renderer.generate_shader(source)
var result = mm_renderer.render_shader(shader, source.textures, size)
while result is GDScriptFunctionState:
result = yield(result, "completed")
@ -174,15 +186,14 @@ func get_shader_code(uv : String, output_index : int, context : MMGenContext) ->
rv.f = "(dot("+rv.rgb+", vec3(1.0))/3.0)"
elif rv.has("rgba"):
rv.f = "(dot("+rv.rgba+".rgb, vec3(1.0))/3.0)"
else:
rv.f = "0.0"
if !rv.has("rgb"):
if rv.has("rgba"):
rv.rgb = rv.rgba+".rgb"
else:
elif rv.has("f"):
rv.rgb = "vec3("+rv.f+")"
if !rv.has("rgba"):
rv.rgba = "vec4("+rv.rgb+", 1.0)"
if rv.has("rgb"):
rv.rgba = "vec4("+rv.rgb+", 1.0)"
return rv
func _get_shader_code(__, __, __) -> Dictionary:

View File

@ -2,17 +2,12 @@ tool
extends MMGenBase
class_name MMGenShader
var shader_model : Dictionary = {}
var uses_seed = false
var editable = false
const PORT_TYPES : Dictionary = {
rgba = { type="vec4" },
rgb = { type="vec3" },
f = { type="float" }
}
const GENERATE_FUNCTIONS : bool = false
func toggle_editable() -> bool:
editable = !editable
@ -60,16 +55,12 @@ func set_shader_model(data: Dictionary) -> void:
for i in range(shader_model.outputs.size()):
var output = shader_model.outputs[i]
var output_code = ""
if output.has("rgba"):
shader_model.outputs[i].type = "rgba"
output_code = output.rgba
elif output.has("rgb"):
shader_model.outputs[i].type = "rgb"
output_code = output.rgb
elif output.has("f"):
shader_model.outputs[i].type = "f"
output_code = output.f
else:
for f in PORT_TYPES.keys():
if output.has(f):
shader_model.outputs[i].type = f
output_code = output[f]
break
if output_code == "":
print("Unsupported output type")
if output_code.find("$seed") != -1 or output_code.find("$(seed)") != -1:
uses_seed = true
@ -132,7 +123,10 @@ func replace_input(string : String, context, input : String, type : String, src
src_code = src.generator.get_shader_code(uv, src.output_index, context)
while src_code is GDScriptFunctionState:
src_code = yield(src_code, "completed")
src_code.string = src_code[type]
if src_code.has(type):
src_code.string = src_code[type]
else:
src_code.string = "*error*"
# Add global definitions
if src_code.has("globals"):
for d in src_code.globals:
@ -218,7 +212,7 @@ func subst(string : String, context : MMGenContext, uv : String = "") -> Diction
for i in range(shader_model.inputs.size()):
var input = shader_model.inputs[i]
var source = get_source(i)
if GENERATE_FUNCTIONS:
if input.has("function") and input.function:
string = replace_input_with_function_call(string, input.name)
else:
var result = replace_input(string, context, input.name, input.type, source, input.default)
@ -251,14 +245,7 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
var rv = { globals=[], defs="", code="", textures={} }
if shader_model != null and shader_model.has("outputs") and shader_model.outputs.size() > output_index:
var output = shader_model.outputs[output_index]
if shader_model.has("instance") && !context.has_variant(self):
var subst_output = subst(shader_model.instance, context, "")
while subst_output is GDScriptFunctionState:
subst_output = yield(subst_output, "completed")
rv.defs += subst_output.string
# process textures
for t in subst_output.textures.keys():
rv.textures[t] = subst_output.textures[t]
if !context.has_variant(self):
# Generate functions for gradients
for p in shader_model.parameters:
if p.type == "gradient":
@ -270,10 +257,10 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
# Generate functions for inputs
if shader_model.has("inputs"):
for i in range(shader_model.inputs.size()):
if GENERATE_FUNCTIONS:
var input = shader_model.inputs[i]
var input = shader_model.inputs[i]
if input.has("function") and input.function:
var source = get_source(i)
var string = "$%s(uv)" % input.name
var string = "$%s(%s)" % [ input.name, PORT_TYPES[input.type].params ]
var local_context = MMGenContext.new(context)
var result = replace_input(string, local_context, input.name, input.type, source, input.default)
while result is GDScriptFunctionState:
@ -287,9 +274,17 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
# Add textures
for t in result.textures.keys():
rv.textures[t] = result.textures[t]
rv.defs += "%s %s_input_%s(vec2 uv) {\n" % [ PORT_TYPES[input.type].type, genname, input.name ]
rv.defs += "%s %s_input_%s(%s) {\n" % [ PORT_TYPES[input.type].type, genname, input.name, PORT_TYPES[input.type].paramdefs ]
rv.defs += "%s\n" % result.code
rv.defs += "return %s;\n}\n" % result.string
if shader_model.has("instance"):
var subst_output = subst(shader_model.instance, context, "")
while subst_output is GDScriptFunctionState:
subst_output = yield(subst_output, "completed")
rv.defs += subst_output.string
# process textures
for t in subst_output.textures.keys():
rv.textures[t] = subst_output.textures[t]
# Add inline code
if shader_model.has("code"):
var variant_index = context.get_variant(self, uv)

View File

@ -27,13 +27,85 @@ static func generate_shader(src_code) -> String:
code += g
var shader_code = src_code.defs
shader_code += "\nvoid fragment() {\n"
shader_code += "vec2 uv = UV;\n"
shader_code += src_code.code
shader_code += "COLOR = "+src_code.rgba+";\n"
if src_code.has("rgba"):
shader_code += "COLOR = "+src_code.rgba+";\n"
else:
shader_code += "COLOR = vec4(1.0, 0.0, 0.0, 1.0);\n"
shader_code += "}\n"
#print("GENERATED SHADER:\n"+shader_code)
code += shader_code
return code
static func generate_preview_shader(src_code) -> String:
var code
code = "shader_type canvas_item;\n"
code += "render_mode blend_disabled;\n"
var file = File.new()
file.open("res://addons/material_maker/common.shader", File.READ)
code += file.get_as_text()
code += "\n"
if src_code.has("textures"):
for t in src_code.textures.keys():
code += "uniform sampler2D "+t+";\n"
if src_code.has("globals"):
for g in src_code.globals:
code += g
var shader_code = src_code.defs
if src_code.has("rgba"):
shader_code += "\nvoid fragment() {\n"
shader_code += "vec2 uv = UV;\n"
shader_code += src_code.code
shader_code += "COLOR = "+src_code.rgba+";\n"
shader_code += "}\n"
elif src_code.has("sdf2d"):
shader_code += "\nvoid fragment() {\n"
shader_code += "vec2 uv = UV;\n"
shader_code += src_code.code
shader_code += "float d = "+src_code.sdf2d+";\n"
shader_code += "vec3 col = vec3(cos(d*62.8318530718*5.0));\n"
shader_code += "col *= clamp(1.0-4.0*abs(d), 0.0, 1.0);\n"
shader_code += "col *= vec3(1.0, vec2(step(-0.015, d)));\n"
shader_code += "col *= vec3(vec2(step(d, 0.015)), 1.0);\n"
shader_code += "COLOR = vec4(col, 1.0);\n"
shader_code += "}\n"
elif src_code.has("sdf3d"):
shader_code += "\nfloat calcdist(vec3 uv) {\n"
shader_code += src_code.code
shader_code += "return min("+src_code.sdf3d+", uv.z);\n"
shader_code += "}\n"
shader_code += "float raymarch(vec3 ro, vec3 rd) {\n"
shader_code += "float d=0.0;\n"
shader_code += "for (int i = 0; i < 50; i++) {\n"
shader_code += "vec3 p = ro + rd*d;\n"
shader_code += "float dstep = calcdist(p);\n"
shader_code += "d += dstep;\n"
shader_code += "if (dstep < 0.0001) break;\n"
shader_code += "}\n"
shader_code += "return d;\n"
shader_code += "}\n"
shader_code += "vec3 normal(vec3 p) {\n"
shader_code += " float d = calcdist(p);\n"
shader_code += " float e = .0001;\n"
shader_code += " vec3 n = d - vec3(calcdist(p-vec3(e, 0.0, 0.0)), calcdist(p-vec3(0.0, e, 0.0)), calcdist(p-vec3(0.0, 0.0, e)));\n"
shader_code += " return normalize(n);\n"
shader_code += "}\n"
shader_code += "\nvoid fragment() {\n"
shader_code += "vec2 uv = UV-vec2(0.5);\n"
shader_code += "vec3 p = vec3(uv, 2.0-raymarch(vec3(uv, 2.0), vec3(0.0, 0.0, -1.0)));\n"
shader_code += "vec3 n = normal(p);\n"
shader_code += "vec3 l = vec3(5.0, 5.0, 10.0);\n"
shader_code += "vec3 ld = normalize(l-p);\n"
shader_code += "float o = step(p.z, 0.001);\n"
shader_code += "float shadow = 1.0-0.75*step(raymarch(l, -ld), length(l-p)-0.01);\n"
shader_code += "float light = 0.3+0.7*dot(n, ld)*shadow;\n"
shader_code += "COLOR = vec4(vec3(0.8+0.2*o, 0.8+0.2*o, 1.0)*light, 1.0);\n"
shader_code += "}\n"
#print("GENERATED SHADER:\n"+shader_code)
code += shader_code
return code
static func generate_combined_shader(red_code, green_code, blue_code) -> String:
var code
code = "shader_type canvas_item;\n"

View File

@ -0,0 +1,664 @@
{
"connections": [
{
"from": "_3",
"from_port": 1,
"to": "Material",
"to_port": 4
},
{
"from": "perlin",
"from_port": 0,
"to": "colorize",
"to_port": 0
},
{
"from": "colorize",
"from_port": 0,
"to": "Material",
"to_port": 2
},
{
"from": "sdf3d_sphere",
"from_port": 0,
"to": "_4",
"to_port": 0
},
{
"from": "sdf3d_sphere",
"from_port": 0,
"to": "_4_2",
"to_port": 0
},
{
"from": "_4",
"from_port": 0,
"to": "sdf3d_boolean",
"to_port": 0
},
{
"from": "_4_2",
"from_port": 0,
"to": "sdf3d_boolean",
"to_port": 1
},
{
"from": "sdf3d_boolean",
"from_port": 0,
"to": "_4_2_2",
"to_port": 0
},
{
"from": "_4_2_2",
"from_port": 0,
"to": "sdf3d_smoothboolean",
"to_port": 0
},
{
"from": "sdf3d_box",
"from_port": 0,
"to": "sdf3d_smoothboolean",
"to_port": 1
},
{
"from": "sdf3d_torus",
"from_port": 0,
"to": "_4_2_2_2",
"to_port": 0
},
{
"from": "sdf3d_smoothboolean",
"from_port": 0,
"to": "sdf3d_smoothboolean_2",
"to_port": 1
},
{
"from": "_4_2_2_2",
"from_port": 0,
"to": "sdf3d_smoothboolean_2",
"to_port": 0
},
{
"from": "sdf3d_smoothboolean_2",
"from_port": 0,
"to": "_3",
"to_port": 0
}
],
"label": "Graph",
"name": "49",
"node_position": {
"x": 0,
"y": 0
},
"nodes": [
{
"name": "Material",
"node_position": {
"x": -36,
"y": -273
},
"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,
"roughness": 1,
"size": 11,
"subsurf_scatter_strength": 0
},
"type": "material"
},
{
"name": "_3",
"node_position": {
"x": -424.5,
"y": -165
},
"parameters": {
},
"shader_model": {
"code": "float $(name_uv)_d = raymarch_$name($uv);\n",
"global": "",
"inputs": [
{
"default": "0.0",
"function": true,
"label": "",
"name": "sdf",
"type": "sdf3d"
}
],
"instance": "float input_$name(vec3 p) {\n\treturn min($sdf(p), p.z);\n}\n\nfloat raymarch_$name(vec2 uv) {\n\tvec3 ro = vec3(uv-vec2(0.5), 1.0);\n\tvec3 rd = vec3(0.0, 0.0, -1.0);\n\tfloat dO=0.;\n \n for (int i=0; i < 50; i++) {\n \tvec3 p = ro + rd*dO;\n float dS = input_$name(p);\n dO += dS;\n if (dO > 0.001 && dS < 0.0001) break;\n }\n \n return dO;\n}\n\nvec3 normal_$name(vec3 p) {\n\tfloat d = input_$name(p);\n float e = .001;\n \n vec3 n = d - vec3(\n input_$name(p-vec3(e, 0.0, 0.0)),\n input_$name(p-vec3(0.0, e, 0.0)),\n input_$name(p-vec3(0.0, 0.0, e)));\n \n return vec3(-1.0, -1.0, -1.0)*normalize(n);\n}\n\n",
"name": "Raymarching",
"outputs": [
{
"f": "1.0-$(name_uv)_d",
"type": "f"
},
{
"rgb": "vec3(0.5)+0.5*normal_$name(vec3($uv-vec2(0.5), 1.0-$(name_uv)_d))",
"type": "rgb"
}
],
"parameters": [
]
},
"type": "shader"
},
{
"name": "perlin",
"node_position": {
"x": -511.535645,
"y": -348.25
},
"parameters": {
"iterations": 5,
"persistence": 0.5,
"scale_x": 4,
"scale_y": 4
},
"type": "perlin"
},
{
"name": "colorize",
"node_position": {
"x": -260.535645,
"y": -304.25
},
"parameters": {
"gradient": {
"interpolation": 1,
"points": [
{
"a": 1,
"b": 0.088542,
"g": 0.088542,
"pos": 0,
"r": 0.088542
},
{
"a": 1,
"b": 0.494792,
"g": 0.494792,
"pos": 0.990909,
"r": 0.494792
},
{
"a": 1,
"b": 0.338542,
"g": 0.338542,
"pos": 1,
"r": 0.338542
}
],
"type": "Gradient"
}
},
"type": "colorize"
},
{
"name": "_4",
"node_position": {
"x": -1008.238525,
"y": -303.85495
},
"parameters": {
"x": -0.17,
"y": 0,
"z": 0
},
"shader_model": {
"code": "",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in",
"type": "sdf3d"
}
],
"instance": "",
"name": "Translate",
"outputs": [
{
"sdf3d": "$in($uv+vec3($x, $y, $z))",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0,
"label": "X",
"max": 1,
"min": -1,
"name": "x",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Y",
"max": 1,
"min": -1,
"name": "y",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Z",
"max": 1,
"min": -1,
"name": "z",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
},
{
"name": "sdf3d_boolean",
"node_position": {
"x": -821.049805,
"y": -365.10495
},
"parameters": {
"bevel": 0,
"cx": 0,
"cy": 0,
"h": 0.08,
"op": 0,
"r": 0.3,
"w": 0.28
},
"type": "sdf3d_boolean"
},
{
"name": "sdf3d_box",
"node_position": {
"x": -1025.376221,
"y": -92.60495
},
"parameters": {
"r": 0.26,
"sx": 0.1,
"sy": 0.1,
"sz": 0.02
},
"shader_model": {
"code": "vec3 $(name_uv)_q = abs($uv) - vec3($sx, $sy, $sz);\n",
"global": "",
"inputs": [
],
"instance": "",
"name": "Box",
"outputs": [
{
"sdf3d": "length(max($(name_uv)_q,0.0))+min(max($(name_uv)_q.x,max($(name_uv)_q.y,$(name_uv)_q.z)),0.0)-$r",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0.5,
"label": "Size X",
"max": 1,
"min": 0,
"name": "sx",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "Size Y",
"max": 1,
"min": 0,
"name": "sy",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "Size Z",
"max": 1,
"min": 0,
"name": "sz",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "Radius",
"max": 1,
"min": 0,
"name": "r",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
},
{
"name": "sdf3d_torus",
"node_position": {
"x": -819.376282,
"y": -100.60495
},
"parameters": {
"R": 0.38,
"a1": 0.5,
"a2": 0.865,
"r": 0.03,
"sx": 0.1,
"sy": 0.1,
"sz": 0.02
},
"shader_model": {
"code": "\n",
"global": "float sdf3CappedTorus(vec3 p, float R, float r, vec2 sc) {\n\tp.x = abs(p.x);\n\tfloat k = (sc.y*p.x>sc.x*p.y)?dot(p.xy,sc):length(p.xy);\n\treturn sqrt(dot(p,p)+R*R-2.0*R*k)-r;\n}\n",
"inputs": [
],
"instance": "",
"name": "Capped Torus",
"outputs": [
{
"sdf3d": "sdf3CappedTorus($uv, $R, $r, vec2($a1, $a2))",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0.5,
"label": "R",
"max": 1,
"min": 0,
"name": "R",
"step": 0.01,
"type": "float"
},
{
"default": 0.1,
"label": "r",
"max": 0.5,
"min": 0,
"name": "r",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "A1",
"max": 1,
"min": 0,
"name": "a1",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "A2",
"max": 1,
"min": 0,
"name": "a2",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
},
{
"name": "sdf3d_smoothboolean",
"node_position": {
"x": -822.049805,
"y": -189.10495
},
"parameters": {
"bevel": 0,
"cx": 0,
"cy": 0,
"h": 0.08,
"k": 0.02,
"op": 1,
"r": 0.3,
"w": 0.28
},
"type": "sdf3d_smoothboolean"
},
{
"name": "_4_2",
"node_position": {
"x": -1004.406982,
"y": -196.60495
},
"parameters": {
"x": 0.17,
"y": 0,
"z": 0
},
"shader_model": {
"code": "",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in",
"type": "sdf3d"
}
],
"instance": "",
"name": "Translate",
"outputs": [
{
"sdf3d": "$in($uv+vec3($x, $y, $z))",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0,
"label": "X",
"max": 1,
"min": -1,
"name": "x",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Y",
"max": 1,
"min": -1,
"name": "y",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Z",
"max": 1,
"min": -1,
"name": "z",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
},
{
"name": "_4_2_2",
"node_position": {
"x": -808.049805,
"y": -300.60495
},
"parameters": {
"x": 0,
"y": 0.14,
"z": -0.23
},
"shader_model": {
"code": "",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in",
"type": "sdf3d"
}
],
"instance": "",
"name": "Translate",
"outputs": [
{
"sdf3d": "$in($uv+vec3($x, $y, $z))",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0,
"label": "X",
"max": 1,
"min": -1,
"name": "x",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Y",
"max": 1,
"min": -1,
"name": "y",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Z",
"max": 1,
"min": -1,
"name": "z",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
},
{
"name": "_4_2_2_2",
"node_position": {
"x": -813.069458,
"y": 32.162903
},
"parameters": {
"x": 0,
"y": 0.19,
"z": -0.23
},
"shader_model": {
"code": "",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in",
"type": "sdf3d"
}
],
"instance": "",
"name": "Translate",
"outputs": [
{
"sdf3d": "$in($uv+vec3($x, $y, $z))",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0,
"label": "X",
"max": 1,
"min": -1,
"name": "x",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Y",
"max": 1,
"min": -1,
"name": "y",
"step": 0.01,
"type": "float"
},
{
"default": 0,
"label": "Z",
"max": 1,
"min": -1,
"name": "z",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
},
{
"name": "sdf3d_smoothboolean_2",
"node_position": {
"x": -621.569458,
"y": -171.337097
},
"parameters": {
"bevel": 0,
"cx": 0,
"cy": 0,
"h": 0.08,
"k": 0.04,
"op": 1,
"r": 0.3,
"w": 0.28
},
"type": "sdf3d_smoothboolean"
},
{
"name": "sdf3d_sphere",
"node_position": {
"x": -1000.049805,
"y": -359.10495
},
"parameters": {
"r": 0.07
},
"type": "sdf3d_sphere"
}
],
"parameters": {
},
"type": "graph"
}

View File

@ -383,7 +383,7 @@ func do_add_to_user_library(name, nodes) -> void:
dir.make_dir("user://library/user")
data.library = "user://library/user.json"
data.icon = library.get_icon_name(name)
var result = nodes[0].generator.render(0, 64)
var result = nodes[0].generator.render(0, 64, true)
while result is GDScriptFunctionState:
result = yield(result, "completed")
result.save_to_file("user://library/user/"+data.icon+".png")
@ -480,7 +480,7 @@ func update_preview_2d(node = null) -> void:
node = n
break
if node != null:
var result = node.generator.render(0, 1024)
var result = node.generator.render(0, 1024, true)
while result is GDScriptFunctionState:
result = yield(result, "completed")
var tex = ImageTexture.new()

View File

@ -66,7 +66,7 @@ margin_left = 125.0
margin_right = 171.0
margin_bottom = 20.0
text = "Tools"
items = [ "Create", null, 0, false, false, -1, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 19, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 20, 268435543, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 22, 0, null, "", false, "Export the nodes library", null, 0, false, false, 23, 0, null, "", false ]
items = [ "Create", null, 0, false, false, 0, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 19, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 20, 268435543, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 22, 0, null, "", false, "Export the nodes library", null, 0, false, false, 23, 0, null, "", false ]
[node name="Help" type="MenuButton" parent="VBoxContainer/Menu"]
margin_left = 175.0

View File

@ -16,7 +16,10 @@ static func generate_shader(src_code) -> String:
var shader_code = src_code.defs
shader_code += "\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\nvec2 UV = fragCoord/iResolution.xy;\n"
shader_code += src_code.code
shader_code += "fragColor = "+src_code.rgba+";\n"
if src_code.has("rgba"):
shader_code += "fragColor = "+src_code.rgba+";\n"
else:
shader_code += "fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
shader_code += "}\n"
#print("GENERATED SHADER:\n"+shader_code)
code += shader_code

View File

@ -175,14 +175,12 @@ func update_node() -> void:
var enable_left = false
var color_left = Color(0.5, 0.5, 0.5)
if typeof(input) == TYPE_DICTIONARY:
if input.type == "rgb":
enable_left = true
color_left = Color(0.5, 0.5, 1.0)
elif input.type == "rgba":
enable_left = true
color_left = Color(0.0, 0.5, 0.0, 0.5)
else:
enable_left = true
enable_left = true
match input.type:
"rgb": color_left = Color(0.5, 0.5, 1.0)
"rgba": color_left = Color(0.0, 0.5, 0.0, 0.5)
"sdf2d": color_left = Color(1.0, 0.5, 0.0, 1.0)
"sdf3d": color_left = Color(1.0, 0.0, 0.0, 1.0)
set_slot(i, enable_left, 0, color_left, false, 0, Color())
var hsizer : HBoxContainer = HBoxContainer.new()
hsizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
@ -240,7 +238,8 @@ func update_node() -> void:
label_widget.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
hsizer.add_child(label_widget)
control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
hsizer.add_child(control)
if hsizer != null:
hsizer.add_child(control)
initialize_properties()
# Outputs
var outputs = generator.get_output_defs()
@ -256,6 +255,8 @@ func update_node() -> void:
match output.type:
"rgb": color_right = Color(0.5, 0.5, 1.0)
"rgba": color_right = Color(0.0, 0.5, 0.0, 0.5)
"sdf2d": color_right = Color(1.0, 0.5, 0.0, 1.0)
"sdf3d": color_right = Color(1.0, 0.0, 0.0, 1.0)
set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right)
var hsizer : HBoxContainer
while i >= get_child_count():
@ -383,7 +384,7 @@ func update_preview(size : int = 0) -> void:
preview_timer.start(0.2)
func do_update_preview() -> void:
var result = generator.render(preview_index, preview_size)
var result = generator.render(preview_index, preview_size, true)
while result is GDScriptFunctionState:
result = yield(result, "completed")
if preview.texture == null:

View File

@ -0,0 +1,39 @@
{
"name": "raymarching",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
},
"shader_model": {
"code": "float $(name_uv)_d = raymarch_$name($uv);\n",
"global": "",
"inputs": [
{
"default": "0.0",
"function": true,
"label": "",
"name": "sdf",
"type": "sdf3d"
}
],
"instance": "float input_$name(vec3 p) {\n\tif (p.z > 0.0) {\n\t\treturn $sdf(p);\n\t} else {\n\t\treturn p.z;\n\t}\n}\n\nfloat raymarch_$name(vec2 uv) {\n\tvec3 ro = vec3(uv-vec2(0.5), 1.0);\n\tvec3 rd = vec3(0.0, 0.0, -1.0);\n\tfloat dO=0.;\n \n for (int i=0; i < 25; i++) {\n \tvec3 p = ro + rd*dO;\n float dS = input_$name(p);\n dO += dS;\n if (dO > 1.0 || dS < 0.0001) break;\n }\n \n return dO;\n}\n\nvec3 normal_$name(vec3 p) {\n\tfloat d = input_$name(p);\n float e = .001;\n \n vec3 n = d - vec3(\n input_$name(p-vec3(e, 0.0, 0.0)),\n input_$name(p-vec3(0.0, e, 0.0)),\n input_$name(p-vec3(0.0, 0.0, e)));\n \n return vec3(-1.0, -1.0, -1.0)*normalize(n);\n}\n\n",
"name": "Raymarching",
"outputs": [
{
"f": "1.0-$(name_uv)_d",
"type": "f"
},
{
"rgb": "vec3(0.5)+0.5*normal_$name(vec3($uv-vec2(0.5), 1.0-$(name_uv)_d))",
"type": "rgb"
}
],
"parameters": [
]
},
"type": "shader"
}

View File

@ -22,15 +22,15 @@
"default": "0.0",
"label": "",
"name": "in",
"type": "f"
"type": "sdf2d"
}
],
"instance": "",
"name": "sdAnnularShape",
"outputs": [
{
"f": "abs($in($uv)) - $r",
"type": "f"
"sdf2d": "abs($in($uv))-$r",
"type": "sdf2d"
}
],
"parameters": [

View File

@ -9,53 +9,53 @@
"cx": 0,
"cy": 0,
"h": 0.08,
"op": 0,
"op": 1,
"r": 0.3,
"w": 0.28
},
"shader_model": {
"code": "",
"global": "float sdUnion( float d1, float d2 ) { return min(d1,d2); }\nfloat sdSubtraction( float d1, float d2 ) { return max(-d1,d2); }\nfloat sdIntersection( float d1, float d2 ) { return max(d1,d2); }\n",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in1",
"type": "f"
"type": "sdf2d"
},
{
"default": "0.0",
"label": "",
"name": "in2",
"type": "f"
"type": "sdf2d"
}
],
"instance": "",
"name": "sdBoolean",
"outputs": [
{
"f": "sd$op($in1($uv), $in2($uv))",
"type": "f"
"sdf2d": "$op $in1($uv), $in2($uv))",
"type": "sdf2d"
}
],
"parameters": [
{
"default": 0,
"default": 2,
"label": "",
"name": "op",
"type": "enum",
"values": [
{
"name": "Union",
"value": "Union"
"value": "min("
},
{
"name": "Subtraction",
"value": "Subtraction"
"value": "max(-"
},
{
"name": "Intersection",
"value": "Intersection"
"value": "max("
}
]
}

View File

@ -12,8 +12,8 @@
"w": 0.3
},
"shader_model": {
"code": "",
"global": "float sdBox(in vec2 p, in vec2 b) {\n vec2 d = abs(p)-b;\n return length(max(d,vec2(0))) + min(max(d.x,d.y),0.0);\n}\n",
"code": "vec2 $(name_uv)_d = abs($uv-0.5*vec2($cx+1.0, $cy+1.0))-vec2($w, $h);\n",
"global": "",
"inputs": [
],
@ -21,8 +21,8 @@
"name": "sdBox",
"outputs": [
{
"f": "sdBox($uv-0.5*vec2($cx+1.0, $cy+1.0), vec2($w, $h))",
"type": "f"
"sdf2d": "length(max($(name_uv)_d,vec2(0)))+min(max($(name_uv)_d.x,$(name_uv)_d.y),0.0)",
"type": "sdf2d"
}
],
"parameters": [

View File

@ -7,11 +7,11 @@
"parameters": {
"cx": 0,
"cy": 0,
"r": 0.5
"r": 0.25
},
"shader_model": {
"code": "",
"global": "float sdCircle(vec2 p, float r) {\n return length(p) - r;\n}\n",
"global": "",
"inputs": [
],
@ -19,8 +19,8 @@
"name": "sdCircle",
"outputs": [
{
"f": "sdCircle($uv-0.5*vec2($cx+1.0, $cy+1.0), $r)",
"type": "f"
"sdf2d": "length($uv-0.5*vec2($cx+1.0, $cy+1.0))-$r",
"type": "sdf2d"
}
],
"parameters": [

View File

@ -0,0 +1,65 @@
{
"name": "sdf3d_boolean",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
"bevel": 0,
"cx": 0,
"cy": 0,
"h": 0.08,
"op": 0,
"r": 0.3,
"w": 0.28
},
"shader_model": {
"code": "",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in1",
"type": "sdf3d"
},
{
"default": "0.0",
"label": "",
"name": "in2",
"type": "sdf3d"
}
],
"instance": "",
"name": "Boolean",
"outputs": [
{
"sdf3d": "$op $in1($uv), $in2($uv))",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 1,
"label": "",
"name": "op",
"type": "enum",
"values": [
{
"name": "Union",
"value": "min("
},
{
"name": "Subtraction",
"value": "max(-"
},
{
"name": "Intersection",
"value": "max("
}
]
}
]
},
"type": "shader"
}

View File

@ -0,0 +1,67 @@
{
"name": "sdf3d_box",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
"r": 0.01,
"sx": 0.25,
"sy": 0.25,
"sz": 0.5
},
"shader_model": {
"code": "vec3 $(name_uv)_q = abs($uv) - vec3($sx, $sy, $sz);\n",
"global": "",
"inputs": [
],
"instance": "",
"name": "Box",
"outputs": [
{
"sdf3d": "length(max($(name_uv)_q,0.0))+min(max($(name_uv)_q.x,max($(name_uv)_q.y,$(name_uv)_q.z)),0.0)-$r",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0.5,
"label": "Size X",
"max": 1,
"min": 0,
"name": "sx",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "Size Y",
"max": 1,
"min": 0,
"name": "sy",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "Size Z",
"max": 1,
"min": 0,
"name": "sz",
"step": 0.01,
"type": "float"
},
{
"default": 0.5,
"label": "Radius",
"max": 1,
"min": 0,
"name": "r",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
}

View File

@ -0,0 +1,75 @@
{
"name": "sdf3d_smoothboolean",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
"bevel": 0,
"cx": 0,
"cy": 0,
"h": 0.08,
"k": 0.1,
"op": 0,
"r": 0.3,
"w": 0.28
},
"shader_model": {
"code": "",
"global": "float sdf3SmoothUnion(float d1, float d2, float k) {\n float h = clamp(0.5+0.5*(d2-d1)/k, 0.0, 1.0);\n return mix(d2, d1, h)-k*h*(1.0-h);\n}\n\nfloat sdf3SmoothSubtraction( float d1, float d2, float k ) {\n float h = clamp(0.5-0.5*(d2+d1)/k, 0.0, 1.0);\n return mix( d2, -d1, h )+k*h*(1.0-h);\n}\n\nfloat sdf3SmoothIntersection( float d1, float d2, float k ) {\n float h = clamp(0.5-0.5*(d2-d1)/k, 0.0, 1.0);\n return mix(d2, d1, h)+k*h*(1.0-h);\n}\n",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in1",
"type": "sdf3d"
},
{
"default": "0.0",
"label": "",
"name": "in2",
"type": "sdf3d"
}
],
"instance": "",
"name": "sdSmoothBoolean",
"outputs": [
{
"sdf3d": "sdf3Smooth$op($in1($uv), $in2($uv), $k)",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0,
"label": "",
"name": "op",
"type": "enum",
"values": [
{
"name": "Union",
"value": "Union"
},
{
"name": "Subtraction",
"value": "Subtraction"
},
{
"name": "Intersection",
"value": "Intersection"
}
]
},
{
"default": 0,
"label": "",
"max": 1,
"min": 0,
"name": "k",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
}

View File

@ -0,0 +1,37 @@
{
"name": "sdf3d_sphere",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
"r": 0.5
},
"shader_model": {
"code": "",
"global": "",
"inputs": [
],
"instance": "",
"name": "Sphere",
"outputs": [
{
"sdf3d": "length($uv)-$r",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0.5,
"label": "",
"max": 1,
"min": 0,
"name": "r",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
}

View File

@ -0,0 +1,50 @@
{
"name": "sdf3d_torus",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
"R": 0.25,
"r": 0.1,
"sx": 0.1,
"sy": 0.1,
"sz": 0.02
},
"shader_model": {
"code": "vec2 $(name_uv)_q = vec2(length($uv.xy)-$R,$uv.z);\n",
"global": "",
"inputs": [
],
"instance": "",
"name": "Torus",
"outputs": [
{
"sdf3d": "length($(name_uv)_q)-$r",
"type": "sdf3d"
}
],
"parameters": [
{
"default": 0.5,
"label": "R",
"max": 1,
"min": 0,
"name": "R",
"step": 0.01,
"type": "float"
},
{
"default": 0.1,
"label": "r",
"max": 0.5,
"min": 0,
"name": "r",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
}

View File

@ -25,8 +25,8 @@
"name": "sdLine",
"outputs": [
{
"f": "sdLine($uv, vec2($ax, $ay), vec2($bx, $by))",
"type": "f"
"sdf2d": "sdLine($uv, vec2($ax, $ay), vec2($bx, $by))",
"type": "sdf2d"
}
],
"parameters": [

View File

@ -9,7 +9,7 @@
"cy": 0,
"h": 0.2,
"r": 0.3,
"w": 0.3
"w": 0.5
},
"shader_model": {
"code": "",
@ -21,8 +21,8 @@
"name": "sdRhombus",
"outputs": [
{
"f": "sdRhombus($uv-0.5*vec2($cx+1.0, $cy+1.0), vec2($w, $h))",
"type": "f"
"sdf2d": "sdRhombus($uv-0.5*vec2($cx+1.0, $cy+1.0), vec2($w, $h))",
"type": "sdf2d"
}
],
"parameters": [

View File

@ -11,26 +11,26 @@
"h": 0.08,
"k": 0.15,
"op": 0,
"r": 0.2,
"r": 0.1,
"w": 0.28
},
"shader_model": {
"code": "",
"global": "float sdSmoothUnion( float d1, float d2, float k ) {\n float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );\n return mix( d2, d1, h ) - k*h*(1.0-h); }\n\nfloat sdSmoothSubtraction( float d1, float d2, float k ) {\n float h = clamp( 0.5 - 0.5*(d2+d1)/k, 0.0, 1.0 );\n return mix( d2, -d1, h ) + k*h*(1.0-h); }\n\nfloat sdSmoothIntersection( float d1, float d2, float k ) {\n float h = clamp( 0.5 - 0.5*(d2-d1)/k, 0.0, 1.0 );\n return mix( d2, d1, h ) + k*h*(1.0-h); }\n",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in",
"type": "f"
"type": "sdf2d"
}
],
"instance": "",
"name": "sdRoundedShape",
"outputs": [
{
"f": "$in($uv) - $r",
"type": "f"
"sdf2d": "$in($uv)-$r",
"type": "sdf2d"
}
],
"parameters": [

View File

@ -0,0 +1,47 @@
{
"name": "sdshow",
"node_position": {
"x": 0,
"y": 0
},
"parameters": {
"bevel": 0.1,
"cx": 0,
"cy": 0,
"h": 0.08,
"r": 0.3,
"w": 0.28
},
"shader_model": {
"code": "",
"global": "",
"inputs": [
{
"default": "0.0",
"label": "",
"name": "in",
"type": "sdf2d"
}
],
"instance": "",
"name": "sdShow",
"outputs": [
{
"f": "clamp(-$in($uv)/max($bevel, 0.00001), 0.0, 1.0)",
"type": "f"
}
],
"parameters": [
{
"default": 0,
"label": "Bevel",
"max": 1,
"min": 0,
"name": "bevel",
"step": 0.01,
"type": "float"
}
]
},
"type": "shader"
}

View File

@ -9,7 +9,7 @@
"cx": 0,
"cy": 0,
"h": 0.08,
"k": 0.1,
"k": 0.04,
"op": 0,
"r": 0.3,
"w": 0.28
@ -22,21 +22,21 @@
"default": "0.0",
"label": "",
"name": "in1",
"type": "f"
"type": "sdf2d"
},
{
"default": "0.0",
"label": "",
"name": "in2",
"type": "f"
"type": "sdf2d"
}
],
"instance": "",
"name": "sdSmoothBoolean",
"outputs": [
{
"f": "sdSmooth$op($in1($uv), $in2($uv), $k)",
"type": "f"
"sdf2d": "sdSmooth$op($in1($uv), $in2($uv), $k)",
"type": "sdf2d"
}
],
"parameters": [

View File

@ -15,9 +15,14 @@ func set_model_data(data) -> void:
$Type.selected = 1
elif data.type == "rgba":
$Type.selected = 2
elif data.type == "sdf2d":
$Type.selected = 3
elif data.type == "sdf3d":
$Type.selected = 4
else:
$Type.selected = 0
$Default.text = data.default
$Function.pressed = data.has("function") and data.function
func get_model_data() -> Dictionary:
var data = { name=$Name.text, label=$Label.text, default=$Default.text }
@ -25,8 +30,14 @@ func get_model_data() -> Dictionary:
data.type = "rgb"
elif $Type.selected == 2:
data.type = "rgba"
elif $Type.selected == 3:
data.type = "sdf2d"
elif $Type.selected == 4:
data.type = "sdf3d"
else:
data.type = "f"
if $Function.pressed:
data.function = true
return data
func _on_Delete_pressed() -> void:

View File

@ -66,7 +66,7 @@ margin_bottom = 24.0
rect_min_size = Vector2( 102, 0 )
hint_tooltip = "Input flag"
text = "GreyScale"
items = [ "GreyScale", null, false, 0, null, "Color", null, false, 1, null, "RGBA", null, false, -1, null ]
items = [ "GreyScale", null, false, 0, null, "Color", null, false, 1, null, "RGBA", null, false, 2, null, "SDF2D", null, false, 3, null, "SDF3D", null, false, 4, null ]
selected = 0
[node name="Default" type="LineEdit" parent="."]
@ -77,6 +77,12 @@ rect_min_size = Vector2( 70, 0 )
hint_tooltip = "Default value"
size_flags_horizontal = 3
text = "0.0"
[node name="Function" type="CheckBox" parent="."]
margin_left = 418.0
margin_right = 501.0
margin_bottom = 24.0
text = "Function"
[connection signal="pressed" from="Delete" to="." method="_on_Delete_pressed"]
[connection signal="pressed" from="Up" to="." method="_on_Up_pressed"]
[connection signal="pressed" from="Down" to="." method="_on_Down_pressed"]

View File

@ -15,6 +15,12 @@ func set_model_data(data) -> void:
elif data.has("rgba"):
$Type.selected = 2
$Value.text = data.rgba
elif data.has("sdf2d"):
$Type.selected = 3
$Value.text = data.sdf2d
elif data.has("sdf3d"):
$Type.selected = 4
$Value.text = data.sdf3d
elif data.has("f"):
$Type.selected = 0
$Value.text = data.f
@ -24,6 +30,10 @@ func get_model_data() -> Dictionary:
return { rgb=$Value.text }
elif $Type.selected == 2:
return { rgba=$Value.text }
elif $Type.selected == 3:
return { sdf2d=$Value.text }
elif $Type.selected == 4:
return { sdf3d=$Value.text }
else:
return { f=$Value.text }

View File

@ -58,7 +58,7 @@ margin_bottom = 25.0
rect_min_size = Vector2( 102, 0 )
hint_tooltip = "Input flag"
text = "GreyScale"
items = [ "GreyScale", null, false, 0, null, "Color", null, false, 1, null, "RGBA", null, false, -1, null ]
items = [ "GreyScale", null, false, 0, null, "Color", null, false, 1, null, "RGBA", null, false, 2, null, "SDF2D", null, false, 3, null, "SDF3D", null, false, 4, null ]
selected = 0
[node name="Value" type="LineEdit" parent="."]