From 55fa62c57e128b41997080791014b6d1d70eb0dc Mon Sep 17 00:00:00 2001 From: James Lambert Date: Mon, 18 Sep 2023 21:08:52 -0600 Subject: [PATCH] Finish up portal trail effect --- assets/materials/static.skm.yaml | 2 +- assets/models/portal_gun/ball_trail.flags | 2 +- src/effects/portal_trail.c | 119 ++++++++++++++++++++-- src/effects/portal_trail.h | 11 +- src/scene/camera.c | 12 +++ src/scene/camera.h | 2 + src/scene/portal_gun.c | 13 ++- src/scene/portal_gun.h | 3 +- src/scene/render_plan.c | 12 --- src/scene/render_plan.h | 1 - src/scene/scene.c | 3 +- 11 files changed, 144 insertions(+), 36 deletions(-) diff --git a/assets/materials/static.skm.yaml b/assets/materials/static.skm.yaml index 12e2879..c1389f5 100644 --- a/assets/materials/static.skm.yaml +++ b/assets/materials/static.skm.yaml @@ -1146,7 +1146,7 @@ materials: gDPSetCombineMode: color: ["1", "PRIMITIVE", "TEXEL0", "PRIMITIVE"] - alpha: ["TEXEL0", "0", "SHADE", "0"] + alpha: ["TEXEL0", "PRIMITIVE", "SHADE", "0"] gSPGeometryMode: clear: [G_CULL_BACK, G_CULL_FRONT, G_ZBUFFER] set: [G_FOG] \ No newline at end of file diff --git a/assets/models/portal_gun/ball_trail.flags b/assets/models/portal_gun/ball_trail.flags index fb0d466..13da653 100644 --- a/assets/models/portal_gun/ball_trail.flags +++ b/assets/models/portal_gun/ball_trail.flags @@ -1 +1 @@ --m assets/materials/static.skm.yaml --rotate 0,0,0 --sort-dir 0,1,0 --default-material brightglow_y \ No newline at end of file +-m assets/materials/static.skm.yaml --default-material portal_trail \ No newline at end of file diff --git a/src/effects/portal_trail.c b/src/effects/portal_trail.c index 410d46f..2c5103c 100644 --- a/src/effects/portal_trail.c +++ b/src/effects/portal_trail.c @@ -1,41 +1,81 @@ #include "portal_trail.h" #include "../math/vector2.h" +#include "../math/mathf.h" #include "../defs.h" #include "../build/assets/models/portal_gun/ball_trail.h" #include "../build/assets/materials/static.h" #include "../graphics/color.h" +#include "../util/time.h" + +#define TRAIL_LENGTH 8.0f +#define FADE_IN_LENGTH 4.0f +#define SEGMENT_LENGTH 2.0f +#define SEGMENT_ROTATION (152 * M_PI / 180.0f) + struct Transform gTrailSectionOffset = { - {0.0f, 0.0f, -8.0f}, + {0.0f, 0.0f, -SEGMENT_LENGTH}, {0.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f}, }; void portalTrailInit(struct PortalTrail* trail) { + quatAxisAngle(&gForward, SEGMENT_ROTATION, &gTrailSectionOffset.rotation); transformToMatrixL(&gTrailSectionOffset, &trail->sectionOffset, SCENE_SCALE); guMtxIdent(&trail->baseTransform[0]); guMtxIdent(&trail->baseTransform[1]); trail->currentBaseTransform = 0; + trail->lastDistance = 0.0f; + trail->maxDistance = -TRAIL_LENGTH; +} + +void portalTrailUpdateBaseTransform(struct PortalTrail* trail) { + trail->currentBaseTransform ^= 1; + transformToMatrixL(&trail->trailTransform, &trail->baseTransform[trail->currentBaseTransform], SCENE_SCALE); + osWritebackDCache(&trail->baseTransform[trail->currentBaseTransform], sizeof(Mtx)); } void portalTrailPlay(struct PortalTrail* trail, struct Vector3* from, struct Vector3* to) { trail->trailTransform.position = *from; struct Vector3 dir; vector3Sub(to, from, &dir); - quatLook(&dir, &gUp, &trail->trailTransform.rotation); + struct Vector3 randomUp; + randomUp.x = randomInRangef(-1.0f, 1.0f); + randomUp.y = randomInRangef(-1.0f, 1.0f); + randomUp.z = randomInRangef(-1.0f, 1.0f); + quatLook(&dir, &randomUp, &trail->trailTransform.rotation); + vector3Normalize(&dir, &trail->direction); trail->trailTransform.scale = gOneVec; - trail->currentBaseTransform ^= 1; + portalTrailUpdateBaseTransform(trail); - transformToMatrixL(&trail->trailTransform, &trail->baseTransform[trail->currentBaseTransform], SCENE_SCALE); - osWritebackDCache(&trail->baseTransform[trail->currentBaseTransform], sizeof(Mtx)); + trail->lastDistance = 0.0f; + trail->maxDistance = vector3Dot(&dir, &trail->direction); + + if (trail->maxDistance < SEGMENT_LENGTH) { + trail->maxDistance = -TRAIL_LENGTH; + } } -void portalTrailUpdate(struct PortalTrail* trail, float distance) { +void portalTrailUpdate(struct PortalTrail* trail) { + if (trail->lastDistance >= trail->maxDistance + TRAIL_LENGTH) { + return; + } + trail->lastDistance += FIXED_DELTA_TIME * PORTAL_PROJECTILE_SPEED; + + if (trail->lastDistance > TRAIL_LENGTH + SEGMENT_LENGTH) { + trail->lastDistance -= SEGMENT_LENGTH; + trail->maxDistance -= SEGMENT_LENGTH; + + struct Transform tmp; + transformConcat(&trail->trailTransform, &gTrailSectionOffset, &tmp); + trail->trailTransform = tmp; + portalTrailUpdateBaseTransform(trail); + } } struct Coloru8 gTrailColor[] = { @@ -43,16 +83,73 @@ struct Coloru8 gTrailColor[] = { {50, 70, 200, 255}, }; -void portalTrailRender(struct PortalTrail* trail, struct RenderState* renderState, struct MaterialState* materialState) { +void portalTrailRender(struct PortalTrail* trail, struct RenderState* renderState, struct MaterialState* materialState, struct Camera* fromCamera, int portalIndex) { + if (trail->lastDistance >= trail->maxDistance + TRAIL_LENGTH) { + return; + } + materialStateSet(materialState, PORTAL_TRAIL_INDEX, renderState); - struct Coloru8* color = &gTrailColor[0]; - gSPFogPosition(renderState->dl++, 800, 999); - gDPSetPrimColor(renderState->dl++, 255, 255, color->r, color->g, color->b, color->a); + struct Coloru8* color = &gTrailColor[portalIndex]; + struct Ray cameraRay; + cameraRay.origin = fromCamera->transform.position; + quatMultVector(&fromCamera->transform.rotation, &gForward, &cameraRay.dir); + vector3Negate(&cameraRay.dir, &cameraRay.dir); + + struct Vector3 pointAlongTrail; + vector3AddScaled(&trail->trailTransform.position, &trail->direction, trail->lastDistance - TRAIL_LENGTH, &pointAlongTrail); + int minDistance = fogIntValue(cameraClipDistance(fromCamera, rayDetermineDistance(&cameraRay, &pointAlongTrail))); + + vector3AddScaled(&trail->trailTransform.position, &trail->direction, trail->lastDistance, &pointAlongTrail); + int maxDistance = fogIntValue(cameraClipDistance(fromCamera, rayDetermineDistance(&cameraRay, &pointAlongTrail))); + + if (maxDistance <= minDistance) { + maxDistance = minDistance + 1; + + if (maxDistance > 1000) { + maxDistance = 1000; + minDistance = 999; + } + } + + float currentDistance = trail->lastDistance - TRAIL_LENGTH; + + int alpha = 0; + + if (currentDistance < -(TRAIL_LENGTH - FADE_IN_LENGTH)) { + alpha = (int)(((TRAIL_LENGTH - FADE_IN_LENGTH) + currentDistance) * (-255.0f / TRAIL_LENGTH)); + + if (alpha < 0) { + alpha = 0; + } + + if (alpha > 255) { + alpha = 255; + } + } + + gSPFogPosition(renderState->dl++, minDistance, maxDistance); + gDPSetPrimColor(renderState->dl++, 255, 255, color->r, color->g, color->b, alpha); gSPMatrix(renderState->dl++, &trail->baseTransform[trail->currentBaseTransform], G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL); - gSPDisplayList(renderState->dl++, portal_gun_ball_trail_model_gfx); + int hasMore = 1; + + while (hasMore) { + currentDistance += SEGMENT_LENGTH; + + hasMore = currentDistance < trail->lastDistance && currentDistance < trail->maxDistance; + + if (currentDistance <= 0.0f) { + continue; + } + + gSPDisplayList(renderState->dl++, portal_gun_ball_trail_model_gfx); + + if (hasMore) { + gSPMatrix(renderState->dl++, &trail->sectionOffset, G_MTX_MODELVIEW | G_MTX_NOPUSH | G_MTX_MUL); + } + } gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW); } \ No newline at end of file diff --git a/src/effects/portal_trail.h b/src/effects/portal_trail.h index ee50196..316fdf2 100644 --- a/src/effects/portal_trail.h +++ b/src/effects/portal_trail.h @@ -8,18 +8,23 @@ #include "../math/transform.h" #include "../graphics/renderstate.h" #include "../levels/material_state.h" +#include "../scene/camera.h" + +#define PORTAL_PROJECTILE_SPEED 50.0f struct PortalTrail { struct Transform trailTransform; Mtx sectionOffset; Mtx baseTransform[2]; - struct Vector3 chunkOffset; + struct Vector3 direction; short currentBaseTransform; + float lastDistance; + float maxDistance; }; void portalTrailInit(struct PortalTrail* trail); void portalTrailPlay(struct PortalTrail* trail, struct Vector3* from, struct Vector3* to); -void portalTrailUpdate(struct PortalTrail* trail, float distance); -void portalTrailRender(struct PortalTrail* trail, struct RenderState* renderState, struct MaterialState* materialState); +void portalTrailUpdate(struct PortalTrail* trail); +void portalTrailRender(struct PortalTrail* trail, struct RenderState* renderState, struct MaterialState* materialState, struct Camera* fromCamera, int portalIndex); #endif \ No newline at end of file diff --git a/src/scene/camera.c b/src/scene/camera.c index 1a2b93f..6192723 100644 --- a/src/scene/camera.c +++ b/src/scene/camera.c @@ -194,4 +194,16 @@ float cameraClipDistance(struct Camera* camera, float distance) { } return -((camera->nearPlane + camera->farPlane) * modifiedDistance + 2.0f * camera->nearPlane * camera->farPlane) / denom; +} + +int fogIntValue(float floatValue) { + if (floatValue < -1.0) { + return 0; + } + + if (floatValue > 1.0) { + return 1000; + } + + return (int)((floatValue + 1.0f) * 500.0f); } \ No newline at end of file diff --git a/src/scene/camera.h b/src/scene/camera.h index b7bc1eb..b0b08aa 100644 --- a/src/scene/camera.h +++ b/src/scene/camera.h @@ -47,4 +47,6 @@ int cameraApplyMatrices(struct RenderState* renderState, struct CameraMatrixInfo float cameraClipDistance(struct Camera* camera, float distance); +int fogIntValue(float floatValue); + #endif \ No newline at end of file diff --git a/src/scene/portal_gun.c b/src/scene/portal_gun.c index b000feb..79d4d66 100644 --- a/src/scene/portal_gun.c +++ b/src/scene/portal_gun.c @@ -14,6 +14,8 @@ #define PORTAL_GUN_RECOIL_TIME (0.18f) +#define PORTAL_GUN_NEAR_PLANE 0.05f + struct Vector2 gGunColliderEdgeVectors[] = { {0.0f, 1.0f}, {0.707f, 0.707f}, @@ -108,20 +110,20 @@ void portalBallRender(struct PortalGunProjectile* projectile, struct RenderState gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW); } -void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* renderState, struct Transform* fromView) { +void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* renderState, struct Camera* fromCamera) { struct MaterialState materialState; materialStateInit(&materialState, DEFAULT_INDEX); for (int i = 0; i < 2; ++i) { struct PortalGunProjectile* projectile = &portalGun->projectiles[i]; - portalTrailRender(&projectile->trail, renderState, &materialState); + portalTrailRender(&projectile->trail, renderState, &materialState, fromCamera, i); if (projectile->roomIndex == -1) { continue; } - portalBallRender(projectile, renderState, &materialState, fromView, i); + portalBallRender(projectile, renderState, &materialState, &fromCamera->transform, i); } portalGun->rigidBody.transform.scale = gOneVec; @@ -131,6 +133,8 @@ void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* render return; } + cameraModifyProjectionViewForPortalGun(fromCamera, renderState, PORTAL_GUN_NEAR_PLANE * SCENE_SCALE, (float)SCREEN_WD / (float)SCREEN_HT); + transformToMatrixL(&portalGun->rigidBody.transform, matrix, SCENE_SCALE); gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL); gSPDisplayList(renderState->dl++, portal_gun_v_portalgun_model_gfx); @@ -138,7 +142,6 @@ void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* render } #define NO_HIT_DISTANCE 20.0f -#define PORTAL_PROJECTILE_SPEED 50.0f #define MAX_PROJECTILE_DISTANCE 100.0f void portalGunUpdate(struct PortalGun* portalGun, struct Player* player) { @@ -163,6 +166,8 @@ void portalGunUpdate(struct PortalGun* portalGun, struct Player* player) { for (int i = 0; i < 2; ++i) { struct PortalGunProjectile* projectile = &portalGun->projectiles[i]; + portalTrailUpdate(&projectile->trail); + if (projectile->roomIndex == -1) { continue; } diff --git a/src/scene/portal_gun.h b/src/scene/portal_gun.h index 89ffafd..091560e 100644 --- a/src/scene/portal_gun.h +++ b/src/scene/portal_gun.h @@ -10,6 +10,7 @@ #include "../player/player.h" #include "../util/time.h" #include "../effects/portal_trail.h" +#include "../scene/camera.h" struct PortalGunProjectile { struct Ray positionDirection; @@ -38,7 +39,7 @@ struct PortalGun { void portalGunInit(struct PortalGun* portalGun, struct Transform* at); // void portalGunDummyRender(void* data, struct DynamicRenderDataList* renderList, struct RenderState* renderState); void portalGunUpdate(struct PortalGun* portalGun, struct Player* player); -void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* renderState, struct Transform* fromView); +void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* renderState, struct Camera* fromCamera); void portalGunFire(struct PortalGun* portalGun, int portalIndex, struct Ray* ray, struct Vector3* playerUp, int roomIndex); diff --git a/src/scene/render_plan.c b/src/scene/render_plan.c index a2baa78..8aad962 100644 --- a/src/scene/render_plan.c +++ b/src/scene/render_plan.c @@ -471,18 +471,6 @@ void renderPlanBuild(struct RenderPlan* renderPlan, struct Scene* scene, struct #define MIN_FOG_DISTANCE 1.0f #define MAX_FOG_DISTANCE 2.5f -int fogIntValue(float floatValue) { - if (floatValue < -1.0) { - return 0; - } - - if (floatValue > 1.0) { - return 1000; - } - - return (int)((floatValue + 1.0f) * 500.0f); -} - void renderPlanExecute(struct RenderPlan* renderPlan, struct Scene* scene, Mtx* staticTransforms, struct RenderState* renderState) { struct DynamicRenderDataList* dynamicList = dynamicRenderListNew(renderState, MAX_DYNAMIC_SCENE_OBJECTS); diff --git a/src/scene/render_plan.h b/src/scene/render_plan.h index d1964d0..452a25c 100644 --- a/src/scene/render_plan.h +++ b/src/scene/render_plan.h @@ -6,7 +6,6 @@ #define DEFAULT_FAR_PLANE 30.0f #define DEFAULT_NEAR_PLANE 0.125f -#define PORTAL_GUN_NEAR_PLANE 0.05f #define MAX_PORTAL_STEPS 6 diff --git a/src/scene/scene.c b/src/scene/scene.c index e3079ea..081d67f 100644 --- a/src/scene/scene.c +++ b/src/scene/scene.c @@ -306,8 +306,7 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr renderPlanExecute(&renderPlan, scene, staticMatrices, renderState); if (scene->portalGun.portalGunVisible){ - cameraModifyProjectionViewForPortalGun(&scene->camera, renderState, PORTAL_GUN_NEAR_PLANE * SCENE_SCALE, renderPlan.stageProps[0].aspectRatio); - portalGunRenderReal(&scene->portalGun, renderState, &scene->camera.transform); + portalGunRenderReal(&scene->portalGun, renderState, &scene->camera); } gDPPipeSync(renderState->dl++);