Shoji Shader (Translucency + Sun Spot)
Recreates the effect when a thin, slightly translucent material is held up to a strong light source. Such as when a piece of paper is held up to the sun.
This effect is achieved by applying custom lighting calculations to faces of an object which are not in direct light. And adding a strong effect when the view lines up with the light source, while looking through the object.
The shader parameters allow for a lot of artistic control, and the shader itself is quite versatile, and could be used in many contexts successfully (Japanese Shoji-style walls, backlit shadow puppety, etc).
Shader code
/*
## Airship 6502 - Shoji Shader ##
Recreates the effect when a thin, slightly translucent material is held up to a strong light
source. Such as when a piece of paper is held up to the sun.
Intended for use on a quad or plane, or imported meshes, since supplied meshes that self-shadow
ruin the effect. However you can set the passthrough shadow contrast to zero to allow for the
shader to work for objects with thickness. Or use 'render_mode shadows_disabled;'
*/
shader_type spatial;
// cull_disabled to allow for quads to render on both sides.
// you can remove this if you're not using a quad.
render_mode cull_disabled;
// how much light passes through the material
uniform float passthrough : hint_range(0.0, 1.0, 0.01) = 0.15;
// the power factor to apply to the sun, higher power factor = smaller, tighter sun
uniform float sun_power_factor : hint_range(1.0, 200.0, 0.1) = 90.0;
// the sun blur reduces the energy of the sun spot and spreads it out over a larger area
uniform float sun_blur : hint_range(0.01, 1.0, 0.01) = 0.40;
// the mix factor controls the difference between
// normal light passthrough and the sun-spot highlight
uniform float mix_factor : hint_range(0.0, 1.0, 0.01) = 0.5;
// Controls the contrast of shadows which pass through the material
uniform float passthrough_shadow_contrast : hint_range(0.0, 1.0, 0.01) = 1.0;
// for directional lights behind the object, adds a sun highlight and backlighting
void light() {
// the normal between the object/fragment and the light source
float nl = clamp(dot(NORMAL, LIGHT), -1.0, 1.0);
// if the normal is facing away from the light source, we use the light passthrough effect
if(nl <= 0.0) {
nl *= clamp(dot(LIGHT, -VIEW), 0.0, 1.0);
// passthrough light, which is basically diffuse,
// except that it's on the side of the object facing away from the light source
float passthrough_effect = clamp(-nl, 0.0, 1.0) * passthrough;
// the sun light punches through when the view and the light are aligned
// this is like looking through a piece of paper with the sun behind it
float sun_light = pow(dot(VIEW, -LIGHT), sun_power_factor) * passthrough;
// blur the sun light so it's not so concentrated, gives a lot of artistic control
float sunspot_effect = sun_light / sun_blur;
// mix the normal light passthrough effect with the sunspot effect by some factor
float total_effect = mix(passthrough_effect, sunspot_effect, mix_factor);
// clamp the resulting value and then apply light colors and attenuation (shadows)
float value = clamp(total_effect, 0.0, 1.0);
// apply a contrast effect to the attenuation, to allow for softer shadows
float attenuation = max(1.0 - passthrough_shadow_contrast, ATTENUATION);
DIFFUSE_LIGHT += value * LIGHT_COLOR * attenuation;
} else {
// the normal is facing toward the light source, so we apply a basic lighting model
// as suggested by Godot docs.
DIFFUSE_LIGHT += clamp(dot(NORMAL, LIGHT), 0.0, 1.0) * LIGHT_COLOR * ATTENUATION;
}
}
I’m making a Japanese-styled game which uses Shoji doors and this could not be more perfect. Thank you very much!
Glad to hear it, Enjoy!