Difference between revisions of "Angle Decay"

From P2SR Wiki

m (typo)
 
Line 1: Line 1:
 
{{P2_Title|Angle Decay}}
 
{{P2_Title|Angle Decay}}
  
Sometimes, the player's pitch angle will naturally decay, very slowly, towards or away from 0. This is normally not noticeable, but can present an issue when attempting to line up precise shots, in particular [[Seamshots]] (such as the one on [[Crazy Box]]).
+
'''Angle Decay''' is a glitch which causes player's pitch angle to slowly change over time without user input. This is normally not noticeable, but can present an issue when attempting to line up precise shots, in particular [[Seamshots]] (such as the one on [[Crazy Box]]).
  
There are two types of angle decay: major decay (which decays the pitch angle towards 0) and minor decay (which decays the pitch angle away from 0, downwards, i.e. towards positive pitch values). The latter of these is much slower, and is only present on Windows.
+
There are two types of angle decay, each differing in occurence and speed:
 +
* '''major decay''' - decays the pitch angle towards 0 and is more prominent the further pitch angle is from 0.
 +
* '''minor decay''' - decays the pitch angle towards positive values. It's slower than major decay, occurs only within small range of pitch angle near 0, and occurs only on Windows version of the game.
  
 
== Factors Affecting Decay ==
 
== Factors Affecting Decay ==
  
Both major and minor decay scale linearly with FPS (i.e. if you have 120FPS, your angle will decay twice as quickly as it would if you had 60FPS). Neither form of decay happens when tabbed out of the game, or with <code>in_forceuser</code> set to control a different player.
+
Both major and minor decay scale linearly with FPS (i.e. if you have 120FPS, your angle will decay twice as quickly as it would if you had 60FPS). Neither form of decay happens when the game is not fetching any user input (for instance, when tabbed out of the game, or with <code>in_forceuser</code> set to control a different player).
  
