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

Tags
depth, Ice, parallax
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from NekotoArts

Basic Vector Sprite Upscaling

Cheaper* Edge Detection Post-Processing

3D Edge Detection Shader (Borderlands-Style)

Related shaders

2D reflective ice

Spatial Ice Shader

Ice Covering

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
lexpartizan
lexpartizan
3 years ago

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.

varying vec3 ro;
varying vec3 p;

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
}

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
}

Last edited 3 years ago by lexpartizan
Alternalo
Alternalo
2 years ago

Sadly this only seems to work well on flat surfaces.

Sithoid
1 month ago

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!