Implement special case logic when standing close to a portal

This commit is contained in:
James Lambert 2022-07-06 12:42:44 -06:00
parent 9c478b6585
commit abf2c858db
6 changed files with 80 additions and 26 deletions

View file

@ -89,7 +89,7 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
- Implement loading levels from the cartridge - Implement loading levels from the cartridge
- [x] Implement "Emancipation grid" - [x] Implement "Emancipation grid"
- [ ] Change the way player standing logic works - [ ] Change the way player standing logic works
- [ ] Cut holes in portal walls - [x] Cut holes in portal walls
- [ ] Cube dispenser - [ ] Cube dispenser
- [ ] NAN in overlap - [ ] NAN in overlap
- [ ] Get an optimized build working - [ ] Get an optimized build working

View file

@ -27,6 +27,7 @@ extern struct CollisionScene gCollisionScene;
void collisionSceneInit(struct CollisionScene* scene, struct CollisionObject* quads, int quadCount, struct World* world); void collisionSceneInit(struct CollisionScene* scene, struct CollisionObject* quads, int quadCount, struct World* world);
void collisionObjectCollideWithScene(struct CollisionObject* object, struct CollisionScene* scene, struct ContactSolver* contactSolver); void collisionObjectCollideWithScene(struct CollisionObject* object, struct CollisionScene* scene, struct ContactSolver* contactSolver);
int collisionSceneIsTouchingSinglePortal(struct Vector3* contactPoint, struct Vector3* contactNormal, struct Transform* portalTransform, int portalIndex);
int collisionSceneIsTouchingPortal(struct Vector3* contactPoint, struct Vector3* contactNormal); int collisionSceneIsTouchingPortal(struct Vector3* contactPoint, struct Vector3* contactNormal);
int collisionSceneIsPortalOpen(); int collisionSceneIsPortalOpen();

View file

@ -5,7 +5,7 @@
#include "../graphics/graphics.h" #include "../graphics/graphics.h"
int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingBoxs16* boundingBox) { int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingBoxs16* boundingBox) {
for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) { for (int i = 0; i < frustrum->usedClippingPlaneCount; ++i) {
struct Vector3 closestPoint; struct Vector3 closestPoint;
struct Vector3* normal = &frustrum->clippingPlanes[i].normal; struct Vector3* normal = &frustrum->clippingPlanes[i].normal;
@ -24,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 < frustrum->usedClippingPlaneCount; ++i) {
if (planePointDistance(&frustrum->clippingPlanes[i], scaledCenter) < -scaledRadius) { if (planePointDistance(&frustrum->clippingPlanes[i], scaledCenter) < -scaledRadius) {
return 1; return 1;
} }
@ -34,7 +34,7 @@ int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct
} }
int isQuadOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct CollisionQuad* quad) { int isQuadOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct CollisionQuad* quad) {
for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) { for (int i = 0; i < frustrum->usedClippingPlaneCount; ++i) {
struct Vector3* normal = &frustrum->clippingPlanes[i].normal; struct Vector3* normal = &frustrum->clippingPlanes[i].normal;
float aLerp = vector3Dot(normal, &quad->edgeA) < 0.0f ? 0.0f : quad->edgeALength; float aLerp = vector3Dot(normal, &quad->edgeA) < 0.0f ? 0.0f : quad->edgeALength;
float bLerp = vector3Dot(normal, &quad->edgeB) < 0.0f ? 0.0f : quad->edgeBLength; float bLerp = vector3Dot(normal, &quad->edgeB) < 0.0f ? 0.0f : quad->edgeBLength;
@ -126,6 +126,7 @@ Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState,
cameraExtractClippingPlane(combined, &clippingInfo->clippingPlanes[3], 1, -1.0f); cameraExtractClippingPlane(combined, &clippingInfo->clippingPlanes[3], 1, -1.0f);
cameraExtractClippingPlane(combined, &clippingInfo->clippingPlanes[4], 2, 1.0f); cameraExtractClippingPlane(combined, &clippingInfo->clippingPlanes[4], 2, 1.0f);
clippingInfo->cameraPos = camera->transform.position; clippingInfo->cameraPos = camera->transform.position;
clippingInfo->usedClippingPlaneCount = 5;
} }
gSPMatrix(renderState->dl++, osVirtualToPhysical(&viewProjMatrix[1]), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); gSPMatrix(renderState->dl++, osVirtualToPhysical(&viewProjMatrix[1]), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);

