Halfway match CAABox; continue CBallCamera

This commit is contained in:
2022-09-29 19:55:38 -04:00
parent 7e8bc34cab
commit 602109d8f0
41 changed files with 1023 additions and 173 deletions

View File

@@ -1,6 +1,196 @@
#include "Kyoto/Math/CAABox.hpp"
#include "Kyoto/Math/CLineSeg.hpp"
#include "Kyoto/Math/CMath.hpp"
#include "Kyoto/Math/CTransform4f.hpp"
#include "Kyoto/Math/CTri.hpp"
#include "Kyoto/Streams/CInputStream.hpp"
#include "float.h"
CAABox CAABox::mskInvertedBox(FLT_MIN, FLT_MIN, FLT_MIN, FLT_MAX, FLT_MAX, FLT_MAX);
CAABox CAABox::mskNullBox(0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
CAABox::CAABox(CInputStream& in) : min(in), max(in) {}
CAABox::CAABox(const CVector3f& min, const CVector3f& max) : min(min), max(max) {}
CLineSeg CAABox::GetEdge(EBoxEdgeId id) const {
switch (id) {
case kE_Z0:
return CLineSeg(CVector3f(min.GetX(), min.GetY(), max.GetZ()),
CVector3f(min.GetX(), min.GetY(), min.GetZ()));
case kE_Y0:
return CLineSeg(CVector3f(min.GetX(), min.GetY(), max.GetZ()),
CVector3f(min.GetX(), max.GetY(), max.GetZ()));
case kE_X0:
return CLineSeg(CVector3f(min.GetX(), min.GetY(), min.GetZ()),
CVector3f(max.GetX(), min.GetY(), min.GetZ()));
case kE_Y1:
return CLineSeg(CVector3f(min.GetX(), min.GetY(), min.GetZ()),
CVector3f(min.GetX(), max.GetY(), min.GetZ()));
case kE_Z1:
return CLineSeg(CVector3f(max.GetX(), min.GetY(), min.GetZ()),
CVector3f(max.GetX(), min.GetY(), max.GetZ()));
case kE_Y2:
return CLineSeg(CVector3f(max.GetX(), min.GetY(), min.GetZ()),
CVector3f(max.GetX(), max.GetY(), min.GetZ()));
case kE_X1:
return CLineSeg(CVector3f(max.GetX(), min.GetY(), max.GetZ()),
CVector3f(min.GetX(), min.GetY(), max.GetZ()));
case kE_Y3:
return CLineSeg(CVector3f(max.GetX(), min.GetY(), max.GetZ()),
CVector3f(max.GetX(), max.GetY(), max.GetZ()));
case kE_Z2:
return CLineSeg(CVector3f(max.GetX(), max.GetY(), max.GetZ()),
CVector3f(max.GetX(), max.GetY(), min.GetZ()));
case kE_X2:
return CLineSeg(CVector3f(max.GetX(), max.GetY(), min.GetZ()),
CVector3f(min.GetX(), max.GetY(), min.GetZ()));
case kE_Z3:
return CLineSeg(CVector3f(min.GetX(), max.GetY(), min.GetZ()),
CVector3f(min.GetX(), max.GetY(), max.GetZ()));
case kE_X3:
return CLineSeg(CVector3f(min.GetX(), max.GetY(), max.GetZ()),
CVector3f(max.GetX(), max.GetY(), max.GetZ()));
default:
return CLineSeg(CVector3f(min.GetX(), min.GetY(), max.GetZ()),
CVector3f(min.GetX(), min.GetY(), min.GetZ()));
}
}
CTri CAABox::GetTri(EBoxFaceId face, int windOffset) const {
CVector3f verts[4] = {
CVector3f(min.GetX(), min.GetY(), max.GetZ()),
CVector3f(min.GetX(), min.GetY(), min.GetZ()),
CVector3f(max.GetX(), min.GetY(), min.GetZ()),
CVector3f(max.GetX(), min.GetY(), max.GetZ()),
};
switch (face) {
case kF_YMin:
default:
verts[0] = CVector3f(min.GetX(), min.GetY(), max.GetZ());
verts[1] = CVector3f(max.GetX(), min.GetY(), max.GetZ());
verts[2] = CVector3f(max.GetX(), min.GetY(), min.GetZ());
verts[3] = CVector3f(min.GetX(), min.GetY(), min.GetZ());
break;
case kF_YMax:
verts[0] = CVector3f(max.GetX(), max.GetY(), max.GetZ());
verts[1] = CVector3f(min.GetX(), max.GetY(), max.GetZ());
verts[2] = CVector3f(min.GetX(), max.GetY(), min.GetZ());
verts[3] = CVector3f(max.GetX(), max.GetY(), min.GetZ());
break;
case kF_XMin:
verts[0] = CVector3f(min.GetX(), max.GetY(), max.GetZ());
verts[1] = CVector3f(min.GetX(), min.GetY(), max.GetZ());
verts[2] = CVector3f(min.GetX(), min.GetY(), min.GetZ());
verts[3] = CVector3f(min.GetX(), max.GetY(), min.GetZ());
break;
case kF_XMax:
verts[0] = CVector3f(max.GetX(), min.GetY(), max.GetZ());
verts[1] = CVector3f(max.GetX(), max.GetY(), max.GetZ());
verts[2] = CVector3f(max.GetX(), max.GetY(), min.GetZ());
verts[3] = CVector3f(max.GetX(), min.GetY(), min.GetZ());
break;
case kF_ZMax:
verts[0] = CVector3f(min.GetX(), max.GetY(), max.GetZ());
verts[1] = CVector3f(max.GetX(), max.GetY(), max.GetZ());
verts[2] = CVector3f(max.GetX(), min.GetY(), max.GetZ());
verts[3] = CVector3f(min.GetX(), min.GetY(), max.GetZ());
break;
case kF_ZMin:
verts[0] = min;
verts[1] = CVector3f(max.GetX(), min.GetY(), min.GetZ());
verts[2] = CVector3f(max.GetX(), max.GetY(), min.GetZ());
verts[3] = CVector3f(min.GetX(), max.GetY(), min.GetZ());
break;
}
return CTri(verts[windOffset], verts[(windOffset + 1) % 4], verts[(windOffset + 2) % 4]);
}
bool CAABox::DoBoundsOverlap(const CAABox& other) const {
if (other.min.GetX() > max.GetX() || min.GetX() > other.max.GetX() ||
other.min.GetY() > max.GetY() || min.GetY() > other.max.GetY() ||
other.min.GetZ() > max.GetZ() || min.GetZ() > other.max.GetZ()) {
return false;
}
return true;
}
void CAABox::AccumulateBounds(const CVector3f& other) {
if (other.GetX() < min.GetX()) {
min.SetX(other.GetX());
}
if (other.GetY() < min.GetY()) {
min.SetY(other.GetY());
}
if (other.GetZ() < min.GetZ()) {
min.SetZ(other.GetZ());
}
if (other.GetX() > max.GetX()) {
max.SetX(other.GetX());
}
if (other.GetY() > max.GetY()) {
max.SetY(other.GetY());
}
if (other.GetZ() > max.GetZ()) {
max.SetZ(other.GetZ());
}
}
bool CAABox::Inside(const CAABox& other) const {
if (min.GetX() >= other.min.GetX() && max.GetX() <= other.max.GetX() &&
min.GetY() >= other.min.GetY() && max.GetY() <= other.max.GetY() &&
min.GetZ() >= other.min.GetZ() && max.GetZ() <= other.max.GetZ()) {
return true;
}
return false;
}
bool CAABox::InsidePlane(const CPlane& plane) const {
CVector3f vec(CMath::FastFSel(plane.GetNormal().GetX(), min.GetX(), max.GetX()),
CMath::FastFSel(plane.GetNormal().GetY(), min.GetY(), max.GetY()),
CMath::FastFSel(plane.GetNormal().GetZ(), min.GetZ(), max.GetZ()));
return !(CVector3f::Dot(plane.GetNormal(), vec) >= plane.GetConstant());
}
// TODO non-matching
CAABox CAABox::GetTransformedAABox(const CTransform4f& xf) const {
if (&xf == &CTransform4f::Identity()) {
return *this;
}
CVector3f newMin = xf.GetTranslation();
CVector3f newMax = xf.GetTranslation();
for (int x = 0; x < 3; ++x) {
for (int y = 0; y < 3; ++y) {
f32 mul = xf.GetRow(x)[y];
f32 minMul = mul * GetMinPoint()[y];
f32 maxMul = mul * GetMaxPoint()[y];
if (minMul < maxMul) {
newMin[x] += maxMul;
newMax[x] += minMul;
} else {
newMin[x] += minMul;
newMax[x] += maxMul;
}
}
}
return CAABox(newMin, newMax);
}
CVector3f CAABox::ClampToBox(const CVector3f& vec) const {
return CVector3f(
vec.GetX() < min.GetX() ? min.GetX() : (vec.GetX() > max.GetX() ? max.GetX() : vec.GetX()),
vec.GetY() < min.GetY() ? min.GetY() : (vec.GetY() > max.GetY() ? max.GetY() : vec.GetY()),
vec.GetZ() < min.GetZ() ? min.GetZ() : (vec.GetZ() > max.GetZ() ? max.GetZ() : vec.GetZ()));
}
CVector3f CAABox::FurthestPointAlongVector(const CVector3f& vec) const {
return CVector3f(CMath::FastFSel(vec.GetX(), max.GetX(), min.GetX()),
CMath::FastFSel(vec.GetY(), max.GetY(), min.GetY()),
CMath::FastFSel(vec.GetZ(), max.GetZ(), min.GetZ()));
}
CVector3f CAABox::ClosestPointAlongVector(const CVector3f& vec) const {
return CVector3f(CMath::FastFSel(vec.GetX(), min.GetX(), max.GetX()),

View File

@@ -2,14 +2,19 @@
#include "math.h"
#include "Collision/CCollidableSphere.hpp"
#include "Collision/CCollisionInfo.hpp"
#include "Collision/CRayCastResult.hpp"
#include "MetroidPrime/CCollisionActor.hpp"
#include "MetroidPrime/CGameCollision.hpp"
#include "MetroidPrime/Cameras/CCameraManager.hpp"
#include "MetroidPrime/Player/CPlayer.hpp"
#include "MetroidPrime/Tweaks/CTweakBall.hpp"
#include "MetroidPrime/Tweaks/CTweakPlayer.hpp"
#include "WorldFormat/CMetroidAreaCollider.hpp"
static CMaterialList kLineOfSightIncludeList = CMaterialList(kMT_Solid);
static CMaterialList kLineOfSightExcludeList =
CMaterialList(kMT_ProjectilePassthrough, kMT_Player, kMT_Character, kMT_CameraPassthrough);
@@ -354,3 +359,231 @@ void CBallCamera::UpdateColliders(const CTransform4f& xf,
}
}
}
// TODO non-matching regswaps
CVector3f
CBallCamera::CalculateCollidersCentroid(const rstl::vector< CCameraCollider >& colliderList,
int numObscured) const {
if (colliderList.size() < 3) {
return CVector3f(0.f, 1.f, 0.f);
}
int clearColliders = 0;
int prevCol = colliderList.size() - 1;
f32 accumCross = 0.f;
f32 accumX = 0.f;
f32 accumZ = 0.f;
for (int i = 0; i < colliderList.size(); ++i) {
if (colliderList[prevCol].GetOcclusionCount() < 2 && colliderList[i].GetOcclusionCount() < 2) {
f32 scale = colliderList[prevCol].GetScale();
f32 z0 = scale * colliderList[prevCol].GetPosition().GetZ();
f32 x0 = scale * colliderList[prevCol].GetPosition().GetX();
f32 x1 = scale * colliderList[i].GetPosition().GetX();
f32 z1 = scale * colliderList[i].GetPosition().GetZ();
f32 cross = x0 * z1 - x1 * z0;
accumCross += cross;
accumX += cross * (x1 + x0);
accumZ += cross * (z1 + z0);
} else {
clearColliders += 1;
}
prevCol = i;
}
if (static_cast< f32 >(clearColliders) / static_cast< f32 >(colliderList.size()) <=
x330_clearColliderThreshold) {
return CVector3f(0.f, 1.f, 0.f);
}
if (accumCross != 0.f) {
f32 baryCross = 3.f * accumCross;
return CVector3f(accumX / baryCross, 0.f, accumZ / baryCross);
}
return CVector3f(0.f, 2.f, 0.f);
}
CVector3f CBallCamera::ApplyColliders() {
CVector3f smallCentroid =
CalculateCollidersCentroid(x264_smallColliders, x2c4_smallCollidersObsCount);
CVector3f mediumCentroid =
CalculateCollidersCentroid(x274_mediumColliders, x2c8_mediumCollidersObsCount);
CVector3f largeCentroid =
CalculateCollidersCentroid(x284_largeColliders, x2cc_largeCollidersObsCount);
if (smallCentroid.GetY() == 0.f) {
x2a0_smallCentroid = smallCentroid;
} else {
x2a0_smallCentroid = CVector3f::Zero();
}
float centroidX = x2a0_smallCentroid.GetX();
float centroidZ = x2a0_smallCentroid.GetZ();
if (mediumCentroid.GetY() == 0.f) {
x2ac_mediumCentroid = mediumCentroid;
} else {
x2ac_mediumCentroid = CVector3f::Zero();
}
centroidX += x2ac_mediumCentroid.GetX();
centroidZ += x2ac_mediumCentroid.GetZ();
if (largeCentroid.GetY() == 0.f) {
x2b8_largeCentroid = largeCentroid;
} else {
x2b8_largeCentroid = CVector3f::Zero();
}
centroidX += x2b8_largeCentroid.GetX();
centroidZ += x2b8_largeCentroid.GetZ();
if (x18c_31_clearLOS) {
centroidX /= 1.5f;
}
centroidZ /= 3.f;
if (!x18c_31_clearLOS && x368_obscuringObjectId == kInvalidUniqueId) {
float xMul = 1.5f;
float zMul = 1.f;
if (x350_obscuringMaterial.HasMaterial(kMT_Floor)) {
zMul += 2.f * x358_unobscureMag;
}
if (x350_obscuringMaterial.HasMaterial(kMT_Wall)) {
xMul += 3.f * CMath::Clamp(0.f, x358_unobscureMag - 0.25f, 1.f);
}
centroidX *= xMul;
centroidZ *= zMul;
}
if (!x18c_28_volumeCollider) {
return CVector3f::Zero();
}
if (fabsf(centroidX) < 0.05f) {
centroidX = 0.f;
}
if (fabsf(centroidZ) < 0.05f) {
centroidZ = 0.f;
}
if (x18c_31_clearLOS) {
centroidZ *= 0.5f;
}
return CVector3f(centroidX, 0.f, centroidZ);
}
int CBallCamera::CountObscuredColliders(const rstl::vector< CCameraCollider >& colliderList) const {
int ret = 0;
for (int i = 0; i < colliderList.size(); i++) {
if (colliderList[i].GetOcclusionCount() >= 2) {
++ret;
}
}
return ret;
}
CAABox
CBallCamera::CalculateCollidersBoundingBox(const rstl::vector< CCameraCollider >& colliderList,
const CStateManager& mgr) const {
CAABox aabb = CAABox::MakeMaxInvertedBox();
for (int i = 0; i < colliderList.size(); i++) {
aabb.AccumulateBounds(colliderList[i].GetRealPosition());
}
aabb.AccumulateBounds(mgr.GetPlayer()->GetTranslation());
return aabb;
}
CVector3f CBallCamera::AvoidGeometryFull(const CTransform4f& xf, const TEntityList& nearList,
f32 dt, CStateManager& mgr) {
UpdateColliders(xf, x264_smallColliders, x2d0_smallColliderIt, x264_smallColliders.size(), 4.f,
nearList, dt, mgr);
UpdateColliders(xf, x274_mediumColliders, x2d4_mediumColliderIt, x274_mediumColliders.size(), 4.f,
nearList, dt, mgr);
UpdateColliders(xf, x284_largeColliders, x2d8_largeColliderIt, x284_largeColliders.size(), 4.f,
nearList, dt, mgr);
return ApplyColliders();
}
CVector3f CBallCamera::AvoidGeometry(const CTransform4f& xf, const TEntityList& nearList, f32 dt,
CStateManager& mgr) {
switch (x328_avoidGeomCycle) {
case 0:
UpdateColliders(xf, x264_smallColliders, x2d0_smallColliderIt, 1, 4.f, nearList, dt, mgr);
break;
case 1:
UpdateColliders(xf, x274_mediumColliders, x2d4_mediumColliderIt, 3, 4.f, nearList, dt, mgr);
break;
case 2:
UpdateColliders(xf, x284_largeColliders, x2d8_largeColliderIt, 4, 4.f, nearList, dt, mgr);
break;
case 3:
UpdateColliders(xf, x284_largeColliders, x2d8_largeColliderIt, 4, 4.f, nearList, dt, mgr);
break;
default:
break;
}
int newCycle = x328_avoidGeomCycle + 1;
x328_avoidGeomCycle = newCycle;
if (newCycle >= 4) {
x328_avoidGeomCycle = 0;
}
return ApplyColliders();
}
// TODO non-matching regswaps
bool CBallCamera::DetectCollision(const CVector3f& from, const CVector3f& to, f32 radius, f32& d,
CStateManager& mgr) {
CVector3f delta = to - from;
f32 deltaMag = delta.Magnitude();
CVector3f deltaNorm = delta * (1.f / deltaMag);
bool clear = true;
if (deltaMag > 0.000001f) {
f32 margin = 2.f * radius;
CAABox aabb = CAABox::MakeMaxInvertedBox();
aabb.AccumulateBounds(from);
aabb.AccumulateBounds(to);
aabb = CAABox(aabb.GetMinPoint() - CVector3f(margin, margin, margin),
aabb.GetMaxPoint() + CVector3f(margin, margin, margin));
TEntityList nearList;
mgr.BuildColliderList(nearList, *mgr.GetPlayer(), aabb);
CAreaCollisionCache cache(aabb);
CGameCollision::BuildAreaCollisionCache(mgr, cache);
if (cache.HasCacheOverflowed()) {
clear = false;
}
if (CGameCollision::DetectCollisionBoolean_Cached(
mgr, cache,
CCollidableSphere(CSphere(CVector3f::Zero(), radius), CMaterialList(kMT_Solid)),
CTransform4f::Translate(from),
CMaterialFilter::MakeIncludeExclude(
CMaterialList(kMT_Solid), CMaterialList(kMT_ProjectilePassthrough, kMT_Player,
kMT_Character, kMT_CameraPassthrough)),
nearList)) {
d = -1.f;
return true;
}
if (clear) {
TUniqueId intersectId = kInvalidUniqueId;
CCollisionInfo info;
f64 dTmp = deltaMag;
if (CGameCollision::DetectCollision_Cached_Moving(
mgr, cache,
CCollidableSphere(CSphere(CVector3f::Zero(), radius), CMaterialList(kMT_Solid)),
CTransform4f::Translate(from),
CMaterialFilter::MakeIncludeExclude(
CMaterialList(kMT_Solid), CMaterialList(kMT_ProjectilePassthrough, kMT_Player,
kMT_Character, kMT_CameraPassthrough)),
nearList, deltaNorm, intersectId, info, dTmp)) {
d = static_cast< f32 >(dTmp);
clear = false;
}
}
}
return !clear;
}