mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Update volumetrics
This commit is contained in:
parent
22ba7449f2
commit
e6752008e0
17 changed files with 420 additions and 181 deletions
|
@ -610,14 +610,15 @@ enable_auto_exposure (Enable Automatic Exposure) bool false
|
||||||
# Requires: shaders, enable_post_processing, enable_auto_exposure
|
# Requires: shaders, enable_post_processing, enable_auto_exposure
|
||||||
exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0
|
exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0
|
||||||
|
|
||||||
# Set the gamma value.
|
# Set the post processing gamma value.
|
||||||
# Higher values give lower contrast and vice versa.
|
# Higher values give lower contrast and vice versa.
|
||||||
# Range: from 1.0 to 5.0
|
# Range: from 1.0 to 5.0
|
||||||
|
# Default: 1.6
|
||||||
#
|
#
|
||||||
# Requires: shaders, enable_post_processing, tone_mapping
|
# Requires: shaders, enable_post_processing, tone_mapping
|
||||||
gamma (Gamma) float 1.6 1.0 5.0
|
gamma (Gamma) float 1.6 1.0 5.0
|
||||||
|
|
||||||
# Apply color grading to make brighter colors warmer and darker colors cooler.
|
# Apply ASL CDL color grading to make brighter colors warmer and darker colors cooler.
|
||||||
#
|
#
|
||||||
# Requires: shaders, enable_post_processing
|
# Requires: shaders, enable_post_processing
|
||||||
enable_color_grading (Color grading) bool false
|
enable_color_grading (Color grading) bool false
|
||||||
|
@ -674,10 +675,28 @@ bloom_strength_factor (Bloom Strength Factor) float 1.0 0.1 10.0
|
||||||
# Requires: shaders, enable_post_processing, enable_bloom
|
# Requires: shaders, enable_post_processing, enable_bloom
|
||||||
bloom_radius (Bloom Radius) float 1 0.1 8
|
bloom_radius (Bloom Radius) float 1 0.1 8
|
||||||
|
|
||||||
|
[**Volumetric Effects]
|
||||||
|
|
||||||
# Set to true to enable volumetric lighting effect (a.k.a. "Godrays").
|
# Set to true to enable volumetric lighting effect (a.k.a. "Godrays").
|
||||||
#
|
#
|
||||||
# Requires: shaders, enable_post_processing, enable_bloom
|
# Requires: shaders, enable_post_processing, enable_bloom
|
||||||
enable_volumetric_lighting (Volumetric lighting) bool false
|
enable_volumetric_lighting (Volumetric Lighting) bool false
|
||||||
|
|
||||||
|
# Set to true to render clouds as scatter volumes.
|
||||||
|
#
|
||||||
|
# Requires: shaders, enable_post_processing, enable_clouds
|
||||||
|
enable_volumetric_clouds (Volumetric Clouds) bool false
|
||||||
|
|
||||||
|
# Higher values reduce visual quality and may introduce artifacts, but improve performance of volumetric cloud/aurora effects.
|
||||||
|
# Range: from 1 to 4, default: 2
|
||||||
|
#
|
||||||
|
# Requires: shaders, enable_post_processing
|
||||||
|
volumetrics_undersampling (Volumetric Undersampling) int 2 1 4
|
||||||
|
|
||||||
|
# Set to true to render volumetric auroras ("Northern Lights").
|
||||||
|
#
|
||||||
|
# Requires: shaders, enable_post_processing
|
||||||
|
enable_volumetric_auroras (Volumetric Auroras) bool false
|
||||||
|
|
||||||
[**Other Effects]
|
[**Other Effects]
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,49 @@
|
||||||
#define cloudsTexture texture0
|
#define cloudsTexture texture0
|
||||||
#define sceneTexture texture1
|
#define sceneTexture texture1
|
||||||
|
#define depthmap texture2
|
||||||
|
|
||||||
uniform sampler2D cloudsTexture;
|
uniform sampler2D cloudsTexture;
|
||||||
uniform sampler2D sceneTexture;
|
uniform sampler2D sceneTexture;
|
||||||
|
uniform sampler2D depthmap;
|
||||||
uniform vec2 texelSize0;
|
uniform vec2 texelSize0;
|
||||||
|
|
||||||
uniform vec3 dayLight;
|
uniform vec3 dayLight;
|
||||||
|
uniform vec3 cloudColor;
|
||||||
|
|
||||||
varying vec2 screenspaceCoordinate;
|
varying vec2 screenspaceCoordinate;
|
||||||
|
varying vec3 relativePosition;
|
||||||
|
varying vec3 viewDirection;
|
||||||
|
varying vec3 sunTint;
|
||||||
|
varying float auroraFactor;
|
||||||
|
|
||||||
|
uniform vec3 cameraOffset;
|
||||||
|
uniform vec3 cameraPosition;
|
||||||
|
|
||||||
|
uniform float cameraNear;
|
||||||
|
uniform float cameraFar;
|
||||||
|
|
||||||
|
uniform float cloudHeight;
|
||||||
|
uniform float cloudThickness;
|
||||||
|
|
||||||
|
float getDepth(vec2 screenspacePosition) {
|
||||||
|
float depth = texture2D(depthmap, screenspacePosition * 0.5 + 0.5).r;
|
||||||
|
return cameraNear * cameraFar / (cameraFar + depth * (cameraNear - cameraFar));
|
||||||
|
}
|
||||||
|
|
||||||
vec4 sampleClouds(vec2 uv) {
|
vec4 sampleClouds(vec2 uv) {
|
||||||
vec4 cloudsKey = texture2D(cloudsTexture, uv);
|
vec4 cloudsKey = texture2D(cloudsTexture, uv);
|
||||||
|
|
||||||
const vec3 darkColor = vec3(0.05, 0.1, 0.2);
|
//const vec3 darkColor = vec3(0.05, 0.1, 0.2);
|
||||||
|
vec3 darkColor = vec3(0.2, 0.4, 0.8) * dayLight;
|
||||||
const vec3 auroraDark = vec3(0., 0.5, 0.5);
|
const vec3 auroraDark = vec3(0., 0.5, 0.5);
|
||||||
const vec3 auroraBright = vec3(0., 0.5, .0);
|
const vec3 auroraBright = vec3(0., 0.5, .0);
|
||||||
|
|
||||||
|
//const vec3 auroraDark = vec3(0.);
|
||||||
|
//const vec3 auroraBright = vec3(0.);
|
||||||
|
|
||||||
return vec4(
|
return vec4(
|
||||||
mix(auroraDark, auroraBright, cloudsKey.b) * cloudsKey.b * max(0., 1. - cloudsKey.r) +
|
mix(auroraDark, auroraBright, cloudsKey.b) * cloudsKey.b * auroraFactor +
|
||||||
cloudsKey.r * (darkColor * max(0., 1. - cloudsKey.g) + dayLight * cloudsKey.g),
|
cloudsKey.r * cloudColor * (darkColor * max(0., 1. - cloudsKey.g) + dayLight * sunTint * cloudsKey.g),
|
||||||
cloudsKey.r);
|
cloudsKey.r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +62,22 @@ vec4 getClouds(vec2 uv) {
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
vec4 cloudsColor = getClouds(screenspaceCoordinate * 0.5 + 0.5);
|
vec3 viewVec = normalize(relativePosition);
|
||||||
|
|
||||||
|
vec3 position = cameraOffset + cameraPosition;
|
||||||
|
|
||||||
|
float depth = getDepth(screenspaceCoordinate) / normalize(viewDirection).z;
|
||||||
|
float bottomPlaneIntersect = max((cloudHeight - cameraPosition.y) / viewVec.y, 0.);
|
||||||
|
float topPlaneIntersect = max((cloudHeight + cloudThickness - cameraPosition.y) / viewVec.y, 0.);
|
||||||
|
float minPlane = min(bottomPlaneIntersect, topPlaneIntersect);
|
||||||
|
|
||||||
vec4 sceneColor = texture2D(sceneTexture, screenspaceCoordinate * 0.5 + 0.5);
|
vec4 sceneColor = texture2D(sceneTexture, screenspaceCoordinate * 0.5 + 0.5);
|
||||||
|
|
||||||
gl_FragColor = vec4(sceneColor.rgb * (1. - cloudsColor.a) + cloudsColor.rgb, 1.);
|
if (depth > minPlane) {
|
||||||
|
vec4 finalColor = getClouds(screenspaceCoordinate * 0.5 + 0.5);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(sceneColor.rgb * (1. - finalColor.a) + finalColor.rgb, 1.);
|
||||||
|
} else {
|
||||||
|
gl_FragColor = sceneColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,48 @@
|
||||||
|
uniform mat4 mCameraProjInv;
|
||||||
|
uniform mat4 mCameraView;
|
||||||
|
uniform vec3 v_LightDirection;
|
||||||
|
uniform float f_timeofday;
|
||||||
|
|
||||||
|
varying vec3 relativePosition;
|
||||||
|
varying vec3 viewDirection;
|
||||||
varying vec2 screenspaceCoordinate;
|
varying vec2 screenspaceCoordinate;
|
||||||
|
varying vec3 sunTint;
|
||||||
|
varying float auroraFactor;
|
||||||
|
|
||||||
|
vec3 getDirectLightScatteringAtGround(vec3 v_LightDirection)
|
||||||
|
{
|
||||||
|
// Based on talk at 2002 Game Developers Conference by Naty Hoffman and Arcot J. Preetham
|
||||||
|
const float beta_r0 = 1e-5; // Rayleigh scattering beta
|
||||||
|
|
||||||
|
// These factors are calculated based on expected value of scattering factor of 1e-5
|
||||||
|
// for Nitrogen at 532nm (green), 2e25 molecules/m3 in atmosphere
|
||||||
|
const vec3 beta_r0_l = vec3(3.3362176e-01, 8.75378289198826e-01, 1.95342379700656) * beta_r0; // wavelength-dependent scattering
|
||||||
|
|
||||||
|
const float atmosphere_height = 15000.; // height of the atmosphere in meters
|
||||||
|
// sun/moon light at the ground level, after going through the atmosphere
|
||||||
|
return exp(-beta_r0_l * atmosphere_height / (1e-5 - dot(v_LightDirection, vec3(0., 1., 0.))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
|
vec4 p = mCameraProjInv * inVertexPosition;
|
||||||
|
viewDirection = p.xyz / p.w;
|
||||||
|
relativePosition = (p.xyz / p.w) * mat3(mCameraView);
|
||||||
screenspaceCoordinate = inVertexPosition.xy;
|
screenspaceCoordinate = inVertexPosition.xy;
|
||||||
|
|
||||||
|
auroraFactor = 1. - mtsmoothstep(0.13, 0.15, f_timeofday) * mtsmoothstep(0.87, 0.85, f_timeofday);
|
||||||
|
|
||||||
|
float tintFactor = mtsmoothstep(0.21, 0.24, f_timeofday) * mtsmoothstep(0.793, 0.753, f_timeofday);
|
||||||
|
|
||||||
|
sunTint = mix(vec3(1.0), getDirectLightScatteringAtGround(v_LightDirection), tintFactor);
|
||||||
|
|
||||||
gl_Position = inVertexPosition;
|
gl_Position = inVertexPosition;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
uniform float cloudDensity;
|
|
||||||
|
|
||||||
// Pseudorandom number generator
|
|
||||||
float rand(vec2 n) {
|
|
||||||
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
|
|
||||||
}
|
|
||||||
|
|
||||||
// More random pseudorandom number generator;
|
|
||||||
float noise(vec2 p){
|
|
||||||
vec2 p2 = p + vec2(rand(p), rand(p.yx));
|
|
||||||
return rand(p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
gl_FragColor = vec4(vec3(step(noise(floor(gl_FragCoord.xy * 0.25)), cloudDensity)), 1.);
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
gl_Position = inVertexPosition;
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// Pseudorandom number generator
|
|
||||||
float rand(vec2 n) {
|
|
||||||
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
|
|
||||||
}
|
|
||||||
|
|
||||||
// More random pseudorandom number generator;
|
|
||||||
float noise(vec2 p){
|
|
||||||
vec2 p2 = p + vec2(rand(p), rand(p.yx));
|
|
||||||
return rand(p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
gl_FragColor = vec4(vec3(noise(gl_FragCoord.xy)), 1.);
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
gl_Position = inVertexPosition;
|
|
||||||
}
|
|
|
@ -2,10 +2,13 @@
|
||||||
#define noiseTexture texture1
|
#define noiseTexture texture1
|
||||||
#define noiseTextureCoarse texture2
|
#define noiseTextureCoarse texture2
|
||||||
|
|
||||||
|
#define PROBING_ITERATIONS 30
|
||||||
#define ITERATIONS 50
|
#define ITERATIONS 50
|
||||||
#define LIGHT_ITERATIONS 10
|
#define LIGHT_ITERATIONS 3
|
||||||
#define LIGHT_DISTANCE 100.
|
#define AURORA_ITERATIONS 80
|
||||||
#define AURORA_ITERATIONS 100
|
|
||||||
|
// See clouds.cpp
|
||||||
|
#define CLOUD_SIZE 640.0
|
||||||
|
|
||||||
uniform sampler2D depthmap;
|
uniform sampler2D depthmap;
|
||||||
uniform sampler2D noiseTexture;
|
uniform sampler2D noiseTexture;
|
||||||
|
@ -19,17 +22,17 @@ uniform float cloudDensity;
|
||||||
|
|
||||||
varying vec3 relativePosition;
|
varying vec3 relativePosition;
|
||||||
varying vec3 viewDirection;
|
varying vec3 viewDirection;
|
||||||
uniform vec3 eyePosition;
|
|
||||||
uniform vec3 cameraOffset;
|
uniform vec3 cameraOffset;
|
||||||
uniform vec3 cameraPosition;
|
uniform vec3 cameraPosition;
|
||||||
|
|
||||||
uniform mat4 mCameraView;
|
|
||||||
uniform mat4 mCameraProjInv;
|
|
||||||
|
|
||||||
uniform float cameraNear;
|
uniform float cameraNear;
|
||||||
uniform float cameraFar;
|
uniform float cameraFar;
|
||||||
|
|
||||||
|
uniform vec2 cloudOffset;
|
||||||
|
uniform float cloudRadius;
|
||||||
|
|
||||||
varying vec2 screenspaceCoordinate;
|
varying vec2 screenspaceCoordinate;
|
||||||
|
varying float sunStrength;
|
||||||
|
|
||||||
uniform float fogDistance;
|
uniform float fogDistance;
|
||||||
uniform float fogShadingParameter;
|
uniform float fogShadingParameter;
|
||||||
|
@ -41,7 +44,8 @@ uniform float animationTimer;
|
||||||
// Derived From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
|
// Derived From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
|
||||||
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
|
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
|
||||||
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
|
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
|
||||||
float screenSpaceDither(highp vec2 frag_coord) {
|
float screenSpaceDither(highp vec2 frag_coord)
|
||||||
|
{
|
||||||
// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR.
|
// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR.
|
||||||
highp float dither = dot(vec2(171.0, 231.0), frag_coord);
|
highp float dither = dot(vec2(171.0, 231.0), frag_coord);
|
||||||
dither = fract(dither / 103.0);
|
dither = fract(dither / 103.0);
|
||||||
|
@ -57,38 +61,47 @@ float mtsmoothstep(in float edge0, in float edge1, in float x)
|
||||||
return t * t * (3.0 - 2.0 * t);
|
return t * t * (3.0 - 2.0 * t);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getDepth(vec2 screenspacePosition) {
|
float toLinearDepth(float depth)
|
||||||
float depth = texture2D(depthmap, screenspacePosition * 0.5 + 0.5).r;
|
{
|
||||||
return cameraNear * cameraFar / (cameraFar + depth * (cameraNear - cameraFar));
|
return cameraNear * cameraFar / (cameraFar + depth * (cameraNear - cameraFar));
|
||||||
}
|
}
|
||||||
|
|
||||||
float getRawDepth(vec2 screenspacePosition) {
|
float getDepth(vec2 screenspacePosition)
|
||||||
|
{
|
||||||
return texture2D(depthmap, screenspacePosition * 0.5 + 0.5).r;
|
return texture2D(depthmap, screenspacePosition * 0.5 + 0.5).r;
|
||||||
}
|
}
|
||||||
|
|
||||||
float noise(vec3 p){
|
float noise(vec3 p)
|
||||||
//p.y *= 1.;
|
{
|
||||||
float y = floor(p.y);
|
float y = floor(p.y);
|
||||||
float f1 = texture2D(noiseTexture, p.xz / 256. + y * 0.2).r;
|
float f1 = texture2D(noiseTexture, p.xz / 256. + y * 0.2).r;
|
||||||
float f2 = texture2D(noiseTexture, p.xz / 256. + y * 0.2 + 0.2).r;
|
float f2 = texture2D(noiseTexture, p.xz / 256. + y * 0.2 + 0.2).r;
|
||||||
return mix(f1, f2, fract(p.y));
|
return mix(f1, f2, fract(p.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
float fnoise(vec3 p) {
|
float fnoise(vec3 p)
|
||||||
|
{
|
||||||
return noise(p * 4.) * 0.5 + noise(p * 8.) * 0.25;
|
return noise(p * 4.) * 0.5 + noise(p * 8.) * 0.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fnoise3(vec3 p) {
|
float fnoise3(vec3 p)
|
||||||
|
{
|
||||||
return noise(p * 4.) * 0.5 + noise(p * 8.) * 0.25 + noise(p * 16.) * 0.125;
|
return noise(p * 4.) * 0.5 + noise(p * 8.) * 0.25 + noise(p * 16.) * 0.125;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getAuroraDensity(vec3 position) {
|
float getAuroraDensity(vec3 position)
|
||||||
|
{
|
||||||
float density = pow(max(0., 1. - 10. * abs(fnoise3(vec3(position.x * 0.25, animationTimer, position.z * 0.25)) - 0.5)), 4.);
|
float density = pow(max(0., 1. - 10. * abs(fnoise3(vec3(position.x * 0.25, animationTimer, position.z * 0.25)) - 0.5)), 4.);
|
||||||
return 1.0 * density * mtsmoothstep(0.0, 0.05, position.y - 1.) * pow(1. - mtsmoothstep(0.05, 2.0, position.y - 1.), 4.);
|
return 0.7 * density * mtsmoothstep(0.0, 0.05, position.y - 1.) * pow(1. - mtsmoothstep(0.05, 2.0, position.y - 1.), 4.);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getDensity(vec3 position) {
|
float getCoarse(vec3 position) {
|
||||||
float density = texture2D(noiseTextureCoarse, position.xz / 2560. / 16.).r *
|
return texture2D(noiseTextureCoarse, (position.xz - cloudOffset) * 0.5 / CLOUD_SIZE / cloudRadius).r;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getDensity(vec3 position)
|
||||||
|
{
|
||||||
|
float density = texture2D(noiseTextureCoarse, (position.xz - cloudOffset) * 0.5 / CLOUD_SIZE / cloudRadius).r *
|
||||||
mtsmoothstep(0.0, cloudThickness * 0.2, position.y - cloudHeight) *
|
mtsmoothstep(0.0, cloudThickness * 0.2, position.y - cloudHeight) *
|
||||||
(1.0 - mtsmoothstep(cloudThickness * 0.5, cloudThickness, position.y - cloudHeight));
|
(1.0 - mtsmoothstep(cloudThickness * 0.5, cloudThickness, position.y - cloudHeight));
|
||||||
|
|
||||||
|
@ -97,17 +110,19 @@ float getDensity(vec3 position) {
|
||||||
return 0.04 * density;
|
return 0.04 * density;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getBrightness(vec3 position, float bias) {
|
float getBrightness(vec3 position, float lightDistance)
|
||||||
|
{
|
||||||
float density = 0.;
|
float density = 0.;
|
||||||
for (int i = 0; i < LIGHT_ITERATIONS; i++) {
|
for (int i = 1; i <= LIGHT_ITERATIONS; i++) {
|
||||||
vec3 rayPosition = position - v_LightDirection * LIGHT_DISTANCE * (float(i) + bias) / float(LIGHT_ITERATIONS);
|
vec3 rayPosition = position - v_LightDirection * lightDistance * float(i) / float(LIGHT_ITERATIONS);
|
||||||
|
|
||||||
density += getDensity(rayPosition) * float(LIGHT_DISTANCE) / float(LIGHT_ITERATIONS);
|
density += getDensity(rayPosition) * float(lightDistance) / float(LIGHT_ITERATIONS);
|
||||||
}
|
}
|
||||||
return exp(-density);
|
return exp(-density);
|
||||||
}
|
}
|
||||||
|
|
||||||
float blend(float A, float B, float alphaA, float alphaB) {
|
float blend(float A, float B, float alphaA, float alphaB)
|
||||||
|
{
|
||||||
float alphaC = alphaA + (1. - alphaA) * alphaB;
|
float alphaC = alphaA + (1. - alphaA) * alphaB;
|
||||||
return (alphaA * A + (1. - alphaA) * alphaB * B) / alphaC;
|
return (alphaA * A + (1. - alphaA) * alphaB * B) / alphaC;
|
||||||
}
|
}
|
||||||
|
@ -116,11 +131,16 @@ void main(void)
|
||||||
{
|
{
|
||||||
vec3 viewVec = normalize(relativePosition);
|
vec3 viewVec = normalize(relativePosition);
|
||||||
|
|
||||||
vec3 position = cameraOffset + eyePosition;
|
vec3 position = cameraOffset + cameraPosition;
|
||||||
|
|
||||||
float depth = getDepth(screenspaceCoordinate) / normalize(viewDirection).z;
|
float depth = toLinearDepth(getDepth(screenspaceCoordinate)) / normalize(viewDirection).z;
|
||||||
float bottomPlaneIntersect = clamp(min((cloudHeight - eyePosition.y) / viewVec.y, depth), 0., 4. * fogDistance);
|
float bottomPlaneIntersect = clamp((cloudHeight - cameraPosition.y) / viewVec.y, 0., 4. * fogDistance);
|
||||||
float topPlaneIntersect = clamp(min((cloudHeight + cloudThickness - eyePosition.y) / viewVec.y, depth), 0., 4. * fogDistance);
|
float topPlaneIntersect = clamp((cloudHeight + cloudThickness - cameraPosition.y) / viewVec.y, 0., 4. * fogDistance);
|
||||||
|
|
||||||
|
if ((bottomPlaneIntersect > depth + 5.0) != (topPlaneIntersect > depth + 5.0)) {
|
||||||
|
bottomPlaneIntersect = min(depth, bottomPlaneIntersect);
|
||||||
|
topPlaneIntersect = min(depth, topPlaneIntersect);
|
||||||
|
}
|
||||||
|
|
||||||
float startDepth = min(bottomPlaneIntersect, topPlaneIntersect);
|
float startDepth = min(bottomPlaneIntersect, topPlaneIntersect);
|
||||||
float endDepth = max(bottomPlaneIntersect, topPlaneIntersect);
|
float endDepth = max(bottomPlaneIntersect, topPlaneIntersect);
|
||||||
|
@ -129,17 +149,15 @@ void main(void)
|
||||||
|
|
||||||
vec3 color = vec3(0.);
|
vec3 color = vec3(0.);
|
||||||
|
|
||||||
float dx = (endDepth - startDepth) / float(ITERATIONS);
|
|
||||||
|
|
||||||
float density = 0.;
|
float density = 0.;
|
||||||
|
|
||||||
float auroraStartDepth = min(max(0., 1.0 / viewVec.y), 8.);
|
float auroraStartDepth = min(max(0., 1.0 / viewVec.y), 8.);
|
||||||
float auroraEndDepth = min(max(0., 3.0 / viewVec.y), 8.);
|
float auroraEndDepth = min(max(0., 3.0 / viewVec.y), 8.);
|
||||||
float rawDepth = getRawDepth(screenspaceCoordinate);
|
float rawDepth = getDepth(screenspaceCoordinate);
|
||||||
|
|
||||||
if (auroraEndDepth - auroraStartDepth > 0.1 && rawDepth >= 1.0) {
|
if (auroraEndDepth - auroraStartDepth > 0.1 && rawDepth >= 1.0) {
|
||||||
for (int i = 0; i < ITERATIONS; i++) {
|
for (int i = 0; i < AURORA_ITERATIONS; i++) {
|
||||||
vec3 rayPosition = viewVec * (auroraStartDepth + (auroraEndDepth - auroraStartDepth) * (float(i) + bias) / float(ITERATIONS));
|
vec3 rayPosition = viewVec * (auroraStartDepth + (auroraEndDepth - auroraStartDepth) * (float(i) + bias) / float(AURORA_ITERATIONS));
|
||||||
|
|
||||||
float localDensity = getAuroraDensity(rayPosition);
|
float localDensity = getAuroraDensity(rayPosition);
|
||||||
|
|
||||||
|
@ -154,17 +172,26 @@ void main(void)
|
||||||
float sunlightContribution = 0.;
|
float sunlightContribution = 0.;
|
||||||
float alpha = 0.;
|
float alpha = 0.;
|
||||||
float outScatter = 2. * (dot(v_LightDirection, viewVec) * 0.5 + 0.5);
|
float outScatter = 2. * (dot(v_LightDirection, viewVec) * 0.5 + 0.5);
|
||||||
|
float forwardScatter = 1. + 2. * pow(min(dot(v_LightDirection, viewVec), 0.), 4.);
|
||||||
density = 0.;
|
density = 0.;
|
||||||
|
|
||||||
|
float fogDepth = min(4. * fogDistance, startDepth + 2000.);
|
||||||
|
endDepth = min(endDepth, fogDepth);
|
||||||
|
|
||||||
|
float dx = (endDepth - startDepth) / float(ITERATIONS);
|
||||||
|
float lightDistance = cloudThickness * 0.5;
|
||||||
|
|
||||||
|
if (endDepth - startDepth > 0.1) {
|
||||||
for (int i = 0; i < ITERATIONS; i++) {
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
vec3 rayPosition = eyePosition + viewVec * (startDepth + (endDepth - startDepth) * (float(i) + bias) / float(ITERATIONS));
|
vec3 rayPosition = cameraPosition + viewVec * (startDepth + (endDepth - startDepth) * (float(i) + bias) / float(ITERATIONS));
|
||||||
|
|
||||||
float localDensity = getDensity(rayPosition) * dx;
|
float localDensity = getDensity(rayPosition) * dx;
|
||||||
|
|
||||||
if (localDensity < 0.0001) continue;
|
if (localDensity < 0.0001) continue;
|
||||||
|
|
||||||
float clarity = clamp(fogShadingParameter - fogShadingParameter * length(rayPosition - eyePosition) / (4. * fogDistance), 0.0, 1.0);
|
float clarity = clamp(fogShadingParameter - fogShadingParameter * length(rayPosition - cameraPosition) / (fogDepth), 0.0, 1.0);
|
||||||
float brightness = getBrightness(rayPosition, bias) * exp(-outScatter * localDensity);
|
float outScatterContribution = exp(-0.5 * outScatter * localDensity);
|
||||||
|
float brightness = getBrightness(rayPosition, lightDistance) * forwardScatter * outScatterContribution * sunStrength + (1. - outScatterContribution);
|
||||||
sunlightContribution = blend(sunlightContribution, brightness, 1. - exp(-density), 1. - exp(-localDensity));
|
sunlightContribution = blend(sunlightContribution, brightness, 1. - exp(-density), 1. - exp(-localDensity));
|
||||||
alpha = blend(alpha, clarity, 1. - exp(-density), 1. - exp(-localDensity));
|
alpha = blend(alpha, clarity, 1. - exp(-density), 1. - exp(-localDensity));
|
||||||
|
|
||||||
|
@ -172,11 +199,11 @@ void main(void)
|
||||||
|
|
||||||
if (density > 10.0) break;
|
if (density > 10.0) break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
float forwardScatter = 1. + 4. * pow(min(dot(v_LightDirection, viewVec), 0.), 4.);
|
|
||||||
|
|
||||||
color.r = (1. - exp(-density)) * alpha;
|
color.r = (1. - exp(-density)) * alpha;
|
||||||
color.g = sunlightContribution * forwardScatter;
|
color.g = sunlightContribution;
|
||||||
|
color.b *= exp(-density);
|
||||||
|
|
||||||
gl_FragColor = vec4(color, 1.0);
|
gl_FragColor = vec4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
uniform mat4 mCameraProjInv;
|
uniform mat4 mCameraProjInv;
|
||||||
uniform mat4 mCameraView;
|
uniform mat4 mCameraView;
|
||||||
uniform vec3 eyePosition;
|
uniform float f_timeofday;
|
||||||
|
|
||||||
varying vec3 relativePosition;
|
varying vec3 relativePosition;
|
||||||
varying vec3 viewDirection;
|
varying vec3 viewDirection;
|
||||||
|
|
||||||
varying vec2 screenspaceCoordinate;
|
varying vec2 screenspaceCoordinate;
|
||||||
|
varying float sunStrength;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
|
@ -13,5 +20,18 @@ void main(void)
|
||||||
vec4 p = mCameraProjInv * inVertexPosition;
|
vec4 p = mCameraProjInv * inVertexPosition;
|
||||||
viewDirection = p.xyz / p.w;
|
viewDirection = p.xyz / p.w;
|
||||||
relativePosition = (p.xyz / p.w) * mat3(mCameraView);
|
relativePosition = (p.xyz / p.w) * mat3(mCameraView);
|
||||||
|
|
||||||
|
if (f_timeofday < 0.21) {
|
||||||
|
sunStrength =
|
||||||
|
(1.0 - mtsmoothstep(0.18, 0.21, f_timeofday));
|
||||||
|
} else if (f_timeofday >= 0.793) {
|
||||||
|
sunStrength =
|
||||||
|
mtsmoothstep(0.793, 0.823, f_timeofday);
|
||||||
|
} else {
|
||||||
|
sunStrength =
|
||||||
|
mtsmoothstep(0.21, 0.26, f_timeofday) *
|
||||||
|
(1.0 - mtsmoothstep(0.743, 0.793, f_timeofday));
|
||||||
|
}
|
||||||
|
|
||||||
gl_Position = inVertexPosition;
|
gl_Position = inVertexPosition;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc,
|
||||||
s32 id,
|
s32 id,
|
||||||
u32 seed
|
u32 seed
|
||||||
):
|
):
|
||||||
scene::ISceneNode(mgr->getRootSceneNode(), mgr, id),
|
scene::ISceneNode(g_settings->getBool("enable_volumetric_clouds") ? nullptr : mgr->getRootSceneNode(), mgr, id),
|
||||||
m_seed(seed)
|
m_seed(seed)
|
||||||
{
|
{
|
||||||
m_enable_shaders = g_settings->getBool("enable_shaders");
|
m_enable_shaders = g_settings->getBool("enable_shaders");
|
||||||
|
@ -106,6 +106,14 @@ void Clouds::updateMesh()
|
||||||
std::floor(center_of_drawing_in_noise_f.Y / cloud_size)
|
std::floor(center_of_drawing_in_noise_f.Y / cloud_size)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// The world position of the integer center point of drawing in the noise
|
||||||
|
v2f world_center_of_drawing_in_noise_f = v2f(
|
||||||
|
center_of_drawing_in_noise_i.X * cloud_size,
|
||||||
|
center_of_drawing_in_noise_i.Y * cloud_size
|
||||||
|
) + m_origin;
|
||||||
|
|
||||||
|
m_noise_position = world_center_of_drawing_in_noise_f - ((float)m_cloud_radius_i + 0.5f) * cloud_size;
|
||||||
|
|
||||||
// Only update mesh if it has moved enough, this saves lots of GPU buffer uploads.
|
// Only update mesh if it has moved enough, this saves lots of GPU buffer uploads.
|
||||||
constexpr float max_d = 5 * BS;
|
constexpr float max_d = 5 * BS;
|
||||||
|
|
||||||
|
@ -128,12 +136,6 @@ void Clouds::updateMesh()
|
||||||
|
|
||||||
const u32 num_faces_to_draw = m_enable_3d ? 6 : 1;
|
const u32 num_faces_to_draw = m_enable_3d ? 6 : 1;
|
||||||
|
|
||||||
// The world position of the integer center point of drawing in the noise
|
|
||||||
v2f world_center_of_drawing_in_noise_f = v2f(
|
|
||||||
center_of_drawing_in_noise_i.X * cloud_size,
|
|
||||||
center_of_drawing_in_noise_i.Y * cloud_size
|
|
||||||
) + m_origin;
|
|
||||||
|
|
||||||
// Colors with primitive shading
|
// Colors with primitive shading
|
||||||
|
|
||||||
video::SColorf c_top_f(m_color);
|
video::SColorf c_top_f(m_color);
|
||||||
|
@ -160,7 +162,7 @@ void Clouds::updateMesh()
|
||||||
|
|
||||||
// Read noise
|
// Read noise
|
||||||
|
|
||||||
std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
|
m_grid.resize(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
|
||||||
|
|
||||||
for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
|
for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
|
||||||
u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
|
u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
|
||||||
|
@ -168,7 +170,7 @@ void Clouds::updateMesh()
|
||||||
for (s16 xi = -m_cloud_radius_i; xi < m_cloud_radius_i; xi++) {
|
for (s16 xi = -m_cloud_radius_i; xi < m_cloud_radius_i; xi++) {
|
||||||
u32 i = si + xi;
|
u32 i = si + xi;
|
||||||
|
|
||||||
grid[i] = gridFilled(
|
m_grid[i] = gridFilled(
|
||||||
xi + center_of_drawing_in_noise_i.X,
|
xi + center_of_drawing_in_noise_i.X,
|
||||||
zi + center_of_drawing_in_noise_i.Y
|
zi + center_of_drawing_in_noise_i.Y
|
||||||
);
|
);
|
||||||
|
@ -205,7 +207,7 @@ void Clouds::updateMesh()
|
||||||
|
|
||||||
u32 i = GETINDEX(xi, zi, m_cloud_radius_i);
|
u32 i = GETINDEX(xi, zi, m_cloud_radius_i);
|
||||||
|
|
||||||
if (!grid[i])
|
if (!m_grid[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
v2f p0 = v2f(xi,zi)*cloud_size + world_center_of_drawing_in_noise_f;
|
v2f p0 = v2f(xi,zi)*cloud_size + world_center_of_drawing_in_noise_f;
|
||||||
|
@ -238,7 +240,7 @@ void Clouds::updateMesh()
|
||||||
case 1: // back
|
case 1: // back
|
||||||
if (INAREA(xi, zi - 1, m_cloud_radius_i)) {
|
if (INAREA(xi, zi - 1, m_cloud_radius_i)) {
|
||||||
u32 j = GETINDEX(xi, zi - 1, m_cloud_radius_i);
|
u32 j = GETINDEX(xi, zi - 1, m_cloud_radius_i);
|
||||||
if(grid[j])
|
if(m_grid[j])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (video::S3DVertex &vertex : v) {
|
for (video::S3DVertex &vertex : v) {
|
||||||
|
@ -253,7 +255,7 @@ void Clouds::updateMesh()
|
||||||
case 2: //right
|
case 2: //right
|
||||||
if (INAREA(xi + 1, zi, m_cloud_radius_i)) {
|
if (INAREA(xi + 1, zi, m_cloud_radius_i)) {
|
||||||
u32 j = GETINDEX(xi+1, zi, m_cloud_radius_i);
|
u32 j = GETINDEX(xi+1, zi, m_cloud_radius_i);
|
||||||
if(grid[j])
|
if(m_grid[j])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (video::S3DVertex &vertex : v) {
|
for (video::S3DVertex &vertex : v) {
|
||||||
|
@ -268,7 +270,7 @@ void Clouds::updateMesh()
|
||||||
case 3: // front
|
case 3: // front
|
||||||
if (INAREA(xi, zi + 1, m_cloud_radius_i)) {
|
if (INAREA(xi, zi + 1, m_cloud_radius_i)) {
|
||||||
u32 j = GETINDEX(xi, zi + 1, m_cloud_radius_i);
|
u32 j = GETINDEX(xi, zi + 1, m_cloud_radius_i);
|
||||||
if(grid[j])
|
if(m_grid[j])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (video::S3DVertex &vertex : v) {
|
for (video::S3DVertex &vertex : v) {
|
||||||
|
@ -283,7 +285,7 @@ void Clouds::updateMesh()
|
||||||
case 4: // left
|
case 4: // left
|
||||||
if (INAREA(xi-1, zi, m_cloud_radius_i)) {
|
if (INAREA(xi-1, zi, m_cloud_radius_i)) {
|
||||||
u32 j = GETINDEX(xi-1, zi, m_cloud_radius_i);
|
u32 j = GETINDEX(xi-1, zi, m_cloud_radius_i);
|
||||||
if(grid[j])
|
if(m_grid[j])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (video::S3DVertex &vertex : v) {
|
for (video::S3DVertex &vertex : v) {
|
||||||
|
@ -343,7 +345,6 @@ void Clouds::updateMesh()
|
||||||
|
|
||||||
void Clouds::render()
|
void Clouds::render()
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
if (m_params.density <= 0.0f)
|
if (m_params.density <= 0.0f)
|
||||||
return; // no need to do anything
|
return; // no need to do anything
|
||||||
|
|
||||||
|
@ -389,12 +390,38 @@ void Clouds::render()
|
||||||
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
|
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#if 0
|
||||||
driver->drawMeshBuffer(m_meshbuffer.get());
|
driver->drawMeshBuffer(m_meshbuffer.get());
|
||||||
|
//#endif
|
||||||
// Restore fog settings
|
// Restore fog settings
|
||||||
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||||
fog_pixelfog, fog_rangefog);
|
fog_pixelfog, fog_rangefog);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
void Clouds::renderDepth() {
|
||||||
|
if (m_params.density <= 0.0f)
|
||||||
|
return; // no need to do anything
|
||||||
|
|
||||||
|
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||||
|
|
||||||
|
updateMesh();
|
||||||
|
|
||||||
|
// Update position
|
||||||
|
{
|
||||||
|
v2f off_origin = m_origin - m_mesh_origin;
|
||||||
|
v3f rel(off_origin.X, 0, off_origin.Y);
|
||||||
|
rel -= intToFloat(m_camera_offset, BS);
|
||||||
|
setPosition(rel);
|
||||||
|
updateAbsolutePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
video::SMaterial material = m_material;
|
||||||
|
material.MaterialType = video::EMT_SOLID;
|
||||||
|
material.ZWriteEnable = video::EZW_ON;
|
||||||
|
|
||||||
|
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||||
|
driver->setMaterial(material);
|
||||||
|
driver->drawMeshBuffer(m_meshbuffer.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clouds::step(float dtime)
|
void Clouds::step(float dtime)
|
||||||
|
|
|
@ -52,6 +52,8 @@ public:
|
||||||
|
|
||||||
virtual void render();
|
virtual void render();
|
||||||
|
|
||||||
|
void renderDepth();
|
||||||
|
|
||||||
virtual const aabb3f &getBoundingBox() const
|
virtual const aabb3f &getBoundingBox() const
|
||||||
{
|
{
|
||||||
return m_box;
|
return m_box;
|
||||||
|
@ -140,6 +142,16 @@ public:
|
||||||
|
|
||||||
const video::SColor getColor() const { return m_color.toSColor(); }
|
const video::SColor getColor() const { return m_color.toSColor(); }
|
||||||
|
|
||||||
|
bool getGrid(int x, int y)
|
||||||
|
{
|
||||||
|
int index = x + y * m_cloud_radius_i * 2;
|
||||||
|
if (index < 0 || index >= m_grid.size())
|
||||||
|
return false;
|
||||||
|
return m_grid[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
v2f getCloudOffset() const { return m_noise_position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateBox()
|
void updateBox()
|
||||||
{
|
{
|
||||||
|
@ -173,6 +185,7 @@ private:
|
||||||
u16 m_cloud_radius_i;
|
u16 m_cloud_radius_i;
|
||||||
u32 m_seed;
|
u32 m_seed;
|
||||||
v3f m_camera_pos;
|
v3f m_camera_pos;
|
||||||
|
v2f m_noise_position;
|
||||||
|
|
||||||
v3s16 m_camera_offset;
|
v3s16 m_camera_offset;
|
||||||
bool m_camera_inside_cloud = false;
|
bool m_camera_inside_cloud = false;
|
||||||
|
@ -180,4 +193,7 @@ private:
|
||||||
bool m_enable_shaders, m_enable_3d;
|
bool m_enable_shaders, m_enable_3d;
|
||||||
video::SColorf m_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
|
video::SColorf m_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
CloudParams m_params;
|
CloudParams m_params;
|
||||||
|
|
||||||
|
std::vector<bool> m_grid;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -383,11 +383,10 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
||||||
m_animation_timer_delta_pixel{"animationTimerDelta"};
|
m_animation_timer_delta_pixel{"animationTimerDelta"};
|
||||||
CachedPixelShaderSetting<float, 3> m_artificial_light{ "artificialLight" };
|
CachedPixelShaderSetting<float, 3> m_artificial_light{ "artificialLight" };
|
||||||
CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"};
|
CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"};
|
||||||
CachedPixelShaderSetting<float, 3> m_eye_position_pixel{ "eyePosition" };
|
|
||||||
CachedVertexShaderSetting<float, 3> m_eye_position_vertex{ "eyePosition" };
|
|
||||||
CachedPixelShaderSetting<float, 3> m_minimap_yaw{"yawVec"};
|
CachedPixelShaderSetting<float, 3> m_minimap_yaw{"yawVec"};
|
||||||
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel{"cameraOffset"};
|
|
||||||
CachedVertexShaderSetting<float, 3> m_camera_offset_vertex{"cameraOffset"};
|
CachedVertexShaderSetting<float, 3> m_camera_offset_vertex{"cameraOffset"};
|
||||||
|
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel{ "cameraOffset" };
|
||||||
|
CachedVertexShaderSetting<float, 3> m_camera_position_vertex{"cameraPosition"};
|
||||||
CachedPixelShaderSetting<float, 3> m_camera_position_pixel{"cameraPosition"};
|
CachedPixelShaderSetting<float, 3> m_camera_position_pixel{"cameraPosition"};
|
||||||
CachedVertexShaderSetting<float, 16> m_camera_projinv_vertex{"mCameraProjInv"};
|
CachedVertexShaderSetting<float, 16> m_camera_projinv_vertex{"mCameraProjInv"};
|
||||||
CachedPixelShaderSetting<float, 16> m_camera_projinv_pixel{"mCameraProjInv"};
|
CachedPixelShaderSetting<float, 16> m_camera_projinv_pixel{"mCameraProjInv"};
|
||||||
|
@ -420,6 +419,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
||||||
CachedPixelShaderSetting<float> m_cloud_height_pixel{"cloudHeight"};
|
CachedPixelShaderSetting<float> m_cloud_height_pixel{"cloudHeight"};
|
||||||
CachedPixelShaderSetting<float> m_cloud_thickness_pixel{"cloudThickness"};
|
CachedPixelShaderSetting<float> m_cloud_thickness_pixel{"cloudThickness"};
|
||||||
CachedPixelShaderSetting<float> m_cloud_density_pixel{"cloudDensity"};
|
CachedPixelShaderSetting<float> m_cloud_density_pixel{"cloudDensity"};
|
||||||
|
CachedPixelShaderSetting<float, 2> m_cloud_offset_pixel{"cloudOffset"};
|
||||||
|
CachedPixelShaderSetting<float> m_cloud_radius_pixel{"cloudRadius"};
|
||||||
CachedPixelShaderSetting<float> m_saturation_pixel{"saturation"};
|
CachedPixelShaderSetting<float> m_saturation_pixel{"saturation"};
|
||||||
float m_gamma;
|
float m_gamma;
|
||||||
CachedPixelShaderSetting<float> m_gamma_pixel{"gamma"};
|
CachedPixelShaderSetting<float> m_gamma_pixel{"gamma"};
|
||||||
|
@ -432,6 +433,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
||||||
CachedPixelShaderSetting<float> m_moon_brightness_pixel{"moonBrightness"};
|
CachedPixelShaderSetting<float> m_moon_brightness_pixel{"moonBrightness"};
|
||||||
CachedPixelShaderSetting<float>
|
CachedPixelShaderSetting<float>
|
||||||
m_volumetric_light_strength_pixel{"volumetricLightStrength"};
|
m_volumetric_light_strength_pixel{"volumetricLightStrength"};
|
||||||
|
CachedPixelShaderSetting<float, 3>
|
||||||
|
m_volumetric_cloud_color{"cloudColor"};
|
||||||
|
|
||||||
static constexpr std::array<const char*, 5> SETTING_CALLBACKS = {
|
static constexpr std::array<const char*, 5> SETTING_CALLBACKS = {
|
||||||
"exposure_compensation",
|
"exposure_compensation",
|
||||||
|
@ -501,20 +504,17 @@ public:
|
||||||
m_animation_timer_delta_vertex.set(&animation_timer_delta_f, services);
|
m_animation_timer_delta_vertex.set(&animation_timer_delta_f, services);
|
||||||
m_animation_timer_delta_pixel.set(&animation_timer_delta_f, services);
|
m_animation_timer_delta_pixel.set(&animation_timer_delta_f, services);
|
||||||
|
|
||||||
v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
|
|
||||||
m_eye_position_pixel.set(epos, services);
|
|
||||||
m_eye_position_vertex.set(epos, services);
|
|
||||||
|
|
||||||
if (m_client->getMinimap()) {
|
if (m_client->getMinimap()) {
|
||||||
v3f minimap_yaw = m_client->getMinimap()->getYawVec();
|
v3f minimap_yaw = m_client->getMinimap()->getYawVec();
|
||||||
m_minimap_yaw.set(minimap_yaw, services);
|
m_minimap_yaw.set(minimap_yaw, services);
|
||||||
}
|
}
|
||||||
|
|
||||||
v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
|
v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
|
||||||
m_camera_offset_pixel.set(offset, services);
|
|
||||||
m_camera_offset_vertex.set(offset, services);
|
m_camera_offset_vertex.set(offset, services);
|
||||||
|
m_camera_offset_pixel.set(offset, services);
|
||||||
|
|
||||||
v3f camera_position = m_client->getCamera()->getPosition();
|
v3f camera_position = m_client->getCamera()->getPosition();
|
||||||
|
m_camera_position_vertex.set(camera_position, services);
|
||||||
m_camera_position_pixel.set(camera_position, services);
|
m_camera_position_pixel.set(camera_position, services);
|
||||||
|
|
||||||
core::matrix4 camera_proj = m_client->getCamera()->getCameraNode()->getProjectionMatrix();
|
core::matrix4 camera_proj = m_client->getCamera()->getCameraNode()->getProjectionMatrix();
|
||||||
|
@ -573,13 +573,19 @@ public:
|
||||||
|
|
||||||
// TODO: settings
|
// TODO: settings
|
||||||
Clouds* clouds = m_client->getClouds();
|
Clouds* clouds = m_client->getClouds();
|
||||||
if (m_client->getClouds()) {
|
if (clouds && g_settings->getBool("enable_volumetric_clouds")) {
|
||||||
float cloud_height = clouds->getHeight() * 10.0f;
|
float cloud_height = clouds->getHeight() * 10.0f;
|
||||||
m_cloud_height_pixel.set(&cloud_height, services);
|
m_cloud_height_pixel.set(&cloud_height, services);
|
||||||
float cloud_thickness = clouds->getThickness() * 10.0f;
|
float cloud_thickness = clouds->getThickness() * 10.0f;
|
||||||
m_cloud_thickness_pixel.set(&cloud_thickness, services);
|
m_cloud_thickness_pixel.set(&cloud_thickness, services);
|
||||||
float cloud_density = clouds->getDensity();
|
float cloud_density = clouds->getDensity();
|
||||||
m_cloud_density_pixel.set(&cloud_density, services);
|
m_cloud_density_pixel.set(&cloud_density, services);
|
||||||
|
v2f cloud_offset = clouds->getCloudOffset();
|
||||||
|
m_cloud_offset_pixel.set(cloud_offset, services);
|
||||||
|
float cloud_radius = g_settings->getU16("cloud_radius");
|
||||||
|
m_cloud_radius_pixel.set(&cloud_radius, services);
|
||||||
|
video::SColor cloud_color = clouds->getColor();
|
||||||
|
m_volumetric_cloud_color.set(cloud_color, services);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_volumetric_light_enabled) {
|
if (m_volumetric_light_enabled) {
|
||||||
|
@ -4294,7 +4300,7 @@ void Game::updateClouds(float dtime)
|
||||||
camera_node_position.Y = camera_node_position.Y + camera_offset.Y * BS;
|
camera_node_position.Y = camera_node_position.Y + camera_offset.Y * BS;
|
||||||
camera_node_position.Z = camera_node_position.Z + camera_offset.Z * BS;
|
camera_node_position.Z = camera_node_position.Z + camera_offset.Z * BS;
|
||||||
this->clouds->update(camera_node_position, this->sky->getCloudColor());
|
this->clouds->update(camera_node_position, this->sky->getCloudColor());
|
||||||
if (this->clouds->isCameraInsideCloud() && this->fogEnabled()) {
|
if (this->clouds->isCameraInsideCloud() && this->fogEnabled() && !g_settings->getBool("enable_volumetric_clouds")) {
|
||||||
// If camera is inside cloud and fog is enabled, use cloud's colors as sky colors.
|
// If camera is inside cloud and fog is enabled, use cloud's colors as sky colors.
|
||||||
video::SColor clouds_dark = this->clouds->getColor().getInterpolated(
|
video::SColor clouds_dark = this->clouds->getColor().getInterpolated(
|
||||||
video::SColor(255, 0, 0, 0), 0.9);
|
video::SColor(255, 0, 0, 0), 0.9);
|
||||||
|
|
|
@ -113,6 +113,18 @@ void TextureBuffer::swapTextures(u8 texture_a, u8 texture_b)
|
||||||
m_textures[texture_b] = temp;
|
m_textures[texture_b] = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureBuffer::setTextureImage(u8 id, video::IImage* image) {
|
||||||
|
assert(m_definitions[id].valid);
|
||||||
|
|
||||||
|
auto &definition = m_definitions[id];
|
||||||
|
|
||||||
|
if (m_textures[id]) m_driver->removeTexture(m_textures[id]);
|
||||||
|
|
||||||
|
m_textures[id] = m_driver->addTexture(definition.name.c_str(), image);
|
||||||
|
definition.fixed_size = true;
|
||||||
|
definition.size = image->getDimension();
|
||||||
|
definition.dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefinition& definition, PipelineContext &context)
|
bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefinition& definition, PipelineContext &context)
|
||||||
{
|
{
|
||||||
|
@ -183,6 +195,8 @@ void TextureBufferOutput::activate(PipelineContext &context)
|
||||||
if (!render_target)
|
if (!render_target)
|
||||||
render_target = driver->addRenderTarget();
|
render_target = driver->addRenderTarget();
|
||||||
|
|
||||||
|
if (disable_clear) m_clear = false;
|
||||||
|
|
||||||
core::array<video::ITexture *> textures;
|
core::array<video::ITexture *> textures;
|
||||||
core::dimension2du size(0, 0);
|
core::dimension2du size(0, 0);
|
||||||
for (size_t i = 0; i < texture_map.size(); i++) {
|
for (size_t i = 0; i < texture_map.size(); i++) {
|
||||||
|
|
|
@ -141,6 +141,7 @@ public:
|
||||||
virtual video::ITexture *getTexture(u8 index) override;
|
virtual video::ITexture *getTexture(u8 index) override;
|
||||||
virtual void reset(PipelineContext &context) override;
|
virtual void reset(PipelineContext &context) override;
|
||||||
void swapTextures(u8 texture_a, u8 texture_b);
|
void swapTextures(u8 texture_a, u8 texture_b);
|
||||||
|
void setTextureImage(u8 id, video::IImage* image);
|
||||||
private:
|
private:
|
||||||
static const u8 NO_DEPTH_TEXTURE = 255;
|
static const u8 NO_DEPTH_TEXTURE = 255;
|
||||||
|
|
||||||
|
@ -182,6 +183,7 @@ public:
|
||||||
TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map, u8 depth_stencil);
|
TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map, u8 depth_stencil);
|
||||||
virtual ~TextureBufferOutput() override;
|
virtual ~TextureBufferOutput() override;
|
||||||
void activate(PipelineContext &context) override;
|
void activate(PipelineContext &context) override;
|
||||||
|
void disableClearing() { disable_clear = true; }
|
||||||
private:
|
private:
|
||||||
static const u8 NO_DEPTH_TEXTURE = 255;
|
static const u8 NO_DEPTH_TEXTURE = 255;
|
||||||
|
|
||||||
|
@ -190,6 +192,7 @@ private:
|
||||||
u8 depth_stencil { NO_DEPTH_TEXTURE };
|
u8 depth_stencil { NO_DEPTH_TEXTURE };
|
||||||
video::IRenderTarget* render_target { nullptr };
|
video::IRenderTarget* render_target { nullptr };
|
||||||
video::IVideoDriver* driver { nullptr };
|
video::IVideoDriver* driver { nullptr };
|
||||||
|
bool disable_clear = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,64 +24,114 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "client/shader.h"
|
#include "client/shader.h"
|
||||||
#include "client/tile.h"
|
#include "client/tile.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "noise.h"
|
||||||
|
|
||||||
class NoiseStep : public RenderStep {
|
class NoiseStep : public RenderStep {
|
||||||
public:
|
public:
|
||||||
NoiseStep(u32 shader_id, u8 texture_id) :
|
NoiseStep(TextureBuffer* buffer, u8 id, u32 size) :
|
||||||
shader_id(shader_id), texture_id(texture_id)
|
buffer(buffer), id(id), size(size)
|
||||||
{
|
{
|
||||||
material.UseMipMaps = false;
|
|
||||||
material.ZBuffer = true;
|
|
||||||
material.ZWriteEnable = video::EZW_ON;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRenderSource(RenderSource* _source) override {
|
void setRenderSource(RenderSource* _source) override {}
|
||||||
source = _source;
|
|
||||||
|
void setRenderTarget(RenderTarget* _target) override {}
|
||||||
|
|
||||||
|
void reset(PipelineContext& context) override {}
|
||||||
|
|
||||||
|
void run(PipelineContext& context) override
|
||||||
|
{
|
||||||
|
if (!needs_run) return;
|
||||||
|
|
||||||
|
needs_run = false;
|
||||||
|
|
||||||
|
video::IImage* noise_image = context.device->getVideoDriver()->createImage(video::ECF_A8R8G8B8, core::dimension2du(256, 256));
|
||||||
|
PseudoRandom random;
|
||||||
|
for (u32 i = 0; i < size * size; ++i) {
|
||||||
|
noise_image->setPixel(i % size, i / size, video::SColor(0, random.next() % 256, 0, 0));
|
||||||
|
}
|
||||||
|
buffer->setTextureImage(id, noise_image);
|
||||||
|
noise_image->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRenderTarget(RenderTarget* _target) override {
|
private:
|
||||||
|
u32 size;
|
||||||
|
u8 id;
|
||||||
|
TextureBuffer* buffer = nullptr;
|
||||||
|
bool needs_run = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CloudDensityStep : public RenderStep {
|
||||||
|
public:
|
||||||
|
CloudDensityStep(TextureBuffer* buffer, u8 id, Clouds* clouds) :
|
||||||
|
buffer(buffer), id(id), clouds(clouds)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRenderSource(RenderSource* _source) override {}
|
||||||
|
|
||||||
|
void setRenderTarget(RenderTarget* _target) override {}
|
||||||
|
|
||||||
|
void reset(PipelineContext& context) override {}
|
||||||
|
|
||||||
|
void run(PipelineContext& context) override
|
||||||
|
{
|
||||||
|
u16 cloud_radius = g_settings->getU16("cloud_radius");
|
||||||
|
if (cloud_radius < 1) cloud_radius = 1;
|
||||||
|
|
||||||
|
video::IImage* image = context.device->getVideoDriver()->createImage(video::ECF_A8R8G8B8, core::dimension2du(8 * cloud_radius, 8 * cloud_radius));
|
||||||
|
|
||||||
|
for (int x = 0; x < 2 * cloud_radius; ++x) {
|
||||||
|
for (int y = 0; y < 2 * cloud_radius; ++y) {
|
||||||
|
bool isFilled = clouds->getGrid(x, y);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
int xp = x * 4 + i % 4;
|
||||||
|
int yp = y * 4 + i / 4;
|
||||||
|
|
||||||
|
image->setPixel(xp, yp, video::SColor(255, isFilled * 255, 0, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->setTextureImage(id, image);
|
||||||
|
|
||||||
|
image->drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Clouds* clouds = nullptr;
|
||||||
|
u8 id = 0;
|
||||||
|
TextureBuffer* buffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CloudDepthStep : public RenderStep {
|
||||||
|
public:
|
||||||
|
CloudDepthStep(Clouds* clouds) :
|
||||||
|
clouds(clouds)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRenderSource(RenderSource* _source) override {}
|
||||||
|
|
||||||
|
void setRenderTarget(RenderTarget* _target) override
|
||||||
|
{
|
||||||
target = _target;
|
target = _target;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset(PipelineContext& context) override {}
|
void reset(PipelineContext& context) override {}
|
||||||
|
|
||||||
void run(PipelineContext& context) override {
|
void run(PipelineContext& context) override
|
||||||
video::ITexture* texture = source->getTexture(texture_id);
|
{
|
||||||
if (texture != last_texture) {
|
|
||||||
last_texture = texture;
|
|
||||||
|
|
||||||
if (target)
|
if (target)
|
||||||
target->activate(context);
|
target->activate(context);
|
||||||
|
|
||||||
// attach the shader
|
clouds->renderDepth();
|
||||||
material.MaterialType = context.client->getShaderSource()->getShaderInfo(shader_id).material;
|
|
||||||
|
|
||||||
auto driver = context.device->getVideoDriver();
|
|
||||||
|
|
||||||
static const video::SColor color = video::SColor(0, 0, 0, 255);
|
|
||||||
static const video::S3DVertex vertices[4] = {
|
|
||||||
video::S3DVertex(1.0, -1.0, 0.0, 0.0, 0.0, -1.0,
|
|
||||||
color, 1.0, 0.0),
|
|
||||||
video::S3DVertex(-1.0, -1.0, 0.0, 0.0, 0.0, -1.0,
|
|
||||||
color, 0.0, 0.0),
|
|
||||||
video::S3DVertex(-1.0, 1.0, 0.0, 0.0, 0.0, -1.0,
|
|
||||||
color, 0.0, 1.0),
|
|
||||||
video::S3DVertex(1.0, 1.0, 0.0, 0.0, 0.0, -1.0,
|
|
||||||
color, 1.0, 1.0),
|
|
||||||
};
|
|
||||||
static const u16 indices[6] = { 0, 1, 2, 2, 3, 0 };
|
|
||||||
driver->setMaterial(material);
|
|
||||||
driver->drawVertexPrimitiveList(&vertices, 4, &indices, 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 shader_id;
|
Clouds* clouds = nullptr;
|
||||||
u8 texture_id;
|
RenderTarget* target = nullptr;
|
||||||
video::SMaterial material;
|
|
||||||
video::ITexture* last_texture = nullptr;
|
|
||||||
RenderSource* source{ nullptr };
|
|
||||||
RenderTarget* target{ nullptr };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_texture_map) :
|
PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_texture_map) :
|
||||||
|
@ -160,6 +210,11 @@ void PostProcessingStep::setWrapRepeat(u8 index, bool value) {
|
||||||
material.TextureLayers[index].TextureWrapV = value ? video::ETC_REPEAT : video::ETC_CLAMP_TO_EDGE;
|
material.TextureLayers[index].TextureWrapV = value ? video::ETC_REPEAT : video::ETC_CLAMP_TO_EDGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PostProcessingStep::disableDepthTest() {
|
||||||
|
material.ZBuffer = video::ECFN_DISABLED;
|
||||||
|
material.ZWriteEnable = video::EZW_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client)
|
RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client)
|
||||||
{
|
{
|
||||||
auto buffer = pipeline->createOwned<TextureBuffer>();
|
auto buffer = pipeline->createOwned<TextureBuffer>();
|
||||||
|
@ -201,8 +256,8 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
||||||
const bool enable_ssaa = antialiasing == "ssaa";
|
const bool enable_ssaa = antialiasing == "ssaa";
|
||||||
const bool enable_fxaa = antialiasing == "fxaa";
|
const bool enable_fxaa = antialiasing == "fxaa";
|
||||||
const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom;
|
const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom;
|
||||||
const bool enable_volumetric_clouds = true;
|
// TODO: Proper constraints
|
||||||
// TODO: Add clouds setting
|
const bool enable_volumetric_clouds = g_settings->getBool("enable_volumetric_clouds") && client->getClouds();
|
||||||
|
|
||||||
if (enable_ssaa) {
|
if (enable_ssaa) {
|
||||||
u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa"));
|
u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa"));
|
||||||
|
@ -227,21 +282,20 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
||||||
|
|
||||||
u8 source = TEXTURE_COLOR;
|
u8 source = TEXTURE_COLOR;
|
||||||
|
|
||||||
|
u8 final_color_source = TEXTURE_COLOR;
|
||||||
|
|
||||||
if (enable_volumetric_clouds) {
|
if (enable_volumetric_clouds) {
|
||||||
|
const u16 cloud_radius = g_settings->getU16("cloud_radius");
|
||||||
|
|
||||||
buffer->setTexture(TEXTURE_NOISE, core::dimension2du(256, 256), "noise", color_format);
|
buffer->setTexture(TEXTURE_NOISE, core::dimension2du(256, 256), "noise", color_format);
|
||||||
|
pipeline->addStep<NoiseStep>(buffer, TEXTURE_NOISE, 256);
|
||||||
|
|
||||||
shader_id = client->getShaderSource()->getShader("noise_shader", TILE_MATERIAL_PLAIN, NDT_MESH);
|
buffer->setTexture(TEXTURE_NOISE_COARSE, core::dimension2du(cloud_radius * 8, cloud_radius * 8), "noise_coarse", color_format);
|
||||||
RenderStep *noise_step = pipeline->addStep<NoiseStep>(shader_id, TEXTURE_NOISE);
|
pipeline->addStep<CloudDensityStep>(buffer, TEXTURE_NOISE_COARSE, client->getClouds());
|
||||||
noise_step->setRenderSource(buffer);
|
|
||||||
noise_step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_NOISE));
|
|
||||||
|
|
||||||
buffer->setTexture(TEXTURE_NOISE_COARSE, core::dimension2du(256, 256), "noise", color_format);
|
u32 undersampling = core::clamp(g_settings->getU32("volumetrics_undersampling"), (u32)1, (u32)4);
|
||||||
|
|
||||||
shader_id = client->getShaderSource()->getShader("coarse_noise_shader", TILE_MATERIAL_PLAIN, NDT_MESH);
|
buffer->setTexture(TEXTURE_CLOUDS_1, scale / (float)undersampling, "clouds_1", color_format, /*clear:*/ true);
|
||||||
noise_step = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8>());
|
|
||||||
noise_step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_NOISE_COARSE));
|
|
||||||
|
|
||||||
buffer->setTexture(TEXTURE_CLOUDS_1, scale * 0.25f, "clouds_1", color_format, /*clear:*/ true);
|
|
||||||
buffer->setTexture(TEXTURE_CLOUDS_2, scale, "clouds_2", color_format);
|
buffer->setTexture(TEXTURE_CLOUDS_2, scale, "clouds_2", color_format);
|
||||||
buffer->setTexture(TEXTURE_CLOUD_DENSITY, scale, "cloud_density", color_format);
|
buffer->setTexture(TEXTURE_CLOUD_DENSITY, scale, "cloud_density", color_format);
|
||||||
|
|
||||||
|
@ -253,16 +307,24 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
||||||
volumetric_clouds->setBilinearFilter(2, true);
|
volumetric_clouds->setBilinearFilter(2, true);
|
||||||
volumetric_clouds->setWrapRepeat(1, true);
|
volumetric_clouds->setWrapRepeat(1, true);
|
||||||
volumetric_clouds->setWrapRepeat(2, true);
|
volumetric_clouds->setWrapRepeat(2, true);
|
||||||
|
volumetric_clouds->disableDepthTest();
|
||||||
|
|
||||||
source = TEXTURE_CLOUDS_1;
|
source = TEXTURE_CLOUDS_1;
|
||||||
|
|
||||||
shader_id = client->getShaderSource()->getShader("clouds_merge", TILE_MATERIAL_PLAIN, NDT_MESH);
|
shader_id = client->getShaderSource()->getShader("clouds_merge", TILE_MATERIAL_PLAIN, NDT_MESH);
|
||||||
PostProcessingStep* blend_clouds = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_CLOUDS_1, TEXTURE_COLOR });
|
PostProcessingStep* blend_clouds = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_CLOUDS_1, TEXTURE_COLOR, TEXTURE_DEPTH });
|
||||||
blend_clouds->setRenderSource(buffer);
|
blend_clouds->setRenderSource(buffer);
|
||||||
blend_clouds->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_CLOUDS_2));
|
blend_clouds->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_CLOUDS_2));
|
||||||
blend_clouds->setBilinearFilter(0, true);
|
blend_clouds->setBilinearFilter(0, true);
|
||||||
|
blend_clouds->disableDepthTest();
|
||||||
|
|
||||||
|
CloudDepthStep* cloud_depth = pipeline->addStep<CloudDepthStep>(client->getClouds());
|
||||||
|
TextureBufferOutput* cloud_depth_output = pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8>{ TEXTURE_COLOR }, TEXTURE_DEPTH);
|
||||||
|
cloud_depth_output->disableClearing();
|
||||||
|
cloud_depth->setRenderTarget(cloud_depth_output);
|
||||||
|
|
||||||
source = TEXTURE_CLOUDS_2;
|
source = TEXTURE_CLOUDS_2;
|
||||||
|
final_color_source = TEXTURE_CLOUDS_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// common downsampling step for bloom or autoexposure
|
// common downsampling step for bloom or autoexposure
|
||||||
|
@ -281,7 +343,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
||||||
|
|
||||||
// get bright spots
|
// get bright spots
|
||||||
u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH);
|
u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH);
|
||||||
auto extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_EXPOSURE_1 });
|
RenderStep* extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_EXPOSURE_1 });
|
||||||
extract_bloom->setRenderSource(buffer);
|
extract_bloom->setRenderSource(buffer);
|
||||||
extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM));
|
extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM));
|
||||||
source = TEXTURE_BLOOM;
|
source = TEXTURE_BLOOM;
|
||||||
|
@ -332,14 +394,14 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
||||||
}
|
}
|
||||||
|
|
||||||
// FXAA
|
// FXAA
|
||||||
u8 final_stage_source = TEXTURE_CLOUDS_2;
|
u8 final_stage_source = final_color_source;
|
||||||
|
|
||||||
if (enable_fxaa) {
|
if (enable_fxaa) {
|
||||||
final_stage_source = TEXTURE_FXAA;
|
final_stage_source = TEXTURE_FXAA;
|
||||||
|
|
||||||
buffer->setTexture(TEXTURE_FXAA, scale, "fxaa", color_format);
|
buffer->setTexture(TEXTURE_FXAA, scale, "fxaa", color_format);
|
||||||
shader_id = client->getShaderSource()->getShader("fxaa", TILE_MATERIAL_PLAIN);
|
shader_id = client->getShaderSource()->getShader("fxaa", TILE_MATERIAL_PLAIN);
|
||||||
PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR });
|
PostProcessingStep* effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { final_color_source });
|
||||||
pipeline->addStep(effect);
|
pipeline->addStep(effect);
|
||||||
effect->setBilinearFilter(0, true);
|
effect->setBilinearFilter(0, true);
|
||||||
effect->setRenderSource(buffer);
|
effect->setRenderSource(buffer);
|
||||||
|
@ -348,7 +410,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
||||||
|
|
||||||
// final merge
|
// final merge
|
||||||
shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH);
|
shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH);
|
||||||
PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { final_stage_source, TEXTURE_SCALE_UP, TEXTURE_EXPOSURE_2 });
|
PostProcessingStep* effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { final_stage_source, TEXTURE_SCALE_UP, TEXTURE_EXPOSURE_2 });
|
||||||
pipeline->addStep(effect);
|
pipeline->addStep(effect);
|
||||||
if (enable_ssaa)
|
if (enable_ssaa)
|
||||||
effect->setBilinearFilter(0, true);
|
effect->setBilinearFilter(0, true);
|
||||||
|
|
|
@ -52,6 +52,10 @@ public:
|
||||||
|
|
||||||
void setWrapRepeat(u8 index, bool value);
|
void setWrapRepeat(u8 index, bool value);
|
||||||
|
|
||||||
|
void setColor(video::SColor color);
|
||||||
|
|
||||||
|
void disableDepthTest();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 shader_id;
|
u32 shader_id;
|
||||||
std::vector<u8> texture_map;
|
std::vector<u8> texture_map;
|
||||||
|
|
|
@ -342,6 +342,7 @@ void set_default_settings()
|
||||||
settings->setDefault("bloom_intensity", "0.05");
|
settings->setDefault("bloom_intensity", "0.05");
|
||||||
settings->setDefault("bloom_radius", "1");
|
settings->setDefault("bloom_radius", "1");
|
||||||
settings->setDefault("enable_volumetric_lighting", "false");
|
settings->setDefault("enable_volumetric_lighting", "false");
|
||||||
|
settings->setDefault("enable_volumetric_clouds", "false");
|
||||||
settings->setDefault("enable_bumpmaps", "false");
|
settings->setDefault("enable_bumpmaps", "false");
|
||||||
|
|
||||||
// Effects Shadows
|
// Effects Shadows
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue