Bettercam improvements: no longer sways when close to geo, no longer zooms if player partially visible

This commit is contained in:
MysterD 2022-05-25 17:47:34 -07:00
parent 0778226e60
commit c15f8bfef0
5 changed files with 134 additions and 86 deletions

View file

@ -985,3 +985,25 @@ f32 not_zero(f32 value, f32 replacement) {
}
return value;
}
void vec3f_project(Vec3f vec, Vec3f onto, Vec3f out) {
f32 numerator = vec3f_dot(vec, onto);
f32 denominator = vec3f_dot(onto, onto);
if (denominator == 0) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
return;
}
vec3f_copy(out, onto);
vec3f_mul(out, numerator / denominator);
}
f32 vec3f_dist(Vec3f v1, Vec3f v2) {
Vec3f diff = {
v1[0] - v2[0],
v1[1] - v2[1],
v1[2] - v2[2],
};
return vec3f_length(diff);
}

View file

@ -84,4 +84,7 @@ s32 anim_spline_poll(struct MarioState* m, Vec3f result);
f32 not_zero(f32 value, f32 replacement);
void vec3f_project(Vec3f vec, Vec3f onto, Vec3f out);
f32 vec3f_dist(Vec3f v1, Vec3f v2);
#endif // MATH_UTIL_H

View file

