1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-16 10:04:28 +02:00

#23 use all-in-one shadow map method for medium shadow quality settings

This commit is contained in:
XProger
2018-04-17 02:33:07 +03:00
parent f2bcbd341d
commit 76b8eecf9f
4 changed files with 93 additions and 58 deletions

View File

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

View File

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

View File

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

View File

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