Work on screen clipping

This commit is contained in:
James Lambert 2022-05-12 22:19:53 -06:00
parent ba6fb4ed2b
commit 2eda4a3710
6 changed files with 116 additions and 118 deletions

View file

@ -29,45 +29,6 @@ void screenClipperInitWithCamera(struct ScreenClipper* clipper, struct Camera* c
guMtxCatF(modelTransform, viewProjection, clipper->pointTransform);
}
enum ClipperBounds {
ClipperBoundsRight = (1 << 0),
ClipperBoundsLeft = (1 << 1),
ClipperBoundsUp = (1 << 2),
ClipperBoundsDown = (1 << 3),
ClipperBoundsFront = (1 << 4),
ClipperBoundsW = (1 << 5),
};
int screenClipperGetOutOfBounds(struct Vector4* transformed) {
int result = 0;
if (transformed->x > transformed->w) {
result |= ClipperBoundsRight;
}
if (transformed->x < -transformed->w) {
result |= ClipperBoundsLeft;
}
if (transformed->y > transformed->w) {
result |= ClipperBoundsUp;
}
if (transformed->y < -transformed->w) {
result |= ClipperBoundsDown;
}
if (transformed->z < -transformed->w) {
result |= ClipperBoundsFront;
}
if (transformed->w <= 0.0001f) {
result |= ClipperBoundsW;
}
return result;
}
float determineClippingDistance(float x0, float x1, float w0, float w1) {
float denominator = (x1 - x0) - (w1 - w0);
@ -78,33 +39,6 @@ float determineClippingDistance(float x0, float x1, float w0, float w1) {
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;
@ -115,6 +49,40 @@ void screenClipperIncludePoint(struct Vector4* point, struct Box2D* output) {
vector2Max(&output->max, &viewportPos, &output->max);
}
unsigned screenClipperClipBoundary(struct ScreenClipper* clipper, struct Vector4* input, struct Vector4* output, unsigned pointCount, int axis, int direction) {
unsigned outputPointCount = 0;
struct Vector4* previous = &input[pointCount - 1];
float pos = VECTOR3_AS_ARRAY(previous)[axis];
float wReference = previous->w;
int wasInside = (direction < 0 ? -pos : pos) < wReference;
for (unsigned i = 0; i < pointCount; ++i) {
struct Vector4* current = &input[i];
pos = VECTOR3_AS_ARRAY(current)[axis];
wReference = current->w;
int isInside = (direction < 0 ? -pos : pos) < wReference;
if (isInside != wasInside) {
float lerp = determineClippingDistance(VECTOR3_AS_ARRAY(previous)[axis], pos, direction < 0 ? -previous->w : previous->w, direction < 0 ? -wReference : wReference);
vector4Lerp(previous, current, lerp, &output[outputPointCount]);
++outputPointCount;
}
if (isInside) {
output[outputPointCount] = input[i];
++outputPointCount;
}
previous = current;
wasInside = isInside;
}
return outputPointCount;
}
void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3* input, unsigned pointCount, struct Box2D* output) {
vector2Scale(&gOneVec2, -1.0f, &output->max);
output->min = gOneVec2;
@ -123,50 +91,21 @@ void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3*
return;
}
struct Vector4 previousPoint;
matrixVec3Mul(clipper->pointTransform, &input[pointCount - 1], &previousPoint);
int prevIsClipped = screenClipperGetOutOfBounds(&previousPoint);
struct Vector4 clipBuffer[16];
struct Vector4 clipBufferSwap[16];
for (unsigned i = 0; i < pointCount; ++i) {
struct Vector4 transformedPoint;
matrixVec3Mul(clipper->pointTransform, &input[i], &clipBuffer[i]);
}
matrixVec3Mul(clipper->pointTransform, &input[i], &transformedPoint);
pointCount = screenClipperClipBoundary(clipper, clipBuffer, clipBufferSwap, pointCount, 0, 1);
pointCount = screenClipperClipBoundary(clipper, clipBufferSwap, clipBuffer, pointCount, 0, -1);
pointCount = screenClipperClipBoundary(clipper, clipBuffer, clipBufferSwap, pointCount, 1, 1);
pointCount = screenClipperClipBoundary(clipper, clipBufferSwap, clipBuffer, pointCount, 1, -1);
pointCount = screenClipperClipBoundary(clipper, clipBuffer, clipBufferSwap, pointCount, 2, -1);
int isClipped = screenClipperGetOutOfBounds(&transformedPoint);
int clippedBoundary = prevIsClipped | isClipped;
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);
} else {
if (!(isClipped & ClipperBoundsW)) {
if (isClipped & ClipperBoundsLeft) {
output->min.x = -1.0f;
} else if (isClipped & ClipperBoundsRight) {
output->max.x = 1.0f;
}
if (isClipped & ClipperBoundsDown) {
output->min.y = -1.0f;
} else if (isClipped & ClipperBoundsUp) {
output->max.y = 1.0f;
}
}
}
previousPoint = transformedPoint;
prevIsClipped = isClipped;
for (unsigned i = 0; i < pointCount; ++i) {
screenClipperIncludePoint(&clipBufferSwap[i], output);
}
struct Vector2 negativeOne;

