BumpOffset VisualShaderNode 4.4
A visual shader node for a simple one-step UV distortion effect meant to clone the functionality of the BumpOffset node in Unreal. Added output for offset only in case user would like to use it directly (eg add parallax effect to another texture with unique tiling without recomputing) and a channel selector for which heightmap channel to use for the parallax.
Craters texture is just an example of how you would use it with a heightmap.
To use this script, copy paste it into a .gd file. It will show up in the Addons/UV category when adding a new visual shader node
Shader code
@tool
extends VisualShaderNodeCustom
class_name VSNode_BumpOffset
const HEIGHT_CONSTANT_SCALE : float = 0.1
#########################
### Editor Shader Props
#########################
func _get_name() -> String:
return "BumpOffset"
func _get_category() -> String:
return "UV"
func _get_description() -> String:
return "Distorts the uvs to appear to have parallax based on a heightmap. UE equivalent is BumpOffset node."
func _get_return_icon_type() -> PortType:
return VisualShaderNode.PORT_TYPE_VECTOR_2D
#########################
### Input Ports
#########################
func _get_input_port_count() -> int:
return 4
func _get_input_port_name(port: int) -> String:
match port:
0: return "UV"
1: return "Height Map T2D"
2: return "Depth Scale"
3: return "Midpoint"
return ""
func _get_input_port_type(port: int) -> PortType:
match port:
0: return VisualShaderNode.PORT_TYPE_VECTOR_2D
1: return VisualShaderNode.PORT_TYPE_SAMPLER
2: return VisualShaderNode.PORT_TYPE_SCALAR
3: return VisualShaderNode.PORT_TYPE_SCALAR
return VisualShaderNode.PORT_TYPE_VECTOR_2D
func _get_input_port_default_value(port: int) -> Variant:
match port:
0: return Vector2(0, 0)
1: return ImageTexture.new()
2: return 0.1
3: return 0.5
return Vector2(0, 0)
func _get_property_count() -> int:
return 1
func _get_property_name(index: int) -> String:
match index:
0: return "Heightmap Channel"
return ""
func _get_property_options(index: int) -> PackedStringArray:
match index:
0: return ["R", "G", "B", "A"]
return []
##########################
### Output Ports
##########################
func _get_output_port_count() -> int:
return 2
func _get_output_port_name(port: int) -> String:
match port:
0: return "UV"
1: return "Offset"
return "UV"
func _get_output_port_type(port: int) -> PortType:
match port:
0: return VisualShaderNode.PORT_TYPE_VECTOR_2D
1: return VisualShaderNode.PORT_TYPE_VECTOR_2D
return VisualShaderNode.PORT_TYPE_VECTOR_2D
###########################
### Global code
###########################
func _get_global_code(mode: Shader.Mode) -> String:
return """
"""
###########################
### Insert Code
###########################
func _get_code(input_vars: Array[String], output_vars: Array[String],
mode: Shader.Mode, type: VisualShader.Type) -> String:
var channel_idx : int = get_option_index(0)
var height_name : String = "r"
match channel_idx:
0: height_name = "r"
1: height_name = "g"
2: height_name = "b"
3: height_name = "a"
if type == VisualShader.TYPE_FRAGMENT:
return """
{
vec2 uv = %s; // inputted uv - s is the uv coord
vec3 view_direction = normalize( -VERTEX + EYE_OFFSET ); // View direction in world space
mat3 tbn = mat3(-TANGENT, BINORMAL, NORMAL); // Tangent Binormal Normal matrix
vec3 view_tangent_space = view_direction * tbn; // Transform view direction to tangent space
float height = %s - texture( %s, uv ).%s; // Sample the height map, invert
vec2 uv_offset = view_tangent_space.xy * height * %s * %s; // Calculate the uv offset
vec2 distorted_uv = uv + uv_offset; // Add the offset to the original uv
%s = distorted_uv; // Output the distorted uv
%s = uv_offset; // Output the offset
}
""" % [input_vars[0], input_vars[3], input_vars[1], height_name, input_vars[2], HEIGHT_CONSTANT_SCALE, output_vars[0], output_vars[1]]
else:
return ""
func _is_available(mode: Shader.Mode, type: VisualShader.Type) -> bool:
return type == VisualShader.TYPE_FRAGMENT