From 91bc31e7dbf565a2c1513a9b2858b745c4861e8a Mon Sep 17 00:00:00 2001 From: peri4 Date: Sat, 18 Feb 2023 19:12:16 +0300 Subject: [PATCH] soft shadows done --- shaders/ds_light.glsl | 125 ++++++++++++++++++++++++++---- src/core/core/gltypes.cpp | 19 +++++ src/core/core/gltypes.h | 1 + src/core/render/renderer.cpp | 16 ++-- src/core/render/renderer_base.cpp | 17 +++- src/core/render/renderer_base.h | 4 +- 6 files changed, 157 insertions(+), 25 deletions(-) diff --git a/shaders/ds_light.glsl b/shaders/ds_light.glsl index 5432f3e..ee52664 100644 --- a/shaders/ds_light.glsl +++ b/shaders/ds_light.glsl @@ -18,13 +18,15 @@ in vec3 view_dir, world_dir; uniform vec2 dt, shadow_size; uniform float z_near; -uniform sampler2D tex_coeffs[2]; +uniform sampler2D tex_coeffs[2], tex_noise; uniform sampler2D tex_0, tex_1, tex_2, tex_3, tex_4, tex_sh; //uniform sampler2DShadow tex_shadow[16]; uniform sampler2DArrayShadow tex_shadows_cone; +uniform sampler2DArray tex_depths_cone; uniform samplerCubeArrayShadow tex_shadows_omni; +uniform samplerCubeArray tex_depths_omni; uniform samplerCube tex_env; -uniform int lights_start, lights_count, soft_shadows_samples = 16; +uniform int lights_start, lights_count, soft_shadows_samples = 16, noise_size = 64; uniform bool soft_shadows_enabled = false; uniform vec4 fog_color = vec4(0.5, 0.5, 0.5, 1); @@ -36,6 +38,7 @@ const vec3 luma = vec3(0.299, 0.587, 0.114); const float _min_rough = 1.e-8, max_lod = 8; const float PI = 3.1416; +ivec2 tc; vec4 pos, lpos, shp; vec3 li, si, ldir, halfV, bn, bn2, lwdir; vec3 normal, vds, vds2; @@ -87,13 +90,55 @@ float getShadowOmni(in vec4 uvwz, in int layer) { #endif +uint hash(uint x) { + x += (x << 10u); + x ^= (x >> 6u); + x += (x << 3u); + x ^= (x >> 11u); + x += (x << 15u); + return x; +} +uint hash( uvec2 v ) { return hash( v.x ^ hash(v.y) ); } +uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ); } +uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); } +float floatConstruct( uint m ) { + const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask + const uint ieeeOne = 0x3F800000u; // 1.0 in IEEE binary32 + + m &= ieeeMantissa; // Keep only mantissa bits (fractional part) + m |= ieeeOne; // Add fractional part to 1.0 + + float f = uintBitsToFloat( m ); // Range [1:2] + return f - 1.0; // Range [0:1] +} +float random( float x ) { return floatConstruct(hash(floatBitsToUint(x))); } +float random( vec2 v ) { return floatConstruct(hash(floatBitsToUint(v))); } +float random( vec3 v ) { return floatConstruct(hash(floatBitsToUint(v))); } +float random( vec4 v ) { return floatConstruct(hash(floatBitsToUint(v))); } +float random( int x ) { return floatConstruct(hash(x)); } +float random( ivec2 v ) { return floatConstruct(hash(v)); } +float random( ivec3 v ) { return floatConstruct(hash(v)); } +float random( ivec4 v ) { return floatConstruct(hash(v)); } + +uvec2 noise_hash; +void noise2init(vec2 v) { + noise_hash = uvec2(hash(uint(v.x + 1)), hash(uint(v.y - 1))); +} +vec2 noise2() { + noise2init(vec2(noise_hash)); + //return vec2(floatConstruct(noise_hash.x), floatConstruct(noise_hash.y)) * 2 - vec2(1.); + float r = floatConstruct(noise_hash.x); + float a = floatConstruct(noise_hash.y) * 2 * PI; + return r * vec2(cos(a), sin(a)); +} + float rand(vec2 co) { float a = 12.9898; float b = 78.233; float c = 43758.5453; - float dt= dot(co.xy ,vec2(a,b)); - float sn= mod(dt,3.14); - return fract(sin(sn) * c) - 0.5; + float d = dot(co.xy, vec2(a, b)); + float e = sin(mod(d, 3.14)) * c; + return fract(e) - 0.5; } vec4 qgl_lightTexture(int index, vec2 coord, vec4 tex_shift) { @@ -121,7 +166,8 @@ void calcLight(in int index, in vec3 n, in vec3 v) { spot *= scos * step(qgl_light_parameter[index].angles.w, scos); spot *= smoothstep(qgl_light_parameter[index].angles.w, qgl_light_parameter[index].angles.y, scos); vec4 shp = mapScreenToShadow(index, vec3(0)); - vec4 light_map_pix = qgl_lightTexture(index, shp.xy / shp.w, vec4(0)); + shp.xy /= shp.w; + vec4 light_map_pix = qgl_lightTexture(index, shp.xy, vec4(0)); light_color *= light_map_pix.rgb; spot *= light_map_pix.a; #endif @@ -131,37 +177,76 @@ void calcLight(in int index, in vec3 n, in vec3 v) { int layer = index - lights_start; float shadow = 0.; //float bias = abs(tan(PI/2.*(1 - abs(dot(normal, ldir)))) + 1) * z_near * 1; - float bias = (1. + 1. / abs(dot(normal, ldir))) * z_near * 5; + float bias = (1. + 1. / abs(dot(normal, ldir))) * z_near * 2; //bias = bias * bias + z_near; if (soft_shadows_enabled) { - float ds = (ldist / 2.) / qgl_light_parameter[index].size; +#ifdef SPOT + float depth = 1; + const int gm_size = 3; + for (int i = -gm_size; i <= gm_size; ++i) { + for (int j = -gm_size; j <= gm_size; ++j) { + depth = min(depth, textureOffset(tex_depths_cone, vec3(shp.xy, layer), ivec2(i, j)).r); + } + } + depth = 1 / (1 - depth) - 1 + z_near; + float dz = max(0, shp.z - depth); + float ds = qgl_light_parameter[index].size * dz / (ldist - dz); + //qgl_FragColor.rgb = vec3(0); +#else + float depth = 1; + const int gm_size = 3; + for (int i = -gm_size; i <= gm_size; ++i) { + for (int j = -gm_size; j <= gm_size; ++j) { + for (int k = -gm_size; k <= gm_size; ++k) { + depth = min(depth, texture(tex_depths_omni, vec4(odir + vec3(i, j, k) / vec3(shadow_size.x), layer)).r); + } + } + } + depth = 1 / (1 - depth) - 1 + z_near; + float dz = max(0, ldist - depth); + float ds = qgl_light_parameter[index].size * dz / (ldist - dz); + //qgl_FragColor.rgb = vec3(dz/5); + //float ds = (ldist / 2.) / qgl_light_parameter[index].size; +#endif + vds = ds * bn.xyz; vds2 = ds * bn2.xyz; vec2 so; + ivec2 sotc = tc; + noise2init(vec2(hash(ivec2(tc.x * 2 + 1, tc.y)), hash(ivec2(tc.x, (tc.y * 2 + 1))))); for (int i = 1; i <= soft_shadows_samples; ++i) { + so = noise2(); #ifdef SPOT - so = vec2(rand(vec2(shp.x + i, shp.y)), rand(vec2(shp.x + i + 1, shp.y))); + //vec4 nc = texelFetch(tex_noise, sotc % noise_size, 0); + //sotc += ivec2(nc.ba * 256) % noise_size; + //so = (nc.rg - vec2(0.5)); + + //so = vec2(rand(vec2(shp.x + i, shp.y)), rand(vec2(shp.x + i + 1, shp.y))); + vec4 shp = mapScreenToShadow(index, vds * so.x + vds2 * so.y); shp.xy /= shp.w; shp.z -= bias; shadow += getShadowCone(shp.xyz, layer); #else - so = vec2(rand(vec2(odir.x + i, odir.y)), rand(vec2(odir.x + i + 1, odir.y))); + //so = vec2(rand(vec2(odir.x + i, odir.y)), rand(vec2(odir.x + i + 1, odir.y)))*1.25; + vec3 old = lpos.xyz - ((pos.xyz + vec3(vds * so.x + vds2 * so.y)) * lpos.w); odir = -(view_mat * old); shadow += getShadowOmni(vec4(odir, length(old) - bias), layer); #endif } - spot *= shadow / (soft_shadows_samples + 0); + spot *= min(1, 2. * shadow / soft_shadows_samples); + //spot *= shadow / soft_shadows_samples; + //spot *= shadow / soft_shadows_samples + 1; } else { #ifdef SPOT - shp.xy /= shp.w; + shp.xy; shp.z -= bias; spot *= getShadowCone(shp.xyz, layer); #else @@ -194,7 +279,7 @@ void calcLight(in int index, in vec3 n, in vec3 v) { void main(void) { - ivec2 tc = ivec2(gl_FragCoord.xy); + tc = ivec2(gl_FragCoord.xy); vec4 v1 = texelFetch(tex_1, tc, 0); float z = v1.w; if (z == 1.) { @@ -218,8 +303,9 @@ void main(void) { float reflectivity = v2.b; float NdotV = dot(normal, v); float roughness3 = roughness*roughness*roughness; - bn = normalize(cross(normal, view_dir)); + bn = normalize(cross(normal, vec3(1,0,0)) + cross(normal, vec3(0,1,0))); bn2 = normalize(cross(normal, bn)); + bn = cross(normal, bn2); rough_diff = max(roughness, _min_rough); rough_spec = max(roughness3, _min_rough); float shlick = clamp(metalness + (1 - metalness) * pow(1 - NdotV, 5), 0, 1); @@ -254,18 +340,23 @@ void main(void) { } qgl_FragColor = vec4(res_col, alpha); - //qgl_FragColor.rgb = vec3(qgl_light_parameter[0].size); + //qgl_FragColor.rgb = vec3(bn.z); #ifdef SPOT vec4 shp = mapScreenToShadow(0, vec3(0)); - //shp.xy /= shp.w; + shp.xy /= shp.w; + float depth = texture(tex_depths_cone, vec3(shp.xy, 0)).r; + depth = 1 / (1 - depth) - 1 + z_near; + float dz = max(0, shp.z - depth); //shp.z -= bias; //for (int xi = -2; xi <= 2; ++xi) { // for (int yi = -2; yi <= 2; ++yi) { //qgl_FragColor.rgb = vec3(step(shp.z, texture(tex_shadows_cone, vec3(shp.xy, 0)).r)); //qgl_FragColor.r = texture(tex_shadows_cone, vec3(0)).r; //qgl_FragColor.gb = vec2(1); - //qgl_FragColor.rgb = vec3(shp.z / shp.w);//vec4(res_col, alpha); + //float _d = texture(tex_depths_cone, vec3(shp.xy, 0)).r; + //_d = 1 / (1 - _d) - 1 + z_near; + //qgl_FragColor.rgb = vec3(texelFetch(tex_noise, tc % noise_size, 0).b);//vec4(res_col, alpha); //shp.z += 0.095; //qgl_FragColor.rgb = vec3(texture(tex_sh, shp.xy).rgb); diff --git a/src/core/core/gltypes.cpp b/src/core/core/gltypes.cpp index aa2894f..fce4ac5 100644 --- a/src/core/core/gltypes.cpp +++ b/src/core/core/gltypes.cpp @@ -21,6 +21,7 @@ #include "qglview.h" #include +#include QString readCharsUntilNull(QDataStream & s) { @@ -387,3 +388,21 @@ QVector3D vectorFromString(const QString & str) { ret.setZ(f); return ret; } + + +QImage generateNoise(QSize sz) { + QImage im(sz, QImage::Format_ARGB32); + QRandomGenerator rg[2] = {1, 2}; + uint pcnt = im.sizeInBytes() / sizeof(QRgb); + QRgb * data = (QRgb *)im.bits(); + for (uint i = 0; i < pcnt; ++i) { + double r = rg[0].generateDouble(); + double a = rg[0].generateDouble() * M_2PI; + double x = r * cos(a) / 2. + 0.5, y = r * sin(a) / 2. + 0.5; + data[i] = qRgba(qRound(x * 256), + qRound(y * 256), + (rg[1].generate() % sz.width()) % 256, + (rg[1].generate() % sz.height()) % 256); // argb GLSL + } + return im; +} diff --git a/src/core/core/gltypes.h b/src/core/core/gltypes.h index f11cb1f..07a1ab7 100644 --- a/src/core/core/gltypes.h +++ b/src/core/core/gltypes.h @@ -494,6 +494,7 @@ inline QVector3D directionFromAngles(const QVector3D & a) { inline float frac(const float & x, const float & b) { return x - int(x / b) * b; } +QImage generateNoise(QSize sz); #endif // GLTYPES_H diff --git a/src/core/render/renderer.cpp b/src/core/render/renderer.cpp index 3a8834a..ae155a2 100644 --- a/src/core/render/renderer.cpp +++ b/src/core/render/renderer.cpp @@ -205,6 +205,7 @@ void Renderer::initShaders() { prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i); prog->setUniformValue("tex_coeffs[0]", (int)Renderer::dbrBuffersCount); prog->setUniformValue("tex_env", (int)Renderer::dbrBuffersCount + 1); + prog->setUniformValue("tex_noise", (int)Renderer::dbrBuffersCount + 2); setUniformMaps(prog); prog->setUniformValue("tex_shadows_cone", (int)tarShadowsCone); } @@ -309,7 +310,7 @@ void Renderer::renderObjects(Scene & scene, RenderPass pass) { void Renderer::renderLight(int first_wr_buff, bool clear_only) { QOpenGLShaderProgram * prog = 0; Camera * cam = view->camera(); - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 3; ++i) { view->glActiveTexture(GL_TEXTURE0 + Renderer::dbrBuffersCount + i); view->glBindTexture(GL_TEXTURE_2D, tex_coeff[i]); } @@ -343,12 +344,20 @@ void Renderer::renderLight(int first_wr_buff, bool clear_only) { prog->setUniformValue("fog_density", view->fogDensity()); prog->setUniformValue("view_mat", cam->viewMatrix().inverted().toGenericMatrix<3, 3>()); prog->setUniformValue("shadow_size", view->shadow_map_size); + prog->setUniformValue("noise_size", noise_size); prog->setUniformValue("tex_shadows_cone", (int)tarShadowsCone); prog->setUniformValue("tex_shadows_omni", (int)tarShadowsOmni); + prog->setUniformValue("tex_depths_cone", (int)tarShadowsCone); + prog->setUniformValue("tex_depths_omni", (int)tarShadowsOmni); prog->setUniformValue("soft_shadows_enabled", view->soft_shadows); prog->setUniformValue("soft_shadows_samples", view->soft_shadows_samples); + GLenum filter = view->softShadows() ? GL_NEAREST : GL_LINEAR; shadow_maps_cone.bind(view, tarShadowsCone); + view->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, filter); + view->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, filter); shadow_maps_omni.bind(view, tarShadowsOmni); + view->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, filter); + view->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, filter); renderQuad(prog, quad, cam); } } @@ -364,8 +373,6 @@ void Renderer::renderConeShadows() { textures_maps.bind(f, tarMaps); auto cone_ll = cur_lights.value(Light::Cone); if (shadow_maps_cone.resize(f, view->shadow_map_size, cone_ll.size())) { - f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); @@ -400,8 +407,6 @@ void Renderer::renderOmniShadows() { textures_maps.bind(f, tarMaps); auto omni_ll = cur_lights.value(Light::Omni); if (shadow_maps_omni.resize(f, view->shadow_map_size, omni_ll.size())) { - f->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // f->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // f->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // f->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); @@ -550,7 +555,6 @@ void Renderer::renderScene() { setUniformCamera(prog, cam); textures_empty.bind(f, tarEmpty); textures_maps.bind(f, tarMaps); - shadow_maps_cone.bind(f, tarShadowsCone); glPolygonMode(GL_FRONT_AND_BACK, view->renderMode()); renderObjects(scene, rpSolid); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); diff --git a/src/core/render/renderer_base.cpp b/src/core/render/renderer_base.cpp index 2e32e51..018e1ce 100644 --- a/src/core/render/renderer_base.cpp +++ b/src/core/render/renderer_base.cpp @@ -42,7 +42,7 @@ RendererBase::RendererBase(QGLView * view_) textures_manager = new TextureManager(view); maps_size = QSize(1024, 1024); maps_hash = 0; - tex_coeff[0] = tex_coeff[1] = 0; + tex_coeff[0] = tex_coeff[1] = tex_coeff[2] = 0; } @@ -400,6 +400,7 @@ void RendererBase::initCoeffTextures() { } } createCoeffTexture(tex_coeff[0], data.constData(), size, 2); + createNoiseTexture(tex_coeff[2]); } @@ -428,3 +429,17 @@ void RendererBase::createCoeffTexture(GLuint & id, const void * data, int size, } f->glTexImage2D(GL_TEXTURE_2D, 0, iformat, size, size, 0, format, GL_FLOAT, data); } + + +void RendererBase::createNoiseTexture(GLuint & id) { + QOpenGLExtraFunctions * f = view; + deleteGLTexture(f, id); + f->glGenTextures(1, &id); + f->glBindTexture(GL_TEXTURE_2D, id); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + QImage im = generateNoise(QSize(noise_size, noise_size)); + f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width(), im.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits()); +} diff --git a/src/core/render/renderer_base.h b/src/core/render/renderer_base.h index 5411d90..92232f9 100644 --- a/src/core/render/renderer_base.h +++ b/src/core/render/renderer_base.h @@ -50,6 +50,7 @@ protected: void renderQuad(QOpenGLShaderProgram * prog, Mesh * mesh, Camera * cam = 0, bool uniforms = true); void initCoeffTextures(); void createCoeffTexture(GLuint & id, const void * data, int size, int channels = 1); + void createNoiseTexture(GLuint & id); QGLView * view; TextureManager * textures_manager; @@ -63,9 +64,10 @@ protected: CubeMapArray shadow_maps_omni; QSize maps_size; uint maps_hash; - GLuint tex_coeff[2]; + GLuint tex_coeff[3]; QMap lights_start; QList current_lights; + int noise_size = 256; }; #endif // RENDERER_BASE_H