Misc bug fixes

This commit is contained in:
James Lambert 2022-06-06 20:37:31 -06:00
parent 56b278a47f
commit 5bcb339dcc
17 changed files with 160 additions and 86 deletions

View file

@ -57,9 +57,11 @@ where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where blender
## Current TODO list
Doorway collision
Implement collider bitmask
Raycast through doorways
Cylinder touching bug
Create elevator geometry
Allow player to press button
Collide player with objects in scene
Radio
Create radio model
Create radio texture

View file

@ -70,6 +70,8 @@ std::shared_ptr<CollisionGeneratorOutput> generateCollision(const aiScene* scene
for (unsigned i = 0; i < nodeInfo.node->mNumMeshes; ++i) {
aiMesh* mesh = scene->mMeshes[nodeInfo.node->mMeshes[i]];
bool isTransparent = std::find(nodeInfo.arguments.begin(), nodeInfo.arguments.end(), "transparent") != nodeInfo.arguments.end();
CollisionQuad collider(mesh, globalTransform * nodeInfo.node->mTransformation);
collidersChunk->Add(std::move(collider.Generate()));
@ -85,6 +87,9 @@ std::shared_ptr<CollisionGeneratorOutput> generateCollision(const aiScene* scene
collisionObject->AddPrimitive(std::string("&" + colliderTypesName + "[" + std::to_string(meshCount) + "]"));
collisionObject->AddPrimitive<const char*>("NULL");
collisionObject->Add(std::unique_ptr<DataChunk>(new StructureDataChunk(collider.BoundingBox())));
collisionObject->AddPrimitive<const char*>(isTransparent ?
"COLLISION_LAYERS_STATIC | COLLISION_LAYERS_TRANSPARENT | COLLISION_LAYERS_TANGIBLE" :
"COLLISION_LAYERS_STATIC | COLLISION_LAYERS_TANGIBLE");
collisionObjectChunk->Add(std::move(collisionObject));

View file

@ -19,7 +19,7 @@ struct DecorObject* decorObjectNew(struct DecorObjectDefinition* definition, str
}
void decorObjectInit(struct DecorObject* object, struct DecorObjectDefinition* definition, struct Transform* at, int room) {
collisionObjectInit(&object->collisionObject, &definition->colliderType, &object->rigidBody, definition->mass);
collisionObjectInit(&object->collisionObject, &definition->colliderType, &object->rigidBody, definition->mass, COLLISION_LAYERS_TANGIBLE | COLLISION_LAYERS_GRABBABLE);
collisionSceneAddDynamicObject(&object->collisionObject);
object->rigidBody.transform = *at;

View file

@ -5,11 +5,12 @@
#include "collision_scene.h"
#include "../math/mathf.h"
void collisionObjectInit(struct CollisionObject* object, struct ColliderTypeData *collider, struct RigidBody* body, float mass) {
void collisionObjectInit(struct CollisionObject* object, struct ColliderTypeData *collider, struct RigidBody* body, float mass, int collisionLayers) {
object->collider = collider;
object->body = body;
rigidBodyInit(body, mass, collider->callbacks->mofICalculator(collider, mass));
collisionObjectUpdateBB(object);
object->collisionLayers = collisionLayers;
}
int collisionObjectIsActive(struct CollisionObject* object) {
@ -17,6 +18,10 @@ int collisionObjectIsActive(struct CollisionObject* object) {
}
void collisionObjectCollideWithQuad(struct CollisionObject* object, struct CollisionObject* quadObject, struct ContactSolver* contactSolver) {
if ((object->collisionLayers | quadObject->collisionLayers) == 0) {
return;
}
if (!box3DHasOverlap(&object->boundingBox, &quadObject->boundingBox)) {
return;
}
@ -51,12 +56,8 @@ void collisionObjectCollideWithQuad(struct CollisionObject* object, struct Colli
return;
}
contact->friction = 0.5f;
contact->restitution = 0.0f;
if (isnan(result.penetration) || isnan(result.contactA.x) || isnan(result.contactB.x) || isnan(result.normal.x)) {
return;
}
contact->friction = MAX(object->collider->friction, quadObject->collider->friction);
contact->restitution = MIN(object->collider->bounce, quadObject->collider->bounce);
transformPointInverseNoScale(&object->body->transform, &result.contactB, &result.contactB);
contactInsert(contact, &result);

View file

@ -5,15 +5,21 @@
#include "collision.h"
#include "../math/box3d.h"
#define COLLISION_LAYERS_STATIC (1 << 0)
#define COLLISION_LAYERS_TRANSPARENT (1 << 1)
#define COLLISION_LAYERS_TANGIBLE (1 << 2)
#define COLLISION_LAYERS_GRABBABLE (1 << 3)
struct CollisionObject {
struct ColliderTypeData *collider;
struct RigidBody* body;
struct Box3D boundingBox;
int collisionLayers;
};
int collisionObjectIsActive(struct CollisionObject* object);
void collisionObjectInit(struct CollisionObject* object, struct ColliderTypeData *collider, struct RigidBody* body, float mass);
void collisionObjectInit(struct CollisionObject* object, struct ColliderTypeData *collider, struct RigidBody* body, float mass, int collisionLayers);
void collisionObjectCollideWithQuad(struct CollisionObject* object, struct CollisionObject* quad, struct ContactSolver* contactSolver);
void collisionObjectCollideTwoObjects(struct CollisionObject* a, struct CollisionObject* b, struct ContactSolver* contactSolver);

View file

@ -145,7 +145,13 @@ void collisionObjectQueryScene(struct CollisionObject* object, struct CollisionS
for (int i = 0; i < quadCount; ++i) {
localContact.contactCount = 0;
if (quadCollider(object->collider->data, &object->body->transform, scene->quads[colliderIndices[i]].collider->data, &localContact) &&
struct CollisionObject* quadObject = &scene->quads[colliderIndices[i]];
if ((quadObject->collisionLayers & object->collisionLayers) == 0) {
continue;
}
if (quadCollider(object->collider->data, &object->body->transform, quadObject->collider->data, &localContact) &&
collisionSceneFilterPortalContacts(&localContact)) {
callback(data, &localContact);
}
@ -192,7 +198,7 @@ int collisionSceneIsPortalOpen() {
return gCollisionScene.portalTransforms[0] != NULL && gCollisionScene.portalTransforms[1] != NULL;
}
void collisionSceneRaycastRoom(struct CollisionScene* scene, struct Room* room, struct Ray* ray, struct RaycastHit* hit) {
void collisionSceneRaycastRoom(struct CollisionScene* scene, struct Room* room, struct Ray* ray, int collisionLayers, struct RaycastHit* hit) {
int currX = GRID_CELL_X(room, ray->origin.x);
int currZ = GRID_CELL_Z(room, ray->origin.z);
@ -207,7 +213,13 @@ void collisionSceneRaycastRoom(struct CollisionScene* scene, struct Room* room,
for (int i = range->min; i < range->max; ++i) {
struct RaycastHit hitTest;
if (raycastQuad(&scene->quads[room->quadIndices[i]], ray, hit->distance, &hitTest) && hitTest.distance < hit->distance && vector3Dot(&hitTest.normal, &ray->dir) < 0.0f) {
struct CollisionObject* collisionObject = &scene->quads[room->quadIndices[i]];
if ((collisionObject->collisionLayers & collisionLayers) == 0) {
continue;
}
if (raycastQuad(collisionObject, ray, hit->distance, &hitTest) && hitTest.distance < hit->distance && vector3Dot(&hitTest.normal, &ray->dir) < 0.0f) {
hit->at = hitTest.at;
hit->normal = hitTest.normal;
hit->distance = hitTest.distance;
@ -260,6 +272,10 @@ int collisionSceneRaycastDoorways(struct CollisionScene* scene, struct Room* roo
struct Doorway* doorway = &scene->world->doorways[room->doorwayIndices[i]];
if ((doorway->flags & DoorwayFlagsOpen) == 0) {
continue;
}
if (raycastQuadShape(&doorway->quad, ray, roomDistance, &hitTest) && hitTest.distance < roomDistance) {
roomDistance = hitTest.distance;
// check that the doorway wasn't hit from the wrong side
@ -275,7 +291,7 @@ int collisionSceneRaycastDoorways(struct CollisionScene* scene, struct Room* roo
return nextRoom;
}
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, float maxDistance, int passThroughPortals, struct RaycastHit* hit) {
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit) {
hit->distance = maxDistance;
hit->throughPortal = NULL;
@ -283,7 +299,7 @@ int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ra
while (roomsToCheck && roomIndex != -1) {
struct Room* room = &scene->world->rooms[roomIndex];
collisionSceneRaycastRoom(scene, room, ray, hit);
collisionSceneRaycastRoom(scene, room, ray, collisionLayers, hit);
if (hit->distance != maxDistance) {
hit->roomIndex = roomIndex;
@ -302,6 +318,10 @@ int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ra
struct CollisionObject* object = scene->dynamicObjects[i];
if ((object->collisionLayers & collisionLayers) == 0) {
continue;
}
if (object->collider->callbacks->raycast &&
object->collider->callbacks->raycast(object, ray, hit->distance, &hitTest) &&
hitTest.distance < hit->distance) {
@ -328,7 +348,7 @@ int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ra
struct RaycastHit newHit;
int result = collisionSceneRaycast(scene, gCollisionScene.portalRooms[1 - i], &newRay, maxDistance - hit->distance, 0, &newHit);
int result = collisionSceneRaycast(scene, gCollisionScene.portalRooms[1 - i], &newRay, collisionLayers, maxDistance - hit->distance, 0, &newHit);
if (result) {
newHit.distance += hit->distance;
@ -466,6 +486,10 @@ void collisionSceneWalkBroadphase(struct CollisionScene* collisionScene, struct
for (int objectIndex = 0; objectIndex < broadphase->objectInRangeCount; ++objectIndex) {
struct CollisionObject* existing = broadphase->objectsInCurrentRange[objectIndex];
if ((existing->collisionLayers & subject->collisionLayers) == 0) {
continue;
}
if (!collisionObjectIsActive(existing) && !collisionObjectIsActive(subject)) {
continue;
}

View file

@ -32,7 +32,7 @@ int collisionSceneIsPortalOpen();
void collisionObjectQueryScene(struct CollisionObject* object, struct CollisionScene* scene, void* data, ManifoldCallback callback);
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, float maxDistance, int passThroughPortals, struct RaycastHit* hit);
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit);
void collisionSceneGetPortalTransform(int fromPortal, struct Transform* out);

View file

@ -103,6 +103,53 @@ void contactSolverRemoveUnusedContacts(struct ContactSolver* contactSolver) {
}
}
void contactSolverCheckPortalManifoldContacts(struct ContactManifold* manifold) {
int writeIndex = 0;
for (int readIndex = 0; readIndex < manifold->contactCount; ++readIndex) {
struct ContactPoint* contactPoint = &manifold->contacts[readIndex];
if (collisionSceneIsTouchingPortal(&contactPoint->contactAWorld, &manifold->normal)) {
continue;
}
if (readIndex != writeIndex) {
manifold->contacts[writeIndex] = *contactPoint;
}
++writeIndex;
}
manifold->contactCount = writeIndex;
}
void contactSolverCheckPortalContacts(struct ContactSolver* contactSolver, struct CollisionObject* objectWithNewPortal) {
struct ContactManifold* curr = contactSolver->activeContacts;
struct ContactManifold* prev = NULL;
while (curr) {
if (curr->shapeA == objectWithNewPortal) {
contactSolverCheckPortalManifoldContacts(curr);
}
if (curr->contactCount == 0) {
if (prev) {
prev->next = curr->next;
} else {
contactSolver->activeContacts = curr->next;
}
struct ContactManifold* next = curr->next;
curr->next = contactSolver->unusedContacts;
contactSolver->unusedContacts = curr;
curr = next;
} else {
prev = curr;
curr = curr->next;
}
}
}
void contactSolverInit(struct ContactSolver* contactSolver) {
int solverSize = sizeof(struct ContactSolver);
memset(contactSolver, 0, solverSize);

View file

@ -63,6 +63,7 @@ struct ContactManifold* contactSolverGetContactManifold(struct ContactSolver* so
struct ContactManifold* contactSolverNextManifold(struct ContactSolver* solver, struct CollisionObject* forObject, struct ContactManifold* current);
void contactSolverRemoveUnusedContacts(struct ContactSolver* contactSolver);
void contactSolverCheckPortalContacts(struct ContactSolver* contactSolver, struct CollisionObject* objectWithNewPortal);
#endif

View file

@ -30,7 +30,7 @@ struct ColliderTypeData gPlayerColliderData = {
};
void playerInit(struct Player* player, struct Location* startLocation) {
collisionObjectInit(&player->collisionObject, &gPlayerColliderData, &player->body, 1.0f);
collisionObjectInit(&player->collisionObject, &gPlayerColliderData, &player->body, 1.0f, COLLISION_LAYERS_TANGIBLE);
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
player->grabbing = NULL;
player->pitchVelocity = 0.0f;
@ -91,7 +91,7 @@ void playerUpdateGrabbedObject(struct Player* player) {
struct RaycastHit hit;
if (collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, GRAB_RAYCAST_DISTANCE, 1, &hit) && hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) {
if (collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_GRABBABLE | COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, &hit) && hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) {
player->grabbing = hit.object->body;
if (hit.throughPortal) {
@ -229,7 +229,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, player->body.currentRoom, &ray, PLAYER_HEAD_HEIGHT, 1, &hit)) {
if (collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_TANGIBLE, PLAYER_HEAD_HEIGHT, 1, &hit)) {
vector3AddScaled(&hit.at, &gUp, PLAYER_HEAD_HEIGHT, &player->body.transform.position);
player->body.velocity.y = 0.0f;

View file

@ -54,7 +54,7 @@ void buttonRender(void* data, struct RenderScene* renderScene) {
}
void buttonInit(struct Button* button, struct ButtonDefinition* definition) {
collisionObjectInit(&button->collisionObject, &gButtonCollider, &button->rigidBody, 1.0f);
collisionObjectInit(&button->collisionObject, &gButtonCollider, &button->rigidBody, 1.0f, COLLISION_LAYERS_TANGIBLE);
rigitBodyMarkKinematic(&button->rigidBody);
collisionSceneAddDynamicObject(&button->collisionObject);

View file

@ -11,45 +11,6 @@ struct CollisionBox gCubeCollisionBox = {
{0.3165f, 0.3165f, 0.3165f}
};
struct Plane gFloor = {{0.0f, 1.0f, 0.0f}, 0.0f};
struct ColliderTypeData gFloorColliderType = {
CollisionShapeTypeQuad,
&gFloor,
0.0f,
1.0f,
NULL,
};
struct CollisionObject gFloorObject = {
&gFloorColliderType,
NULL,
};
struct CollisionQuad gFloatingQuad = {
{-1.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
2.0f,
{0.0f, 1.0f, 0.0f},
2.0f,
{{0.0f, 0.0f, -1.0}, 0.0f},
0xF,
};
struct ColliderTypeData gFloatingQuadCollider = {
CollisionShapeTypeQuad,
&gFloatingQuad,
0.0f,
1.0f,
NULL,
} ;
struct CollisionObject gFloatingQuadObject = {
&gFloatingQuadCollider,
NULL,
};
struct ColliderTypeData gCubeCollider = {
CollisionShapeTypeBox,
&gCubeCollisionBox,
@ -67,7 +28,7 @@ void cubeRender(void* data, struct RenderScene* renderScene) {
}
void cubeInit(struct Cube* cube) {
collisionObjectInit(&cube->collisionObject, &gCubeCollider, &cube->rigidBody, 2.0f);
collisionObjectInit(&cube->collisionObject, &gCubeCollider, &cube->rigidBody, 2.0f, COLLISION_LAYERS_TANGIBLE | COLLISION_LAYERS_GRABBABLE);
collisionSceneAddDynamicObject(&cube->collisionObject);
cube->collisionObject.body->flags |= RigidBodyFlagsGrabbable;

View file

@ -7,6 +7,8 @@
#include "signals.h"
#include "../math/mathf.h"
#include "../util/time.h"
#include "../physics/collision_box.h"
#include "../physics/collision_scene.h"
#include "../build/assets/models/props/door_01.h"
@ -14,10 +16,27 @@
#define OPEN_WIDTH 0.625
struct CollisionBox gDoorCollisionBox = {
{1.0f, 1.0f, 0.1125f}
};
struct ColliderTypeData gDoorCollider = {
CollisionShapeTypeBox,
&gDoorCollisionBox,
0.0f,
0.5f,
&gCollisionBoxCallbacks,
};
void doorRender(void* data, struct RenderScene* renderScene) {
struct Door* door = (struct Door*)data;
Mtx* matrix = renderStateRequestMatrices(renderScene->renderState, 1);
transformToMatrixL(&door->rigidBody.transform, matrix, SCENE_SCALE);
struct Transform originalTransform;
originalTransform.position = door->doorDefinition->location;
originalTransform.rotation = door->doorDefinition->rotation;
originalTransform.scale = gOneVec;
transformToMatrixL(&originalTransform, matrix, SCENE_SCALE);
props_door_01_default_bones[PROPS_DOOR_01_DOORL_BONE].position.x = door->openAmount * -0.625f * SCENE_SCALE;
props_door_01_default_bones[PROPS_DOOR_01_DOORR_BONE].position.x = door->openAmount * 0.625f * SCENE_SCALE;
@ -31,15 +50,17 @@ void doorRender(void* data, struct RenderScene* renderScene) {
}
void doorInit(struct Door* door, struct DoorDefinition* doorDefinition, struct World* world) {
// collisionObjectInit(&cube->collisionObject, &gCubeCollider, &cube->rigidBody, 1.0f);
// collisionSceneAddDynamicObject(&cube->collisionObject);
// cube->collisionObject.body->flags |= RigidBodyFlagsGrabbable;
collisionObjectInit(&door->collisionObject, &gDoorCollider, &door->rigidBody, 1.0f, COLLISION_LAYERS_TANGIBLE);
rigitBodyMarkKinematic(&door->rigidBody);
collisionSceneAddDynamicObject(&door->collisionObject);
door->rigidBody.transform.position = doorDefinition->location;
door->rigidBody.transform.position.y += 1.0f;
door->rigidBody.transform.rotation = doorDefinition->rotation;
door->rigidBody.transform.scale = gOneVec;
collisionObjectUpdateBB(&door->collisionObject);
door->dynamicId = dynamicSceneAdd(door, doorRender, &door->rigidBody.transform, 1.7f);
door->signalIndex = doorDefinition->signalIndex;
door->openAmount = 0.0f;
@ -50,6 +71,8 @@ void doorInit(struct Door* door, struct DoorDefinition* doorDefinition, struct W
} else {
door->forDoorway = NULL;
}
door->doorDefinition = doorDefinition;
}
void doorUpdate(struct Door* door) {
@ -59,8 +82,10 @@ void doorUpdate(struct Door* door) {
if (door->forDoorway) {
if (door->openAmount == 0.0f) {
door->forDoorway->flags &= ~DoorwayFlagsOpen;
door->collisionObject.collisionLayers = COLLISION_LAYERS_TANGIBLE;
} else {
door->forDoorway->flags |= DoorwayFlagsOpen;
door->collisionObject.collisionLayers = 0;
}
}
}

View file

@ -8,6 +8,7 @@ struct Door {
struct CollisionObject collisionObject;
struct RigidBody rigidBody;
struct Doorway* forDoorway;
struct DoorDefinition* doorDefinition;
short dynamicId;
short signalIndex;
float openAmount;

View file

@ -224,10 +224,29 @@ void sceneUpdate(struct Scene* scene) {
scene->lastFrameStart = frameStart;
}
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) {
if (portalSurfaceGenerate(&gCurrentLevel->portalSurfaces[i], at, NULL, NULL)) {
soundPlayerPlay(soundsPortalOpen2, 1.0f, 1.0f);
scene->portals[portalIndex].transform = *at;
gCollisionScene.portalTransforms[portalIndex] = &scene->portals[portalIndex].transform;
gCollisionScene.portalRooms[portalIndex] = roomIndex;
contactSolverCheckPortalContacts(&gContactSolver, &gCurrentLevel->collisionQuads[quadIndex]);
return 1;
}
}
return 0;
}
int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* playerUp, int portalIndex, int roomIndex) {
struct RaycastHit hit;
if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, 1000000.0f, 0, &hit)) {
if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC, 1000000.0f, 0, &hit)) {
return 0;
}
@ -254,21 +273,4 @@ int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* player
}
return sceneOpenPortal(scene, &portalLocation, portalIndex, quadIndex, hit.roomIndex);
}
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) {
if (portalSurfaceGenerate(&gCurrentLevel->portalSurfaces[i], at, NULL, NULL)) {
soundPlayerPlay(soundsPortalOpen2, 1.0f, 1.0f);
scene->portals[portalIndex].transform = *at;
gCollisionScene.portalTransforms[portalIndex] = &scene->portals[portalIndex].transform;
gCollisionScene.portalRooms[portalIndex] = roomIndex;
return 1;
}
}
return 0;
}

View file

@ -40,6 +40,5 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr
void sceneUpdate(struct Scene* scene);
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