Parallax Ice | Depth effect
Small note:
This shader uses 2 matrix multiplications to figure out the camera vector.
You can also pass the camera vector as a uniform from any node, however I chose to keep it this way as its simpler to drag and drop the shader.
See here for more details: GLSL Performance Thread
21 July 2021 – Performance improved thanks to u/lexpartizan !
Extra note:
I made this shader for ice, but it’ll actually work as a really good 3D parallax shader if you just slap in some “non-ice” textures. Trust me, if you use a roughness map (or some texture thats mostly black with a few white spots) you can get a really cool gemstone kinda thing (wink wink). Check the last screenshot to see what I mean.
What the parameters mean + How To Use:
For the Over Texture
parameter you wanna use a diffuse/albedo ice texture. You can get the one I used over here: Ice 003 (CC0 license)
For the Under Texture
parameter, you wanna use something black/white, preferably a displacement map. The one I used is the displacement map from this: Ice 002 (CC0 license)
For the Surface Normal
parameter you use the normalmap of the Over Texture
. Of course, you can leave this blank as well, though it wont look “icy” but more “glassy”.
Depth
specifies “how far away the bottom texture appears to be”.
Normal Depth
will control the strength of the normalmap used in Surface Normal
Roughness
is just roughness, nothing special there.
Metallic
is also just metallic, it will control how reflective the ice is. This works best with an HDRI sky.
If you just wanna copy my settings, they’re in the screenshots.
Shader code
// Saw a few of these in Unreal Engine and Unity but no Godot :(
// So I made one, check other comments for free textures and more info on the shader
shader_type spatial;
uniform sampler2D over_texture : hint_albedo;
uniform sampler2D under_texture : hint_albedo;
uniform sampler2D surface_normalmap : hint_normal;
// Here's a free CC0 ice texture -> https://ambientcg.com/view?id=Ice003
// You can use that for the over_texture and surface_normalmap
// Here's another CC0 ice texture -> https://ambientcg.com/view?id=Ice002
// You can use the displacement map of this texture as the under_texture
uniform vec4 top_color : hint_color = vec4(0.6764, 0.980092, 1.0, 1.0);
uniform float depth = 0.1;
uniform float normal_depth = 1.0;
uniform float roughness : hint_range(0.0, 1.0) = 0.0;
uniform float metallic : hint_range(0.0, 1.0) = 0.7;
uniform float refractive_index = 0.1;
// ========= ↓↓↓ From u/lexpartizan the GOAT ↓↓↓ ==============
float blendOverlay_f(float base, float blend) {
float branchless = step (base,0.5);
return (2.0*base*blend)*branchless + (1.0-2.0*(1.0-base)*(1.0-blend))*(1.0-branchless); //This is branchless version
}
// ======== ↑↑↑ From u/lexpartizan the GOAT ↑↑↑ ==============
vec3 blendOverlay(vec3 base, vec3 blend) {
return vec3(blendOverlay_f(base.r,blend.r),blendOverlay_f(base.g,blend.g),blendOverlay_f(base.b,blend.b));
}
// ============= ↓↓↓ More from u/lexpartizan the GOAT ========================
varying vec3 ro;
varying vec3 p;
varying vec3 vertex_normal_ws;
void vertex()
{
ro = (CAMERA_MATRIX * vec4(0.0, 0.0, 0.0, 1.0)).xyz;// Get camera position in World space coordinates
p = ((WORLD_MATRIX)*vec4(VERTEX,1.0)).xyz;// Get fragment position in world space coordinates
vertex_normal_ws = ((WORLD_MATRIX)*vec4(NORMAL,1.0)).xyz;
}
// ============= ↑↑↑ More from u/lexpartizan the GOAT ↑↑↑ ====================
void fragment(){
vec3 normal = texture(surface_normalmap, UV).xyz * 2.0 - 1.0;
NORMALMAP = texture(surface_normalmap, UV).xyz;
NORMALMAP_DEPTH = normal_depth;
vec3 refraction;
vec3 rd = normalize(p - ro - normal * refractive_index) * depth;
vec3 over_color = texture(over_texture, UV).rgb;
vec3 color = blendOverlay(over_color, top_color.rgb);
vec2 offset = rd.xz;
vec3 under_color = texture(under_texture, UV + offset + (normal.xy)).rgb;
ALBEDO = blendOverlay(color, under_color);
ROUGHNESS = roughness;
METALLIC = metallic;
}
Hi! Thank you for your wonderful shader! I was able to improve it a little. I made the calculation of p and ro in vertex and made the function blendOverlay_f() brancless. This should slightly improve the performance.
Sadly this only seems to work well on flat surfaces.
Updates for 4.x:
hint_albedo is now source_color
hint_color is now also source_color
CAMERA_MATRIX is now INV_VIEW_MATRIX
WORLD_MATRIX is now MODEL_MATRIX
NORMALMAP is now NORMAL_MAP
NORMALMAP_DEPTH is now NORMAL_MAP_DEPTH
After those changes, it works like a charm. Thank you!