Tiler node for mat_maker_gd.

This commit is contained in:
Relintai 2021-11-05 22:15:30 +01:00
parent b78f3c8358
commit 1b9450cc74
2 changed files with 334 additions and 187 deletions

View File

@ -92,7 +92,8 @@ const Commons = preload("res://addons/mat_maker_gd/nodes/common/commons.gd")
# for (int dx = -overlap; dx <= overlap; ++dx) {\n\t\t
# for (int dy = -overlap; dy <= overlap; ++dy) {\n\t\t\t
# vec2 pos = fract((floor(uv*tile)+vec2(float(dx), float(dy))+vec2(0.5))/tile-vec2(0.5));\n\t\t\t
# vec2 seed = rand2(pos+_seed);\n\t\t\trc1 = rand3(seed);\n\t\t\t
# vec2 seed = rand2(pos+_seed);\n\t\t\t
# rc1 = rand3(seed);\n\t\t\t
# pos = fract(pos+vec2($fixed_offset/tile.x, 0.0)*floor(mod(pos.y*tile.y, 2.0))+$offset*seed/tile);\n\t\t\t
# float mask = $mask(fract(pos+vec2(0.5)));\n\t\t\t
#
@ -124,194 +125,34 @@ const Commons = preload("res://addons/mat_maker_gd/nodes/common/commons.gd")
# return vec4(rc, c);\n
#}
#Inputs:
#in, float, default: 0, - The input image or atlas of 4 or 16 input images
#Mask, float, default: 1, - The mask applied to the pattern
# "code": "vec4 $(name_uv)_rch = tiler_$(name)($uv, vec2($tx, $ty), int($overlap), vec2(float($seed)));",
# "inputs": [
# {
# "default": "0.0",
# "function": true,
# "label": "",
# "longdesc": "The input image or atlas of 4 or 16 input images",
# "name": "in",
# "shortdesc": "Input",
# "type": "f"
# },
# {
# "default": "1.0",
# "function": true,
# "label": "",
# "longdesc": "The mask applied to the pattern",
# "name": "mask",
# "shortdesc": "Mask",
# "type": "f"
# }
# ],
# "instance": "vec4 tiler_$(name)(vec2 uv, vec2 tile, int overlap, vec2 _seed) {\n\tfloat c = 0.0;\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tfor (int dx = -overlap; dx <= overlap; ++dx) {\n\t\tfor (int dy = -overlap; dy <= overlap; ++dy) {\n\t\t\tvec2 pos = fract((floor(uv*tile)+vec2(float(dx), float(dy))+vec2(0.5))/tile-vec2(0.5));\n\t\t\tvec2 seed = rand2(pos+_seed);\n\t\t\trc1 = rand3(seed);\n\t\t\tpos = fract(pos+vec2($fixed_offset/tile.x, 0.0)*floor(mod(pos.y*tile.y, 2.0))+$offset*seed/tile);\n\t\t\tfloat mask = $mask(fract(pos+vec2(0.5)));\n\t\t\tif (mask > 0.01) {\n\t\t\t\tvec2 pv = fract(uv - pos)-vec2(0.5);\n\t\t\t\tseed = rand2(seed);\n\t\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251;\n\t\t\t\tfloat ca = cos(angle);\n\t\t\t\tfloat sa = sin(angle);\n\t\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\t\tpv += vec2(0.5);\n\t\t\t\tseed = rand2(seed);\n\t\t\t\tvec2 clamped_pv = clamp(pv, vec2(0.0), vec2(1.0));\n\t\t\t\tif (pv.x != clamped_pv.x || pv.y != clamped_pv.y) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t$select_inputs\n\t\t\t\tfloat c1 = $in.variation(pv, $variations ? seed.x : 0.0)*mask*(1.0-$value*seed.x);\n\t\t\t\tc = max(c, c1);\n\t\t\t\trc = mix(rc, rc1, step(c, c1));\n\t\t\t}\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}",
# "outputs": [
# {
# "f": "$(name_uv)_rch.a",
# "longdesc": "Shows the generated pattern",
# "shortdesc": "Output",
# "type": "f"
# },
# {
# "longdesc": "Shows a random color for each instance of the input image",
# "rgb": "$(name_uv)_rch.rgb",
# "shortdesc": "Instance map",
# "type": "rgb"
# }
# ],
# "parameters": [
# {
# "control": "None",
# "default": 4,
# "label": "Tile X",
# "longdesc": "The number of columns of the tiles pattern",
# "max": 64,
# "min": 1,
# "name": "tx",
# "shortdesc": "Tile.x",
# "step": 1,
# "type": "float"
# },
# {
# "control": "None",
# "default": 4,
# "label": "Tile Y",
# "longdesc": "The number of rows of the tiles pattern",
# "max": 64,
# "min": 1,
# "name": "ty",
# "shortdesc": "Tile.y",
# "step": 1,
# "type": "float"
# },
# {
# "control": "None",
# "default": 1,
# "label": "Overlap",
# "longdesc": "The number of neighbour tiles an instance of the input image can overlap. Set this parameter to the lowest value that generates the expected result (where all instances are fully visible) to improve performance.",
# "max": 5,
# "min": 0,
# "name": "overlap",
# "shortdesc": "Overlap",
# "step": 1,
# "type": "float"
# },
# {
# "default": 0,
# "label": "Inputs",
# "longdesc": "The input type of the node:\n- 1: single image\n- 4: atlas of 4 images\n- 16: atlas of 16 images\nAtlases can be created using the Tile2x2 node.",
# "name": "select_inputs",
# "shortdesc": "Input",
# "type": "enum",
# "values": [
# {
# "name": "1",
# "value": " "
# },
# {
# "name": "4",
# "value": "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));"
# },
# {
# "name": "16",
# "value": "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));"
# }
# ]
# },
# {
# "control": "None",
# "default": 1,
# "label": "Scale X",
# "longdesc": "The scale of input images on the X axis",
# "max": 2,
# "min": 0,
# "name": "scale_x",
# "shortdesc": "Scale.x",
# "step": 0.01,
# "type": "float"
# },
# {
# "control": "None",
# "default": 1,
# "label": "Scale Y",
# "longdesc": "The scale of input images on the Y axis",
# "max": 2,
# "min": 0,
# "name": "scale_y",
# "shortdesc": "Scale.y",
# "step": 0.01,
# "type": "float"
# },
# {
# "control": "None",
# "default": 0.5,
# "label": "Fixed Offset",
# "longdesc": "The relative offset of odd rows",
# "max": 1,
# "min": 0,
# "name": "fixed_offset",
# "shortdesc": "FixedOffset",
# "step": 0.01,
# "type": "float"
# },
# {
# "control": "None",
# "default": 0.5,
# "label": "Rnd Offset",
# "max": 1,
# "min": 0,
# "name": "offset",
# "step": 0.01,
# "type": "float"
# },
# {
# "control": "None",
# "default": 0,
# "label": "Rnd Rotate",
# "longdesc": "The random rotation applied to each image instance",
# "max": 180,
# "min": 0,
# "name": "rotate",
# "shortdesc": "RndRotate",
# "step": 0.1,
# "type": "float"
# },
# {
# "control": "None",
# "default": 0,
# "label": "Rnd Scale",
# "longdesc": "The random scale applied to each image instance",
# "max": 1,
# "min": 0,
# "name": "scale",
# "shortdesc": "RndScale",
# "step": 0.01,
# "type": "float"
# },
# {
# "control": "None",
# "default": 0.5,
# "label": "Rnd Value",
# "longdesc": "The random greyscale value applied to each image instance",
# "max": 1,
# "min": 0,
# "name": "value",
# "shortdesc": "RndValue",
# "step": 0.01,
# "type": "float"
# },
# {
# "default": false,
# "label": "Variations",
# "longdesc": "Check to tile variations of the input",
# "name": "variations",
# "shortdesc": "Variations",
# "type": "boolean"
# }
# ],
#Outputs:
#Output, float, Shows the generated pattern
#$(name_uv)_rch.a
#Instance map, rgb, Shows a random color for each instance of the input image
#$(name_uv)_rch.rgb
#select_inputs enum
#1, " "
#4, "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));"
#16, "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));"
#Parameters:
#tile, Vector2, default 4, min:1, max:64, step:1 - The number of columns of the tiles pattern
#overlap, float, default 1, min 0, max 5, step 1 - The number of neighbour tiles an instance of the input image can overlap. Set this parameter to the lowest value that generates the expected result (where all instances are fully visible) to improve performance.
#select_inputs (Inputs), enum, default 0, values 1, 4, 16
#scale, Vector2, default 1, min:0, max:2, step:0.01 - "The scale of input images on the X axis
#fixed_offset, float, default 0.5, min 0, max 1, step 0.01 - The relative offset of odd rows
#offset (rnd_offset), float, default 0.5, min 0, max 1, step 0.01
#rotate (rnd_rotate), float, default 0, min 0, max 180, step 0.1
#scale (rnd_scale), float, default 0.5, min 0, max 1, step 0.01 - The random scale applied to each image instance
#value (rnd_value), float, default 0.5, min 0, max 1, step 0.01 - The random greyscale value applied to each image instance
#variations, bool, default false, (disabled) - Check to tile variations of the input
#----------------------
#tiler_advanced.mmg

