mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Volumetric effects
This commit is contained in:
parent
cd6e304cfa
commit
22ba7449f2
15 changed files with 468 additions and 23 deletions
44
client/shaders/clouds_merge/opengl_fragment.glsl
Normal file
44
client/shaders/clouds_merge/opengl_fragment.glsl
Normal file
|
@ -0,0 +1,44 @@
|
|||
#define cloudsTexture texture0
|
||||
#define sceneTexture texture1
|
||||
|
||||
uniform sampler2D cloudsTexture;
|
||||
uniform sampler2D sceneTexture;
|
||||
uniform vec2 texelSize0;
|
||||
|
||||
uniform vec3 dayLight;
|
||||
|
||||
varying vec2 screenspaceCoordinate;
|
||||
|
||||
vec4 sampleClouds(vec2 uv) {
|
||||
vec4 cloudsKey = texture2D(cloudsTexture, uv);
|
||||
|
||||
const vec3 darkColor = vec3(0.05, 0.1, 0.2);
|
||||
const vec3 auroraDark = vec3(0., 0.5, 0.5);
|
||||
const vec3 auroraBright = vec3(0., 0.5, .0);
|
||||
|
||||
return vec4(
|
||||
mix(auroraDark, auroraBright, cloudsKey.b) * cloudsKey.b * max(0., 1. - cloudsKey.r) +
|
||||
cloudsKey.r * (darkColor * max(0., 1. - cloudsKey.g) + dayLight * cloudsKey.g),
|
||||
cloudsKey.r);
|
||||
}
|
||||
|
||||
vec4 getClouds(vec2 uv) {
|
||||
return
|
||||
sampleClouds(uv - texelSize0 * vec2(-1.0, -1.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2( 0.0, -1.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2( 1.0, -1.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2(-1.0, 0.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2( 0.0, 0.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2( 1.0, 0.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2(-1.0, 1.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2( 0.0, 1.0)) / 9.0 +
|
||||
sampleClouds(uv - texelSize0 * vec2( 1.0, 1.0)) / 9.0;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec4 cloudsColor = getClouds(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.);
|
||||
}
|
7
client/shaders/clouds_merge/opengl_vertex.glsl
Normal file
7
client/shaders/clouds_merge/opengl_vertex.glsl
Normal file
|
@ -0,0 +1,7 @@
|
|||
varying vec2 screenspaceCoordinate;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
screenspaceCoordinate = inVertexPosition.xy;
|
||||
gl_Position = inVertexPosition;
|
||||
}
|
17
client/shaders/coarse_noise_shader/opengl_fragment.glsl
Normal file
17
client/shaders/coarse_noise_shader/opengl_fragment.glsl
Normal file
|
@ -0,0 +1,17 @@
|
|||
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.);
|
||||
}
|
4
client/shaders/coarse_noise_shader/opengl_vertex.glsl
Normal file
4
client/shaders/coarse_noise_shader/opengl_vertex.glsl
Normal file
|
@ -0,0 +1,4 @@
|
|||
void main(void)
|
||||
{
|
||||
gl_Position = inVertexPosition;
|
||||
}
|
15
client/shaders/noise_shader/opengl_fragment.glsl
Normal file
15
client/shaders/noise_shader/opengl_fragment.glsl
Normal file
|
@ -0,0 +1,15 @@
|
|||
// 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.);
|
||||
}
|
4
client/shaders/noise_shader/opengl_vertex.glsl
Normal file
4
client/shaders/noise_shader/opengl_vertex.glsl
Normal file
|
@ -0,0 +1,4 @@
|
|||
void main(void)
|
||||
{
|
||||
gl_Position = inVertexPosition;
|
||||
}
|
|
@ -163,7 +163,7 @@ void main(void)
|
|||
// Filter out blue pixels, because the color grading tends to wash them out.
|
||||
float blue_factor = clamp((color.b - max(color.r, color.g)) / max(0.01, min(color.r, color.g)), 0.0, 1.0);
|
||||
|
||||
color.rgb = mix(color.rgb, pow(color.rgb * slope, power), pow(1. - blue_factor, 4.));
|
||||
color.rgb = mix(color.rgb, pow(color.rgb * slope, power), 1.);
|
||||
#endif
|
||||
color.rgb = applySaturation(color.rgb, saturation);
|
||||
}
|
||||
|
|
182
client/shaders/volumetric_clouds/opengl_fragment.glsl
Normal file
182
client/shaders/volumetric_clouds/opengl_fragment.glsl
Normal file
|
@ -0,0 +1,182 @@
|
|||
#define depthmap texture0
|
||||
#define noiseTexture texture1
|
||||
#define noiseTextureCoarse texture2
|
||||
|
||||
#define ITERATIONS 50
|
||||
#define LIGHT_ITERATIONS 10
|
||||
#define LIGHT_DISTANCE 100.
|
||||
#define AURORA_ITERATIONS 100
|
||||
|
||||
uniform sampler2D depthmap;
|
||||
uniform sampler2D noiseTexture;
|
||||
uniform sampler2D noiseTextureCoarse;
|
||||
|
||||
uniform vec2 texelSize0;
|
||||
|
||||
uniform float cloudHeight;
|
||||
uniform float cloudThickness;
|
||||
uniform float cloudDensity;
|
||||
|
||||
varying vec3 relativePosition;
|
||||
varying vec3 viewDirection;
|
||||
uniform vec3 eyePosition;
|
||||
uniform vec3 cameraOffset;
|
||||
uniform vec3 cameraPosition;
|
||||
|
||||
uniform mat4 mCameraView;
|
||||
uniform mat4 mCameraProjInv;
|
||||
|
||||
uniform float cameraNear;
|
||||
uniform float cameraFar;
|
||||
|
||||
varying vec2 screenspaceCoordinate;
|
||||
|
||||
uniform float fogDistance;
|
||||
uniform float fogShadingParameter;
|
||||
|
||||
uniform vec3 v_LightDirection;
|
||||
|
||||
uniform float animationTimer;
|
||||
|
||||
// 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)
|
||||
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
|
||||
float screenSpaceDither(highp vec2 frag_coord) {
|
||||
// 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);
|
||||
dither = fract(dither / 103.0);
|
||||
|
||||
return dither;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
float getDepth(vec2 screenspacePosition) {
|
||||
float depth = texture2D(depthmap, screenspacePosition * 0.5 + 0.5).r;
|
||||
return cameraNear * cameraFar / (cameraFar + depth * (cameraNear - cameraFar));
|
||||
}
|
||||
|
||||
float getRawDepth(vec2 screenspacePosition) {
|
||||
return texture2D(depthmap, screenspacePosition * 0.5 + 0.5).r;
|
||||
}
|
||||
|
||||
float noise(vec3 p){
|
||||
//p.y *= 1.;
|
||||
float y = floor(p.y);
|
||||
float f1 = texture2D(noiseTexture, p.xz / 256. + y * 0.2).r;
|
||||
float f2 = texture2D(noiseTexture, p.xz / 256. + y * 0.2 + 0.2).r;
|
||||
return mix(f1, f2, fract(p.y));
|
||||
}
|
||||
|
||||
float fnoise(vec3 p) {
|
||||
return noise(p * 4.) * 0.5 + noise(p * 8.) * 0.25;
|
||||
}
|
||||
|
||||
float fnoise3(vec3 p) {
|
||||
return noise(p * 4.) * 0.5 + noise(p * 8.) * 0.25 + noise(p * 16.) * 0.125;
|
||||
}
|
||||
|
||||
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.);
|
||||
return 1.0 * 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 density = texture2D(noiseTextureCoarse, position.xz / 2560. / 16.).r *
|
||||
mtsmoothstep(0.0, cloudThickness * 0.2, position.y - cloudHeight) *
|
||||
(1.0 - mtsmoothstep(cloudThickness * 0.5, cloudThickness, position.y - cloudHeight));
|
||||
|
||||
density = max(0., density - 0.5 * fnoise(position * 0.005));
|
||||
|
||||
return 0.04 * density;
|
||||
}
|
||||
|
||||
float getBrightness(vec3 position, float bias) {
|
||||
float density = 0.;
|
||||
for (int i = 0; i < LIGHT_ITERATIONS; i++) {
|
||||
vec3 rayPosition = position - v_LightDirection * LIGHT_DISTANCE * (float(i) + bias) / float(LIGHT_ITERATIONS);
|
||||
|
||||
density += getDensity(rayPosition) * float(LIGHT_DISTANCE) / float(LIGHT_ITERATIONS);
|
||||
}
|
||||
return exp(-density);
|
||||
}
|
||||
|
||||
float blend(float A, float B, float alphaA, float alphaB) {
|
||||
float alphaC = alphaA + (1. - alphaA) * alphaB;
|
||||
return (alphaA * A + (1. - alphaA) * alphaB * B) / alphaC;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec3 viewVec = normalize(relativePosition);
|
||||
|
||||
vec3 position = cameraOffset + eyePosition;
|
||||
|
||||
float depth = getDepth(screenspaceCoordinate) / normalize(viewDirection).z;
|
||||
float bottomPlaneIntersect = clamp(min((cloudHeight - eyePosition.y) / viewVec.y, depth), 0., 4. * fogDistance);
|
||||
float topPlaneIntersect = clamp(min((cloudHeight + cloudThickness - eyePosition.y) / viewVec.y, depth), 0., 4. * fogDistance);
|
||||
|
||||
float startDepth = min(bottomPlaneIntersect, topPlaneIntersect);
|
||||
float endDepth = max(bottomPlaneIntersect, topPlaneIntersect);
|
||||
|
||||
float bias = screenSpaceDither(gl_FragCoord.xy + animationTimer * 2400.0);
|
||||
|
||||
vec3 color = vec3(0.);
|
||||
|
||||
float dx = (endDepth - startDepth) / float(ITERATIONS);
|
||||
|
||||
float density = 0.;
|
||||
|
||||
float auroraStartDepth = min(max(0., 1.0 / viewVec.y), 8.);
|
||||
float auroraEndDepth = min(max(0., 3.0 / viewVec.y), 8.);
|
||||
float rawDepth = getRawDepth(screenspaceCoordinate);
|
||||
|
||||
if (auroraEndDepth - auroraStartDepth > 0.1 && rawDepth >= 1.0) {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
vec3 rayPosition = viewVec * (auroraStartDepth + (auroraEndDepth - auroraStartDepth) * (float(i) + bias) / float(ITERATIONS));
|
||||
|
||||
float localDensity = getAuroraDensity(rayPosition);
|
||||
|
||||
localDensity *= 1.0 - mtsmoothstep(4.0, 8.0, length(rayPosition));
|
||||
|
||||
density += localDensity;
|
||||
}
|
||||
}
|
||||
|
||||
color.b = density * (auroraEndDepth - auroraStartDepth) / float(AURORA_ITERATIONS);
|
||||
|
||||
float sunlightContribution = 0.;
|
||||
float alpha = 0.;
|
||||
float outScatter = 2. * (dot(v_LightDirection, viewVec) * 0.5 + 0.5);
|
||||
density = 0.;
|
||||
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
vec3 rayPosition = eyePosition + viewVec * (startDepth + (endDepth - startDepth) * (float(i) + bias) / float(ITERATIONS));
|
||||
|
||||
float localDensity = getDensity(rayPosition) * dx;
|
||||
|
||||
if (localDensity < 0.0001) continue;
|
||||
|
||||
float clarity = clamp(fogShadingParameter - fogShadingParameter * length(rayPosition - eyePosition) / (4. * fogDistance), 0.0, 1.0);
|
||||
float brightness = getBrightness(rayPosition, bias) * exp(-outScatter * localDensity);
|
||||
sunlightContribution = blend(sunlightContribution, brightness, 1. - exp(-density), 1. - exp(-localDensity));
|
||||
alpha = blend(alpha, clarity, 1. - exp(-density), 1. - exp(-localDensity));
|
||||
|
||||
density += localDensity;
|
||||
|
||||
if (density > 10.0) break;
|
||||
}
|
||||
|
||||
float forwardScatter = 1. + 4. * pow(min(dot(v_LightDirection, viewVec), 0.), 4.);
|
||||
|
||||
color.r = (1. - exp(-density)) * alpha;
|
||||
color.g = sunlightContribution * forwardScatter;
|
||||
|
||||
gl_FragColor = vec4(color, 1.0);
|
||||
}
|
17
client/shaders/volumetric_clouds/opengl_vertex.glsl
Normal file
17
client/shaders/volumetric_clouds/opengl_vertex.glsl
Normal file
|
@ -0,0 +1,17 @@
|
|||
uniform mat4 mCameraProjInv;
|
||||
uniform mat4 mCameraView;
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 relativePosition;
|
||||
varying vec3 viewDirection;
|
||||
|
||||
varying vec2 screenspaceCoordinate;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
screenspaceCoordinate = inVertexPosition.xy;
|
||||
vec4 p = mCameraProjInv * inVertexPosition;
|
||||
viewDirection = p.xyz / p.w;
|
||||
relativePosition = (p.xyz / p.w) * mat3(mCameraView);
|
||||
gl_Position = inVertexPosition;
|
||||
}
|
|
@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "settings.h"
|
||||
#include <cmath>
|
||||
|
||||
|
||||
// Menu clouds are created later
|
||||
class Clouds;
|
||||
Clouds *g_menuclouds = NULL;
|
||||
|
@ -344,6 +343,7 @@ void Clouds::updateMesh()
|
|||
|
||||
void Clouds::render()
|
||||
{
|
||||
#if 0
|
||||
if (m_params.density <= 0.0f)
|
||||
return; // no need to do anything
|
||||
|
||||
|
@ -394,13 +394,7 @@ void Clouds::render()
|
|||
// Restore fog settings
|
||||
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||
fog_pixelfog, fog_rangefog);
|
||||
}
|
||||
|
||||
void Clouds::renderVolumetrics() {
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
v2u32 ss = driver->getScreenSize();
|
||||
core::rect<s32> rect(0, 0, ss.X, ss.Y);
|
||||
driver->draw2DRectangle(video::SColor(255, 255, 255, 255), rect);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Clouds::step(float dtime)
|
||||
|
|
|
@ -52,8 +52,6 @@ public:
|
|||
|
||||
virtual void render();
|
||||
|
||||
void renderVolumetrics();
|
||||
|
||||
virtual const aabb3f &getBoundingBox() const
|
||||
{
|
||||
return m_box;
|
||||
|
@ -93,6 +91,10 @@ public:
|
|||
invalidateMesh();
|
||||
}
|
||||
|
||||
float getDensity() const {
|
||||
return m_params.density;
|
||||
}
|
||||
|
||||
void setColorBright(video::SColor color_bright)
|
||||
{
|
||||
m_params.color_bright = color_bright;
|
||||
|
@ -112,6 +114,10 @@ public:
|
|||
invalidateMesh();
|
||||
}
|
||||
|
||||
float getHeight() const {
|
||||
return m_params.height;
|
||||
}
|
||||
|
||||
void setSpeed(v2f speed)
|
||||
{
|
||||
m_params.speed = speed;
|
||||
|
@ -126,6 +132,10 @@ public:
|
|||
invalidateMesh();
|
||||
}
|
||||
|
||||
float getThickness() const {
|
||||
return m_params.thickness;
|
||||
}
|
||||
|
||||
bool isCameraInsideCloud() const { return m_camera_inside_cloud; }
|
||||
|
||||
const video::SColor getColor() const { return m_color.toSColor(); }
|
||||
|
@ -147,7 +157,7 @@ private:
|
|||
|
||||
bool gridFilled(int x, int y) const;
|
||||
|
||||
video::SMaterial m_volume_material;
|
||||
video::ITexture *m_density_texture = nullptr;
|
||||
|
||||
video::SMaterial m_material;
|
||||
irr_ptr<scene::SMeshBuffer> m_meshbuffer;
|
||||
|
|
|
@ -383,9 +383,18 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
|||
m_animation_timer_delta_pixel{"animationTimerDelta"};
|
||||
CachedPixelShaderSetting<float, 3> m_artificial_light{ "artificialLight" };
|
||||
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_camera_offset_pixel{"cameraOffset"};
|
||||
CachedVertexShaderSetting<float, 3> m_camera_offset_vertex{"cameraOffset"};
|
||||
CachedPixelShaderSetting<float, 3> m_camera_position_pixel{"cameraPosition"};
|
||||
CachedVertexShaderSetting<float, 16> m_camera_projinv_vertex{"mCameraProjInv"};
|
||||
CachedPixelShaderSetting<float, 16> m_camera_projinv_pixel{"mCameraProjInv"};
|
||||
CachedVertexShaderSetting<float, 16> m_camera_view_vertex{"mCameraView"};
|
||||
CachedPixelShaderSetting<float, 16> m_camera_view_pixel{"mCameraView"};
|
||||
CachedPixelShaderSetting<float> m_camera_near_pixel{"cameraNear"};
|
||||
CachedPixelShaderSetting<float> m_camera_far_pixel{"cameraFar"};
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture0{"texture0"};
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture1{"texture1"};
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture2{"texture2"};
|
||||
|
@ -408,6 +417,9 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
|||
float m_bloom_strength;
|
||||
CachedPixelShaderSetting<float> m_bloom_radius_pixel{"bloomRadius"};
|
||||
float m_bloom_radius;
|
||||
CachedPixelShaderSetting<float> m_cloud_height_pixel{"cloudHeight"};
|
||||
CachedPixelShaderSetting<float> m_cloud_thickness_pixel{"cloudThickness"};
|
||||
CachedPixelShaderSetting<float> m_cloud_density_pixel{"cloudDensity"};
|
||||
CachedPixelShaderSetting<float> m_saturation_pixel{"saturation"};
|
||||
float m_gamma;
|
||||
CachedPixelShaderSetting<float> m_gamma_pixel{"gamma"};
|
||||
|
@ -489,6 +501,10 @@ public:
|
|||
m_animation_timer_delta_vertex.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()) {
|
||||
v3f minimap_yaw = m_client->getMinimap()->getYawVec();
|
||||
m_minimap_yaw.set(minimap_yaw, services);
|
||||
|
@ -498,6 +514,24 @@ public:
|
|||
m_camera_offset_pixel.set(offset, services);
|
||||
m_camera_offset_vertex.set(offset, services);
|
||||
|
||||
v3f camera_position = m_client->getCamera()->getPosition();
|
||||
m_camera_position_pixel.set(camera_position, services);
|
||||
|
||||
core::matrix4 camera_proj = m_client->getCamera()->getCameraNode()->getProjectionMatrix();
|
||||
core::matrix4 camera_projinv;
|
||||
camera_proj.getInverse(camera_projinv);
|
||||
m_camera_projinv_vertex.set(camera_projinv, services);
|
||||
m_camera_projinv_pixel.set(camera_projinv, services);
|
||||
|
||||
core::matrix4 camera_view = m_client->getCamera()->getCameraNode()->getViewMatrix();
|
||||
m_camera_view_vertex.set(camera_view, services);
|
||||
m_camera_view_pixel.set(camera_view, services);
|
||||
|
||||
float camera_near = m_client->getCamera()->getCameraNode()->getNearValue();
|
||||
m_camera_near_pixel.set(&camera_near, services);
|
||||
float camera_far = m_client->getCamera()->getCameraNode()->getFarValue();
|
||||
m_camera_far_pixel.set(&camera_far, services);
|
||||
|
||||
SamplerLayer_t tex_id;
|
||||
tex_id = 0;
|
||||
m_texture0.set(&tex_id, services);
|
||||
|
@ -537,6 +571,17 @@ public:
|
|||
video::SColorf artificial_light = lighting.artificial_light_color;
|
||||
m_artificial_light.set(artificial_light, services);
|
||||
|
||||
// TODO: settings
|
||||
Clouds* clouds = m_client->getClouds();
|
||||
if (m_client->getClouds()) {
|
||||
float cloud_height = clouds->getHeight() * 10.0f;
|
||||
m_cloud_height_pixel.set(&cloud_height, services);
|
||||
float cloud_thickness = clouds->getThickness() * 10.0f;
|
||||
m_cloud_thickness_pixel.set(&cloud_thickness, services);
|
||||
float cloud_density = clouds->getDensity();
|
||||
m_cloud_density_pixel.set(&cloud_density, services);
|
||||
}
|
||||
|
||||
if (m_volumetric_light_enabled) {
|
||||
// Map directional light to screen space
|
||||
auto camera_node = m_client->getCamera()->getCameraNode();
|
||||
|
|
|
@ -66,11 +66,6 @@ void DrawHUD::run(PipelineContext &context)
|
|||
context.client->getCamera()->drawNametags();
|
||||
}
|
||||
context.device->getGUIEnvironment()->drawAll();
|
||||
|
||||
// TODO: proper settings
|
||||
if (true && context.client->getClouds()) {
|
||||
context.client->getClouds()->renderVolumetrics();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,65 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "client/tile.h"
|
||||
#include "settings.h"
|
||||
|
||||
class NoiseStep : public RenderStep {
|
||||
public:
|
||||
NoiseStep(u32 shader_id, u8 texture_id) :
|
||||
shader_id(shader_id), texture_id(texture_id)
|
||||
{
|
||||
material.UseMipMaps = false;
|
||||
material.ZBuffer = true;
|
||||
material.ZWriteEnable = video::EZW_ON;
|
||||
}
|
||||
|
||||
void setRenderSource(RenderSource* _source) override {
|
||||
source = _source;
|
||||
}
|
||||
|
||||
void setRenderTarget(RenderTarget* _target) override {
|
||||
target = _target;
|
||||
}
|
||||
|
||||
void reset(PipelineContext& context) override {}
|
||||
|
||||
void run(PipelineContext& context) override {
|
||||
video::ITexture* texture = source->getTexture(texture_id);
|
||||
if (texture != last_texture) {
|
||||
last_texture = texture;
|
||||
|
||||
if (target)
|
||||
target->activate(context);
|
||||
|
||||
// attach the shader
|
||||
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:
|
||||
u32 shader_id;
|
||||
u8 texture_id;
|
||||
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) :
|
||||
shader_id(_shader_id), texture_map(_texture_map)
|
||||
{
|
||||
|
@ -65,7 +124,6 @@ void PostProcessingStep::run(PipelineContext &context)
|
|||
if (target)
|
||||
target->activate(context);
|
||||
|
||||
// attach the shader
|
||||
material.MaterialType = context.client->getShaderSource()->getShaderInfo(shader_id).material;
|
||||
|
||||
auto driver = context.device->getVideoDriver();
|
||||
|
@ -96,6 +154,12 @@ void PostProcessingStep::setBilinearFilter(u8 index, bool value)
|
|||
material.TextureLayers[index].MagFilter = value ? video::ETMAGF_LINEAR : video::ETMAGF_NEAREST;
|
||||
}
|
||||
|
||||
void PostProcessingStep::setWrapRepeat(u8 index, bool value) {
|
||||
assert(index < video::MATERIAL_MAX_TEXTURES);
|
||||
material.TextureLayers[index].TextureWrapU = value ? video::ETC_REPEAT : video::ETC_CLAMP_TO_EDGE;
|
||||
material.TextureLayers[index].TextureWrapV = value ? video::ETC_REPEAT : video::ETC_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client)
|
||||
{
|
||||
auto buffer = pipeline->createOwned<TextureBuffer>();
|
||||
|
@ -121,8 +185,13 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
|||
static const u8 TEXTURE_EXPOSURE_2 = 4;
|
||||
static const u8 TEXTURE_FXAA = 5;
|
||||
static const u8 TEXTURE_VOLUME = 6;
|
||||
static const u8 TEXTURE_SCALE_DOWN = 10;
|
||||
static const u8 TEXTURE_SCALE_UP = 20;
|
||||
static const u8 TEXTURE_CLOUDS_1 = 7;
|
||||
static const u8 TEXTURE_CLOUDS_2 = 8;
|
||||
static const u8 TEXTURE_CLOUD_DENSITY = 9;
|
||||
static const u8 TEXTURE_NOISE = 10;
|
||||
static const u8 TEXTURE_NOISE_COARSE = 11;
|
||||
static const u8 TEXTURE_SCALE_DOWN = 20;
|
||||
static const u8 TEXTURE_SCALE_UP = 30;
|
||||
|
||||
// Super-sampling is simply rendering into a larger texture.
|
||||
// Downscaling is done by the final step when rendering to the screen.
|
||||
|
@ -132,6 +201,8 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
|||
const bool enable_ssaa = antialiasing == "ssaa";
|
||||
const bool enable_fxaa = antialiasing == "fxaa";
|
||||
const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom;
|
||||
const bool enable_volumetric_clouds = true;
|
||||
// TODO: Add clouds setting
|
||||
|
||||
if (enable_ssaa) {
|
||||
u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa"));
|
||||
|
@ -152,11 +223,48 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
|||
// Number of mipmap levels of the bloom downsampling texture
|
||||
const u8 MIPMAP_LEVELS = 4;
|
||||
|
||||
|
||||
// post-processing stage
|
||||
|
||||
u8 source = TEXTURE_COLOR;
|
||||
|
||||
if (enable_volumetric_clouds) {
|
||||
buffer->setTexture(TEXTURE_NOISE, core::dimension2du(256, 256), "noise", color_format);
|
||||
|
||||
shader_id = client->getShaderSource()->getShader("noise_shader", TILE_MATERIAL_PLAIN, NDT_MESH);
|
||||
RenderStep *noise_step = pipeline->addStep<NoiseStep>(shader_id, TEXTURE_NOISE);
|
||||
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);
|
||||
|
||||
shader_id = client->getShaderSource()->getShader("coarse_noise_shader", TILE_MATERIAL_PLAIN, NDT_MESH);
|
||||
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_CLOUD_DENSITY, scale, "cloud_density", color_format);
|
||||
|
||||
shader_id = client->getShaderSource()->getShader("volumetric_clouds", TILE_MATERIAL_PLAIN, NDT_MESH);
|
||||
PostProcessingStep *volumetric_clouds = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_DEPTH, TEXTURE_NOISE, TEXTURE_NOISE_COARSE });
|
||||
volumetric_clouds->setRenderSource(buffer);
|
||||
volumetric_clouds->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_CLOUDS_1));
|
||||
volumetric_clouds->setBilinearFilter(1, true);
|
||||
volumetric_clouds->setBilinearFilter(2, true);
|
||||
volumetric_clouds->setWrapRepeat(1, true);
|
||||
volumetric_clouds->setWrapRepeat(2, true);
|
||||
|
||||
source = TEXTURE_CLOUDS_1;
|
||||
|
||||
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 });
|
||||
blend_clouds->setRenderSource(buffer);
|
||||
blend_clouds->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_CLOUDS_2));
|
||||
blend_clouds->setBilinearFilter(0, true);
|
||||
|
||||
source = TEXTURE_CLOUDS_2;
|
||||
}
|
||||
|
||||
// common downsampling step for bloom or autoexposure
|
||||
if (enable_bloom || enable_auto_exposure) {
|
||||
|
||||
|
@ -173,7 +281,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
|||
|
||||
// get bright spots
|
||||
u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH);
|
||||
RenderStep *extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_EXPOSURE_1 });
|
||||
auto extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_EXPOSURE_1 });
|
||||
extract_bloom->setRenderSource(buffer);
|
||||
extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM));
|
||||
source = TEXTURE_BLOOM;
|
||||
|
@ -224,7 +332,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
|||
}
|
||||
|
||||
// FXAA
|
||||
u8 final_stage_source = TEXTURE_COLOR;
|
||||
u8 final_stage_source = TEXTURE_CLOUDS_2;
|
||||
|
||||
if (enable_fxaa) {
|
||||
final_stage_source = TEXTURE_FXAA;
|
||||
|
|
|
@ -49,6 +49,9 @@ public:
|
|||
* @param value true to enable the bilinear filter, false to disable
|
||||
*/
|
||||
void setBilinearFilter(u8 index, bool value);
|
||||
|
||||
void setWrapRepeat(u8 index, bool value);
|
||||
|
||||
private:
|
||||
u32 shader_id;
|
||||
std::vector<u8> texture_map;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue