- screenshot_20221221_221525.jpg (117.42 KiB) Viewed 6454 times
Post your screenshots!
Re: Post your screenshots!
light and shadow
Re: Post your screenshots!
@SB66 - Nice image for the avatar of your MT forum account.
Which door mod were you using for this? Or was this a greater structure?
Very nice picture and interesting effect of the lights.
Which door mod were you using for this? Or was this a greater structure?
Re: Post your screenshots!
MT presents a Back To The Future revival apparently.
A DeLorean DMC-12 model (completed with anti-matter device on the top of the roof) flying over Hogwardish landscape. Funny.
Re: Post your screenshots!
I dont' used a special door mood.
The Building is a simple warehouse. the entry opens in the direction of the sunrise, you can spot the sun.
The mods in the pic : jonez , pkarc, stoneworks
Th structure that gives the structured shadow is simply a fence between two pillars
Re: Post your screenshots!
@SB66 - Thank you and good to know.
Apparently, you have a mind open for good architecture and enjoyable dimensions. Obviously, your building concepts and pictures provide a piece of art.
Re: Post your screenshots!
I not speak English.
In reality the model is the experimental model who i create for the player in my mod,the hat and the shirt are cloths who can be put in the player.
- Eris
- Member
- Posts: 191
- Joined: Thu Nov 19, 2020 23:12
- IRC: definitelya Ovalo
- In-game: Eris_still_crafts
Re: Post your screenshots!
Re: Post your screenshots!
i tried x2048's example of particle spawners and it looks better now

Re: Post your screenshots!
this Wolf likes too be high...
It's the second time he stands on those pillars.....
It's the second time he stands on those pillars.....
- Eris
- Member
- Posts: 191
- Joined: Thu Nov 19, 2020 23:12
- IRC: definitelya Ovalo
- In-game: Eris_still_crafts
Re: Post your screenshots!
You're right, didn't notice them.
Jump in the caac
- sorcerykid
- Member
- Posts: 1876
- Joined: Fri Aug 26, 2016 15:36
- GitHub: sorcerykid
- In-game: Nemo
- Location: Illinois, USA
Re: Post your screenshots!
Just a throwback to new years eve 2020 on the JT2 server. Even after the celebration was long over and everyone was passed out in bed, maikerumine was STILL at spawn ready to party!