Minor decay is always present while your pitch angle is close to 0. Major decay, however, only manifests itself in certain cases. When passing through a portal with a non-trivial angle difference (this means any portal which isn't wall<->wall or floor<->ceiling), the game will choose one of two methods for correcting the player's angle - either a "quaternion punch" or an "up vector snap". The method used determines whether, after the portal transition, major decay will be present: if a quaternion punch is used, the decay will not happen, but if an up vector snap is used, it will.
+
Minor decay is always present when your pitch angle is within a couple of degrees from zero. Major decay, however, only manifests itself in certain cases. When passing through a portal with a non-trivial angle difference (this means any portal which isn't wall<->wall or floor<->ceiling), the game will choose one of two methods for correcting the player's angle - either a "quaternion punch" or an "up vector snap". The method used determines whether, after the portal transition, major decay will be present: if a quaternion punch is used, the decay will not happen, but if an up vector snap is used, it will.
  
 
Thus, to avoid major decay (important for e.g. certain seamshots), the transition needs to be performed in such a way that a quaternion punch is used. A consistent method of achieving this is to set your angle before the portal transition such that, after the transition, you will be looking approximately straight up.
 
Thus, to avoid major decay (important for e.g. certain seamshots), the transition needs to be performed in such a way that a quaternion punch is used. A consistent method of achieving this is to set your angle before the portal transition such that, after the transition, you will be looking approximately straight up.
Line 15: Line 17:
 
== Technical Explanation ==
 
== Technical Explanation ==
  
=== Minor Decay ===
+
Both minor and major angle decay are caused within the <code>C_Paint_Input::ApplyMouse</code> <ref>https://github.com/sabaasa/Portal-2-Paint-Gun-src/blob/d87746e8f626dee09ddf79ad24b3de8b1549edfe/client/c_paint_input.cpp#L69</ref> function - more specifically, the part responsible for pitch adjustment.
  
The cause of minor angle decay is currently not well understood.
+
In rare cases, like portal transition or using Adhesion Gel, your relative up direction does not match the global up direction. In order to properly handle view angle change with that relative orientation, a bunch of mathematical operations were included in <code>C_Paint_Input::ApplyMouse</code> to transform view angles into a local space determined by player's <code>m_PlayerLocal.m_Up</code> vector, and then back into global view angles. This transformation introduced a couple of individual issues from which both major and minor decays arose.  
  
 
=== Major Decay ===
 
=== Major Decay ===
Line 23: Line 25:
 
Major angle decay is caused by a floating-point error in the player's <code>m_PlayerLocal.m_Up</code> vector.
 
Major angle decay is caused by a floating-point error in the player's <code>m_PlayerLocal.m_Up</code> vector.
  
This field represents the up vector of the player's view as it is rotating after a portal transition which uses an up vector snap; it is set by <code>CPortal_Player::SnapCamera</code>, which is responsible for initiating the viewangle fixup after a portal passthrough. When a quaternion punch is used, <code>m_Up</code> is immediately set to the value of <code>m_vLocalUp</code>, which will always be exactly <code>0,0,1</code> (the field's existence is a remnant of Adhesion Gel code). However, when an up vector snap is used, <code>m_Up</code> is snapped to the value your current up vector corresponds to when translated across the portal, and is then decayed across the following ticks to <code>m_vLocalUp</code> by <code>CPortal_Player::RotateUpVector</code>.
+
This field represents the up vector of the player's view as it is rotating after a portal transition which uses an up vector snap; it is set by <code>CPortal_Player::SnapCamera</code>, which is responsible for initiating the viewangle fixup after a portal passthrough. When a quaternion punch is used, <code>m_Up</code> is immediately set to the value of <code>m_vLocalUp</code>, which will always be exactly <code>(0, 0, 1)</code> (the field's existence is a remnant of Adhesion Gel code). However, when an up vector snap is used, <code>m_Up</code> is snapped to the value your current up vector corresponds to when translated across the portal, and is then decayed across the following ticks to <code>m_vLocalUp</code> by <code>CPortal_Player::RotateUpVector</code>.
 +
 
 +
This method of setting <code>m_Up</code> raises an issue when <code>RotateUpVector</code> does not correctly decay the value to precisely <code>(0, 0, 1)</code>. In fact, it turns out that due to some floating point error in the calculations performed by this function (possibly the call to <code>vEndUp.NormalizeInPlace()</code>), this value ends up decaying to a vector of around <code>(0, 0, 0.9999999)</code>. This is the root cause of angle decay; the distance of this value from the expected one dictates how far the player's angle will decay every frame.
 +
 
 +
The actual decay comes from the dot product of the forward view vector and <code>m_Up</code>. For angles close to +/-90, the deviation from the expected value here is enough to cause the pitch angle to decay noticably, particularly on higher framerates.
 +
 
 +
=== Minor Decay ===
 +
 
 +
Minor angle decay is caused by inaccurate results of <code>acos</code> function.
  
This method of setting <code>m_Up</code> raises an issue when <code>RotateUpVector</code> does not correctly decay the value to precisely <code>0,0,1</code>. In fact, it turns out that due to some floating point error in the calculations performed by this function (possibly the call to <code>vEndUp.NormalizeInPlace()</code>), this value ends up decaying to a vector of around <code>0,0,0.9999999</code>. This is the root cause of angle decay; the distance of this value from the expected one dictates how far the player's angle will decay every frame.
+
When calculating local pitch angle, the game performs an arccosine on a dot product of the forward view vector and <code>m_Up</code>. Function used specifically on Windows to calculate an arccosine does not return accurate enough results, creating a noticeable error. This error dictates how much the player's angle will decay every frame.  
  
The actual decay comes from the <code>C_Paint_Input::ApplyMouse</code> function. This function tries to calculate mouse movement using the player's <code>m_Up</code> vector; specifically, the pitch adjustment code calculates the dot product of the forward view vector and <code>m_Up</code>. For angles close to +/-90, the deviation from the expected value here is enough to cause the pitch angle to decay noticably, particularly on higher framerates.
+
==Notes==
 +
