Shield with impact visualisation
This shield was made using visual shaders and so I have provided the visual shader resource (for easier editing), which includes the generated shader code. The voronoi section was made using an expression block due to its complexity. To use this shader, you must first tune the basic parameters to your liking (you may wish to turn off the voronoi if it is too detailed for your game). To use the collision visualisation, you must provide all but the collision time and position beforehand. When you get a collision, you must set the collision position to where you want to collision to originate from IN GLOBAL COORDINATES. Additionally at collision time, you must set the collision time parameter to OS.get_ticks_msec()/1000 in order for the shader to calculate how long it has been since the collision took place. For testing how it looks, there is a feature to loop the first second of the shader. If you turn this on, be sure to set the collision time to 0 to match up with the looping shader time.
Shader code
[gd_resource type="VisualShader" load_steps=54 format=2]
[sub_resource type="VisualShaderNodeScalarOp" id=2]
default_input_values = [ 0, 0.0, 1, 0.5 ]
operator = 2
[sub_resource type="VisualShaderNodeColorUniform" id=3]
uniform_name = "ShieldColour"
[sub_resource type="VisualShaderNodeScalarUniform" id=4]
uniform_name = "BreathingAmount"
[sub_resource type="VisualShaderNodeScalarUniform" id=5]
uniform_name = "Thinness"
[sub_resource type="VisualShaderNodeExpression" id=6]
output_port_for_preview = 0
size = Vector2( 661, 792 )
expression = "vec2 index_uv = floor(vec2(uv.x * columns, uv.y * rows));
vec2 fract_uv = fract(vec2(uv.x * columns, uv.y * rows));
minimum_dist = 1.0;
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
vec2 neighbor = vec2(float(x),float(y));
vec2 p = index_uv + neighbor;
vec2 point = vec2(fract(sin(dot(p.xy,
vec2(12.9898,78.233))) * 43758.5453123)) * clamp(offset.xy, 0, 1);
vec2 diff = neighbor + point - fract_uv;
float dist = length(diff);
minimum_dist = min(minimum_dist, dist);
}
}
"
[sub_resource type="VisualShaderNodeInput" id=7]
input_name = "uv"
[sub_resource type="VisualShaderNodeVectorOp" id=9]
[sub_resource type="VisualShaderNodeInput" id=10]
input_name = "normal"
[sub_resource type="VisualShaderNodeInput" id=11]
input_name = "time"
[sub_resource type="VisualShaderNodeScalarFunc" id=12]
function = 0
[sub_resource type="VisualShaderNodeScalarOp" id=13]
default_input_values = [ 0, 0.0, 1, 0.2 ]
operator = 2
[sub_resource type="VisualShaderNodeScalarFunc" id=14]
function = 1
[sub_resource type="VisualShaderNodeVectorCompose" id=15]
[sub_resource type="VisualShaderNodeScalarOp" id=16]
default_input_values = [ 0, 0.0, 1, 0.6 ]
[sub_resource type="VisualShaderNodeScalarOp" id=17]
default_input_values = [ 0, 0.0, 1, 0.6 ]
[sub_resource type="VisualShaderNodeScalarOp" id=18]
default_input_values = [ 0, 0.0, 1, 0.2 ]
operator = 2
[sub_resource type="VisualShaderNodeInput" id=19]
input_name = "view"
[sub_resource type="VisualShaderNodeScalarOp" id=20]
default_input_values = [ 0, 0.0, 1, 7.21 ]
operator = 2
[sub_resource type="VisualShaderNodeScalarOp" id=21]
default_input_values = [ 0, 0.0, 1, 6.32 ]
operator = 2
[sub_resource type="VisualShaderNodeScalarOp" id=22]
operator = 5
[sub_resource type="VisualShaderNodeScalarFunc" id=23]
function = 31
[sub_resource type="VisualShaderNodeScalarUniform" id=24]
uniform_name = "XOscillationSpeed"
[sub_resource type="VisualShaderNodeScalarUniform" id=25]
uniform_name = "YOscillationSpeed"
[sub_resource type="VisualShaderNodeScalarUniform" id=26]
uniform_name = "XOscillationOffset"
[sub_resource type="VisualShaderNodeScalarUniform" id=27]
uniform_name = "YOscillationOffset"
[sub_resource type="VisualShaderNodeScalarUniform" id=28]
uniform_name = "XOscillationAmount"
[sub_resource type="VisualShaderNodeScalarUniform" id=29]
uniform_name = "YOscillationAmount"
[sub_resource type="VisualShaderNodeDotProduct" id=30]
[sub_resource type="VisualShaderNodeScalarUniform" id=31]
uniform_name = "CollisionTime"
[sub_resource type="VisualShaderNodeVec3Uniform" id=32]
uniform_name = "CollisionPosition"
[sub_resource type="VisualShaderNodeInput" id=33]
input_name = "time"
[sub_resource type="VisualShaderNodeScalarUniform" id=35]
uniform_name = "CollisionProp"
[sub_resource type="VisualShaderNodeScalarOp" id=36]
operator = 1
[sub_resource type="VisualShaderNodeVectorOp" id=37]
operator = 1
[sub_resource type="VisualShaderNodeScalarFunc" id=38]
function = 31
[sub_resource type="VisualShaderNodeScalarOp" id=40]
operator = 2
[sub_resource type="VisualShaderNodeIf" id=41]
default_input_values = [ 0, 0.0, 1, 0.0, 2, 0.01, 3, Vector3( 0, 0, 0 ), 4, Vector3( 0, 0, 0 ), 5, Vector3( 0, 0, 0 ) ]
[sub_resource type="VisualShaderNodeBooleanUniform" id=48]
uniform_name = "RepeatCollision"
[sub_resource type="VisualShaderNodeScalarOp" id=49]
default_input_values = [ 0, 0.0, 1, 1.0 ]
operator = 4
[sub_resource type="VisualShaderNodeScalarSwitch" id=50]
[sub_resource type="VisualShaderNodeInput" id=51]
input_name = "camera"
[sub_resource type="VisualShaderNodeInput" id=52]
input_name = "vertex"
[sub_resource type="VisualShaderNodeTransformVecMult" id=53]
[sub_resource type="VisualShaderNodeScalarOp" id=54]
default_input_values = [ 0, 0.05, 1, 0.0 ]
operator = 1
[sub_resource type="VisualShaderNodeScalarOp" id=42]
default_input_values = [ 0, 0.0, 1, 3.0 ]
operator = 5
[sub_resource type="VisualShaderNodeScalarOp" id=55]
default_input_values = [ 0, 0.0, 1, 0.5 ]
operator = 2
[sub_resource type="VisualShaderNodeScalarUniform" id=56]
uniform_name = "CollisionSize"
[sub_resource type="VisualShaderNodeScalarUniform" id=57]
uniform_name = "CollisionFalloff"
[sub_resource type="VisualShaderNodeVectorLen" id=58]
[sub_resource type="VisualShaderNodeScalarUniform" id=59]
uniform_name = "VoronoiGridSize"
[sub_resource type="VisualShaderNodeInput" id=43]
input_name = "time"
[sub_resource type="VisualShaderNodeScalarFunc" id=44]
function = 0
[sub_resource type="VisualShaderNodeScalarOp" id=45]
default_input_values = [ 0, 0.0, 1, 2.0 ]
[resource]
code = "shader_type spatial;
render_mode specular_schlick_ggx;
uniform bool RepeatCollision;
uniform float CollisionTime;
uniform float CollisionProp;
uniform vec3 CollisionPosition;
uniform float CollisionSize;
uniform float CollisionFalloff;
uniform vec4 ShieldColour : hint_color;
uniform float VoronoiGridSize;
uniform float XOscillationSpeed;
uniform float XOscillationAmount;
uniform float XOscillationOffset;
uniform float YOscillationSpeed;
uniform float YOscillationAmount;
uniform float YOscillationOffset;
uniform float BreathingAmount;
uniform float Thinness;
void vertex() {
// Output:0
}
void fragment() {
// BooleanUniform:53
bool n_out53p0 = RepeatCollision;
// Input:43
float n_out43p0 = TIME;
// ScalarOp:54
float n_in54p1 = 1.00000;
float n_out54p0 = mod(n_out43p0, n_in54p1);
// ScalarSwitch:55
float n_out55p0;
if(n_out53p0)
{
n_out55p0 = n_out54p0;
}
else
{
n_out55p0 = n_out43p0;
}
// ScalarUniform:40
float n_out40p0 = CollisionTime;
// ScalarOp:48
float n_out48p0 = n_out55p0 - n_out40p0;
// ScalarUniform:47
float n_out47p0 = CollisionProp;
// ScalarOp:51
float n_out51p0 = n_out48p0 * n_out47p0;
// Input:56
mat4 n_out56p0 = CAMERA_MATRIX;
// Input:57
vec3 n_out57p0 = VERTEX;
// TransformVectorMult:58
vec3 n_out58p0 = (n_out56p0 * vec4(n_out57p0, 1.0)).xyz;
// VectorUniform:41
vec3 n_out41p0 = CollisionPosition;
// VectorOp:49
vec3 n_out49p0 = n_out58p0 - n_out41p0;
// VectorLen:63
float n_out63p0 = length(n_out49p0);
// ScalarUniform:61
float n_out61p0 = CollisionSize;
// ScalarUniform:62
float n_out62p0 = CollisionFalloff;
// ScalarOp:60
float n_out60p0 = n_out48p0 * n_out62p0;
// ScalarOp:59
float n_out59p0 = n_out61p0 - n_out60p0;
// ColorUniform:13
vec3 n_out13p0 = ShieldColour.rgb;
float n_out13p1 = ShieldColour.a;
// Input:2
vec3 n_out2p0 = NORMAL;
// Input:3
vec3 n_out3p0 = VIEW;
// DotProduct:4
float n_out4p0 = dot(n_out2p0, n_out3p0);
// ScalarFunc:5
float n_out5p0 = 1.0 - n_out4p0;
// Input:17
vec3 n_out17p0 = vec3(UV, 0.0);
// ScalarUniform:64
float n_out64p0 = VoronoiGridSize;
// Input:22
float n_out22p0 = TIME;
// ScalarUniform:34
float n_out34p0 = XOscillationSpeed;
// ScalarOp:31
float n_out31p0 = n_out22p0 * n_out34p0;
// ScalarFunc:23
float n_out23p0 = sin(n_out31p0);
// ScalarUniform:38
float n_out38p0 = XOscillationAmount;
// ScalarOp:24
float n_out24p0 = n_out23p0 * n_out38p0;
// ScalarUniform:36
float n_out36p0 = XOscillationOffset;
// ScalarOp:28
float n_out28p0 = n_out24p0 + n_out36p0;
// ScalarUniform:35
float n_out35p0 = YOscillationSpeed;
// ScalarOp:30
float n_out30p0 = n_out22p0 * n_out35p0;
// ScalarFunc:25
float n_out25p0 = cos(n_out30p0);
// ScalarUniform:39
float n_out39p0 = YOscillationAmount;
// ScalarOp:29
float n_out29p0 = n_out25p0 * n_out39p0;
// ScalarUniform:37
float n_out37p0 = YOscillationOffset;
// ScalarOp:27
float n_out27p0 = n_out29p0 + n_out37p0;
// VectorCompose:26
float n_in26p2 = 0.00000;
vec3 n_out26p0 = vec3(n_out28p0, n_out27p0, n_in26p2);
// Expression:16
float n_out16p0;
n_out16p0 = 0.0;
{
vec2 index_uv = floor(vec2(n_out17p0.x * n_out64p0, n_out17p0.y * n_out64p0));
vec2 fract_uv = fract(vec2(n_out17p0.x * n_out64p0, n_out17p0.y * n_out64p0));
n_out16p0 = 1.0;
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
vec2 neighbor = vec2(float(x),float(y));
vec2 p = index_uv + neighbor;
vec2 point = vec2(fract(sin(dot(p.xy,
vec2(12.9898,78.233))) * 43758.5453123)) * clamp(n_out26p0.xy, 0, 1);
vec2 diff = neighbor + point - fract_uv;
float dist = length(diff);
n_out16p0 = min(n_out16p0, dist);
}
}
}
// ScalarFunc:33
float n_out33p0 = 1.0 - n_out16p0;
// ScalarOp:32
float n_out32p0 = pow(n_out5p0, n_out33p0);
// Input:7
float n_out7p0 = TIME;
// ScalarFunc:8
float n_out8p0 = sin(n_out7p0);
// ScalarUniform:14
float n_out14p0 = BreathingAmount;
// ScalarOp:10
float n_out10p0 = n_out8p0 * n_out14p0;
// ScalarUniform:15
float n_out15p0 = Thinness;
// ScalarOp:9
float n_out9p0 = n_out10p0 + n_out15p0;
// ScalarOp:6
float n_out6p0 = pow(n_out32p0, n_out9p0);
// If:52
vec3 n_out52p0;
if(abs(n_out51p0 - n_out63p0) < n_out59p0)
{
n_out52p0 = n_out13p0;
}
else if(n_out51p0 < n_out63p0)
{
n_out52p0 = vec3(n_out6p0);
}
else
{
n_out52p0 = vec3(n_out6p0);
}
// VectorOp:19
vec3 n_in19p1 = vec3(0.00000, 0.00000, 0.00000);
vec3 n_out19p0 = n_out13p0 + n_in19p1;
// Output:0
ALPHA = dot(n_out52p0, vec3(0.333333, 0.333333, 0.333333));
EMISSION = n_out19p0;
}
void light() {
// Output:0
}
"
graph_offset = Vector2( -260.083, 655.538 )
nodes/fragment/0/position = Vector2( 1400, 200 )
nodes/fragment/2/node = SubResource( 10 )
nodes/fragment/2/position = Vector2( 260, 0 )
nodes/fragment/3/node = SubResource( 19 )
nodes/fragment/3/position = Vector2( 260, 120 )
nodes/fragment/4/node = SubResource( 30 )
nodes/fragment/4/position = Vector2( 480, 60 )
nodes/fragment/5/node = SubResource( 38 )
nodes/fragment/5/position = Vector2( 640, 60 )
nodes/fragment/6/node = SubResource( 42 )
nodes/fragment/6/position = Vector2( 1120, 180 )
nodes/fragment/7/node = SubResource( 43 )
nodes/fragment/7/position = Vector2( -100, 220 )
nodes/fragment/8/node = SubResource( 44 )
nodes/fragment/8/position = Vector2( 180, 220 )
nodes/fragment/9/node = SubResource( 45 )
nodes/fragment/9/position = Vector2( 640, 200 )
nodes/fragment/10/node = SubResource( 2 )
nodes/fragment/10/position = Vector2( 400, 200 )
nodes/fragment/13/node = SubResource( 3 )
nodes/fragment/13/position = Vector2( 740, 440 )
nodes/fragment/14/node = SubResource( 4 )
nodes/fragment/14/position = Vector2( 120, 280 )
nodes/fragment/15/node = SubResource( 5 )
nodes/fragment/15/position = Vector2( 199, 378.6 )
nodes/fragment/16/node = SubResource( 6 )
nodes/fragment/16/position = Vector2( 260, 680 )
nodes/fragment/16/size = Vector2( 661, 792 )
nodes/fragment/16/input_ports = "0,1,uv;1,0,columns;2,0,rows;3,1,offset;"
nodes/fragment/16/output_ports = "0,0,minimum_dist;"
nodes/fragment/16/expression = "vec2 index_uv = floor(vec2(uv.x * columns, uv.y * rows));
vec2 fract_uv = fract(vec2(uv.x * columns, uv.y * rows));
minimum_dist = 1.0;
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
vec2 neighbor = vec2(float(x),float(y));
vec2 p = index_uv + neighbor;
vec2 point = vec2(fract(sin(dot(p.xy,
vec2(12.9898,78.233))) * 43758.5453123)) * clamp(offset.xy, 0, 1);
vec2 diff = neighbor + point - fract_uv;
float dist = length(diff);
minimum_dist = min(minimum_dist, dist);
}
}
"
nodes/fragment/17/node = SubResource( 7 )
nodes/fragment/17/position = Vector2( -240, 700 )
nodes/fragment/19/node = SubResource( 9 )
nodes/fragment/19/position = Vector2( 1002.7, 433.825 )
nodes/fragment/22/node = SubResource( 11 )
nodes/fragment/22/position = Vector2( -760, 860 )
nodes/fragment/23/node = SubResource( 12 )
nodes/fragment/23/position = Vector2( -360, 880 )
nodes/fragment/24/node = SubResource( 13 )
nodes/fragment/24/position = Vector2( -180, 860 )
nodes/fragment/25/node = SubResource( 14 )
nodes/fragment/25/position = Vector2( -360, 1140 )
nodes/fragment/26/node = SubResource( 15 )
nodes/fragment/26/position = Vector2( 40, 1000 )
nodes/fragment/27/node = SubResource( 16 )
nodes/fragment/27/position = Vector2( -40, 1140 )
nodes/fragment/28/node = SubResource( 17 )
nodes/fragment/28/position = Vector2( -20, 860 )
nodes/fragment/29/node = SubResource( 18 )
nodes/fragment/29/position = Vector2( -187.698, 1113.46 )
nodes/fragment/30/node = SubResource( 20 )
nodes/fragment/30/position = Vector2( -520, 1080 )
nodes/fragment/31/node = SubResource( 21 )
nodes/fragment/31/position = Vector2( -540, 820 )
nodes/fragment/32/node = SubResource( 22 )
nodes/fragment/32/position = Vector2( 880, 140 )
nodes/fragment/33/node = SubResource( 23 )
nodes/fragment/33/position = Vector2( 973.705, 651.038 )
nodes/fragment/34/node = SubResource( 24 )
nodes/fragment/34/position = Vector2( -986.149, 1004.04 )
nodes/fragment/35/node = SubResource( 25 )
nodes/fragment/35/position = Vector2( -880, 1160 )
nodes/fragment/36/node = SubResource( 26 )
nodes/fragment/36/position = Vector2( -180, 1000 )
nodes/fragment/37/node = SubResource( 27 )
nodes/fragment/37/position = Vector2( -200, 1240 )
nodes/fragment/38/node = SubResource( 28 )
nodes/fragment/38/position = Vector2( -380, 980 )
nodes/fragment/39/node = SubResource( 29 )
nodes/fragment/39/position = Vector2( -379.352, 1245.04 )
nodes/fragment/40/node = SubResource( 31 )
nodes/fragment/40/position = Vector2( 840, -320 )
nodes/fragment/41/node = SubResource( 32 )
nodes/fragment/41/position = Vector2( 820, -20 )
nodes/fragment/43/node = SubResource( 33 )
nodes/fragment/43/position = Vector2( 680, -500 )
nodes/fragment/47/node = SubResource( 35 )
nodes/fragment/47/position = Vector2( 1340, -520 )
nodes/fragment/48/node = SubResource( 36 )
nodes/fragment/48/position = Vector2( 1160, -420 )
nodes/fragment/49/node = SubResource( 37 )
nodes/fragment/49/position = Vector2( 1098.46, -89.4618 )
nodes/fragment/51/node = SubResource( 40 )
nodes/fragment/51/position = Vector2( 1520, -460 )
nodes/fragment/52/node = SubResource( 41 )
nodes/fragment/52/position = Vector2( 1716.97, -247.962 )
nodes/fragment/53/node = SubResource( 48 )
nodes/fragment/53/position = Vector2( 680, -660 )
nodes/fragment/54/node = SubResource( 49 )
nodes/fragment/54/position = Vector2( 920, -680 )
nodes/fragment/55/node = SubResource( 50 )
nodes/fragment/55/position = Vector2( 1190.64, -634.962 )
nodes/fragment/56/node = SubResource( 51 )
nodes/fragment/56/position = Vector2( 580, -200 )
nodes/fragment/57/node = SubResource( 52 )
nodes/fragment/57/position = Vector2( 600, -100 )
nodes/fragment/58/node = SubResource( 53 )
nodes/fragment/58/position = Vector2( 820, -160 )
nodes/fragment/59/node = SubResource( 54 )
nodes/fragment/59/position = Vector2( 1520, -280 )
nodes/fragment/60/node = SubResource( 55 )
nodes/fragment/60/position = Vector2( 1200, -260 )
nodes/fragment/61/node = SubResource( 56 )
nodes/fragment/61/position = Vector2( 1320, -340 )
nodes/fragment/62/node = SubResource( 57 )
nodes/fragment/62/position = Vector2( 940, -240 )
nodes/fragment/63/node = SubResource( 58 )
nodes/fragment/63/position = Vector2( 1340, -100 )
nodes/fragment/64/node = SubResource( 59 )
nodes/fragment/64/position = Vector2( 71.293, 790.667 )
nodes/fragment/connections = PoolIntArray( 2, 0, 4, 0, 3, 0, 4, 1, 4, 0, 5, 0, 7, 0, 8, 0, 9, 0, 6, 1, 8, 0, 10, 0, 10, 0, 9, 0, 14, 0, 10, 1, 15, 0, 9, 1, 17, 0, 16, 0, 13, 0, 19, 0, 19, 0, 0, 5, 23, 0, 24, 0, 26, 0, 16, 3, 27, 0, 26, 1, 24, 0, 28, 0, 28, 0, 26, 0, 25, 0, 29, 0, 29, 0, 27, 0, 22, 0, 30, 0, 30, 0, 25, 0, 22, 0, 31, 0, 31, 0, 23, 0, 16, 0, 33, 0, 33, 0, 32, 1, 32, 0, 6, 0, 5, 0, 32, 0, 34, 0, 31, 1, 35, 0, 30, 1, 36, 0, 28, 1, 37, 0, 27, 1, 38, 0, 24, 1, 39, 0, 29, 1, 40, 0, 48, 1, 41, 0, 49, 1, 48, 0, 51, 0, 47, 0, 51, 1, 51, 0, 52, 0, 6, 0, 52, 4, 6, 0, 52, 5, 13, 0, 52, 3, 52, 0, 0, 1, 43, 0, 54, 0, 53, 0, 55, 0, 54, 0, 55, 1, 43, 0, 55, 2, 55, 0, 48, 0, 56, 0, 58, 0, 57, 0, 58, 1, 58, 0, 49, 0, 48, 0, 60, 0, 60, 0, 59, 1, 59, 0, 52, 2, 61, 0, 59, 0, 62, 0, 60, 1, 49, 0, 63, 0, 63, 0, 52, 1, 64, 0, 16, 1, 64, 0, 16, 2 )