Re: Post your screenshots!
Re: Post your screenshots!
Didn't know.....
....horses growing on trees !
....horses growing on trees !
- Hybrid Dog
- Member
- Posts: 2852
- Joined: Thu Nov 01, 2012 12:46
- GitHub: HybridDog
Re: Post your screenshots!
I did some experiments with Blinn-Phong specular reflection of sun light and moon light where the shininess and intensity is somehow calculated from the albedo colour.
There's the code: https://github.com/HybridDog/minetest/b ... gment.glsl
There's the code: https://github.com/HybridDog/minetest/b ... gment.glsl
- apercy
- Member
- Posts: 667
- Joined: Wed Mar 25, 2020 16:31
- GitHub: APercy
- In-game: APercy
- Location: Pinheiral - RJ - Brazil
Re: Post your screenshots!
very interesting!Hybrid Dog wrote: ↑Fri Jan 06, 2023 14:38I did some experiments with Blinn-Phong specular reflection of sun light and moon light where the shininess and intensity is somehow calculated from the albedo colour.
There's the code: https://github.com/HybridDog/minetest/b ... gment.glsl
2023-01-06-150956_1920x1054_scrot.png2023-01-06-151438_1920x1054_scrot.png2023-01-06-151459_1920x1054_scrot.png
So I'm playing with it a bit, and I'm faking water reflection with an adaptation of your code
Code: Select all
// Get the Y component of base.rgb converted to YCbCr as an approximate
// brightness of the albedo
float albedo_y = dot(base.rgb, vec3(0.299, 0.587, 0.114));
// There are no specular map textures, so approximate the shininess
// and specular reflections strength with albedo_y
//~ float shininess = 16.0;
float shininess = 16.0 * pow(1.0 - albedo_y, 2.0);
float specular_visibility = pow(albedo_y, 1.0); //old value 3.0
//~ float specular_visibility = 1.0;
// view_dir: Vector from the fragment to the eye in world space.
// (eyeVec is view_dir in view space, but v_LightDirection is in
// world space)
vec3 view_dir = normalize((eyePosition - cameraOffset) - worldPosition);
vec3 halfway = normalize(normalize(view_dir) + normalize(-v_LightDirection));
// Colour (and intensity) of the sun/moon light
vec3 light_colour = skyBgColor.rgb * (0.5-adjusted_night_ratio);
specular_visibility *= 1.0 - shadow_int; // darken in shadows
if(base.a < 0.8) specular_visibility *= 7.0 - shadow_int; //testing water and some glasses
// Calculate specular reflections with the Blinn-Phong model
float spec = specular_visibility * pow(max(dot(vNormal, halfway), 0.0), shininess);
shadow_int *= f_adj_shadow_strength;
col.rgb =
adjusted_night_ratio * col.rgb + // artificial light
(1.0 - adjusted_night_ratio) * ( // natural light
col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color
light_colour * spec + // Specular reflection of the sun/moon
dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
Re: Post your screenshots!
I don't speak English.
I upload the last alpha version of Assets warehouse 1.0,this is a preview of the experimental player model,if some o yours know a form of obtain the bones from a .x model in game you can tell me,i ask this because the actual method for the clothes is not ideal and for create some better i need to know how to obtain the bones from a model in the game.

I upload the last alpha version of Assets warehouse 1.0,this is a preview of the experimental player model,if some o yours know a form of obtain the bones from a .x model in game you can tell me,i ask this because the actual method for the clothes is not ideal and for create some better i need to know how to obtain the bones from a model in the game.

- apercy
- Member
- Posts: 667
- Joined: Wed Mar 25, 2020 16:31
- GitHub: APercy
- In-game: APercy
- Location: Pinheiral - RJ - Brazil
Re: Post your screenshots!
Thank you!
If you want to test my last experiment, try this:
Code: Select all
uniform sampler2D baseTexture;
uniform vec3 dayLight;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
uniform vec3 cameraOffset;
uniform float animationTimer;
#ifdef ENABLE_DYNAMIC_SHADOWS
// shadow texture
uniform sampler2D ShadowMapSampler;
// shadow uniforms
uniform vec3 v_LightDirection;
uniform float f_textureresolution;
uniform mat4 m_ShadowViewProj;
uniform float f_shadowfar;
uniform float f_shadow_strength;
uniform vec4 CameraPos;
uniform float xyPerspectiveBias0;
uniform float xyPerspectiveBias1;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
varying vec3 shadow_position;
varying float perspective_factor;
#endif
varying vec3 vNormal;
varying vec3 vPosition;
// World position in the visible world (i.e. relative to the cameraOffset.)
// This can be used for many shader effects without loss of precision.
// If the absolute position is required it can be calculated with
// cameraOffset + worldPosition (for large coordinates the limits of float
// precision must be considered).
varying vec3 worldPosition;
varying lowp vec4 varColor;
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec;
varying float nightRatio;
varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
#ifdef ENABLE_DYNAMIC_SHADOWS
// assuming near is always 1.0
float getLinearDepth()
{
return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
}
vec3 getLightSpacePosition()
{
return shadow_position * 0.5 + 0.5;
}
// custom smoothstep implementation because it's not defined in glsl1.2
// https://docs.gl/sl4/smoothstep
float mtsmoothstep(in float edge0, in float edge1, in float x)
{
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
}
#ifdef COLORED_SHADOWS
// c_precision of 128 fits within 7 base-10 digits
const float c_precision = 128.0;
const float c_precisionp1 = c_precision + 1.0;
float packColor(vec3 color)
{
return floor(color.b * c_precision + 0.5)
+ floor(color.g * c_precision + 0.5) * c_precisionp1
+ floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
}
vec3 unpackColor(float value)
{
vec3 color;
color.b = mod(value, c_precisionp1) / c_precision;
color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
return color;
}
vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
float visibility = step(0.0, realDistance - texDepth.r);
vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
if (visibility < 0.1) {
visibility = step(0.0, realDistance - texDepth.b);
result = vec4(visibility, unpackColor(texDepth.a));
}
return result;
}
#else
float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
float visibility = step(0.0, realDistance - texDepth);
return visibility;
}
#endif
#if SHADOW_FILTER == 2
#define PCFBOUND 2.0 // 5x5
#define PCFSAMPLES 25
#elif SHADOW_FILTER == 1
#define PCFBOUND 1.0 // 3x3
#define PCFSAMPLES 9
#else
#define PCFBOUND 0.0
#define PCFSAMPLES 1
#endif
#ifdef COLORED_SHADOWS
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
return depth;
}
#else
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
float depth = realDistance - texDepth;
return depth;
}
#endif
#define BASEFILTERRADIUS 1.0
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
// Return fast if sharp shadows are requested
if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0)
return 0.0;
vec2 clampedpos;
float y, x;
float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance);
// A factor from 0 to 1 to reduce blurring of short shadows
float sharpness_factor = 1.0;
// conversion factor from shadow depth to blur radius
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
if (depth > 0.0 && f_normal_length > 0.0)
// 5 is empirical factor that controls how fast shadow loses sharpness
sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0);
depth = 0.0;
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
* f_textureresolution / 2.0 / f_shadowfar;
float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node
return max(BASEFILTERRADIUS * f_textureresolution / 4096.0, sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS);
}
#ifdef POISSON_FILTER
const vec2[64] poissonDisk = vec2[64](
vec2(0.170019, -0.040254),
vec2(-0.299417, 0.791925),
vec2(0.645680, 0.493210),
vec2(-0.651784, 0.717887),
vec2(0.421003, 0.027070),
vec2(-0.817194, -0.271096),
vec2(-0.705374, -0.668203),
vec2(0.977050, -0.108615),
vec2(0.063326, 0.142369),
vec2(0.203528, 0.214331),
vec2(-0.667531, 0.326090),
vec2(-0.098422, -0.295755),
vec2(-0.885922, 0.215369),
vec2(0.566637, 0.605213),
vec2(0.039766, -0.396100),
vec2(0.751946, 0.453352),
vec2(0.078707, -0.715323),
vec2(-0.075838, -0.529344),
vec2(0.724479, -0.580798),
vec2(0.222999, -0.215125),
vec2(-0.467574, -0.405438),
vec2(-0.248268, -0.814753),
vec2(0.354411, -0.887570),
vec2(0.175817, 0.382366),
vec2(0.487472, -0.063082),
vec2(0.355476, 0.025357),
vec2(-0.084078, 0.898312),
vec2(0.488876, -0.783441),
vec2(0.470016, 0.217933),
vec2(-0.696890, -0.549791),
vec2(-0.149693, 0.605762),
vec2(0.034211, 0.979980),
vec2(0.503098, -0.308878),
vec2(-0.016205, -0.872921),
vec2(0.385784, -0.393902),
vec2(-0.146886, -0.859249),
vec2(0.643361, 0.164098),
vec2(0.634388, -0.049471),
vec2(-0.688894, 0.007843),
vec2(0.464034, -0.188818),
vec2(-0.440840, 0.137486),
vec2(0.364483, 0.511704),
vec2(0.034028, 0.325968),
vec2(0.099094, -0.308023),
vec2(0.693960, -0.366253),
vec2(0.678884, -0.204688),
vec2(0.001801, 0.780328),
vec2(0.145177, -0.898984),
vec2(0.062655, -0.611866),
vec2(0.315226, -0.604297),
vec2(-0.780145, 0.486251),
vec2(-0.371868, 0.882138),
vec2(0.200476, 0.494430),
vec2(-0.494552, -0.711051),
vec2(0.612476, 0.705252),
vec2(-0.578845, -0.768792),
vec2(-0.772454, -0.090976),
vec2(0.504440, 0.372295),
vec2(0.155736, 0.065157),
vec2(0.391522, 0.849605),
vec2(-0.620106, -0.328104),
vec2(0.789239, -0.419965),
vec2(-0.545396, 0.538133),
vec2(-0.178564, -0.596057)
);
#ifdef COLORED_SHADOWS
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
vec4 visibility = vec4(0.0);
float scale_factor = radius / f_textureresolution;
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
}
return visibility / samples;
}
#else
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
float visibility = 0.0;
float scale_factor = radius / f_textureresolution;
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
}
return visibility / samples;
}
#endif
#else
/* poisson filter disabled */
#ifdef COLORED_SHADOWS
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
vec4 visibility = vec4(0.0);
float x, y;
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
float scale_factor = radius / bound / f_textureresolution;
float n = 0.0;
// basic PCF filter
for (y = -bound; y <= bound; y += 1.0)
for (x = -bound; x <= bound; x += 1.0) {
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
n += 1.0;
}
return visibility / max(n, 1.0);
}
#else
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
float visibility = 0.0;
float x, y;
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
float scale_factor = radius / bound / f_textureresolution;
float n = 0.0;
// basic PCF filter
for (y = -bound; y <= bound; y += 1.0)
for (x = -bound; x <= bound; x += 1.0) {
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
n += 1.0;
}
return visibility / max(n, 1.0);
}
#endif
#endif
#endif
void main(void)
{
vec3 color;
vec2 uv = varTexCoord.st;
vec4 base = texture2D(baseTexture, uv).rgba;
// If alpha is zero, we can just discard the pixel. This fixes transparency
// on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
// and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
#ifdef USE_DISCARD
if (base.a == 0.0)
discard;
#endif
#ifdef USE_DISCARD_REF
/*if (base.a < 0.5)
discard;*/
#endif
color = base.rgb;
vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
#ifdef ENABLE_DYNAMIC_SHADOWS
if (f_shadow_strength > 0.0) {
float shadow_int = 0.0;
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
vec3 posLightSpace = getLightSpacePosition();
float distance_rate = (1.0 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 10.0));
if (max(abs(posLightSpace.x - 0.5), abs(posLightSpace.y - 0.5)) > 0.5)
distance_rate = 0.0;
float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z),0.0);
if (distance_rate > 1e-7) {
#ifdef COLORED_SHADOWS
vec4 visibility;
if (cosLight > 0.0 || f_normal_length < 1e-3)
visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
else
visibility = vec4(1.0, 0.0, 0.0, 0.0);
shadow_int = visibility.r;
shadow_color = visibility.gba;
#else
if (cosLight > 0.0 || f_normal_length < 1e-3)
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
else
shadow_int = 1.0;
#endif
shadow_int *= distance_rate;
shadow_int = clamp(shadow_int, 0.0, 1.0);
}
// turns out that nightRatio falls off much faster than
// actual brightness of artificial light in relation to natual light.
// Power ratio was measured on torches in MTG (brightness = 14).
float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);
// Apply self-shadowing when light falls at a narrow angle to the surface
// Cosine of the cut-off angle.
const float self_shadow_cutoff_cosine = 0.035;
if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) {
shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
}
// Get the Y component of base.rgb converted to YCbCr as an approximate
// brightness of the albedo
float albedo_y = dot(base.rgb, vec3(0.299, 0.587, 0.114));
// There are no specular map textures, so approximate the shininess
// and specular reflections strength with albedo_y
//~ float shininess = 16.0;
float shininess = 6.0 + (16.0 * pow(1.0 - albedo_y, 1.0));
float specular_visibility = pow(albedo_y, 1.0); //old value 3.0
//~ float specular_visibility = 1.0;
// view_dir: Vector from the fragment to the eye in world space.
// (eyeVec is view_dir in view space, but v_LightDirection is in
// world space)
vec3 view_dir = normalize((eyePosition - cameraOffset) - worldPosition);
vec3 halfway = normalize(normalize(view_dir) + normalize(-v_LightDirection));
// Colour (and intensity) of the sun/moon light
vec3 light_colour = mix(dayLight.rgb/4, col.rgb, 0.5);
shadow_int *= f_adj_shadow_strength;
if(base.a < 0.9) {
specular_visibility *= 7.0 - shadow_int; //testing water and some glasses
} else {
specular_visibility *= 1.0 - shadow_int; // darken in shadows
}
// Calculate specular reflections with the Blinn-Phong model
float spec = specular_visibility * pow(max(dot(vNormal, halfway), 0.0), shininess);
col.rgb =
adjusted_night_ratio * col.rgb + // artificial light
(1.0 - adjusted_night_ratio) * ( // natural light
col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color
light_colour * spec + // Specular reflection of the sun/moon
dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
}
#endif
// Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
// the fog will only be rendered correctly if the last operation before the
// clamp() is an addition. Else, the clamp() seems to be ignored.
// E.g. the following won't work:
// float clarity = clamp(fogShadingParameter
// * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
// As additions usually come for free following a multiplication, the new formula
// should be more efficient as well.
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(skyBgColor, col, clarity);
col = vec4(col.rgb, base.a);
gl_FragData[0] = col;
}
- apercy
- Member
- Posts: 667
- Joined: Wed Mar 25, 2020 16:31
- GitHub: APercy
- In-game: APercy
- Location: Pinheiral - RJ - Brazil
Re: Post your screenshots!
And for my last experiment, I adjusted it to work only with translucent objects reflections, to avoid some strange effects with bloom activated
Code: Select all
uniform sampler2D baseTexture;
uniform vec3 dayLight;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
uniform vec3 cameraOffset;
uniform float animationTimer;
#ifdef ENABLE_DYNAMIC_SHADOWS
// shadow texture
uniform sampler2D ShadowMapSampler;
// shadow uniforms
uniform vec3 v_LightDirection;
uniform float f_textureresolution;
uniform mat4 m_ShadowViewProj;
uniform float f_shadowfar;
uniform float f_shadow_strength;
uniform vec4 CameraPos;
uniform float xyPerspectiveBias0;
uniform float xyPerspectiveBias1;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
varying vec3 shadow_position;
varying float perspective_factor;
#endif
varying vec3 vNormal;
varying vec3 vPosition;
// World position in the visible world (i.e. relative to the cameraOffset.)
// This can be used for many shader effects without loss of precision.
// If the absolute position is required it can be calculated with
// cameraOffset + worldPosition (for large coordinates the limits of float
// precision must be considered).
varying vec3 worldPosition;
varying lowp vec4 varColor;
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec;
varying float nightRatio;
varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
#ifdef ENABLE_DYNAMIC_SHADOWS
// assuming near is always 1.0
float getLinearDepth()
{
return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
}
vec3 getLightSpacePosition()
{
return shadow_position * 0.5 + 0.5;
}
// custom smoothstep implementation because it's not defined in glsl1.2
// https://docs.gl/sl4/smoothstep
float mtsmoothstep(in float edge0, in float edge1, in float x)
{
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
}
#ifdef COLORED_SHADOWS
// c_precision of 128 fits within 7 base-10 digits
const float c_precision = 128.0;
const float c_precisionp1 = c_precision + 1.0;
float packColor(vec3 color)
{
return floor(color.b * c_precision + 0.5)
+ floor(color.g * c_precision + 0.5) * c_precisionp1
+ floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
}
vec3 unpackColor(float value)
{
vec3 color;
color.b = mod(value, c_precisionp1) / c_precision;
color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
return color;
}
vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
float visibility = step(0.0, realDistance - texDepth.r);
vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
if (visibility < 0.1) {
visibility = step(0.0, realDistance - texDepth.b);
result = vec4(visibility, unpackColor(texDepth.a));
}
return result;
}
#else
float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
float visibility = step(0.0, realDistance - texDepth);
return visibility;
}
#endif
#if SHADOW_FILTER == 2
#define PCFBOUND 2.0 // 5x5
#define PCFSAMPLES 25
#elif SHADOW_FILTER == 1
#define PCFBOUND 1.0 // 3x3
#define PCFSAMPLES 9
#else
#define PCFBOUND 0.0
#define PCFSAMPLES 1
#endif
#ifdef COLORED_SHADOWS
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
return depth;
}
#else
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
float depth = realDistance - texDepth;
return depth;
}
#endif
#define BASEFILTERRADIUS 1.0
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
// Return fast if sharp shadows are requested
if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0)
return 0.0;
vec2 clampedpos;
float y, x;
float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance);
// A factor from 0 to 1 to reduce blurring of short shadows
float sharpness_factor = 1.0;
// conversion factor from shadow depth to blur radius
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
if (depth > 0.0 && f_normal_length > 0.0)
// 5 is empirical factor that controls how fast shadow loses sharpness
sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0);
depth = 0.0;
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
* f_textureresolution / 2.0 / f_shadowfar;
float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node
return max(BASEFILTERRADIUS * f_textureresolution / 4096.0, sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS);
}
#ifdef POISSON_FILTER
const vec2[64] poissonDisk = vec2[64](
vec2(0.170019, -0.040254),
vec2(-0.299417, 0.791925),
vec2(0.645680, 0.493210),
vec2(-0.651784, 0.717887),
vec2(0.421003, 0.027070),
vec2(-0.817194, -0.271096),
vec2(-0.705374, -0.668203),
vec2(0.977050, -0.108615),
vec2(0.063326, 0.142369),
vec2(0.203528, 0.214331),
vec2(-0.667531, 0.326090),
vec2(-0.098422, -0.295755),
vec2(-0.885922, 0.215369),
vec2(0.566637, 0.605213),
vec2(0.039766, -0.396100),
vec2(0.751946, 0.453352),
vec2(0.078707, -0.715323),
vec2(-0.075838, -0.529344),
vec2(0.724479, -0.580798),
vec2(0.222999, -0.215125),
vec2(-0.467574, -0.405438),
vec2(-0.248268, -0.814753),
vec2(0.354411, -0.887570),
vec2(0.175817, 0.382366),
vec2(0.487472, -0.063082),
vec2(0.355476, 0.025357),
vec2(-0.084078, 0.898312),
vec2(0.488876, -0.783441),
vec2(0.470016, 0.217933),
vec2(-0.696890, -0.549791),
vec2(-0.149693, 0.605762),
vec2(0.034211, 0.979980),
vec2(0.503098, -0.308878),
vec2(-0.016205, -0.872921),
vec2(0.385784, -0.393902),
vec2(-0.146886, -0.859249),
vec2(0.643361, 0.164098),
vec2(0.634388, -0.049471),
vec2(-0.688894, 0.007843),
vec2(0.464034, -0.188818),
vec2(-0.440840, 0.137486),
vec2(0.364483, 0.511704),
vec2(0.034028, 0.325968),
vec2(0.099094, -0.308023),
vec2(0.693960, -0.366253),
vec2(0.678884, -0.204688),
vec2(0.001801, 0.780328),
vec2(0.145177, -0.898984),
vec2(0.062655, -0.611866),
vec2(0.315226, -0.604297),
vec2(-0.780145, 0.486251),
vec2(-0.371868, 0.882138),
vec2(0.200476, 0.494430),
vec2(-0.494552, -0.711051),
vec2(0.612476, 0.705252),
vec2(-0.578845, -0.768792),
vec2(-0.772454, -0.090976),
vec2(0.504440, 0.372295),
vec2(0.155736, 0.065157),
vec2(0.391522, 0.849605),
vec2(-0.620106, -0.328104),
vec2(0.789239, -0.419965),
vec2(-0.545396, 0.538133),
vec2(-0.178564, -0.596057)
);
#ifdef COLORED_SHADOWS
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
vec4 visibility = vec4(0.0);
float scale_factor = radius / f_textureresolution;
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
}
return visibility / samples;
}
#else
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
float visibility = 0.0;
float scale_factor = radius / f_textureresolution;
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
}
return visibility / samples;
}
#endif
#else
/* poisson filter disabled */
#ifdef COLORED_SHADOWS
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
vec4 visibility = vec4(0.0);
float x, y;
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
float scale_factor = radius / bound / f_textureresolution;
float n = 0.0;
// basic PCF filter
for (y = -bound; y <= bound; y += 1.0)
for (x = -bound; x <= bound; x += 1.0) {
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
n += 1.0;
}
return visibility / max(n, 1.0);
}
#else
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
float visibility = 0.0;
float x, y;
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
float scale_factor = radius / bound / f_textureresolution;
float n = 0.0;
// basic PCF filter
for (y = -bound; y <= bound; y += 1.0)
for (x = -bound; x <= bound; x += 1.0) {
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
n += 1.0;
}
return visibility / max(n, 1.0);
}
#endif
#endif
#endif
vec3 get_transparent_reflections(vec4 base, vec3 eyePosition, vec3 cameraOffset, vec3 worldPosition,
vec3 v_LightDirection, vec3 dayLight, vec4 col, float f_adj_shadow_strength,
vec3 vNormal, float shadow_int)
{
if(base.a > 0.9) return vec3(0.0);
// Get the Y component of base.rgb converted to YCbCr as an approximate
// brightness of the albedo
float albedo_y = dot(base.rgb, vec3(0.299, 0.587, 0.114));
// There are no specular map textures, so approximate the shininess
// and specular reflections strength with albedo_y
//~ float shininess = 16.0;
float shininess = 6.0 + (16.0 * pow(1.0 - albedo_y, 1.0));
float specular_visibility = pow(albedo_y, 1.0); //old value 3.0
//~ float specular_visibility = 1.0;
// view_dir: Vector from the fragment to the eye in world space.
// (eyeVec is view_dir in view space, but v_LightDirection is in
// world space)
vec3 view_dir = normalize((eyePosition - cameraOffset) - worldPosition);
vec3 halfway = normalize(normalize(view_dir) + normalize(-v_LightDirection));
// Colour (and intensity) of the sun/moon light
vec3 light_colour = mix(dayLight.rgb/4, col.rgb, 0.5);
shadow_int *= f_adj_shadow_strength;
specular_visibility *= 7.0 - shadow_int; //testing water and some glasses
// Calculate specular reflections with the Blinn-Phong model
float spec = specular_visibility * pow(max(dot(vNormal, halfway), 0.0), shininess);
vec3 retVal = light_colour * spec;
return retVal;
}
void main(void)
{
vec3 color;
vec2 uv = varTexCoord.st;
vec4 base = texture2D(baseTexture, uv).rgba;
// If alpha is zero, we can just discard the pixel. This fixes transparency
// on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
// and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
#ifdef USE_DISCARD
if (base.a == 0.0)
discard;
#endif
#ifdef USE_DISCARD_REF
if (base.a < 0.5)
discard;
#endif
color = base.rgb;
vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
#ifdef ENABLE_DYNAMIC_SHADOWS
if (f_shadow_strength > 0.0) {
float shadow_int = 0.0;
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
vec3 posLightSpace = getLightSpacePosition();
float distance_rate = (1.0 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 10.0));
if (max(abs(posLightSpace.x - 0.5), abs(posLightSpace.y - 0.5)) > 0.5)
distance_rate = 0.0;
float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z),0.0);
if (distance_rate > 1e-7) {
#ifdef COLORED_SHADOWS
vec4 visibility;
if (cosLight > 0.0 || f_normal_length < 1e-3)
visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
else
visibility = vec4(1.0, 0.0, 0.0, 0.0);
shadow_int = visibility.r;
shadow_color = visibility.gba;
#else
if (cosLight > 0.0 || f_normal_length < 1e-3)
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
else
shadow_int = 1.0;
#endif
shadow_int *= distance_rate;
shadow_int = clamp(shadow_int, 0.0, 1.0);
}
// turns out that nightRatio falls off much faster than
// actual brightness of artificial light in relation to natual light.
// Power ratio was measured on torches in MTG (brightness = 14).
float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);
// Apply self-shadowing when light falls at a narrow angle to the surface
// Cosine of the cut-off angle.
const float self_shadow_cutoff_cosine = 0.035;
if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) {
shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
}
shadow_int *= f_adj_shadow_strength;
vec3 reflections = get_transparent_reflections(base, eyePosition, cameraOffset, worldPosition,
v_LightDirection, dayLight, col, f_adj_shadow_strength,
vNormal, shadow_int);
// calculate fragment color from components:
col.rgb =
adjusted_night_ratio * col.rgb + // artificial light
(1.0 - adjusted_night_ratio) * ( // natural light
col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color
reflections +
dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
}
#endif
// Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
// the fog will only be rendered correctly if the last operation before the
// clamp() is an addition. Else, the clamp() seems to be ignored.
// E.g. the following won't work:
// float clarity = clamp(fogShadingParameter
// * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
// As additions usually come for free following a multiplication, the new formula
// should be more efficient as well.
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(skyBgColor, col, clarity);
col = vec4(col.rgb, base.a);
gl_FragData[0] = col;
}
- apercy
- Member
- Posts: 667
- Joined: Wed Mar 25, 2020 16:31
- GitHub: APercy
- In-game: APercy
- Location: Pinheiral - RJ - Brazil
Re: Post your screenshots!
Shadows improved
Code: Select all
uniform sampler2D baseTexture;
uniform vec3 dayLight;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
uniform vec3 cameraOffset;
uniform float animationTimer;
#ifdef ENABLE_DYNAMIC_SHADOWS
// shadow texture
uniform sampler2D ShadowMapSampler;
// shadow uniforms
uniform vec3 v_LightDirection;
uniform float f_textureresolution;
uniform mat4 m_ShadowViewProj;
uniform float f_shadowfar;
uniform float f_shadow_strength;
uniform vec4 CameraPos;
uniform float xyPerspectiveBias0;
uniform float xyPerspectiveBias1;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
varying vec3 shadow_position;
varying float perspective_factor;
#endif
varying vec3 vNormal;
varying vec3 vPosition;
// World position in the visible world (i.e. relative to the cameraOffset.)
// This can be used for many shader effects without loss of precision.
// If the absolute position is required it can be calculated with
// cameraOffset + worldPosition (for large coordinates the limits of float
// precision must be considered).
varying vec3 worldPosition;
varying lowp vec4 varColor;
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec;
varying float nightRatio;
varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
#ifdef ENABLE_DYNAMIC_SHADOWS
// assuming near is always 1.0
float getLinearDepth()
{
return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
}
vec3 getLightSpacePosition()
{
return shadow_position * 0.5 + 0.5;
}
// custom smoothstep implementation because it's not defined in glsl1.2
// https://docs.gl/sl4/smoothstep
float mtsmoothstep(in float edge0, in float edge1, in float x)
{
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
}
#ifdef COLORED_SHADOWS
// c_precision of 128 fits within 7 base-10 digits
const float c_precision = 128.0;
const float c_precisionp1 = c_precision + 1.0;
float packColor(vec3 color)
{
return floor(color.b * c_precision + 0.5)
+ floor(color.g * c_precision + 0.5) * c_precisionp1
+ floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
}
vec3 unpackColor(float value)
{
vec3 color;
color.b = mod(value, c_precisionp1) / c_precision;
color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
return color;
}
vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
float visibility = step(0.0, realDistance - texDepth.r);
vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
if (visibility < 0.1) {
visibility = step(0.0, realDistance - texDepth.b);
result = vec4(visibility, unpackColor(texDepth.a));
}
return result;
}
#else
float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
float visibility = step(0.0, realDistance - texDepth);
return visibility;
}
#endif
#if SHADOW_FILTER == 2
#define PCFBOUND 2.0 // 5x5
#define PCFSAMPLES 25
#elif SHADOW_FILTER == 1
#define PCFBOUND 1.0 // 3x3
#define PCFSAMPLES 9
#else
#define PCFBOUND 0.0
#define PCFSAMPLES 1
#endif
#ifdef COLORED_SHADOWS
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
return depth;
}
#else
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
float depth = realDistance - texDepth;
return depth;
}
#endif
#define BASEFILTERRADIUS 1.0
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
// Return fast if sharp shadows are requested
if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0)
return 0.0;
vec2 clampedpos;
float y, x;
float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance);
// A factor from 0 to 1 to reduce blurring of short shadows
float sharpness_factor = 1.0;
// conversion factor from shadow depth to blur radius
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
if (depth > 0.0 && f_normal_length > 0.0)
// 5 is empirical factor that controls how fast shadow loses sharpness
sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0);
depth = 0.0;
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
* f_textureresolution / 2.0 / f_shadowfar;
float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node
return max(BASEFILTERRADIUS * f_textureresolution / 4096.0, sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS);
}
#ifdef POISSON_FILTER
const vec2[64] poissonDisk = vec2[64](
vec2(0.170019, -0.040254),
vec2(-0.299417, 0.791925),
vec2(0.645680, 0.493210),
vec2(-0.651784, 0.717887),
vec2(0.421003, 0.027070),
vec2(-0.817194, -0.271096),
vec2(-0.705374, -0.668203),
vec2(0.977050, -0.108615),
vec2(0.063326, 0.142369),
vec2(0.203528, 0.214331),
vec2(-0.667531, 0.326090),
vec2(-0.098422, -0.295755),
vec2(-0.885922, 0.215369),
vec2(0.566637, 0.605213),
vec2(0.039766, -0.396100),
vec2(0.751946, 0.453352),
vec2(0.078707, -0.715323),
vec2(-0.075838, -0.529344),
vec2(0.724479, -0.580798),
vec2(0.222999, -0.215125),
vec2(-0.467574, -0.405438),
vec2(-0.248268, -0.814753),
vec2(0.354411, -0.887570),
vec2(0.175817, 0.382366),
vec2(0.487472, -0.063082),
vec2(0.355476, 0.025357),
vec2(-0.084078, 0.898312),
vec2(0.488876, -0.783441),
vec2(0.470016, 0.217933),
vec2(-0.696890, -0.549791),
vec2(-0.149693, 0.605762),
vec2(0.034211, 0.979980),
vec2(0.503098, -0.308878),
vec2(-0.016205, -0.872921),
vec2(0.385784, -0.393902),
vec2(-0.146886, -0.859249),
vec2(0.643361, 0.164098),
vec2(0.634388, -0.049471),
vec2(-0.688894, 0.007843),
vec2(0.464034, -0.188818),
vec2(-0.440840, 0.137486),
vec2(0.364483, 0.511704),
vec2(0.034028, 0.325968),
vec2(0.099094, -0.308023),
vec2(0.693960, -0.366253),
vec2(0.678884, -0.204688),
vec2(0.001801, 0.780328),
vec2(0.145177, -0.898984),
vec2(0.062655, -0.611866),
vec2(0.315226, -0.604297),
vec2(-0.780145, 0.486251),
vec2(-0.371868, 0.882138),
vec2(0.200476, 0.494430),
vec2(-0.494552, -0.711051),
vec2(0.612476, 0.705252),
vec2(-0.578845, -0.768792),
vec2(-0.772454, -0.090976),
vec2(0.504440, 0.372295),
vec2(0.155736, 0.065157),
vec2(0.391522, 0.849605),
vec2(-0.620106, -0.328104),
vec2(0.789239, -0.419965),
vec2(-0.545396, 0.538133),
vec2(-0.178564, -0.596057)
);
#ifdef COLORED_SHADOWS
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
vec4 visibility = vec4(0.0);
float scale_factor = radius / f_textureresolution;
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
}
return visibility / samples;
}
#else
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
float visibility = 0.0;
float scale_factor = radius / f_textureresolution;
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
}
return visibility / samples;
}
#endif
#else
/* poisson filter disabled */
#ifdef COLORED_SHADOWS
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
vec4 visibility = vec4(0.0);
float x, y;
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
float scale_factor = radius / bound / f_textureresolution;
float n = 0.0;
// basic PCF filter
for (y = -bound; y <= bound; y += 1.0)
for (x = -bound; x <= bound; x += 1.0) {
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
n += 1.0;
}
return visibility / max(n, 1.0);
}
#else
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
if (radius < 0.1) {
// we are in the middle of even brightness, no need for filtering
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
}
vec2 clampedpos;
float visibility = 0.0;
float x, y;
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
float scale_factor = radius / bound / f_textureresolution;
float n = 0.0;
// basic PCF filter
for (y = -bound; y <= bound; y += 1.0)
for (x = -bound; x <= bound; x += 1.0) {
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
n += 1.0;
}
return visibility / max(n, 1.0);
}
#endif
#endif
#endif
vec3 get_transparent_reflections(vec4 base, vec3 eyePosition, vec3 cameraOffset, vec3 worldPosition,
vec3 v_LightDirection, vec3 dayLight, vec4 col, float f_adj_shadow_strength,
vec3 vNormal, float shadow_int)
{
if(base.a > 0.9) return vec3(0.0);
shadow_int *= f_adj_shadow_strength; //adjust by strength
// Get the Y component of base.rgb converted to YCbCr as an approximate
// brightness of the albedo
float albedo_y = dot(base.rgb, vec3(0.299, 0.587, 0.114));
albedo_y = albedo_y - min(shadow_int,albedo_y); //remove from the shadows
// There are no specular map textures, so approximate the shininess
// and specular reflections strength with albedo_y
float shininess = 6.0 + (16.0 * (1.0 - albedo_y));
float specular_visibility = albedo_y; //pow(albedo_y, 3.0);
// view_dir: Vector from the fragment to the eye in world space.
// (eyeVec is view_dir in view space, but v_LightDirection is in
// world space)
vec3 view_dir = normalize((eyePosition - cameraOffset) - worldPosition);
vec3 halfway = normalize(normalize(view_dir) + normalize(-v_LightDirection));
// Colour (and intensity) of the sun/moon light
vec3 light_colour = mix(dayLight.rgb/4, col.rgb, 0.5);
float multiplier = 7.0;
specular_visibility *= multiplier - (shadow_int*multiplier); //set shadow correctly
// Calculate specular reflections with the Blinn-Phong model
float spec = specular_visibility * pow(max(dot(vNormal, halfway), 0.0), shininess);
vec3 retVal = light_colour * spec;
return retVal;
}
void main(void)
{
vec3 color;
vec2 uv = varTexCoord.st;
vec4 base = texture2D(baseTexture, uv).rgba;
// If alpha is zero, we can just discard the pixel. This fixes transparency
// on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
// and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
#ifdef USE_DISCARD
if (base.a == 0.0)
discard;
#endif
#ifdef USE_DISCARD_REF
if (base.a < 0.5)
discard;
#endif
color = base.rgb;
vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
#ifdef ENABLE_DYNAMIC_SHADOWS
if (f_shadow_strength > 0.0) {
float shadow_int = 0.0;
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
vec3 posLightSpace = getLightSpacePosition();
float distance_rate = (1.0 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 10.0));
if (max(abs(posLightSpace.x - 0.5), abs(posLightSpace.y - 0.5)) > 0.5)
distance_rate = 0.0;
float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z),0.0);
if (distance_rate > 1e-7) {
#ifdef COLORED_SHADOWS
vec4 visibility;
if (cosLight > 0.0 || f_normal_length < 1e-3)
visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
else
visibility = vec4(1.0, 0.0, 0.0, 0.0);
shadow_int = visibility.r;
shadow_color = visibility.gba;
#else
if (cosLight > 0.0 || f_normal_length < 1e-3)
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
else
shadow_int = 1.0;
#endif
shadow_int *= distance_rate;
shadow_int = clamp(shadow_int, 0.0, 1.0);
}
// turns out that nightRatio falls off much faster than
// actual brightness of artificial light in relation to natual light.
// Power ratio was measured on torches in MTG (brightness = 14).
float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);
// Apply self-shadowing when light falls at a narrow angle to the surface
// Cosine of the cut-off angle.
const float self_shadow_cutoff_cosine = 0.035;
if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) {
shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
}
shadow_int *= f_adj_shadow_strength;
vec3 reflections = get_transparent_reflections(base, eyePosition, cameraOffset, worldPosition,
v_LightDirection, dayLight, col, f_adj_shadow_strength,
vNormal, shadow_int);
// calculate fragment color from components:
col.rgb =
adjusted_night_ratio * col.rgb + // artificial light
(1.0 - adjusted_night_ratio) * ( // natural light
col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color
reflections +
dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
}
#endif
// Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
// the fog will only be rendered correctly if the last operation before the
// clamp() is an addition. Else, the clamp() seems to be ignored.
// E.g. the following won't work:
// float clarity = clamp(fogShadingParameter
// * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
// As additions usually come for free following a multiplication, the new formula
// should be more efficient as well.
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(skyBgColor, col, clarity);
col = vec4(col.rgb, base.a);
gl_FragData[0] = col;
}
- Blockhead
- Moderator
- Posts: 2238
- Joined: Wed Jul 17, 2019 10:14
- GitHub: Montandalar
- IRC: Blockhead256
- In-game: Blockhead Blockhead256
- Location: Land Down Under
- Contact:
Re: Post your screenshots!
Cooking up some kelp
- Attachments
-
- screenshot_20230110_224156.png (186.57 KiB) Viewed 6651 times
/˳˳_˳˳]_[˳˳_˳˳]_[˳˳_˳˳\ Advtrains enthusiast | My map: Noah's Railyard | My Content on ContentDB ✝️♂