View file

@ -9,9 +9,15 @@ struct StaticContentElement {
u8 materialIndex;
};
struct BoundingSphere {
short x, y, z;
short radius;
};
struct LevelDefinition {
struct CollisionObject* collisionQuads;
struct StaticContentElement *staticContent;
struct BoundingSphere* boundingSpheres;
struct PortalSurface* portalSurfaces;
// maps index of a collisionQuads to indices in portalSurfaces
struct PortalSurfaceMapping* portalSurfaceMapping;

View file

@ -45,6 +45,35 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
props->maxY = SCREEN_HT;
}
#define MIN_VP_WIDTH 40
Vp* renderPropsBuildViewport(struct RenderProps* props, struct RenderState* renderState) {
int minX = props->minX;
int maxX = props->maxX;
if (maxX < MIN_VP_WIDTH) {
maxX = MIN_VP_WIDTH;
}
if (minX > SCREEN_WD - MIN_VP_WIDTH) {
minX = SCREEN_WD - MIN_VP_WIDTH;
}
Vp* viewport = renderStateRequestViewport(renderState);
viewport->vp.vscale[0] = (maxX - minX) << 1;
viewport->vp.vscale[1] = (props->maxY - props->minY) << 1;
viewport->vp.vscale[2] = G_MAXZ/2;
viewport->vp.vscale[3] = 0;
viewport->vp.vtrans[0] = (maxX + minX) << 1;
viewport->vp.vtrans[1] = (props->maxY + props->minY) << 1;
viewport->vp.vtrans[2] = G_MAXZ/2;
viewport->vp.vtrans[3] = 0;
return viewport;
}
void renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState) {
struct Transform otherInverse;
transformInvert(fromPortal, &otherInverse);
@ -59,17 +88,7 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru
cameraSetupMatrices(&next->camera, renderState, next->aspectRatio, &next->perspectiveCorrect, current->viewport);
dynamicSceneRender(renderState, 1);
Vp* viewport = renderStateRequestViewport(renderState);
viewport->vp.vscale[0] = (next->maxX - next->minX) << 1;
viewport->vp.vscale[1] = (next->maxY - next->minY) << 1;
viewport->vp.vscale[2] = G_MAXZ/2;
viewport->vp.vscale[3] = 0;
viewport->vp.vtrans[0] = (next->maxX + next->minX) << 1;
viewport->vp.vtrans[1] = (next->maxY + next->minY) << 1;
viewport->vp.vtrans[2] = G_MAXZ/2;
viewport->vp.vtrans[3] = 0;
Vp* viewport = renderPropsBuildViewport(next, renderState);
next->viewport = viewport;

View file

@ -2,8 +2,11 @@
#define __PORTAL_H__
#include "../math/transform.h"
#include "../math/plane.h"
#include "../graphics/renderstate.h"
#include "camera.h"
#include "static_scene.h"
#define PORTAL_LOOP_SIZE 8
@ -27,6 +30,8 @@ struct RenderProps {
float aspectRatio;
Mtx* perspectiveMatrix;
Vp* viewport;
struct FrustrumCullingInformation cullingInfo;
u16 perspectiveCorrect;
short currentDepth;
@ -34,6 +39,7 @@ struct RenderProps {
short minY;
short maxX;
short maxY;
};
#define STARTING_RENDER_DEPTH 1

View file

@ -1 +1,18 @@
#include "static_scene.h"
#include "static_scene.h"
#include "defs.h"
int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingSphere* boundingSphere) {
struct Vector3 spherePos;
spherePos.x = boundingSphere->x * (1.0f / SCENE_SCALE);
spherePos.y = boundingSphere->y * (1.0f / SCENE_SCALE);
spherePos.z = boundingSphere->z * (1.0f / SCENE_SCALE);
vector3Sub(&spherePos, &frustrum->cameraPosition, &spherePos);
struct Vector3 crossDirection;
vector3Cross(&frustrum->frustrumDirection, &spherePos, &crossDirection);
float distance = sqrtf(vector3MagSqrd(&crossDirection)) * frustrum->cosFrustumAngle - vector3Dot(&frustrum->frustrumDirection, &crossDirection) * frustrum->sinFrustrumAngle;
return distance > boundingSphere->radius * (1.0f / SCENE_SCALE);
}

View file

@ -5,6 +5,7 @@
#include <ultra64.h>
#include "../math/transform.h"
#include "../math/box3d.h"
#include "../levels/level_definition.h"
enum StaticSceneEntryFlags {
StaticSceneEntryFlagsHidden,
@ -30,6 +31,16 @@ struct StaticScene {
u16 gridHeight;
};
struct FrustrumCullingInformation {
struct Plane nearPlane;
struct Vector3 frustrumDirection;
struct Vector3 cameraPosition;
float cosFrustumAngle;
float sinFrustrumAngle;
};
void staticSceneInit();
int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingSphere* boundingSphere);
#endif