diff --git a/shaders/ds_light.glsl b/shaders/ds_light.glsl index 32275fe..59dc3b3 100644 --- a/shaders/ds_light.glsl +++ b/shaders/ds_light.glsl @@ -16,11 +16,12 @@ void main(void) { in vec3 view_dir, world_dir; -uniform vec2 dt; +uniform vec2 dt, shadow_size; uniform float z_near; uniform sampler2D tex_coeffs[2]; uniform sampler2D tex_0, tex_1, tex_2, tex_3, tex_4, tex_sh; -uniform sampler2DShadow tex_shadow[16]; +//uniform sampler2DShadow tex_shadow[16]; +uniform sampler2DArray tex_shadows_cone; uniform samplerCube tex_env; uniform int lights_start, lights_count; @@ -34,16 +35,30 @@ const float PI = 3.1416; vec4 pos, lpos, shp; vec3 li, si, ldir, halfV, bn, bn2, lwdir; -//vec3 vds, vds2; +vec3 vds, vds2; float rough_diff, rough_spec, dist, NdotL, NdotH, spot, ldist, diff, spec, sdist, shadow; -vec4 mapScreenToShadow(in int light_index) { - vec4 shp = qgl_light_position[light_index].shadow_matrix * pos; - shp.z += 0.095; + +vec4 mapScreenToShadow(in int light_index, in vec3 offset) { + vec4 shp = qgl_light_position[light_index].shadow_matrix * (pos + vec4(offset, 0)); + shp.z -= 0.05; return shp; } +float getShadow(in vec3 uvz, in int layer) { + vec2 uvpix = uvz.xy * shadow_size + vec2(0.5f); + vec2 uvp = fract(uvpix), iuvp = vec2(1.f) - uvp; + vec4 gt = textureGather(tex_shadows_cone, vec3(floor(uvpix.xy) / shadow_size, layer), 0); + vec4 uvv; + uvv[0] = iuvp.x * uvp.y; + uvv[1] = uvp.x * uvp.y; + uvv[2] = uvp.x * iuvp.y; + uvv[3] = iuvp.x * iuvp.y; + return dot(step(vec4(uvz.z), gt), uvv); +} + + void calcLight(in int index, in vec3 n, in vec3 v) { lpos = qgl_light_position[index].position; ldir = lpos.xyz - (pos.xyz * lpos.w); @@ -59,39 +74,60 @@ 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); - spot *= textureProj(tex_shadow[index - lights_start], shp); - - /*//lwdir = mat3(mat_viewi) * qgl_Light[index].direction.xyz; - //bn = normalize(cross(lwdir, vec3(1, 0, 0))); - //bn2 = normalize(cross(lwdir, bn)); - float ds = ldist/200.;//max(abs(sdist) / 5000, 0.02); - //spot *= clamp(1. - sdist, 0, 1); - vds = ds * bn.xyz; - vds2 = ds * bn2.xyz; - float shadow = getShadow(index, pos.xyz, vec3(0)) * 3.; - shadow += getShadow(index, pos.xyz, vds ) * 2.; - shadow += getShadow(index, pos.xyz, - vds ) * 2.; - shadow += getShadow(index, pos.xyz, - vds2 ) * 2.; - shadow += getShadow(index, pos.xyz, + vds2 ) * 2.; - //shadow += getShadow(index, pos.xyz, vds - vds2 ) * 1.5; - //shadow += getShadow(index, pos.xyz, vds + vds2 ) * 1.5; - //shadow += getShadow(index, pos.xyz, - vds - vds2 ) * 1.5; - //shadow += getShadow(index, pos.xyz, - vds + vds2 ) * 1.5; - //shadow += getShadow(index, pos.xyz, vds + vds ); - //shadow += getShadow(index, pos.xyz, - vds - vds ); - //shadow += getShadow(index, pos.xyz, - vds2 - vds2); - //shadow += getShadow(index, pos.xyz, + vds2 + vds2); - //shadow += getShadow(index, pos.xyz, vds + vds - vds2 ); - //shadow += getShadow(index, pos.xyz, - vds - vds - vds2 ); - //shadow += getShadow(index, pos.xyz, vds + vds + vds2 ); - //shadow += getShadow(index, pos.xyz, - vds - vds + vds2 ); - //shadow += getShadow(index, pos.xyz, vds - vds2 - vds2); - //shadow += getShadow(index, pos.xyz, vds + vds2 + vds2); - //shadow += getShadow(index, pos.xyz, - vds - vds2 - vds2); - //shadow += getShadow(index, pos.xyz, - vds + vds2 + vds2); - //shadow += shadow += getShadow(index, pos.xyz, vds+vds2)*10; - spot *= mix(1., shadow / 11., shadow_on);*/ + if (qgl_light_parameter[index].flags == 1) { + + float ds = ldist/300.; + //float bias = ldist * 0.05; + vds = ds * bn.xyz; + vds2 = ds * bn2.xyz; + + int layer = index - lights_start; + float shadow = 0.; + vec4 shp = mapScreenToShadow(index, vec3(0)); + shp.xy /= shp.w; + //shp.z -= bias; + //for (int xi = -2; xi <= 2; ++xi) { + // for (int yi = -2; yi <= 2; ++yi) { + //shadow += step(shp.z, texture(tex_shadows_cone, vec3(shp.xy, layer), ivec2(0, 0)).r); + shadow = getShadow(shp.xyz, layer); + // } + //} + spot *= shadow;// / 25.f; + + //spot = texture(tex_shadows_cone, shp.xyz).r/20; + //spot = sz; + + /*//lwdir = mat3(mat_viewi) * qgl_Light[index].direction.xyz; + //bn = normalize(cross(lwdir, vec3(1, 0, 0))); + //bn2 = normalize(cross(lwdir, bn)); + float ds = ldist/200.;//max(abs(sdist) / 5000, 0.02); + //spot *= clamp(1. - sdist, 0, 1); + vds = ds * bn.xyz; + vds2 = ds * bn2.xyz; + float shadow = getShadow(index, pos.xyz, vec3(0)) * 3.; + shadow += getShadow(index, pos.xyz, vds ) * 2.; + shadow += getShadow(index, pos.xyz, - vds ) * 2.; + shadow += getShadow(index, pos.xyz, - vds2 ) * 2.; + shadow += getShadow(index, pos.xyz, + vds2 ) * 2.; + //shadow += getShadow(index, pos.xyz, vds - vds2 ) * 1.5; + //shadow += getShadow(index, pos.xyz, vds + vds2 ) * 1.5; + //shadow += getShadow(index, pos.xyz, - vds - vds2 ) * 1.5; + //shadow += getShadow(index, pos.xyz, - vds + vds2 ) * 1.5; + //shadow += getShadow(index, pos.xyz, vds + vds ); + //shadow += getShadow(index, pos.xyz, - vds - vds ); + //shadow += getShadow(index, pos.xyz, - vds2 - vds2); + //shadow += getShadow(index, pos.xyz, + vds2 + vds2); + //shadow += getShadow(index, pos.xyz, vds + vds - vds2 ); + //shadow += getShadow(index, pos.xyz, - vds - vds - vds2 ); + //shadow += getShadow(index, pos.xyz, vds + vds + vds2 ); + //shadow += getShadow(index, pos.xyz, - vds - vds + vds2 ); + //shadow += getShadow(index, pos.xyz, vds - vds2 - vds2); + //shadow += getShadow(index, pos.xyz, vds + vds2 + vds2); + //shadow += getShadow(index, pos.xyz, - vds - vds2 - vds2); + //shadow += getShadow(index, pos.xyz, - vds + vds2 + vds2); + //shadow += shadow += getShadow(index, pos.xyz, vds+vds2)*10; + spot *= mix(1., shadow / 11., shadow_on);*/ + } #endif vec3 dist_decay = vec3(1, ldist, ldist*ldist); spot /= dot(qgl_light_parameter[index].decay_intensity.xyz, dist_decay); @@ -156,8 +192,8 @@ void main(void) { float reflectivity = v2.b; float NdotV = dot(normal, v); float roughness3 = roughness*roughness*roughness; - //bn = normalize(vec3(v3.w, v4.zw)); - //bn2 = normalize(cross(n, bn)); + bn = normalize(cross(normal, view_dir)); + bn2 = normalize(cross(normal, bn)); rough_diff = max(roughness, _min_rough); rough_spec = max(roughness3, _min_rough); float shlick = clamp(metalness + (1 - metalness) * pow(1 - NdotV, 5), 0, 1); @@ -185,6 +221,7 @@ void main(void) { res_col = mix(res_col, fog_color.rgb, fog); qgl_FragColor = vec4(res_col, alpha); + //qgl_FragColor.rgb = view_dir; /* #ifdef SPOT vec4 wpos = vec4(world_dir * z, 1); diff --git a/shaders/shadow.glsl b/shaders/shadow.glsl index 679c292..e0de228 100644 --- a/shaders/shadow.glsl +++ b/shaders/shadow.glsl @@ -18,7 +18,6 @@ void main(void) { discard; float z = gl_FragCoord.z; - z = z + z - 1; - z = ((_pe - 2.) * z_near) / (z + _pe - 1.); // infinite depth - qgl_FragData[0] = vec4(z / 20); + z = ((_pe - 2.) * z_near) / (z + z + _pe - 2.); // infinite depth + qgl_FragData[0].r = z; } diff --git a/src/core/core/glshaders_headers.h b/src/core/core/glshaders_headers.h index 8187a78..2a94007 100644 --- a/src/core/core/glshaders_headers.h +++ b/src/core/core/glshaders_headers.h @@ -95,6 +95,7 @@ const char qgl_structs[] = "#define QGL_MAPS_COUNT 6\n" " vec4 color;\n" " vec4 decay_intensity;\n" " vec4 angles;\n" + " uint flags;\n" "};\n" "struct QGLLightPosition {\n" " vec4 position;\n" diff --git a/src/core/core/glshaders_types.h b/src/core/core/glshaders_types.h index 4598651..9d8e99d 100644 --- a/src/core/core/glshaders_types.h +++ b/src/core/core/glshaders_types.h @@ -98,8 +98,9 @@ enum MapType { mtShadowCone = 8, }; enum TextureArrayRole { - tarEmpty = 0, - tarMaps = 1, + tarEmpty = 0, + tarMaps = 1, + tarShadowsCone = 2, }; enum EmptyMapRole { emrWhite = 0, @@ -130,6 +131,8 @@ struct QGLLightParameter { QVector4D color; QVector4D decay_intensity; // [^0, ^1, ^2, intensity] QVector4D angles; // [start, cos(start), end, cos(end)] + GLuint flags = 0; + GLuint _align[3]; }; struct QGLLightPosition { QGLLightPosition() { QMatrix4x4().copyDataTo(shadowmatrix); } diff --git a/src/core/core/gltexturearray.cpp b/src/core/core/gltexturearray.cpp index f419fe5..c2d94ba 100644 --- a/src/core/core/gltexturearray.cpp +++ b/src/core/core/gltexturearray.cpp @@ -82,7 +82,13 @@ bool Texture2DArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layer f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST); f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } - f->glTexImage3D(target_, 0, GL_RGBA8, size_.width(), size_.height(), layers_, 0, format_, GL_UNSIGNED_BYTE, nullptr); + GLenum bformat = format_; + GLenum btype = GL_UNSIGNED_BYTE; + if (format_ == GL_R16F || format_ == GL_R32F) { + bformat = GL_RED; + btype = GL_FLOAT; + } + f->glTexImage3D(target_, 0, format_, size_.width(), size_.height(), layers_, 0, bformat, btype, nullptr); return true; } diff --git a/src/core/render/renderer.cpp b/src/core/render/renderer.cpp index f3f7dcc..a398c97 100644 --- a/src/core/render/renderer.cpp +++ b/src/core/render/renderer.cpp @@ -88,6 +88,7 @@ void Renderer::init(int width, int height) { buffer_lights_pos.reinit(); textures_maps.reinit(); textures_empty.reinit(); + shadow_maps_cone.reinit(); resize(width, height); rend_mat.init(width, height); rend_service.init(width, height); @@ -163,10 +164,14 @@ bool Renderer::bindShader(QOpenGLShaderProgram * sp) { void Renderer::initShaders() { if (!need_init_shaders) return; - need_init_shaders = false; + need_init_shaders = false; // initUniformBuffer(shaders.value(srGeometrySolidPass), &buffer_materials, bpMaterials, "QGLMaterialData"); // initUniformBuffer(shaders.value(srGeometryTransparentPass), &buffer_materials, bpMaterials, "QGLMaterialData"); // initUniformBuffer(shaders.value(srShadowPass), &buffer_materials, bpMaterials, "QGLMaterialData"); + QVector samplers; + samplers.resize(16); + for (int i = 0; i < samplers.size(); ++i) + samplers[i] = mtShadowCone + i; QOpenGLShaderProgram * prog = 0; for (ShaderRole role: {srLightOmniPass, srLightSpotPass}) { if (!bindShader(role, &prog)) continue; @@ -177,6 +182,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_shadows_cone", (int)tarShadowsCone); } if (bindShader(srFinalPass, &prog)) { prog->setUniformValue("tex_g1", 0); @@ -288,18 +294,14 @@ void Renderer::renderLight(int first_wr_buff, bool clear_only) { back.setAlpha(0); foreach(PassPair pass, passes) { if (bindShader(pass.first, &prog)) { - if (pass.second == Light::Cone) { - QVector samplers; - samplers.resize(16); + /*if (pass.second == Light::Cone) { auto & cone_ll(cur_lights[pass.second]); for (int i = 0; i < cone_ll.size(); ++i) { Light * l = cone_ll[i]; - l->shadow_map.bindDepthTexture(mtShadowCone + i); - // l->shadow_map.bindColorTexture(0, 10); - samplers[i] = mtShadowCone + i; + // l->shadow_map.bindDepthTexture(mtShadowCone + i); + l->shadow_map.bindColorTexture(0, mtShadowCone + i); } - prog->setUniformValueArray("tex_shadow", samplers.data(), samplers.size()); - } + }*/ fbo_out.setWriteBuffer(first_wr_buff + pass.second); glClearFramebuffer(back, false); if (clear_only) continue; @@ -311,13 +313,14 @@ void Renderer::renderLight(int first_wr_buff, bool clear_only) { prog->setUniformValue("fog_decay", qMax(view->fogDecay(), 0.001f)); prog->setUniformValue("fog_density", view->fogDensity()); prog->setUniformValue("view_mat", cam->viewMatrix().inverted().toGenericMatrix<3, 3>()); + prog->setUniformValue("shadow_size", view->shadow_map_size); renderQuad(prog, quad, cam); } } } -void Renderer::renderShadow(Light * light) { +void Renderer::renderShadow(int index, Light * light) { Scene & scene(*(view->scene())); bool force_resize = false; if (!light->shadow_map.isInit()) { @@ -325,12 +328,16 @@ void Renderer::renderShadow(Light * light) { force_resize = true; } light->shadow_map.resize(view->shadow_map_size, force_resize); - if (force_resize) { - light->shadow_map.bindDepthTexture(mtShadowCone); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } light->shadow_map.bind(); + + if (!framebufferTextureLayer) { + framebufferTextureLayer = view->context()->getProcAddress("glFramebufferTextureLayer"); + } + if (framebufferTextureLayer) { + ((PFNGLFRAMEBUFFERTEXTURELAYERPROC)framebufferTextureLayer)(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, shadow_maps_cone.ID(), 0, index); + // glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadow_maps_cone.ID(), 0, index); + } + glDrawBuffer(GL_COLOR_ATTACHMENT0); glClearFramebuffer(); renderObjects(scene, rpSolid); light->shadow_map.release(); @@ -378,11 +385,13 @@ void Renderer::renderScene() { textures_maps.bind(f, tarMaps); auto cam_ivm = cam->fullViewMatrix().inverted(); auto cone_ll = cur_lights.value(Light::Cone); + shadow_maps_cone.resize(f, view->shadow_map_size, cone_ll.size()); QMatrix4x4 mat_vp; mat_vp.scale(0.5, 0.5); mat_vp.translate(1, 1); for (int i = 0; i < cone_ll.size(); ++i) { - Light * l = cone_ll[i]; + Light * l = cone_ll[i]; + if (!l->isCastShadows()) continue; QMatrix4x4 pm = glMatrixPerspective(l->angle_end, 1., 0.1), om, vm; om.translate(-l->worldAim()); vm.translate(0., 0., -l->distance()); @@ -392,7 +401,7 @@ void Renderer::renderScene() { vm *= pmat.inverted(); auto vpm = pm * (vm * om); prog->setUniformValue("qgl_ViewProjMatrix", vpm); - renderShadow(l); + renderShadow(i, l); l->shadow_matrix = mat_vp * vpm * cam_ivm; } } @@ -432,12 +441,13 @@ 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); } fbo_ds.blit(dbrNormalZ, fbo_ds.id(), dbrNormalZSolid, fbo_ds.rect(), fbo_ds.rect()); - fbo_ds.blit(dbrSpecularReflect, fbo_ds.id(), dbrSpecularReflectSolid, fbo_ds.rect(), fbo_ds.rect()); + fbo_ds.blit(dbrMetalRoughReflectFlags, fbo_ds.id(), dbrMetalRoughReflectFlagsSolid, fbo_ds.rect(), fbo_ds.rect()); fbo_ds.release(); phase.end(); diff --git a/src/core/render/renderer.h b/src/core/render/renderer.h index ef26eb0..bcb0b55 100644 --- a/src/core/render/renderer.h +++ b/src/core/render/renderer.h @@ -81,12 +81,12 @@ public: enum DeferredBufferRole { dbrDiffuse, dbrNormalZ, - dbrSpecularReflect, - dbrEmissionRough, + dbrMetalRoughReflectFlags, + dbrEmission, dbrSpeedBitangXY, dbrNormalZSolid, - dbrSpecularReflectSolid, + dbrMetalRoughReflectFlagsSolid, dbrBuffersCount, }; @@ -113,7 +113,7 @@ protected: void reloadObjects(); void renderObjects(Scene & scene, RenderPass pass); void renderLight(int first_wr_buff, bool clear_only); - void renderShadow(Light * light); + void renderShadow(int index, Light * light); bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0); bool bindShader(QOpenGLShaderProgram * sp); @@ -151,7 +151,8 @@ private: QVector fb_effects; QImage last_img; QString timings; - bool is_grabbing = false; + bool is_grabbing = false; + QFunctionPointer framebufferTextureLayer = nullptr; }; #endif // RENDERER_H diff --git a/src/core/render/renderer_base.cpp b/src/core/render/renderer_base.cpp index 3f26d5e..a6cdb00 100644 --- a/src/core/render/renderer_base.cpp +++ b/src/core/render/renderer_base.cpp @@ -36,7 +36,8 @@ RendererBase::RendererBase(QGLView * view_) , buffer_lights(GL_UNIFORM_BUFFER, GL_STREAM_DRAW) , buffer_lights_pos(GL_UNIFORM_BUFFER, GL_STREAM_DRAW) , textures_empty(GL_RGBA, false) - , textures_maps(GL_RGBA, true) { + , textures_maps(GL_RGBA, true) + , shadow_maps_cone(GL_R32F, false) { textures_manager = new TextureManager(view); maps_size = QSize(1024, 1024); maps_hash = 0; @@ -60,6 +61,7 @@ void RendererBase::initTextureArrays() { textures_empty.load(f, im, emrWhite); im.fill(0xFF8080); textures_empty.load(f, im, emrBlue); + shadow_maps_cone.init(f); } @@ -223,6 +225,7 @@ void RendererBase::reloadLightsParameters(const QMap> & ligh so.decay_intensity[1] = l->decay_linear; so.decay_intensity[2] = l->decay_quadratic; so.decay_intensity[3] = l->intensity; + so.flags = l->cast_shadow ? 1 : 0; } buffer_lights.bind(view); buffer_lights.resize(view, cur_lights_params_.size() * sizeof(QGLLightParameter)); diff --git a/src/core/render/renderer_base.h b/src/core/render/renderer_base.h index cfb297a..a7edf0f 100644 --- a/src/core/render/renderer_base.h +++ b/src/core/render/renderer_base.h @@ -57,7 +57,7 @@ protected: QVector cur_lights_pos_; Buffer buffer_materials; Buffer buffer_lights, buffer_lights_pos; - Texture2DArray textures_empty, textures_maps; + Texture2DArray textures_empty, textures_maps, shadow_maps_cone; QSize maps_size; uint maps_hash; GLuint tex_coeff[2]; diff --git a/src/core/scene/globject.cpp b/src/core/scene/globject.cpp index 508d922..25315c4 100644 --- a/src/core/scene/globject.cpp +++ b/src/core/scene/globject.cpp @@ -223,6 +223,12 @@ void ObjectBase::setVisible(bool v) { } +void ObjectBase::setCastShadows(bool on) { + cast_shadow = on; + if (type_ == glLight) ((Light *)this)->apply(); +} + + void ObjectBase::rotateZ(GLfloat a) { raw_matrix = false; trans.setRotationZ(trans.rotationZ() + a); @@ -587,23 +593,12 @@ void AimedObject::orbitXY(const float & a) { void AimedObject::transformChanged() {} -Light::Light(): AimedObject(), shadow_map(nullptr, 1, true) { - type_ = glLight; - light_type = Omni; - intensity = 1.; - angle_start = angle_end = 180.; - decay_linear = decay_quadratic = decay_start = 0.; - decay_const = decay_end = 1.; - setDirection(0, 0, -1.); -} - - -Light::Light(const QVector3D & p, const QColor & c, float i): AimedObject(), shadow_map(nullptr, 1, true) { +Light::Light(const QVector3D & p, const QColor & c, float i): AimedObject(), shadow_map(nullptr, 0, true, GL_R32F) { type_ = glLight; light_type = Omni; intensity = i; color_ = c; - angle_start = angle_end = 180.; + angle_start = angle_end = 90.; decay_linear = decay_quadratic = decay_start = 0.; decay_const = decay_end = 1.; setPos(p); diff --git a/src/core/scene/globject.h b/src/core/scene/globject.h index 71f15fd..f22f1a3 100644 --- a/src/core/scene/globject.h +++ b/src/core/scene/globject.h @@ -85,7 +85,7 @@ public: bool isReceiveShadows() const { return rec_shadow; } bool isCastShadows() const { return cast_shadow; } void setReceiveShadows(bool on) { rec_shadow = on; } - void setCastShadows(bool on) { cast_shadow = on; } + void setCastShadows(bool on); void move(const QVector3D & dv) { trans.setTranslation(pos() + dv); @@ -398,8 +398,7 @@ public: Directional }; - Light(); - Light(const QVector3D & p, const QColor & c = Qt::white, float i = 1.); + Light(const QVector3D & p = QVector3D(), const QColor & c = Qt::white, float i = 1.); virtual ObjectBase * clone(bool withChildren = true); virtual void init() { shadow_map.resize(512, 512);