From 23a32b9bb7e19e179e2516e92ae5f39b654f1a36 Mon Sep 17 00:00:00 2001 From: Kasper Frandsen Date: Mon, 31 Jan 2022 15:53:50 +0000 Subject: [PATCH 1/3] feat: add custom uv output to tiler and splatter nodes --- .../material_maker/nodes/circle_splatter.mmg | 25 +++-- addons/material_maker/nodes/splatter.mmg | 28 +++-- addons/material_maker/nodes/tiler.mmg | 40 ++++--- .../material_maker/nodes/tiler_advanced.mmg | 25 +++-- .../doc/node_transform_circlesplatter.rst | 102 +++++++++--------- .../doc/node_transform_splatter.rst | 2 +- .../doc/node_transform_tiler_advanced.rst | 4 +- 7 files changed, 136 insertions(+), 90 deletions(-) diff --git a/addons/material_maker/nodes/circle_splatter.mmg b/addons/material_maker/nodes/circle_splatter.mmg index 39313f2f..28c87144 100644 --- a/addons/material_maker/nodes/circle_splatter.mmg +++ b/addons/material_maker/nodes/circle_splatter.mmg @@ -8,19 +8,24 @@ "count": 20, "i_rotate": 0, "i_scale": 0, + "inputs": 0, "radius": 0.4, "rings": 2, "rotate": 0, "scale": 0, "scale_x": 1, "scale_y": 1, - "select_inputs": 0, "spiral": 0, "value": 0 }, + "seed": 0, + "seed_locked": false, "shader_model": { - "code": "vec4 $(name_uv)_rch = splatter_$(name)($uv, int($count), int($rings), vec2(float($seed)));", + "code": "vec3 $(name_uv)_instance_uv = vec3(0.0);\nvec4 $(name_uv)_rch = splatter_$(name)($uv, int($count), int($rings), $(name_uv)_instance_uv, vec2(float($seed)));", "global": "", + "includes": [ + "custom_uv" + ], "inputs": [ { "default": "0.0", @@ -41,7 +46,7 @@ "type": "f" } ], - "instance": "vec4 splatter_$(name)(vec2 uv, int count, int rings, vec2 seed) {\n\tfloat c = 0.0;\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tseed = rand2(seed);\n\tfor (int i = 0; i < count; ++i) {\n\t\tfloat a = -1.57079632679+6.28318530718*float(i)*$rings/float(count);\n\t\tfloat rings_distance = ceil(float(i+1)*float(rings)/float(count))/float(rings);\n\t\tfloat spiral_distance = float(i+1)/float(count);\n\t\tvec2 pos = $radius*mix(rings_distance, spiral_distance, $spiral)*vec2(cos(a), sin(a));\n\t\tfloat mask = $mask(fract(pos-vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = uv-0.5-pos;\n\t\t\trc1 = rand3(seed);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251 + (a+1.57079632679) * $i_rotate;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv /= mix(1.0, float(i+1)/float(count+1), $i_scale);\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$select_inputs\n\t\t\tfloat c1 = $in(pv)*mask*(1.0-$value*seed.x);\n\t\t\tc = max(c, c1);\n\t\t\trc = mix(rc, rc1, step(c, c1));\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}\n", + "instance": "vec4 splatter_$(name)(vec2 uv, int count, int rings, inout vec3 instance_uv, vec2 seed) {\n\tfloat c = 0.0;\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tseed = rand2(seed);\n\tfor (int i = 0; i < count; ++i) {\n\t\tfloat a = -1.57079632679+6.28318530718*float(i)*$rings/float(count);\n\t\tfloat rings_distance = ceil(float(i+1)*float(rings)/float(count))/float(rings);\n\t\tfloat spiral_distance = float(i+1)/float(count);\n\t\tvec2 pos = $radius*mix(rings_distance, spiral_distance, $spiral)*vec2(cos(a), sin(a));\n\t\tfloat mask = $mask(fract(pos-vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = uv-0.5-pos;\n\t\t\trc1 = rand3(seed);\n\t\t\tfloat uv_rand = rand(seed.yx);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251 + (a+1.57079632679) * $i_rotate;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv /= mix(1.0, float(i+1)/float(count+1), $i_scale);\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvec2 full_uv = pv;\n\t\t\tpv = get_from_tileset($inputs, uv_rand, pv);\n\t\t\tfloat c1 = $in(pv)*mask*(1.0-$value*seed.x);\n\t\t\tc = max(c, c1);\n\t\t\trc = mix(rc, rc1, step(c, c1));\n\t\t\tinstance_uv = mix(instance_uv, vec3(full_uv, uv_rand), step(c, c1));\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}\n", "longdesc": "Spreads several occurences of an input image in a circle or spiral pattern.", "name": "Circle Splatter", "outputs": [ @@ -56,6 +61,12 @@ "rgb": "$(name_uv)_rch.rgb", "shortdesc": "Instance map", "type": "rgb" + }, + { + "longdesc": "Per instance UVs. Can be used with Custom UV node.", + "rgb": "$(name_uv)_instance_uv", + "shortdesc": "Instance UV", + "type": "rgb" } ], "parameters": [ @@ -87,21 +98,21 @@ "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", + "name": "inputs", "shortdesc": "Input", "type": "enum", "values": [ { "name": "1", - "value": " " + "value": " 1.0" }, { "name": "4", - "value": "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));" + "value": "2.0" }, { "name": "16", - "value": "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));" + "value": "4.0" } ] }, diff --git a/addons/material_maker/nodes/splatter.mmg b/addons/material_maker/nodes/splatter.mmg index fe3742a9..9b8c74bc 100644 --- a/addons/material_maker/nodes/splatter.mmg +++ b/addons/material_maker/nodes/splatter.mmg @@ -6,16 +6,22 @@ }, "parameters": { "count": 25, + "inputs": 0, "rotate": 0, "scale": 0, "scale_x": 1, "scale_y": 1, - "select_inputs": 0, - "value": 0 + "value": 0, + "variations": false }, + "seed": 0, + "seed_locked": false, "shader_model": { - "code": "vec4 $(name_uv)_rch = splatter_$(name)($uv, int($count), vec2(float($seed)));", + "code": "vec3 $(name_uv)_instance_uv = vec3(0.0);\nvec4 $(name_uv)_rch = splatter_$(name)($uv, int($count), $(name_uv)_instance_uv, vec2(float($seed)));", "global": "", + "includes": [ + "custom_uv" + ], "inputs": [ { "default": "0.0", @@ -36,7 +42,7 @@ "type": "f" } ], - "instance": "vec4 splatter_$(name)(vec2 uv, int count, vec2 seed) {\n\tfloat c = 0.0;\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tfor (int i = 0; i < count; ++i) {\n\t\tseed = rand2(seed);\n\t\trc1 = rand3(seed);\n\t\tfloat mask = $mask(fract(seed+vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = fract(uv - seed)-vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tvec2 clamped_pv = clamp(pv, vec2(0.0), vec2(1.0));\n\t\t\tif (pv.x != clamped_pv.x || pv.y != clamped_pv.y) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$select_inputs\n\t\t\tfloat c1 = $in.variation(pv, $variations ? seed.x : 0.0)*mask*(1.0-$value*seed.x);\n\t\t\tc = max(c, c1);\n\t\t\trc = mix(rc, rc1, step(c, c1));\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}\n", + "instance": "vec4 splatter_$(name)(vec2 uv, int count, inout vec3 instance_uv, vec2 seed) {\n\tfloat c = 0.0;\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tfor (int i = 0; i < count; ++i) {\n\t\tseed = rand2(seed);\n\t\trc1 = rand3(seed);\n\t\tfloat uv_rand = rand(seed.yx);\n\t\tfloat mask = $mask(fract(seed+vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = fract(uv - seed)-vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tvec2 clamped_pv = clamp(pv, vec2(0.0), vec2(1.0));\n\t\t\tif (pv.x != clamped_pv.x || pv.y != clamped_pv.y) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvec2 full_uv = pv;\n\t\t\tpv = get_from_tileset($inputs, uv_rand, pv);\n\t\t\tfloat c1 = $in.variation(pv, $variations ? seed.x : 0.0)*mask*(1.0-$value*seed.x);\n\t\t\tc = max(c, c1);\n\t\t\trc = mix(rc, rc1, step(c, c1));\n\t\t\tinstance_uv = mix(instance_uv, vec3(full_uv, uv_rand), step(c, c1));\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}\n", "longdesc": "Spreads several occurences of an input image randomly.", "name": "Splatter", "outputs": [ @@ -51,6 +57,12 @@ "rgb": "$(name_uv)_rch.rgb", "shortdesc": "Instance map", "type": "rgb" + }, + { + "longdesc": "Per instance UVs. Can be used with Custom UV node.", + "rgb": "$(name_uv)_instance_uv", + "shortdesc": "Instance UV", + "type": "rgb" } ], "parameters": [ @@ -70,21 +82,21 @@ "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", + "name": "inputs", "shortdesc": "Input", "type": "enum", "values": [ { "name": "1", - "value": " " + "value": " 1.0" }, { "name": "4", - "value": "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));" + "value": "2.0" }, { "name": "16", - "value": "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));" + "value": "4.0" } ] }, diff --git a/addons/material_maker/nodes/tiler.mmg b/addons/material_maker/nodes/tiler.mmg index d130d523..b5aa73c2 100644 --- a/addons/material_maker/nodes/tiler.mmg +++ b/addons/material_maker/nodes/tiler.mmg @@ -6,20 +6,26 @@ }, "parameters": { "fixed_offset": 0, - "offset": 1, - "overlap": 1, - "rotate": 180, - "scale": 0.5, + "inputs": 0, + "offset": 0.25, + "overlap": 2, + "rotate": 45, + "scale": 0.2, "scale_x": 0.5, "scale_y": 0.5, - "select_inputs": 0, - "tx": 20, - "ty": 20, - "value": 2 + "tx": 4, + "ty": 4, + "value": 1, + "variations": false }, + "seed": 0, + "seed_locked": false, "shader_model": { - "code": "vec4 $(name_uv)_rch = tiler_$(name)($uv, vec2($tx, $ty), int($overlap), vec2(float($seed)));", + "code": "vec3 $(name_uv)_instance_uv = vec3(0.0);\nvec4 $(name_uv)_rch = tiler_$(name)($uv, vec2($tx, $ty), int($overlap), $(name_uv)_instance_uv, vec2(float($seed)));", "global": "", + "includes": [ + "custom_uv" + ], "inputs": [ { "default": "0.0", @@ -40,7 +46,7 @@ "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 = uv*tile+vec2(float(dx), float(dy)); pos = fract((floor(mod(pos, tile))+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}", + "instance": "vec4 tiler_$(name)(vec2 uv, vec2 tile, int overlap, inout vec3 instance_uv, 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 = uv*tile+vec2(float(dx), float(dy)); pos = fract((floor(mod(pos, tile))+vec2(0.5))/tile)-vec2(0.5);\n\t\t\tvec2 seed = rand2(pos+_seed);\n\t\t\trc1 = rand3(seed);\n\t\t\tfloat uv_rand = rand(seed.yx);\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\tvec2 full_uv = pv;\n\t\t\t\tpv = get_from_tileset($inputs, uv_rand, pv);\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\tinstance_uv = mix(instance_uv, vec3(full_uv, uv_rand), step(c, c1));\n\t\t\t}\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}", "longdesc": "Tiles several occurences of an input image while adding randomness.", "name": "Tiler", "outputs": [ @@ -55,6 +61,12 @@ "rgb": "$(name_uv)_rch.rgb", "shortdesc": "Instance map", "type": "rgb" + }, + { + "longdesc": "Per instance UVs. Can be used with Custom UV node.", + "rgb": "$(name_uv)_instance_uv", + "shortdesc": "Instance UV", + "type": "rgb" } ], "parameters": [ @@ -98,21 +110,21 @@ "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", + "name": "inputs", "shortdesc": "Input", "type": "enum", "values": [ { "name": "1", - "value": " " + "value": " 1.0" }, { "name": "4", - "value": "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));" + "value": "2.0" }, { "name": "16", - "value": "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));" + "value": "4.0" } ] }, diff --git a/addons/material_maker/nodes/tiler_advanced.mmg b/addons/material_maker/nodes/tiler_advanced.mmg index 13ae235d..4c884d6c 100644 --- a/addons/material_maker/nodes/tiler_advanced.mmg +++ b/addons/material_maker/nodes/tiler_advanced.mmg @@ -5,22 +5,25 @@ "y": 0 }, "parameters": { + "inputs": 0, "overlap": 1, "rotate": 0, "scale_x": 1, "scale_y": 1, - "select_inputs": 0, "translate_x": 0, "translate_y": 0, "tx": 4, "ty": 4, "variations": false }, - "seed": 0.488938, + "seed": 0, "seed_locked": false, "shader_model": { - "code": "vec4 $(name_uv)_rch = tiler_$(name)($uv, vec2($tx, $ty), int($overlap), float($seed));", + "code": "vec3 $(name_uv)_instance_uv = vec3(0.0);\nvec4 $(name_uv)_rch = tiler_$(name)($uv, vec2($tx, $ty), int($overlap), $(name_uv)_instance_uv, float($seed));", "global": "", + "includes": [ + "custom_uv" + ], "inputs": [ { "default": "0.0", @@ -102,7 +105,7 @@ "type": "f" } ], - "instance": "vec4 tiler_$(name)(vec2 uv, vec2 tile, int overlap, float _seed) {\n\tfloat c = 0.0;\n\tvec2 map_uv = vec2(0.0);\n\tfor (int dx = -overlap; dx <= overlap; ++dx) {\n\t\tfor (int dy = -overlap; dy <= overlap; ++dy) {\n\t\t\tvec2 pos = uv*tile+vec2(float(dx), float(dy)); pos = fract((floor(mod(pos, tile))+vec2(0.5))/tile)-vec2(0.5);\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\tpos = fract(pos+vec2(0.5));\n\t\t\t\tpv -= vec2($translate_x*$tr_x(pos), $translate_y*$tr_y(pos))/tile;\n\t\t\t\tfloat angle = $r(pos) * $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 /= vec2($scale_x*$sc_x(pos), $scale_y*$sc_y(pos));\n\t\t\t\tpv += vec2(0.5);\n\t\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tvec2 seed = rand2(vec2(_seed)+pos);\n\t\t\t\t$select_inputs\n\t\t\t\tfloat c1 = $in.variation(pv, $variations ? seed.x : 0.0)*mask;\n\t\t\t\tc = max(c, c1);\n\t\t\t\tmap_uv = mix(map_uv, pos, step(c, c1));\n\t\t\t}\n\t\t}\n\t}\n\treturn vec4(map_uv, 0.0, c);\n}", + "instance": "vec4 tiler_$(name)(vec2 uv, vec2 tile, int overlap, inout vec3 instance_uv, float _seed) {\n\tfloat c = 0.0;\n\tvec2 map_uv = vec2(0.0);\n\tfor (int dx = -overlap; dx <= overlap; ++dx) {\n\t\tfor (int dy = -overlap; dy <= overlap; ++dy) {\n\t\t\tvec2 pos = uv*tile+vec2(float(dx), float(dy)); pos = fract((floor(mod(pos, tile))+vec2(0.5))/tile)-vec2(0.5);\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\tpos = fract(pos+vec2(0.5));\n\t\t\t\tpv -= vec2($translate_x*$tr_x(pos), $translate_y*$tr_y(pos))/tile;\n\t\t\t\tfloat angle = $r(pos) * $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 /= vec2($scale_x*$sc_x(pos), $scale_y*$sc_y(pos));\n\t\t\t\tpv += vec2(0.5);\n\t\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tvec2 seed = rand2(vec2(_seed)+pos);\n\t\t\t\tfloat uv_rand = rand(seed.yx);\n\t\t\t\tvec2 full_uv = pv;\n\t\t\t\tpv = get_from_tileset($inputs, uv_rand, pv);\n\t\t\t\tfloat c1 = $in.variation(pv, $variations ? seed.x : 0.0)*mask;\n\t\t\t\tc = max(c, c1);\n\t\t\t\tmap_uv = mix(map_uv, pos, step(c, c1));\n\t\t\t\tinstance_uv = mix(instance_uv, vec3(full_uv, uv_rand), step(c, c1));\n\t\t\t}\n\t\t}\n\t}\n\treturn vec4(map_uv, 0.0, c);\n}", "longdesc": "Tiles several occurences of an input image while adding randomness.", "name": "Advanced Tiler", "outputs": [ @@ -123,6 +126,12 @@ "rgba": "$color2($(name_uv)_rch.rg)", "shortdesc": "Instance map 2", "type": "rgba" + }, + { + "longdesc": "Per instance UVs. Can be used with Custom UV node.", + "rgb": "$(name_uv)_instance_uv", + "shortdesc": "Instance UV", + "type": "rgb" } ], "parameters": [ @@ -166,21 +175,21 @@ "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", + "name": "inputs", "shortdesc": "Input", "type": "enum", "values": [ { "name": "1", - "value": " " + "value": " 1.0" }, { "name": "4", - "value": "pv = clamp(0.5*(pv+floor(rand2(seed)*2.0)), vec2(0.0), vec2(1.0));" + "value": "2.0" }, { "name": "16", - "value": "pv = clamp(0.25*(pv+floor(rand2(seed)*4.0)), vec2(0.0), vec2(1.0));" + "value": "4.0" } ] }, diff --git a/material_maker/doc/node_transform_circlesplatter.rst b/material_maker/doc/node_transform_circlesplatter.rst index 4f1a7538..29f86e6d 100644 --- a/material_maker/doc/node_transform_circlesplatter.rst +++ b/material_maker/doc/node_transform_circlesplatter.rst @@ -1,51 +1,51 @@ -Circle Splatter node -~~~~~~~~~~~~~~~~~~~~ - -The **Circle Splatter** node splats several instances of its input around a circle -or a spiral. -Overlapping instances are mixed with each other using a *lighten* filter. - -The **Circle Splatter** also has a color version whose input is in RGBA format. - -.. image:: images/node_transform_circlesplatter.png - :align: center - -Inputs -++++++ - -The **Circle Splatter** node accepts two inputs: - -* The *Source* inputs is the image to be splat into the output. - -* The *Mask* input is a greyscale image that is used as a mask and affects each instance's value. - -Outputs -+++++++ - -The **Circle Splatter** node outputs the splat image. - -The greyscale splatter has a secondary output that assigns a random color to each splat instance. - -Parameters -++++++++++ - -The **Circle Splatter** node accepts the following parameters: - -* *Count*, the number of instances of the source image in the result, including those canceled by the mask. -* *Rings*, the number of rings of the circle or spiral pattern. -* *Inputs* is the number of alternate shapes in the input (1, 4 or 16). Images containing several - shapes can easily be created using the **Tile2x2** node. -* *Scale X and Scale Y* are the scale along X and Y axes applied to each instance. -* *Radius* is the radius of the outer circle (or distance to center of the outer instance when a spiral is generated) -* *Spiral* can be used to select between a circle or a spiral pattern (or anything in between) -* *IncRotate* is the rotation increment applied to each instance. -* *IncScale* is the scale increment applied to each instance. -* *RndRotate* is the maximum angle of the random rotation applied to each instance. -* *RndScale* is the amount of random scaling applied to each instance. -* *RndValue* is the amount of random value applied to each instance. - -Example images -++++++++++++++ - -.. image:: images/node_transform_circlesplatter_samples.png - :align: center +Circle Splatter node +~~~~~~~~~~~~~~~~~~~~ + +The **Circle Splatter** node splats several instances of its input around a circle +or a spiral. +Overlapping instances are mixed with each other using a *lighten* filter. + +The **Circle Splatter** also has a color version whose input is in RGBA format. + +.. image:: images/node_transform_circlesplatter.png + :align: center + +Inputs +++++++ + +The **Circle Splatter** node accepts two inputs: + +* The *Source* inputs is the image to be splat into the output. + +* The *Mask* input is a greyscale image that is used as a mask and affects each instance's value. + +Outputs ++++++++ + +The **Circle Splatter** node outputs the splat image. + +The greyscale circle splatter has two additional outputs, one that assigns a random color to each splat instance and one that assigns a UV layout to each splat instance. + +Parameters +++++++++++ + +The **Circle Splatter** node accepts the following parameters: + +* *Count*, the number of instances of the source image in the result, including those canceled by the mask. +* *Rings*, the number of rings of the circle or spiral pattern. +* *Inputs* is the number of alternate shapes in the input (1, 4 or 16). Images containing several + shapes can easily be created using the **Tile2x2** node. +* *Scale X and Scale Y* are the scale along X and Y axes applied to each instance. +* *Radius* is the radius of the outer circle (or distance to center of the outer instance when a spiral is generated) +* *Spiral* can be used to select between a circle or a spiral pattern (or anything in between) +* *IncRotate* is the rotation increment applied to each instance. +* *IncScale* is the scale increment applied to each instance. +* *RndRotate* is the maximum angle of the random rotation applied to each instance. +* *RndScale* is the amount of random scaling applied to each instance. +* *RndValue* is the amount of random value applied to each instance. + +Example images +++++++++++++++ + +.. image:: images/node_transform_circlesplatter_samples.png + :align: center diff --git a/material_maker/doc/node_transform_splatter.rst b/material_maker/doc/node_transform_splatter.rst index 5e6a5e02..d945246d 100644 --- a/material_maker/doc/node_transform_splatter.rst +++ b/material_maker/doc/node_transform_splatter.rst @@ -23,7 +23,7 @@ Outputs The **Splatter** node outputs the splat image. -The greyscale splatter has a secondary output that assigns a random color to each splat instance. +The greyscale splatter has two additional outputs, one that assigns a random color to each splat instance and one that assigns a UV layout to each splat instance. Parameters ++++++++++ diff --git a/material_maker/doc/node_transform_tiler_advanced.rst b/material_maker/doc/node_transform_tiler_advanced.rst index 75ec85a2..b2d9e66e 100644 --- a/material_maker/doc/node_transform_tiler_advanced.rst +++ b/material_maker/doc/node_transform_tiler_advanced.rst @@ -48,7 +48,9 @@ must be set to 1. Outputs +++++++ -The **Advanced Tiler** node outputs the splat image and 2 instance color maps. +The **Advanced Tiler** node outputs the splat image, 2 instance color maps. + +The greyscale tiler has a fourth output that assigns a UV layout to each tile. Parameters ++++++++++ From cd79a38eb0b44a9dff2b3b4495ae6b28454fab40 Mon Sep 17 00:00:00 2001 From: Kasper Frandsen Date: Sat, 19 Feb 2022 12:13:34 +0000 Subject: [PATCH 2/3] feat: add variations to circle splatter nodes --- addons/material_maker/nodes/circle_splatter.mmg | 11 +++++++++-- .../material_maker/nodes/circle_splatter_color.mmg | 13 +++++++++++-- .../doc/node_transform_circlesplatter.rst | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/addons/material_maker/nodes/circle_splatter.mmg b/addons/material_maker/nodes/circle_splatter.mmg index 28c87144..92dd2655 100644 --- a/addons/material_maker/nodes/circle_splatter.mmg +++ b/addons/material_maker/nodes/circle_splatter.mmg @@ -16,7 +16,8 @@ "scale_x": 1, "scale_y": 1, "spiral": 0, - "value": 0 + "value": 0, + "variations": false }, "seed": 0, "seed_locked": false, @@ -46,7 +47,7 @@ "type": "f" } ], - "instance": "vec4 splatter_$(name)(vec2 uv, int count, int rings, inout vec3 instance_uv, vec2 seed) {\n\tfloat c = 0.0;\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tseed = rand2(seed);\n\tfor (int i = 0; i < count; ++i) {\n\t\tfloat a = -1.57079632679+6.28318530718*float(i)*$rings/float(count);\n\t\tfloat rings_distance = ceil(float(i+1)*float(rings)/float(count))/float(rings);\n\t\tfloat spiral_distance = float(i+1)/float(count);\n\t\tvec2 pos = $radius*mix(rings_distance, spiral_distance, $spiral)*vec2(cos(a), sin(a));\n\t\tfloat mask = $mask(fract(pos-vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = uv-0.5-pos;\n\t\t\trc1 = rand3(seed);\n\t\t\tfloat uv_rand = rand(seed.yx);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251 + (a+1.57079632679) * $i_rotate;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv /= mix(1.0, float(i+1)/float(count+1), $i_scale);\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvec2 full_uv = pv;\n\t\t\tpv = get_from_tileset($inputs, uv_rand, pv);\n\t\t\tfloat c1 = $in(pv)*mask*(1.0-$value*seed.x);\n\t\t\tc = max(c, c1);\n\t\t\trc = mix(rc, rc1, step(c, c1));\n\t\t\tinstance_uv = mix(instance_uv, vec3(full_uv, uv_rand), step(c, c1));\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}\n", + "instance": "vec4 splatter_$(name)(vec2 uv, int count, int rings, inout vec3 instance_uv, vec2 seed) {\n\tfloat c = 0.0;\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tseed = rand2(seed);\n\tfor (int i = 0; i < count; ++i) {\n\t\tfloat a = -1.57079632679+6.28318530718*float(i)*$rings/float(count);\n\t\tfloat rings_distance = ceil(float(i+1)*float(rings)/float(count))/float(rings);\n\t\tfloat spiral_distance = float(i+1)/float(count);\n\t\tvec2 pos = $radius*mix(rings_distance, spiral_distance, $spiral)*vec2(cos(a), sin(a));\n\t\tfloat mask = $mask(fract(pos-vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = uv-0.5-pos;\n\t\t\trc1 = rand3(seed);\n\t\t\tfloat uv_rand = rand(seed.yx);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251 + (a+1.57079632679) * $i_rotate;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv /= mix(1.0, float(i+1)/float(count+1), $i_scale);\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvec2 full_uv = pv;\n\t\t\tpv = get_from_tileset($inputs, uv_rand, pv);\n\t\t\tfloat c1 = $in.variation(pv, $variations ? seed.x : 0.0)*mask*(1.0-$value*seed.x);\n\t\t\tc = max(c, c1);\n\t\t\trc = mix(rc, rc1, step(c, c1));\n\t\t\tinstance_uv = mix(instance_uv, vec3(full_uv, uv_rand), step(c, c1));\n\t\t}\n\t}\n\treturn vec4(rc, c);\n}\n", "longdesc": "Spreads several occurences of an input image in a circle or spiral pattern.", "name": "Circle Splatter", "outputs": [ @@ -223,6 +224,12 @@ "shortdesc": "RndValue", "step": 0.01, "type": "float" + }, + { + "default": false, + "label": "Variations", + "name": "variations", + "type": "boolean" } ] }, diff --git a/addons/material_maker/nodes/circle_splatter_color.mmg b/addons/material_maker/nodes/circle_splatter_color.mmg index 158fefeb..2c0e9889 100644 --- a/addons/material_maker/nodes/circle_splatter_color.mmg +++ b/addons/material_maker/nodes/circle_splatter_color.mmg @@ -16,8 +16,11 @@ "scale_x": 1, "scale_y": 1, "select_inputs": 0, - "spiral": 0 + "spiral": 0, + "variations": false }, + "seed": 0, + "seed_locked": false, "shader_model": { "code": "", "global": "", @@ -41,7 +44,7 @@ "type": "f" } ], - "instance": "vec4 splatter_$(name)(vec2 uv, int count, int rings, vec2 seed) {\n\tvec4 c = vec4(0.0);\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tseed = rand2(seed);\n\tfor (int i = 0; i < count; ++i) {\n\t\tfloat a = -1.57079632679+6.28318530718*float(i)*$rings/float(count);\n\t\tfloat rings_distance = ceil(float(i+1)*float(rings)/float(count))/float(rings);\n\t\tfloat spiral_distance = float(i+1)/float(count);\n\t\tvec2 pos = $radius*mix(rings_distance, spiral_distance, $spiral)*vec2(cos(a), sin(a));\n\t\tfloat mask = $mask(fract(pos-vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = uv-0.5-pos;\n\t\t\trc1 = rand3(seed);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251 + (a+1.57079632679) * $i_rotate;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv /= mix(1.0, float(i+1)/float(count+1), $i_scale);\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$select_inputs\n\t\t\tvec4 n = $in(pv);\n\t\t\tfloat na = n.a*mask*(1.0-$opacity*seed.x);\n\t\t\tc = mix(c, n, na);\n\t\t}\n\t}\n\treturn c;\n}\n", + "instance": "vec4 splatter_$(name)(vec2 uv, int count, int rings, vec2 seed) {\n\tvec4 c = vec4(0.0);\n\tvec3 rc = vec3(0.0);\n\tvec3 rc1;\n\tseed = rand2(seed);\n\tfor (int i = 0; i < count; ++i) {\n\t\tfloat a = -1.57079632679+6.28318530718*float(i)*$rings/float(count);\n\t\tfloat rings_distance = ceil(float(i+1)*float(rings)/float(count))/float(rings);\n\t\tfloat spiral_distance = float(i+1)/float(count);\n\t\tvec2 pos = $radius*mix(rings_distance, spiral_distance, $spiral)*vec2(cos(a), sin(a));\n\t\tfloat mask = $mask(fract(pos-vec2(0.5)));\n\t\tif (mask > 0.01) {\n\t\t\tvec2 pv = uv-0.5-pos;\n\t\t\trc1 = rand3(seed);\n\t\t\tseed = rand2(seed);\n\t\t\tfloat angle = (seed.x * 2.0 - 1.0) * $rotate * 0.01745329251 + (a+1.57079632679) * $i_rotate;\n\t\t\tfloat ca = cos(angle);\n\t\t\tfloat sa = sin(angle);\n\t\t\tpv = vec2(ca*pv.x+sa*pv.y, -sa*pv.x+ca*pv.y);\n\t\t\tpv /= mix(1.0, float(i+1)/float(count+1), $i_scale);\n\t\t\tpv /= vec2($scale_x, $scale_y);\n\t\t\tpv *= (seed.y-0.5)*2.0*$scale+1.0;\n\t\t\tpv += vec2(0.5);\n\t\t\tseed = rand2(seed);\n\t\t\tif (pv != clamp(pv, vec2(0.0), vec2(1.0))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$select_inputs\n\t\t\tvec4 n = $in.variation(pv, $variations ? seed.x : 0.0);\n\t\t\tfloat na = n.a*mask*(1.0-$opacity*seed.x);\t\t\t\n\t\t\tc = mix(c, n, na);\n\t\t}\n\t}\n\treturn c;\n}\n", "longdesc": "Spreads several occurences of an input image in a circle or spiral pattern.", "name": "Color Circle Splatter", "outputs": [ @@ -206,6 +209,12 @@ "shortdesc": "RndOpacity", "step": 0.01, "type": "float" + }, + { + "default": false, + "label": "Variations", + "name": "variations", + "type": "boolean" } ] }, diff --git a/material_maker/doc/node_transform_circlesplatter.rst b/material_maker/doc/node_transform_circlesplatter.rst index 29f86e6d..43740994 100644 --- a/material_maker/doc/node_transform_circlesplatter.rst +++ b/material_maker/doc/node_transform_circlesplatter.rst @@ -43,6 +43,8 @@ The **Circle Splatter** node accepts the following parameters: * *RndRotate* is the maximum angle of the random rotation applied to each instance. * *RndScale* is the amount of random scaling applied to each instance. * *RndValue* is the amount of random value applied to each instance. +* *Variations*: if checked, the node will tile different variations of its input + (i.e. roll a different seed for each instance) Example images ++++++++++++++ From a434f62d63754953291f83a063c39a98b588671e Mon Sep 17 00:00:00 2001 From: Kasper Frandsen Date: Mon, 21 Feb 2022 07:12:25 +0000 Subject: [PATCH 3/3] docs: update to tiler documentation --- material_maker/doc/node_transform_tiler.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/material_maker/doc/node_transform_tiler.rst b/material_maker/doc/node_transform_tiler.rst index d5588e68..4a9bc503 100644 --- a/material_maker/doc/node_transform_tiler.rst +++ b/material_maker/doc/node_transform_tiler.rst @@ -20,9 +20,9 @@ The **Tiler** node accepts two inputs: Outputs +++++++ -The **Tiler** node outputs the splat image. +The **Tiler** node outputs the splat image and a secondary output that assigns a random color to each tile. -The greyscale tiler has a secondary output that assigns a random color to each tile. +The greyscale tiler has a third output that assigns a UV layout to each tile. Parameters ++++++++++