1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-01-17 21:09:00 +01:00

add view frustum & portals culling

This commit is contained in:
XProger 2016-08-31 03:37:52 +03:00
parent 9d60262916
commit b8f49e4883
7 changed files with 206 additions and 21 deletions

Binary file not shown.

View File

@ -3,10 +3,133 @@
#include "core.h"
#define MAX_CLIP_PLANES 16
struct Camera {
struct Frustum {
struct Poly {
vec3 vertices[MAX_CLIP_PLANES];
int count;
};
vec3 pos;
vec4 planes[MAX_CLIP_PLANES];
int count;
void calcPlanes(const mat4 &m) {
count = 4;
planes[0] = vec4(m.e30 - m.e00, m.e31 - m.e01, m.e32 - m.e02, m.e33 - m.e03); // right
planes[1] = vec4(m.e30 + m.e00, m.e31 + m.e01, m.e32 + m.e02, m.e33 + m.e03); // left
planes[2] = vec4(m.e30 - m.e10, m.e31 - m.e11, m.e32 - m.e12, m.e33 - m.e13); // top
planes[3] = vec4(m.e30 + m.e10, m.e31 + m.e11, m.e32 + m.e12, m.e33 + m.e13); // bottom
for (int i = 0; i < count; i++)
planes[i] *= 1.0f / planes[i].xyz.length();
}
void calcPlanes(const Poly &poly) {
count = poly.count;
ASSERT(count < MAX_CLIP_PLANES);
if (!count) return;
vec3 e1 = poly.vertices[0] - pos;
for (int i = 0; i < count; i++) {
vec3 e2 = poly.vertices[(i + 1) % count] - pos;
planes[i].xyz = e1.cross(e2).normal();
planes[i].w = -(pos.dot(planes[i].xyz));
e1 = e2;
}
}
void clipPlane(const Poly &src, Poly &dst, const vec4 &plane) {
dst.count = 0;
if (!src.count) return;
float t1 = src.vertices[0].dot(plane.xyz) + plane.w;
for (int i = 0; i < src.count; i++) {
const vec3 &v1 = src.vertices[i];
const vec3 &v2 = src.vertices[(i + 1) % src.count];
float t2 = v2.dot(plane.xyz) + plane.w;
if (t1 >= 0.0f) {
dst.vertices[dst.count++] = v1;
ASSERT(dst.count < MAX_CLIP_PLANES);
}
if (t1 * t2 < 0.0f) {
float k1 = t2 / (t2 - t1);
float k2 = t1 / (t2 - t1);
dst.vertices[dst.count++] = v1 * k1 - v2 * k2;
ASSERT(dst.count < MAX_CLIP_PLANES);
}
t1 = t2;
}
}
bool clipByPortal(const vec3 *vertices, const vec3 &normal) { // 4 vertices
if (normal.dot(pos - vertices[0]) < 0.0f) // check portal winding order
return false;
Poly poly[2];
poly[0].count = 4;
memmove(poly[0].vertices, vertices, sizeof(vec3) * poly[0].count);
int j = 0;
for (int i = 0; i < count; i++, j ^= 1)
clipPlane(poly[j], poly[j ^ 1], planes[i]);
if (poly[j].count < 3)
return false;
calcPlanes(poly[j]);
return true;
}
bool isVisible(const vec3 &min, const vec3 &max) const {
if (count < 3) return false;
for (int i = 0; i < count; i++) {
const vec3 &n = planes[i].xyz;
const float d = -planes[i].w;
if (n.dot(max) < d &&
n.dot(vec3(min.x, max.y, max.z)) < d &&
n.dot(vec3(max.x, min.y, max.z)) < d &&
n.dot(vec3(min.x, min.y, max.z)) < d &&
n.dot(vec3(max.x, max.y, min.z)) < d &&
n.dot(vec3(min.x, max.y, min.z)) < d &&
n.dot(vec3(max.x, min.y, min.z)) < d &&
n.dot(min) < d)
return false;
}
return true;
}
bool isVisible(const vec3 &center, float radius) {
if (count < 3) return false;
for (int i = 0; i < count; i++)
if (planes[i].xyz.dot(center) + planes[i].w < -radius)
return false;
return true;
}
} *frustum;
float fov, znear, zfar;
vec3 pos, angle, offset;
Camera() : frustum(new Frustum()) {}
~Camera() {
delete frustum;
}
void update() {
#ifdef FREE_CAMERA
vec3 dir = vec3(sinf(angle.y - PI) * cosf(-angle.x), -sinf(-angle.x), cosf(angle.y - PI) * cosf(-angle.x));
@ -42,6 +165,9 @@ struct Camera {
Core::mViewProj = Core::mProj * Core::mView;
Core::viewPos = Core::mView.inverse().getPos();
frustum->pos = Core::viewPos;
frustum->calcPlanes(Core::mViewProj);
}
};

View File

@ -27,7 +27,7 @@ struct Controller {
lastFrame = 0;
TR::Entity &e = level->entities[entity];
pos = vec3(e.x, e.y, e.z);
pos = vec3((float)e.x, (float)e.y, (float)e.z);
angle = e.rotation / 16384.0f * PI * 0.5f;
sc = 0;
@ -83,7 +83,7 @@ struct Controller {
// stateMask[TR::STATE_FAST_TURN_14]
stateMask[TR::STATE_COMPRESS] = GROUND | JUMP;
stateMask[TR::STATE_BACK] = GROUND | WALK | BACK;
stateMask[TR::STATE_SWIM] = WATER | FORTH;
stateMask[TR::STATE_SWIM] = WATER | JUMP;
// stateMask[TR::STATE_GLIDE]
// stateMask[TR::STATE_NULL_19]
// stateMask[TR::STATE_FAST_TURN_20]
@ -106,7 +106,13 @@ struct Controller {
stateMask[TR::STATE_USE_KEY] = GROUND | ACTION | KEY;
stateMask[TR::STATE_USE_PUZZLE] = GROUND | ACTION | PUZZLE;
stateMask[TR::STATE_GLIDE] = WATER | JUMP;
stateMask[TR::STATE_SWAN_DIVE] = JUMP | WALK | FORTH;
stateMask[TR::STATE_TREAD] = WATER | GROUND;
stateMask[TR::STATE_UNDERWATER_DEATH] = WATER | DEATH;
fTime += Core::deltaTime;
@ -254,8 +260,6 @@ struct Controller {
}
}
float dt = Core::deltaTime * 30.0f;
if (onGround) {
@ -263,8 +267,10 @@ struct Controller {
velocity.x = sinf(d) * speed;
velocity.z = cosf(d) * speed;
}
velocity.y += GRAVITY * dt;
if (endFrame) {
fIndex = anim->nextFrame;
int id = anim->nextAnimation;
@ -360,7 +366,7 @@ struct Controller {
TR::Room::Sector &s = getSector(dx, dz);
TR::Entity &entity = getEntity();
float bottom = (int)s.floor * 256;
float bottom = s.floor * 256.0f;
float fx = dx / 1024.0f, fz = dz / 1024.0f;

View File

@ -6,6 +6,8 @@
#define TR1_DEMO
namespace TR {
#define ROOM_FLAG_VISIBLE 0x8000
#define DATA_PORTAL 0x01
#define DATA_FLOOR 0x02
#define DATA_CEILING 0x03
@ -156,6 +158,8 @@ namespace TR {
struct Vertex {
int16 x, y, z;
operator vec3() const { return vec3((float)x, (float)y, (float)z); };
};
struct Rectangle {

View File

@ -238,7 +238,7 @@ struct Level {
info.vStart = vCount;
info.iStart = iCount;
info.center = ptr->center;
// info.radius = ptr->radius;
info.radius = ptr->radius;
TR::Vertex *mVertices = (TR::Vertex*)&ptr->vertices;
@ -423,13 +423,16 @@ struct Level {
return NULL;
}
//#define SCALE (1.0f / 1024.0f / 2.0f)
void renderRoom(int index) {
TR::Room &room = level.rooms[index];
if (room.flags & ROOM_FLAG_VISIBLE) return; // already rendered
room.flags |= ROOM_FLAG_VISIBLE;
vec3 offset = vec3(room.info.x, 0.0f, room.info.z);
mat4 m = Core::mModel;
Core::mModel.translate(vec3(room.info.x, 0.0f, room.info.z));
Core::mModel.translate(offset);
Core::color = vec4(1.0f);
Core::ambient = vec3(1.0f);
Core::lightColor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
@ -443,15 +446,17 @@ struct Level {
Core::mModel = m;
// meshes
for (int j = 0; j < room.meshesCount; j++) {
TR::Room::Mesh &rMesh = room.meshes[j];
for (int i = 0; i < room.meshesCount; i++) {
TR::Room::Mesh &rMesh = room.meshes[i];
TR::StaticMesh *sMesh = getMeshByID(rMesh.meshID);
ASSERT(sMesh != NULL);
mat4 m = Core::mModel;
Core::mModel.translate(vec3(rMesh.x, rMesh.y, rMesh.z));
Core::mModel.translate(vec3((float)rMesh.x, (float)rMesh.y, (float)rMesh.z));
Core::mModel.rotateY(rMesh.rotation / 16384.0f * PI * 0.5f);
// TODO: check visibility for sMesh.vBox
getLight(vec3(rMesh.x, rMesh.y, rMesh.z), index);
renderMesh(sMesh->mesh);
@ -459,6 +464,28 @@ struct Level {
Core::mModel = m;
}
Camera::Frustum *camFrustum = camera.frustum; // push camera frustum
Camera::Frustum frustum = *camFrustum;
camera.frustum = &frustum;
for (int i = 0; i < room.portalsCount; i++) {
TR::Room::Portal &p = room.portals[i];
vec3 v[4] = {
offset + p.vertices[0],
offset + p.vertices[1],
offset + p.vertices[2],
offset + p.vertices[3],
};
if (frustum.clipByPortal(v, p.normal)) {
renderRoom(p.roomIndex);
frustum = *camFrustum;
}
}
camera.frustum = camFrustum; // pop camera frustum
/*
// sprites
Core::setBlending(bmAlpha);
@ -474,8 +501,12 @@ struct Level {
for (int i = 0; i < mCount; i++)
if (meshInfo[i].offset == level.meshOffsets[meshOffset]) {
shader->setParam(uModel, Core::mModel);
mesh->render(meshInfo[i]);
MeshInfo &m = meshInfo[i];
if (camera.frustum->isVisible(Core::mModel * m.center, m.radius)) {
shader->setParam(uModel, Core::mModel);
mesh->render(m);
}
break;
}
}
@ -687,6 +718,8 @@ struct Level {
void renderEntity(const TR::Entity &entity) {
// if (!(entity.flags & ENTITY_FLAG_VISIBLE))
// return;
if (!(level.rooms[entity.room].flags & ROOM_FLAG_VISIBLE)) // check for room visibility
return;
mat4 m = Core::mModel;
Core::mModel.translate(vec3(entity.x, entity.y, entity.z));
@ -902,13 +935,13 @@ struct Level {
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 = l.intensity / 8191.0f;
vec3 p = vec3(l.x, l.y, l.z);
vec4 color = vec4(a, a, a, 1);
Debug::Draw::point(p, color);
if (i == roomIndex && j == lightIndex)
color = vec4(0, 1, 0, 1);
Debug::Draw::sphere(p, l.fade, color);
Debug::Draw::sphere(p, l.attenuation, color);
}
glEnd();
}
@ -942,7 +975,15 @@ struct Level {
*/
}
int getCameraRoomIndex() {
for (int i = 0; i < level.roomsCount; i++)
if (lara->insideRoom(Core::viewPos, i))
return i;
return lara->getEntity().room;
}
void render() {
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#ifndef FREE_CAMERA
camera.pos = vec3(-lara->pos.x, -lara->pos.y + 768, lara->pos.z);
#endif
@ -953,7 +994,6 @@ struct Level {
mesh->bind();
shader->setParam(uViewProj, Core::mViewProj);
shader->setParam(uModel, Core::mModel);
glEnable(GL_DEPTH_TEST);
@ -962,7 +1002,13 @@ struct Level {
Core::mModel.identity();
for (int i = 0; i < level.roomsCount; i++)
renderRoom(i);
level.rooms[i].flags &= ~ROOM_FLAG_VISIBLE; // clear visible flag
renderRoom(getCameraRoomIndex());
renderRoom(lara->getEntity().room);
//for (int i = 0; i < level.roomsCount; i++)
// renderRoom(i);
for (int i = 0; i < level.entitiesCount; i++)
renderEntity(level.entities[i]);
@ -971,8 +1017,8 @@ struct Level {
// debugMeshes();
Debug::Draw::begin();
debugRooms();
// debugLights();
// debugRooms();
// debugLights();
debugPortals();
Debug::Draw::end();
#endif

View File

@ -114,6 +114,8 @@ struct vec4 {
vec4(float s) : x(s), y(s), z(s), w(s) {}
vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
vec4(const vec3 &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
vec4& operator *= (const vec4 &v) { x*=v.x; y*=v.y; z*=v.z; w*=v.w; return *this; }
};
struct quat {

View File

@ -70,7 +70,7 @@
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NOMINMAX;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -79,6 +79,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FloatingPointModel>Strict</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>