@ -482,60 +482,93 @@ static void newcam_update_values(void) {
}
}
static void newcam_bounding_box(void) {
Vec3f camdirs[NEW_CAM_BOUNDING_BOX_RAYS] = { 0 };
Vec3f raypos[NEW_CAM_BOUNDING_BOX_RAYS] = { 0 };
s16 antiYaw = newcam_yaw - 0x4000;
// sideways ray 1
camdirs[0][0] = coss(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS;
camdirs[0][2] = sins(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS;
// sideways ray 2
camdirs[1][0] = -coss(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS;
camdirs[1][2] = -sins(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS;
// vertical rays
camdirs[2][1] = -NEW_CAM_BOUNDING_BOX_VRADIUS;
camdirs[3][1] = NEW_CAM_BOUNDING_BOX_VRADIUS;
for (s32 i = 0; i < NEW_CAM_BOUNDING_BOX_RAYS; i++) {
struct Surface* surf;
Vec3f offset = { 0 };
Vec3f startpos = { 0 };
vec3f_copy(startpos, newcam_pos);
vec3f_add(startpos, offset);
find_surface_on_ray(startpos, camdirs[i], &surf, raypos[i]);
if (!surf) {
vec3f_copy(raypos[i], startpos);
vec3f_add(raypos[i], camdirs[i]);
}
}
Vec3f avg = { 0 };
for (s32 i = 0; i < NEW_CAM_BOUNDING_BOX_RAYS; i++) {
vec3f_add(avg, raypos[i]);
}
vec3f_mul(avg, 1.0f / ((f32)NEW_CAM_BOUNDING_BOX_RAYS));
vec3f_copy(newcam_pos, avg);
static void debug_pos(f32 x, f32 y, f32 z, u8 hit) { // DO NOT COMMIT
if(gMarioStates[0].marioObj == NULL) { return; }
struct Object* obj = spawn_object(gMarioStates[0].marioObj, hit ? MODEL_RED_COIN : MODEL_YELLOW_COIN, bhvSparkle);
if (obj == NULL) { return; }
obj->oPosX = x;
obj->oPosY = y;
obj->oPosZ = z;
obj_scale(obj, 0.5f);
}
static void newcam_collision(void) {
struct Surface *surf;
Vec3f camdir;
// check if we can see player
Vec3f up = { 0, 1, 0 };
Vec3f mainRay = {
newcam_pos[0]-newcam_lookat[0],
newcam_pos[1]-newcam_lookat[1],
newcam_pos[2]-newcam_lookat[2],
};
Vec3f sideway;
vec3f_normalize(mainRay);
vec3f_cross(sideway, mainRay, up);
f32 checkWidth = 75;
f32 checkHeight = 90;
bool allhit = true;
for (f32 x = -1; x <= 1; x++) {
for (f32 y = 0; y <= 1; y++) {
if (fabs(x) + fabs(y) != 1) { continue; }
Vec3f offset = {
sideway[0] * x * checkWidth,
-checkHeight / 2 + y * checkHeight,
sideway[2] * x * checkWidth,
};
if (x != 0) {
struct Surface* surf;
Vec3f hitpos;
Vec3f move = {
offset[0] * 1.2f,
offset[1],
offset[2] * 1.2f,
};
find_surface_on_ray(newcam_pos_target, move, &surf, hitpos);
vec3f_copy(offset, hitpos);
vec3f_sub(offset, newcam_pos_target);
if (surf) {
offset[0] *= 0;
offset[2] *= 0;
}
}
Vec3f camray = {
newcam_pos[0] - newcam_lookat[0] - offset[0],
newcam_pos[1] - newcam_lookat[1] - offset[1],
newcam_pos[2] - newcam_lookat[2] - offset[2],
};
Vec3f camorig = {
newcam_pos_target[0] + offset[0],
newcam_pos_target[1] + offset[1],
newcam_pos_target[2] + offset[2],
};
struct Surface* surf;
Vec3f hitpos;
find_surface_on_ray(camorig, camray, &surf, hitpos);
debug_pos(camorig[0], camorig[1], camorig[2], surf != NULL);
if (surf == NULL) {
allhit = false;
}
}
}
Vec3f camdir = {
newcam_pos[0]-newcam_lookat[0],
newcam_pos[1]-newcam_lookat[1],
newcam_pos[2]-newcam_lookat[2],
};
if (allhit) {
struct Surface *surf = NULL;
Vec3f hitpos;
camdir[0] = newcam_pos[0]-newcam_lookat[0];
camdir[1] = newcam_pos[1]-newcam_lookat[1];
camdir[2] = newcam_pos[2]-newcam_lookat[2];
find_surface_on_ray(newcam_pos_target, camdir, &surf, hitpos);
newcam_coldist = sqrtf((newcam_pos_target[0] - hitpos[0]) * (newcam_pos_target[0] - hitpos[0]) + (newcam_pos_target[1] - hitpos[1]) * (newcam_pos_target[1] - hitpos[1]) + (newcam_pos_target[2] - hitpos[2]) * (newcam_pos_target[2] - hitpos[2]));
if (surf) {
// offset the hit pos by the hit normal
Vec3f offset = { 0 };
@ -551,6 +584,15 @@ static void newcam_collision(void) {
newcam_pan_x = 0;
newcam_pan_z = 0;
}
newcam_coldist = vec3f_dist(newcam_pos_target, hitpos);
} else {
newcam_pos[0] = newcam_pos_target[0] + camdir[0];
newcam_pos[1] = newcam_pos_target[1] + camdir[1];
newcam_pos[2] = newcam_pos_target[2] + camdir[2];
newcam_coldist = vec3f_length(camdir);
}
}
static void newcam_set_pan(void) {
@ -611,7 +653,6 @@ static void newcam_position_cam(void) {
newcam_level_bounds();
if (newcam_modeflags & NC_FLAG_COLLISION) {
newcam_collision();
newcam_bounding_box();
}
}

View file

@ -11741,28 +11741,6 @@ static s8 sRomHackIsUpdate = 0;
static f32 sRomHackWaterFocus = 0;
static f32 sRomHackWaterPitchOffset = 0;
static void vec3f_project(Vec3f vec, Vec3f onto, Vec3f out) {
f32 numerator = vec3f_dot(vec, onto);
f32 denominator = vec3f_dot(onto, onto);
if (denominator == 0) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
return;
}
vec3f_copy(out, onto);
vec3f_mul(out, numerator / denominator);
}
static f32 vec3f_dist(Vec3f v1, Vec3f v2) {
Vec3f diff = {
v1[0] - v2[0],
v1[1] - v2[1],
v1[2] - v2[2],
};
return vec3f_length(diff);
}
static u8 rom_hack_cam_can_see_mario(Vec3f desiredPos) {
// do collision checking
struct Surface *surf = NULL;

View file

@ -42,6 +42,8 @@
#define MATRIX_STACK_SIZE 32
#define MAX_PROJECTION_NEAR_VALUE 5
s16 gMatStackIndex;
Mat4 gMatStack[MATRIX_STACK_SIZE] = {};
Mat4 gMatStackPrev[MATRIX_STACK_SIZE] = {};
@ -222,7 +224,8 @@ void patch_mtx_interpolated(f32 delta) {
if (sPerspectiveNode != NULL) {
u16 perspNorm;
f32 fovInterpolated = delta_interpolate_f32(sPerspectiveNode->prevFov, sPerspectiveNode->fov, delta);
guPerspective(sPerspectiveMtx, &perspNorm, not_zero(fovInterpolated, gOverrideFOV), sPerspectiveAspect, not_zero(sPerspectiveNode->near, gOverrideNear), not_zero(sPerspectiveNode->far, gOverrideFar), 1.0f);
f32 near = MIN(sPerspectiveNode->near, MAX_PROJECTION_NEAR_VALUE);
guPerspective(sPerspectiveMtx, &perspNorm, not_zero(fovInterpolated, gOverrideFOV), sPerspectiveAspect, not_zero(near, gOverrideNear), not_zero(sPerspectiveNode->far, gOverrideFar), 1.0f);
gSPMatrix(sPerspectivePos, VIRTUAL_TO_PHYSICAL(sPerspectiveNode), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
}
@ -456,7 +459,8 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {
f32 aspect = (f32) gCurGraphNodeRoot->width / divisor;
#endif
guPerspective(mtx, &perspNorm, not_zero(node->prevFov, gOverrideFOV), aspect, not_zero(node->near, gOverrideNear), not_zero(node->far, gOverrideFar), 1.0f);
f32 near = MIN(node->near, MAX_PROJECTION_NEAR_VALUE);
guPerspective(mtx, &perspNorm, not_zero(node->prevFov, gOverrideFOV), aspect, not_zero(near, gOverrideNear), not_zero(node->far, gOverrideFar), 1.0f);
sPerspectiveNode = node;
sPerspectiveMtx = mtx;