soft shadows done

This commit is contained in:
2023-02-18 19:12:16 +03:00
parent eb5f50fc9d
commit 91bc31e7db
6 changed files with 157 additions and 25 deletions

View File

@@ -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);

View File

@@ -21,6 +21,7 @@
#include "qglview.h"
#include <QPainter>
#include <QRandomGenerator>
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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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());
}

View File

@@ -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<int, int> lights_start;
QList<Light *> current_lights;
int noise_size = 256;
};
#endif // RENDERER_BASE_H