View file

@ -11,7 +11,7 @@
#include "../physics/collision_quad.h" #include "../physics/collision_quad.h"
#include "../math/boxs16.h" #include "../math/boxs16.h"
#define CLIPPING_PLANE_COUNT 5 #define MAX_CLIPPING_PLANE_COUNT 6
struct Camera { struct Camera {
struct Transform transform; struct Transform transform;
@ -21,7 +21,8 @@ struct Camera {
}; };
struct FrustrumCullingInformation { struct FrustrumCullingInformation {
struct Plane clippingPlanes[CLIPPING_PLANE_COUNT]; struct Plane clippingPlanes[MAX_CLIPPING_PLANE_COUNT];
short usedClippingPlaneCount;
struct Vector3 cameraPos; struct Vector3 cameraPos;
}; };

View file

@ -6,6 +6,7 @@
#include "../defs.h" #include "../defs.h"
#include "dynamic_scene.h" #include "dynamic_scene.h"
#include "../physics/collision_scene.h" #include "../physics/collision_scene.h"
#include "../math/mathf.h"
#define CALC_SCREEN_SPACE(clip_space, screen_size) ((clip_space + 1.0f) * ((screen_size) / 2)) #define CALC_SCREEN_SPACE(clip_space, screen_size) ((clip_space + 1.0f) * ((screen_size) / 2))
@ -48,6 +49,8 @@ struct Quaternion gVerticalFlip = {0.0f, 1.0f, 0.0f, 0.0f};
#define PORTAL_CLIPPING_PLANE_BIAS (SCENE_SCALE * 0.25f) #define PORTAL_CLIPPING_PLANE_BIAS (SCENE_SCALE * 0.25f)
#define CAMERA_CLIPPING_RADIUS 0.2f
void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex) { void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex) {
props->camera = *camera; props->camera = *camera;
props->aspectRatio = aspectRatio; props->aspectRatio = aspectRatio;
@ -66,6 +69,40 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
props->perspectiveMatrix = cameraSetupMatrices(&externalCamera, renderState, aspectRatio, &props->perspectiveCorrect, &fullscreenViewport, NULL, 0.0f); props->perspectiveMatrix = cameraSetupMatrices(&externalCamera, renderState, aspectRatio, &props->perspectiveCorrect, &fullscreenViewport, NULL, 0.0f);
#endif #endif
props->clippingPortalIndex = -1;
if (collisionSceneIsPortalOpen()) {
for (int i = 0; i < 2; ++i) {
struct Vector3 portalOffset;
vector3Sub(&camera->transform.position, &gCollisionScene.portalTransforms[i]->position, &portalOffset);
struct Vector3 portalNormal;
quatMultVector(&gCollisionScene.portalTransforms[i]->rotation, &gForward, &portalNormal);
struct Vector3 projectedPoint;
if (i == 0) {
vector3Negate(&portalNormal, &portalNormal);
}
float clippingDistnace = vector3Dot(&portalNormal, &portalOffset);
if (fabsf(clippingDistnace) > CAMERA_CLIPPING_RADIUS) {
continue;
}
vector3AddScaled(&camera->transform.position, &portalNormal, -clippingDistnace, &projectedPoint);
if (collisionSceneIsTouchingSinglePortal(&projectedPoint, &portalNormal, gCollisionScene.portalTransforms[i], i)) {
vector3Negate(&portalNormal, &portalNormal);
planeInitWithNormalAndPoint(&props->cullingInfo.clippingPlanes[5], &portalNormal, &gCollisionScene.portalTransforms[i]->position);
++props->cullingInfo.usedClippingPlaneCount;
props->clippingPortalIndex = i;
break;
}
}
}
props->minX = 0; props->minX = 0;
props->minY = 0; props->minY = 0;
props->maxX = SCREEN_WD; props->maxX = SCREEN_WD;
@ -149,12 +186,15 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru
next->perspectiveMatrix = cameraSetupMatrices(&externalCamera, renderState, (float)SCREEN_WD / (float)SCREEN_HT, &next->perspectiveCorrect, &fullscreenViewport, NULL, zBias); next->perspectiveMatrix = cameraSetupMatrices(&externalCamera, renderState, (float)SCREEN_WD / (float)SCREEN_HT, &next->perspectiveCorrect, &fullscreenViewport, NULL, zBias);
#endif #endif
// set the near clipping plane to be the exit portal surface if (current->clippingPortalIndex != -1) {
quatMultVector(&toPortal->rotation, &gForward, &next->cullingInfo.clippingPlanes[4].normal); // set the near clipping plane to be the exit portal surface
if (toPortal < fromPortal) { quatMultVector(&toPortal->rotation, &gForward, &next->cullingInfo.clippingPlanes[4].normal);
vector3Negate(&next->cullingInfo.clippingPlanes[4].normal, &next->cullingInfo.clippingPlanes[4].normal); if (toPortal < fromPortal) {
vector3Negate(&next->cullingInfo.clippingPlanes[4].normal, &next->cullingInfo.clippingPlanes[4].normal);
}
next->cullingInfo.clippingPlanes[4].d = -vector3Dot(&next->cullingInfo.clippingPlanes[4].normal, &toPortal->position) * SCENE_SCALE - PORTAL_CLIPPING_PLANE_BIAS;
} }
next->cullingInfo.clippingPlanes[4].d = -vector3Dot(&next->cullingInfo.clippingPlanes[4].normal, &toPortal->position) * SCENE_SCALE - PORTAL_CLIPPING_PLANE_BIAS; next->clippingPortalIndex = -1;
next->currentDepth = current->currentDepth - 1; next->currentDepth = current->currentDepth - 1;
next->fromPortalIndex = toPortal < fromPortal ? 0 : 1; next->fromPortalIndex = toPortal < fromPortal ? 0 : 1;
@ -219,26 +259,35 @@ void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Rend
return; return;
} }
screenClipperInitWithCamera(&clipper, &props->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
struct Box2D clippingBounds;
screenClipperBoundingPoints(&clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds);
struct RenderProps nextProps; struct RenderProps nextProps;
nextProps.minX = CALC_SCREEN_SPACE(clippingBounds.min.x, SCREEN_WD); int portalIndex = portal < otherPortal ? 0 : 1;
nextProps.maxX = CALC_SCREEN_SPACE(clippingBounds.max.x, SCREEN_WD);
nextProps.minY = CALC_SCREEN_SPACE(-clippingBounds.max.y, SCREEN_HT);
nextProps.maxY = CALC_SCREEN_SPACE(-clippingBounds.min.y, SCREEN_HT);
nextProps.minX = MAX(nextProps.minX, props->minX); if (props->clippingPortalIndex == portalIndex) {
nextProps.maxX = MIN(nextProps.maxX, props->maxX); nextProps.minX = props->minX;
nextProps.minY = MAX(nextProps.minY, props->minY); nextProps.maxX = props->maxX;
nextProps.maxY = MIN(nextProps.maxY, props->maxY); nextProps.minY = props->minY;
nextProps.maxY = props->maxY;
} else {
screenClipperInitWithCamera(&clipper, &props->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
struct Box2D clippingBounds;
screenClipperBoundingPoints(&clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds);
nextProps.minX = CALC_SCREEN_SPACE(clippingBounds.min.x, SCREEN_WD);
nextProps.maxX = CALC_SCREEN_SPACE(clippingBounds.max.x, SCREEN_WD);
nextProps.minY = CALC_SCREEN_SPACE(-clippingBounds.max.y, SCREEN_HT);
nextProps.maxY = CALC_SCREEN_SPACE(-clippingBounds.min.y, SCREEN_HT);
nextProps.minX = MAX(nextProps.minX, props->minX);
nextProps.maxX = MIN(nextProps.maxX, props->maxX);
nextProps.minY = MAX(nextProps.minY, props->minY);
nextProps.maxY = MIN(nextProps.maxY, props->maxY);
}
if (nextProps.minX < nextProps.maxX && nextProps.minY < nextProps.maxY) { if (nextProps.minX < nextProps.maxX && nextProps.minY < nextProps.maxY) {
renderPropsNext(props, &nextProps, &portal->transform, &otherPortal->transform, renderState); renderPropsNext(props, &nextProps, &portal->transform, &otherPortal->transform, renderState);
sceneRenderer(data, &nextProps, renderState); sceneRenderer(data, &nextProps, renderState);

View file

@ -44,6 +44,8 @@ struct RenderProps {
short minY; short minY;
short maxX; short maxX;
short maxY; short maxY;
s8 clippingPortalIndex;
}; };
void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex); void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex);