Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various visual effects #14508

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions builtin/settingtypes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ enable_clouds (Clouds) bool true
# Requires: enable_clouds
enable_3d_clouds (3D clouds) bool true

# Use smooth cloud shading.
#
# Requires: enable_3d_clouds, enable_clouds
soft_clouds (Soft clouds) bool false

[**Filtering and Antialiasing]

# Use mipmaps when scaling textures. May slightly increase performance,
Expand Down Expand Up @@ -506,6 +511,11 @@ water_wave_length (Waving liquids wavelength) float 20.0 0.1
# Requires: shaders, enable_waving_water
water_wave_speed (Waving liquids wave speed) float 5.0

# When enabled, liquid reflections are simulated.
#
# Requires: shaders, enable_waving_water, enable_dynamic_shadows
enable_water_reflections (Liquid reflections) bool false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... Should this be here, or also under shaders? I feel like this into the shader section.


[**Dynamic shadows]

# Set to true to enable Shadow Mapping.
Expand Down Expand Up @@ -610,6 +620,16 @@ enable_auto_exposure (Enable Automatic Exposure) bool false
# Requires: shaders, enable_post_processing, enable_auto_exposure
exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0

# Apply color grading to make brighter colors warmer and darker colors cooler.
#
# Requires: shaders, enable_post_processing
enable_color_grading (Color grading) bool false

# Apply vignette effect to darken the edges of the screen.
#
# Requires: shaders, enable_post_processing
enable_vignette (Vignette) bool false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these two sound like a good target for splitting into another PR


# Apply dithering to reduce color banding artifacts.
# Dithering significantly increases the size of losslessly-compressed
# screenshots and it works incorrectly if the display or operating system
Expand Down Expand Up @@ -662,6 +682,36 @@ bloom_radius (Bloom Radius) float 1 0.1 8
# Requires: shaders, enable_post_processing, enable_bloom
enable_volumetric_lighting (Volumetric lighting) bool false

[**Other Effects]

# Simulate translucency when looking at foliage in the sunlight.
#
# Requires: enable_shaders, enable_dynamic_shadows
enable_translucent_foliage (Translucent foliage) bool false

# Apply crude bump maps to nodes. It is recommended to use a tilted sun orbit to go with this (Sky Body Orbit Tilt).
#
# Requires: enable_shaders, enable_dynamic_shadows
enable_bumpmaps (Bump maps) bool false

# Apply reflections to nodes.
#
# Requires: enable_shaders, enable_dynamic_shadows
enable_node_reflections (Node reflections) bool false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this just work as one-size-fits-all effect on all nodes?
due to the assumed complexity also sounds like a good splitting target


# Tint sunlight orange during dusk and dawn.
#
# Requires: enable_shaders
tinted_sunlight (Tinted sunlight) bool false

# The color of light that sources like lamps, torches etc. give off.
# - default: Neutral, white light.
# - medium: Slightly warmer color than default.
# - warm: Warm (yellowish-orangy) light.
#
# Requires: enable_shaders
artificial_light (Artificial light color) enum default default,medium,warm

[*Audio]

# Volume of all sounds.
Expand Down
173 changes: 166 additions & 7 deletions client/shaders/nodes_shader/opengl_fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT)
#define MATERIAL_WAVING_LIQUID 1
#define MATERIAL_LIQUID 1
#elif (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE)
#define MATERIAL_LIQUID 1
#endif

uniform sampler2D baseTexture;
uniform vec2 texelSize0;

uniform vec3 dayLight;
uniform lowp vec4 fogColor;
Expand All @@ -20,6 +28,7 @@ uniform float animationTimer;
uniform vec4 CameraPos;
uniform float xyPerspectiveBias0;
uniform float xyPerspectiveBias1;
uniform vec3 shadow_tint;

varying float adj_shadow_strength;
varying float cosLight;
Expand All @@ -46,7 +55,75 @@ centroid varying vec2 varTexCoord;
varying highp vec3 eyeVec;
varying float nightRatio;

varying vec3 viewVec;

#ifdef ENABLE_DYNAMIC_SHADOWS
vec4 perm(vec4 x)
{
return mod(((x * 34.0) + 1.0) * x, 289.0);
}

