More CBallCamera and CCameraSpline work

This commit is contained in:
Jack Andersen 2017-10-12 21:19:22 -10:00
parent 651d0a27c2
commit 16f6307642
4 changed files with 378 additions and 18 deletions

View File

@ -11,6 +11,7 @@
#include "World/CScriptCameraHint.hpp"
#include "World/CScriptDoor.hpp"
#include "World/CScriptWater.hpp"
#include "Collision/CGameCollision.hpp"
namespace urde
{
@ -23,19 +24,19 @@ void CCameraSpring::Reset()
float CCameraSpring::ApplyDistanceSpringNoMax(float targetX, float curX, float dt)
{
float usePos = xc_tardis * x10_dx * dt + curX;
float useX = xc_tardis * x10_dx * dt + curX;
x10_dx += xc_tardis * (x0_k * (targetX - curX) - x4_k2Sqrt * x10_dx) * dt;
return std::max(usePos, targetX);
return std::max(useX, targetX);
}
float CCameraSpring::ApplyDistanceSpring(float targetX, float curX, float dt)
{
float usePos = xc_tardis * x10_dx * dt + curX;
float useX = xc_tardis * x10_dx * dt + curX;
x10_dx += xc_tardis * (x0_k * (targetX - curX) - x4_k2Sqrt * x10_dx) * dt;
usePos = std::max(usePos, targetX);
if (usePos - targetX > x8_max)
usePos = targetX + x8_max;
return usePos;
useX = std::max(useX, targetX);
if (useX - targetX > x8_max)
useX = targetX + x8_max;
return useX;
}
CBallCamera::CBallCamera(TUniqueId uid, TUniqueId watchedId, const zeus::CTransform& xf,
@ -332,7 +333,7 @@ void CBallCamera::ResetSpline(CStateManager& mgr)
tmpPoint2Ball = mgr.GetPlayer().GetMoveDir();
zeus::CVector3f desiredPosition = FindDesiredPosition(distance, elevation, tmpPoint2Ball, mgr);
x37c_camSpline.AddKnot(desiredPosition, zeus::CVector3f::skForward);
x37c_camSpline.x44_ = x37c_camSpline.CalculateSplineLength();
x37c_camSpline.UpdateSplineLength();
x3d0_24_ = false;
CMaterialList intersectMat;
x3c8_ = CMaterialList(EMaterialTypes::Floor, EMaterialTypes::Ceiling);
@ -411,7 +412,7 @@ void CBallCamera::BuildSpline(CStateManager& mgr)
mgr.RayWorldIntersection(intersectId, x9ac, -x978.normalized(), x978.magnitude(), BallCameraFilter, nearList);
if (result.IsValid() && !result.GetMaterial().HasMaterial(EMaterialTypes::Pillar))
x37c_camSpline.SetKnotPosition(2, result.GetPoint() - x978.normalized() * 0.3f * 1.25f);
x37c_camSpline.x44_ = x37c_camSpline.CalculateSplineLength();
x37c_camSpline.UpdateSplineLength();
if (!SplineIntersectTest(intersectMat, mgr))
{
x36c_ = 0;
@ -420,7 +421,7 @@ void CBallCamera::BuildSpline(CStateManager& mgr)
}
x374_ = 0.5f;
x378_ = 0.5f;
x37c_camSpline.x44_ = x37c_camSpline.CalculateSplineLength();
x37c_camSpline.UpdateSplineLength();
x3c8_ = CMaterialList();
}
@ -775,17 +776,161 @@ zeus::CVector3f CBallCamera::ComputeVelocity(const zeus::CVector3f& curVel, cons
zeus::CVector3f CBallCamera::TweenVelocity(const zeus::CVector3f& curVel, const zeus::CVector3f& newVel,
float rate, float dt)
{
return {};
zeus::CVector3f velDelta = newVel - curVel;
if (velDelta.canBeNormalized())
{
float t = zeus::clamp(-1.f, velDelta.magnitude() / (rate * dt), 1.f);
return velDelta.normalized() * rate * dt * t + curVel;
}
return newVel;
}
zeus::CVector3f CBallCamera::MoveCollisionActor(const zeus::CVector3f& pos, float dt, CStateManager& mgr)
{
return {};
if (TCastToPtr<CPhysicsActor> act = mgr.ObjectById(x46c_collisionActorId))
{
zeus::CVector3f posDelta = pos - act->GetTranslation();
if (!posDelta.canBeNormalized() || posDelta.magnitude() < 0.01f)
{
act->Stop();
return act->GetTranslation();
}
zeus::CVector3f oldTranslation = act->GetTranslation();
zeus::CVector3f oldVel = act->GetVelocity();
zeus::CVector3f newVel = ComputeVelocity(oldVel, posDelta * (1.f / dt));
act->SetVelocityWR(newVel);
act->SetMovable(true);
act->AddMaterial(EMaterialTypes::Solid, mgr);
CGameCollision::Move(mgr, *act, dt, nullptr);
zeus::CVector3f posDelta2 = act->GetTranslation() - pos;
if (posDelta2.canBeNormalized() && posDelta2.magnitude() > 0.1f)
{
act->SetTranslation(oldTranslation);
act->SetVelocityWR(TweenVelocity(oldVel, newVel, 50.f, dt));
CGameCollision::Move(mgr, *act, dt, nullptr);
posDelta2 = act->GetTranslation() - pos;
if (posDelta2.magnitude() > 0.1f)
x478_ += 1;
else
x478_ = 0;
}
else
{
act->Stop();
x478_ = 0;
}
act->SetMovable(false);
act->RemoveMaterial(EMaterialTypes::Solid, mgr);
return act->GetTranslation();
}
return pos;
}
void CBallCamera::UpdateUsingFreeLook(float dt, CStateManager& mgr)
{
if (x400_state == EBallCameraState::Four || x400_state == EBallCameraState::Five)
{
x36c_ = 0;
return;
}
if (x36c_ == 1 && x188_behaviour <= EBallCameraBehaviour::Eight &&
x188_behaviour >= EBallCameraBehaviour::Four)
{
x36c_ = 0;
return;
}
float elevation = x1a0_elevation;
float distance = x190_curMinDistance;
ConstrainElevationAndDistance(elevation, distance, 0.f, mgr);
zeus::CVector3f ballPos = mgr.GetPlayer().GetBallPosition();
zeus::CVector3f knotToBall = ballPos - x37c_camSpline.GetKnotPosition(2);
if (knotToBall.canBeNormalized())
knotToBall.normalize();
else
knotToBall = mgr.GetPlayer().GetMoveDir();
zeus::CVector3f knot3 = x37c_camSpline.GetKnotPosition(3);
zeus::CVector3f desiredPos = FindDesiredPosition(distance, elevation, knotToBall, mgr);
if (x370_24_)
x37c_camSpline.SetKnotPosition(3, desiredPos);
x374_ -= dt;
float f26 = 1.f - zeus::clamp(0.f, x374_ / x378_, 1.f);
if (x36c_ == 1)
{
CMaterialList intersectMat;
if (!SplineIntersectTest(intersectMat, mgr))
{
x37c_camSpline.SetKnotPosition(3, knot3);
if (intersectMat.HasMaterial(EMaterialTypes::Floor))
{
x36c_ = 0;
return;
}
}
}
if (x374_ <= 0.f || (f26 > 0.75f && x18c_31_))
{
if (x36c_ == 2 && !x18c_31_)
{
CMaterialList intersectMat;
if (!SplineIntersectTest(intersectMat, mgr))
{
x36c_ = 0;
}
else
{
zeus::CVector3f oldKnot2 = x37c_camSpline.GetKnotPosition(2);
zeus::CVector3f oldKnot1 = x37c_camSpline.GetKnotPosition(1);
BuildSpline(mgr);
x37c_camSpline.SetKnotPosition(3, x37c_camSpline.GetKnotPosition(1));
x37c_camSpline.SetKnotPosition(2, x37c_camSpline.GetKnotPosition(0));
x37c_camSpline.SetKnotPosition(1, oldKnot2);
x37c_camSpline.SetKnotPosition(0, oldKnot1);
x37c_camSpline.UpdateSplineLength();
x374_ = x378_ - x378_ * (x37c_camSpline.GetKnotT(2) / x37c_camSpline.x44_length);
x374_ -= dt;
f26 = zeus::clamp(0.f, x374_ / x378_, 1.f);
}
}
else
{
x36c_ = 0;
}
}
x37c_camSpline.UpdateSplineLength();
zeus::CVector3f pos = x37c_camSpline.GetInterpolatedSplinePointByLength(f26 * x37c_camSpline.x44_length).origin;
if (TCastToPtr<CPhysicsActor> act = mgr.ObjectById(x46c_collisionActorId))
{
CMaterialFilter filter = act->GetMaterialFilter();
CMaterialFilter tmpFilter = filter;
tmpFilter.IncludeList().Add(EMaterialTypes::Wall);
tmpFilter.ExcludeList().Add(x3c8_);
act->SetMaterialFilter(tmpFilter);
MoveCollisionActor(pos, dt, mgr);
act->SetMaterialFilter(filter);
}
zeus::CVector3f lookDir = x1d8_ - desiredPos;
if (x18d_26_)
lookDir = ballPos - desiredPos;
if (lookDir.canBeNormalized())
{
lookDir.normalize();
UpdateTransform(lookDir, desiredPos, dt, mgr);
}
TeleportCamera(desiredPos, mgr);
if (x3d0_24_ && x374_ / x378_ < 0.5f)
x36c_ = 0;
}
zeus::CVector3f CBallCamera::InterpolateCameraElevation(const zeus::CVector3f& camPos) const

View File

@ -5,7 +5,7 @@
namespace urde
{
CCameraSpline::CCameraSpline(bool b) : x48_(b) {}
CCameraSpline::CCameraSpline(bool b) : x48_closedLoop(b) {}
void CCameraSpline::CalculateKnots(TUniqueId cameraId, const std::vector<SConnection>& connections, CStateManager& mgr)
{
@ -27,12 +27,12 @@ void CCameraSpline::CalculateKnots(TUniqueId cameraId, const std::vector<SConnec
void CCameraSpline::Reset(int size)
{
x4_positions.clear();
x24_.clear();
x24_t.clear();
x34_directions.clear();
if (size != 0)
{
x4_positions.reserve(size);
x24_.reserve(size);
x24_t.reserve(size);
x34_directions.reserve(size);
}
}
@ -50,8 +50,214 @@ void CCameraSpline::SetKnotPosition(int idx, const zeus::CVector3f& pos)
x4_positions[idx] = pos;
}
const zeus::CVector3f& CCameraSpline::GetKnotPosition(int idx) const
{
if (idx >= x4_positions.size())
return zeus::CVector3f::skZero;
return x4_positions[idx];
}
float CCameraSpline::GetKnotT(int idx) const
{
if (idx >= x4_positions.size())
return 0.f;
return x24_t[idx];
}
float CCameraSpline::CalculateSplineLength()
{
float ret = 0.f;
x24_t.clear();
if (x4_positions.size() > 0)
{
zeus::CVector3f prevPoint = x4_positions[0];
float tDiv = 1.f / float(x4_positions.size() - 1);
for (int i=0 ; i<x4_positions.size() ; ++i)
{
float subT = 0.f;
float baseT = i * tDiv;
x24_t.push_back(ret);
while (subT <= tDiv)
{
subT += tDiv * 0.03125f;
zeus::CVector3f nextPoint = GetInterpolatedSplinePointByTime(baseT + subT, 1.f);
zeus::CVector3f delta = nextPoint - prevPoint;
if (delta.canBeNormalized())
{
prevPoint = nextPoint;
ret += delta.magnitude();
}
}
}
x24_t.push_back(ret);
if (x48_closedLoop)
{
zeus::CVector3f delta = x4_positions[0] - x4_positions[x4_positions.size() - 1];
if (delta.canBeNormalized())
ret += delta.magnitude();
}
return ret;
}
return 0.f;
}
bool CCameraSpline::GetSurroundingPoints(int idx, rstl::reserved_vector<zeus::CVector3f, 4>& positions,
rstl::reserved_vector<zeus::CVector3f, 4>& directions) const
{
if (x4_positions.size() <= 3 || idx < 0 || idx >= x4_positions.size())
return false;
if (idx > 0)
{
positions.push_back(x4_positions[idx - 1]);
directions.push_back(x34_directions[idx - 1]);
}
else if (x48_closedLoop)
{
positions.push_back(x4_positions[x4_positions.size() - 1]);
directions.push_back(x34_directions[x4_positions.size() - 1]);
}
else
{
positions.push_back(x4_positions[0] - (x4_positions[1] - x4_positions[0]));
directions.push_back(x34_directions[0]);
}
positions.push_back(x4_positions[idx]);
directions.push_back(x34_directions[idx]);
if (idx + 1 >= x4_positions.size())
{
if (x48_closedLoop)
{
positions.push_back(x4_positions[idx - x4_positions.size()]);
directions.push_back(x34_directions[idx - x4_positions.size()]);
}
else
{
positions.push_back(x4_positions[x4_positions.size() - 1] -
(x4_positions[x4_positions.size() - 2] - x4_positions[x4_positions.size() - 1]));
directions.push_back(x34_directions[x4_positions.size() - 1]);
}
}
else
{
positions.push_back(x4_positions[idx + 1]);
directions.push_back(x34_directions[idx + 1]);
}
if (idx + 2 >= x4_positions.size())
{
if (x48_closedLoop)
{
positions.push_back(x4_positions[idx + 2 - x4_positions.size()]);
directions.push_back(x34_directions[idx + 2 - x4_positions.size()]);
}
else
{
positions.push_back(x4_positions[x4_positions.size() - 1] -
(x4_positions[x4_positions.size() - 2] - x4_positions[x4_positions.size() - 1]));
directions.push_back(x34_directions[x4_positions.size() - 1]);
}
}
else
{
positions.push_back(x4_positions[idx + 2]);
directions.push_back(x34_directions[idx + 2]);
}
return true;
}
zeus::CTransform CCameraSpline::GetInterpolatedSplinePointByLength(float pos)
{
if (x4_positions.empty())
return zeus::CTransform();
int baseIdx = 0;
int i;
for (i=1 ; i<x4_positions.size() ; ++i)
{
if (x24_t[i] > pos)
{
baseIdx = i - 1;
break;
}
}
if (i == x4_positions.size())
baseIdx = i - 1;
if (pos < 0.f)
baseIdx = 0;
if (pos >= x44_length)
{
if (x48_closedLoop)
{
pos -= x44_length;
baseIdx = 0;
}
else
{
baseIdx = x4_positions.size() - 2;
pos = x44_length;
}
}
float range;
if (baseIdx == x4_positions.size() - 1)
{
if (x48_closedLoop)
range = x44_length - x24_t[baseIdx];
else
range = x44_length - x24_t[x4_positions.size() - 2];
}
else
{
range = x24_t[baseIdx + 1] - x24_t[baseIdx];
}
float t = zeus::clamp(0.f, (pos - x24_t[baseIdx]) / range, 1.f);
rstl::reserved_vector<zeus::CVector3f, 4> positions;
rstl::reserved_vector<zeus::CVector3f, 4> directions;
if (GetSurroundingPoints(baseIdx, positions, directions))
{
float f1 = zeus::clamp(-1.f, directions[1].dot(directions[2]), 1.f);
if (f1 >= 1.f)
{
zeus::CTransform ret = zeus::lookAt(zeus::CVector3f::skZero, directions[2]);
ret.origin = zeus::getCatmullRomSplinePoint(positions[0], positions[1], positions[2], positions[3], t);
return ret;
}
else
{
zeus::CTransform ret = zeus::lookAt(zeus::CVector3f::skZero,
zeus::CQuaternion::lookAt(directions[1], directions[2], std::acos(f1) * t).transform(directions[1]));
ret.origin = zeus::getCatmullRomSplinePoint(positions[0], positions[1], positions[2], positions[3], t);
return ret;
}
}
return zeus::CTransform();
}
zeus::CVector3f CCameraSpline::GetInterpolatedSplinePointByTime(float time, float range)
{
if (x4_positions.empty())
return {};
rstl::reserved_vector<zeus::CVector3f, 4> positions;
rstl::reserved_vector<zeus::CVector3f, 4> directions;
float rangeFac = range / float(x4_positions.size() - 1);
int baseIdx = std::min(int(x4_positions.size() - 1), int(time / rangeFac));
if (GetSurroundingPoints(baseIdx, positions, directions))
return zeus::getCatmullRomSplinePoint(positions[0], positions[1], positions[2], positions[3],
(time - float(baseIdx) * rangeFac) / rangeFac);
return {};
}
}

View File

@ -11,10 +11,12 @@ class CCameraSpline
friend class CBallCamera;
std::vector<zeus::CVector3f> x4_positions;
std::vector<TUniqueId> x14_;
std::vector<float> x24_;
std::vector<float> x24_t;
std::vector<zeus::CVector3f> x34_directions;
float x44_ = 0.f;
bool x48_ = false;
float x44_length = 0.f;
bool x48_closedLoop = false;
bool GetSurroundingPoints(int idx, rstl::reserved_vector<zeus::CVector3f, 4>& positions,
rstl::reserved_vector<zeus::CVector3f, 4>& directions) const;
public:
CCameraSpline(bool);
void CalculateKnots(TUniqueId, const std::vector<SConnection>&, CStateManager&);
@ -22,7 +24,12 @@ public:
void Reset(int size);
void AddKnot(const zeus::CVector3f& pos, const zeus::CVector3f& dir);
void SetKnotPosition(int idx, const zeus::CVector3f& pos);
const zeus::CVector3f& GetKnotPosition(int idx) const;
float GetKnotT(int idx) const;
float CalculateSplineLength();
void UpdateSplineLength() { x44_length = CalculateSplineLength(); }
zeus::CTransform GetInterpolatedSplinePointByLength(float pos);
zeus::CVector3f GetInterpolatedSplinePointByTime(float time, float range);
};
}

View File

@ -32,6 +32,8 @@ public:
const CMaterialList& GetIncludeList() const { return x0_include; }
const CMaterialList& GetExcludeList() const { return x8_exclude; }
CMaterialList& IncludeList() { return x0_include; }
CMaterialList& ExcludeList() { return x8_exclude; }
bool Passes(const CMaterialList&) const;
};
}