diff --git a/.gitignore b/.gitignore index eb4c9dc..7e178cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # Godot 4+ specific ignores .godot/ tests/ +*.import diff --git a/addons/ShaderLib/Maths/Vector/Distance/Chebyshev2D.gdshaderinc b/addons/ShaderLib/Maths/Vector/Distance/Chebyshev2D.gdshaderinc new file mode 100644 index 0000000..a270d5b --- /dev/null +++ b/addons/ShaderLib/Maths/Vector/Distance/Chebyshev2D.gdshaderinc @@ -0,0 +1,4 @@ +float chebyshev_distance_2d(vec2 point1, vec2 point2, float power) { + vec2 p = abs(point1 - point2); + return pow(pow(p.x, power) + pow(p.y, power), 1. / power); +} \ No newline at end of file diff --git a/addons/ShaderLib/Maths/Vector/Distance/Chebyshev3D.gdshaderinc b/addons/ShaderLib/Maths/Vector/Distance/Chebyshev3D.gdshaderinc new file mode 100644 index 0000000..d5e525b --- /dev/null +++ b/addons/ShaderLib/Maths/Vector/Distance/Chebyshev3D.gdshaderinc @@ -0,0 +1,4 @@ +float chebyshev_distance_3d(vec3 point1, vec3 point2, float power) { + vec3 p = abs(point1 - point2); + return pow(pow(p.x, power) + pow(p.y, power) + pow(p.z, power), 1. / power); +} \ No newline at end of file diff --git a/addons/ShaderLib/Maths/Vector/Distance/ChebyshevDistance.gd b/addons/ShaderLib/Maths/Vector/Distance/ChebyshevDistance.gd new file mode 100644 index 0000000..bd89d87 --- /dev/null +++ b/addons/ShaderLib/Maths/Vector/Distance/ChebyshevDistance.gd @@ -0,0 +1,102 @@ +@tool +class_name VisualShaderNodeMathsChebyshevDistance extends VisualShaderNodeCustom + +func _get_name() -> String: + return "ChebyshevDistance" + +func _get_category() -> String: + return "Maths/Vector/Distance" + +func _get_description() -> String: + return "Returns the distance between two points using Chebyshev distance matrix." + +func _get_return_icon_type() -> PortType: + return PORT_TYPE_SCALAR + +func _get_input_port_count() -> int: + return 3 + +func _get_input_port_name(port: int) -> String: + match port: + 0: + return "a" + 1: + return "b" + _: + return "power" + +func _get_input_port_type(port: int) -> PortType: + var vector_index: int = get_option_index(0) + match port: + 2: + return PORT_TYPE_SCALAR + _: + match vector_index: + 0: + return PORT_TYPE_VECTOR_2D + _: + return PORT_TYPE_VECTOR_3D + +func _get_input_port_default_value(port: int) -> Variant: + match port: + 2: + return 2.0 + _: + return null + +func _get_output_port_count() -> int: + return 1 + +func _get_output_port_name(port: int) -> String: + return "distance" + +func _get_output_port_type(port: int) -> PortType: + return PORT_TYPE_SCALAR + +func _get_property_count() -> int: + return 1 + +func _get_property_name(index: int) -> String: + return "" + +func _get_property_default_index(index: int) -> int: + return 0 + +func _get_property_options(index: int) -> PackedStringArray: + return ["Vector2", "Vector3"] + +func _get_global_code(mode: Shader.Mode) -> String: + var code: String + var vector_index: int = get_option_index(0) + match vector_index: + 0: + code = preload("Chebyshev2D.gdshaderinc").code + _: + code = preload("Chebyshev3D.gdshaderinc").code + return code + +func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String: + var point_a: String + var point_b: String + var power: String = input_vars[2] + var vector_index: int = get_option_index(0) + match vector_index: + 0: + point_a = "vec2(0)" + point_b = "vec2(0)" + _: + point_b = "vec3(0)" + point_a = "vec3(0)" + + if input_vars[0]: + point_a = input_vars[0] + + if input_vars[1]: + point_b = input_vars[1] + + match vector_index: + 0: + return output_vars[0] + " = chebyshev_distance_2d(%s, %s, %s);" % [point_a, point_b, power] + _: + return output_vars[0] + " = chebyshev_distance_3d(%s, %s, %s);" % [point_a, point_b, power] + diff --git a/addons/ShaderLib/Maths/Vector/Distance/Manhattan2D.gdshaderinc b/addons/ShaderLib/Maths/Vector/Distance/Manhattan2D.gdshaderinc new file mode 100644 index 0000000..b2d6d7e --- /dev/null +++ b/addons/ShaderLib/Maths/Vector/Distance/Manhattan2D.gdshaderinc @@ -0,0 +1,4 @@ +float manhattan_distance_2d(vec2 point1, vec2 point2) { + vec2 d = point1 - point2; + return abs(d.x) + abs(d.y); +} \ No newline at end of file diff --git a/addons/ShaderLib/Maths/Vector/Distance/Manhattan3D.gdshaderinc b/addons/ShaderLib/Maths/Vector/Distance/Manhattan3D.gdshaderinc new file mode 100644 index 0000000..78ba265 --- /dev/null +++ b/addons/ShaderLib/Maths/Vector/Distance/Manhattan3D.gdshaderinc @@ -0,0 +1,4 @@ +float manhattan_distance_3d(vec3 point1, vec3 point2) { + vec3 d = point1 - point2; + return abs(d.x) + abs(d.y) + abs(d.z); +} \ No newline at end of file diff --git a/addons/ShaderLib/Maths/Vector/Distance/ManhattanDistance.gd b/addons/ShaderLib/Maths/Vector/Distance/ManhattanDistance.gd new file mode 100644 index 0000000..ce99534 --- /dev/null +++ b/addons/ShaderLib/Maths/Vector/Distance/ManhattanDistance.gd @@ -0,0 +1,88 @@ +@tool +class_name VisualShaderNodeMathsManhattanDistance extends VisualShaderNodeCustom + +func _get_name() -> String: + return "ManhattanDistance" + +func _get_category() -> String: + return "Maths/Vector/Distance" + +func _get_description() -> String: + return "Returns the distance between two points using Manhattan distance matrix." + +func _get_return_icon_type() -> PortType: + return PORT_TYPE_SCALAR + +func _get_input_port_count() -> int: + return 2 + +func _get_input_port_name(port: int) -> String: + match port: + 0: + return "a" + _: + return "b" + +func _get_input_port_type(port: int) -> PortType: + var vector_index: int = get_option_index(0) + match vector_index: + 0: + return PORT_TYPE_VECTOR_2D + _: + return PORT_TYPE_VECTOR_3D + +func _get_output_port_count() -> int: + return 1 + +func _get_output_port_name(port: int) -> String: + return "distance" + +func _get_output_port_type(port: int) -> PortType: + return PORT_TYPE_SCALAR + +func _get_property_count() -> int: + return 1 + +func _get_property_name(index: int) -> String: + return "" + +func _get_property_default_index(index: int) -> int: + return 0 + +func _get_property_options(index: int) -> PackedStringArray: + return ["Vector2", "Vector3"] + +func _get_global_code(mode: Shader.Mode) -> String: + var code: String + var vector_index: int = get_option_index(0) + match vector_index: + 0: + code = preload("Manhattan2D.gdshaderinc").code + _: + code = preload("Manhattan3D.gdshaderinc").code + return code + +func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String: + var point_a: String + var point_b: String + var vector_index: int = get_option_index(0) + match vector_index: + 0: + point_a = "vec2(0)" + point_b = "vec2(0)" + _: + point_b = "vec3(0)" + point_a = "vec3(0)" + + if input_vars[0]: + point_a = input_vars[0] + + if input_vars[1]: + point_b = input_vars[1] + + match vector_index: + 0: + return output_vars[0] + " = manhattan_distance_2d(%s, %s);" % [point_a, point_b] + _: + return output_vars[0] + " = manhattan_distance_3d(%s, %s);" % [point_a, point_b] + diff --git a/addons/ShaderLib/Maths/Vector/VectorTransform.gdshaderinc b/addons/ShaderLib/Maths/Vector/VectorTransform.gdshaderinc index d6f7b52..91ceb44 100644 --- a/addons/ShaderLib/Maths/Vector/VectorTransform.gdshaderinc +++ b/addons/ShaderLib/Maths/Vector/VectorTransform.gdshaderinc @@ -1,14 +1,14 @@ vec3 vector_transform_world_to_local(mat4 model_matrix, vec3 vector){ - return (transpose(model_matrix) * vec4(vector, 0.0)).xyz; + return (inverse(model_matrix) * vec4(vector, 1.0)).xyz; } vec3 vector_transform_world_to_view(mat4 view_matrix, vec3 vector){ - return (view_matrix * vec4(vector, 0.0)).xyz; + return (view_matrix * vec4(vector, 1.0)).xyz; } vec3 vector_transform_world_to_screen(mat4 view_matrix, mat4 projection_matrix, vec3 vector){ vec3 vector_view = vector_transform_world_to_view(view_matrix, vector); - return (projection_matrix * vec4(vector_view, 0.0)).xyz; + return (projection_matrix * vec4(vector_view, 1.0)).xyz; } vec3 vector_transform_world_to_tangent(mat4 model_matrix, vec3 normal, vec3 binormal, vec3 tangent, vec3 vector){ @@ -18,17 +18,17 @@ vec3 vector_transform_world_to_tangent(mat4 model_matrix, vec3 normal, vec3 bino } vec3 vector_transform_local_to_world(mat4 model_matrix, vec3 vector){ - return (model_matrix * vec4(vector, 0.0)).xyz; + return (model_matrix * vec4(vector, 1.0)).xyz; } vec3 vector_transform_local_to_view(mat4 model_matrix, mat4 view_matrix, vec3 vector){ vec3 vector_world = vector_transform_local_to_world(model_matrix, vector); - return (view_matrix * vec4(vector_world, 0.0)).xyz; + return (view_matrix * vec4(vector_world, 1.0)).xyz; } vec3 vector_transform_local_to_screen(mat4 model_matrix, mat4 view_matrix, mat4 projection_matrix, vec3 vector){ vec3 vector_view = vector_transform_local_to_view(model_matrix, view_matrix, vector); - return (projection_matrix * vec4(vector_view, 0.0)).xyz; + return (projection_matrix * vec4(vector_view, 1.0)).xyz; } vec3 vector_transform_local_to_tangent(vec3 normal, vec3 binormal, vec3 tangent, vec3 vector){ @@ -37,7 +37,7 @@ vec3 vector_transform_local_to_tangent(vec3 normal, vec3 binormal, vec3 tangent, } vec3 vector_transform_view_to_world(mat4 inv_view_matrix, vec3 vector){ - return (inv_view_matrix * vec4(vector, 0.0)).xyz;; + return (inv_view_matrix * vec4(vector, 1.0)).xyz;; } vec3 vector_transform_view_to_local(mat4 inv_view_matrix, mat4 model_matrix, vec3 vector){ @@ -46,7 +46,7 @@ vec3 vector_transform_view_to_local(mat4 inv_view_matrix, mat4 model_matrix, vec } vec3 vector_transform_view_to_screen(mat4 projection_matrix, vec3 vector){ - return (projection_matrix * vec4(vector, 0.0)).xyz; + return (projection_matrix * vec4(vector, 1.0)).xyz; } vec3 vector_transform_view_to_tangent(mat4 inv_view_matrix, mat4 model_matrix, vec3 normal, vec3 binormal, vec3 tangent, vec3 vector){ @@ -56,7 +56,7 @@ vec3 vector_transform_view_to_tangent(mat4 inv_view_matrix, mat4 model_matrix, v } vec3 vector_transform_screen_to_view(mat4 inv_projection_matrix, vec3 vector){ - return (inv_projection_matrix * vec4(vector, 0.0)).xyz;; + return (inv_projection_matrix * vec4(vector, 1.0)).xyz;; } vec3 vector_transform_screen_to_local(mat4 inv_projection_matrix, mat4 inv_view_matrix, mat4 model_matrix, vec3 vector){ @@ -76,24 +76,24 @@ vec3 vector_transform_screen_to_tangent(mat4 inv_projection_matrix, mat4 inv_vie } vec3 vector_transform_tangent_to_local(vec3 normal, vec3 binormal, vec3 tangent, vec3 vector){ - mat3 tangent_to_local_matrix = transpose(mat3(tangent, binormal, normal)); + mat3 tangent_to_local_matrix = inverse(mat3(tangent, binormal, normal)); return tangent_to_local_matrix * vector; } vec3 vector_transform_tangent_to_world(mat4 model_matrix, vec3 normal, vec3 binormal, vec3 tangent, vec3 vector){ - mat3 tangent_to_local_matrix = transpose(mat3(tangent, binormal, normal)); + mat3 tangent_to_local_matrix = inverse(mat3(tangent, binormal, normal)); vec3 vector_local = tangent_to_local_matrix * vector; return vector_transform_local_to_world(model_matrix, vector_local); } vec3 vector_transform_tangent_to_view(mat4 model_matrix, mat4 view_matrix, vec3 normal, vec3 binormal, vec3 tangent, vec3 vector){ - mat3 tangent_to_local_matrix = transpose(mat3(tangent, binormal, normal)); + mat3 tangent_to_local_matrix = inverse(mat3(tangent, binormal, normal)); vec3 vector_local = tangent_to_local_matrix * vector; return vector_transform_local_to_view(model_matrix, view_matrix, vector_local); } vec3 vector_transform_tangent_to_screen(mat4 model_matrix, mat4 view_matrix, mat4 projection_matrix, vec3 normal, vec3 binormal, vec3 tangent, vec3 vector){ - mat3 tangent_to_local_matrix = transpose(mat3(tangent, binormal, normal)); + mat3 tangent_to_local_matrix = inverse(mat3(tangent, binormal, normal)); vec3 vector_local = tangent_to_local_matrix * vector; return vector_transform_local_to_screen(model_matrix, view_matrix, projection_matrix, vector_local); } diff --git a/addons/ShaderLib/Procedural/Noise/GyroidNoise.gd b/addons/ShaderLib/Procedural/Noise/GyroidNoise.gd new file mode 100644 index 0000000..711b2ba --- /dev/null +++ b/addons/ShaderLib/Procedural/Noise/GyroidNoise.gd @@ -0,0 +1,79 @@ +@tool +class_name VisualShaderNodeProceduralGyroidNoise extends VisualShaderNodeCustom + +func _init() -> void: + output_port_for_preview = 0 + +func _get_name() -> String: + return "GyroidNoise" + +func _get_category() -> String: + return "Procedural/Noise" + +func _get_description() -> String: + return "Generates a gyroid noise based on input UV." + +func _get_return_icon_type() -> PortType: + return PORT_TYPE_SCALAR + +func _get_input_port_count() -> int: + return 5 + +func _get_input_port_name(port: int) -> String: + match port: + 0: + return "uv" + 1: + return "scale" + 2: + return "ratio" + 3: + return "height" + _: + return "thickness" + +func _get_input_port_type(port: int) -> PortType: + match port: + 0, 2: + return PORT_TYPE_VECTOR_2D + _: + return PORT_TYPE_SCALAR + +func _get_input_port_default_value(port: int) -> Variant: + match port: + 1: + return 2.0 + 2: + return Vector2(1, 1) + 3: + return 0.5 + 4: + return 0.0 + _: + return null + +func _get_output_port_count() -> int: + return 1 + +func _get_output_port_name(port: int) -> String: + return "output" + +func _get_output_port_type(port: int) -> PortType: + return PORT_TYPE_SCALAR + +func _get_global_code(mode: Shader.Mode) -> String: + var code: String = preload("GyroidNoise.gdshaderinc").code + return code + +func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String: + var uv: String = "UV" + + if input_vars[0]: + uv = input_vars[0] + + var scale: String = input_vars[1] + var ratio: String = input_vars[2] + var height: String = input_vars[3] + var thickness: String = input_vars[4] + + return output_vars[0] + " = gyroid_noise(%s, %s, %s, %s, %s);" % [uv, scale, ratio, height, thickness] diff --git a/addons/ShaderLib/Procedural/Noise/GyroidNoise.gdshaderinc b/addons/ShaderLib/Procedural/Noise/GyroidNoise.gdshaderinc new file mode 100644 index 0000000..a7007dc --- /dev/null +++ b/addons/ShaderLib/Procedural/Noise/GyroidNoise.gdshaderinc @@ -0,0 +1,7 @@ +float gyroid_noise(vec2 uv, float scale, vec2 ratio, float height, float thickness) { + scale *= 10.; + thickness = clamp(thickness, 0., 1.); + vec3 vector = vec3(uv, height); + vector *= scale; + return abs(dot(sin(vector * ratio.x), cos(vector.zxy * ratio.y))) - thickness; +} \ No newline at end of file diff --git a/addons/ShaderLib/Procedural/Noise/SimpleNoise.gd b/addons/ShaderLib/Procedural/Noise/SimpleNoise.gd index 86dbaa0..fdffb25 100644 --- a/addons/ShaderLib/Procedural/Noise/SimpleNoise.gd +++ b/addons/ShaderLib/Procedural/Noise/SimpleNoise.gd @@ -17,7 +17,7 @@ func _get_return_icon_type() -> VisualShaderNode.PortType: return PORT_TYPE_SCALAR func _get_input_port_count() -> int: - return 2 + return 3 func _get_input_port_name(port: int) -> String: match port: @@ -25,7 +25,8 @@ func _get_input_port_name(port: int) -> String: return "uv" 1: return "scale" - return "" + _: + return "octaves" func _get_input_port_type(port: int) -> VisualShaderNode.PortType: match port: @@ -33,12 +34,15 @@ func _get_input_port_type(port: int) -> VisualShaderNode.PortType: return PORT_TYPE_VECTOR_2D 1: return PORT_TYPE_SCALAR - return PORT_TYPE_SCALAR + _: + return PORT_TYPE_SCALAR_INT func _get_input_port_default_value(port: int) -> Variant: match port: 1: return 10.0 + 2: + return 6 _: return null @@ -62,5 +66,6 @@ func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shad uv = input_vars[0] var scale: String = input_vars[1] + var octaves: String = input_vars[2] - return output_vars[0] + " = simple_noise(%s, %s);" % [uv, scale] + return output_vars[0] + " = simple_noise(%s, %s, %s);" % [uv, scale, octaves] diff --git a/addons/ShaderLib/Procedural/Noise/SimpleNoise.gdshaderinc b/addons/ShaderLib/Procedural/Noise/SimpleNoise.gdshaderinc index 14e30db..31c1f3e 100644 --- a/addons/ShaderLib/Procedural/Noise/SimpleNoise.gdshaderinc +++ b/addons/ShaderLib/Procedural/Noise/SimpleNoise.gdshaderinc @@ -1,32 +1,33 @@ -float noise_random_value(vec2 uv){ - return fract(sin(dot(uv.xy, vec2(12.9898,78.233))) * 43758.5453123); +float simple_noise_random(vec2 point) { + return fract(sin(point.x * 100. + point.y * 654.125) * 55647.8745); } -float value_noise(vec2 uv){ - vec2 _floor = floor(uv); - vec2 _fraction = fract(uv); - _fraction = _fraction * _fraction * (3.0 - 2.0 * _fraction); - vec2 _corner = vec2(1.0, 0.0); +float value_noise(vec2 uv) { + vec2 grid_uv = fract(uv); + vec2 grid_id = floor(uv); + grid_uv = grid_uv * grid_uv * (3. - 2. * grid_uv); - float _c0 = noise_random_value(_floor + _corner.yy); - float _c1 = noise_random_value(_floor + _corner.xy); - float _c2 = noise_random_value(_floor + _corner.yx); - float _c3 = noise_random_value(_floor + _corner.xx); + float bottom_left = simple_noise_random(grid_id); + float bottom_right = simple_noise_random(grid_id + vec2(1, 0)); + float bottom = mix(bottom_left, bottom_right, grid_uv.x); - vec2 _blur = smoothstep(0.0, 1.0, _fraction); - float mix_one = mix(_c0, _c1, _blur.x) + (_c2 - _c0) * _blur.y * (1.0 - _blur.x) + (_c3 - _c1) * _blur.x * _blur.y; - return mix_one; + float top_left = simple_noise_random(grid_id + vec2(0, 1)); + float top_right = simple_noise_random(grid_id + vec2(1, 1)); + float top = mix(top_left, top_right, grid_uv.x); + + return mix(bottom, top, grid_uv.y); } -float simple_noise(vec2 uv, float scale){ - int octaves = 6; - float amplitude = 0.25; - float value = 0.0; +float simple_noise(vec2 uv, float scale, int octaves) { + octaves = clamp(octaves, 1, 6); + float noise = value_noise(uv * scale); + float amplitude = 1.; - for(int i = 0; i < octaves; i++) { - value += amplitude * value_noise(scale * uv); - amplitude *= 0.85; - scale *= 3.0; + for(int i = 1; i < octaves; i++) { + scale *= 2.; + amplitude /= 2.; + noise += value_noise(uv * scale) * amplitude; } - return value; + + return noise / 2.; } \ No newline at end of file diff --git a/addons/ShaderLib/Procedural/Noise/Voronoi.gd b/addons/ShaderLib/Procedural/Noise/Voronoi.gd index 4a139da..303df43 100644 --- a/addons/ShaderLib/Procedural/Noise/Voronoi.gd +++ b/addons/ShaderLib/Procedural/Noise/Voronoi.gd @@ -17,34 +17,63 @@ func _get_return_icon_type() -> VisualShaderNode.PortType: return PORT_TYPE_SCALAR func _get_input_port_count() -> int: - return 3 + var distance_index: int = get_option_index(0) + match distance_index: + 2: + return 4 + _: + return 3 func _get_input_port_name(port: int) -> String: - match port: - 0: - return "uv" - 1: - return "cell density" + var distance_index: int = get_option_index(0) + match distance_index: 2: - return "angle offset" - return "" + match port: + 0: + return "uv" + 1: + return "cell density" + 2: + return "angle offset" + _: + return "chebyshev power" + _: + match port: + 0: + return "uv" + 1: + return "cell density" + _: + return "angle offset" func _get_input_port_type(port: int) -> VisualShaderNode.PortType: match port: 0: return PORT_TYPE_VECTOR_2D - 1, 2: + _: return PORT_TYPE_SCALAR - return PORT_TYPE_SCALAR func _get_input_port_default_value(port: int) -> Variant: - match port: - 1: - return 5.0 + var distance_index: int = get_option_index(0) + match distance_index: 2: - return 2.0 + match port: + 1: + return 5.0 + 2: + return 2.0 + 3: + return 2.0 + _: + return null _: - return null + match port: + 1: + return 5.0 + 2: + return 2.0 + _: + return null func _get_output_port_count() -> int: return 2 @@ -53,13 +82,24 @@ func _get_output_port_name(port: int) -> String: match port: 0: return "output" - 1: + _: return "cells" - return "" func _get_output_port_type(port: int) -> VisualShaderNode.PortType: return PORT_TYPE_SCALAR +func _get_property_count() -> int: + return 1 + +func _get_property_name(index: int) -> String: + return "Distance" + +func _get_property_default_index(index: int) -> int: + return 0 + +func _get_property_options(index: int) -> PackedStringArray: + return ["Euclidean", "Manhattan", "Chebyshev"] + func _get_global_code(mode: Shader.Mode) -> String: var code: String = preload("Voronoi.gdshaderinc").code return code @@ -70,9 +110,17 @@ func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shad if input_vars[0]: uv = input_vars[0] + var distance_index: int = get_option_index(0) + var cell_density: String = input_vars[1] var angle_offset: String = input_vars[2] + var chebyshev_power: String = "0." + + if distance_index == 2: + if input_vars[3]: + chebyshev_power = input_vars[3] + var output: String = output_vars[0] var cells: String = output_vars[1] - return "voronoi_noise(%s,%s, %s, %s, %s);" % [uv, cell_density, angle_offset, output, cells] + return "voronoi_noise(%s, %s, %s, %s, %s, %s, %s);" % [uv, cell_density, angle_offset, distance_index, chebyshev_power, output, cells] diff --git a/addons/ShaderLib/Procedural/Noise/Voronoi.gdshaderinc b/addons/ShaderLib/Procedural/Noise/Voronoi.gdshaderinc index 36213c8..cec15bb 100644 --- a/addons/ShaderLib/Procedural/Noise/Voronoi.gdshaderinc +++ b/addons/ShaderLib/Procedural/Noise/Voronoi.gdshaderinc @@ -1,24 +1,43 @@ -void voronoi_noise(vec2 uv, float cell_density, float angle_offset, out float output, out float cells){ - vec2 _g = floor(uv * cell_density); - vec2 _f = fract(uv * cell_density); - vec3 _res = vec3(8.0, 0.0, 0.0); - mat2 _matrix = mat2(vec2(15.27, 47.63), vec2(99.41, 89.98)); - - for(int y=-1; y<=1; y++) - { - for(int x=-1; x<=1; x++) - { - vec2 lattice = vec2(float(x), float(y)); - vec2 new_uv = lattice + _g; - new_uv = fract(sin(new_uv * _matrix) * 46839.32); - vec2 offset = vec2(sin(new_uv.y * angle_offset) * 0.5 + 0.5, cos(new_uv.x * angle_offset) * 0.5 + 0.5); - float d = distance(lattice + offset, _f); - if(d < _res.x) - { - _res = vec3(d, offset.x, offset.y); - output = _res.x; - cells = _res.y; +#include "res://addons/ShaderLib/Maths/Vector/Distance/Manhattan2D.gdshaderinc" +#include "res://addons/ShaderLib/Maths/Vector/Distance/Chebyshev2D.gdshaderinc" + +vec2 voronoi_random_vector(vec2 p) { + mat2 matrix = mat2(vec2(15.27, 47.63), vec2(99.41, 89.98)); + return fract(sin(p * matrix) * 46839.32); +} + +void voronoi_noise(vec2 uv, float cell_density, float angle_offset, int distance_index, float chebyshev_power, out float output, out float cells){ + vec2 grid_uv = fract(uv * cell_density); + vec2 grid_id = floor(uv * cell_density); + vec2 cell_id = vec2(0); + float min_dist = 100.; + + for(float y = -1.; y <= 1.; y++) { + for(float x = -1.; x <= 1.; x++) { + vec2 offset = vec2(x, y); + vec2 n = voronoi_random_vector(grid_id + offset); + vec2 p = offset + vec2(sin(n.x + angle_offset) * .5 + .5, cos(n.y + angle_offset) * .5 + .5); + float d = min_dist; + + switch(distance_index){ + case 1: + d = manhattan_distance_2d(grid_uv, p); + break; + case 2: + d = chebyshev_distance_2d(grid_uv, p, chebyshev_power); + break; + default: + d = distance(grid_uv, p); + break; + } + + if(d < min_dist) { + min_dist = d; + cell_id = voronoi_random_vector(grid_id + offset); } } } + + output = min_dist; + cells = cell_id.y; } \ No newline at end of file diff --git a/addons/ShaderLib/RayMarching/RayMarch.gd b/addons/ShaderLib/RayMarching/RayMarch.gd new file mode 100644 index 0000000..acab6b9 --- /dev/null +++ b/addons/ShaderLib/RayMarching/RayMarch.gd @@ -0,0 +1,239 @@ +@tool +class_name VisualShaderNodeRayMarch extends VisualShaderNodeCustom + +func _get_name() -> String: + return "RayMarch" + +func _get_category() -> String: + return "RayMarching" + +func _get_description() -> String: + return "A simple ray marcher for primitive shapes." + +func _get_return_icon_type() -> PortType: + return PORT_TYPE_SCALAR + +func _get_input_port_count() -> int: + var sdf_index: int = get_option_index(0) + match sdf_index: + 2, 3, 4: + return 9 + _: + return 8 + +func _get_input_port_name(port: int) -> String: + var sdf_index: int = get_option_index(0) + match sdf_index: + 0, 1: + match port: + 0: + return "ray origin" + 1: + return "ray direction" + 2: + return "max steps" + 3: + return "max distance" + 4: + return "distance threshold" + 5: + return "cube pos" if sdf_index == 0 else "sphere pos" + 6: + return "cube eulers" if sdf_index == 0 else "sphere eulers" + _: + return "cube scale" if sdf_index == 0 else "sphere scale" + 2, 3: + match port: + 0: + return "ray origin" + 1: + return "ray direction" + 2: + return "max steps" + 3: + return "max distance" + 4: + return "distance threshold" + 5: + return "capsule pos" if sdf_index == 2 else "cylinder pos" + 6: + return "capsule eulers" if sdf_index == 2 else "cylinder eulers" + 7: + return "capsule height" if sdf_index == 2 else "cylinder height" + _: + return "capsule radius" if sdf_index == 2 else "cylinder radius" + _: + match port: + 0: + return "ray origin" + 1: + return "ray direction" + 2: + return "max steps" + 3: + return "max distance" + 4: + return "distance threshold" + 5: + return "torus pos" + 6: + return "torus eulers" + 7: + return "torus small radius" + _: + return "torus big radius" + +func _get_input_port_type(port: int) -> PortType: + var sdf_index: int = get_option_index(0) + match sdf_index: + 0, 1: + match port: + 0, 1, 5, 6, 7: + return PORT_TYPE_VECTOR_3D + 2: + return PORT_TYPE_SCALAR_INT + _: + return PORT_TYPE_SCALAR + 2, 3: + match port: + 0, 1, 5, 6: + return PORT_TYPE_VECTOR_3D + 2: + return PORT_TYPE_SCALAR_INT + _: + return PORT_TYPE_SCALAR + _: + match port: + 0, 1, 5, 6: + return PORT_TYPE_VECTOR_3D + 2: + return PORT_TYPE_SCALAR_INT + _: + return PORT_TYPE_SCALAR + +func _get_input_port_default_value(port: int) -> Variant: + var sdf_index: int = get_option_index(0) + match sdf_index: + 0, 1: + match port: + 0, 5, 6: + return Vector3(0, 0, 0) + 1: + return Vector3(0 ,0 ,-1) + 2: + return 15 + 3: + return 15.0 + 7: + return Vector3(0.3, 0.3, 0.3) + _: + return 1e-2 + 2, 3: + match port: + 0, 5, 6: + return Vector3(0, 0, 0) + 1: + return Vector3(0 ,0 ,-1) + 2: + return 15 + 3: + return 15.0 + 4: + return 1e-2 + 7: + return .5 if sdf_index == 2 else 1.0 + _: + return .3 + _: + match port: + 0, 5, 6: + return Vector3(0, 0, 0) + 1: + return Vector3(0 ,0 ,-1) + 2: + return 15 + 3: + return 15.0 + 4: + return 1e-2 + 7: + return 0.1 + _: + return 0.4 + +func _get_property_count() -> int: + return 1 + +func _get_property_default_index(index: int) -> int: + return 0 + +func _get_property_name(index: int) -> String: + return "SDF" + +func _get_property_options(index: int) -> PackedStringArray: + return ["SDBox", "SDSphere", "SDCapsule", "SDCylinder", "SDTorus"] + +func _get_output_port_count() -> int: + return 1 + +func _get_output_port_name(port: int) -> String: + return "distance" + +func _get_output_port_type(port: int) -> PortType: + return PORT_TYPE_SCALAR + +func _get_global_code(mode: Shader.Mode) -> String: + var code: String + var sdf_index: int = get_option_index(0) + code = preload("RayMarchRotation.gdshaderinc").code + match sdf_index: + 0: + code += preload("SDBox.gdshaderinc").code + 1: + code += preload("SDSphere.gdshaderinc").code + 2: + code += preload("SDCapsule.gdshaderinc").code + 3: + code += preload("SDCylinder.gdshaderinc").code + _: + code += preload("SDTorus.gdshaderinc").code + return code + +func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String: + var sdf_index: int = get_option_index(0) + var ray_origin: String = input_vars[0] + var ray_direction: String = input_vars[1] + var max_steps: String = input_vars[2] + var max_dist: String = input_vars[3] + var dist_threshold: String = input_vars[4] + + match sdf_index: + 0: + var cube_pos: String = input_vars[5] + var eulers: String = input_vars[6] + var size: String = input_vars[7] + return output_vars[0] + " = ray_march_sd_box(%s, %s, %s, %s, %s, %s, %s, %s);" % [ray_origin, ray_direction, max_steps, max_dist, dist_threshold, cube_pos, eulers, size] + 1: + var sphere_pos: String = input_vars[5] + var eulers: String = input_vars[6] + var scale: String = input_vars[7] + return output_vars[0] + " = ray_march_sd_sphere(%s, %s, %s, %s, %s, %s, %s, %s);" % [ray_origin, ray_direction, max_steps, max_dist, dist_threshold, sphere_pos, eulers, scale] + 2: + var capsule_pos: String = input_vars[5] + var capsule_eulers: String = input_vars[6] + var capsule_height: String = input_vars[7] + var capsule_radius: String = input_vars[8] + return output_vars[0] + " = ray_march_sd_capsule(%s, %s, %s, %s, %s, %s, %s, %s, %s);" % [ray_origin, ray_direction, max_steps, max_dist, dist_threshold, capsule_pos, capsule_height, capsule_radius, capsule_eulers] + 3: + var cylinder_pos: String = input_vars[5] + var cylinder_eulers: String = input_vars[6] + var cylinder_height: String = input_vars[7] + var cylinder_radius: String = input_vars[8] + return output_vars[0] + " = ray_march_sd_cylinder(%s, %s, %s, %s, %s, %s, %s, %s, %s);" % [ray_origin, ray_direction, max_steps, max_dist, dist_threshold, cylinder_pos, cylinder_height, cylinder_radius, cylinder_eulers] + _: + var torus_pos: String = input_vars[5] + var eulers: String = input_vars[6] + var small_radius: String = input_vars[7] + var big_radius: String = input_vars[8] + return output_vars[0] + " = ray_march_sd_torus(%s, %s, %s, %s, %s, %s, %s, %s, %s);" % [ray_origin, ray_direction, max_steps, max_dist, dist_threshold, torus_pos, eulers, small_radius, big_radius] + diff --git a/addons/ShaderLib/RayMarching/RayMarchCustom.gdshaderinc b/addons/ShaderLib/RayMarching/RayMarchCustom.gdshaderinc new file mode 100644 index 0000000..1a46c9e --- /dev/null +++ b/addons/ShaderLib/RayMarching/RayMarchCustom.gdshaderinc @@ -0,0 +1,21 @@ +float sdf_custom(vec3 p) { + // Basic example of Sphere SDF with radius of .3 + // Put your custom logic here + float radius = .3; + return length(p) - radius; +} + +float ray_march_custom(vec3 ray_origin, vec3 ray_dir, int max_steps, float max_dist, float dist_threshold) { + ray_dir = normalize(ray_dir); + dist_threshold = abs(dist_threshold); + float dist_from_origin = 0.; + float dist_to_surface; + for(int i = 0; i < max_steps; i++) { + vec3 point = ray_origin + dist_from_origin * ray_dir; + dist_to_surface = sdf_custom(point); + dist_from_origin += dist_to_surface; + if(dist_to_surface < dist_threshold || dist_to_surface > max_dist) + break; + } + return dist_from_origin; +} \ No newline at end of file diff --git a/addons/ShaderLib/RayMarching/RayMarchRotation.gdshaderinc b/addons/ShaderLib/RayMarching/RayMarchRotation.gdshaderinc new file mode 100644 index 0000000..6f88c7e --- /dev/null +++ b/addons/ShaderLib/RayMarching/RayMarchRotation.gdshaderinc @@ -0,0 +1,7 @@ +mat2 rm_rotation(float angle) { + angle = -angle * (3.1415926 / 180.); + return mat2( + vec2(cos(angle), -sin(angle)), + vec2(sin(angle), cos(angle)) + ); +} diff --git a/addons/ShaderLib/RayMarching/SDBox.gdshaderinc b/addons/ShaderLib/RayMarching/SDBox.gdshaderinc new file mode 100644 index 0000000..3da6be7 --- /dev/null +++ b/addons/ShaderLib/RayMarching/SDBox.gdshaderinc @@ -0,0 +1,21 @@ +float sd_box(vec3 point, vec3 size, vec3 eulers) { + point.yz *= rm_rotation(eulers.x); + point.xy *= rm_rotation(eulers.z); + point.xz *= rm_rotation(-eulers.y); + return length(max(abs(point) - size, vec3(0))); +} + +float ray_march_sd_box(vec3 ray_origin, vec3 ray_dir, int max_steps, float max_dist, float dist_threshold, vec3 cube_pos, vec3 eulers, vec3 size) { + ray_dir = normalize(ray_dir); + dist_threshold = abs(dist_threshold); + float dist_from_origin = 0.; + float dist_to_surface; + for(int i = 0; i < max_steps; i++) { + vec3 point = ray_origin + dist_from_origin * ray_dir; + dist_to_surface = sd_box(point - cube_pos, size, eulers); + dist_from_origin += dist_to_surface; + if(dist_to_surface < dist_threshold || dist_to_surface > max_dist) + break; + } + return dist_from_origin; +} \ No newline at end of file diff --git a/addons/ShaderLib/RayMarching/SDCapsule.gdshaderinc b/addons/ShaderLib/RayMarching/SDCapsule.gdshaderinc new file mode 100644 index 0000000..75d56d9 --- /dev/null +++ b/addons/ShaderLib/RayMarching/SDCapsule.gdshaderinc @@ -0,0 +1,33 @@ +float sd_capsule(vec3 point, vec3 capsule_pos, float height, float radius, vec3 eulers) { + vec3 orientation = vec3(0, 1, 0); + orientation.yz *= rm_rotation(eulers.x); + orientation.xy *= rm_rotation(eulers.z); + orientation.xz *= rm_rotation(-eulers.y); + + vec3 top_point = point + orientation * (height * .5); + vec3 bottom_point = point - orientation * (height * .5); + + vec3 height_vector = bottom_point - top_point; + vec3 top_distance = capsule_pos - top_point; + + float t = dot(height_vector, top_distance) / dot(height_vector, height_vector); + t = clamp(t, 0., 1.); + vec3 hit_point = top_point + t * height_vector; + + return length(capsule_pos - hit_point) - radius; +} + +float ray_march_sd_capsule(vec3 ray_origin, vec3 ray_dir, int max_steps, float max_dist, float dist_threshold, vec3 capsule_pos, float capsule_height, float capsule_radius, vec3 eulers) { + ray_dir = normalize(ray_dir); + dist_threshold = abs(dist_threshold); + float dist_from_origin = 0.; + float dist_to_surface; + for(int i = 0; i < max_steps; i++) { + vec3 point = ray_origin + dist_from_origin * ray_dir; + dist_to_surface = sd_capsule(point, capsule_pos, capsule_height, capsule_radius, eulers); + dist_from_origin += dist_to_surface; + if(dist_to_surface < dist_threshold || dist_to_surface > max_dist) + break; + } + return dist_from_origin; +} \ No newline at end of file diff --git a/addons/ShaderLib/RayMarching/SDCylinder.gdshaderinc b/addons/ShaderLib/RayMarching/SDCylinder.gdshaderinc new file mode 100644 index 0000000..0b5316e --- /dev/null +++ b/addons/ShaderLib/RayMarching/SDCylinder.gdshaderinc @@ -0,0 +1,37 @@ +float sd_cylinder(vec3 point, vec3 cylinder_pos, float height, float radius, vec3 eulers) { + vec3 orientation = vec3(0, 1, 0); + orientation.yz *= rm_rotation(eulers.x); + orientation.xy *= rm_rotation(eulers.z); + orientation.xz *= rm_rotation(-eulers.y); + + vec3 top_point = point + orientation * (height * .5); + vec3 bottom_point = point - orientation * (height * .5); + + vec3 height_vector = bottom_point - top_point; + vec3 top_distance = cylinder_pos - top_point; + + float t = dot(height_vector, top_distance) / dot(height_vector, height_vector); + vec3 hit_point = top_point + t * height_vector; + + float x = length(cylinder_pos - hit_point) - radius; + float y = (abs(t - .5) - .5) * length(height_vector); + float e = length(max(vec2(x, y), 0)); + float i = min(max(x, y), 0.); + + return e + i; +} + +float ray_march_sd_cylinder(vec3 ray_origin, vec3 ray_dir, int max_steps, float max_dist, float dist_threshold, vec3 cylinder_pos, float cylinder_height, float cylinder_radius, vec3 eulers) { + ray_dir = normalize(ray_dir); + dist_threshold = abs(dist_threshold); + float dist_from_origin = 0.; + float dist_to_surface; + for(int i = 0; i < max_steps; i++) { + vec3 point = ray_origin + dist_from_origin * ray_dir; + dist_to_surface = sd_cylinder(point, cylinder_pos, cylinder_height, cylinder_radius, eulers); + dist_from_origin += dist_to_surface; + if(dist_to_surface < dist_threshold || dist_to_surface > max_dist) + break; + } + return dist_from_origin; +} \ No newline at end of file diff --git a/addons/ShaderLib/RayMarching/SDSphere.gdshaderinc b/addons/ShaderLib/RayMarching/SDSphere.gdshaderinc new file mode 100644 index 0000000..7319423 --- /dev/null +++ b/addons/ShaderLib/RayMarching/SDSphere.gdshaderinc @@ -0,0 +1,23 @@ +float sd_sphere(vec3 point, vec3 eulers, vec3 scale) { + float radius = 1.; + point.yz *= rm_rotation(eulers.x); + point.xy *= rm_rotation(eulers.z); + point.xz *= rm_rotation(-eulers.y); + point /= scale; + return (length(point) - radius) * min(scale.x, min(scale.y, scale.z)); +} + +float ray_march_sd_sphere(vec3 ray_origin, vec3 ray_dir, int max_steps, float max_dist, float dist_threshold, vec3 sphere_pos, vec3 eulers, vec3 scale) { + ray_dir = normalize(ray_dir); + dist_threshold = abs(dist_threshold); + float dist_from_origin = 0.; + float dist_to_surface; + for(int i = 0; i < max_steps; i++) { + vec3 point = ray_origin + dist_from_origin * ray_dir; + dist_to_surface = sd_sphere(point - sphere_pos, eulers, scale); + dist_from_origin += dist_to_surface; + if(dist_to_surface < dist_threshold || dist_to_surface > max_dist) + break; + } + return dist_from_origin; +} \ No newline at end of file diff --git a/addons/ShaderLib/RayMarching/SDTorus.gdshaderinc b/addons/ShaderLib/RayMarching/SDTorus.gdshaderinc new file mode 100644 index 0000000..37c9746 --- /dev/null +++ b/addons/ShaderLib/RayMarching/SDTorus.gdshaderinc @@ -0,0 +1,21 @@ +float sd_torus(vec3 point, float small_radius, float big_radius, vec3 eulers) { + point.yz *= rm_rotation(eulers.x); + point.xy *= rm_rotation(eulers.z); + point.xz *= rm_rotation(-eulers.y); + return length(vec2(length(point.xz) - big_radius, point.y)) - small_radius; +} + +float ray_march_sd_torus(vec3 ray_origin, vec3 ray_dir, int max_steps, float max_dist, float dist_threshold, vec3 torus_pos, vec3 eulers, float small_radius, float big_radius) { + ray_dir = normalize(ray_dir); + dist_threshold = abs(dist_threshold); + float dist_from_origin = 0.; + float dist_to_surface; + for(int i = 0; i < max_steps; i++) { + vec3 point = ray_origin + dist_from_origin * ray_dir; + dist_to_surface = sd_torus(point - torus_pos, small_radius, big_radius, eulers); + dist_from_origin += dist_to_surface; + if(dist_to_surface < dist_threshold || dist_to_surface > max_dist) + break; + } + return dist_from_origin; +} \ No newline at end of file diff --git a/documentation/Documentation.md b/documentation/Documentation.md index 90f5a2a..2731592 100644 --- a/documentation/Documentation.md +++ b/documentation/Documentation.md @@ -32,6 +32,11 @@ For example if you want to rotate UV in your **_.gdshader_** file, you can use `