[gd_resource type="VisualShader" load_steps=26 format=3 uid="uid://wugkii55u1of"] [sub_resource type="VisualShaderNodeIntParameter" id="VisualShaderNodeIntParameter_nfwxq"] parameter_name = "TextureDetail" [sub_resource type="VisualShaderNodeExpression" id="VisualShaderNodeExpression_cubym"] size = Vector2(866.365, 620.735) expression = "int currentChannel = 0; for (int i = 0; i < numberOfTextures; i++) { vec3 textureUV = vec3(inputTextureUV.x, inputTextureUV.y, float(i)); vec3 splatmapUV = vec3(uvValue.x, uvValue.y, floor(float(i/4))); vec4 currentTexture = useAntitile ? texture_array_antitile(textures, textureUV) : texture(textures, textureUV) ; vec4 currentNormal = useAntitile ? texture_array_antitile(normals, textureUV) : texture(normals, textureUV); vec4 currentRoughness = useAntitile ? texture_array_antitile(roughnessTexutres, textureUV) : texture(roughnessTexutres, textureUV); vec4 currentSplatmap = texture(splatmaps, splatmapUV); float channelValue = 0.0; if (currentChannel == 0) { channelValue = currentSplatmap.x; } else if (currentChannel == 1) { channelValue = currentSplatmap.y; } else if (currentChannel == 2) { channelValue = currentSplatmap.z; } else if (currentChannel == 3) { channelValue = currentSplatmap.w; } resultTexture += currentTexture * channelValue; resultNormal += currentNormal * channelValue; resultRoughness += currentRoughness * channelValue; if (currentChannel == 3) { currentChannel = 0; } else { currentChannel++; } }" [sub_resource type="VisualShaderNodeTexture2DArrayParameter" id="VisualShaderNodeTexture2DArrayParameter_14ddd"] parameter_name = "Textures" texture_type = 1 [sub_resource type="VisualShaderNodeTexture2DArrayParameter" id="VisualShaderNodeTexture2DArrayParameter_lj2oh"] parameter_name = "Splatmaps" texture_repeat = 2 [sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_b1nt7"] input_name = "uv" [sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_p8jed"] input_name = "uv" [sub_resource type="VisualShaderNodeIntParameter" id="VisualShaderNodeIntParameter_bhdu6"] parameter_name = "NumberOfTextures" [sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_rjcc0"] default_input_values = [0, Vector2(0, 0), 1, Vector2(0, 0)] op_type = 0 operator = 2 [sub_resource type="VisualShaderNodeTexture2DArrayParameter" id="VisualShaderNodeTexture2DArrayParameter_b0n17"] parameter_name = "Normals" [sub_resource type="VisualShaderNodeTexture2DArrayParameter" id="VisualShaderNodeTexture2DArrayParameter_kwhd6"] parameter_name = "RoughnessTexutres" [sub_resource type="VisualShaderNodeGlobalExpression" id="VisualShaderNodeGlobalExpression_ta343"] size = Vector2(931.661, 512.267) expression = "vec2 rotate(vec2 v, float cosa, float sina) { return vec2(cosa * v.x - sina * v.y, sina * v.x + cosa * v.y); } vec4 depth_blend2(vec4 a_value, float a_bump, vec4 b_value, float b_bump, float t) { // https://www.gamasutra.com // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php float d = 0.1; float ma = max(a_bump + (1.0 - t), b_bump + t) - d; float ba = max(a_bump + (1.0 - t) - ma, 0.0); float bb = max(b_bump + t - ma, 0.0); return (a_value * ba + b_value * bb) / (ba + bb); } // Antitile from zylann's shader vec4 texture_array_antitile(sampler2DArray tex, vec3 uv) { float frequency = 2.0; float scale = 1.3; float sharpness = 0.7; // Rotate and scale UV float rot = 3.14 * 0.6; float cosa = cos(rot); float sina = sin(rot); vec3 uv2 = vec3(rotate(uv.xy, cosa, sina) * scale, uv.z); vec4 col0 = texture(tex, uv); vec4 col1 = texture(tex, uv2); // Periodically alternate between the two versions using a warped checker pattern float t = 1.1 + 0.5 * sin(uv2.x * frequency + sin(uv.x) * 2.0) * cos(uv2.y * frequency + sin(uv.y) * 2.0); t = smoothstep(sharpness, 2.0 - sharpness, t); return depth_blend2(col0, col0.a, col1, col1.a, t); }" [sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_t40n8"] input_name = "uv" [sub_resource type="VisualShaderNodeBooleanParameter" id="VisualShaderNodeBooleanParameter_ukfh7"] parameter_name = "UseAntitile" default_value_enabled = true default_value = true [sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_rrnf3"] input_name = "vertex" [sub_resource type="VisualShaderNodeVectorCompose" id="VisualShaderNodeVectorCompose_eao4l"] [sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_fwalu"] [sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_qnr1q"] parameter_name = "HeightmapFactor" default_value_enabled = true default_value = 1.0 [sub_resource type="VisualShaderNodeFloatOp" id="VisualShaderNodeFloatOp_7ljy2"] operator = 2 [sub_resource type="VisualShaderNodeTexture2DParameter" id="VisualShaderNodeTexture2DParameter_fg5hl"] parameter_name = "HeightmapTexture" texture_repeat = 2 [sub_resource type="VisualShaderNodeTexture" id="VisualShaderNodeTexture_10f0s"] expanded_output_ports = [0] source = 5 [sub_resource type="VisualShaderNodeTexture2DParameter" id="VisualShaderNodeTexture2DParameter_fe2j0"] parameter_name = "WaterTexture" texture_repeat = 2 [sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_xn5dd"] parameter_name = "WaterFactor" default_value_enabled = true default_value = 1.0 [sub_resource type="VisualShaderNodeTexture" id="VisualShaderNodeTexture_yy7e7"] expanded_output_ports = [0] source = 5 [sub_resource type="VisualShaderNodeFloatOp" id="VisualShaderNodeFloatOp_t0pdk"] operator = 2 [sub_resource type="VisualShaderNodeFloatOp" id="VisualShaderNodeFloatOp_fbn1q"] operator = 1 [resource] code = "shader_type spatial; render_mode blend_mix, depth_draw_opaque, cull_disabled, diffuse_lambert, specular_schlick_ggx; uniform sampler2D HeightmapTexture : repeat_disable; uniform float HeightmapFactor = 1; uniform sampler2D WaterTexture : repeat_disable; uniform float WaterFactor = 1; uniform sampler2DArray Textures : source_color; uniform sampler2DArray Splatmaps : repeat_disable; uniform int TextureDetail; uniform int NumberOfTextures; uniform sampler2DArray Normals; uniform sampler2DArray RoughnessTexutres; uniform bool UseAntitile = true; // GlobalExpression:0 vec2 rotate(vec2 v, float cosa, float sina) { return vec2(cosa * v.x - sina * v.y, sina * v.x + cosa * v.y); } vec4 depth_blend2(vec4 a_value, float a_bump, vec4 b_value, float b_bump, float t) { // https://www.gamasutra.com // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php float d = 0.1; float ma = max(a_bump + (1.0 - t), b_bump + t) - d; float ba = max(a_bump + (1.0 - t) - ma, 0.0); float bb = max(b_bump + t - ma, 0.0); return (a_value * ba + b_value * bb) / (ba + bb); } // Antitile from zylann's shader vec4 texture_array_antitile(sampler2DArray tex, vec3 uv) { float frequency = 2.0; float scale = 1.3; float sharpness = 0.7; // Rotate and scale UV float rot = 3.14 * 0.6; float cosa = cos(rot); float sina = sin(rot); vec3 uv2 = vec3(rotate(uv.xy, cosa, sina) * scale, uv.z); vec4 col0 = texture(tex, uv); vec4 col1 = texture(tex, uv2); // Periodically alternate between the two versions using a warped checker pattern float t = 1.1 + 0.5 * sin(uv2.x * frequency + sin(uv.x) * 2.0) * cos(uv2.y * frequency + sin(uv.y) * 2.0); t = smoothstep(sharpness, 2.0 - sharpness, t); return depth_blend2(col0, col0.a, col1, col1.a, t); } void vertex() { // Input:25 vec3 n_out25p0 = VERTEX; vec4 n_out32p0; // Texture2D:32 n_out32p0 = texture(HeightmapTexture, UV); float n_out32p1 = n_out32p0.r; // FloatParameter:29 float n_out29p0 = HeightmapFactor; // FloatOp:30 float n_out30p0 = n_out32p1 * n_out29p0; vec4 n_out35p0; // Texture2D:35 n_out35p0 = texture(WaterTexture, UV); float n_out35p1 = n_out35p0.r; // FloatParameter:34 float n_out34p0 = WaterFactor; // FloatOp:36 float n_out36p0 = n_out35p1 * n_out34p0; // FloatOp:37 float n_out37p0 = n_out30p0 - n_out36p0; // VectorCompose:26 float n_in26p0 = 0.00000; float n_in26p2 = 0.00000; vec3 n_out26p0 = vec3(n_in26p0, n_out37p0, n_in26p2); // VectorOp:27 vec3 n_out27p0 = n_out25p0 + n_out26p0; // Output:0 VERTEX = n_out27p0; } void fragment() { // Input:59 vec2 n_out59p0 = UV; // IntParameter:50 int n_out50p0 = TextureDetail; // VectorOp:62 vec2 n_out62p0 = n_out59p0 * vec2(float(n_out50p0)); // IntParameter:61 int n_out61p0 = NumberOfTextures; // Input:66 vec2 n_out66p0 = UV; // BooleanParameter:67 bool n_out67p0 = UseAntitile; vec4 n_out56p0; vec4 n_out56p1; vec4 n_out56p2; // Expression:56 n_out56p0 = vec4(0.0, 0.0, 0.0, 0.0); n_out56p1 = vec4(0.0, 0.0, 0.0, 0.0); n_out56p2 = vec4(0.0, 0.0, 0.0, 0.0); { int currentChannel = 0; for (int i = 0; i < n_out61p0; i++) { vec3 textureUV = vec3(n_out62p0.x, n_out62p0.y, float(i)); vec3 splatmapUV = vec3(n_out66p0.x, n_out66p0.y, floor(float(i/4))); vec4 currentTexture = n_out67p0 ? texture_array_antitile(Textures, textureUV) : texture(Textures, textureUV) ; vec4 currentNormal = n_out67p0 ? texture_array_antitile(Normals, textureUV) : texture(Normals, textureUV); vec4 currentRoughness = n_out67p0 ? texture_array_antitile(RoughnessTexutres, textureUV) : texture(RoughnessTexutres, textureUV); vec4 currentSplatmap = texture(Splatmaps, splatmapUV); float channelValue = 0.0; if (currentChannel == 0) { channelValue = currentSplatmap.x; } else if (currentChannel == 1) { channelValue = currentSplatmap.y; } else if (currentChannel == 2) { channelValue = currentSplatmap.z; } else if (currentChannel == 3) { channelValue = currentSplatmap.w; } n_out56p0 += currentTexture * channelValue; n_out56p1 += currentNormal * channelValue; n_out56p2 += currentRoughness * channelValue; if (currentChannel == 3) { currentChannel = 0; } else { currentChannel++; } } } // Output:0 ALBEDO = vec3(n_out56p0.xyz); ROUGHNESS = n_out56p2.x; NORMAL_MAP = vec3(n_out56p1.xyz); } " modes/cull = 2 nodes/vertex/0/position = Vector2(2140, -120) nodes/vertex/25/node = SubResource("VisualShaderNodeInput_rrnf3") nodes/vertex/25/position = Vector2(1340, -300) nodes/vertex/26/node = SubResource("VisualShaderNodeVectorCompose_eao4l") nodes/vertex/26/position = Vector2(1760, 40) nodes/vertex/27/node = SubResource("VisualShaderNodeVectorOp_fwalu") nodes/vertex/27/position = Vector2(1900, -160) nodes/vertex/29/node = SubResource("VisualShaderNodeFloatParameter_qnr1q") nodes/vertex/29/position = Vector2(1080, 280) nodes/vertex/30/node = SubResource("VisualShaderNodeFloatOp_7ljy2") nodes/vertex/30/position = Vector2(1400, 80) nodes/vertex/31/node = SubResource("VisualShaderNodeTexture2DParameter_fg5hl") nodes/vertex/31/position = Vector2(660, -240) nodes/vertex/32/node = SubResource("VisualShaderNodeTexture_10f0s") nodes/vertex/32/position = Vector2(1100, -140) nodes/vertex/33/node = SubResource("VisualShaderNodeTexture2DParameter_fe2j0") nodes/vertex/33/position = Vector2(600, 460) nodes/vertex/34/node = SubResource("VisualShaderNodeFloatParameter_xn5dd") nodes/vertex/34/position = Vector2(1100, 800) nodes/vertex/35/node = SubResource("VisualShaderNodeTexture_yy7e7") nodes/vertex/35/position = Vector2(1120, 540) nodes/vertex/36/node = SubResource("VisualShaderNodeFloatOp_t0pdk") nodes/vertex/36/position = Vector2(1460, 540) nodes/vertex/37/node = SubResource("VisualShaderNodeFloatOp_fbn1q") nodes/vertex/37/position = Vector2(1600, 380) nodes/vertex/connections = PackedInt32Array(25, 0, 27, 0, 26, 0, 27, 1, 29, 0, 30, 1, 31, 0, 32, 2, 32, 1, 30, 0, 27, 0, 0, 0, 33, 0, 35, 2, 35, 1, 36, 0, 34, 0, 36, 1, 36, 0, 37, 1, 30, 0, 37, 0, 37, 0, 26, 1) nodes/fragment/0/position = Vector2(1360, 600) nodes/fragment/50/node = SubResource("VisualShaderNodeIntParameter_nfwxq") nodes/fragment/50/position = Vector2(-1620, 540) nodes/fragment/56/node = SubResource("VisualShaderNodeExpression_cubym") nodes/fragment/56/position = Vector2(-320, -220) nodes/fragment/56/size = Vector2(866.365, 620.735) nodes/fragment/56/input_ports = "0,8,textures;1,8,splatmaps;2,3,inputTextureUV;3,1,numberOfTextures;4,8,normals;5,8,roughnessTexutres;6,3,uvValue;7,6,useAntitile;" nodes/fragment/56/output_ports = "0,5,resultTexture;1,5,resultNormal;2,5,resultRoughness;" nodes/fragment/56/expression = "int currentChannel = 0; for (int i = 0; i < numberOfTextures; i++) { vec3 textureUV = vec3(inputTextureUV.x, inputTextureUV.y, float(i)); vec3 splatmapUV = vec3(uvValue.x, uvValue.y, floor(float(i/4))); vec4 currentTexture = useAntitile ? texture_array_antitile(textures, textureUV) : texture(textures, textureUV) ; vec4 currentNormal = useAntitile ? texture_array_antitile(normals, textureUV) : texture(normals, textureUV); vec4 currentRoughness = useAntitile ? texture_array_antitile(roughnessTexutres, textureUV) : texture(roughnessTexutres, textureUV); vec4 currentSplatmap = texture(splatmaps, splatmapUV); float channelValue = 0.0; if (currentChannel == 0) { channelValue = currentSplatmap.x; } else if (currentChannel == 1) { channelValue = currentSplatmap.y; } else if (currentChannel == 2) { channelValue = currentSplatmap.z; } else if (currentChannel == 3) { channelValue = currentSplatmap.w; } resultTexture += currentTexture * channelValue; resultNormal += currentNormal * channelValue; resultRoughness += currentRoughness * channelValue; if (currentChannel == 3) { currentChannel = 0; } else { currentChannel++; } }" nodes/fragment/57/node = SubResource("VisualShaderNodeTexture2DArrayParameter_14ddd") nodes/fragment/57/position = Vector2(-1280, -400) nodes/fragment/58/node = SubResource("VisualShaderNodeTexture2DArrayParameter_lj2oh") nodes/fragment/58/position = Vector2(-1280, -100) nodes/fragment/59/node = SubResource("VisualShaderNodeInput_b1nt7") nodes/fragment/59/position = Vector2(-1620, 440) nodes/fragment/60/node = SubResource("VisualShaderNodeInput_p8jed") nodes/fragment/60/position = Vector2(-1600, 720) nodes/fragment/61/node = SubResource("VisualShaderNodeIntParameter_bhdu6") nodes/fragment/61/position = Vector2(-1180, 700) nodes/fragment/62/node = SubResource("VisualShaderNodeVectorOp_rjcc0") nodes/fragment/62/position = Vector2(-1240, 320) nodes/fragment/63/node = SubResource("VisualShaderNodeTexture2DArrayParameter_b0n17") nodes/fragment/63/position = Vector2(-1260, 920) nodes/fragment/64/node = SubResource("VisualShaderNodeTexture2DArrayParameter_kwhd6") nodes/fragment/64/position = Vector2(-1260, 1300) nodes/fragment/65/node = SubResource("VisualShaderNodeGlobalExpression_ta343") nodes/fragment/65/position = Vector2(-340, 780) nodes/fragment/65/size = Vector2(931.661, 512.267) nodes/fragment/65/input_ports = "" nodes/fragment/65/output_ports = "" nodes/fragment/65/expression = "vec2 rotate(vec2 v, float cosa, float sina) { return vec2(cosa * v.x - sina * v.y, sina * v.x + cosa * v.y); } vec4 depth_blend2(vec4 a_value, float a_bump, vec4 b_value, float b_bump, float t) { // https://www.gamasutra.com // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php float d = 0.1; float ma = max(a_bump + (1.0 - t), b_bump + t) - d; float ba = max(a_bump + (1.0 - t) - ma, 0.0); float bb = max(b_bump + t - ma, 0.0); return (a_value * ba + b_value * bb) / (ba + bb); } // Antitile from zylann's shader vec4 texture_array_antitile(sampler2DArray tex, vec3 uv) { float frequency = 2.0; float scale = 1.3; float sharpness = 0.7; // Rotate and scale UV float rot = 3.14 * 0.6; float cosa = cos(rot); float sina = sin(rot); vec3 uv2 = vec3(rotate(uv.xy, cosa, sina) * scale, uv.z); vec4 col0 = texture(tex, uv); vec4 col1 = texture(tex, uv2); // Periodically alternate between the two versions using a warped checker pattern float t = 1.1 + 0.5 * sin(uv2.x * frequency + sin(uv.x) * 2.0) * cos(uv2.y * frequency + sin(uv.y) * 2.0); t = smoothstep(sharpness, 2.0 - sharpness, t); return depth_blend2(col0, col0.a, col1, col1.a, t); }" nodes/fragment/66/node = SubResource("VisualShaderNodeInput_t40n8") nodes/fragment/66/position = Vector2(-960, 460) nodes/fragment/67/node = SubResource("VisualShaderNodeBooleanParameter_ukfh7") nodes/fragment/67/position = Vector2(-1140, 1680) nodes/fragment/connections = PackedInt32Array(59, 0, 62, 0, 50, 0, 62, 1, 62, 0, 56, 2, 57, 0, 56, 0, 58, 0, 56, 1, 61, 0, 56, 3, 63, 0, 56, 4, 64, 0, 56, 5, 66, 0, 56, 6, 56, 0, 0, 0, 67, 0, 56, 7, 56, 2, 0, 3, 56, 1, 0, 9) metadata/_edit_res_path = "res://addons/terrabrush/Resources/Shaders/heightmap_shader.tres"