Added new patterns for bricks

Added a Running Bond variant, HerringBone, Basket Weave and Spanish bond patterns to the bricks generator.
Shader was refactored to make it easy to add new patterns made of axis-aligned bricks.
This commit is contained in:
Rodolphe Suescun 2018-08-19 15:23:11 +02:00
parent 0d0f862a99
commit ddbd69ea25
3 changed files with 234 additions and 34 deletions

View File

@ -145,21 +145,99 @@ vec2 transform_norepeat(vec2 uv, vec2 translate, float rotate, vec2 scale) {
return clamp(transform(uv, translate, rotate, scale), vec2(0.0), vec2(1.0));
}
vec3 bricks(vec2 uv, vec2 count, float offset, float mortar, float bevel) {
vec3 brick(vec2 uv, vec2 bmin, vec2 bmax, float mortar, float bevel) {
float color = 0.5;
vec2 c1 = (uv-bmin-vec2(mortar))/bevel;
vec2 c2 = (bmax-uv-vec2(mortar))/bevel;
vec2 c = min(c1, c2);
color = clamp(min(c.x, c.y), 0.0, 1.0);
return vec3(color, bmin);
}
vec3 bricks_rb(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
count *= repeat;
mortar /= max(count.x, count.y);
bevel /= max(count.x, count.y);
float x = uv.x*count.x+offset*step(0.5, fract(uv.y*count.y*0.5));
float fract_x = fract(x);
float slope_x = 1.0/(bevel*count.x);
float off = 0.5*mortar/bevel;
float f1 = fract_x*slope_x-off;
float f2 = (1.0-fract_x)*slope_x-off;
float y = uv.y*count.y;
float fract_y = fract(uv.y*count.y);
float slope_y = 1.0/(bevel*count.y);
float f3 = fract_y*slope_y-off;
float f4 = (1.0-fract_y)*slope_y-off;
return vec3(max(0.0, min(1.0, min(min(f1, f2), min(f3, f4)))), floor(mod(x, count.x)), floor(mod(y, count.y)));
float x_offset = offset*step(0.5, fract(uv.y*count.y*0.5));
vec2 bmin = floor(vec2(uv.x*count.x-x_offset, uv.y*count.y));
bmin.x += x_offset;
bmin /= count;
return brick(uv, bmin, bmin+vec2(1.0)/count, mortar, bevel);
}
vec3 bricks_rb2(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
count *= repeat;
mortar /= max(2.0*count.x, count.y);
bevel /= max(2.0*count.x, count.y);
float x_offset = offset*step(0.5, fract(uv.y*count.y*0.5));
count.x = count.x*(1.0+step(0.5, fract(uv.y*count.y*0.5)));
vec2 bmin = floor(vec2(uv.x*count.x-x_offset, uv.y*count.y));
bmin.x += x_offset;
bmin /= count;
return brick(uv, bmin, bmin+vec2(1.0)/count, mortar, bevel);
}
vec3 bricks_hb(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
float pc = count.x+count.y;
float c = pc*repeat;
mortar /= c;
bevel /= c;
vec2 corner = floor(uv*c);
float cdiff = mod(corner.x-corner.y, pc);
if (cdiff < count.x) {
return brick(uv, (corner-vec2(cdiff, 0.0))/c, (corner-vec2(cdiff, 0.0)+vec2(count.x, 1.0))/c, mortar, bevel);
} else {
return brick(uv, (corner-vec2(0.0, pc-cdiff-1.0))/c, (corner-vec2(0.0, pc-cdiff-1.0)+vec2(1.0, count.y))/c, mortar, bevel);
}
}
vec3 bricks_bw(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
vec2 c = 2.0*count*repeat;
float mc = max(c.x, c.y);
mortar /= mc;
bevel /= mc;
vec2 corner1 = floor(uv*c);
vec2 corner2 = count*floor(repeat*2.0*uv);
float cdiff = mod(dot(floor(repeat*2.0*uv), vec2(1.0)), 2.0);
vec2 corner;
vec2 size;
if (cdiff == 0.0) {
corner = vec2(corner1.x, corner2.y);
size = vec2(1.0, count.y);
} else {
corner = vec2(corner2.x, corner1.y);
size = vec2(count.x, 1.0);
}
return brick(uv, corner/c, (corner+size)/c, mortar, bevel);
}
vec3 bricks_sb(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
vec2 c = (count+vec2(1.0))*repeat;
float mc = max(c.x, c.y);
mortar /= mc;
bevel /= mc;
vec2 corner1 = floor(uv*c);
vec2 corner2 = (count+vec2(1.0))*floor(repeat*uv);
vec2 rcorner = corner1 - corner2;
vec2 corner;
vec2 size;
if (rcorner.x == 0.0 && rcorner.y < count.y) {
corner = corner2;
size = vec2(1.0, count.y);
} else if (rcorner.y == 0.0) {
corner = corner2+vec2(1.0, 0.0);
size = vec2(count.x, 1.0);
} else if (rcorner.x == count.x) {
corner = corner2+vec2(count.x, 1.0);
size = vec2(1.0, count.y);
} else if (rcorner.y == count.y) {
corner = corner2+vec2(0.0, count.y);
size = vec2(count.x, 1.0);
} else {
corner = corner2+vec2(1.0);
size = vec2(count.x-1.0, count.y-1.0);
}
return brick(uv, corner/c, (corner+size)/c, mortar, bevel);
}
float colored_bricks(vec2 uv, vec2 count, float offset) {

View File

@ -1,27 +1,42 @@
tool
extends "res://addons/procedural_material/node_base.gd"
var pattern = 0
var repeat
var rows
var columns
var row_offset
var mortar
var bevel
const BRICK_PATTERNS = [
{ name="Running bond", suffix="rb", has_offset=true, has_repeat=false },
{ name="Running bond (2)", suffix="rb2", has_offset=true, has_repeat=false },
{ name="HerringBone", suffix="hb", has_offset=false, has_repeat=true },
{ name="Basket weave", suffix="bw", has_offset=false, has_repeat=true },
{ name="Spanish bond", suffix="sb", has_offset=false, has_repeat=true }
]
func _ready():
set_slot(0, false, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
initialize_properties([ $HBoxContainer1/rows, $HBoxContainer2/columns, $HBoxContainer3/row_offset, $HBoxContainer4/mortar, $HBoxContainer5/bevel ])
$pattern.clear()
for p in BRICK_PATTERNS:
$pattern.add_item(p.name)
initialize_properties([ $pattern, $HBoxContainer1/rows, $HBoxContainer2/columns, $HBoxContainer6/repeat, $HBoxContainer3/row_offset, $HBoxContainer4/mortar, $HBoxContainer5/bevel ])
func _get_shader_code(uv, slot = 0):
var rv = { defs="", code="" }
if generated_variants.empty():
rv.defs = "vec3 "+name+"_xyz(vec2 uv) { return bricks(uv, vec2("+str(columns)+", "+str(rows)+"), "+str(row_offset)+", "+str(mortar)+", "+str(max(0.001, bevel))+"); }\n"
rv.defs = "vec3 %s_xyz(vec2 uv) { return bricks_%s(uv, vec2(%d, %d), %.9f, %.9f, %.9f, %.9f); }\n" % [ name, BRICK_PATTERNS[pattern].suffix, columns, rows, repeat, row_offset, mortar, max(0.001, bevel) ]
var variant_index = generated_variants.find(uv)
if variant_index == -1:
variant_index = generated_variants.size()
generated_variants.append(uv)
rv.code = "vec3 "+name+"_"+str(variant_index)+"_xyz = "+name+"_xyz("+uv+");\n"
rv.code = "vec3 %s_%d_xyz = %s_xyz(%s);\n" % [ name, variant_index, name, uv ]
if slot == 0:
rv.f = name+"_"+str(variant_index)+"_xyz.x"
rv.f = "%s_%d_xyz.x" % [ name, variant_index ]
else:
rv.rgb = "rand3("+name+"_"+str(variant_index)+"_xyz.yz)"
rv.rgb = "rand3(%s_%d_xyz.yz+vec2(%.9f))" % [ name, variant_index, get_seed() ]
return rv
func _on_offset_changed():
update_shaders()

View File

@ -5,7 +5,7 @@
[sub_resource type="Theme" id=1]
[node name="Bricks" type="GraphNode"]
[node name="Bricks" type="GraphNode" index="0"]
anchor_left = 0.0
anchor_top = 0.0
@ -58,10 +58,22 @@ slot/4/left_color = Color( 1, 1, 1, 1 )
slot/4/right_enabled = false
slot/4/right_type = 0
slot/4/right_color = Color( 1, 1, 1, 1 )
slot/5/left_enabled = false
slot/5/left_type = 0
slot/5/left_color = Color( 1, 1, 1, 1 )
slot/5/right_enabled = false
slot/5/right_type = 0
slot/5/right_color = Color( 1, 1, 1, 1 )
slot/6/left_enabled = false
slot/6/left_type = 0
slot/6/left_color = Color( 1, 1, 1, 1 )
slot/6/right_enabled = false
slot/6/right_type = 0
slot/6/right_color = Color( 1, 1, 1, 1 )
script = ExtResource( 1 )
_sections_unfolded = [ "Mouse", "Theme", "slot", "slot/0", "slot/1" ]
[node name="HBoxContainer1" type="HBoxContainer" parent="." index="0"]
[node name="pattern" type="OptionButton" parent="." index="0"]
anchor_left = 0.0
anchor_top = 0.0
@ -70,7 +82,100 @@ anchor_bottom = 0.0
margin_left = 16.0
margin_top = 24.0
margin_right = 154.0
margin_bottom = 48.0
margin_bottom = 44.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 1
toggle_mode = false
action_mode = 0
enabled_focus_mode = 2
shortcut = null
group = null
flat = false
align = 0
items = [ ]
selected = -1
_sections_unfolded = [ "Size Flags" ]
[node name="HBoxContainer6" type="HBoxContainer" parent="." index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 44.0
margin_right = 154.0
margin_bottom = 68.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
alignment = 0
[node name="Label1" type="Label" parent="HBoxContainer6" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 5.0
margin_right = 60.0
margin_bottom = 19.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 4
text = "Repeat:"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="repeat" type="SpinBox" parent="HBoxContainer6" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 64.0
margin_right = 138.0
margin_bottom = 24.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 9
size_flags_vertical = 1
min_value = 1.0
max_value = 8.0
step = 1.0
page = 0.0
value = 1.0
exp_edit = false
rounded = false
editable = true
prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="HBoxContainer1" type="HBoxContainer" parent="." index="2"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 69.0
margin_right = 154.0
margin_bottom = 93.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
@ -126,16 +231,16 @@ prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="HBoxContainer2" type="HBoxContainer" parent="." index="1"]
[node name="HBoxContainer2" type="HBoxContainer" parent="." index="3"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 48.0
margin_top = 94.0
margin_right = 154.0
margin_bottom = 72.0
margin_bottom = 118.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
@ -191,16 +296,16 @@ prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="HBoxContainer3" type="HBoxContainer" parent="." index="2"]
[node name="HBoxContainer3" type="HBoxContainer" parent="." index="4"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 73.0
margin_top = 119.0
margin_right = 154.0
margin_bottom = 97.0
margin_bottom = 143.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
@ -256,16 +361,16 @@ prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="HBoxContainer4" type="HBoxContainer" parent="." index="3"]
[node name="HBoxContainer4" type="HBoxContainer" parent="." index="5"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 98.0
margin_top = 144.0
margin_right = 154.0
margin_bottom = 122.0
margin_bottom = 168.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
@ -321,16 +426,16 @@ prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder" ]
[node name="HBoxContainer5" type="HBoxContainer" parent="." index="4"]
[node name="HBoxContainer5" type="HBoxContainer" parent="." index="6"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 16.0
margin_top = 123.0
margin_top = 169.0
margin_right = 154.0
margin_bottom = 147.0
margin_bottom = 193.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
@ -386,4 +491,6 @@ prefix = ""
suffix = ""
_sections_unfolded = [ "Caret", "Placeholder" ]
[connection signal="offset_changed" from="." to="." method="_on_offset_changed"]