mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-13 16:44:50 +02:00
#23 experimental shadows (XPSM, crop etc.)
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
|
||||
#define NO_CLIP_PLANE 1000000.0f
|
||||
|
||||
#define SHADOW_TEX_SIZE 1024
|
||||
|
||||
#define FOG_DIST (18 * 1024)
|
||||
#define WATER_FOG_DIST (8 * 1024)
|
||||
//#define WATER_USE_GRID
|
||||
@@ -130,7 +132,7 @@ struct ShaderCache {
|
||||
typ = typeNames[type];
|
||||
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);
|
||||
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#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST, SHADOW_TEX_SIZE);
|
||||
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");
|
||||
|
@@ -133,6 +133,7 @@ struct Character : Controller {
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
vec3 p = pos;
|
||||
lastInput = input;
|
||||
input = getInput();
|
||||
stand = getStand();
|
||||
@@ -140,6 +141,8 @@ struct Character : Controller {
|
||||
Controller::update();
|
||||
updateVelocity();
|
||||
updatePosition();
|
||||
if (p != pos)
|
||||
updateLights();
|
||||
}
|
||||
|
||||
virtual void cmdJump(const vec3 &vel) {
|
||||
|
@@ -46,6 +46,10 @@ struct Controller {
|
||||
vec3 ambient[6];
|
||||
float specular;
|
||||
|
||||
TR::Room::Light *lights[MAX_LIGHTS];
|
||||
vec3 mainLightPos;
|
||||
float mainLightRadius;
|
||||
|
||||
struct MeshLayer {
|
||||
uint32 model;
|
||||
uint32 mask;
|
||||
@@ -71,6 +75,7 @@ struct Controller {
|
||||
frameIndex = -1;
|
||||
specular = 0.0f;
|
||||
ambient[0] = ambient[1] = ambient[2] = ambient[3] = ambient[4] = ambient[5] = vec3(intensityf(getRoom().ambient));
|
||||
updateLights();
|
||||
}
|
||||
|
||||
virtual ~Controller() {
|
||||
@@ -130,8 +135,6 @@ struct Controller {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void updateEntity() {
|
||||
TR::Entity &e = getEntity();
|
||||
e.x = int(pos.x);
|
||||
@@ -273,7 +276,11 @@ struct Controller {
|
||||
}
|
||||
|
||||
virtual Box getBoundingBox() {
|
||||
return animation.getBoundingBox(pos, getEntity().rotation.value / 0x4000);
|
||||
return getBoundingBoxLocal() * getMatrix();
|
||||
}
|
||||
|
||||
virtual Box getBoundingBoxLocal() {
|
||||
return animation.getBoundingBox(vec3(0, 0, 0), 0);
|
||||
}
|
||||
|
||||
vec3 trace(int fromRoom, const vec3 &from, const vec3 &to, int &room, bool isCamera) { // TODO: use Bresenham
|
||||
@@ -464,6 +471,85 @@ struct Controller {
|
||||
virtual void update() {
|
||||
updateAnimation(true);
|
||||
}
|
||||
|
||||
struct MaxLight {
|
||||
TR::Room::Light *light;
|
||||
float att;
|
||||
};
|
||||
|
||||
void checkRoomLights(int roomIndex, int fromRoom, const vec3 &from, MaxLight *maxLights, vec3 &mainDir, float &mainRad, float &attSum, int deep) {
|
||||
TR::Room &room = level->rooms[roomIndex];
|
||||
|
||||
for (int i = 0; i < room.lightsCount; i++) {
|
||||
TR::Room::Light &light = room.lights[i];
|
||||
|
||||
bool exists = false;
|
||||
for (int m = 0; m < MAX_LIGHTS; m++)
|
||||
if (maxLights[m].light == &light) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
if (exists) continue;
|
||||
|
||||
vec3 dir = vec3(float(light.x), float(light.y), float(light.z)) - from;
|
||||
float att = max(0.0f, 1.0f - dir.length2() / float(light.radius) / float(light.radius)) * intensityf(light.intensity);
|
||||
|
||||
for (int m = 0; m < MAX_LIGHTS; m++) {
|
||||
if (maxLights[m].att < att) {
|
||||
for (int n = MAX_LIGHTS - 1; n > m; n--)
|
||||
maxLights[n] = maxLights[n - 1];
|
||||
maxLights[m].light = &light;
|
||||
maxLights[m].att = att;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (att > 0.0f) {
|
||||
// if (dir.y > 0.0f)
|
||||
// att *= 1.0f - dir.y / float(light.radius);
|
||||
att = max(0.0f, att - dir.y / 8192.0f);
|
||||
attSum += att;
|
||||
mainDir += dir * att;
|
||||
mainRad += float(light.radius) * att;
|
||||
}
|
||||
}
|
||||
|
||||
if (--deep > 0)
|
||||
for (int i = 0; i < room.portalsCount; i++)
|
||||
if (room.portals[i].roomIndex != fromRoom)
|
||||
checkRoomLights(room.portals[i].roomIndex, roomIndex, from, maxLights, mainDir, mainRad, attSum, deep);
|
||||
}
|
||||
|
||||
void updateLights() {
|
||||
if (!getModel()) {
|
||||
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||
lights[i] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
MaxLight maxLights[MAX_LIGHTS];
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
maxLights[i].light = NULL;
|
||||
maxLights[i].att = 0.0f;
|
||||
}
|
||||
|
||||
vec3 p = getBoundingBox().center();
|
||||
vec3 mainDir(0.0f);
|
||||
float mainRad = 0.0f;
|
||||
float attSum = 0.0f;
|
||||
|
||||
checkRoomLights(getRoomIndex(), -1, p, maxLights, mainDir, mainRad, attSum, 1);
|
||||
|
||||
if (attSum > 0.0f) {
|
||||
attSum = 1.0f / attSum;
|
||||
mainLightPos = mainDir * attSum + p;
|
||||
mainLightRadius = mainRad * attSum;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||
lights[i] = maxLights[i].light;
|
||||
}
|
||||
/*
|
||||
void renderMesh(MeshBuilder *mesh, uint32 offsetIndex) {
|
||||
return;
|
||||
|
14
src/debug.h
14
src/debug.h
@@ -350,18 +350,24 @@ namespace Debug {
|
||||
}
|
||||
}
|
||||
|
||||
void lights(const TR::Level &level, int room) {
|
||||
void lights(const TR::Level &level, int room, Controller *lara) {
|
||||
// int roomIndex = level.entities[lara->entity].room;
|
||||
// int lightIndex = getLightIndex(lara->pos, roomIndex);
|
||||
|
||||
lara->updateLights();
|
||||
glPointSize(8);
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
for (int j = 0; j < level.rooms[i].lightsCount; j++) {
|
||||
TR::Room::Light &l = level.rooms[i].lights[j];
|
||||
float a = l.intensity / 8191.0f;
|
||||
float a = intensityf(l.intensity);
|
||||
vec3 p = vec3(l.x, l.y, l.z);
|
||||
vec4 color = vec4(a, a, a, 1);
|
||||
if (i == room) color.x = color.z = 0;
|
||||
|
||||
if (&l == lara->lights[0]) color.y = color.z = 0; // r
|
||||
if (&l == lara->lights[1]) color.x = color.z = 0; // g
|
||||
if (&l == lara->lights[2]) color.x = color.y = 0; // b
|
||||
if (&l == lara->lights[3]) color.y = 0; // a
|
||||
|
||||
// if (i == room) color.x = color.z = 0;
|
||||
Debug::Draw::point(p, color);
|
||||
//if (i == roomIndex && j == lightIndex)
|
||||
// color = vec4(0, 1, 0, 1);
|
||||
|
@@ -949,7 +949,7 @@ namespace TR {
|
||||
stream.read(light.intensity);
|
||||
stream.read(light.radius);
|
||||
|
||||
light.radius *= 2;
|
||||
// light.radius *= 2;
|
||||
}
|
||||
// meshes
|
||||
stream.read(r.meshesCount);
|
||||
|
@@ -1808,6 +1808,9 @@ struct Lara : Character {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == STATE_DEATH || state == STATE_UNDERWATER_DEATH)
|
||||
velocity.x = velocity.z = 0.0f;
|
||||
}
|
||||
|
||||
virtual void updatePosition() { // TODO: sphere / bbox collision
|
||||
|
380
src/level.h
380
src/level.h
@@ -22,7 +22,7 @@ struct Level : IGame {
|
||||
|
||||
Lara *lara;
|
||||
Camera *camera;
|
||||
Texture *shadow, *shadowMask;
|
||||
Texture *shadow;
|
||||
|
||||
struct Params {
|
||||
float time;
|
||||
@@ -221,8 +221,7 @@ struct Level : IGame {
|
||||
|
||||
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;
|
||||
shadowMask = NULL;
|
||||
shadow = Core::settings.shadows ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL;
|
||||
|
||||
initReflections();
|
||||
|
||||
@@ -250,7 +249,6 @@ struct Level : IGame {
|
||||
delete shaderCache;
|
||||
|
||||
delete shadow;
|
||||
delete shadowMask;
|
||||
delete ambientCache;
|
||||
delete waterCache;
|
||||
|
||||
@@ -460,48 +458,26 @@ struct Level : IGame {
|
||||
}
|
||||
camera->frustum = camFrustum; // pop camera frustum
|
||||
}
|
||||
|
||||
void setLights(Controller *controller, bool onlyFlashes = false) {
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
TR::Room::Light *light = controller->lights[i];
|
||||
if (onlyFlashes && i && light && light->radius > 0.0f)
|
||||
light = NULL;
|
||||
|
||||
int getLightIndex(const vec3 &pos, int &room, float maxAtt = -1.0f, int depth = 0) {
|
||||
int idx = -1;
|
||||
|
||||
TR::Room &r = level.rooms[room];
|
||||
|
||||
for (int i = 0; i < r.lightsCount; i++) {
|
||||
TR::Room::Light &light = r.lights[i];
|
||||
if (light.intensity > 0x1FFF) continue;
|
||||
float att = max(0.0f, 1.0f - (pos - vec3(float(light.x), float(light.y), float(light.z))).length2() / ((float)light.radius * (float)light.radius));
|
||||
if (att > maxAtt) {
|
||||
maxAtt = att;
|
||||
idx = i;
|
||||
if (light) {
|
||||
float c = 1.0f - intensityf(light->intensity);
|
||||
Core::lightPos[i] = vec3(float(light->x), float(light->y), float(light->z));
|
||||
Core::lightColor[i] = vec4(c, c, c, 1.0f / float(light->radius));
|
||||
} else {
|
||||
Core::lightPos[i] = vec3(0);
|
||||
Core::lightColor[i] = vec4(0, 0, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (depth > 0)
|
||||
for (int i = 0; i < r.portalsCount; i++) {
|
||||
int nextRoom = r.portals[i].roomIndex;
|
||||
int nextLight = getLightIndex(pos, nextRoom, maxAtt, depth - 1);
|
||||
if (nextLight > -1) {
|
||||
room = nextRoom;
|
||||
idx = nextLight;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void getLight(const vec3 &pos, int roomIndex) {
|
||||
int room = roomIndex;
|
||||
int idx = getLightIndex(pos, room);
|
||||
|
||||
if (idx > -1) {
|
||||
TR::Room::Light &light = level.rooms[room].lights[idx];
|
||||
float c = 1.0f - intensityf(level.rooms[room].lights[idx].intensity);
|
||||
Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z));
|
||||
Core::lightColor[0] = vec4(c, c, c, 1.0f / (float)light.radius);
|
||||
} else {
|
||||
Core::lightPos[0] = vec3(0);
|
||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||
}
|
||||
Core::lightPos[0] = lara->mainLightPos;
|
||||
if (lara->mainLightRadius > 0.0f)
|
||||
Core::lightColor[0].w = 1.0f / lara->mainLightRadius;
|
||||
}
|
||||
|
||||
void renderEntity(const TR::Entity &entity) {
|
||||
@@ -543,7 +519,8 @@ struct Level : IGame {
|
||||
}
|
||||
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
|
||||
}
|
||||
getLight(pos, entity.room);
|
||||
|
||||
setLights(controller);
|
||||
} else { // sprite
|
||||
Core::lightPos[0] = vec3(0);
|
||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||
@@ -610,7 +587,7 @@ struct Level : IGame {
|
||||
void renderRooms(int roomIndex) {
|
||||
PROFILE_MARKER("ROOMS");
|
||||
|
||||
getLight(lara->pos, lara->getRoomIndex());
|
||||
setLights(lara, true);
|
||||
|
||||
#ifdef LEVEL_EDITOR
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
@@ -656,20 +633,43 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
|
||||
mat4 calcCromMatrix(const mat4 &lightViewProj, const Box *boxes, int count) {
|
||||
mat4 cameraViewProjInv = (mat4(camera->fov, float(Core::width) / Core::height, 512.0f, 4096.0f) * camera->mViewInv.inverse()).inverse();
|
||||
Box bRec, bCast, bCrop, bSplit;
|
||||
/*
|
||||
mat4 calcCropMatrix(const mat4 &viewProj, const Box &receivers, const Box &casters) {
|
||||
mat4 cameraViewProjInv = (camera->getProjMatrix() * camera->mViewInv.inverse()).inverse();
|
||||
// camera->mViewInv (mat4(camera->fov, float(Core::width) / Core::height, camera->znear, camera->zfar) * camera->mViewInv.inverse()).inverse();
|
||||
Box frustumBox = Box(vec3(-1.0f), vec3(1.0f)) * cameraViewProjInv;
|
||||
|
||||
Box casterBox(vec3(+INF), vec3(-INF));
|
||||
Box caster = casters;// * viewProj;
|
||||
Box receiver = receivers * viewProj;
|
||||
Box split = frustumBox * viewProj;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
casterBox += boxes[i] * lightViewProj;
|
||||
Box crop;
|
||||
crop.min.x = max(max(caster.min.x, receiver.min.x), split.min.x);
|
||||
crop.max.x = min(min(caster.max.x, receiver.max.x), split.max.x);
|
||||
crop.min.y = max(max(caster.min.y, receiver.min.y), split.min.y);
|
||||
crop.max.y = min(min(caster.max.y, receiver.max.y), split.max.y);
|
||||
crop.min.z = min(caster.min.z, split.min.z);
|
||||
crop.max.z = min(receiver.max.z, split.max.z);
|
||||
|
||||
casterBox -= frustumBox * lightViewProj;
|
||||
mat4 m = camera->getProjMatrix();
|
||||
Box cc = receivers * m;
|
||||
cc = cc * m.inverse();
|
||||
|
||||
vec3 scale = vec3(2.0f, 2.0f, 1.0f) / casterBox.size();
|
||||
vec3 center = casterBox.center();
|
||||
vec3 offset = vec3(center.x, center.y, casterBox.min.z) * scale;
|
||||
if (!Input::down[ikShift]) {
|
||||
mat4 m = viewProj.inverse();
|
||||
bRec = receivers;// * m;
|
||||
bCast = casters;// * m;
|
||||
bCrop = crop * m;
|
||||
bSplit = split * m;
|
||||
}
|
||||
|
||||
// casterBox -= frustumBox * viewProj;
|
||||
// crop.min.z = 0.0f;
|
||||
|
||||
vec3 scale = vec3(2.0f, 2.0f, 1.0f) / crop.size();
|
||||
vec3 center = crop.center();
|
||||
vec3 offset = vec3(center.x, center.y, crop.min.z) * scale;
|
||||
|
||||
return mat4(scale.x, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, scale.y, 0.0f, 0.0f,
|
||||
@@ -679,62 +679,241 @@ struct Level : IGame {
|
||||
|
||||
|
||||
bool setupLightCamera() {
|
||||
vec3 pos = lara->getPos();
|
||||
|
||||
// omni-spot light shadows
|
||||
int room = lara->getRoomIndex();
|
||||
int idx = getLightIndex(lara->pos, room);
|
||||
if (idx < 0) return false;
|
||||
lara->updateLights();
|
||||
vec3 pos = lara->getBoundingBox().center();
|
||||
|
||||
TR::Room::Light &light = level.rooms[room].lights[idx];
|
||||
vec3 shadowLightPos = vec3(float(light.x), float(light.y), float(light.z));
|
||||
Core::mViewInv = mat4(shadowLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0));
|
||||
Core::mViewInv = mat4(lara->mainLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0));
|
||||
Core::mView = Core::mViewInv.inverse();
|
||||
Core::mProj = mat4(120.0f, 1.0f, camera->znear, camera->zfar);
|
||||
Core::mProj = mat4(1.0f, 1.0f, camera->znear, camera->zfar);//lara->mainLightRadius * 2.0f);
|
||||
|
||||
mat4 mLightProj = Core::mProj * Core::mView;
|
||||
|
||||
Box casters = lara->getBoundingBox() * mLightProj;
|
||||
|
||||
float rq = lara->mainLightRadius * lara->mainLightRadius;
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
TR::Entity &e = level.entities[i];
|
||||
Controller *controller = (Controller*)e.controller;
|
||||
if (controller && TR::castShadow(e.type) && rq > (lara->mainLightPos - controller->pos).length2())
|
||||
casters += controller->getBoundingBox() * mLightProj;
|
||||
}
|
||||
//casters.expand(vec3(128.0f));
|
||||
|
||||
Box lightBox = Box(lara->mainLightPos - vec3(lara->mainLightRadius), lara->mainLightPos + vec3(lara->mainLightRadius));
|
||||
|
||||
Core::mProj = calcCropMatrix(mLightProj, lightBox, casters) * Core::mProj;
|
||||
|
||||
mat4 bias;
|
||||
bias.identity();
|
||||
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
|
||||
/*
|
||||
Box boxes[32];
|
||||
int bCount = 0;
|
||||
|
||||
float rq = light.radius * light.radius;
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
TR::Entity &e = level.entities[i];
|
||||
Controller *controller = (Controller*)e.controller;
|
||||
if (controller && TR::castShadow(e.type) && rq > (shadowLightPos - controller->pos).length2())
|
||||
boxes[bCount++] = controller->getBoundingBox();
|
||||
|
||||
Core::mLightProj = bias * (Core::mProj * Core::mView);
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
/* // --> XPSM
|
||||
Box transformPointsBox(const vec3 *points, int count, const mat4 &matrix, float eps) {
|
||||
Box box(vec3(+INF), vec3(-INF));
|
||||
for (int i = 0; i < count; i++) {
|
||||
vec4 p = matrix * vec4(points[i], 1.0f);
|
||||
if (p.w > eps)
|
||||
box += p.xyz / p.w;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
vec3 shadowBox(1024.0f, 0.0f, 1024.0f);
|
||||
boxes[0] = lara->getBoundingBox();
|
||||
boxes[0] += Box(lara->pos - shadowBox, lara->pos + shadowBox);
|
||||
bCount++;
|
||||
Core::mProj = calcCromMatrix(Core::mProj * Core::mView, &boxes[0], bCount) * Core::mProj;
|
||||
*/
|
||||
return box;
|
||||
}
|
||||
|
||||
bool setupLightCamera() {
|
||||
lara->updateLights();
|
||||
vec3 pos = lara->getBoundingBox().center();
|
||||
|
||||
mat4 mViewCamera = camera->mViewInv.inverse();
|
||||
|
||||
// get shadow casters (bbox corner points)
|
||||
#define MAX_CASTER_POINTS (32 * 8)
|
||||
|
||||
vec3 cPoints[32 * 8];
|
||||
int cPointsCount = 0;
|
||||
|
||||
vec3 rPoints[1 * 8];
|
||||
int rPointsCount = 0;
|
||||
|
||||
float rq = lara->mainLightRadius * lara->mainLightRadius;
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
if (cPointsCount >= MAX_CASTER_POINTS)
|
||||
break;
|
||||
|
||||
TR::Entity &e = level.entities[i];
|
||||
Controller *controller = (Controller*)e.controller;
|
||||
if (!controller || !TR::castShadow(e.type) || rq < (lara->mainLightPos - controller->pos).length2())
|
||||
continue;
|
||||
|
||||
Box box = controller->getBoundingBoxLocal();
|
||||
mat4 m = mViewCamera * controller->getMatrix();
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
cPoints[cPointsCount++] = m * box[j];
|
||||
}
|
||||
#undef MAX_CASTER_POINTS
|
||||
|
||||
{
|
||||
mat4 cameraViewProjInv = (camera->getProjMatrix() * mViewCamera).inverse();
|
||||
Box box(vec3(-1.0f), vec3(1.0f));
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
vec4 p = cameraViewProjInv * vec4(box[i], 1.0f);
|
||||
rPoints[rPointsCount++] = mViewCamera * (p.xyz / p.w);
|
||||
}
|
||||
}
|
||||
|
||||
mat4 mViewLight = mat4(mViewCamera * pos, mViewCamera * lara->mainLightPos, vec3(0, -1, 0)).inverse();
|
||||
|
||||
vec2 uP = mViewLight.dir.xy.normal();
|
||||
|
||||
float minCastersProj = 1.0f;
|
||||
for (int i = 0; i < cPointsCount; i++) {
|
||||
vec3 p = mViewLight * cPoints[i];
|
||||
minCastersProj = min(minCastersProj, uP.dot(p.xy));
|
||||
}
|
||||
|
||||
float minReceiversProj = 1.0f;
|
||||
for (int i = 0; i < rPointsCount; i++) {
|
||||
vec3 p = mViewLight * rPoints[i];
|
||||
minReceiversProj = min(minReceiversProj, uP.dot(p.xy));
|
||||
}
|
||||
|
||||
float eps = 0.85f;
|
||||
float maxLengthP = (eps - 1.0f) / minCastersProj; //max(minCastersProj, minReceiversProj);
|
||||
float lengthP = (0.05f * 0.06f) / uP.dot(mViewLight.dir.xy);
|
||||
|
||||
if (maxLengthP > 0.0f && lengthP > maxLengthP)
|
||||
lengthP = maxLengthP;
|
||||
|
||||
mat4 mLProj(1, 0, 0, uP.x * lengthP,
|
||||
0, 1, 0, uP.y * lengthP,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
|
||||
mat4 mLZRot(uP.x, uP.y, 0, 0,
|
||||
uP.y, -uP.x, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
|
||||
mat4 mProjLight = mLZRot * mLProj * mViewLight;
|
||||
|
||||
Box casters = transformPointsBox(cPoints, cPointsCount, mProjLight, eps);
|
||||
Box receivers = transformPointsBox(rPoints, rPointsCount, mProjLight, eps);
|
||||
Box focus = casters;//.intersection2D(receivers);
|
||||
|
||||
//focus.min.z = min(casters.min.z, receivers.min.z);
|
||||
//focus.max.z = max(casters.max.z, receivers.max.z);
|
||||
|
||||
vec3 size = focus.size();
|
||||
|
||||
if (size.x < EPS || size.y < EPS || size.z < EPS)
|
||||
return false;
|
||||
|
||||
vec3 u = vec3(1.0f) / size;
|
||||
|
||||
mat4 mUnitCube(u.x, 0, 0, 0,
|
||||
0, u.y, 0, 0,
|
||||
0, 0, u.z, 0,
|
||||
-focus.min.x * u.x, -focus.min.y * u.y, -focus.min.z * u.z, 1);
|
||||
|
||||
mat4 mUnitSpace( 2, 0, 0, 0,
|
||||
0, 2, 0, 0,
|
||||
0, 0, 2, 0,
|
||||
-1, -1, -1, 1);
|
||||
|
||||
Core::mView = mViewLight * mViewCamera;
|
||||
Core::mProj = mUnitSpace * mUnitCube * mLZRot * mLProj;
|
||||
Core::mViewProj = Core::mProj * Core::mView;
|
||||
|
||||
mat4 bias;
|
||||
bias.identity();
|
||||
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
|
||||
|
||||
Core::mLightProj = bias * Core::mViewProj;
|
||||
return true;
|
||||
}
|
||||
<-- */
|
||||
|
||||
mat4 calcCropMatrix(const mat4 &viewProj, const Box &receivers, const Box &casters) {
|
||||
mat4 cameraViewProjInv = (camera->getProjMatrix() * camera->mViewInv.inverse()).inverse();
|
||||
// camera->mViewInv (mat4(camera->fov, float(Core::width) / Core::height, camera->znear, camera->zfar) * camera->mViewInv.inverse()).inverse();
|
||||
Box frustumBox = Box(vec3(-1.0f), vec3(1.0f)) * cameraViewProjInv;
|
||||
|
||||
Box caster = casters;// * viewProj;
|
||||
Box receiver = receivers * viewProj;
|
||||
Box split = frustumBox * viewProj;
|
||||
|
||||
Box crop;
|
||||
crop.min.x = max(max(caster.min.x, receiver.min.x), split.min.x);
|
||||
crop.max.x = min(min(caster.max.x, receiver.max.x), split.max.x);
|
||||
crop.min.y = max(max(caster.min.y, receiver.min.y), split.min.y);
|
||||
crop.max.y = min(min(caster.max.y, receiver.max.y), split.max.y);
|
||||
crop.min.z = min(caster.min.z, split.min.z);
|
||||
crop.max.z = min(receiver.max.z, split.max.z);
|
||||
|
||||
mat4 m = camera->getProjMatrix();
|
||||
Box cc = receivers * m;
|
||||
cc = cc * m.inverse();
|
||||
|
||||
if (!Input::down[ikShift]) {
|
||||
mat4 m = viewProj.inverse();
|
||||
bRec = receivers;// * m;
|
||||
bCast = casters;// * m;
|
||||
bCrop = crop * m;
|
||||
bSplit = split * m;
|
||||
}
|
||||
|
||||
// casterBox -= frustumBox * viewProj;
|
||||
// crop.min.z = 0.0f;
|
||||
|
||||
vec3 scale = vec3(2.0f, 2.0f, 1.0f) / crop.size();
|
||||
vec3 center = crop.center();
|
||||
vec3 offset = vec3(center.x, center.y, crop.min.z) * scale;
|
||||
|
||||
return mat4(scale.x, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, scale.y, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, scale.z, 0.0f,
|
||||
-offset.x, -offset.y, -offset.z, 1.0f);
|
||||
}
|
||||
|
||||
bool setupLightCamera() {
|
||||
lara->updateLights();
|
||||
vec3 pos = lara->getBoundingBox().center();
|
||||
|
||||
Core::mViewInv = mat4(lara->mainLightPos, pos, vec3(0, -1, 0));
|
||||
Core::mView = Core::mViewInv.inverse();
|
||||
Core::mProj = mat4(120.0f, 1.0f, camera->znear, lara->mainLightRadius);
|
||||
|
||||
mat4 bias;
|
||||
bias.identity();
|
||||
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
|
||||
|
||||
Core::mLightProj = bias * (Core::mProj * Core::mView);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void renderShadows(int roomIndex) {
|
||||
PROFILE_MARKER("PASS_SHADOW");
|
||||
Core::eye = 0.0f;
|
||||
Core::pass = Core::passShadow;
|
||||
if (!setupLightCamera()) return;
|
||||
shadow->unbind(sShadow);
|
||||
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
|
||||
if (colorShadow)
|
||||
Core::setClearColor(vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
Core::setTarget(shadow);
|
||||
Core::setTarget(shadow);
|
||||
if (!setupLightCamera()) return;
|
||||
Core::clear(true, true);
|
||||
Core::setCulling(cfBack);
|
||||
renderScene(roomIndex);
|
||||
renderScene(roomIndex);
|
||||
Core::invalidateTarget(!colorShadow, colorShadow);
|
||||
Core::setCulling(cfFront);
|
||||
Core::setCulling(cfFront);
|
||||
if (colorShadow)
|
||||
Core::setClearColor(vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
@@ -851,7 +1030,7 @@ struct Level : IGame {
|
||||
// renderModel(level.models[modelIndex], level.entities[4]);
|
||||
*/
|
||||
Debug::begin();
|
||||
|
||||
/*
|
||||
lara->updateEntity(); // TODO clip angle while rotating
|
||||
|
||||
int q = int(normalizeAngle(lara->angleExt + PI * 0.25f) / (PI * 0.5f));
|
||||
@@ -882,7 +1061,7 @@ struct Level : IGame {
|
||||
glColor3f(1, 1, 0); p = lara->pos; glVertex3fv((GLfloat*)&p); p -= vec3(0.0f, LARA_HANG_OFFSET, 0.0f); glVertex3fv((GLfloat*)&p);
|
||||
glEnd();
|
||||
Core::setDepthTest(true);
|
||||
/*
|
||||
*/
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
@@ -891,8 +1070,8 @@ struct Level : IGame {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
||||
|
||||
if (waterCache->visible)
|
||||
waterCache->reflect->bind(sDiffuse);
|
||||
if (shadow)
|
||||
shadow->bind(sDiffuse);
|
||||
else
|
||||
atlas->bind(sDiffuse);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
@@ -921,10 +1100,29 @@ struct Level : IGame {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
|
||||
|
||||
Core::setDepthTest(false);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(1, 1, 1);
|
||||
glVertex3fv((GLfloat*)&lara->pos);
|
||||
glVertex3fv((GLfloat*)&lara->mainLightPos);
|
||||
glEnd();
|
||||
Core::setDepthTest(true);
|
||||
|
||||
Debug::Draw::sphere(lara->mainLightPos, lara->mainLightRadius, vec4(1, 1, 0, 1));
|
||||
|
||||
Box bbox = lara->getBoundingBox();
|
||||
Debug::Draw::box(bbox.min, bbox.max , vec4(1, 0, 1, 1));
|
||||
Debug::Draw::box(bRec.min, bRec.max , vec4(1, 0, 0, 1));
|
||||
Debug::Draw::box(bCast.min, bCast.max, vec4(0, 0, 1, 1));
|
||||
Debug::Draw::box(bSplit.min, bSplit.max, vec4(0, 1, 1, 1));
|
||||
Debug::Draw::box(bCrop.min, bCrop.max, vec4(0, 1, 0, 1));
|
||||
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
// Debug::Level::lights(level, lara->getRoomIndex());
|
||||
Debug::Level::lights(level, lara->getRoomIndex(), lara);
|
||||
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||
// Core::setDepthTest(false);
|
||||
// Debug::Level::portals(level);
|
||||
|
@@ -132,8 +132,8 @@ struct Mesh {
|
||||
n.y = (int)o.y;\
|
||||
n.z = (int)o.z;
|
||||
|
||||
float intensityf(int lighting) {
|
||||
if (lighting < 0) return 1.0f;
|
||||
float intensityf(uint16 lighting) {
|
||||
if (lighting > 0x1FFF) return 1.0f;
|
||||
float lum = 1.0f - (lighting >> 5) / 255.0f;
|
||||
//return powf(lum, 2.2f); // gamma to linear space
|
||||
return lum;// * lum; // gamma to "linear" space
|
||||
|
@@ -281,7 +281,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2D sShadow;
|
||||
#define CMP(a,b) step(b, a)
|
||||
#define CMP(a,b) step(min(1.0, b), a)
|
||||
|
||||
#ifdef SHADOW_DEPTH
|
||||
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
|
||||
@@ -298,7 +298,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SHADOW_TEXEL (2.0 / 1024.0)
|
||||
#define SHADOW_TEXEL (2.0 / SHADOW_TEX_SIZE)
|
||||
|
||||
float random(vec3 seed, float freq) {
|
||||
float dt = dot(floor(seed * freq), vec3(53.1215, 21.1352, 9.1322));
|
||||
@@ -338,14 +338,17 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
} else
|
||||
rShadow /= 4.0;
|
||||
|
||||
vec3 lv = vLightVec;
|
||||
float fade = clamp(dot(lv, lv), 0.0, 1.0);
|
||||
|
||||
return mix(rShadow, 1.0, fade);
|
||||
return rShadow;
|
||||
}
|
||||
|
||||
float getShadow() {
|
||||
return min(dot(vNormal.xyz, vLightVec), vLightProj.w) > 0.0 ? getShadow(vLightProj) : 1.0;
|
||||
vec3 p = vLightProj.xyz / vLightProj.w;
|
||||
float fade = smoothstep(0.0, 0.9, p.z);// * (p.z < 1.0 ? 1.0 : 0.0);
|
||||
float k = max(abs(p.x), abs(p.y));
|
||||
fade *= 1.0 - smoothstep(0.5, 1.0, k);
|
||||
fade *= 1.0 - smoothstep(0.999, 1.0, max(0.0, p.z));
|
||||
|
||||
return ( fade > 0.0001 && min(dot(vNormal.xyz, vLightVec), vLightProj.w) > 0.0) ? mix(1.0, getShadow(vLightProj), fade) : 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -23,6 +23,7 @@ struct Texture {
|
||||
bind(0);
|
||||
|
||||
GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
||||
bool isShadow = format == SHADOW;
|
||||
|
||||
if (format == SHADOW && !Core::support.shadowSampler) {
|
||||
format = DEPTH;
|
||||
@@ -57,8 +58,12 @@ struct Texture {
|
||||
glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
}
|
||||
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, isShadow ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, isShadow ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE);
|
||||
if (isShadow) {
|
||||
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color);
|
||||
}
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
|
16
src/utils.h
16
src/utils.h
@@ -725,6 +725,17 @@ struct Box {
|
||||
return min;
|
||||
}
|
||||
|
||||
Box intersection2D(const Box &b) const {
|
||||
Box r(vec3(0.0f), vec3(0.0f));
|
||||
if (max.x < b.min.x || min.x > b.max.x) return r;
|
||||
if (max.y < b.min.y || min.y > b.max.y) return r;
|
||||
r.max.x = ::min(max.x, b.max.x);
|
||||
r.max.y = ::min(max.y, b.max.y);
|
||||
r.min.x = ::max(min.x, b.min.x);
|
||||
r.min.y = ::max(min.y, b.min.y);
|
||||
return r;
|
||||
}
|
||||
|
||||
Box& operator += (const Box &box) {
|
||||
min.x = ::min(min.x, box.min.x);
|
||||
min.y = ::min(min.y, box.min.y);
|
||||
@@ -772,6 +783,11 @@ struct Box {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
void expand(const vec3 &v) {
|
||||
min -= v;
|
||||
max += v;
|
||||
}
|
||||
|
||||
void rotate90(int n) {
|
||||
switch (n) {
|
||||
case 0 : break;
|
||||
|
Reference in New Issue
Block a user