secondlife/viewer#1200 Avatar rotates 360 degrees when viewed from the top and below

master
Alexander Gavriliuk 2024-04-15 22:56:53 +02:00 committed by Guru
parent e5b14e4c2c
commit 0d4f52b778
2 changed files with 52 additions and 32 deletions

View File

@ -1453,48 +1453,67 @@ LLVector3 LLAgent::getReferenceUpVector()
return up_vector;
}
// Radians, positive is forward into ground
//-----------------------------------------------------------------------------
// pitch()
//-----------------------------------------------------------------------------
void LLAgent::pitch(F32 angle)
{
// don't let user pitch if pointed almost all the way down or up
if (fabs(angle) <= 1e-4)
return;
// A dot B = mag(A) * mag(B) * cos(angle between A and B)
// so... cos(angle between A and B) = A dot B / mag(A) / mag(B)
// = A dot B for unit vectors
LLCoordFrame newCoordFrame(mFrameAgent);
newCoordFrame.pitch(angle);
LLVector3 skyward = getReferenceUpVector();
// don't let user pitch if rotated 180 degree around the vertical axis
if ((newCoordFrame.getXAxis()[VX] * mFrameAgent.getXAxis()[VX] < 0) &&
(newCoordFrame.getXAxis()[VY] * mFrameAgent.getXAxis()[VY] < 0))
return;
// clamp pitch to limits
if (angle >= 0.f)
{
const F32 look_down_limit = 179.f * DEG_TO_RAD;
F32 angle_from_skyward = acos(mFrameAgent.getAtAxis() * skyward);
if (angle_from_skyward + angle > look_down_limit)
{
angle = look_down_limit - angle_from_skyward;
}
}
else if (angle < 0.f)
{
const F32 look_up_limit = 5.f * DEG_TO_RAD;
const LLVector3& viewer_camera_pos = LLViewerCamera::getInstance()->getOrigin();
LLVector3 agent_focus_pos = getPosAgentFromGlobal(gAgentCamera.calcFocusPositionTargetGlobal());
LLVector3 look_dir = agent_focus_pos - viewer_camera_pos;
F32 angle_from_skyward = angle_between(look_dir, skyward);
if (angle_from_skyward + angle < look_up_limit)
{
angle = look_up_limit - angle_from_skyward;
}
}
// don't let user pitch if pointed almost all the way down or up
LLVector3 skyward = getReferenceUpVector();
if (fabs(angle) > 1e-4)
{
mFrameAgent.pitch(angle);
}
// A dot B = mag(A) * mag(B) * cos(angle between A and B)
// so... cos(angle between A and B) = A dot B / mag(A) / mag(B)
// = A dot B for unit vectors
F32 agent_camera_angle_from_skyward = acos(newCoordFrame.getAtAxis() * skyward) * RAD_TO_DEG;
F32 min_angle = 1;
F32 max_angle = 179;
bool check_viewer_camera = false;
if (gAgentCamera.getCameraMode() == CAMERA_MODE_THIRD_PERSON)
{
// These values of min_angle and max_angle are obtained purely empirically
if (gAgentCamera.getCameraPreset() == CAMERA_PRESET_REAR_VIEW)
{
min_angle = 10;
check_viewer_camera = true;
}
else if (gAgentCamera.getCameraPreset() == CAMERA_PRESET_GROUP_VIEW)
{
min_angle = 10;
max_angle = 170;
check_viewer_camera = true;
}
}
if ((angle < 0 && agent_camera_angle_from_skyward < min_angle) ||
(angle > 0 && agent_camera_angle_from_skyward > max_angle))
return;
if (check_viewer_camera)
{
const LLVector3& viewer_camera_pos = LLViewerCamera::getInstance()->getOrigin();
LLVector3 agent_focus_pos = getPosAgentFromGlobal(gAgentCamera.calcFocusPositionTargetGlobal());
LLVector3 look_dir = agent_focus_pos - viewer_camera_pos;
F32 viewer_camera_angle_from_skyward = angle_between(look_dir, skyward) * RAD_TO_DEG;
if ((angle < 0 && viewer_camera_angle_from_skyward < min_angle) ||
(angle > 0 && viewer_camera_angle_from_skyward > max_angle))
return;
}
mFrameAgent = newCoordFrame;
}

View File

@ -112,6 +112,7 @@ private:
//--------------------------------------------------------------------
public:
void switchCameraPreset(ECameraPreset preset);
ECameraPreset getCameraPreset() const { return mCameraPreset; }
/** Determines default camera offset depending on the current camera preset */
LLVector3 getCameraOffsetInitial();
/** Determines default focus offset depending on the current camera preset */