Portal effect is working

This commit is contained in:
James Lambert 2022-03-01 21:20:27 -07:00
parent ccf04df65d
commit de467c45e6
9 changed files with 202 additions and 39 deletions

View file

@ -4,6 +4,8 @@
#include "../math/vector4.h"
#include "../math/matrix.h"
#include <math.h>
#include <ultra64.h>
void screenClipperInit(struct ScreenClipper* clipper, float transform[4][4]) {
@ -66,10 +68,65 @@ int screenClipperGetOutOfBounds(struct Vector4* transformed) {
return result;
}
float determineClippingDistance(float x0, float x1, float w0, float w1) {
float denominator = (x1 - x0) - (w1 - w0);
if (fabsf(denominator) < 0.00001f) {
return 1.0f;
}
return (w0 - x0) / denominator;
}
void screenClipperClip(struct Vector4* from, struct Vector4* to, int clippingMask, struct Vector4* output) {
float t = 1.0f;
float check;
if ((clippingMask & ClipperBoundsRight) && (check = determineClippingDistance(from->x, to->x, from->w, to->w)) < t) {
t = check;
}
if ((clippingMask & ClipperBoundsLeft) && (check = determineClippingDistance(from->x, to->x, -from->w, -to->w)) < t) {
t = check;
}
if ((clippingMask & ClipperBoundsUp) && (check = determineClippingDistance(from->y, to->y, from->w, to->w)) < t) {
t = check;
}
if ((clippingMask & ClipperBoundsDown) && (check = determineClippingDistance(from->y, to->y, -from->w, -to->w)) < t) {
t = check;
}
if ((clippingMask & ClipperBoundsFront) && (check = determineClippingDistance(from->z, to->z, -from->w, -to->w)) < t) {
t = check;
}
vector4Lerp(from, to, t, output);
}
void screenClipperIncludePoint(struct Vector4* point, struct Box2D* output) {
struct Vector2 viewportPos;
float invW = 1.0f / point->w;
viewportPos.x = point->x * invW;
viewportPos.y = point->y * invW;
vector2Min(&output->min, &viewportPos, &output->min);
vector2Max(&output->max, &viewportPos, &output->max);
}
void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3* input, unsigned pointCount, struct Box2D* output) {
vector2Scale(&gOneVec2, -1.0f, &output->max);
output->min = gOneVec2;
if (pointCount == 0) {
return;
}
struct Vector4 previousPoint;
matrixVec3Mul(clipper->pointTransform, &input[pointCount - 1], &previousPoint);
int prevIsClipped = screenClipperGetOutOfBounds(&previousPoint);
for (unsigned i = 0; i < pointCount; ++i) {
struct Vector4 transformedPoint;
@ -77,15 +134,29 @@ void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3*
int isClipped = screenClipperGetOutOfBounds(&transformedPoint);
if (!isClipped) {
struct Vector2 viewportPos;
viewportPos.x = transformedPoint.x / transformedPoint.w;
viewportPos.y = transformedPoint.y / transformedPoint.w;
int clippedBoundary = prevIsClipped | isClipped;
vector2Min(&output->min, &viewportPos, &output->min);
vector2Max(&output->max, &viewportPos, &output->max);
} else {
// TODO find edge intersections
if (clippedBoundary && (!isClipped || !prevIsClipped)) {
struct Vector4 clipped;
if (isClipped) {
screenClipperClip(&previousPoint, &transformedPoint, clippedBoundary, &clipped);
} else {
screenClipperClip(&transformedPoint, &previousPoint, clippedBoundary, &clipped);
}
screenClipperIncludePoint(&clipped, output);
}
if (!isClipped) {
screenClipperIncludePoint(&transformedPoint, output);
}
previousPoint = transformedPoint;
prevIsClipped = isClipped;
}
struct Vector2 negativeOne;
vector2Scale(&gOneVec2, -1.0f, &negativeOne);
vector2Max(&output->min, &negativeOne, &output->min);
vector2Min(&output->max, &gOneVec2, &output->max);
}

View file

@ -1 +1,10 @@
#include "vector4.h"
#include "vector4.h"
void vector4Lerp(struct Vector4* a, struct Vector4* b, float lerp, struct Vector4* out) {
float tInv = 1.0f - lerp;
out->x = a->x * tInv + b->x * lerp;
out->y = a->y * tInv + b->y * lerp;
out->z = a->z * tInv + b->z * lerp;
out->w = a->w * tInv + b->w * lerp;
}

View file

@ -6,4 +6,6 @@ struct Vector4 {
float x, y, z, w;
};
void vector4Lerp(struct Vector4* a, struct Vector4* b, float lerp, struct Vector4* out);
#endif

View file

@ -34,7 +34,7 @@ Gfx mat_portal_mask_portal_mask[] = {
gsDPPipeSync(),
gsDPSetRenderMode(RM_UPDATE_Z(1), RM_UPDATE_Z(2)),
gsDPSetCombineLERP(0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE),
gsDPSetPrimColor(0, 0, 255, 128, 0, 128),
gsDPSetPrimColor(0, 0, 255, 128, 0, 0),
gsSPEndDisplayList(),
};
@ -43,7 +43,7 @@ Gfx portal_mask_Circle_mesh[] = {
gsSPDisplayList(portal_mask_Circle_mesh_tri_0),
gsDPPipeSync(),
gsSPGeometryMode(G_CULL_BACK, G_CULL_FRONT),
gsDPSetPrimColor(0, 0, 0, 128, 255, 128),
gsDPSetPrimColor(0, 0, 0, 128, 255, 0),
gsSP1Triangle(0, 1, 2, 0),
gsSP1Triangle(0, 2, 3, 0),
gsSP1Triangle(2, 4, 3, 0),

View file

@ -26,11 +26,11 @@ void cameraBuildProjectionMatrix(struct Camera* camera, float matrix[4][4], u16*
guPerspectiveF(matrix, perspectiveNormalize, camera->fov, aspectRatio, camera->nearPlane * planeScalar, camera->farPlane * planeScalar, 1.0f);
}
void cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, float aspectRatio) {
Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, float aspectRatio, u16* perspNorm) {
Mtx* viewProjMatrix = renderStateRequestMatrices(renderState, 2);
if (!viewProjMatrix) {
return;
return NULL;
}
guMtxIdent(&viewProjMatrix[0]);
@ -48,4 +48,10 @@ void cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState,
gSPMatrix(renderState->dl++, osVirtualToPhysical(&viewProjMatrix[1]), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
gSPPerspNormalize(renderState->dl++, perspectiveNormalize);
if (perspNorm) {
*perspNorm = perspectiveNormalize;
}
return &viewProjMatrix[1];
}

View file

@ -18,6 +18,6 @@ struct Camera {
void cameraInit(struct Camera* camera, float fov, float near, float far);
void cameraBuildViewMatrix(struct Camera* camera, float matrix[4][4]);
void cameraBuildProjectionMatrix(struct Camera* camera, float matrix[4][4], u16* perspectiveNorm, float aspectRatio);
void cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, float aspectRatio);
Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, float aspectRatio, u16* perspNorm);
#endif

View file

@ -18,41 +18,83 @@ struct Vector3 gPortalOutline[] = {
{-0.353553f * SCENE_SCALE, 0.707107f * SCENE_SCALE, 0.0f},
};
void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState) {
props->camera = *camera;
props->aspectRatio = aspectRatio;
props->perspectiveMatrix = cameraSetupMatrices(camera, renderState, aspectRatio, &props->perspectiveCorrect);
props->currentDepth = STARTING_RENDER_DEPTH;
props->minX = 0;
props->minY = 0;
props->maxX = SCREEN_WD;
props->maxY = SCREEN_HT;
}
void renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, short minX, short minY, short maxX, short maxY, struct RenderState* renderState) {
struct Transform otherInverse;
transformInvert(fromPortal, &otherInverse);
struct Transform portalCombined;
transformConcat(toPortal, &otherInverse, &portalCombined);
next->camera = current->camera;
next->aspectRatio = current->aspectRatio;
transformConcat(&portalCombined, &current->camera.transform, &next->camera.transform);
next->perspectiveMatrix = cameraSetupMatrices(&next->camera, renderState, next->aspectRatio, &next->perspectiveCorrect);
next->currentDepth = current->currentDepth - 1;
next->minX = minX;
next->minY = minY;
next->maxX = maxX;
next->maxY = maxY;
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, minX, minY, maxX, maxY);
}
void portalInit(struct Portal* portal, enum PortalFlags flags) {
transformInitIdentity(&portal->transform);
portal->flags = flags;
}
void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Camera* camera, struct RenderState* renderState) {
void portalRender(struct Portal* portal, struct Portal* otherPortal, struct RenderProps* props, SceneRenderCallback sceneRenderer, void* data, struct RenderState* renderState) {
if (props->currentDepth == 0) {
// TODO render non see through portal
return;
}
struct ScreenClipper clipper;
float portalTransform[4][4];
transformToMatrix(&portal->transform, portalTransform);
screenClipperInitWithCamera(&clipper, camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
screenClipperInitWithCamera(&clipper, &props->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
struct Box2D clippingBounds;
screenClipperBoundingPoints(&clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds);
Mtx* matrix = renderStateRequestMatrices(renderState, 1);
guMtxF2L(portalTransform, matrix);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
gSPDisplayList(renderState->dl++, portal_mask_Circle_mesh);
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
if (clippingBounds.min.x < clippingBounds.max.x) {
int minX = CALC_SCREEN_SPACE(clippingBounds.min.x, SCREEN_WD << 2);
int maxX = CALC_SCREEN_SPACE(clippingBounds.max.x, SCREEN_WD << 2);
int minY = CALC_SCREEN_SPACE(-clippingBounds.max.y, SCREEN_HT << 2);
int maxY = CALC_SCREEN_SPACE(-clippingBounds.min.y, SCREEN_HT << 2);
int minX = CALC_SCREEN_SPACE(clippingBounds.min.x, SCREEN_WD);
int maxX = CALC_SCREEN_SPACE(clippingBounds.max.x, SCREEN_WD);
int minY = CALC_SCREEN_SPACE(-clippingBounds.max.y, SCREEN_HT);
int maxY = CALC_SCREEN_SPACE(-clippingBounds.min.y, SCREEN_HT);
gDPPipeSync(renderState->dl++);
gDPSetCombineLERP(renderState->dl++, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE);
gDPSetRenderMode(renderState->dl++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetPrimColor(renderState->dl++, 0, 0, 0, 255, 0, 64);
gSPTextureRectangle(renderState->dl++, minX, minY, maxX, maxY, 0, 0, 0, 1 << 10, 1 << 10);
gDPPipeSync(renderState->dl++);
struct RenderProps nextProps;
renderPropsNext(props, &nextProps, &portal->transform, &otherPortal->transform, minX, minY, maxX, maxY, renderState);
sceneRenderer(data, &nextProps, renderState);
// revert to previous state
gSPMatrix(renderState->dl++, osVirtualToPhysical(props->perspectiveMatrix), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
gSPPerspNormalize(renderState->dl++, props->perspectiveCorrect);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, props->minX, props->minY, props->maxX, props->maxY);
Mtx* matrix = renderStateRequestMatrices(renderState, 1);
guMtxF2L(portalTransform, matrix);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
gSPDisplayList(renderState->dl++, portal_mask_Circle_mesh);
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
}
}

View file

@ -14,8 +14,30 @@ struct Portal {
enum PortalFlags flags;
};
struct RenderProps;
typedef void SceneRenderCallback(void* data, struct RenderProps* properties, struct RenderState* renderState);
struct RenderProps {
struct Camera camera;
float aspectRatio;
Mtx* perspectiveMatrix;
u16 perspectiveCorrect;
short currentDepth;
short minX;
short minY;
short maxX;
short maxY;
};
#define STARTING_RENDER_DEPTH 1
void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState);
void renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, short minX, short minY, short maxX, short maxY, struct RenderState* renderState);
void portalInit(struct Portal* portal, enum PortalFlags flags);
void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Camera* camera, struct RenderState* renderState);
void portalRender(struct Portal* portal, struct Portal* otherPortal, struct RenderProps* props, SceneRenderCallback sceneRenderer, void* data, struct RenderState* renderState);
#endif

View file

@ -39,14 +39,25 @@ void sceneInit(struct Scene* scene) {
quatAxisAngle(&gUp, M_PI * 0.5f, &scene->portals[1].transform.rotation);
}
void sceneRender(struct Scene* scene, struct RenderState* renderState, struct GraphicsTask* task) {
cameraSetupMatrices(&scene->camera, renderState, (float)SCREEN_WD / (float)SCREEN_HT);
void sceneRenderWithProperties(void* data, struct RenderProps* properties, struct RenderState* renderState) {
struct Scene* scene = (struct Scene*)data;
portalRender(&scene->portals[0], &scene->portals[1], properties, sceneRenderWithProperties, data, renderState);
portalRender(&scene->portals[1], &scene->portals[0], properties, sceneRenderWithProperties, data, renderState);
gDPSetRenderMode(renderState->dl++, G_RM_ZB_OPA_SURF, G_RM_ZB_OPA_SURF2);
gSPDisplayList(renderState->dl++, test_chamber_00_0_test_chamber_00_0_mesh);
}
portalRender(&scene->portals[0], &scene->portals[1], &scene->camera, renderState);
portalRender(&scene->portals[1], &scene->portals[2], &scene->camera, renderState);
void sceneRender(struct Scene* scene, struct RenderState* renderState, struct GraphicsTask* task) {
struct RenderProps renderProperties;
// gSPDisplayList(renderState->dl++, test_chamber_00_0_test_chamber_00_0_mesh);
renderPropsInit(&renderProperties, &scene->camera, (float)SCREEN_WD / (float)SCREEN_HT, renderState);
renderProperties.camera = scene->camera;
renderProperties.currentDepth = STARTING_RENDER_DEPTH;
sceneRenderWithProperties(scene, &renderProperties, renderState);
}
unsigned ignoreInputFrames = 10;