Working portal gun

This commit is contained in:
James Lambert 2022-05-09 17:17:46 -06:00
parent 9e6903f11b
commit ea0f4ce45c
6 changed files with 79 additions and 32 deletions

View file

@ -165,28 +165,49 @@ void quatRandom(struct Quaternion* q) {
}
void quatLook(struct Vector3* lookDir, struct Vector3* up, struct Quaternion* out) {
struct Vector3 horizontal;
horizontal = *lookDir;
horizontal.y = 0.0f;
vector3Normalize(&horizontal, &horizontal);
// calculate orthonormal basis
struct Vector3 zDir;
vector3Normalize(lookDir, &zDir);
vector3Negate(&zDir, &zDir);
struct Vector2 complex;
complex.x = -horizontal.z;
complex.y = -horizontal.x;
struct Vector3 yDir;
vector3AddScaled(up, &zDir, -vector3Dot(&zDir, up), &yDir);
vector3Normalize(&yDir, &yDir);
struct Quaternion yaw;
quatAxisComplex(&gUp, &complex, &yaw);
struct Vector3 xDir;
vector3Cross(&yDir, &zDir, &xDir);
struct Vector3 lookNormalized;
vector3Normalize(lookDir, &lookNormalized);
complex.y = lookNormalized.y;
complex.x = sqrtf(1.0f - complex.y * complex.y);
struct Quaternion pitch;
quatAxisComplex(&gRight, &complex, &pitch);
quatMultiply(&yaw, &pitch, out);
// convert orthonormal basis to a quaternion
float trace = xDir.x + yDir.y + zDir.z;
if (trace > 0) {
float sqrtResult = sqrtf(trace+1.0f) * 2.0f;
float invSqrtResult = 1.0f / sqrtResult;
out->w = 0.25 * sqrtResult;
out->x = (yDir.z - zDir.y) * invSqrtResult;
out->y = (zDir.x - xDir.z) * invSqrtResult;
out->z = (xDir.y - yDir.x) * invSqrtResult;
} else if ((xDir.x > yDir.y) && (xDir.x > zDir.z)) {
float sqrtResult = sqrtf(1.0 + xDir.x - yDir.y - zDir.z) * 2.0f;
float invSqrtResult = 1.0f / sqrtResult;
out->w = (yDir.z - zDir.y) * invSqrtResult;
out->x = 0.25 * sqrtResult;
out->y = (yDir.x + xDir.y) * invSqrtResult;
out->z = (zDir.x + xDir.z) * invSqrtResult;
} else if (yDir.y > zDir.z) {
float sqrtResult = sqrtf(1.0 + yDir.y - xDir.x - zDir.z) * 2.0f;
float invSqrtResult = 1.0f / sqrtResult;
out->w = (zDir.x - xDir.z) * invSqrtResult;
out->x = (yDir.x + xDir.y) * invSqrtResult;
out->y = 0.25 * sqrtResult;
out->z = (zDir.y + yDir.z) * invSqrtResult;
} else {
float sqrtResult = sqrtf(1.0 + zDir.z - xDir.x - yDir.y) * 2.0f;
float invSqrtResult = 1.0f / sqrtResult;
out->w = (xDir.y - yDir.x) * invSqrtResult;
out->x = (zDir.x + xDir.z) * invSqrtResult;
out->y = (zDir.y + yDir.z) * invSqrtResult;
out->z = 0.25 * sqrtResult;
}
}
void quatLerp(struct Quaternion* a, struct Quaternion* b, float t, struct Quaternion* out) {

View file

@ -124,7 +124,7 @@ void rigidBodyCheckPortals(struct RigidBody* rigidBody) {
quatConjugate(&gCollisionScene.portalTransforms[i]->rotation, &inverseARotation);
struct Quaternion rotationTransfer;
quatMultiply(&inverseARotation, &otherPortal->rotation, &rotationTransfer);
quatMultiply(&otherPortal->rotation, &inverseARotation, &rotationTransfer);
quatMultVector(&rotationTransfer, &rigidBody->velocity, &rigidBody->velocity);
quatMultVector(&rotationTransfer, &rigidBody->angularVelocity, &rigidBody->angularVelocity);

View file

@ -217,6 +217,14 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
player->pitchVelocity * targetPitch > 0.0f ? ROTATE_RATE_DELTA : ROTATE_RATE_STOP_DELTA
);
struct Vector3 lookingForward;
vector3Negate(&gForward, &lookingForward);
quatMultVector(&player->body.transform.rotation, &lookingForward, &lookingForward);
struct Quaternion upRotation;
quatLook(&lookingForward, &gUp, &upRotation);
quatLerp(&upRotation, &player->body.transform.rotation, 0.9f, &player->body.transform.rotation);
struct Quaternion deltaRotate;
quatAxisAngle(&gUp, player->yawVelocity * FIXED_DELTA_TIME, &deltaRotate);

View file

@ -48,11 +48,11 @@ int portalSurfaceIsInside(struct PortalSurface* surface, struct Transform* porta
continue;
}
int yIntersection = (int)(a.y - b.y) * (portalPosition.x - b.x) / (a.x - b.x);
int yIntersection = (int)(a.y - b.y) * (portalPosition.x - b.x) / (a.x - b.x) + b.y;
if (yIntersection > 0) {
if (yIntersection > portalPosition.y) {
++intersectionCount;
} else if (yIntersection == 0) {
} else if (yIntersection == portalPosition.y) {
// portal is on an edge exit early
return 0;
}
@ -88,7 +88,7 @@ void portalSurfaceAdjustPosition(struct PortalSurface* surface, struct Transform
halfSize.x = (maxPortal.x - minPortal.x) >> 1;
halfSize.y = (maxPortal.y - minPortal.y) >> 1;
for (int i = 0; i < 2; ++i) {
for (int interation = 0; interation < 2; ++interation) {
int minOverlap = NO_OVERLAP;
struct Vector2s16 minOverlapOffset;
@ -136,11 +136,11 @@ void portalSurfaceAdjustPosition(struct PortalSurface* surface, struct Transform
if (abs(offset.x) > abs(offset.y)) {
lineAxis = 0;
crossAxis = 1;
crossDirection = sign(offset.x);
crossDirection = -sign(offset.x);
} else {
lineAxis = 1;
crossAxis = 0;
crossDirection = -sign(offset.y);
crossDirection = sign(offset.y);
}
int portalPosLineAxis = VECTOR2s16_AS_ARRAY(output)[lineAxis];
@ -153,14 +153,14 @@ void portalSurfaceAdjustPosition(struct PortalSurface* surface, struct Transform
int boxPosition = VECTOR2s16_AS_ARRAY(output)[crossAxis] + crossDirection * VECTOR2s16_AS_ARRAY(&halfSize)[crossAxis];
int distance = (boxPosition - VECTOR2s16_AS_ARRAY(&a)[crossAxis]) * crossDirection;
if (distance <= 0) {
if (distance <= 0 && distance < VECTOR2s16_AS_ARRAY(&halfSize)[crossAxis]) {
continue;
}
if (distance < minOverlap) {
minOverlap = distance;
VECTOR2s16_AS_ARRAY(&minOverlapOffset)[lineAxis] = 0;
VECTOR2s16_AS_ARRAY(&minOverlapOffset)[crossAxis] = distance * crossDirection;
VECTOR2s16_AS_ARRAY(&minOverlapOffset)[crossAxis] = -distance * crossDirection;
}
}

View file

@ -103,13 +103,29 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr
// contactSolverDebugDraw(&gContactSolver, renderState);
}
unsigned ignoreInputFrames = 10;
void sceneCheckPortals(struct Scene* scene) {
struct Ray raycastRay;
struct Vector3 playerUp;
raycastRay.origin = scene->player.body.transform.position;
vector3Negate(&gForward, &raycastRay.dir);
quatMultVector(&scene->player.body.transform.rotation, &raycastRay.dir, &raycastRay.dir);
quatMultVector(&scene->player.body.transform.rotation, &gUp, &playerUp);
if (controllerGetButtonDown(0, Z_TRIG)) {
sceneFirePortal(scene, &raycastRay, &playerUp, 0);
}
if (controllerGetButtonDown(0, R_TRIG)) {
sceneFirePortal(scene, &raycastRay, &playerUp, 1);
}
}
void sceneUpdate(struct Scene* scene) {
OSTime frameStart = osGetTime();
scene->lastFrameTime = frameStart - scene->lastFrameStart;
playerUpdate(&scene->player, &scene->camera.transform);
sceneCheckPortals(scene);
collisionSceneUpdateDynamics();
@ -146,9 +162,6 @@ int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* player
quatLook(&hitDirection, playerUp, &portalLocation.rotation);
}
// TODO remove once there is a hole in the wall
vector3AddScaled(&portalLocation.position, &hit.normal, 0.1f, &portalLocation.position);
return sceneOpenPortal(scene, &portalLocation, portalIndex, quadIndex);
}
@ -157,6 +170,11 @@ int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex,
for (int i = surfaceMapping.minPortalIndex; i < surfaceMapping.maxPortalIndex; ++i) {
if (portalSurfaceGenerate(&gCurrentLevel->portalSurfaces[i], at, NULL, NULL)) {
struct Vector3 portalForward;
quatMultVector(&at->rotation, &gForward, &portalForward);
// TODO remove once there is a hole in the wall
vector3AddScaled(&at->position, &portalForward, (portalIndex == 0) ? -0.1f : 0.1f, &at->position);
scene->portals[portalIndex].transform = *at;
gCollisionScene.portalTransforms[portalIndex] = &scene->portals[portalIndex].transform;
return 1;