Work on raycasting in rooms
This commit is contained in:
parent
0b718811ec
commit
40ae68e455
|
@ -56,6 +56,11 @@ int mergeColliderList(short* a, int aCount, short* b, int bCount, short* output)
|
|||
|
||||
#define COLLISION_GRID_CELL_SIZE 4
|
||||
|
||||
#define GRID_CELL_X(room, worldX) floorf(((worldX) - room->cornerX) * (1.0f / COLLISION_GRID_CELL_SIZE));
|
||||
#define GRID_CELL_Z(room, worldZ) floorf(((worldZ) - room->cornerZ) * (1.0f / COLLISION_GRID_CELL_SIZE));
|
||||
|
||||
#define GRID_CELL_CONTENTS(room, x, z) (&room->cellContents[(x) * room->spanX + (z)])
|
||||
|
||||
int collisionObjectRoomColliders(struct Room* room, struct Box3D* box, short output[MAX_COLLIDERS]) {
|
||||
short tmp[MAX_COLLIDERS];
|
||||
|
||||
|
@ -63,15 +68,15 @@ int collisionObjectRoomColliders(struct Room* room, struct Box3D* box, short out
|
|||
short* currentResult = output;
|
||||
int result = 0;
|
||||
|
||||
int minX = floorf((box->min.x - room->cornerX) * (1.0f / COLLISION_GRID_CELL_SIZE));
|
||||
int maxX = floorf((box->max.x - room->cornerX) * (1.0f / COLLISION_GRID_CELL_SIZE));
|
||||
int minX = GRID_CELL_X(room, box->min.x);
|
||||
int maxX = GRID_CELL_Z(room, box->min.z);
|
||||
|
||||
int minZ = floorf((box->min.z - room->cornerZ) * (1.0f / COLLISION_GRID_CELL_SIZE));
|
||||
int maxZ = floorf((box->max.z - room->cornerZ) * (1.0f / COLLISION_GRID_CELL_SIZE));
|
||||
int minZ = GRID_CELL_X(room, box->max.x);
|
||||
int maxZ = GRID_CELL_Z(room, box->max.z);
|
||||
|
||||
for (int x = MAX(minX, 0); x <= maxX && x < room->spanX; ++x) {
|
||||
for (int z = MAX(minZ, 0); z <= maxZ && z < room->spanZ; ++z) {
|
||||
struct Rangeu16* range = &room->cellContents[x * room->spanX + z];
|
||||
struct Rangeu16* range = GRID_CELL_CONTENTS(room, x, z);
|
||||
|
||||
result = mergeColliderList(currentSource, result, &room->quadIndices[range->min], range->max - range->min, currentResult);
|
||||
|
||||
|
@ -99,10 +104,6 @@ void collisionObjectCollideWithScene(struct CollisionObject* object, struct Coll
|
|||
for (int i = 0; i < quadCount; ++i) {
|
||||
collisionObjectCollideWithQuad(object, &scene->quads[colliderIndices[i]], contactSolver);
|
||||
}
|
||||
|
||||
// for (int i = 0; i < scene->quadCount; ++i) {
|
||||
// collisionObjectCollideWithQuad(object, &scene->quads[i], contactSolver);
|
||||
// }
|
||||
}
|
||||
|
||||
int collisionSceneFilterPortalContacts(struct ContactConstraintState* contact) {
|
||||
|
@ -132,12 +133,15 @@ void collisionObjectQueryScene(struct CollisionObject* object, struct CollisionS
|
|||
return;
|
||||
}
|
||||
|
||||
short colliderIndices[MAX_COLLIDERS];
|
||||
int quadCount = collisionObjectRoomColliders(&scene->world->rooms[object->body->currentRoom], &object->boundingBox, colliderIndices);
|
||||
|
||||
struct ContactConstraintState localContact;
|
||||
|
||||
for (int i = 0; i < scene->quadCount; ++i) {
|
||||
for (int i = 0; i < quadCount; ++i) {
|
||||
localContact.contactCount = 0;
|
||||
|
||||
if (quadCollider(object->collider->data, &object->body->transform, scene->quads[i].collider->data, &localContact) &&
|
||||
if (quadCollider(object->collider->data, &object->body->transform, scene->quads[colliderIndices[i]].collider->data, &localContact) &&
|
||||
collisionSceneFilterPortalContacts(&localContact)) {
|
||||
callback(data, &localContact);
|
||||
}
|
||||
|
@ -176,14 +180,22 @@ int collisionSceneIsPortalOpen() {
|
|||
return gCollisionScene.portalTransforms[0] != NULL && gCollisionScene.portalTransforms[1] != NULL;
|
||||
}
|
||||
|
||||
int collisionSceneRaycast(struct CollisionScene* scene, struct Ray* ray, float maxDistance, int passThroughPortals, struct RaycastHit* hit) {
|
||||
hit->distance = maxDistance;
|
||||
hit->throughPortal = NULL;
|
||||
void collisionSceneRaycastRoom(struct CollisionScene* scene, struct Room* room, struct Ray* ray, struct RaycastHit* hit) {
|
||||
int currX = GRID_CELL_X(room, ray->origin.x);
|
||||
int currZ = GRID_CELL_Z(room, ray->origin.z);
|
||||
|
||||
for (int i = 0; i < scene->quadCount; ++i) {
|
||||
float xDirInv = fabsf(ray->dir.x) > 0.00001f ? 1.0f / ray->dir.x : 0.0f;
|
||||
float zDirInv = fabsf(ray->dir.z) > 0.00001f ? 1.0f / ray->dir.z : 0.0f;
|
||||
|
||||
// TODO adjust currX and currZ if ray starts outside room
|
||||
|
||||
while (currX >=0 && currX < room->spanX && currZ >= 0 && currZ < room->spanZ) {
|
||||
struct Rangeu16* range = GRID_CELL_CONTENTS(room, currX, currZ);
|
||||
|
||||
for (int i = range->min; i < range->max; ++i) {
|
||||
struct RaycastHit hitTest;
|
||||
|
||||
if (raycastQuad(&scene->quads[i], ray, hit->distance, &hitTest) && hitTest.distance < hit->distance) {
|
||||
if (raycastQuad(&scene->quads[room->quadIndices[i]], ray, hit->distance, &hitTest) && hitTest.distance < hit->distance) {
|
||||
hit->at = hitTest.at;
|
||||
hit->normal = hitTest.normal;
|
||||
hit->distance = hitTest.distance;
|
||||
|
@ -191,6 +203,88 @@ int collisionSceneRaycast(struct CollisionScene* scene, struct Ray* ray, float m
|
|||
}
|
||||
}
|
||||
|
||||
int xStep = 0;
|
||||
int zStep = 0;
|
||||
float cellDistance = hit->distance;
|
||||
|
||||
if (xDirInv != 0.0f) {
|
||||
float nextEdge = (currX + (ray->dir.x > 0.0f ? 1 : 0)) * COLLISION_GRID_CELL_SIZE + room->cornerX;
|
||||
float distanceCheck = (nextEdge - ray->origin.x) * xDirInv;
|
||||
|
||||
if (distanceCheck < cellDistance) {
|
||||
cellDistance = distanceCheck;
|
||||
xStep = ray->dir.x > 0.0f ? 1 : -1;
|
||||
zStep = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (zDirInv != 0.0f) {
|
||||
float nextEdge = (currZ + (ray->dir.x > 0.0f ? 1 : 0)) * COLLISION_GRID_CELL_SIZE + room->cornerZ;
|
||||
float distanceCheck = (nextEdge - ray->origin.z) * zDirInv;
|
||||
|
||||
if (distanceCheck < cellDistance) {
|
||||
cellDistance = distanceCheck;
|
||||
xStep = 0;
|
||||
zStep = ray->dir.z > 0.0f ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!xStep && !zStep) {
|
||||
return;
|
||||
}
|
||||
|
||||
currX += xStep;
|
||||
currZ += zStep;
|
||||
}
|
||||
}
|
||||
|
||||
int collisionSceneRaycastDoorways(struct CollisionScene* scene, struct Room* room, struct Ray* ray, float maxDistance, int currentRoom) {
|
||||
int nextRoom = -1;
|
||||
|
||||
float roomDistance = maxDistance;
|
||||
|
||||
for (int i = 0; i < room->doorwayCount; ++i) {
|
||||
struct RaycastHit hitTest;
|
||||
|
||||
struct Doorway* doorway = &scene->world->doorways[room->doorwayIndices[i]];
|
||||
|
||||
if (raycastQuadShape(&doorway->quad, ray, roomDistance, &hitTest) && hitTest.distance < roomDistance) {
|
||||
roomDistance = hitTest.distance;
|
||||
// check that the doorway wasn't hit from the wrong side
|
||||
int expectedRoom = vector3Dot(&doorway->quad.plane.normal, &hitTest.normal) < 0.0f ? doorway->roomA : doorway->roomB;
|
||||
int otherRoom = currentRoom == doorway->roomA ? doorway->roomB : doorway->roomA;
|
||||
|
||||
if (expectedRoom == otherRoom) {
|
||||
nextRoom = otherRoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nextRoom;
|
||||
}
|
||||
|
||||
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, float maxDistance, int passThroughPortals, struct RaycastHit* hit) {
|
||||
hit->distance = maxDistance;
|
||||
hit->throughPortal = NULL;
|
||||
|
||||
int roomsToCheck = 5;
|
||||
|
||||
while (roomsToCheck && roomIndex != -1) {
|
||||
struct Room* room = &scene->world->rooms[roomIndex];
|
||||
collisionSceneRaycastRoom(scene, room, ray, hit);
|
||||
|
||||
if (hit->distance != maxDistance) {
|
||||
hit->roomIndex = roomIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
int nextRoom = collisionSceneRaycastDoorways(scene, room, ray, hit->distance, roomIndex);
|
||||
|
||||
roomIndex = nextRoom;
|
||||
|
||||
--roomsToCheck;
|
||||
}
|
||||
|
||||
for (int i = 0; i < scene->dynamicObjectCount; ++i) {
|
||||
struct RaycastHit hitTest;
|
||||
|
||||
|
@ -203,6 +297,7 @@ int collisionSceneRaycast(struct CollisionScene* scene, struct Ray* ray, float m
|
|||
hit->normal = hitTest.normal;
|
||||
hit->distance = hitTest.distance;
|
||||
hit->object = hitTest.object;
|
||||
hit->roomIndex = hitTest.roomIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +316,7 @@ int collisionSceneRaycast(struct CollisionScene* scene, struct Ray* ray, float m
|
|||
|
||||
struct RaycastHit newHit;
|
||||
|
||||
int result = collisionSceneRaycast(scene, &newRay, maxDistance - hit->distance, 0, &newHit);
|
||||
int result = collisionSceneRaycast(scene, gCollisionScene.portalRooms[1 - i], &newRay, maxDistance - hit->distance, 0, &newHit);
|
||||
|
||||
if (result) {
|
||||
newHit.distance += hit->distance;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
struct CollisionScene {
|
||||
struct CollisionObject* quads;
|
||||
struct World* world;
|
||||
short portalRooms[2];
|
||||
struct Transform* portalTransforms[2];
|
||||
struct CollisionObject* dynamicObjects[MAX_DYNAMIC_OBJECTS];
|
||||
u16 dynamicObjectCount;
|
||||
|
@ -31,7 +32,7 @@ int collisionSceneIsPortalOpen();
|
|||
|
||||
void collisionObjectQueryScene(struct CollisionObject* object, struct CollisionScene* scene, void* data, ManifoldCallback callback);
|
||||
|
||||
int collisionSceneRaycast(struct CollisionScene* scene, struct Ray* ray, float maxDistance, int passThroughPortals, struct RaycastHit* hit);
|
||||
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, float maxDistance, int passThroughPortals, struct RaycastHit* hit);
|
||||
|
||||
void collisionSceneGetPortalTransform(int fromPortal, struct Transform* out);
|
||||
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
#define NEAR_DOT_ZERO 0.00001f
|
||||
#define MIN_RAY_LENGTH 0.05f
|
||||
|
||||
int raycastQuad(struct CollisionObject* quadObject, struct Ray* ray, float maxDistance, struct RaycastHit* contact) {
|
||||
struct CollisionQuad* quad = (struct CollisionQuad*)quadObject->collider->data;
|
||||
|
||||
int raycastQuadShape(struct CollisionQuad* quad, struct Ray* ray, float maxDistance, struct RaycastHit* contact) {
|
||||
float normalDot = vector3Dot(&ray->dir, &quad->plane.normal);
|
||||
|
||||
if (fabsf(normalDot) < NEAR_DOT_ZERO) {
|
||||
|
@ -29,11 +27,22 @@ int raycastQuad(struct CollisionObject* quadObject, struct Ray* ray, float maxDi
|
|||
}
|
||||
|
||||
contact->normal = quad->plane.normal;
|
||||
contact->object = quadObject;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int raycastQuad(struct CollisionObject* quadObject, struct Ray* ray, float maxDistance, struct RaycastHit* contact) {
|
||||
struct CollisionQuad* quad = (struct CollisionQuad*)quadObject->collider->data;
|
||||
|
||||
int result = raycastQuadShape(quad, ray, maxDistance, contact);
|
||||
|
||||
if (result) {
|
||||
contact->object = quadObject;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int raycastBox(struct CollisionObject* boxObject, struct Ray* ray, float maxDistance, struct RaycastHit* contact) {
|
||||
struct CollisionBox* box = (struct CollisionBox*)boxObject->collider->data;
|
||||
|
||||
|
@ -102,5 +111,7 @@ int raycastBox(struct CollisionObject* boxObject, struct Ray* ray, float maxDist
|
|||
quatMultVector(&boxObject->body->transform.rotation, &contact->normal, &contact->normal);
|
||||
}
|
||||
|
||||
contact->roomIndex = boxObject->body->currentRoom;
|
||||
|
||||
return contact->distance != maxDistance;
|
||||
}
|
|
@ -11,8 +11,10 @@ struct RaycastHit {
|
|||
float distance;
|
||||
struct CollisionObject* object;
|
||||
struct Transform* throughPortal;
|
||||
short roomIndex;
|
||||
};
|
||||
|
||||
int raycastQuadShape(struct CollisionQuad* quad, struct Ray* ray, float maxDistance, struct RaycastHit* contact);
|
||||
int raycastQuad(struct CollisionObject* quadObject, struct Ray* ray, float maxDistance, struct RaycastHit* contact);
|
||||
int raycastBox(struct CollisionObject* boxObject, struct Ray* ray, float maxDistance, struct RaycastHit* contact);
|
||||
|
||||
|
|
|
@ -142,6 +142,8 @@ void rigidBodyCheckPortals(struct RigidBody* rigidBody) {
|
|||
rigidBody->transform.rotation = newRotation;
|
||||
|
||||
newFlags |= RigidBodyFlagsCrossedPortal0 << i;
|
||||
|
||||
rigidBody->currentRoom = gCollisionScene.portalRooms[1 - i];
|
||||
}
|
||||
|
||||
rigidBody->flags &= ~(
|
||||
|
|
|
@ -89,7 +89,7 @@ void playerUpdateGrabbedObject(struct Player* player) {
|
|||
|
||||
struct RaycastHit hit;
|
||||
|
||||
if (collisionSceneRaycast(&gCollisionScene, &ray, GRAB_RAYCAST_DISTANCE, 1, &hit) && hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) {
|
||||
if (collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, GRAB_RAYCAST_DISTANCE, 1, &hit) && hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) {
|
||||
player->grabbing = hit.object->body;
|
||||
|
||||
if (hit.throughPortal) {
|
||||
|
@ -199,7 +199,7 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
|
|||
struct Ray ray;
|
||||
ray.origin = player->body.transform.position;
|
||||
vector3Scale(&gUp, &ray.dir, -1.0f);
|
||||
if (collisionSceneRaycast(&gCollisionScene, &ray, PLAYER_HEAD_HEIGHT, 1, &hit)) {
|
||||
if (collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, PLAYER_HEAD_HEIGHT, 1, &hit)) {
|
||||
vector3AddScaled(&hit.at, &gUp, PLAYER_HEAD_HEIGHT, &player->body.transform.position);
|
||||
|
||||
player->body.velocity.y = 0.0f;
|
||||
|
@ -280,5 +280,7 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
|
|||
transformPoint(transform, &gCameraOffset, &cameraTransform->position);
|
||||
playerUpdateGrabbedObject(player);
|
||||
|
||||
collisionObjectUpdateBB(&player->collisionObject);
|
||||
|
||||
player->body.currentRoom = worldCheckDoorwayCrossings(&gCurrentLevel->world, &player->body.transform.position, player->body.currentRoom, doorwayMask);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../graphics/graphics.h"
|
||||
#include "../defs.h"
|
||||
#include "dynamic_scene.h"
|
||||
#include "../physics/collision_scene.h"
|
||||
|
||||
#define CALC_SCREEN_SPACE(clip_space, screen_size) ((clip_space + 1.0f) * ((screen_size) / 2))
|
||||
|
||||
|
@ -151,8 +152,8 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru
|
|||
|
||||
next->currentDepth = current->currentDepth - 1;
|
||||
next->fromPortalIndex = toPortal < fromPortal ? 0 : 1;
|
||||
// TODO
|
||||
next->fromRoom = current->fromRoom;
|
||||
// Gross
|
||||
next->fromRoom = gCollisionScene.portalRooms[toPortal == gCollisionScene.portalTransforms[0] ? 0 : 1];
|
||||
|
||||
#if !SHOW_EXTERNAL_VIEW
|
||||
gSPViewport(renderState->dl++, viewport);
|
||||
|
|
|
@ -146,11 +146,11 @@ void sceneCheckPortals(struct Scene* scene) {
|
|||
quatMultVector(&scene->player.body.transform.rotation, &gUp, &playerUp);
|
||||
|
||||
if (controllerGetButtonDown(0, Z_TRIG)) {
|
||||
sceneFirePortal(scene, &raycastRay, &playerUp, 0);
|
||||
sceneFirePortal(scene, &raycastRay, &playerUp, 0, scene->player.body.currentRoom);
|
||||
}
|
||||
|
||||
if (controllerGetButtonDown(0, R_TRIG)) {
|
||||
sceneFirePortal(scene, &raycastRay, &playerUp, 1);
|
||||
sceneFirePortal(scene, &raycastRay, &playerUp, 1, scene->player.body.currentRoom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,10 +174,10 @@ void sceneUpdate(struct Scene* scene) {
|
|||
scene->lastFrameStart = frameStart;
|
||||
}
|
||||
|
||||
int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* playerUp, int portalIndex) {
|
||||
int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* playerUp, int portalIndex, int roomIndex) {
|
||||
struct RaycastHit hit;
|
||||
|
||||
if (!collisionSceneRaycast(&gCollisionScene, ray, 1000000.0f, 0, &hit)) {
|
||||
if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, 1000000.0f, 0, &hit)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -203,10 +203,10 @@ int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* player
|
|||
quatLook(&hitDirection, playerUp, &portalLocation.rotation);
|
||||
}
|
||||
|
||||
return sceneOpenPortal(scene, &portalLocation, portalIndex, quadIndex);
|
||||
return sceneOpenPortal(scene, &portalLocation, portalIndex, quadIndex, hit.roomIndex);
|
||||
}
|
||||
|
||||
int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, int quadIndex) {
|
||||
int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, int quadIndex, int roomIndex) {
|
||||
struct PortalSurfaceMapping surfaceMapping = gCurrentLevel->portalSurfaceMapping[quadIndex];
|
||||
|
||||
for (int i = surfaceMapping.minPortalIndex; i < surfaceMapping.maxPortalIndex; ++i) {
|
||||
|
@ -220,6 +220,7 @@ int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex,
|
|||
|
||||
scene->portals[portalIndex].transform = *at;
|
||||
gCollisionScene.portalTransforms[portalIndex] = &scene->portals[portalIndex].transform;
|
||||
gCollisionScene.portalRooms[portalIndex] = roomIndex;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ void sceneInit(struct Scene* scene);
|
|||
void sceneRender(struct Scene* scene, struct RenderState* renderState, struct GraphicsTask* task);
|
||||
void sceneUpdate(struct Scene* scene);
|
||||
|
||||
int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* playerUp, int portalIndex);
|
||||
int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, int quadIndex);
|
||||
int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* playerUp, int portalIndex, int roomIndex);
|
||||
int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, int quadIndex, int roomIndex);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue