Work on room culling

This commit is contained in:
James Lambert 2022-05-21 20:39:01 -06:00
parent 22995afadf
commit d1d8ed9b76
16 changed files with 423 additions and 225 deletions

View file

@ -148,7 +148,7 @@ int main(int argc, char *argv[]) {
if (args.mIsLevel) { if (args.mIsLevel) {
std::cout << "Grouping objects by room" << std::endl; std::cout << "Grouping objects by room" << std::endl;
RoomGenerator roomGenerator; RoomGenerator roomGenerator(settings);
roomGenerator.TraverseScene(scene); roomGenerator.TraverseScene(scene);
roomGenerator.GenerateDefinitions(scene, fileDef); roomGenerator.GenerateDefinitions(scene, fileDef);

View file

@ -175,6 +175,13 @@ void CFileDefinition::AddDefinition(std::unique_ptr<FileDefinition> definition)
mDefinitions.push_back(std::move(definition)); mDefinitions.push_back(std::move(definition));
} }
std::string CFileDefinition::AddDataDefinition(const std::string& nameHint, const std::string& dataType, bool isArray, const std::string& location, std::unique_ptr<DataChunk> data) {
std::string name = GetUniqueName(nameHint);
std::unique_ptr<FileDefinition> def(new DataFileDefinition(dataType, name, isArray, location, std::move(data)));
AddDefinition(std::move(def));
return name;
}
void CFileDefinition::AddMacro(const std::string& name, const std::string& value) { void CFileDefinition::AddMacro(const std::string& name, const std::string& value) {
mMacros.push_back(name + " " + value); mMacros.push_back(name + " " + value);
} }

View file

@ -31,6 +31,7 @@ public:
CFileDefinition(std::string prefix, float modelScale, aiQuaternion modelRotate); CFileDefinition(std::string prefix, float modelScale, aiQuaternion modelRotate);
void AddDefinition(std::unique_ptr<FileDefinition> definition); void AddDefinition(std::unique_ptr<FileDefinition> definition);
std::string AddDataDefinition(const std::string& nameHint, const std::string& dataType, bool isArray, const std::string& location, std::unique_ptr<DataChunk> data);
void AddMacro(const std::string& name, const std::string& value); void AddMacro(const std::string& name, const std::string& value);
std::string GetVertexBuffer(std::shared_ptr<ExtendedMesh> mesh, VertexType vertexType, int textureWidth, int textureHeight, const std::string& modelSuffix); std::string GetVertexBuffer(std::shared_ptr<ExtendedMesh> mesh, VertexType vertexType, int textureWidth, int textureHeight, const std::string& modelSuffix);

View file

@ -4,165 +4,6 @@
#include <algorithm> #include <algorithm>
#define SAME_TOLERANCE 0.00001f
bool bottomRightMost(const aiVector3D& a, const aiVector3D& b) {
if (fabs(a.x - b.x) > SAME_TOLERANCE) {
return a.x < b.x;
}
if (fabs(a.y - b.y) > SAME_TOLERANCE) {
return a.y < b.y;
}
return a.z - b.z;
}
const aiVector3D* findMostOppositeEdge(const aiVector3D& fromEdge, const std::vector<aiVector3D>& edges) {
return std::min_element(edges.begin(), edges.end(), [=](const aiVector3D& a, const aiVector3D& b) {
return (a * fromEdge) < (b * fromEdge);
}).base();
}
CollisionQuad::CollisionQuad(aiMesh* mesh, const aiMatrix4x4& transform) {
if (mesh->mVertices) {
std::vector<aiVector3D> transformedPoints;
for (unsigned index = 0; index < mesh->mNumVertices; ++index) {
transformedPoints.push_back(transform * mesh->mVertices[index]);
}
auto cornerPointer = std::min_element(transformedPoints.begin(), transformedPoints.end(), bottomRightMost);
unsigned cornerIndex = cornerPointer - transformedPoints.begin();
corner = *cornerPointer;
std::set<int> adjacentIndices;
findAdjacentVertices(mesh, cornerIndex, adjacentIndices);
std::vector<aiVector3D> edgesFromCorner;
for (auto index : adjacentIndices) {
edgesFromCorner.push_back(transformedPoints[index] - corner);
}
auto edgeAPoint = findMostOppositeEdge(edgesFromCorner[0], edgesFromCorner);
edgeA = *edgeAPoint;
edgeALength = edgeA.Length();
edgeA.Normalize();
auto edgeBPoint = findMostOppositeEdge(edgeA, edgesFromCorner);
edgeB = *edgeBPoint;
edgeBLength = edgeB.Length();
edgeB.Normalize();
aiMatrix3x3 rotation(transform);
for (unsigned i = 0; i < mesh->mNumVertices; ++i) {
normal += rotation * mesh->mNormals[i];
}
normal.Normalize();
if ((edgeA ^ edgeB) * normal < 0.0f) {
aiVector3D tmpEdge = edgeA;
float tmpLength = edgeALength;
edgeA = edgeB;
edgeALength = edgeBLength;
edgeB = tmpEdge;
edgeBLength = tmpLength;
}
corner.x = 0.001f * round(1000.0f * corner.x);
corner.y = 0.001f * round(1000.0f * corner.y);
corner.z = 0.001f * round(1000.0f * corner.z);
edgeA.x = 0.001f * round(1000.0f * edgeA.x);
edgeA.y = 0.001f * round(1000.0f * edgeA.y);
edgeA.z = 0.001f * round(1000.0f * edgeA.z);
edgeALength = 0.001f * round(1000.0f * edgeALength);
edgeB.x = 0.001f * round(1000.0f * edgeB.x);
edgeB.y = 0.001f * round(1000.0f * edgeB.y);
edgeB.z = 0.001f * round(1000.0f * edgeB.z);
edgeBLength = 0.001f * round(1000.0f * edgeBLength);
normal.x = 0.001f * round(1000.0f * normal.x);
normal.y = 0.001f * round(1000.0f * normal.y);
normal.z = 0.001f * round(1000.0f * normal.z);
} else {
corner = aiVector3D();
edgeA = aiVector3D();
edgeALength = 0.0f;
edgeB = aiVector3D();
edgeBLength = 0.0f;
normal = aiVector3D();
}
}
std::unique_ptr<DataChunk> CollisionQuad::Generate() {
std::unique_ptr<StructureDataChunk> result(new StructureDataChunk());
result->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(corner)));
result->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(edgeA)));
result->AddPrimitive(edgeALength);
result->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(edgeB)));
result->AddPrimitive(edgeBLength);
std::unique_ptr<StructureDataChunk> plane(new StructureDataChunk());
plane->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(normal)));
plane->AddPrimitive(-(corner * normal));
result->Add(std::move(plane));
result->AddPrimitive(0xF);
return result;
}
#define FIXED_POINT_PRECISION 8
#define FIXED_POINT_SCALAR (1 << FIXED_POINT_PRECISION)
void CollisionQuad::ToLocalCoords(const aiVector3D& input, short& outX, short& outY) {
aiVector3D relative = input - corner;
outX = (short)(relative * edgeA * FIXED_POINT_SCALAR + 0.5f);
outY = (short)(relative * edgeB * FIXED_POINT_SCALAR + 0.5f);
}
#define INSIDE_NORMAL_TOLERANCE 0.1f
bool CollisionQuad::IsCoplanar(ExtendedMesh& mesh, float relativeScale) const {
for (unsigned i = 0; i < mesh.mMesh->mNumVertices; ++i) {
aiVector3D offset = mesh.mMesh->mVertices[i] * relativeScale - corner;
float z = offset * normal;
if (fabs(z) >= INSIDE_NORMAL_TOLERANCE) {
return false;
}
float x = offset * edgeA;
if (x < -INSIDE_NORMAL_TOLERANCE || x > edgeALength + INSIDE_NORMAL_TOLERANCE) {
return false;
}
float y = offset * edgeB;
if (y < -INSIDE_NORMAL_TOLERANCE || y > edgeBLength + INSIDE_NORMAL_TOLERANCE) {
return false;
}
}
return true;
}
CollisionGenerator::CollisionGenerator(const DisplayListSettings& settings) : CollisionGenerator::CollisionGenerator(const DisplayListSettings& settings) :
DefinitionGenerator(), DefinitionGenerator(),
mSettings(settings) {} mSettings(settings) {}
@ -177,11 +18,7 @@ void CollisionGenerator::GenerateDefinitions(const aiScene* scene, CFileDefiniti
std::unique_ptr<StructureDataChunk> colliderTypeChunk(new StructureDataChunk()); std::unique_ptr<StructureDataChunk> colliderTypeChunk(new StructureDataChunk());
std::unique_ptr<StructureDataChunk> collisionObjectChunk(new StructureDataChunk()); std::unique_ptr<StructureDataChunk> collisionObjectChunk(new StructureDataChunk());
aiMatrix4x4 scale; aiMatrix4x4 globalTransform = mSettings.CreateCollisionTransform();
aiMatrix4x4::Scaling(aiVector3D(1, 1, 1) * mSettings.mCollisionScale, scale);
aiMatrix4x4 rotation(mSettings.mRotateModel.GetMatrix());
aiMatrix4x4 globalTransform = rotation * scale;
int meshCount = 0; int meshCount = 0;

View file

@ -3,23 +3,7 @@
#include "DefinitionGenerator.h" #include "DefinitionGenerator.h"
#include "../DisplayListSettings.h" #include "../DisplayListSettings.h"
#include "CollisionQuad.h"
struct CollisionQuad {
CollisionQuad(aiMesh* mesh, const aiMatrix4x4& transform);
aiVector3D corner;
aiVector3D edgeA;
float edgeALength;
aiVector3D edgeB;
float edgeBLength;
aiVector3D normal;
std::unique_ptr<DataChunk> Generate();
void ToLocalCoords(const aiVector3D& input, short& outX, short& outY);
bool IsCoplanar(ExtendedMesh& mesh, float relativeScale) const;
};
struct CollisionGeneratorOutput { struct CollisionGeneratorOutput {
std::string quadsName; std::string quadsName;

View file

@ -0,0 +1,160 @@
#include "CollisionQuad.h"
#define SAME_TOLERANCE 0.00001f
bool bottomRightMost(const aiVector3D& a, const aiVector3D& b) {
if (fabs(a.x - b.x) > SAME_TOLERANCE) {
return a.x < b.x;
}
if (fabs(a.y - b.y) > SAME_TOLERANCE) {
return a.y < b.y;
}
return a.z - b.z;
}
const aiVector3D* findMostOppositeEdge(const aiVector3D& fromEdge, const std::vector<aiVector3D>& edges) {
return std::min_element(edges.begin(), edges.end(), [=](const aiVector3D& a, const aiVector3D& b) {
return (a * fromEdge) < (b * fromEdge);
}).base();
}
CollisionQuad::CollisionQuad(aiMesh* mesh, const aiMatrix4x4& transform) {
if (mesh->mVertices) {
std::vector<aiVector3D> transformedPoints;
for (unsigned index = 0; index < mesh->mNumVertices; ++index) {
transformedPoints.push_back(transform * mesh->mVertices[index]);
}
auto cornerPointer = std::min_element(transformedPoints.begin(), transformedPoints.end(), bottomRightMost);
unsigned cornerIndex = cornerPointer - transformedPoints.begin();
corner = *cornerPointer;
std::set<int> adjacentIndices;
findAdjacentVertices(mesh, cornerIndex, adjacentIndices);
std::vector<aiVector3D> edgesFromCorner;
for (auto index : adjacentIndices) {
edgesFromCorner.push_back(transformedPoints[index] - corner);
}
auto edgeAPoint = findMostOppositeEdge(edgesFromCorner[0], edgesFromCorner);
edgeA = *edgeAPoint;
edgeALength = edgeA.Length();
edgeA.Normalize();
auto edgeBPoint = findMostOppositeEdge(edgeA, edgesFromCorner);
edgeB = *edgeBPoint;
edgeBLength = edgeB.Length();
edgeB.Normalize();
aiMatrix3x3 rotation(transform);
for (unsigned i = 0; i < mesh->mNumVertices; ++i) {
normal += rotation * mesh->mNormals[i];
}
normal.Normalize();
if ((edgeA ^ edgeB) * normal < 0.0f) {
aiVector3D tmpEdge = edgeA;
float tmpLength = edgeALength;
edgeA = edgeB;
edgeALength = edgeBLength;
edgeB = tmpEdge;
edgeBLength = tmpLength;
}
corner.x = 0.001f * round(1000.0f * corner.x);
corner.y = 0.001f * round(1000.0f * corner.y);
corner.z = 0.001f * round(1000.0f * corner.z);
edgeA.x = 0.001f * round(1000.0f * edgeA.x);
edgeA.y = 0.001f * round(1000.0f * edgeA.y);
edgeA.z = 0.001f * round(1000.0f * edgeA.z);
edgeALength = 0.001f * round(1000.0f * edgeALength);
edgeB.x = 0.001f * round(1000.0f * edgeB.x);
edgeB.y = 0.001f * round(1000.0f * edgeB.y);
edgeB.z = 0.001f * round(1000.0f * edgeB.z);
edgeBLength = 0.001f * round(1000.0f * edgeBLength);
normal.x = 0.001f * round(1000.0f * normal.x);
normal.y = 0.001f * round(1000.0f * normal.y);
normal.z = 0.001f * round(1000.0f * normal.z);
} else {
corner = aiVector3D();
edgeA = aiVector3D();
edgeALength = 0.0f;
edgeB = aiVector3D();
edgeBLength = 0.0f;
normal = aiVector3D();
}
}
std::unique_ptr<DataChunk> CollisionQuad::Generate() {
std::unique_ptr<StructureDataChunk> result(new StructureDataChunk());
result->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(corner)));
result->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(edgeA)));
result->AddPrimitive(edgeALength);
result->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(edgeB)));
result->AddPrimitive(edgeBLength);
std::unique_ptr<StructureDataChunk> plane(new StructureDataChunk());
plane->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(normal)));
plane->AddPrimitive(-(corner * normal));
result->Add(std::move(plane));
result->AddPrimitive(0xF);
return result;
}
#define FIXED_POINT_PRECISION 8
#define FIXED_POINT_SCALAR (1 << FIXED_POINT_PRECISION)
void CollisionQuad::ToLocalCoords(const aiVector3D& input, short& outX, short& outY) {
aiVector3D relative = input - corner;
outX = (short)(relative * edgeA * FIXED_POINT_SCALAR + 0.5f);
outY = (short)(relative * edgeB * FIXED_POINT_SCALAR + 0.5f);
}
#define INSIDE_NORMAL_TOLERANCE 0.1f
bool CollisionQuad::IsCoplanar(ExtendedMesh& mesh, float relativeScale) const {
for (unsigned i = 0; i < mesh.mMesh->mNumVertices; ++i) {
aiVector3D offset = mesh.mMesh->mVertices[i] * relativeScale - corner;
float z = offset * normal;
if (fabs(z) >= INSIDE_NORMAL_TOLERANCE) {
return false;
}
float x = offset * edgeA;
if (x < -INSIDE_NORMAL_TOLERANCE || x > edgeALength + INSIDE_NORMAL_TOLERANCE) {
return false;
}
float y = offset * edgeB;
if (y < -INSIDE_NORMAL_TOLERANCE || y > edgeBLength + INSIDE_NORMAL_TOLERANCE) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,24 @@
#ifndef __COLLISION_QUAD_H__
#define __COLLISION_QUAD_H__
#include <assimp/mesh.h>
#include "../ExtendedMesh.h"
struct CollisionQuad {
CollisionQuad(aiMesh* mesh, const aiMatrix4x4& transform);
aiVector3D corner;
aiVector3D edgeA;
float edgeALength;
aiVector3D edgeB;
float edgeBLength;
aiVector3D normal;
std::unique_ptr<DataChunk> Generate();
void ToLocalCoords(const aiVector3D& input, short& outX, short& outY);
bool IsCoplanar(ExtendedMesh& mesh, float relativeScale) const;
};
#endif

View file

@ -235,6 +235,70 @@ void LevelGenerator::CalculateLocations(const aiScene* scene, CFileDefinition& f
fileDefinition.AddDefinition(std::move(triggersDef)); fileDefinition.AddDefinition(std::move(triggersDef));
} }
void LevelGenerator::CalculateDoorwaysAndRooms(const aiScene* scene, CFileDefinition& fileDefinition, std::string& doorwaysName, std::string& roomsName) {
std::vector<std::vector<int>> roomDoorways;
for (int i = 0; i < mRoomOutput.roomCount; ++i) {
roomDoorways.push_back(std::vector<int>());
}
int doorwayIndex = 0;
std::unique_ptr<StructureDataChunk> doorways(new StructureDataChunk());
for (auto& doorway : mRoomOutput.doorways) {
roomDoorways[doorway.roomA].push_back(doorwayIndex);
roomDoorways[doorway.roomB].push_back(doorwayIndex);
std::unique_ptr<StructureDataChunk> doorwayData(new StructureDataChunk());
doorwayData->Add(std::move(doorway.quad.Generate()));
doorwayData->AddPrimitive(doorway.roomA);
doorwayData->AddPrimitive(doorway.roomB);
doorways->Add(std::move(doorwayData));
++doorwayIndex;
}
doorwaysName = fileDefinition.AddDataDefinition(
"doorways",
"struct Doorway",
true,
"_geo",
std::move(doorways)
);
std::unique_ptr<StructureDataChunk> rooms(new StructureDataChunk());
for (int i = 0; i < mRoomOutput.roomCount; ++i) {
std::unique_ptr<StructureDataChunk> doorwayList(new StructureDataChunk());
for (auto doorway : roomDoorways[i]) {
doorwayList->AddPrimitive(doorway);
}
std::string doorwayListName = fileDefinition.AddDataDefinition(
"room_doorways",
"short",
true,
"_geo",
std::move(doorwayList)
);
std::unique_ptr<StructureDataChunk> room(new StructureDataChunk());
room->AddPrimitive(std::move(doorwayListName));
room->AddPrimitive(roomDoorways[i].size());
rooms->Add(std::move(room));
}
roomsName = fileDefinition.AddDataDefinition(
"rooms",
"struct Room",
true,
"_geo",
std::move(rooms)
);
}
void LevelGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition) { void LevelGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition) {
std::string portalSurfaces; std::string portalSurfaces;
std::string portalSurfaceMapping; std::string portalSurfaceMapping;
@ -248,23 +312,31 @@ void LevelGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition&
std::string locations; std::string locations;
CalculateLocations(scene, fileDefinition, locations); CalculateLocations(scene, fileDefinition, locations);
std::string doorways;
std::string rooms;
CalculateDoorwaysAndRooms(scene, fileDefinition, doorways, rooms);
std::unique_ptr<StructureDataChunk> levelDef(new StructureDataChunk()); std::unique_ptr<StructureDataChunk> levelDef(new StructureDataChunk());
levelDef->AddPrimitive(mCollisionOutput.quadsName); levelDef->AddPrimitive("collisionQuads", mCollisionOutput.quadsName);
levelDef->AddPrimitive(mStaticOutput.staticContentName); levelDef->AddPrimitive("staticContent", mStaticOutput.staticContentName);
levelDef->AddPrimitive(mStaticOutput.roomMappingName); levelDef->AddPrimitive("roomStaticMapping", mStaticOutput.roomMappingName);
levelDef->AddPrimitive(boundingBoxes); levelDef->AddPrimitive("staticBoundingBoxes", boundingBoxes);
levelDef->AddPrimitive(portalSurfaces); levelDef->AddPrimitive("portalSurfaces", portalSurfaces);
levelDef->AddPrimitive(portalSurfaceMapping); levelDef->AddPrimitive("portalSurfaceMapping", portalSurfaceMapping);
levelDef->AddPrimitive(triggers); levelDef->AddPrimitive("triggers", triggers);
levelDef->AddPrimitive(locations); levelDef->AddPrimitive("locations", locations);
levelDef->AddPrimitive(mCollisionOutput.quads.size()); levelDef->AddPrimitive("rooms", rooms);
levelDef->AddPrimitive(mStaticOutput.staticMeshes.size()); levelDef->AddPrimitive("doorways", doorways);
levelDef->AddPrimitive(portalSurfacesCount); levelDef->AddPrimitive("collisionQuadCount", mCollisionOutput.quads.size());
levelDef->AddPrimitive(mTriggerOutput.triggers.size()); levelDef->AddPrimitive("staticContentCount", mStaticOutput.staticMeshes.size());
levelDef->AddPrimitive(mRoomOutput.namedLocations.size()); levelDef->AddPrimitive("portalSurfaceCount", portalSurfacesCount);
levelDef->AddPrimitive(mRoomOutput.FindLocationRoom("start")); levelDef->AddPrimitive("triggerCount", mTriggerOutput.triggers.size());
levelDef->AddPrimitive("locationCount", mRoomOutput.namedLocations.size());
levelDef->AddPrimitive("roomCount", mRoomOutput.roomCount);
levelDef->AddPrimitive("doorwayCount", mRoomOutput.doorways.size());
levelDef->AddPrimitive("startLocation", mRoomOutput.FindLocationRoom("start"));
fileDefinition.AddDefinition(std::unique_ptr<FileDefinition>(new DataFileDefinition("struct LevelDefinition", fileDefinition.GetUniqueName("level"), false, "_geo", std::move(levelDef)))); fileDefinition.AddDefinition(std::unique_ptr<FileDefinition>(new DataFileDefinition("struct LevelDefinition", fileDefinition.GetUniqueName("level"), false, "_geo", std::move(levelDef))));
} }

