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:
parent
9d60262916
commit
b8f49e4883
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
126
src/camera.h
126
src/camera.h
@ -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 ¢er, 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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
76
src/level.h
76
src/level.h
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user