diff --git a/.gitignore b/.gitignore index 589f6c7..fa242d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,14 @@ .import generated_image.png generated_image.png +doc/bricks.png.import +doc/perlin.png.import +doc/screenshot.png.import +doc/sine.png.import +doc/voronoi.png.import +examples/test.ptex +examples/test_blend.ptex +addons/procedural_material/models/Material.material +addons/procedural_material/models/models.blend1 +addons/procedural_material/models/models.dae +addons/procedural_material/models/models.dae.import diff --git a/addons/procedural_material/models/models.blend b/addons/procedural_material/models/models.blend new file mode 100644 index 0000000..16a3e4e Binary files /dev/null and b/addons/procedural_material/models/models.blend differ diff --git a/addons/procedural_material/nodes/perlin.gd b/addons/procedural_material/nodes/perlin.gd index fb249e5..2abef8a 100644 --- a/addons/procedural_material/nodes/perlin.gd +++ b/addons/procedural_material/nodes/perlin.gd @@ -4,16 +4,16 @@ extends "res://addons/procedural_material/node_base.gd" var scale_x var scale_y var iterations -var persistance +var persistence func _ready(): set_slot(0, false, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1)) - initialize_properties([ $GridContainer/scale_x, $GridContainer/scale_y, $GridContainer/iterations, $GridContainer/persistance ]) + initialize_properties([ $GridContainer/scale_x, $GridContainer/scale_y, $GridContainer/iterations, $GridContainer/persistence ]) func _get_shader_code(uv): var rv = { defs="", code="" } if generated_variants.empty(): - rv.defs = "float "+name+"_f(vec2 uv) { return perlin(uv, vec2(%f, %f), %d, %.9f, %d); }\n" % [ scale_x, scale_y, iterations, persistance, get_seed() ] + rv.defs = "float "+name+"_f(vec2 uv) { return perlin(uv, vec2(%f, %f), %d, %.9f, %d); }\n" % [ scale_x, scale_y, iterations, persistence, get_seed() ] var variant_index = generated_variants.find(uv) if variant_index == -1: variant_index = generated_variants.size() diff --git a/addons/procedural_material/nodes/perlin.tscn b/addons/procedural_material/nodes/perlin.tscn index 05630eb..4f981b6 100644 --- a/addons/procedural_material/nodes/perlin.tscn +++ b/addons/procedural_material/nodes/perlin.tscn @@ -5,7 +5,7 @@ [sub_resource type="Theme" id=1] -[node name="Perlin" type="GraphNode"] +[node name="Perlin" type="GraphNode" index="0"] anchor_left = 0.0 anchor_top = 0.0 @@ -219,7 +219,7 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 -[node name="persistance" type="SpinBox" parent="GridContainer" index="7"] +[node name="persistence" type="SpinBox" parent="GridContainer" index="7"] anchor_left = 0.0 anchor_top = 0.0 diff --git a/addons/procedural_material/pm_editor.tscn b/addons/procedural_material/pm_editor.tscn index 1c1a244..13bdab8 100644 --- a/addons/procedural_material/pm_editor.tscn +++ b/addons/procedural_material/pm_editor.tscn @@ -4,7 +4,7 @@ [ext_resource path="res://addons/procedural_material/graph_edit.gd" type="Script" id=2] [ext_resource path="res://addons/procedural_material/nodes/material.tscn" type="PackedScene" id=3] [ext_resource path="res://addons/procedural_material/preview.gd" type="Script" id=4] -[ext_resource path="res://addons/procedural_material/panoramas/night.hdr" type="Texture" id=5] +[ext_resource path="res://addons/procedural_material/panoramas/park.hdr" type="Texture" id=5] [sub_resource type="Animation" id=1] @@ -259,8 +259,72 @@ vec3 rand3(vec2 x) { dot(x, vec2(13.254, 5.867)))) * 43758.5453); } +vec3 blend_normal(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*c1 + (1.0-opacity)*c2; +} + +vec3 blend_dissolve(vec2 uv, vec3 c1, vec3 c2, float opacity) { + if (rand(uv) < opacity) { + return c1; + } else { + return c2; + } +} + +vec3 blend_multiply(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*c1*c2 + (1.0-opacity)*c2; +} + +vec3 blend_screen(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*(1.0-(1.0-c1)*(1.0-c2)) + (1.0-opacity)*c2; +} + +float blend_overlay_f(float c1, float c2) { + return (c1 < 0.5) ? (2.0*c1*c2) : (1.0-2.0*(1.0-c1)*(1.0-c2)); +} + +vec3 blend_overlay(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*vec3(blend_overlay_f(c1.x, c2.x), blend_overlay_f(c1.y, c2.y), blend_overlay_f(c1.z, c2.z)) + (1.0-opacity)*c2; +} + +vec3 blend_hard_light(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*0.5*(c1*c2+blend_overlay(uv, c1, c2, 1.0)) + (1.0-opacity)*c2; +} + +float blend_soft_light_f(float c1, float c2) { + return (c2 < 0.5) ? (2.0*c1*c2+c1*c1*(1.0-2.0*c2)) : 2.0*c1*(1.0-c2)+sqrt(c1)*(2.0*c2-1.0); +} + +vec3 blend_soft_light(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*vec3(blend_soft_light_f(c1.x, c2.x), blend_soft_light_f(c1.y, c2.y), blend_soft_light_f(c1.z, c2.z)) + (1.0-opacity)*c2; +} + +float blend_burn_f(float c1, float c2) { + return (c1==0.0)?c1:max((1.0-((1.0-c2)/c1)),0.0); +} + +vec3 blend_burn(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*vec3(blend_burn_f(c1.x, c2.x), blend_burn_f(c1.y, c2.y), blend_burn_f(c1.z, c2.z)) + (1.0-opacity)*c2; +} + +float blend_dodge_f(float c1, float c2) { + return (c1==1.0)?c1:min(c2/(1.0-c1),1.0); +} + +vec3 blend_dodge(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*vec3(blend_dodge_f(c1.x, c2.x), blend_dodge_f(c1.y, c2.y), blend_dodge_f(c1.z, c2.z)) + (1.0-opacity)*c2; +} + +vec3 blend_lighten(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*max(c1, c2) + (1.0-opacity)*c2; +} + +vec3 blend_darken(vec2 uv, vec3 c1, vec3 c2, float opacity) { + return opacity*min(c1, c2) + (1.0-opacity)*c2; +} + float sine(vec2 uv, float count, float sharpness) { - return max(0.0, min(1.0, (0.5+sharpness*0.5*sin(count*3.1415928*2.0*uv.x)))); + return clamp(0.5+sharpness*0.5*sin(count*3.1415928*2.0*uv.x), 0.0, 1.0); } vec2 transform(vec2 uv, float rotate, float scale) { @@ -294,7 +358,8 @@ float colored_bricks(vec2 uv, vec2 count, float offset) { return fract(x/3.0+y/7.0); } -float perlin(vec2 uv, vec2 size, int iterations, float persistence) { +float perlin(vec2 uv, vec2 size, int iterations, float persistence, int seed) { + uv += vec2(float(seed)*0.1234567); float rv = 0.0; float coef = 1.0; float acc = 0.0; @@ -315,49 +380,40 @@ float perlin(vec2 uv, vec2 size, int iterations, float persistence) { return rv / acc; } -vec2 voronoi(vec2 uv, vec2 size, float intensity) { +vec4 voronoi(vec2 uv, vec2 size, float intensity, int seed) { + uv += vec2(float(seed)*0.1234567); uv *= size; - float rv = 10.0; - vec2 point; + float best_distance0 = 1.0; + float best_distance1 = 1.0; + vec2 point0; + vec2 point1; vec2 p0 = floor(uv); for (int dx = -1; dx < 2; ++dx) { for (int dy = -1; dy < 2; ++dy) { - vec2 p = p0+vec2(float(dx), float(dy)); + vec2 d = vec2(float(dx), float(dy)); + vec2 p = p0+d; p += rand2(mod(p, size)); - float l = length((uv - p) / size); - l *= l; - if (rv > l) { - rv = l; - point = p; + float distance = length((uv - p) / size); + if (best_distance0 > distance) { + best_distance1 = best_distance0; + best_distance0 = distance; + point1 = point0; + point0 = p; + } else if (best_distance1 > distance) { + best_distance1 = distance; + point1 = p; } } } + float edge_distance = dot(uv - 0.5*(point0+point1), normalize(point0-point1)); - return vec2(rand(point), rv*length(size)*intensity); + return vec4(point0, best_distance0*length(size)*intensity, edge_distance); } - -float Perlin_f(vec2 uv) { return perlin(uv, vec2(4, 4), 6, 0.35); } -float Bricks_f(vec2 uv) { return bricks(uv, vec2(3, 6), 0.5, 0.05, 0.6); } -vec3 Colorize3_gradient(float x) { - if (x < 0.000000000) { - return vec3(0.000000000,0.000000000,0.000000000); - } else if (x < 0.081818182) { - return vec3(0.000000000,0.000000000,0.000000000)+x*vec3(12.222222328,12.222222328,12.222222328); - } - return vec3(1.000000000,1.000000000,1.000000000); -} +vec4 voronoi_0_xyzw(vec2 uv) { return voronoi(uv, vec2(4.000000, 4.000000), 1.000000000, 3766); } void fragment() { -float Perlin_0_f = Perlin_f(UV+vec2(0.01, 0.0)); -float Perlin_1_f = Perlin_f(UV-vec2(0.01, 0.0)); -float Perlin_2_f = Perlin_f(UV+vec2(0.0, 0.01)); -float Perlin_3_f = Perlin_f(UV-vec2(0.0, 0.01)); -vec2 Warp_0_uv = UV+0.300000012*vec2((Perlin_0_f)-(Perlin_1_f), (Perlin_2_f)-(Perlin_3_f)); -float Bricks_0_f = Bricks_f(Warp_0_uv); -vec3 Warp_0_rgb = vec3(Bricks_0_f); -float Warp_0_f = dot(vec3(Bricks_0_f), vec3(1.0))/3.0; -vec3 Colorize3_0_rgb = Colorize3_gradient(dot(Warp_0_rgb, vec3(1.0))/3.0); -COLOR = vec4(Colorize3_0_rgb, 1.0); +vec4 voronoi_0_0_xyzw = voronoi_0_xyzw(UV); +COLOR = vec4(vec3(voronoi_0_0_xyzw.z), 1.0); } " @@ -366,7 +422,7 @@ COLOR = vec4(Colorize3_0_rgb, 1.0); render_priority = 0 shader = SubResource( 12 ) -[node name="ProceduralMaterialEditor" type="MarginContainer"] +[node name="ProceduralMaterialEditor" type="MarginContainer" index="0"] anchor_left = 0.0 anchor_top = 0.0 @@ -514,7 +570,7 @@ _sections_unfolded = [ "GUI", "Render Target" ] [node name="Objects" type="Spatial" parent="Preview/Preview/MaterialPreview" index="0"] -transform = Transform( 0.277021, 0, -0.960862, 0, 1, 0, 0.960862, 0, 0.277021, 0, 0, 0 ) +transform = Transform( 0.172897, 0, 0.984938, 0, 1, 0, -0.984938, 0, 0.172897, 0, 0, 0 ) _sections_unfolded = [ "Transform" ] [node name="Cube" type="MeshInstance" parent="Preview/Preview/MaterialPreview/Objects" index="0"] diff --git a/examples/bricks.ptex b/examples/bricks.ptex index a82803d..0d658b4 100644 --- a/examples/bricks.ptex +++ b/examples/bricks.ptex @@ -1 +1 @@ -{"connections":[{"from":"Bricks","from_port":0,"to":"Warp","to_port":0},{"from":"Perlin","from_port":0,"to":"Warp","to_port":1},{"from":"Warp","from_port":0,"to":"NormalMap","to_port":0},{"from":"Perlin2","from_port":0,"to":"colorize_0","to_port":0},{"from":"Perlin2","from_port":0,"to":"colorize_1","to_port":0},{"from":"colorize_0","from_port":0,"to":"blend_0","to_port":0},{"from":"colorize_1","from_port":0,"to":"blend_0","to_port":1},{"from":"Warp","from_port":0,"to":"colorize_2","to_port":0},{"from":"colorize_2","from_port":0,"to":"blend_0","to_port":2},{"from":"blend_0","from_port":0,"to":"transform_0","to_port":0},{"from":"transform_0","from_port":0,"to":"Material","to_port":0},{"from":"NormalMap","from_port":0,"to":"transform_1","to_port":0},{"from":"transform_1","from_port":0,"to":"Material","to_port":1}],"nodes":[{"iterations":7,"name":"Perlin2","node_position":{"x":258,"y":-32},"persistance":0.9,"scale_x":8,"scale_y":8,"type":"perlin"},{"bevel":0.6,"columns":6,"mortar":0.05,"name":"Bricks","node_position":{"x":260,"y":132},"row_offset":0.5,"rows":12,"type":"bricks"},{"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":1,"r":1}],"name":"colorize_0","node_position":{"x":556.943665,"y":-32},"type":"colorize"},{"gradient":[{"b":0.002889,"g":0.102424,"pos":0,"r":0.184896},{"b":0,"g":0.19869,"pos":0.327273,"r":0.669271},{"b":0.019368,"g":0.060224,"pos":0.690909,"r":0.309896},{"b":0,"g":0.180135,"pos":1,"r":0.606771}],"name":"colorize_1","node_position":{"x":550.943665,"y":53},"type":"colorize"},{"amount":0.5,"name":"NormalMap","node_position":{"x":694,"y":297},"type":"normal_map"},{"iterations":6,"name":"Perlin","node_position":{"x":255,"y":322},"persistance":0.35,"scale_x":4,"scale_y":4,"type":"perlin"},{"amount":0.2,"name":"Warp","node_position":{"x":504,"y":199.75},"type":"warp"},{"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":0.072727,"r":1}],"name":"colorize_2","node_position":{"x":639.943665,"y":152},"type":"colorize"},{"amount":0.5,"name":"blend_0","node_position":{"x":819.943726,"y":-33},"type":"blend"},{"name":"transform_0","node_position":{"x":938.779785,"y":129.75},"rotate":0,"scale":1,"type":"transform"},{"name":"transform_1","node_position":{"x":944.779785,"y":262.75},"rotate":0,"scale":1,"type":"transform"},{"name":"Material","node_position":{"x":1165,"y":171},"type":"material"}]} \ No newline at end of file +{"connections":[{"from":"Bricks","from_port":0,"to":"Warp","to_port":0},{"from":"Perlin","from_port":0,"to":"Warp","to_port":1},{"from":"Warp","from_port":0,"to":"NormalMap","to_port":0},{"from":"Perlin2","from_port":0,"to":"colorize_0","to_port":0},{"from":"Perlin2","from_port":0,"to":"colorize_1","to_port":0},{"from":"Warp","from_port":0,"to":"colorize_2","to_port":0},{"from":"colorize_2","from_port":0,"to":"blend_0","to_port":2},{"from":"blend_0","from_port":0,"to":"transform_0","to_port":0},{"from":"transform_0","from_port":0,"to":"Material","to_port":0},{"from":"NormalMap","from_port":0,"to":"transform_1","to_port":0},{"from":"transform_1","from_port":0,"to":"Material","to_port":1},{"from":"colorize_1","from_port":0,"to":"blend_0","to_port":0},{"from":"colorize_0","from_port":0,"to":"blend_0","to_port":1}],"nodes":[{"iterations":7,"name":"Perlin2","node_position":{"x":258,"y":-32},"persistence":0.5,"scale_x":8,"scale_y":8,"type":"perlin"},{"bevel":0.6,"columns":6,"mortar":0.05,"name":"Bricks","node_position":{"x":260,"y":132},"row_offset":0.5,"rows":12,"type":"bricks"},{"amount":0.5,"name":"NormalMap","node_position":{"x":694,"y":297},"type":"normal_map"},{"iterations":6,"name":"Perlin","node_position":{"x":255,"y":322},"persistence":0.5,"scale_x":4,"scale_y":4,"type":"perlin"},{"amount":0.1,"name":"Warp","node_position":{"x":504,"y":199.75},"type":"warp"},{"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":0.090909,"r":1}],"name":"colorize_2","node_position":{"x":639.943665,"y":152},"type":"colorize"},{"name":"transform_1","node_position":{"x":944.779785,"y":262.75},"rotate":0,"scale":1,"type":"transform"},{"name":"Material","node_position":{"x":1165,"y":171},"type":"material"},{"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":1,"r":1}],"name":"colorize_0","node_position":{"x":560.943665,"y":50},"type":"colorize"},{"gradient":[{"b":0.002889,"g":0.102424,"pos":0,"r":0.184896},{"b":0,"g":0.19869,"pos":0.327273,"r":0.669271},{"b":0.019368,"g":0.060224,"pos":0.681818,"r":0.309896},{"b":0,"g":0.180135,"pos":1,"r":0.606771}],"name":"colorize_1","node_position":{"x":562.943665,"y":-65},"type":"colorize"},{"name":"transform_0","node_position":{"x":938.779785,"y":129.75},"rotate":0,"scale":1,"type":"transform"},{"amount":0.5,"blend_type":0,"name":"blend_0","node_position":{"x":820.943726,"y":-33},"type":"blend"}]} \ No newline at end of file