View File

@ -0,0 +1,306 @@
tool
extends MMNode
const Commons = preload("res://addons/mat_maker_gd/nodes/common/commons.gd")
export(Resource) var input : Resource
export(Resource) var in_mask : Resource
export(Resource) var output : Resource
export(Resource) var instance_map : Resource
export(Vector2) var tile : Vector2 = Vector2(4, 4)
export(float) var overlap : float = 1
export(int, "1,4,16") var select_inputs : int = 0
export(Vector2) var scale : Vector2 = Vector2(0.5, 0.5)
export(float) var fixed_offset : float = 0
export(float) var rnd_offset : float = 0.25
export(float) var rnd_rotate : float = 45
export(float) var rnd_scale : float = 0.2
export(float) var rnd_value : float = 2
export(bool) var variations : bool = false
func _init_properties():
if !input:
input = MMNodeUniversalProperty.new()
input.default_type = MMNodeUniversalProperty.MMNodeUniversalPropertyDefaultType.DEFAULT_TYPE_FLOAT
input.set_default_value(0)
input.input_slot_type = MMNodeUniversalProperty.SlotTypes.SLOT_TYPE_UNIVERSAL
input.slot_name = ">>> Input "
if !in_mask:
in_mask = MMNodeUniversalProperty.new()
in_mask.default_type = MMNodeUniversalProperty.MMNodeUniversalPropertyDefaultType.DEFAULT_TYPE_FLOAT
in_mask.set_default_value(1)
in_mask.input_slot_type = MMNodeUniversalProperty.SlotTypes.SLOT_TYPE_UNIVERSAL
in_mask.slot_name = ">>> Mask "
if !output:
output = MMNodeUniversalProperty.new()
output.default_type = MMNodeUniversalProperty.MMNodeUniversalPropertyDefaultType.DEFAULT_TYPE_IMAGE
output.output_slot_type = MMNodeUniversalProperty.SlotTypes.SLOT_TYPE_IMAGE
if !instance_map:
instance_map = MMNodeUniversalProperty.new()
instance_map.default_type = MMNodeUniversalProperty.MMNodeUniversalPropertyDefaultType.DEFAULT_TYPE_IMAGE
instance_map.output_slot_type = MMNodeUniversalProperty.SlotTypes.SLOT_TYPE_IMAGE
register_input_property(input)
register_input_property(in_mask)
register_output_property(output)
register_output_property(instance_map)
func _register_methods(mm_graph_node) -> void:
mm_graph_node.add_slot_label_universal(input)
mm_graph_node.add_slot_label_universal(in_mask)
mm_graph_node.add_slot_texture_universal(output)
mm_graph_node.add_slot_texture_universal(instance_map)
mm_graph_node.add_slot_vector2("get_tile", "set_tile", "Tile", 1)
mm_graph_node.add_slot_float("get_overlap", "set_overlap", "Overlap", 1)
mm_graph_node.add_slot_enum("get_select_inputs", "set_select_inputs", "Select inputs", [ "1", "4", "16" ])
mm_graph_node.add_slot_vector2("get_scale", "set_scale", "Scale", 0.01)
mm_graph_node.add_slot_float("get_fixed_offset", "set_fixed_offset", "Fixed Offset", 0.01)
mm_graph_node.add_slot_float("get_rnd_offset", "set_rnd_offset", "Rnd Offset", 0.01)
mm_graph_node.add_slot_float("get_rnd_rotate", "set_rnd_rotate", "Rnd Rotate", 0.1)
mm_graph_node.add_slot_float("get_rnd_scale", "set_rnd_scale", "Rnd Scale", 0.01)
mm_graph_node.add_slot_float("get_rnd_value", "set_rnd_value", "Rnd Value", 0.01)
#mm_graph_node.add_slot_bool("get_variations", "set_variations", "Variations")
func _render(material) -> void:
var output_img : Image = Image.new()
var instance_map_img : Image = Image.new()
output_img.create(material.image_size.x, material.image_size.y, false, Image.FORMAT_RGBA8)
instance_map_img.create(material.image_size.x, material.image_size.y, false, Image.FORMAT_RGBA8)
output_img.lock()
instance_map_img.lock()
var w : float = material.image_size.x
var h : float = material.image_size.y
var pseed : float = randf() + randi()
var ps : float = 1.0 / float(pseed)
var ix : int = int(material.image_size.x)
var iy : int = int(material.image_size.y)
for x in range(ix):
for y in range(iy):
var uv : Vector2 = Vector2(x / w, y / h)
#vec4 $(name_uv)_rch = tiler_$(name)($uv, vec2($tx, $ty), int($overlap), vec2(float($seed)))
var rch : Color = tiler_calc(uv, tile, overlap, Vector2(ps, ps))
#Output, float, Shows the generated pattern
#$(name_uv)_rch.a
var output_img_col : Color = Color(rch.a, rch.a, rch.a, 1)
#Instance map, rgb, Shows a random color for each instance of the input image
#$(name_uv)_rch.rgb
var instance_map_img_col : Color = Color(rch.r, rch.g, rch.b, 1)
output_img.set_pixel(x, y, output_img_col)
instance_map_img.set_pixel(x, y, instance_map_img_col)
output_img.unlock()
instance_map_img.unlock()
output.set_value(output_img)
instance_map.set_value(instance_map_img)
func get_value_for(uv : Vector2, pseed : int) -> Color:
return Color()
#tile
func get_tile() -> Vector2:
return tile
func set_tile(val : Vector2) -> void:
tile = val
set_dirty(true)
#overlap
func get_overlap() -> float:
return overlap
func set_overlap(val : float) -> void:
overlap = val
set_dirty(true)
#select_inputs
func get_select_inputs() -> int:
return select_inputs
func set_select_inputs(val : int) -> void:
select_inputs = val
set_dirty(true)
#scale
func get_scale() -> Vector2:
return scale
func set_scale(val : Vector2) -> void:
scale = val
set_dirty(true)
#fixed_offset
func get_fixed_offset() -> float:
return fixed_offset
func set_fixed_offset(val : float) -> void:
fixed_offset = val
set_dirty(true)
#rnd_offset
func get_rnd_offset() -> float:
return rnd_offset
func set_rnd_offset(val : float) -> void:
rnd_offset = val
set_dirty(true)
#rnd_rotate
func get_rnd_rotate() -> float:
return rnd_rotate
func set_rnd_rotate(val : float) -> void:
rnd_rotate = val
set_dirty(true)
#rnd_scale
func get_rnd_scale() -> float:
return rnd_scale
func set_rnd_scale(val : float) -> void:
rnd_scale = val
set_dirty(true)
#rnd_value
func get_rnd_value() -> float:
return rnd_value
func set_rnd_value(val : float) -> void:
rnd_value = val
set_dirty(true)
#variations
func get_variations() -> bool:
return variations
func set_variations(val : bool) -> void:
variations = val
set_dirty(true)
#----------------------
#tiler.mmg
#Tiles several occurences of an input image while adding randomness.
#instance
#vec4 tiler_$(name)(vec2 uv, vec2 tile, int overlap, vec2 _seed) {
# float c = 0.0;
# vec3 rc = vec3(0.0);
# vec3 rc1;
# for (int dx = -overlap; dx <= overlap; ++dx) {
# for (int dy = -overlap; dy <= overlap; ++dy) {
# vec2 pos = fract((floor(uv*tile)+vec2(float(dx), float(dy))+vec2(0.5))/tile-vec2(0.5));
# vec2 seed = rand2(pos+_seed);
# rc1 = rand3(seed);
# pos = fract(pos+vec2($fixed_offset/tile.x, 0.0)*floor(mod(pos.y*tile.y, 2.0))+$offset*seed/tile);
# float mask = $mask(fract(pos+vec2(0.5)));
#
# if (mask > 0.01) {
# vec2 pv = fract(uv - pos)-vec2(0.5);
# seed = rand2(seed);
# float angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251;
# float ca = cos(angle);
# float sa = sin(angle);
# pv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);
# pv *= (seed.y-0.5)*2.0*$scale+1.0;
# pv /= vec2($scale_x, $scale_y);
# pv += vec2(0.5);
# seed = rand2(seed);
# vec2 clamped_pv = clamp(pv, vec2(0.0), vec2(1.0));
# if (pv.x != clamped_pv.x || pv.y != clamped_pv.y) {
# continue;
# }
#
# $select_inputs
#
# float c1 = $in.variation(pv, $variations ? seed.x : 0.0)*mask*(1.0-$value*seed.x);
# c = max(c, c1);
# rc = mix(rc, rc1, step(c, c1));
# }
# }
# }
#
# return vec4(rc, c);
#}
#select_inputs enum
#1, " "
#4, "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));"
#16, "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));"
func tiler_calc(uv : Vector2, tile : Vector2, overlap : int, _seed : Vector2) -> Color:
var c : float = 0.0
var rc : Vector3 = Vector3()
var rc1 : Vector3 = Vector3()
for dx in range(-overlap, overlap): #for (int dx = -overlap; dx <= overlap; ++dx) {
for dy in range(-overlap, overlap): #for (int dy = -overlap; dy <= overlap; ++dy) {
var pos : Vector2 = Commons.fractv2((Commons.floorv2(uv * tile) + Vector2(dx, dy) + Vector2(0.5, 0.5)) / tile - Vector2(0.5, 0.5))
var vseed : Vector2 = Commons.rand2(pos+_seed)
rc1 = Commons.rand3(vseed)
pos = Commons.fractv2(pos + Vector2(fixed_offset / tile.x, 0.0) * floor(Commons.modf(pos.y * tile.y, 2.0)) + rnd_offset * vseed / tile)
var mask : float = in_mask.get_value(Commons.fractv2(pos + Vector2(0.5, 0.5)))
if (mask > 0.01):
var pv : Vector2 = Commons.fractv2(uv - pos) - Vector2(0.5, 0.5)
vseed = Commons.rand2(vseed)
var angle : float = (vseed.x * 2.0 - 1.0) * rnd_rotate * 0.01745329251
var ca : float = cos(angle)
var sa : float = sin(angle)
pv = Vector2(ca * pv.x + sa * pv.y, -sa * pv.x + ca * pv.y)
pv *= (vseed.y-0.5) * 2.0 * rnd_scale + 1.0
pv /= scale
pv += Vector2(0.5, 0.5)
vseed = Commons.rand2(vseed)
var clamped_pv : Vector2 = Commons.clampv2(pv, Vector2(), Vector2(1, 1))
if (pv.x != clamped_pv.x || pv.y != clamped_pv.y):
continue
#1, " "
#4, "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));"
#16, "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));"
if select_inputs == 1:
pv = Commons.clampv2(0.5*(pv + Commons.floorv2(Commons.rand2(vseed)*2.0)), Vector2(), Vector2(1, 1));
elif select_inputs == 2:
pv = Commons.clampv2(0.25*(pv + Commons.floorv2(Commons.rand2(vseed)*4.0)), Vector2(), Vector2(1, 1));
#float c1 = $in.variation(pv, $variations ? vseed.x : 0.0) * mask * (1.0-$value*vseed.x)
var c1 : float = input.get_value(pv) * mask * (1.0 - rnd_value * vseed.x)
c = max(c, c1)
rc = lerp(rc, rc1, Commons.step(c, c1))
return Color(rc.x, rc.y, rc.z, c)