#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS)) || defined(ENABLE_BUMPMAPS)
float snoise(vec3 p)
{
vec3 a = floor(p);
vec3 d = p - a;
d = d * d * (3.0 - 2.0 * d);

vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);
vec4 k1 = perm(b.xyxy);
vec4 k2 = perm(k1.xyxy + b.zzww);

vec4 c = k2 + a.zzzz;
vec4 k3 = perm(c);
vec4 k4 = perm(c + 1.0);

vec4 o1 = fract(k3 * (1.0 / 41.0));
vec4 o2 = fract(k4 * (1.0 / 41.0));

vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);
vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);

return o4.y * d.y + o4.x * (1.0 - d.y);
}

// Corresponding gradient of snoise
vec3 gnoise(vec3 p){
vec3 a = floor(p);
vec3 d = p - a;
vec3 dd = 6.0 * d * (1.0 - d);
d = d * d * (3.0 - 2.0 * d);

vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);
vec4 k1 = perm(b.xyxy);
vec4 k2 = perm(k1.xyxy + b.zzww);

vec4 c = k2 + a.zzzz;
vec4 k3 = perm(c);
vec4 k4 = perm(c + 1.0);

vec4 o1 = fract(k3 * (1.0 / 41.0));
vec4 o2 = fract(k4 * (1.0 / 41.0));

vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);
vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);

vec4 dz1 = (o2 - o1) * dd.z;
vec2 dz2 = dz1.yw * d.x + dz1.xz * (1.0 - d.x);

vec2 dx = (o3.yw - o3.xz) * dd.x;

return vec3(
dx.y * d.y + dx.x * (1. - d.y),
(o4.y - o4.x) * dd.y,
dz2.y * d.y + dz2.x * (1. - d.y)
);
}

vec2 wave_noise(vec3 p, float off) {
return (gnoise(p + vec3(0.0, 0.0, off)) * 0.4 + gnoise(2.0 * p + vec3(0.0, off, off)) * 0.2 + gnoise(3.0 * p + vec3(0.0, off, off)) * 0.225 + gnoise(4.0 * p + vec3(-off, off, 0.0)) * 0.2).xz;
}
#endif

// assuming near is always 1.0
float getLinearDepth()
Expand Down Expand Up @@ -378,6 +455,26 @@ void main(void)
vec4 col = vec4(color.rgb * varColor.rgb, 1.0);

#ifdef ENABLE_DYNAMIC_SHADOWS
// Fragment normal, can differ from vNormal which is derived from vertex normals.
vec3 fNormal = vNormal;

#if (defined(ENABLE_BUMPMAPS) && !defined(MATERIAL_LIQUID))
vec2 dr = vec2(0.25) * texelSize0;
// Sample the texture to then compute the derivative
float fx0y0 = texture2D(baseTexture, uv).r;
float fx1y0 = texture2D(baseTexture, uv + vec2(dr.x, 0.0)).r;
float fx0y1 = texture2D(baseTexture, uv + vec2(0.0, dr.y)).r;
// Compute a set of orthogonal basis vectors representing the node's surface plane.
vec3 orth1 = normalize(cross(vNormal, mix(vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, -1.0), step(0.9, abs(vNormal.y)))));
vec3 orth2 = normalize(cross(vNormal, orth1));
// The normal is computed using the partial derivatives along the texture space x and y axes.
// These axes in world space are assumed to be parallel to the basis vectors we defined before.
fNormal = normalize(vNormal + (orth1 * (fx1y0 - fx0y0) / dr.x + orth2 * (fx0y1 - fx0y0) / dr.y) * 0.25 * snoise(vec3(uv / texelSize0, 0.0)));
float adj_cosLight = max(1e-5, dot(fNormal, -v_LightDirection));
#else
float adj_cosLight = cosLight;
#endif

if (f_shadow_strength > 0.0) {
float shadow_int = 0.0;
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
Expand All @@ -392,14 +489,14 @@ void main(void)

#ifdef COLORED_SHADOWS
vec4 visibility;
if (cosLight > 0.0 || f_normal_length < 1e-3)
if (adj_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)
if (adj_cosLight > 0.0 || f_normal_length < 1e-3)
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
else
shadow_int = 1.0;
Expand All @@ -414,12 +511,18 @@ void main(void)
// Power ratio was measured on torches in MTG (brightness = 14).
float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);

