PBR Glass
This is a glass shader that preserves specular lighting even at low opacity.
The shader does not read from the screen_texture, unlike the standard way to do realistic glass in Godot, so it can be used on many surfaces that render in front of other transparent objects.
This shader is ideal for large glass panes or small glass props. Basically a standard glass and plastic material since Godot 4 does not have a good way to do basic glass.
Uniforms
The shader supports standard PBR Albedo, Roughness and Normal Map textures and has controls for how they appear.
The Edge Color is applied as a Fresnel effect that generally darkens the material at glancing angles, and brings back some reflections. This can be changed or turned off entirely.
Material Types
The default values in the shader are setup to give a more realistic glass look, but the shader should be able to do plastic or other transparent materials.
The edge color is set to solid black for glass, but other colors or lowering the colors opacity would work for more plastic materials.
Materials using this shader look best when there are lot’s of specular highlights from lighting, or reflective information from probes or the skybox.
Shader Magic
The key to this shader is one line that allows it to preserve the intensity of specular details even at low opacity. While the standard material fades out reflections and specular light with the rest of the object, this is not realistic for real life transparent materials such as glass, water and plastic.
SPECULAR = 0.5 * inversesqrt(ALPHA);
This line takes the original specular value (0.5, but could be anything 0.0 – 1.0) and multiplies it with the inverse square-root of the alpha value. This increases the specularity of the material as the object becomes more transparent, in a way that counteracts the alpha blending done to the rest of the material. This won’t work at 0 opacity, so your ALPHA should be clamped to something slightly above 0.0.
I couldn’t find anywhere online how to make glass like this in Godot, so I hope this line helps anyone trying to make transparent materials and effects in Godot from now on.
This only works in the Forward+ renderer, so I’m not sure right now what the formula is for the other pipelines.
Shader code
shader_type spatial;
render_mode diffuse_burley, specular_schlick_ggx, blend_mix;
group_uniforms albedo;
uniform vec4 albedo : source_color = vec4(1.0, 1.0, 1.0, 0.0);
uniform sampler2D albedo_texture : source_color, hint_default_white;
group_uniforms roughness;
uniform float roughness : hint_range(0.0, 1.0) = 0.15;
uniform sampler2D roughness_texture : hint_roughness_r;
group_uniforms normal;
uniform float normal_strength : hint_range(-16.0, 16.0) = 1.0;
uniform sampler2D normal_map : hint_normal;
group_uniforms misc;
uniform vec4 edge_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
float SchlickFresnel(float u) {
float m = 1.0 - u;
float m2 = m * m;
return m2 * m2 * m;
}
void fragment() {
// calculate fresnel values
float VdotN = dot(VIEW, NORMAL);
float fresnel = clamp(SchlickFresnel(VdotN), 0.0, 1.0);
// sample and mix textures
vec4 _albedo = texture(albedo_texture, UV) * albedo;
float _roughness = texture(roughness_texture, UV).r * roughness;
// apply glass look
float a = mix(0.001, 1.0, _albedo.a);
ALPHA = mix(fresnel * edge_color.a, 1.0, a);
ALBEDO = mix(edge_color.rgb * edge_color.a, _albedo.rgb, a);
ROUGHNESS = _roughness;
NORMAL_MAP = texture(normal_map, UV).xyz;
NORMAL_MAP_DEPTH = normal_strength;
// function to compensate specular for alpha blend
// 0.5 * ALPHA^-0.5
SPECULAR = 0.5 * inversesqrt(ALPHA);
}
We need an eye shader with this.