<references/>

Latest revision as of 18:54, 15 December 2023

Angle Decay


Angle Decay is a glitch which causes player's pitch angle to slowly change over time without user input. This is normally not noticeable, but can present an issue when attempting to line up precise shots, in particular Seamshots (such as the one on Crazy Box).

There are two types of angle decay, each differing in occurence and speed:

  • major decay - decays the pitch angle towards 0 and is more prominent the further pitch angle is from 0.
  • minor decay - decays the pitch angle towards positive values. It's slower than major decay, occurs only within small range of pitch angle near 0, and occurs only on Windows version of the game.

Factors Affecting Decay

Both major and minor decay scale linearly with FPS (i.e. if you have 120FPS, your angle will decay twice as quickly as it would if you had 60FPS). Neither form of decay happens when the game is not fetching any user input (for instance, when tabbed out of the game, or with in_forceuser set to control a different player).

Minor decay is always present when your pitch angle is within a couple of degrees from zero. Major decay, however, only manifests itself in certain cases. When passing through a portal with a non-trivial angle difference (this means any portal which isn't wall<->wall or floor<->ceiling), the game will choose one of two methods for correcting the player's angle - either a "quaternion punch" or an "up vector snap". The method used determines whether, after the portal transition, major decay will be present: if a quaternion punch is used, the decay will not happen, but if an up vector snap is used, it will.

Thus, to avoid major decay (important for e.g. certain seamshots), the transition needs to be performed in such a way that a quaternion punch is used. A consistent method of achieving this is to set your angle before the portal transition such that, after the transition, you will be looking approximately straight up.

Technical Explanation

Both minor and major angle decay are caused within the C_Paint_Input::ApplyMouse [1] function - more specifically, the part responsible for pitch adjustment.

In rare cases, like portal transition or using Adhesion Gel, your relative up direction does not match the global up direction. In order to properly handle view angle change with that relative orientation, a bunch of mathematical operations were included in C_Paint_Input::ApplyMouse to transform view angles into a local space determined by player's m_PlayerLocal.m_Up vector, and then back into global view angles. This transformation introduced a couple of individual issues from which both major and minor decays arose.

Major Decay

Major angle decay is caused by a floating-point error in the player's m_PlayerLocal.m_Up vector.

This field represents the up vector of the player's view as it is rotating after a portal transition which uses an up vector snap; it is set by CPortal_Player::SnapCamera, which is responsible for initiating the viewangle fixup after a portal passthrough. When a quaternion punch is used, m_Up is immediately set to the value of m_vLocalUp, which will always be exactly (0, 0, 1) (the field's existence is a remnant of Adhesion Gel code). However, when an up vector snap is used, m_Up is snapped to the value your current up vector corresponds to when translated across the portal, and is then decayed across the following ticks to m_vLocalUp by CPortal_Player::RotateUpVector.

This method of setting m_Up raises an issue when RotateUpVector does not correctly decay the value to precisely (0, 0, 1). In fact, it turns out that due to some floating point error in the calculations performed by this function (possibly the call to vEndUp.NormalizeInPlace()), this value ends up decaying to a vector of around (0, 0, 0.9999999). This is the root cause of angle decay; the distance of this value from the expected one dictates how far the player's angle will decay every frame.

The actual decay comes from the dot product of the forward view vector and m_Up. For angles close to +/-90, the deviation from the expected value here is enough to cause the pitch angle to decay noticably, particularly on higher framerates.

Minor Decay

Minor angle decay is caused by inaccurate results of acos function.

When calculating local pitch angle, the game performs an arccosine on a dot product of the forward view vector and m_Up. Function used specifically on Windows to calculate an arccosine does not return accurate enough results, creating a noticeable error. This error dictates how much the player's angle will decay every frame.

Notes