View file

@ -34,6 +34,8 @@ private:
void CalculateTriggers(const aiScene* scene, CFileDefinition& fileDefinition, std::string& triggersName); void CalculateTriggers(const aiScene* scene, CFileDefinition& fileDefinition, std::string& triggersName);
void CalculateLocations(const aiScene* scene, CFileDefinition& fileDefinition, std::string& locationsName); void CalculateLocations(const aiScene* scene, CFileDefinition& fileDefinition, std::string& locationsName);
void CalculateDoorwaysAndRooms(const aiScene* scene, CFileDefinition& fileDefinition, std::string& doorwaysName, std::string& roomsName);
}; };
#endif #endif

View file

@ -8,6 +8,15 @@
#define LOCATION_PREFIX "@location " #define LOCATION_PREFIX "@location "
#define DOORWAY_PREFIX "@doorway"
Doorway::Doorway(const aiNode* node, const CollisionQuad& quad):
node(node), quad(quad), roomA(0), roomB(0) {
}
RoomGenerator::RoomGenerator(const DisplayListSettings& settings): DefinitionGenerator(), mSettings(settings) {}
short RoomGeneratorOutput::FindLocationRoom(const std::string& name) const { short RoomGeneratorOutput::FindLocationRoom(const std::string& name) const {
for (auto& location : namedLocations) { for (auto& location : namedLocations) {
if (location.name == name) { if (location.name == name) {
@ -39,9 +48,39 @@ void sortNodesByRoom(std::vector<aiNode*>& nodes, RoomGeneratorOutput& roomOutpu
}); });
} }
int findClosestRoom(const aiNode* node, const aiScene* scene, CFileDefinition& fileDefinition, const std::vector<RoomBlock>& roomBlocks, int ignoreRoom) {
float distance = INFINITY;
int closestRoom = 0;
for (auto& roomBlock : roomBlocks) {
if (roomBlock.roomIndex == ignoreRoom) {
continue;
}
aiVector3D localCenter;
if (node->mNumMeshes) {
auto mesh = fileDefinition.GetExtendedMesh(scene->mMeshes[node->mMeshes[0]]);
localCenter = (mesh->bbMax + mesh->bbMin) * 0.5f;
}
float roomDistance = distanceToAABB(roomBlock.boundingBox, node->mTransformation * localCenter);
if (roomDistance < distance) {
distance = roomDistance;
closestRoom = roomBlock.roomIndex;
}
}
return closestRoom;
}
void RoomGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition) { void RoomGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition) {
std::vector<RoomBlock> roomBlocks; std::vector<RoomBlock> roomBlocks;
aiMatrix4x4 collisionTransform = mSettings.CreateCollisionTransform();
mOutput.roomCount = 0; mOutput.roomCount = 0;
for (auto node : mIncludedNodes) { for (auto node : mIncludedNodes) {
@ -67,6 +106,13 @@ void RoomGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition& f
mOutput.namedLocations.push_back(location); mOutput.namedLocations.push_back(location);
} }
if (StartsWith(nodeName, DOORWAY_PREFIX) && node->mNumMeshes) {
mOutput.doorways.push_back(Doorway(node, CollisionQuad(
scene->mMeshes[node->mMeshes[0]],
collisionTransform * node->mTransformation
)));
}
} }
if (roomBlocks.size() == 0) { if (roomBlocks.size() == 0) {
@ -76,29 +122,17 @@ void RoomGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition& f
} }
for (auto node : mIncludedNodes) { for (auto node : mIncludedNodes) {
float distance = INFINITY; int closestRoom = findClosestRoom(node, scene, fileDefinition, roomBlocks, -1);
int closestRoom = 0;
for (auto& roomBlock : roomBlocks) {
aiVector3D localCenter;
if (node->mNumMeshes) {
auto mesh = fileDefinition.GetExtendedMesh(scene->mMeshes[node->mMeshes[0]]);
localCenter = (mesh->bbMax + mesh->bbMin) * 0.5f;
}
float roomDistance = distanceToAABB(roomBlock.boundingBox, node->mTransformation * localCenter);
if (roomDistance < distance) {
distance = roomDistance;
closestRoom = roomBlock.roomIndex;
}
}
mOutput.roomIndexMapping[node] = closestRoom; mOutput.roomIndexMapping[node] = closestRoom;
mOutput.roomCount = std::max(mOutput.roomCount, closestRoom + 1); mOutput.roomCount = std::max(mOutput.roomCount, closestRoom + 1);
} }
for (auto& doorway : mOutput.doorways) {
doorway.roomA = mOutput.roomIndexMapping[doorway.node];
doorway.roomB = findClosestRoom(doorway.node, scene, fileDefinition, roomBlocks, doorway.roomA);
mOutput.roomCount = std::max(mOutput.roomCount, doorway.roomB + 1);
}
} }
const RoomGeneratorOutput& RoomGenerator::GetOutput() const { const RoomGeneratorOutput& RoomGenerator::GetOutput() const {

View file

@ -2,6 +2,8 @@
#define __ROOM_GENERATOR_H__ #define __ROOM_GENERATOR_H__
#include "DefinitionGenerator.h" #include "DefinitionGenerator.h"
#include "CollisionQuad.h"
#include "../DisplayListSettings.h"
#include <map> #include <map>
@ -11,9 +13,18 @@ struct NamedLocation {
int index; int index;
}; };
struct Doorway {
Doorway(const aiNode* node, const CollisionQuad& quad);
const aiNode* node;
CollisionQuad quad;
int roomA;
int roomB;
};
struct RoomGeneratorOutput { struct RoomGeneratorOutput {
std::map<const aiNode*, int> roomIndexMapping; std::map<const aiNode*, int> roomIndexMapping;
std::vector<NamedLocation> namedLocations; std::vector<NamedLocation> namedLocations;
std::vector<Doorway> doorways;
int roomCount; int roomCount;
short FindLocationRoom(const std::string& name) const; short FindLocationRoom(const std::string& name) const;
@ -23,11 +34,14 @@ void sortNodesByRoom(std::vector<aiNode*>& nodes, RoomGeneratorOutput& roomOutpu
class RoomGenerator : public DefinitionGenerator { class RoomGenerator : public DefinitionGenerator {
public: public:
RoomGenerator(const DisplayListSettings& settings);
virtual bool ShouldIncludeNode(aiNode* node); virtual bool ShouldIncludeNode(aiNode* node);
virtual void GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition); virtual void GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition);
const RoomGeneratorOutput& GetOutput() const; const RoomGeneratorOutput& GetOutput() const;
private: private:
DisplayListSettings mSettings;
RoomGeneratorOutput mOutput; RoomGeneratorOutput mOutput;
}; };

View file

@ -61,6 +61,17 @@ struct Location {
short roomIndex; short roomIndex;
}; };
struct Doorway {
struct CollisionQuad quad;
short roomA;
short roomB;
};
struct Room {
short* doorwayIndices;
short doorwayCount;
};
struct LevelDefinition { struct LevelDefinition {
struct CollisionObject* collisionQuads; struct CollisionObject* collisionQuads;
struct StaticContentElement *staticContent; struct StaticContentElement *staticContent;
@ -71,11 +82,15 @@ struct LevelDefinition {
struct PortalSurfaceMapping* portalSurfaceMapping; struct PortalSurfaceMapping* portalSurfaceMapping;
struct Trigger* triggers; struct Trigger* triggers;
struct Location* locations; struct Location* locations;
struct Room* rooms;
struct Doorway* doorways;
short collisionQuadCount; short collisionQuadCount;
short staticContentCount; short staticContentCount;
short portalSurfaceCount; short portalSurfaceCount;
short triggerCount; short triggerCount;
short locationCount; short locationCount;
short roomCount;
short doorwayCount;
short startLocation; short startLocation;
}; };

View file

@ -81,14 +81,16 @@ void staticRenderSort(int min, int max) {
} }
} }
void staticRender(struct FrustrumCullingInformation* cullingInfo, u16 startingRoom, struct RenderState* renderState) { int staticRenderPopulateRooms(struct FrustrumCullingInformation* cullingInfo, int renderCount, u16 currentRoom, u32* visitedRooms) {
if (!gCurrentLevel) { u32 roomMask = 1 << currentRoom;
return;
if (*visitedRooms & roomMask) {
return renderCount;
} }
int renderCount = 0; *visitedRooms |= roomMask;
struct Rangeu16 staticRange = gCurrentLevel->roomStaticMapping[startingRoom]; struct Rangeu16 staticRange = gCurrentLevel->roomStaticMapping[currentRoom];
for (int i = staticRange.min; i < staticRange.max; ++i) { for (int i = staticRange.min; i < staticRange.max; ++i) {
if (isOutsideFrustrum(cullingInfo, &gCurrentLevel->staticBoundingBoxes[i])) { if (isOutsideFrustrum(cullingInfo, &gCurrentLevel->staticBoundingBoxes[i])) {
@ -100,6 +102,27 @@ void staticRender(struct FrustrumCullingInformation* cullingInfo, u16 startingRo
++renderCount; ++renderCount;
} }
for (int i = 0; i < gCurrentLevel->rooms[currentRoom].doorwayCount; ++i) {
struct Doorway* doorway = &gCurrentLevel->doorways[gCurrentLevel->rooms[currentRoom].doorwayIndices[i]];
if (isQuadOutsideFrustrum(cullingInfo, &doorway->quad)) {
continue;
}
renderCount = staticRenderPopulateRooms(cullingInfo, renderCount, currentRoom == doorway->roomA ? doorway->roomB : doorway->roomA, visitedRooms);
};
return renderCount;
}
void staticRender(struct FrustrumCullingInformation* cullingInfo, u16 startingRoom, struct RenderState* renderState) {
if (!gCurrentLevel) {
return;
}
u32 visitedRooms = 0;
int renderCount = staticRenderPopulateRooms(cullingInfo, 0, startingRoom, &visitedRooms);
renderCount = dynamicScenePopulate(cullingInfo, renderCount, gCurrentLevel->staticContentCount, gSortKey, gRenderOrder); renderCount = dynamicScenePopulate(cullingInfo, renderCount, gCurrentLevel->staticContentCount, gSortKey, gRenderOrder);
staticRenderSort(0, renderCount); staticRenderSort(0, renderCount);

View file

@ -8,9 +8,11 @@ int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Boundi
for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) { for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) {
struct Vector3 closestPoint; struct Vector3 closestPoint;
closestPoint.x = frustrum->clippingPlanes[i].normal.x < 0.0f ? boundingBox->minX : boundingBox->maxX; struct Vector3* normal = &frustrum->clippingPlanes[i].normal;
closestPoint.y = frustrum->clippingPlanes[i].normal.y < 0.0f ? boundingBox->minY : boundingBox->maxY;
closestPoint.z = frustrum->clippingPlanes[i].normal.z < 0.0f ? boundingBox->minZ : boundingBox->maxZ; closestPoint.x = normal->x < 0.0f ? boundingBox->minX : boundingBox->maxX;
closestPoint.y = normal->y < 0.0f ? boundingBox->minY : boundingBox->maxY;
closestPoint.z = normal->z < 0.0f ? boundingBox->minZ : boundingBox->maxZ;
if (planePointDistance(&frustrum->clippingPlanes[i], &closestPoint) < 0.0f) { if (planePointDistance(&frustrum->clippingPlanes[i], &closestPoint) < 0.0f) {
return 1; return 1;
@ -22,7 +24,7 @@ int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Boundi
} }
int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Vector3* scaledCenter, float scaledRadius) { int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Vector3* scaledCenter, float scaledRadius) {
for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) { for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) {
if (planePointDistance(&frustrum->clippingPlanes[i], scaledCenter) < -scaledRadius) { if (planePointDistance(&frustrum->clippingPlanes[i], scaledCenter) < -scaledRadius) {
return 1; return 1;
} }
@ -31,6 +33,27 @@ int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct
return 0; return 0;
} }
int isQuadOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct CollisionQuad* quad) {
for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) {
struct Vector3* normal = &frustrum->clippingPlanes[i].normal;
float aLerp = vector3Dot(normal, &quad->edgeA) < 0.0f ? 0.0f : quad->edgeALength;
float bLerp = vector3Dot(normal, &quad->edgeB) < 0.0f ? 0.0f : quad->edgeBLength;
struct Vector3 closestPoint;
vector3AddScaled(&quad->corner, &quad->edgeA, aLerp, &closestPoint);
vector3AddScaled(&closestPoint, &quad->edgeB, bLerp, &closestPoint);
vector3Scale(&closestPoint, &closestPoint, SCENE_SCALE);
if (planePointDistance(&frustrum->clippingPlanes[i], &closestPoint) < 0.0f) {
return 1;
}
}
return 0;
}
void cameraInit(struct Camera* camera, float fov, float near, float far) { void cameraInit(struct Camera* camera, float fov, float near, float far) {
transformInitIdentity(&camera->transform); transformInitIdentity(&camera->transform);
camera->fov = fov; camera->fov = fov;

View file

@ -8,6 +8,7 @@
#include "math/transform.h" #include "math/transform.h"
#include "math/plane.h" #include "math/plane.h"
#include "graphics/renderstate.h" #include "graphics/renderstate.h"
#include "../physics/collision_quad.h"
#include "../math/boxs16.h" #include "../math/boxs16.h"
#define CLIPPING_PLANE_COUNT 5 #define CLIPPING_PLANE_COUNT 5
@ -27,6 +28,7 @@ struct FrustrumCullingInformation {
int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingBoxs16* boundingBox); int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingBoxs16* boundingBox);
int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Vector3* scaledCenter, float scaledRadius); int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Vector3* scaledCenter, float scaledRadius);
int isQuadOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct CollisionQuad* quad);
void cameraInit(struct Camera* camera, float fov, float near, float far); void cameraInit(struct Camera* camera, float fov, float near, float far);
void cameraBuildViewMatrix(struct Camera* camera, float matrix[4][4]); void cameraBuildViewMatrix(struct Camera* camera, float matrix[4][4]);