1
0
mirror of https://github.com/DigvijaysinhGohil/Godot-Shader-Lib.git synced 2025-01-05 00:53:36 +08:00

Merge branch 'godot-4.2'

This commit is contained in:
Digvijaysinh Gohil 2024-03-27 11:48:44 +05:30
commit 6576785b47
31 changed files with 980 additions and 78 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
# Godot 4+ specific ignores
.godot/
tests/
*.import

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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]

View File

@ -0,0 +1,4 @@
float manhattan_distance_2d(vec2 point1, vec2 point2) {
vec2 d = point1 - point2;
return abs(d.x) + abs(d.y);
}

View File

@ -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);
}

View File

@ -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]

View File

@ -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);
}

View File

@ -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]

View File

@ -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;
}

View File

@ -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]

View File

@ -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.;
}

View File

@ -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]

View File

@ -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;
}

View File

@ -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]

View File

@ -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;
}

View File

@ -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))
);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -32,6 +32,11 @@ For example if you want to rotate UV in your **_.gdshader_** file, you can use `
<h3>&emsp;Vector</h3>
<h3>&emsp;&emsp;Distance</h3>
<h4><a href="/documentation/Nodes/Maths/Vector/Distance/ChebyshevDistance.md">&emsp;&emsp;&emsp;Chebyshev Distance node</a></h4>
<h4><a href="/documentation/Nodes/Maths/Vector/Distance/ManhattanDistance.md">&emsp;&emsp;&emsp;Manhattan Distance node</a></h4>
<h4><a href="/documentation/Nodes/Maths/Vector/Project.md">&emsp;&emsp;Project node</a></h4>
<h4><a href="/documentation/Nodes/Maths/Vector/ProjectOnPlane.md">&emsp;&emsp;Project On Plane node</a></h4>
<h4><a href="/documentation/Nodes/Maths/Vector/VectorTransform.md">&emsp;&emsp;Vector Transform node</a></h4>
@ -54,6 +59,7 @@ For example if you want to rotate UV in your **_.gdshader_** file, you can use `
<h3>&emsp;Noise</h3>
<h4><a href="/documentation/Nodes/Procedural/Noise/GradientNoise.md">&emsp;&emsp;Gradient Noise node</a></h4>
<h4><a href="/documentation/Nodes/Procedural/Noise/GyroidNoise.md">&emsp;&emsp;Gyroid Noise node</a></h4>
<h4><a href="/documentation/Nodes/Procedural/Noise/PseudoRandomNoise.md">&emsp;&emsp;Pseudo Random Noise node</a></h4>
<h4><a href="/documentation/Nodes/Procedural/Noise/SimpleNoise.md">&emsp;&emsp;Simple Noise node</a></h4>
<h4><a href="/documentation/Nodes/Procedural/Noise/Voronoi.md">&emsp;&emsp;Voronoi node</a></h4>
@ -66,6 +72,10 @@ For example if you want to rotate UV in your **_.gdshader_** file, you can use `
<h4><a href="/documentation/Nodes/Procedural/Shapes/RoundedPolygon.md">&emsp;&emsp;Rounded Polygon node</a></h4>
<h4><a href="/documentation/Nodes/Procedural/Shapes/RoundedRectangle.md">&emsp;&emsp;Rounded Rectangle node</a></h4>
<h2>Ray marching nodes</h2>
<h4><a href="/documentation/Nodes/RayMarching/RayMarch.md">&emsp;Ray March node</a></h4>
<h2>UV nodes</h2>
<h4><a href="/documentation/Nodes/UV/Flipbook.md">&emsp;Flipbook node</a></h4>

View File

@ -0,0 +1,21 @@
# Chebyshev Distance node
Returns the distance between two points using Chebyshev distance matrix.
<hr>
**Controls**
|Options|Description|
|---|---|
|Vector2, Vector3|Vector type to use for calculation|
**Inputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|a|Dynamic vector|none|Point a|
|b|Dynamic vector|none|Point b|
|power|float|none|Power to use for Chebyshev distance|
**Outputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|distance|float|None|Distance between 2 points|
___

View File

@ -0,0 +1,20 @@
# Manhattan Distance node
Returns the distance between two points using Manhattan distance matrix.
<hr>
**Controls**
|Options|Description|
|---|---|
|Vector2, Vector3|Vector type to use for calculation|
**Inputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|a|Dynamic vector|none|Point a|
|b|Dynamic vector|none|Point b|
**Outputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|distance|float|None|Distance between 2 points|
___

View File

@ -0,0 +1,18 @@
# Gyroid Noise node
Generates a gyroid noise based on input UV. The resulting <b><i>output</i></b> values will be between 0 and 1.
<hr>
**Inputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|uv|vec2|UV|Input UV value|
|scale|float|none|Noise scale|
|ratio|vec2|none|Noise ratio for X and Y Axes|
|height|float|none|Noise height|
|thickness|float|none|Noise thickness, clamped between 0 and 1|
**Outputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|output|float|None|Output noise value|
___

View File

@ -7,6 +7,7 @@ Generates a simplex, or value noise based on input UV. The resulting <b><i>outpu
|---|---|---|---|
|uv|vec2|UV|Input UV value|
|scale|float|none|Noise scale|
|octaves|int|none|Octaves/Layers of noise, <b><i>octaves</i></b> input is clamped between 1 and 6.|
**Outputs**
|Name|Type|Binding|Description|

View File

@ -2,12 +2,18 @@
Generates a Voronoi or Worley noise based on input UV. Voronoi noise is generated by calculating distances between a pixel and a lattice of points. By offsetting these points by a pseudo-random number, controlled by <b><i>angle offset</i></b>, a cluster of cells can be generated.
<hr>
**Controls**
|Name|Options|Description|
|---|---|---|
|Distance|Euclidean, Manhattan, Chebyshev|Distance matrix used to calculate the noise|
**Inputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|uv|vec2|UV|Input UV value|
|cell density|float|none|Density of generated cells|
|angle offset|float|none|Offset values for points|
|chebyshev power|float|none|Power values for Chebyshev distance matrix|
**Outputs**
|Name|Type|Binding|Description|

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@ -0,0 +1,58 @@
# Ray March node
A simple ray marcher for primitive shapes.
<hr>
**Controls**
|Name|Options|Description|
|---|---|---|
|SDF (Signed Distance Function)|SDBox, SDSphere, SDCapsule, SDCylinder, SDTorus|Signed Distance Functions for the space to draw.|
**Inputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|signed distance|float|none|Signed distance calculated from Signed Distance Functions (SDFs)|
|ray origin|vec3|none|Ray origin|
|ray direction|vec3|none|Normalized ray direction|
|max steps|int|none|Maximum number of steps for ray marching|
|max distance|float|none|Maximum distance to march along the <b><i>ray direction</i></b>|
|distance threshold|float|none|Threshold to check against <b><i>signed distance</i></b> to determine the ray intersection point.|
**SDFs Inputs**
|Name|Type|Availability|Description|
|---|---|---|---|
|cube pos|vec3|SDBox|Position offset of the box shape|
|cube eulers|vec3|SDBox|Rotation of the box shape in Degrees|
|cube scale|vec3|SDBox|Scale of the box shape|
|sphere pos|vec3|SDSphere|Position offset of the sphere shape|
|sphere eulers|vec3|SDSphere|Rotation of the box sphere in Degrees|
|sphere scale|vec3|SDSphere|Scale of the sphere shape|
|capsule pos|vec3|SDCapsule|Position offset of the capsule shape|
|capsule eulers|vec3|SDCapsule|Rotation of the capsule shape in Degrees|
|capsule height|float|SDCapsule|Height of the capsule shape|
|capsule radius|float|SDCapsule|Radius of the capsule shape|
|cylinder pos|vec3|SDCylinder|Position offset of the cylinder shape|
|cylinder eulers|vec3|SDCylinder|Rotation of the cylinder shape in Degrees|
|cylinder height|float|SDCylinder|Height of the cylinder shape|
|cylinder radius|float|SDCylinder|Radius of the cylinder shape|
|torus pos|vec3|SDTorus|Position offset of the torus shape|
|torus eulers|vec3|SDTorus|Rotation of the torus shape in Degrees|
|torus small radius|float|SDTorus|Small radius of the torus shape|
|torus big radius|float|SDTorus|Big radius of the torus shape|
**Outputs**
|Name|Type|Binding|Description|
|---|---|---|---|
|distance|float|None|Ray intersection distance|
<hr>
<h3>Extras</h3>
This node is only simple ray marching example, the true power of raymarching can only be achieved by custom SDFs. At the moment I am unable to inject the custom code via visual shaders, so I have provided the custom template at the following location.<br><br>
The default location can be found at<br>
`res://addons/ShaderLib/RayMarching/RayMarchCustom.gdshaderinc`
You can copy the code from `RayMarchCustom.gdshaderinc` and then create a <b><i>Global Expression</i></b> node and paste it in your visual shader.<br><br>
![Global Expression Node](GlobalExpression.jpg)<br><br>
Lastly you also need to create an <b><i>Expression</i></b> node, define required input and output parameters and call the custom ray marching function as below.<br><br>
![Expression Node](Expression.jpg)<br>
___