float shadow_uncorrected = shadow_int;

// 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);
if (f_normal_length != 0 && adj_cosLight < self_shadow_cutoff_cosine) {
shadow_int = max(shadow_int, 1 - clamp(adj_cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
shadow_color = mix(vec3(0.0), shadow_color, min(adj_cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);

#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES)
shadow_uncorrected = mix(shadow_int, shadow_uncorrected, clamp(distance_rate * 4.0 - 3.0, 0.0, 1.0));
#endif
}

shadow_int *= f_adj_shadow_strength;
Expand All @@ -428,8 +531,62 @@ void main(void)
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
col.rgb * (1.0 - shadow_int * (1.0 - shadow_color) * (1.0 - shadow_tint)) + // filtered texture color
dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight


vec3 reflect_ray = -normalize(v_LightDirection - fNormal * dot(v_LightDirection, fNormal) * 2.0);

#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS))
vec3 wavePos = worldPosition * vec3(2.0, 0.0, 2.0);
float off = animationTimer * WATER_WAVE_SPEED * 10.0;
wavePos.x /= WATER_WAVE_LENGTH * 3.0;
wavePos.z /= WATER_WAVE_LENGTH * 2.0;

// This is an analogous method to the bumpmap, except we get the gradient information directly from gnoise.
vec2 gradient = wave_noise(wavePos, off);
fNormal = normalize(normalize(fNormal) + vec3(gradient.x, 0., gradient.y) * WATER_WAVE_HEIGHT * abs(fNormal.y) * 0.25);
reflect_ray = -normalize(v_LightDirection - fNormal * dot(v_LightDirection, fNormal) * 2.0);
float fresnel_factor = dot(fNormal, viewVec);

float brightness_factor = 1.0 - adjusted_night_ratio;

// A little trig hack. We go from the dot product of viewVec and normal to the dot product of viewVec and tangent to apply a fresnel effect.
fresnel_factor = clamp(pow(1.0 - fresnel_factor * fresnel_factor, 8.0), 0.0, 1.0);
col.rgb *= 0.5;
vec3 reflection_color = mix(vec3(max(fogColor.r, max(fogColor.g, fogColor.b))), fogColor.rgb, f_shadow_strength);

// Sky reflection
col.rgb += reflection_color * pow(fresnel_factor, 2.0) * 0.5 * brightness_factor;
vec3 water_reflect_color = 12.0 * dayLight * fresnel_factor * mtsmoothstep(0.85, 0.9, pow(clamp(dot(reflect_ray, viewVec), 0.0, 1.0), 32.0)) * max(1.0 - shadow_uncorrected, 0.0);

// This line exists to prevent ridiculously bright reflection colors.
water_reflect_color /= clamp(max(water_reflect_color.r, max(water_reflect_color.g, water_reflect_color.b)) * 0.5, 1.0, 400.0);
col.rgb += water_reflect_color * f_adj_shadow_strength * brightness_factor;
#endif

#if (defined(ENABLE_NODE_REFLECTIONS) && !defined(MATERIAL_WAVING_LIQUID))

#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES)
#define REFLECTION_INTENSITY 2.0
#elif (defined(MATERIAL_WAVING_LIQUID))
#define REFLECTION_INTENSITY 0.0
#else
#define REFLECTION_INTENSITY 1.0
#endif
// Apply reflections to blocks.
if (dot(v_LightDirection, vNormal) < 0.0) {
col.rgb +=
1.5 * dayLight * f_adj_shadow_strength * REFLECTION_INTENSITY * (1.0 - nightRatio) *
pow(max(dot(reflect_ray, viewVec), 0.0), 4.0) * pow(1.0 - abs(dot(viewVec, fNormal)), 5.0) *
(1.0 - shadow_uncorrected) * (1.0 - base.r);
}
#endif

#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES) && defined(ENABLE_TRANSLUCENT_FOLIAGE)
// Simulate translucent foliage.
col.rgb += 3.0 * dayLight * base.rgb * normalize(base.rgb * varColor.rgb * varColor.rgb) * f_adj_shadow_strength * pow(max(-dot(v_LightDirection, viewVec), 0.0), 4.0) * max(1.0 - shadow_uncorrected, 0.0);
#endif
}
#endif

Expand All @@ -444,7 +601,9 @@ void main(void)
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(fogColor, col, clarity);
float fogColorMax = max(max(fogColor.r, fogColor.g), fogColor.b);
if (fogColorMax < 0.0000001) fogColorMax = 1.0;
col = mix(fogColor * pow(fogColor / fogColorMax, vec4(2.0 * clarity)), col, clarity);
col = vec4(col.rgb, base.a);

gl_FragData[0] = col;
Expand Down
14 changes: 9 additions & 5 deletions client/shaders/nodes_shader/opengl_vertex.glsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
uniform mat4 mWorld;
// Color of the light emitted by the sun.
uniform vec3 dayLight;
uniform vec3 eyePosition;

// The cameraOffset is the current center of the visible world.
uniform highp vec3 cameraOffset;
Expand Down Expand Up @@ -43,10 +44,11 @@ centroid varying vec2 varTexCoord;

varying float area_enable_parallax;

varying vec3 viewVec;
varying highp vec3 eyeVec;
varying float nightRatio;
// Color of the light emitted by the light sources.
const vec3 artificialLight = vec3(1.04, 1.04, 1.04);
uniform vec3 artificialLight;
const float e = 2.718281828459;
const float BS = 10.0;
uniform float xyPerspectiveBias0;
Expand Down Expand Up @@ -231,6 +233,8 @@ void main(void)
#else
vec4 shadow_pos = pos;
#endif
viewVec = normalize(worldPosition + cameraOffset - eyePosition);

vec3 nNormal;
f_normal_length = length(vNormal);

Expand Down Expand Up @@ -261,14 +265,14 @@ void main(void)

if (f_timeofday < 0.2) {
adj_shadow_strength = f_shadow_strength * 0.5 *
(1.0 - mtsmoothstep(0.18, 0.2, f_timeofday));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the magic number changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simple reason is the old values don't look very good imo, especially during sunsets the shadows fade far too quickly. This is basically a function for shadow strength over time, so I've plotted that here. Blue is the original, red is the changed one.

functions

It should be pretty apparent why sunsets would be especially washed out. The old function is also very strangely asymmetric, which is odd if you think about the physical implications of that, and the new one isn't. I suppose it makes sense that the shadows change faster when the moon rises and sets compared to the sun, so that might make sense to change back to be fair.

(1.0 - mtsmoothstep(0.15, 0.2, f_timeofday));
} else if (f_timeofday >= 0.8) {
adj_shadow_strength = f_shadow_strength * 0.5 *
mtsmoothstep(0.8, 0.83, f_timeofday);
mtsmoothstep(0.8, 0.85, f_timeofday);
} else {
adj_shadow_strength = f_shadow_strength *
mtsmoothstep(0.20, 0.25, f_timeofday) *
(1.0 - mtsmoothstep(0.7, 0.8, f_timeofday));
mtsmoothstep(0.18, 0.25, f_timeofday) *
(1.0 - mtsmoothstep(0.75, 0.8, f_timeofday));
}
}
#endif
Expand Down
7 changes: 5 additions & 2 deletions client/shaders/object_shader/opengl_fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ uniform float animationTimer;
uniform vec4 CameraPos;
uniform float xyPerspectiveBias0;
uniform float xyPerspectiveBias1;
uniform vec3 shadow_tint;

varying float adj_shadow_strength;
varying float cosLight;
Expand Down Expand Up @@ -432,7 +433,7 @@ void main(void)
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
col.rgb * (1.0 - shadow_int * (1.0 - shadow_color) * (1.0 - shadow_tint)) + // filtered texture color
dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
}
#endif
Expand All @@ -448,7 +449,9 @@ void main(void)
// Note: clarity = (1 - fogginess)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(fogColor, col, clarity);
float fogColorMax = max(max(fogColor.r, fogColor.g), fogColor.b);
if (fogColorMax < 0.0000001) fogColorMax = 1.0;
col = mix(fogColor * pow(fogColor / fogColorMax, vec4(2.0 * clarity)), col, clarity);
col = vec4(col.rgb, base.a);

gl_FragData[0] = col;
Expand Down
Loading
Loading