mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-19 11:21:31 +02:00
#23 refactoring of shader system
This commit is contained in:
187
src/cache.h
187
src/cache.h
@@ -11,6 +11,7 @@
|
||||
#define FOG_DIST (18 * 1024)
|
||||
#define WATER_FOG_DIST (8 * 1024)
|
||||
//#define WATER_USE_GRID
|
||||
#define UNDERWATER_COLOR "#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9)\n"
|
||||
|
||||
const char SHADER[] =
|
||||
#include "shader.glsl"
|
||||
@@ -29,46 +30,55 @@ const char GUI[] =
|
||||
;
|
||||
|
||||
struct ShaderCache {
|
||||
enum Effect { FX_NONE = 0, FX_UNDERWATER = 1, FX_ALPHA_TEST = 2, FX_CLIP_PLANE = 4 };
|
||||
|
||||
IGame *game;
|
||||
Shader *shaders[Core::passMAX][Shader::MAX][2][2][2];
|
||||
Shader *shaders[Core::passMAX][Shader::MAX][(FX_UNDERWATER | FX_ALPHA_TEST | FX_CLIP_PLANE) + 1];
|
||||
|
||||
ShaderCache(IGame *game) : game(game) {
|
||||
memset(shaders, 0, sizeof(shaders));
|
||||
|
||||
LOG("shader: cache warm up...\n");
|
||||
compile(Core::passShadow , Shader::ENTITY, false, false, false);
|
||||
if (Core::settings.shadows)
|
||||
compile(Core::passShadow, Shader::ENTITY, FX_NONE);
|
||||
|
||||
compile(Core::passAmbient, Shader::ROOM, false, false, false);
|
||||
compile(Core::passAmbient, Shader::ROOM, false, true, false);
|
||||
compile(Core::passAmbient, Shader::ROOM, false, false, true);
|
||||
compile(Core::passAmbient, Shader::ROOM, false, true, true);
|
||||
compile(Core::passAmbient, Shader::ROOM, true, false, false);
|
||||
compile(Core::passAmbient, Shader::SPRITE, false, true, false);
|
||||
compile(Core::passAmbient, Shader::SPRITE, false, true, true);
|
||||
if (Core::settings.ambient) {
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_NONE);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_CLIP_PLANE);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_UNDERWATER);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_UNDERWATER | FX_CLIP_PLANE);
|
||||
compile(Core::passAmbient, Shader::SPRITE, FX_ALPHA_TEST);
|
||||
compile(Core::passAmbient, Shader::SPRITE, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
}
|
||||
|
||||
compile(Core::passCompose, Shader::ROOM, false, false, false);
|
||||
compile(Core::passCompose, Shader::ROOM, false, true, false);
|
||||
compile(Core::passCompose, Shader::ROOM, false, true, true);
|
||||
compile(Core::passCompose, Shader::ROOM, false, false, true);
|
||||
compile(Core::passCompose, Shader::ROOM, true, false, false);
|
||||
compile(Core::passCompose, Shader::ROOM, true, false, true);
|
||||
compile(Core::passCompose, Shader::ENTITY, false, false, false);
|
||||
compile(Core::passCompose, Shader::ENTITY, false, false, true);
|
||||
compile(Core::passCompose, Shader::ENTITY, true, false, false);
|
||||
compile(Core::passCompose, Shader::ENTITY, true, false, true);
|
||||
compile(Core::passCompose, Shader::SPRITE, false, true, false);
|
||||
compile(Core::passCompose, Shader::SPRITE, false, true, true);
|
||||
compile(Core::passCompose, Shader::SPRITE, true, true, false);
|
||||
compile(Core::passCompose, Shader::SPRITE, true, true, true);
|
||||
compile(Core::passCompose, Shader::FLASH, false, true, false);
|
||||
if (Core::settings.water) {
|
||||
compile(Core::passWater, Shader::WATER_MASK, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_STEP, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_CAUSTICS, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_COMPOSE, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_DROP, FX_NONE);
|
||||
}
|
||||
|
||||
compile(Core::passFilter , Shader::FILTER_DOWNSAMPLE, false, false, false);
|
||||
compile(Core::passFilter, Shader::FILTER_DOWNSAMPLE, FX_NONE);
|
||||
|
||||
compile(Core::passWater , Shader::WATER_MASK, false, false, false);
|
||||
compile(Core::passWater , Shader::WATER_STEP, false, false, false);
|
||||
compile(Core::passWater , Shader::WATER_CAUSTICS, false, false, false);
|
||||
compile(Core::passWater , Shader::WATER_COMPOSE, false, false, false);
|
||||
compile(Core::passWater , Shader::WATER_DROP, false, false, false);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_NONE);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_UNDERWATER);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_UNDERWATER | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_NONE);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_UNDERWATER);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_UNDERWATER | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_UNDERWATER | FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_UNDERWATER | FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::FLASH, FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::MIRROR, FX_NONE);
|
||||
|
||||
LOG("shader: cache is ready\n");
|
||||
}
|
||||
@@ -76,25 +86,26 @@ struct ShaderCache {
|
||||
~ShaderCache() {
|
||||
for (int pass = 0; pass < Core::passMAX; pass++)
|
||||
for (int type = 0; type < Shader::MAX; type++)
|
||||
for (int caustics = 0; caustics < 2; caustics++)
|
||||
for (int alphaTest = 0; alphaTest < 2; alphaTest++)
|
||||
for (int clipPlane = 0; clipPlane < 2; clipPlane++)
|
||||
delete shaders[pass][type][caustics][alphaTest][clipPlane];
|
||||
for (int fx = 0; fx < sizeof(shaders[Core::passMAX][Shader::MAX]) / sizeof(shaders[Core::passMAX][Shader::MAX][FX_NONE]); fx++)
|
||||
delete shaders[pass][type][fx];
|
||||
}
|
||||
|
||||
Shader* compile(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false, bool clipPlane = false) {
|
||||
Shader* compile(Core::Pass pass, Shader::Type type, int fx) {
|
||||
char def[1024], ext[255];
|
||||
ext[0] = 0;
|
||||
if (Core::support.shadowSampler) {
|
||||
#ifdef MOBILE
|
||||
strcat(ext, "#extension GL_EXT_shadow_samplers : require\n");
|
||||
#endif
|
||||
strcat(ext, "#define SHADOW_SAMPLER\n");
|
||||
} else
|
||||
if (Core::support.depthTexture)
|
||||
strcat(ext, "#define SHADOW_DEPTH\n");
|
||||
else
|
||||
strcat(ext, "#define SHADOW_COLOR\n");
|
||||
if (Core::settings.shadows) {
|
||||
if (Core::support.shadowSampler) {
|
||||
#ifdef MOBILE
|
||||
strcat(ext, "#extension GL_EXT_shadow_samplers : require\n");
|
||||
#endif
|
||||
strcat(ext, "#define SHADOW_SAMPLER\n");
|
||||
} else {
|
||||
if (Core::support.depthTexture)
|
||||
strcat(ext, "#define SHADOW_DEPTH\n");
|
||||
else
|
||||
strcat(ext, "#define SHADOW_COLOR\n");
|
||||
}
|
||||
}
|
||||
|
||||
const char *passNames[] = { "COMPOSE", "SHADOW", "AMBIENT", "FILTER", "WATER" };
|
||||
const char *src = NULL;
|
||||
@@ -109,16 +120,20 @@ struct ShaderCache {
|
||||
int animTexRangesCount = game->getMesh()->animTexRangesCount;
|
||||
int animTexOffsetsCount = game->getMesh()->animTexOffsetsCount;
|
||||
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST);
|
||||
if (caustics) strcat(def, "#define CAUSTICS\n");
|
||||
if (alphaTest) strcat(def, "#define ALPHA_TEST\n");
|
||||
if (clipPlane) strcat(def, "#define CLIP_PLANE\n");
|
||||
if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR);
|
||||
if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\n");
|
||||
if (fx & FX_CLIP_PLANE) strcat(def, "#define CLIP_PLANE\n");
|
||||
if (Core::settings.ambient) strcat(def, "#define OPT_AMBIENT\n");
|
||||
if (Core::settings.lighting) strcat(def, "#define OPT_LIGHTING\n");
|
||||
if (Core::settings.shadows) strcat(def, "#define OPT_SHADOW\n");
|
||||
if (Core::settings.water) strcat(def, "#define OPT_WATER\n");
|
||||
break;
|
||||
}
|
||||
case Core::passWater : {
|
||||
static const char *typeNames[] = { "DROP", "STEP", "CAUSTICS", "MASK", "COMPOSE" };
|
||||
src = WATER;
|
||||
typ = typeNames[type];
|
||||
sprintf(def, "%s#define PASS_%s\n#define WATER_%s\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, WATER_FOG_DIST);
|
||||
sprintf(def, "%s#define PASS_%s\n#define WATER_%s\n#define WATER_FOG_DIST (1.0/%d.0)\n" UNDERWATER_COLOR, ext, passNames[pass], typ, WATER_FOG_DIST);
|
||||
#ifdef WATER_USE_GRID
|
||||
strcat(def, "#define WATER_USE_GRID\n");
|
||||
#endif
|
||||
@@ -133,17 +148,26 @@ struct ShaderCache {
|
||||
}
|
||||
default : ASSERT(false);
|
||||
}
|
||||
LOG("shader: compile %s -> %s %s%s%s\n", passNames[pass], typ, caustics ? "caustics " : "", alphaTest ? "alphaTest " : "", clipPlane ? "clipPlane" : "");
|
||||
return shaders[pass][type][caustics][alphaTest][clipPlane] = new Shader(src, def);
|
||||
LOG("shader: compile %s -> %s %s%s%s\n", passNames[pass], typ, (fx & FX_UNDERWATER) ? "underwater " : "", (fx & FX_ALPHA_TEST) ? "alphaTest " : "", (fx & FX_CLIP_PLANE) ? "clipPlane" : "");
|
||||
return shaders[pass][type][fx] = new Shader(src, def);
|
||||
}
|
||||
|
||||
void bind(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false, bool clipPlane = false) {
|
||||
void bind(Core::Pass pass, Shader::Type type, int fx) {
|
||||
Core::pass = pass;
|
||||
Shader *shader = shaders[pass][type][caustics][alphaTest][clipPlane];
|
||||
Shader *shader = shaders[pass][type][fx];
|
||||
if (!shader)
|
||||
shader = compile(pass, type, caustics, alphaTest, clipPlane);
|
||||
shader = compile(pass, type, fx);
|
||||
ASSERT(shader != NULL);
|
||||
shader->bind();
|
||||
// TODO: bindable uniform block
|
||||
shader->setParam(uViewProj, Core::mViewProj);
|
||||
shader->setParam(uLightProj, Core::mLightProj);
|
||||
shader->setParam(uViewInv, Core::mViewInv);
|
||||
shader->setParam(uViewPos, Core::viewPos);
|
||||
shader->setParam(uParam, Core::params);
|
||||
MeshBuilder *mesh = game->getMesh();
|
||||
shader->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||
shader->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -220,7 +244,7 @@ struct AmbientCache {
|
||||
// second pass - downsample it
|
||||
Core::setDepthTest(false);
|
||||
|
||||
game->setShader(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false);
|
||||
game->setShader(Core::passFilter, Shader::FILTER_DOWNSAMPLE);
|
||||
|
||||
for (int i = 1; i < 4; i++) {
|
||||
int size = 64 >> (i << 1);
|
||||
@@ -291,7 +315,6 @@ struct WaterCache {
|
||||
TR::Level *level;
|
||||
Texture *refract;
|
||||
Texture *reflect;
|
||||
vec3 color;
|
||||
|
||||
struct Item {
|
||||
int from, to, caust;
|
||||
@@ -312,6 +335,7 @@ struct WaterCache {
|
||||
}
|
||||
|
||||
void init(IGame *game) {
|
||||
|
||||
TR::Level *level = game->getLevel();
|
||||
TR::Room &r = level->rooms[to]; // underwater room
|
||||
|
||||
@@ -356,21 +380,22 @@ struct WaterCache {
|
||||
}
|
||||
}
|
||||
|
||||
m[(x - minX) + w * (z - minZ)] = hasWater ? (hasFlow ? 0xFFFF : 0xFF00) : 0;
|
||||
m[(x - minX) + w * (z - minZ)] = hasWater ? (hasFlow ? 0xF81F : 0xF800) : 0;
|
||||
}
|
||||
mask = new Texture(w, h, Texture::RGB16, false, m, false);
|
||||
delete[] m;
|
||||
|
||||
size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size
|
||||
pos = vec3(r.info.x + minX * 1024 + size.x, float(posY), r.info.z + minZ * 1024 + size.z);
|
||||
|
||||
data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF, false);
|
||||
data[1] = new Texture(data[0]->width, data[0]->height, Texture::RGBA_HALF, false);
|
||||
data[1] = new Texture(w * 64, h * 64, Texture::RGBA_HALF, false);
|
||||
caustics = new Texture(512, 512, Texture::RGB16, false);
|
||||
mask = new Texture(w, h, Texture::RGB16, false, m, false);
|
||||
delete[] m;
|
||||
|
||||
blank = false;
|
||||
|
||||
Core::setTarget(data[0], true);
|
||||
Core::invalidateTarget(false, true);
|
||||
// Core::setTarget(data[0], true);
|
||||
// Core::invalidateTarget(false, true);
|
||||
}
|
||||
|
||||
void free() {
|
||||
@@ -394,7 +419,7 @@ struct WaterCache {
|
||||
Drop(const vec3 &pos, float radius, float strength) : pos(pos), radius(radius), strength(strength) {}
|
||||
} drops[MAX_DROPS];
|
||||
|
||||
WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), color(0.6f, 0.9f, 0.9f), count(0), checkVisibility(false), dropCount(0) {
|
||||
WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), count(0), checkVisibility(false), dropCount(0) {
|
||||
reflect = new Texture(512, 512, Texture::RGB16, false);
|
||||
}
|
||||
|
||||
@@ -494,7 +519,7 @@ struct WaterCache {
|
||||
void drop(Item &item) {
|
||||
if (!dropCount) return;
|
||||
|
||||
game->setShader(Core::passWater, Shader::WATER_DROP, false);
|
||||
game->setShader(Core::passWater, Shader::WATER_DROP);
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
|
||||
|
||||
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) };
|
||||
@@ -520,7 +545,7 @@ struct WaterCache {
|
||||
void step(Item &item) {
|
||||
if (item.timer < SIMULATE_TIMESTEP) return;
|
||||
|
||||
game->setShader(Core::passWater, Shader::WATER_STEP, false);
|
||||
game->setShader(Core::passWater, Shader::WATER_STEP);
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
|
||||
Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0));
|
||||
|
||||
@@ -537,7 +562,7 @@ struct WaterCache {
|
||||
|
||||
|
||||
// calc caustics
|
||||
game->setShader(Core::passWater, Shader::WATER_CAUSTICS, false);
|
||||
game->setShader(Core::passWater, Shader::WATER_CAUSTICS);
|
||||
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) };
|
||||
Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
|
||||
|
||||
@@ -557,11 +582,19 @@ struct WaterCache {
|
||||
if (!visible) return;
|
||||
|
||||
// mask underwater geometry by zero alpha
|
||||
game->setShader(Core::passWater, Shader::WATER_MASK, false);
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
if (item.visible && item.blank)
|
||||
item.init(game);
|
||||
}
|
||||
Core::setTarget(NULL);
|
||||
|
||||
game->setShader(Core::passWater, Shader::WATER_MASK);
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f));
|
||||
Core::setCulling(cfNone);
|
||||
Core::setDepthWrite(false);
|
||||
|
||||
Core::setColorWrite(false, false, false, true);
|
||||
Core::setDepthWrite(false);
|
||||
Core::setCulling(cfNone);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
@@ -587,11 +620,6 @@ struct WaterCache {
|
||||
Item &item = items[i];
|
||||
if (!item.visible) continue;
|
||||
|
||||
if (item.blank) {
|
||||
item.init(game);
|
||||
item.blank = false;
|
||||
}
|
||||
|
||||
// render mirror reflection
|
||||
Core::setTarget(reflect, true);
|
||||
vec3 p = item.pos;
|
||||
@@ -639,13 +667,10 @@ struct WaterCache {
|
||||
Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius));
|
||||
}
|
||||
|
||||
game->setShader(Core::passWater, Shader::WATER_COMPOSE, false);
|
||||
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
||||
Core::active.shader->setParam(uViewPos, Core::viewPos);
|
||||
game->setShader(Core::passWater, Shader::WATER_COMPOSE);
|
||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
|
||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
|
||||
Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.05f, 0.02f));
|
||||
Core::active.shader->setParam(uColor, vec4(color * 0.2f, 1.0f));
|
||||
|
||||
float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
|
||||
float sz = item.size.z * DETAIL / (item.data[0]->height / 2);
|
||||
@@ -659,9 +684,9 @@ struct WaterCache {
|
||||
#ifdef WATER_USE_GRID
|
||||
vec3 rPosScale[2] = { item.pos, item.size * vec3(1.0f / PLANE_DETAIL, 512.0f, 1.0f / PLANE_DETAIL) };
|
||||
Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
|
||||
level->mesh->renderPlane();
|
||||
game->getMesh()->renderPlane();
|
||||
#else
|
||||
Core::active.shader->setParam(uPosScale, item.pos, 2);
|
||||
Core::active.shader->setParam(uPosScale, item.pos, 2);
|
||||
game->getMesh()->renderQuad();
|
||||
#endif
|
||||
Core::setCulling(cfFront);
|
||||
@@ -716,4 +741,6 @@ struct LightCache {
|
||||
};
|
||||
*/
|
||||
|
||||
#undef UNDERWATER_COLOR
|
||||
|
||||
#endif
|
@@ -161,7 +161,7 @@ struct Camera : Controller {
|
||||
if (Input::down[ikS]) v = v - d;
|
||||
if (Input::down[ikA]) v = v + d.cross(vec3(0, 1, 0));
|
||||
if (Input::down[ikD]) v = v - d.cross(vec3(0, 1, 0));
|
||||
pos = pos + v.normal() * (Core::deltaTime * 512.0 * 10.0f);
|
||||
pos = pos + v.normal() * (Core::deltaTime * 512.0f * 10.0f);
|
||||
|
||||
mViewInv.identity();
|
||||
mViewInv.translate(pos);
|
||||
|
@@ -24,7 +24,7 @@ struct IGame {
|
||||
virtual void setWaterParams(float height) {}
|
||||
virtual void updateParams() {}
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
|
||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false) {}
|
||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {}
|
||||
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
|
||||
virtual void renderCompose(int roomIndex) {}
|
||||
};
|
||||
@@ -487,21 +487,45 @@ struct Controller {
|
||||
return matrix;
|
||||
}
|
||||
|
||||
/*
|
||||
void renderShadow(MeshBuilder *mesh, const vec3 &pos, const vec3 &offset, const vec3 &size, float angle) {
|
||||
/*
|
||||
mat4 m;
|
||||
m.identity();
|
||||
m.translate(pos);
|
||||
m.rotateY(angle);
|
||||
m.translate(vec3(offset.x, 0.0f, offset.z));
|
||||
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
|
||||
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
|
||||
|
||||
Core::active.shader->setParam(uModel, m);
|
||||
Core::active.shader->setParam(uColor, vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
game->setShader(Core::pass, Shader::FLASH, false, false);
|
||||
Core::active.shader->setParam(uBasis, Basis(m));
|
||||
Core::active.shader->setParam(uColor, vec4(0.5f, 0.5f, 0.5f, 1.0f));
|
||||
Core::active.shader->setParam(uAmbient, vec3(0.0f));
|
||||
|
||||
Core::setBlending(bmMultiply);
|
||||
mesh->renderShadowSpot();
|
||||
Core::setBlending(bmNone);
|
||||
*/
|
||||
mat4 m = Core::mViewProj;
|
||||
m.translate(pos);
|
||||
m.rotateY(angle);
|
||||
m.translate(vec3(offset.x, 0.0f, offset.z));
|
||||
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
|
||||
|
||||
Basis b;
|
||||
b.identity();
|
||||
|
||||
game->setShader(Core::pass, Shader::FLASH, false, false);
|
||||
Core::active.shader->setParam(uViewProj, m);
|
||||
Core::active.shader->setParam(uBasis, b);
|
||||
Core::active.shader->setParam(uMaterial, vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
Core::active.shader->setParam(uAmbient, vec3(0.0f));
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
mesh->renderShadowSpot();
|
||||
Core::setBlending(bmNone);
|
||||
|
||||
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
||||
}
|
||||
*/
|
||||
|
||||
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { // TODO: animation.calcJoints
|
||||
mat4 matrix = getMatrix();
|
||||
@@ -540,13 +564,12 @@ struct Controller {
|
||||
|
||||
frameIndex = Core::frameIndex;
|
||||
|
||||
/* // blob shadow // TODO: fake AO
|
||||
if (TR::castShadow(entity.type)) {
|
||||
// blob shadow // TODO: fake AO
|
||||
if (!Core::settings.shadows && Core::pass == Core::passCompose && TR::castShadow(entity.type)) {
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(entity.room, entity.x, entity.y, entity.z, info);
|
||||
renderShadow(mesh, vec3(float(entity.x), info.floor - 16.0f, float(entity.z)), box.center(), box.size() * 0.8f, angle.y);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
68
src/core.h
68
src/core.h
@@ -183,6 +183,9 @@ struct Texture;
|
||||
#define PROFILE_LABEL(id, name, label)
|
||||
#endif
|
||||
|
||||
enum CullMode { cfNone, cfBack, cfFront };
|
||||
enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen };
|
||||
|
||||
namespace Core {
|
||||
int width, height;
|
||||
int frameIndex;
|
||||
@@ -192,7 +195,7 @@ namespace Core {
|
||||
vec3 viewPos;
|
||||
vec3 lightPos[MAX_LIGHTS];
|
||||
vec4 lightColor[MAX_LIGHTS];
|
||||
vec4 color;
|
||||
vec4 params;
|
||||
|
||||
Texture *blackTex, *whiteTex;
|
||||
|
||||
@@ -209,10 +212,13 @@ namespace Core {
|
||||
} rtCache[2];
|
||||
|
||||
struct {
|
||||
Shader *shader;
|
||||
Texture *textures[8];
|
||||
Texture *target;
|
||||
GLuint VAO;
|
||||
Shader *shader;
|
||||
Texture *textures[8];
|
||||
Texture *target;
|
||||
int targetFace;
|
||||
GLuint VAO;
|
||||
BlendMode blendMode;
|
||||
CullMode cullMode;
|
||||
} active;
|
||||
|
||||
struct {
|
||||
@@ -230,15 +236,19 @@ namespace Core {
|
||||
bool texHalf, texHalfLinear;
|
||||
bool shaderBinary;
|
||||
} support;
|
||||
|
||||
struct {
|
||||
bool ambient;
|
||||
bool lighting;
|
||||
bool shadows;
|
||||
bool water;
|
||||
} settings;
|
||||
}
|
||||
|
||||
#include "texture.h"
|
||||
#include "shader.h"
|
||||
#include "mesh.h"
|
||||
|
||||
enum CullMode { cfNone, cfBack, cfFront };
|
||||
enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen };
|
||||
|
||||
namespace Core {
|
||||
|
||||
bool extSupport(const char *str, const char *ext) {
|
||||
@@ -336,8 +346,8 @@ namespace Core {
|
||||
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
||||
LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false");
|
||||
LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false");
|
||||
LOG(" discard frame : %s\n", support.discardFrame ? "true" : "false");
|
||||
LOG(" NPOT textures : %s\n", support.texNPOT ? "true" : "false");
|
||||
LOG(" discard frame : %s\n", support.discardFrame ? "true" : "false");
|
||||
LOG(" NPOT textures : %s\n", support.texNPOT ? "true" : "false");
|
||||
LOG(" float textures : float = %s, half = %s\n",
|
||||
support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false",
|
||||
support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false");
|
||||
@@ -353,10 +363,10 @@ namespace Core {
|
||||
|
||||
frameIndex = 0;
|
||||
|
||||
uint32 data = 0xFF000000;
|
||||
blackTex = new Texture(1, 1, Texture::RGBA, false, &data);
|
||||
uint32 data = 0x00000000;
|
||||
blackTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
|
||||
data = 0xFFFFFFFF;
|
||||
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data);
|
||||
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
|
||||
}
|
||||
|
||||
void free() {
|
||||
@@ -396,17 +406,23 @@ namespace Core {
|
||||
return cache.count++;
|
||||
}
|
||||
|
||||
void clear(bool clearColor, bool clearDepth, const vec4 &color) {
|
||||
glClearColor(color.x, color.y, color.z, color.w);
|
||||
void clear(bool clearColor, bool clearDepth) {
|
||||
if (GLbitfield mask = (clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0))
|
||||
glClear(mask);
|
||||
}
|
||||
|
||||
void setClearColor(const vec4 &color) {
|
||||
glClearColor(color.x, color.y, color.z, color.w);
|
||||
}
|
||||
|
||||
void setViewport(int x, int y, int width, int height) {
|
||||
glViewport(x, y, width, height);
|
||||
}
|
||||
|
||||
void setCulling(CullMode mode) {
|
||||
if (active.cullMode == mode)
|
||||
return;
|
||||
|
||||
switch (mode) {
|
||||
case cfNone :
|
||||
glDisable(GL_CULL_FACE);
|
||||
@@ -418,11 +434,16 @@ namespace Core {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode != cfNone)
|
||||
if (mode != cfNone && active.cullMode == cfNone)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
active.cullMode = mode;
|
||||
}
|
||||
|
||||
void setBlending(BlendMode mode) {
|
||||
if (active.blendMode == mode)
|
||||
return;
|
||||
|
||||
switch (mode) {
|
||||
case bmNone :
|
||||
glDisable(GL_BLEND);
|
||||
@@ -441,8 +462,10 @@ namespace Core {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode != bmNone)
|
||||
if (mode != bmNone && active.blendMode == bmNone)
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
active.blendMode = mode;
|
||||
}
|
||||
|
||||
void setColorWrite(bool r, bool g, bool b, bool a) {
|
||||
@@ -473,6 +496,9 @@ namespace Core {
|
||||
}
|
||||
|
||||
void setTarget(Texture *target, bool clear = false, int face = 0) {
|
||||
if (target == active.target && face == active.targetFace)
|
||||
return;
|
||||
|
||||
if (!target) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glColorMask(true, true, true, true);
|
||||
@@ -493,10 +519,12 @@ namespace Core {
|
||||
glColorMask(false, false, false, false);
|
||||
setViewport(0, 0, target->width, target->height);
|
||||
}
|
||||
active.target = target;
|
||||
|
||||
if (clear)
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
active.target = target;
|
||||
active.targetFace = face;
|
||||
}
|
||||
|
||||
void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) {
|
||||
@@ -506,7 +534,9 @@ namespace Core {
|
||||
|
||||
void resetStates() {
|
||||
memset(&active, 0, sizeof(active));
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
setDepthTest(true);
|
||||
active.blendMode = bmAlpha;
|
||||
active.cullMode = cfNone;
|
||||
setCulling(cfFront);
|
||||
setBlending(bmNone);
|
||||
}
|
||||
|
@@ -20,6 +20,12 @@ namespace Game {
|
||||
|
||||
void init(Stream *lvl, Stream *snd) {
|
||||
Core::init();
|
||||
|
||||
Core::settings.ambient = true;
|
||||
Core::settings.lighting = true;
|
||||
Core::settings.shadows = true;
|
||||
Core::settings.water = Core::support.texFloat || Core::support.texHalf;
|
||||
|
||||
level = NULL;
|
||||
startLevel(lvl, snd, false, false);
|
||||
}
|
||||
|
@@ -213,6 +213,7 @@ struct Lara : Character {
|
||||
Inventory inventory;
|
||||
int lastPickUp;
|
||||
int viewTarget;
|
||||
int roomPrev; // water out from room
|
||||
|
||||
struct Braid {
|
||||
Lara *lara;
|
||||
@@ -405,7 +406,7 @@ struct Lara : Character {
|
||||
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
|
||||
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
|
||||
|
||||
#ifdef _DEBUG
|
||||
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool)
|
||||
|
||||
@@ -1063,6 +1064,7 @@ struct Lara : Character {
|
||||
|
||||
if (h >= 0 && h <= (256 + 128) && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) {
|
||||
alignToWall(LARA_RADIUS);
|
||||
roomPrev = getRoomIndex();
|
||||
getEntity().room = roomAbove;
|
||||
pos.y = float(info.floor);
|
||||
specular = LARA_WET_SPECULAR;
|
||||
@@ -1555,6 +1557,7 @@ struct Lara : Character {
|
||||
|
||||
if (state != STATE_SURF_TREAD && state != STATE_SURF_LEFT && state != STATE_SURF_RIGHT && state != STATE_SURF_SWIM && state != STATE_SURF_BACK && state != STATE_STOP) {
|
||||
game->waterDrop(pos, 128.0f, 0.2f);
|
||||
specular = LARA_WET_SPECULAR;
|
||||
return animation.setAnim(ANIM_TO_ONWATER);
|
||||
}
|
||||
|
||||
@@ -2011,7 +2014,7 @@ struct Lara : Character {
|
||||
Basis b(basis);
|
||||
b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f));
|
||||
b.translate(offset);
|
||||
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
|
||||
Core::active.shader->setParam(uMaterial, vec4(lum, 0.0f, 0.0f, alpha));
|
||||
Core::active.shader->setParam(uBasis, b);
|
||||
mesh->renderModel(level->extra.muzzleFlash);
|
||||
}
|
||||
|
213
src/level.h
213
src/level.h
@@ -24,12 +24,12 @@ struct Level : IGame {
|
||||
Camera *camera;
|
||||
Texture *shadow;
|
||||
|
||||
struct {
|
||||
struct Params {
|
||||
float time;
|
||||
float waterHeight;
|
||||
float clipSign;
|
||||
float clipHeight;
|
||||
} params;
|
||||
} *params = (Params*)&Core::params;
|
||||
|
||||
ShaderCache *shaderCache;
|
||||
AmbientCache *ambientCache;
|
||||
@@ -49,24 +49,25 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
virtual void setClipParams(float clipSign, float clipHeight) {
|
||||
params.clipSign = clipSign;
|
||||
params.clipHeight = clipHeight;
|
||||
params->clipSign = clipSign;
|
||||
params->clipHeight = clipHeight;
|
||||
}
|
||||
|
||||
virtual void setWaterParams(float height) {
|
||||
params.waterHeight = height;
|
||||
params->waterHeight = height;
|
||||
}
|
||||
|
||||
virtual void updateParams() {
|
||||
Core::active.shader->setParam(uParam, *((vec4*)¶ms));
|
||||
Core::active.shader->setParam(uParam, Core::params);
|
||||
}
|
||||
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {
|
||||
waterCache->addDrop(pos, radius, strength);
|
||||
if (waterCache)
|
||||
waterCache->addDrop(pos, radius, strength);
|
||||
}
|
||||
|
||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false) {
|
||||
shaderCache->bind(pass, type, caustics, alphaTest, params.clipHeight != NO_CLIP_PLANE);
|
||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {
|
||||
shaderCache->bind(pass, type, (underwater ? ShaderCache::FX_UNDERWATER : 0) | (alphaTest ? ShaderCache::FX_ALPHA_TEST : 0) | (params->clipHeight != NO_CLIP_PLANE ? ShaderCache::FX_CLIP_PLANE : 0));
|
||||
}
|
||||
|
||||
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {
|
||||
@@ -88,13 +89,14 @@ struct Level : IGame {
|
||||
|
||||
Core::setDepthTest(true);
|
||||
Core::setDepthWrite(true);
|
||||
shadow->bind(sShadow);
|
||||
if (shadow)
|
||||
shadow->bind(sShadow);
|
||||
renderScene(roomIndex);
|
||||
}
|
||||
//==============================
|
||||
|
||||
Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL) {
|
||||
params.time = 0.0f;
|
||||
params->time = 0.0f;
|
||||
|
||||
#ifdef _DEBUG
|
||||
Debug::init();
|
||||
@@ -204,8 +206,9 @@ struct Level : IGame {
|
||||
|
||||
level.cameraController = camera;
|
||||
|
||||
ambientCache = new AmbientCache(this);
|
||||
waterCache = new WaterCache(this);
|
||||
ambientCache = Core::settings.ambient ? new AmbientCache(this) : NULL;
|
||||
waterCache = Core::settings.water ? new WaterCache(this) : NULL;
|
||||
shadow = Core::settings.shadows ? new Texture(1024, 1024, Texture::SHADOW, false) : NULL;
|
||||
|
||||
initReflections();
|
||||
for (int i = 0; i < level.soundSourcesCount; i++) {
|
||||
@@ -236,8 +239,6 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
void initTextures() {
|
||||
shadow = new Texture(1024, 1024, Texture::SHADOW, false);
|
||||
|
||||
if (!level.tilesCount) {
|
||||
atlas = NULL;
|
||||
return;
|
||||
@@ -327,95 +328,28 @@ struct Level : IGame {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LEVEL_EDITOR
|
||||
struct Light {
|
||||
vec3 pos;
|
||||
float radius;
|
||||
float intensity;
|
||||
} lights[255];
|
||||
int lightsCount = 0;
|
||||
int lightIntensity = 0.5f;
|
||||
float lightRadius = 4096.0f;
|
||||
|
||||
int findLight(const vec3 &pos, float maxDist) const {
|
||||
int index = 0;
|
||||
for (int i = 0; i < lightsCount; i++) {
|
||||
float d = (lights[i].pos - pos).length();
|
||||
if (d < maxDist) {
|
||||
maxDist = d;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void addLight(const vec3 &pos, float radius) {
|
||||
int index = findLight(pos, 1024.0f);
|
||||
if (index > -1) {
|
||||
lightRadius = lights[index].radius;
|
||||
lightIntensity = lights[index].intensity;
|
||||
} else
|
||||
index = lightsCount++;
|
||||
|
||||
lights[index].pos = pos;
|
||||
lights[index].radius = radius;
|
||||
}
|
||||
|
||||
void removeLight(const vec3 &pos) {
|
||||
int index = findLight(pos, 1024.0f);
|
||||
if (index > -1)
|
||||
lights[index] = lights[--lightsCount];
|
||||
}
|
||||
|
||||
void updateLight(const vec3 &pos, float addRadius, float addIntensity) {
|
||||
int index = findLight(pos, 1024.0f);
|
||||
if (index > -1) {
|
||||
lights[index].radius = max(lights[index].radius + addRadius, 256.0f);
|
||||
lights[index].intensity = clamp(lights[index].intensity + addIntensity, 0.0f, 1.0f);
|
||||
lightRadius = lights[index].radius;
|
||||
lightIntensity = lights[index].intensity;
|
||||
}
|
||||
}
|
||||
|
||||
void updateEditor() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void renderEditor() {
|
||||
#ifdef _DEBUG
|
||||
Debug::begin();
|
||||
|
||||
Debug::end();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void setRoomParams(int roomIndex, float intensity, Shader::Type type, bool alphaTest = false) {
|
||||
void setRoomParams(int roomIndex, Shader::Type type, float diffuse, float ambient, float specular, float alpha, bool alphaTest = false) {
|
||||
if (Core::pass == Core::passShadow) {
|
||||
setShader(Core::pass, type, false);
|
||||
setShader(Core::pass, type);
|
||||
return;
|
||||
}
|
||||
|
||||
TR::Room &room = level.rooms[roomIndex];
|
||||
|
||||
if (room.flags.water)
|
||||
setWaterParams(float(room.info.yTop));
|
||||
else
|
||||
setWaterParams(NO_CLIP_PLANE);
|
||||
|
||||
setShader(Core::pass, type, room.flags.water, alphaTest);
|
||||
|
||||
if (room.flags.water) {
|
||||
Core::color = vec4(waterCache->color, intensity);
|
||||
/*
|
||||
// trace to water surface room
|
||||
int wrIndex = roomIndex;
|
||||
if (waterCache)
|
||||
waterCache->bindCaustics(roomIndex);
|
||||
setWaterParams(float(room.info.yTop));
|
||||
}
|
||||
|
||||
room.sectors[sx * room.zSectors + sz];
|
||||
|
||||
int sx = room.xSectors
|
||||
*/
|
||||
waterCache->bindCaustics(roomIndex);
|
||||
} else
|
||||
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
|
||||
|
||||
Core::active.shader->setParam(uColor, Core::color);
|
||||
Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha));
|
||||
}
|
||||
|
||||
void renderRoom(int roomIndex, int from = TR::NO_ROOM) {
|
||||
@@ -427,7 +361,7 @@ struct Level : IGame {
|
||||
|
||||
// room geometry & sprites
|
||||
if (!room.flags.rendered) { // skip if already rendered
|
||||
if (room.flags.water)
|
||||
if (waterCache && room.flags.water)
|
||||
waterCache->setVisible(roomIndex);
|
||||
|
||||
room.flags.rendered = true;
|
||||
@@ -445,7 +379,7 @@ struct Level : IGame {
|
||||
|
||||
Core::setBlending(transp ? bmAlpha : bmNone);
|
||||
|
||||
setRoomParams(roomIndex, intensityf(room.ambient), Shader::ROOM, transp > 0);
|
||||
setRoomParams(roomIndex, Shader::ROOM, 1.0f, intensityf(room.ambient), 0.0f, 1.0f, transp > 0);
|
||||
Shader *sh = Core::active.shader;
|
||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
@@ -458,7 +392,7 @@ struct Level : IGame {
|
||||
// render room sprites
|
||||
if (range.sprites.iCount) {
|
||||
Core::setBlending(bmAlpha);
|
||||
setRoomParams(roomIndex, 1.0, Shader::SPRITE, true);
|
||||
setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true);
|
||||
Shader *sh = Core::active.shader;
|
||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
@@ -494,7 +428,7 @@ struct Level : IGame {
|
||||
|
||||
frustum = *camFrustum;
|
||||
if (frustum.clipByPortal(v, 4, p.normal)) {
|
||||
if ((level.rooms[roomIndex].flags.water ^ level.rooms[p.roomIndex].flags.water) && v[0].y == v[1].y && v[0].y == v[2].y)
|
||||
if (waterCache &&(level.rooms[roomIndex].flags.water ^ level.rooms[p.roomIndex].flags.water) && v[0].y == v[1].y && v[0].y == v[2].y)
|
||||
waterCache->setVisible(roomIndex, p.roomIndex);
|
||||
renderRoom(p.roomIndex, roomIndex);
|
||||
}
|
||||
@@ -556,6 +490,7 @@ struct Level : IGame {
|
||||
|
||||
Controller *controller = (Controller*)entity.controller;
|
||||
|
||||
|
||||
TR::Room &room = level.rooms[entity.room];
|
||||
if (!room.flags.rendered || entity.flags.invisible || entity.flags.rendered)
|
||||
return;
|
||||
@@ -566,25 +501,29 @@ struct Level : IGame {
|
||||
if (entity.type == TR::Entity::CRYSTAL)
|
||||
type = Shader::MIRROR;
|
||||
|
||||
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum), type, !isModel);
|
||||
int roomIndex = entity.room;
|
||||
// if (entity.type == TR::Entity::LARA && ((Lara*)entity.controller)->state == Lara::STATE_WATER_OUT)
|
||||
// roomIndex = ((Lara*)entity.controller)->roomPrev;
|
||||
|
||||
setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? mesh->models[entity.modelIndex].opaque : true);
|
||||
|
||||
if (isModel) { // model
|
||||
vec3 pos = controller->getPos();
|
||||
AmbientCache::Cube cube;
|
||||
if (Core::frameIndex != controller->frameIndex) {
|
||||
ambientCache->getAmbient(entity.room, pos, cube);
|
||||
if (cube.status == AmbientCache::Cube::READY)
|
||||
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
|
||||
if (Core::settings.ambient) {
|
||||
AmbientCache::Cube cube;
|
||||
if (Core::frameIndex != controller->frameIndex) {
|
||||
ambientCache->getAmbient(entity.room, pos, cube);
|
||||
if (cube.status == AmbientCache::Cube::READY)
|
||||
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
|
||||
}
|
||||
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
|
||||
}
|
||||
getLight(pos, entity.room);
|
||||
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
|
||||
} else { // sprite
|
||||
Core::lightPos[0] = vec3(0);
|
||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
||||
Core::active.shader->setParam(uLightProj, Core::mLightProj);
|
||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
|
||||
@@ -592,7 +531,7 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
void update() {
|
||||
params.time += Core::deltaTime;
|
||||
params->time += Core::deltaTime;
|
||||
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
TR::Entity &e = level.entities[i];
|
||||
@@ -601,7 +540,7 @@ struct Level : IGame {
|
||||
if (controller) {
|
||||
controller->update();
|
||||
|
||||
if (e.type == TR::Entity::WATERFALL && ((Waterfall*)controller)->drop) { // add water drops for waterfalls
|
||||
if (waterCache && e.type == TR::Entity::WATERFALL && ((Waterfall*)controller)->drop) { // add water drops for waterfalls
|
||||
Waterfall *w = (Waterfall*)controller;
|
||||
waterCache->addDrop(w->dropPos, w->dropRadius, w->dropStrength);
|
||||
}
|
||||
@@ -610,7 +549,8 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
camera->update();
|
||||
waterCache->update();
|
||||
if (waterCache)
|
||||
waterCache->update();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
@@ -627,22 +567,6 @@ struct Level : IGame {
|
||||
if (!Core::support.VAO)
|
||||
mesh->bind();
|
||||
//Core::mViewProj = Core::mLightProj;
|
||||
// set frame constants for all shaders
|
||||
for (int i = 0; i < sizeof(shaderCache->shaders[Core::pass]) / sizeof(shaderCache->shaders[Core::pass][0]); i++) {
|
||||
Shader **ptr = &shaderCache->shaders[Core::pass][i][0][0][0];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
Shader *sh = *ptr++;
|
||||
if (!sh) continue;
|
||||
sh->bind();
|
||||
sh->setParam(uViewProj, Core::mViewProj);
|
||||
sh->setParam(uLightProj, Core::mLightProj);
|
||||
sh->setParam(uViewInv, Core::mViewInv);
|
||||
sh->setParam(uViewPos, Core::viewPos);
|
||||
sh->setParam(uParam, *((vec4*)¶ms));
|
||||
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||
}
|
||||
}
|
||||
Core::basis.identity();
|
||||
|
||||
// clear visibility flag for rooms
|
||||
@@ -731,35 +655,42 @@ struct Level : IGame {
|
||||
shadow->unbind(sShadow);
|
||||
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
|
||||
if (colorShadow)
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
Core::setClearColor(vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
Core::setTarget(shadow, true);
|
||||
Core::setCulling(cfBack);
|
||||
renderScene(roomIndex);
|
||||
Core::invalidateTarget(!colorShadow, colorShadow);
|
||||
Core::setCulling(cfFront);
|
||||
if (colorShadow)
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
Core::setClearColor(vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
void render() {
|
||||
Core::invalidateTarget(true, true);
|
||||
params.clipHeight = NO_CLIP_PLANE;
|
||||
params.clipSign = 1.0f;
|
||||
params.waterHeight = params.clipHeight;
|
||||
params->clipHeight = NO_CLIP_PLANE;
|
||||
params->clipSign = 1.0f;
|
||||
params->waterHeight = params->clipHeight;
|
||||
Core::resetStates();
|
||||
|
||||
ambientCache->precessQueue();
|
||||
waterCache->reset();
|
||||
if (ambientCache)
|
||||
ambientCache->precessQueue();
|
||||
if (waterCache)
|
||||
waterCache->reset();
|
||||
if (shadow)
|
||||
renderShadows(lara->getRoomIndex());
|
||||
|
||||
renderShadows(lara->getRoomIndex());
|
||||
Core::setTarget(NULL, true);
|
||||
Core::setViewport(0, 0, Core::width, Core::height);
|
||||
|
||||
waterCache->checkVisibility = true;
|
||||
renderCompose(camera->getRoomIndex());
|
||||
waterCache->checkVisibility = false;
|
||||
if (waterCache)
|
||||
waterCache->checkVisibility = true;
|
||||
|
||||
waterCache->render();
|
||||
renderCompose(camera->getRoomIndex());
|
||||
|
||||
if (waterCache) {
|
||||
waterCache->checkVisibility = false;
|
||||
waterCache->render();
|
||||
}
|
||||
|
||||
// Core::mViewInv = camera->mViewInv;
|
||||
// Core::mView = Core::mViewInv.inverse();
|
||||
@@ -832,8 +763,8 @@ struct Level : IGame {
|
||||
glEnd();
|
||||
Core::setDepthTest(true);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
@@ -871,7 +802,7 @@ struct Level : IGame {
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
*/
|
||||
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
@@ -886,7 +817,7 @@ struct Level : IGame {
|
||||
|
||||
/*
|
||||
static int dbg_ambient = 0;
|
||||
dbg_ambient = int(params.time * 2) % 4;
|
||||
dbg_ambient = int(params->time * 2) % 4;
|
||||
|
||||
shadow->unbind(sShadow);
|
||||
atlas->bind(sDiffuse);
|
||||
|
54
src/mesh.h
54
src/mesh.h
@@ -138,7 +138,10 @@ struct MeshBuilder {
|
||||
MeshRange sprites;
|
||||
MeshRange **meshes;
|
||||
} *rooms;
|
||||
MeshRange *models;
|
||||
struct ModelRange {
|
||||
MeshRange geometry;
|
||||
bool opaque;
|
||||
} *models;
|
||||
MeshRange *sequences;
|
||||
// procedured
|
||||
MeshRange shadowBlob;
|
||||
@@ -180,7 +183,8 @@ struct MeshBuilder {
|
||||
iCount += d.rCount * 6 + d.tCount * 3;
|
||||
vCount += d.rCount * 4 + d.tCount * 3;
|
||||
|
||||
roomRemoveWaterSurfaces(r, iCount, vCount);
|
||||
if (Core::settings.water)
|
||||
roomRemoveWaterSurfaces(r, iCount, vCount);
|
||||
|
||||
for (int j = 0; j < r.meshesCount; j++) {
|
||||
TR::Room::Mesh &m = r.meshes[j];
|
||||
@@ -203,7 +207,7 @@ struct MeshBuilder {
|
||||
}
|
||||
|
||||
// get models info
|
||||
models = new MeshRange[level.modelsCount];
|
||||
models = new ModelRange[level.modelsCount];
|
||||
for (int i = 0; i < level.modelsCount; i++) {
|
||||
TR::Model &model = level.models[i];
|
||||
for (int j = 0; j < model.mCount; j++) {
|
||||
@@ -311,21 +315,23 @@ struct MeshBuilder {
|
||||
// build models geometry
|
||||
for (int i = 0; i < level.modelsCount; i++) {
|
||||
TR::Model &model = level.models[i];
|
||||
MeshRange &range = models[i];
|
||||
ModelRange &range = models[i];
|
||||
int vStart = vCount;
|
||||
range.vStart = vStart;
|
||||
range.iStart = iCount;
|
||||
range.geometry.vStart = vStart;
|
||||
range.geometry.iStart = iCount;
|
||||
range.opaque = true;
|
||||
|
||||
for (int j = 0; j < model.mCount; j++) {
|
||||
int index = level.meshOffsets[model.mStart + j];
|
||||
if (!index && model.mStart + j > 0) continue;
|
||||
aCount++;
|
||||
TR::Mesh &mesh = level.meshes[index];
|
||||
buildMesh( true, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
|
||||
buildMesh(false, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
|
||||
bool opaque = buildMesh(true, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
|
||||
if (!opaque)
|
||||
buildMesh(false, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
|
||||
range.opaque &= opaque;
|
||||
}
|
||||
|
||||
range.iCount = iCount - range.iStart;
|
||||
range.geometry.iCount = iCount - range.geometry.iStart;
|
||||
}
|
||||
|
||||
// build sprite sequences
|
||||
@@ -429,7 +435,7 @@ struct MeshBuilder {
|
||||
for (int i = 0; i < level.spriteSequencesCount; i++)
|
||||
mesh->initRange(sequences[i]);
|
||||
for (int i = 0; i < level.modelsCount; i++)
|
||||
mesh->initRange(models[i]);
|
||||
mesh->initRange(models[i].geometry);
|
||||
mesh->initRange(shadowBlob);
|
||||
mesh->initRange(bar);
|
||||
mesh->initRange(quad);
|
||||
@@ -538,8 +544,9 @@ struct MeshBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
void buildRoom(bool opaque, const TR::Room &room, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) {
|
||||
bool buildRoom(bool opaque, const TR::Room &room, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) {
|
||||
const TR::Room::Data &d = room.data;
|
||||
bool isOpaque = true;
|
||||
|
||||
for (int j = 0; j < d.rCount; j++) {
|
||||
TR::Rectangle &f = d.rectangles[j];
|
||||
@@ -547,6 +554,9 @@ struct MeshBuilder {
|
||||
|
||||
if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes)
|
||||
|
||||
if (t.attribute != 0)
|
||||
isOpaque = false;
|
||||
|
||||
if (opaque != (t.attribute == 0))
|
||||
continue;
|
||||
|
||||
@@ -570,6 +580,9 @@ struct MeshBuilder {
|
||||
|
||||
if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes)
|
||||
|
||||
if (t.attribute != 0)
|
||||
isOpaque = false;
|
||||
|
||||
if (opaque != (t.attribute == 0))
|
||||
continue;
|
||||
|
||||
@@ -586,16 +599,22 @@ struct MeshBuilder {
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return isOpaque;
|
||||
}
|
||||
|
||||
void buildMesh(bool opaque, const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) {
|
||||
bool buildMesh(bool opaque, const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) {
|
||||
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
|
||||
bool isOpaque = true;
|
||||
|
||||
for (int j = 0; j < mesh.rCount; j++) {
|
||||
TR::Rectangle &f = mesh.rectangles[j];
|
||||
bool textured = !(f.texture & 0x8000);
|
||||
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile;
|
||||
|
||||
if (t.attribute != 0)
|
||||
isOpaque = false;
|
||||
|
||||
if (opaque != (t.attribute == 0))
|
||||
continue;
|
||||
|
||||
@@ -619,6 +638,9 @@ struct MeshBuilder {
|
||||
bool textured = !(f.texture & 0x8000);
|
||||
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile;
|
||||
|
||||
if (t.attribute != 0)
|
||||
isOpaque = false;
|
||||
|
||||
if (opaque != (t.attribute == 0))
|
||||
continue;
|
||||
|
||||
@@ -636,6 +658,8 @@ struct MeshBuilder {
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return isOpaque;
|
||||
}
|
||||
|
||||
vec2 getTexCoord(const TR::ObjectTexture &tex) {
|
||||
@@ -791,7 +815,7 @@ struct MeshBuilder {
|
||||
}
|
||||
|
||||
void renderModel(int modelIndex) {
|
||||
mesh->render(models[modelIndex]);
|
||||
mesh->render(models[modelIndex].geometry);
|
||||
}
|
||||
|
||||
void renderSprite(int sequenceIndex, int frame) {
|
||||
@@ -860,7 +884,7 @@ struct MeshBuilder {
|
||||
|
||||
if (!text) return;
|
||||
|
||||
Core::active.shader->setParam(uColor, color);
|
||||
Core::active.shader->setParam(uMaterial, vec4(1.0, 0.0, 0.0, 1.0));
|
||||
//text = "a: b";
|
||||
Basis basis;
|
||||
basis.identity();
|
||||
|
289
src/shader.glsl
289
src/shader.glsl
@@ -12,18 +12,19 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
#ifndef PASS_AMBIENT
|
||||
varying vec3 vCoord;
|
||||
varying vec4 vNormal;
|
||||
varying vec3 vViewVec;
|
||||
varying vec4 vLightProj;
|
||||
varying vec3 vCoord;
|
||||
varying vec4 vNormal;
|
||||
varying vec3 vViewVec;
|
||||
varying vec4 vLightProj;
|
||||
#endif
|
||||
varying vec4 vColor;
|
||||
varying vec4 vColor;
|
||||
uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
uniform vec3 uViewPos;
|
||||
uniform vec4 uParam;
|
||||
#ifdef CAUSTICS
|
||||
uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height
|
||||
#ifdef UNDERWATER
|
||||
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
|
||||
#endif
|
||||
#endif
|
||||
@@ -82,6 +83,15 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
vColor = aColor;
|
||||
vColor.xyz *= uMaterial.x; // apply diffuse intensity
|
||||
#ifdef TYPE_MIRROR
|
||||
vColor.xyz *= vec3(0.6, 0.6, 4.0); // blue color dodge for crystal
|
||||
#endif
|
||||
#ifdef UNDERWATER
|
||||
#ifndef TYPE_ENTITY
|
||||
vColor.xyz *= UNDERWATER_COLOR; // underwater blue color
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
@@ -95,7 +105,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
|
||||
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
|
||||
|
||||
#ifdef CAUSTICS
|
||||
#ifdef UNDERWATER
|
||||
float sum = coord.x + coord.y + coord.z;
|
||||
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
|
||||
#endif
|
||||
@@ -105,7 +115,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
|
||||
#endif
|
||||
|
||||
#ifdef CAUSTICS
|
||||
#ifdef UNDERWATER
|
||||
vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
|
||||
#else
|
||||
vTexCoord.zw = vec2(1.0);
|
||||
@@ -123,14 +133,23 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
gl_Position = uViewProj * coord;
|
||||
}
|
||||
#else
|
||||
uniform sampler2D sDiffuse;
|
||||
uniform sampler2D sReflect;
|
||||
uniform vec4 uColor;
|
||||
uniform sampler2D sDiffuse;
|
||||
|
||||
#if defined(UNDERWATER) && defined(OPT_WATER)
|
||||
uniform sampler2D sReflect;
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
uniform samplerCube sEnvironment;
|
||||
uniform vec3 uLightPos[MAX_LIGHTS];
|
||||
uniform vec4 uLightColor[MAX_LIGHTS];
|
||||
uniform vec3 uAmbient[6];
|
||||
#ifdef TYPE_MIRROR
|
||||
uniform samplerCube sEnvironment;
|
||||
#endif
|
||||
|
||||
#ifdef OPT_AMBIENT
|
||||
uniform vec3 uAmbient[6];
|
||||
#endif
|
||||
|
||||
uniform vec3 uLightPos[MAX_LIGHTS];
|
||||
uniform vec4 uLightColor[MAX_LIGHTS];
|
||||
#endif
|
||||
|
||||
#ifdef PASS_SHADOW
|
||||
@@ -147,94 +166,78 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
|
||||
#ifdef SHADOW_SAMPLER
|
||||
uniform sampler2DShadow sShadow;
|
||||
#ifdef GL_ES
|
||||
#define SHADOW(V) (shadow2DEXT(sShadow, V))
|
||||
#ifdef OPT_SHADOW
|
||||
#ifdef SHADOW_SAMPLER
|
||||
uniform sampler2DShadow sShadow;
|
||||
#ifdef GL_ES
|
||||
#define SHADOW(V) (shadow2DEXT(sShadow, V))
|
||||
#else
|
||||
#define SHADOW(V) (shadow2D(sShadow, V).x)
|
||||
#endif
|
||||
#else
|
||||
#define SHADOW(V) (shadow2D(sShadow, V).x)
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2D sShadow;
|
||||
#define CMP(a,b) step(b, a)
|
||||
uniform sampler2D sShadow;
|
||||
#define CMP(a,b) step(b, a)
|
||||
|
||||
#ifdef SHADOW_DEPTH
|
||||
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
|
||||
#elif defined(SHADOW_COLOR)
|
||||
float unpack(vec4 value) {
|
||||
vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
|
||||
return dot(value, bitSh);
|
||||
#ifdef SHADOW_DEPTH
|
||||
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
|
||||
#elif defined(SHADOW_COLOR)
|
||||
float unpack(vec4 value) {
|
||||
vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
|
||||
return dot(value, bitSh);
|
||||
}
|
||||
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
|
||||
#endif
|
||||
|
||||
float SHADOW(vec3 p) {
|
||||
return compare(p.xy, p.z);
|
||||
/*
|
||||
vec2 t = vec2(0.0, 1.0 / 1024.0);
|
||||
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0;
|
||||
vec4 s;
|
||||
s.x = compare(c + t.xx, p.z);
|
||||
s.y = compare(c + t.xy, p.z);
|
||||
s.z = compare(c + t.yx, p.z);
|
||||
s.w = compare(c + t.yy, p.z);
|
||||
vec2 f = fract(p.xy * 1024.0 + 0.5);
|
||||
return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x);
|
||||
*/
|
||||
}
|
||||
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
|
||||
#endif
|
||||
|
||||
float SHADOW(vec3 p) {
|
||||
return compare(p.xy, p.z);
|
||||
/*
|
||||
vec2 t = vec2(0.0, 1.0 / 1024.0);
|
||||
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0;
|
||||
vec4 s;
|
||||
s.x = compare(c + t.xx, p.z);
|
||||
s.y = compare(c + t.xy, p.z);
|
||||
s.z = compare(c + t.yx, p.z);
|
||||
s.w = compare(c + t.yy, p.z);
|
||||
vec2 f = fract(p.xy * 1024.0 + 0.5);
|
||||
return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x);
|
||||
*/
|
||||
float getShadow(vec4 lightProj) {
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
|
||||
float rShadow = 0.0;
|
||||
rShadow += SHADOW(p + (vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0)));
|
||||
rShadow += SHADOW(p + (vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0)));
|
||||
|
||||
rShadow /= 16.0;
|
||||
|
||||
vec3 lv = uLightPos[0].xyz - vCoord.xyz;
|
||||
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
|
||||
|
||||
return mix(rShadow, 1.0, fade);
|
||||
}
|
||||
|
||||
float getShadow() {
|
||||
return min(dot(vNormal.xyz, uLightPos[0].xyz - vCoord), vLightProj.w) > 0.0 ? getShadow(vLightProj) : 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
float getShadow(vec4 lightProj) {
|
||||
vec3 poissonDisk[16];
|
||||
poissonDisk[ 0] = vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 1] = vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 2] = vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 3] = vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 4] = vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 5] = vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 6] = vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 7] = vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 8] = vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 9] = vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[10] = vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[11] = vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[12] = vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[13] = vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[14] = vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[15] = vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0);
|
||||
|
||||
float rShadow = 0.0;
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
|
||||
rShadow += SHADOW(p + poissonDisk[0]);
|
||||
rShadow += SHADOW(p + poissonDisk[1]);
|
||||
rShadow += SHADOW(p + poissonDisk[2]);
|
||||
rShadow += SHADOW(p + poissonDisk[3]);
|
||||
rShadow += SHADOW(p + poissonDisk[4]);
|
||||
rShadow += SHADOW(p + poissonDisk[5]);
|
||||
rShadow += SHADOW(p + poissonDisk[6]);
|
||||
rShadow += SHADOW(p + poissonDisk[7]);
|
||||
rShadow += SHADOW(p + poissonDisk[8]);
|
||||
rShadow += SHADOW(p + poissonDisk[9]);
|
||||
rShadow += SHADOW(p + poissonDisk[10]);
|
||||
rShadow += SHADOW(p + poissonDisk[11]);
|
||||
rShadow += SHADOW(p + poissonDisk[12]);
|
||||
rShadow += SHADOW(p + poissonDisk[13]);
|
||||
rShadow += SHADOW(p + poissonDisk[14]);
|
||||
rShadow += SHADOW(p + poissonDisk[15]);
|
||||
|
||||
rShadow /= 16.0;
|
||||
|
||||
vec3 lv = uLightPos[0].xyz - vCoord.xyz;
|
||||
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
|
||||
|
||||
return mix(rShadow, 1.0, fade);
|
||||
}
|
||||
|
||||
float getShadow() {
|
||||
return min(dot(vNormal.xyz, uLightPos[0].xyz - vCoord), vLightProj.w) > 0.0 ? getShadow(vLightProj) : 1.0;
|
||||
}
|
||||
|
||||
vec3 calcLight(vec3 normal, vec3 pos, vec4 color) {
|
||||
vec3 lv = pos - vCoord.xyz;
|
||||
float lum = max(0.0, dot(normal, normalize(lv)));
|
||||
@@ -249,18 +252,20 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
return vec3(spec);
|
||||
}
|
||||
|
||||
vec3 calcAmbient(vec3 n) {
|
||||
vec3 sqr = n * n;
|
||||
vec3 pos = step(0.0, n);
|
||||
return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) +
|
||||
sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) +
|
||||
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
|
||||
}
|
||||
#ifdef OPT_AMBIENT
|
||||
vec3 calcAmbient(vec3 n) {
|
||||
vec3 sqr = n * n;
|
||||
vec3 pos = step(0.0, n);
|
||||
return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) +
|
||||
sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) +
|
||||
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CAUSTICS
|
||||
#if defined(UNDERWATER) && defined(OPT_WATER)
|
||||
float calcCaustics(vec3 n) {
|
||||
vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0 - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz));
|
||||
return texture2D(sReflect, vTexCoord.zw).r * (max(0.0, -n.y)) * fade.x * fade.y;
|
||||
return texture2D(sReflect, vTexCoord.zw).g * (max(0.0, -n.y)) * fade.x * fade.y;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -285,6 +290,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
#ifdef ALPHA_TEST
|
||||
if (color.w <= 0.1)
|
||||
discard;
|
||||
//color.xyz *= vec3(1.0, 0.0, 0.0);
|
||||
#endif
|
||||
|
||||
#ifdef PASS_SHADOW
|
||||
@@ -294,9 +300,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
gl_FragColor = vec4(1.0);
|
||||
#endif
|
||||
#else
|
||||
color.xyz *= uColor.xyz;
|
||||
color.xyz *= vColor.xyz;
|
||||
|
||||
color.xyz *= color.xyz; // to "linear" space
|
||||
|
||||
#ifdef PASS_AMBIENT
|
||||
@@ -308,42 +312,62 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
vec3 viewVec = normalize(vViewVec);
|
||||
vec3 light = vec3(0.0);
|
||||
|
||||
light += calcLight(normal, uLightPos[1], uLightColor[1]);
|
||||
light += calcLight(normal, uLightPos[2], uLightColor[2]);
|
||||
#ifdef OPT_LIGHTING
|
||||
light += calcLight(normal, uLightPos[1], uLightColor[1]);
|
||||
light += calcLight(normal, uLightPos[2], uLightColor[2]);
|
||||
#endif
|
||||
|
||||
// apply lighting
|
||||
#ifdef TYPE_SPRITE
|
||||
light += vColor.w * uColor.w;
|
||||
light += vColor.w * uMaterial.y; // apply diffuse intensity
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_ROOM
|
||||
light += mix(min(uColor.w, vColor.w), vColor.w, getShadow());
|
||||
#ifdef CAUSTICS
|
||||
#ifdef OPT_SHADOW
|
||||
light += mix(min(uMaterial.y, vColor.w), vColor.w, getShadow());
|
||||
#else
|
||||
light += vColor.w;
|
||||
#endif
|
||||
#if defined(UNDERWATER) && defined(OPT_WATER)
|
||||
light += calcCaustics(normal);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
vec3 rAmbient = calcAmbient(normal);
|
||||
float rShadow = getShadow();
|
||||
light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient;
|
||||
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], uColor.w * rShadow + 0.03);
|
||||
#ifdef CAUSTICS
|
||||
light += calcCaustics(normal);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef TYPE_ENTITY
|
||||
vec3 mainLight = calcLight(normal, uLightPos[0], uLightColor[0]);
|
||||
float mainSpec = uMaterial.z;
|
||||
|
||||
#ifdef TYPE_MIRROR
|
||||
vec3 rv = reflect(-viewVec, normal);
|
||||
color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2));
|
||||
light.xyz = vec3(1.0);
|
||||
#ifdef OPT_SHADOW
|
||||
float rShadow = getShadow();
|
||||
mainLight *= rShadow;
|
||||
mainSpec *= rShadow;
|
||||
#endif
|
||||
light += mainLight;
|
||||
|
||||
#ifdef OPT_AMBIENT
|
||||
light += calcAmbient(normal);
|
||||
#else
|
||||
light += uMaterial.y;
|
||||
#endif
|
||||
|
||||
#ifdef UNDERWATER
|
||||
if (vCoord.y > uParam.y) {
|
||||
color.xyz *= UNDERWATER_COLOR;
|
||||
#ifdef OPT_WATER
|
||||
light += calcCaustics(normal);
|
||||
#endif
|
||||
} else
|
||||
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], mainSpec + 0.03);
|
||||
#else
|
||||
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], mainSpec + 0.03);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
color.xyz *= light;
|
||||
|
||||
#else // ifndef TYPE_FLASH
|
||||
|
||||
color.w *= uColor.w;
|
||||
color.w *= uMaterial.w;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -351,14 +375,21 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
color.xyz = sqrt(color.xyz); // back to "gamma" space
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
#ifdef TYPE_MIRROR
|
||||
vec3 rv = reflect(-normalize(vViewVec), normalize(vNormal.xyz));
|
||||
color.xyz = vColor.xyz * textureCube(sEnvironment, normalize(rv)).xyz;
|
||||
#endif
|
||||
|
||||
color.xyz = applyFog(color.xyz, vec3(0.0), length(vViewVec) * FOG_DIST);
|
||||
#ifdef CAUSTICS
|
||||
#if defined(UNDERWATER) && defined(OPT_WATER)
|
||||
float d = abs((vCoord.y - max(uViewPos.y, uParam.y)) / normalize(vViewVec).y);
|
||||
d *= step(0.0, vCoord.y - uParam.y);
|
||||
color.xyz = applyFog(color.xyz, uColor.xyz * 0.2, d * WATER_FOG_DIST);
|
||||
d *= step(0.0, vCoord.y - uParam.y);
|
||||
color.xyz = applyFog(color.xyz, UNDERWATER_COLOR * 0.2, d * WATER_FOG_DIST);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
color.xyz *= 1.5; // add contrast
|
||||
|
||||
gl_FragColor = color;
|
||||
#endif
|
||||
}
|
||||
|
58
src/shader.h
58
src/shader.h
@@ -3,13 +3,53 @@
|
||||
|
||||
#include "core.h"
|
||||
|
||||
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
||||
enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMask, sMAX };
|
||||
enum UniformType { uParam, uTexParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, uMAX };
|
||||
#define SHADER_ATTRIBS(E) \
|
||||
E( aCoord ) \
|
||||
E( aTexCoord ) \
|
||||
E( aNormal ) \
|
||||
E( aColor )
|
||||
|
||||
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
|
||||
const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment", "sMask" };
|
||||
const char *UniformName[uMAX] = { "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" };
|
||||
#define SHADER_SAMPLERS(E) \
|
||||
E( sDiffuse ) \
|
||||
E( sNormal ) \
|
||||
E( sReflect ) \
|
||||
E( sShadow ) \
|
||||
E( sEnvironment ) \
|
||||
E( sMask )
|
||||
|
||||
#define SHADER_UNIFORMS(E) \
|
||||
E( uParam ) \
|
||||
E( uTexParam ) \
|
||||
E( uViewProj ) \
|
||||
E( uViewInv ) \
|
||||
E( uBasis ) \
|
||||
E( uLightProj ) \
|
||||
E( uMaterial ) \
|
||||
E( uAmbient ) \
|
||||
E( uViewPos ) \
|
||||
E( uLightPos ) \
|
||||
E( uLightColor ) \
|
||||
E( uAnimTexRanges ) \
|
||||
E( uAnimTexOffsets ) \
|
||||
E( uRoomSize ) \
|
||||
E( uPosScale )
|
||||
|
||||
#define ENUM(v) v,
|
||||
#define STR(v) #v,
|
||||
|
||||
enum AttribType { SHADER_ATTRIBS(ENUM) aMAX };
|
||||
enum SamplerType { SHADER_SAMPLERS(ENUM) sMAX };
|
||||
enum UniformType { SHADER_UNIFORMS(ENUM) uMAX };
|
||||
|
||||
const char *AttribName[aMAX] = { SHADER_ATTRIBS(STR) };
|
||||
const char *SamplerName[sMAX] = { SHADER_SAMPLERS(STR) };
|
||||
const char *UniformName[uMAX] = { SHADER_UNIFORMS(STR) };
|
||||
|
||||
#undef SHADER_ATTRIBS
|
||||
#undef SHADER_SAMPLERS
|
||||
#undef SHADER_UNIFORMS
|
||||
#undef ENUM
|
||||
#undef STR
|
||||
|
||||
struct Shader {
|
||||
GLuint ID;
|
||||
@@ -26,7 +66,7 @@ struct Shader {
|
||||
|
||||
Shader(const char *source, const char *defines = "") {
|
||||
char fileName[255];
|
||||
|
||||
//LOG(hello[0]);
|
||||
// generate shader file path
|
||||
if (Core::support.shaderBinary) {
|
||||
uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source)));
|
||||
@@ -131,11 +171,13 @@ struct Shader {
|
||||
memset(params, 0, sizeof(params));
|
||||
}
|
||||
|
||||
void bind() {
|
||||
bool bind() {
|
||||
if (Core::active.shader != this) {
|
||||
Core::active.shader = this;
|
||||
glUseProgram(ID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool checkParam(UniformType uType, const void *value, int size) {
|
||||
|
@@ -4,7 +4,7 @@
|
||||
#include "core.h"
|
||||
|
||||
struct Texture {
|
||||
enum Format : uint32 { RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, SHADOW, MAX };
|
||||
enum Format : uint32 { LUMINANCE, RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, SHADOW, MAX };
|
||||
|
||||
GLuint ID;
|
||||
int width, height;
|
||||
@@ -38,14 +38,14 @@ struct Texture {
|
||||
|
||||
if (format == RGBA_HALF) {
|
||||
if (Core::support.texHalf)
|
||||
filter = Core::support.texHalfLinear;
|
||||
filter = filter && Core::support.texHalfLinear;
|
||||
else
|
||||
format = RGBA_FLOAT;
|
||||
}
|
||||
|
||||
if (format == RGBA_FLOAT) {
|
||||
if (Core::support.texFloat)
|
||||
filter = Core::support.texFloatLinear;
|
||||
filter = filter && Core::support.texFloatLinear;
|
||||
else
|
||||
format = RGBA;
|
||||
}
|
||||
@@ -66,6 +66,7 @@ struct Texture {
|
||||
GLuint ifmt, fmt;
|
||||
GLenum type;
|
||||
} formats[MAX] = {
|
||||
{ GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, // LUMINANCE
|
||||
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA
|
||||
{ GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB16
|
||||
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16
|
||||
@@ -88,14 +89,19 @@ struct Texture {
|
||||
}
|
||||
|
||||
void bind(int sampler) {
|
||||
Core::active.textures[sampler] = this;
|
||||
glActiveTexture(GL_TEXTURE0 + sampler);
|
||||
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
|
||||
if (Core::active.textures[sampler] != this) {
|
||||
Core::active.textures[sampler] = this;
|
||||
glActiveTexture(GL_TEXTURE0 + sampler);
|
||||
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
|
||||
}
|
||||
}
|
||||
|
||||
void unbind(int sampler) {
|
||||
glActiveTexture(GL_TEXTURE0 + sampler);
|
||||
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0);
|
||||
if (Core::active.textures[sampler]) {
|
||||
Core::active.textures[sampler] = NULL;
|
||||
glActiveTexture(GL_TEXTURE0 + sampler);
|
||||
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -301,7 +301,7 @@ struct Crystal : Controller {
|
||||
|
||||
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
|
||||
Shader *sh = Core::active.shader;
|
||||
sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge
|
||||
sh->setParam(uMaterial, vec4(1.0f));
|
||||
environment->bind(sEnvironment);
|
||||
Controller::render(frustum, mesh, type, caustics);
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@ uniform vec3 uPosScale[2];
|
||||
|
||||
uniform vec4 uTexParam;
|
||||
uniform vec4 uParam;
|
||||
uniform vec4 uColor;
|
||||
|
||||
uniform sampler2D sNormal;
|
||||
|
||||
@@ -107,7 +106,7 @@ uniform sampler2D sNormal;
|
||||
vec4 calc() {
|
||||
vec2 tc = gl_FragCoord.xy * uTexParam.xy;
|
||||
|
||||
if (texture2D(sMask, tc).x == 0.0)
|
||||
if (texture2D(sMask, tc).x < 0.5)
|
||||
return vec4(0.0);
|
||||
|
||||
vec4 v = texture2D(sDiffuse, tc); // height, speed, normal.xz
|
||||
@@ -135,11 +134,11 @@ uniform sampler2D sNormal;
|
||||
float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz));
|
||||
float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz));
|
||||
float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w;
|
||||
return vec4(vec3(value), 1.0);
|
||||
return vec4(0.0, value, 0.0, 0.0);
|
||||
}
|
||||
|
||||
vec4 mask() {
|
||||
return vec4(0.0);
|
||||
return vec4(1.0, 1.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
vec4 compose() {
|
||||
@@ -164,11 +163,11 @@ uniform sampler2D sNormal;
|
||||
|
||||
float fresnel = calcFresnel(dot(normal, viewVec), 0.1, 2.0);
|
||||
|
||||
vec4 color = mix(refr, refl, fresnel) + spec;
|
||||
vec4 color = mix(refr, refl, fresnel) + spec * 1.5;
|
||||
|
||||
float d = abs((vCoord.y - uViewPos.y) / normalize(vViewVec).y);
|
||||
d *= step(0.0, uViewPos.y - vCoord.y); // apply fog only when camera is underwater
|
||||
color.xyz = applyFog(color.xyz, uColor.xyz, d * WATER_FOG_DIST);
|
||||
color.xyz = applyFog(color.xyz, UNDERWATER_COLOR * 0.2, d * WATER_FOG_DIST);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
Reference in New Issue
Block a user