From 76b8eecf9f81763aa9f94b1d8a6c6951eb88e252 Mon Sep 17 00:00:00 2001 From: XProger Date: Tue, 17 Apr 2018 02:33:07 +0300 Subject: [PATCH] #23 use all-in-one shadow map method for medium shadow quality settings --- src/cache.h | 13 +++++-- src/core.h | 14 ++++--- src/level.h | 81 ++++++++++++++++++++++++++++++----------- src/shaders/shader.glsl | 43 ++++++++-------------- 4 files changed, 93 insertions(+), 58 deletions(-) diff --git a/src/cache.h b/src/cache.h index 52936f3..5878718 100644 --- a/src/cache.h +++ b/src/cache.h @@ -142,7 +142,7 @@ struct ShaderCache { src = SHADER; typ = typeNames[type]; - sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_CONTACTS %d\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEXEL vec3(1.0 / %d.0, 1.0 / %d.0, 0.0)\n#define SHADOW_OBJ_MAX %d\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_CONTACTS, WATER_FOG_DIST, SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, SHADOW_OBJ_MAX); + sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_CONTACTS %d\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_CONTACTS, WATER_FOG_DIST); #ifdef MERGE_SPRITES if (type == Shader::SPRITE) strcat(def, "#define ALIGN_SPRITES 1\n"); @@ -157,8 +157,15 @@ struct ShaderCache { strcat(def, "#define OPT_LIGHTING\n"); if (Core::settings.detail.lighting > Core::Settings::MEDIUM && (type == Shader::ENTITY)) strcat(def, "#define OPT_AMBIENT\n"); - if (Core::settings.detail.shadows > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM)) + if (Core::settings.detail.shadows > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM)) { strcat(def, "#define OPT_SHADOW\n"); + + if (Core::settings.detail.shadows > Core::Settings::MEDIUM) { + strcat(def, "#define OPT_SHADOW_HIGH\n"); + sprintf(def, "%s#define SHADOW_TEXEL vec3(1.0 / %d.0, 1.0 / %d.0, 0.0)\n#define SHADOW_OBJ_MAX %d\n", def, SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, SHADOW_OBJ_MAX); + } else + sprintf(def, "%s#define SHADOW_TEXEL vec3(1.0 / %d.0, 1.0 / %d.0, 0.0)\n#define SHADOW_OBJ_MAX %d\n", def, SHADOW_TEX_BIG_WIDTH, SHADOW_TEX_BIG_HEIGHT, 1); + } if (Core::settings.detail.shadows > Core::Settings::MEDIUM && (type == Shader::ROOM)) strcat(def, "#define OPT_CONTACT\n"); if (Core::settings.detail.water > Core::Settings::MEDIUM && (type == Shader::ENTITY || type == Shader::ROOM) && (fx & FX_UNDERWATER)) @@ -209,7 +216,7 @@ struct ShaderCache { shader->bind(); // TODO: bindable uniform block shader->setParam(uViewProj, Core::mViewProj); - shader->setParam(uLightProj, Core::mLightProj[0], SHADOW_OBJ_MAX); + shader->setParam(uLightProj, Core::mLightProj[0], Core::settings.detail.shadows > Core::Settings::Quality::MEDIUM ? SHADOW_OBJ_MAX : 1); shader->setParam(uViewPos, Core::viewPos); shader->setParam(uParam, Core::params); shader->setParam(uFogParams, Core::fogParams); diff --git a/src/core.h b/src/core.h index e302cd5..a706289 100644 --- a/src/core.h +++ b/src/core.h @@ -192,12 +192,14 @@ #include "utils.h" -#define SHADOW_OBJ_COLS 4 -#define SHADOW_OBJ_ROWS 2 -#define SHADOW_TEX_TILE 128 -#define SHADOW_TEX_WIDTH (SHADOW_OBJ_COLS * SHADOW_TEX_TILE) -#define SHADOW_TEX_HEIGHT (SHADOW_OBJ_ROWS * SHADOW_TEX_TILE) -#define SHADOW_OBJ_MAX (SHADOW_OBJ_COLS * SHADOW_OBJ_ROWS) +#define SHADOW_OBJ_COLS 4 +#define SHADOW_OBJ_ROWS 2 +#define SHADOW_TEX_TILE 128 +#define SHADOW_TEX_BIG_WIDTH 1024 +#define SHADOW_TEX_BIG_HEIGHT 1024 +#define SHADOW_TEX_WIDTH (SHADOW_OBJ_COLS * SHADOW_TEX_TILE) +#define SHADOW_TEX_HEIGHT (SHADOW_OBJ_ROWS * SHADOW_TEX_TILE) +#define SHADOW_OBJ_MAX (SHADOW_OBJ_COLS * SHADOW_OBJ_ROWS) extern void* osMutexInit (); extern void osMutexFree (void *obj); diff --git a/src/level.h b/src/level.h index 398dc13..f149a71 100644 --- a/src/level.h +++ b/src/level.h @@ -223,6 +223,16 @@ struct Level : IGame { } } + void initShadow() { + delete shadow; + if (Core::settings.detail.shadows > Core::Settings::MEDIUM) + shadow = new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, Texture::SHADOW); + else if (Core::settings.detail.shadows > Core::Settings::LOW) + shadow = new Texture(SHADOW_TEX_BIG_WIDTH, SHADOW_TEX_BIG_HEIGHT, Texture::SHADOW); + else + shadow = NULL; + } + virtual void applySettings(const Core::Settings &settings) { if (settings.detail.filter != Core::settings.detail.filter) atlas->setFilterQuality(settings.detail.filter); @@ -259,10 +269,8 @@ struct Level : IGame { ambientCache = Core::settings.detail.lighting > Core::Settings::MEDIUM ? new AmbientCache(this) : NULL; } - if (rebuildShadows) { - delete shadow; - shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, Texture::SHADOW) : NULL; - } + if (rebuildShadows) + initShadow(); if (rebuildWater) { delete waterCache; @@ -681,7 +689,9 @@ struct Level : IGame { zoneCache = new ZoneCache(this); ambientCache = Core::settings.detail.lighting > Core::Settings::MEDIUM ? new AmbientCache(this) : NULL; waterCache = Core::settings.detail.water > Core::Settings::LOW ? new WaterCache(this) : NULL; - shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, Texture::SHADOW) : NULL; + + shadow = NULL; + initShadow(); initReflections(); @@ -1931,7 +1941,27 @@ struct Level : IGame { camera->setup(false); } - void renderEntityShadow(int index, Controller *controller, Controller *player) { + void renderShadowView(int roomIndex) { + vec3 pos = player->getBoundingBox().center(); + + Core::mViewInv = mat4(player->mainLightPos, pos, vec3(0, -1, 0)); + Core::mView = Core::mViewInv.inverseOrtho(); + Core::mProj = mat4(90.0f, 1.0f, camera->znear, player->mainLightColor.w * 1.5f); + + mat4 bias; + bias.identity(); + bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; + + Core::mLightProj[0] = bias * (Core::mProj * Core::mView); + + camera->frustum->pos = Core::viewPos; + camera->frustum->calcPlanes(Core::mViewProj); + + setup(); + renderView(roomIndex, false, false); + } + + void renderShadowEntity(int index, Controller *controller, Controller *player) { Box box = controller->getSpheresBox(true); mat4 m = controller->getMatrix(); @@ -1940,8 +1970,7 @@ struct Level : IGame { Core::mView = Core::mViewInv.inverseOrtho(); Core::mProj = mat4(90.0f, 1.0f, 1.0f, 2.0f); - mat4 mLightProj = Core::mProj * Core::mView * m; - Box crop = box * (mLightProj); + Box crop = box * (Core::mProj * Core::mView * m); crop.min.z = max(0.0f, crop.min.z); float sx = 2.0f / (crop.max.x - crop.min.x); @@ -1954,14 +1983,13 @@ struct Level : IGame { Core::mProj = mat4(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, - ox, oy, oz, 1) * Core::mProj; + ox, oy, oz, 1) * Core::mProj; Core::setViewProj(Core::mView, Core::mProj); mat4 bias; bias.identity(); - bias.e00 = bias.e11 = bias.e22 = 0.5f; - bias.e03 = bias.e13 = bias.e23 = 0.5f; + bias.e00 = bias.e11 = bias.e22 = bias.e03 = bias.e13 = bias.e23 = 0.5f; Core::mLightProj[index] = bias * (Core::mProj * Core::mView); Core::setBlending(bmNone); @@ -2032,9 +2060,9 @@ struct Level : IGame { void renderShadows(int roomIndex) { PROFILE_MARKER("PASS_SHADOW"); - // get near objects - NearObj nearObj[SHADOW_OBJ_MAX]; - int nearCount = getNearObjects(nearObj, SHADOW_OBJ_MAX); + if (Core::settings.detail.shadows == Core::Settings::Quality::LOW) + return; + ASSERT(shadow); // render to shadow map float oldEye = Core::eye; @@ -2050,13 +2078,19 @@ struct Level : IGame { Core::setCulling(cfBack); - for (int i = 0; i < nearCount; i++) { - Core::setViewport((i % SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, (i / SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, SHADOW_TEX_TILE, SHADOW_TEX_TILE); - renderEntityShadow(i, (Controller*)level.entities[nearObj[i].index].controller, players[nearObj[i].player]); - } + if (Core::settings.detail.shadows > Core::Settings::Quality::MEDIUM) { // per-object shadow map (atlas) + NearObj nearObj[SHADOW_OBJ_MAX]; + int nearCount = getNearObjects(nearObj, SHADOW_OBJ_MAX); - for (int i = nearCount; i < SHADOW_OBJ_MAX; i++) - Core::mLightProj[i].identity(); + for (int i = 0; i < nearCount; i++) { + Core::setViewport((i % SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, (i / SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, SHADOW_TEX_TILE, SHADOW_TEX_TILE); + renderShadowEntity(i, (Controller*)level.entities[nearObj[i].index].controller, players[nearObj[i].player]); + } + + for (int i = nearCount; i < SHADOW_OBJ_MAX; i++) + Core::mLightProj[i].identity(); + } else // all-in-one shadow map + renderShadowView(roomIndex); Core::setCulling(cfFront); if (colorShadow) @@ -2350,7 +2384,12 @@ struct Level : IGame { params->clipSign = 1.0f; params->waterHeight = params->clipHeight; - if (shadow) shadow->bind(sShadow); + if (shadow) { + if (view > 0 && Core::settings.detail.shadows < Core::Settings::Quality::HIGH) + renderShadows(player->getRoomIndex()); // render shadows for player2 for all-in-one shadow technique + shadow->bind(sShadow); + } + Core::pass = Core::passCompose; /* if (view == 0 && Input::hmd.ready) { diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index 724223e..963226c 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -14,7 +14,10 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - trapezoidal correction uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ #endif -uniform mat4 uLightProj[SHADOW_OBJ_MAX]; +#ifdef OPT_SHADOW + uniform mat4 uLightProj[SHADOW_OBJ_MAX]; +#endif + uniform mat4 uViewProj; uniform vec3 uViewPos; uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height @@ -283,28 +286,18 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha } #endif - float random(vec3 seed, float freq) { - float dt = dot(floor(seed * freq), vec3(53.1215, 21.1352, 9.1322)); - return fract(sin(dt) * 2105.2354); - } - - float randomAngle(vec3 seed, float freq) { - return random(seed, freq) * 6.283285; - } - - vec3 rotate(vec2 sc, vec2 v) { - return vec3(v.x * sc.y + v.y * sc.x, v.x * -sc.x + v.y * sc.y, 0.0); - } - float getShadow(vec4 lightProj, vec2 tileOffset) { vec3 p = lightProj.xyz / lightProj.w; + float vis = lightProj.w; #ifdef TYPE_ROOM vis = min(vis, dot(vNormal.xyz, vLightVec.xyz)); #endif if (vis < 0.0 || p.x < 0.0 || p.y < 0.0 || p.x > 1.0 || p.y > 1.0) return 1.0; - p.xy = p.xy * vec2(0.25, 0.5) + tileOffset; + #ifdef OPT_SHADOW_HIGH + p.xy = p.xy * vec2(0.25, 0.5) + tileOffset; + #endif float rShadow =(SHADOW(SHADOW_TEXEL * vec3(-0.5, -0.5, 0.0) + p) + SHADOW(SHADOW_TEXEL * vec3( 0.5, -0.5, 0.0) + p) + @@ -315,9 +308,10 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha return rShadow + (1.0 - rShadow) * fade; } - float getShadow() { // hardcoded for 4x2 shadow atlas + float getShadow() { vec4 c = vec4(vCoord, 1.0); - return min(min(min(min(min(min(min( + #ifdef OPT_SHADOW_HIGH + return min(min(min(min(min(min(min( // hardcoded for 4x2 shadow atlas getShadow(uLightProj[0] * c, vec2(0.00, 0.0)), getShadow(uLightProj[1] * c, vec2(0.25, 0.0))), getShadow(uLightProj[2] * c, vec2(0.50, 0.0))), @@ -326,6 +320,9 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha getShadow(uLightProj[5] * c, vec2(0.25, 0.5))), getShadow(uLightProj[6] * c, vec2(0.50, 0.5))), getShadow(uLightProj[7] * c, vec2(0.75, 0.5))); + #else + return getShadow(uLightProj[0] * c, vec2(0.0, 0.0)); + #endif } #endif @@ -457,19 +454,9 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha color.xyz = mix(uFogParams.xyz, color.xyz, vLightVec.w); #endif #endif -/* catsuit test - #elif defined(TYPE_MIRROR) - color.xyz += calcSpecular(normalize(vNormal.xyz), vViewVec.xyz, vLightVec.xyz, uLightColor[0], 0.4); - color.w = 1.0; -*/ - #endif - - #ifdef TYPE_PARTICLE_SPRITE - gl_FragColor = vec4(color.xyz * max(1.0 - vNormal.w, color.w), color.w * vNormal.w); // premultiplied - #else - gl_FragColor = color; #endif + gl_FragColor = color; #endif } #endif