# 游戏人生

• Posts - 147
• Stories - 1

## [工作积累] UE4 TAA ReProjection的精度处理

TAA用到的Velocity和抖动对精度要求比较高， 特别是大场景下误差容易比较大，UE4做了一系列的处理来保持精度。

投影矩阵的精度

 1     static const FMatrix InvertProjectionMatrix( const FMatrix& M )
2     {
3         if( M.M[1][0] == 0.0f &&
4             M.M[3][0] == 0.0f &&
5             M.M[0][1] == 0.0f &&
6             M.M[3][1] == 0.0f &&
7             M.M[0][2] == 0.0f &&
8             M.M[1][2] == 0.0f &&
9             M.M[0][3] == 0.0f &&
10             M.M[1][3] == 0.0f &&
11             M.M[2][3] == 1.0f &&
12             M.M[3][3] == 0.0f )
13         {
14             // Solve the common case directly with very high precision.
15             /*
16             M =
17             | a | 0 | 0 | 0 |
18             | 0 | b | 0 | 0 |
19             | s | t | c | 1 |
20             | 0 | 0 | d | 0 |
21             */
22
23             double a = M.M[0][0];
24             double b = M.M[1][1];
25             double c = M.M[2][2];
26             double d = M.M[3][2];
27             double s = M.M[2][0];
28             double t = M.M[2][1];
29
30             return FMatrix(
31                 FPlane( 1.0 / a, 0.0f, 0.0f, 0.0f ),
32                 FPlane( 0.0f, 1.0 / b, 0.0f, 0.0f ),
33                 FPlane( 0.0f, 0.0f, 0.0f, 1.0 / d ),
34                 FPlane( -s/a, -t/b, 1.0f, -c/d )
35             );
36         }
37         else
38         {
39             return M.Inverse();
40         }
41     }

1     FVector DeltaTranslation = InPrevViewMatrices.GetPreViewTranslation() - InViewMatrices.GetPreViewTranslation();
2     FMatrix InvViewProj = InViewMatrices.ComputeInvProjectionNoAAMatrix() * InViewMatrices.GetTranslatedViewMatrix().GetTransposed();
3     FMatrix PrevViewProj = FTranslationMatrix(DeltaTranslation) * InPrevViewMatrices.GetTranslatedViewMatrix() * InPrevViewMatrices.ComputeProjectionNoAAMatrix();
4
5     ViewUniformShaderParameters.ClipToPrevClip = InvViewProj * PrevViewProj;

Reprojection是把当前帧Clip space或NDC space的点重新投影到上一帧的位置

Reprojection = (V*P)-1 * (PrevV*PrevP)

=  P-1 * V-1 * PrevV * PrevP

Reprojection = P-1 * (T*R)-1 * (PrevT*PrevR) * prevP

= P-1 * R-1 * T-1 * PrevT * PrevR * PrevP

= P-1 * R-1 * (T-1 * PrevT) * PrevR * PrevP

R是ViewMatrix的旋转部分（UE4代码中的GetTranslatedViewMatrix），
T是ViewMatrix的位移部分，

T-1*PrevT 就是UE4代码中的 FTranslationMatrix(DeltaTranslation) 。

VelocityBuffer的精度

 1 // for velocity rendering, motionblur and temporal AA
2 // velocity needs to support -2..2 screen space range for x and y
3 // texture is 16bit 0..1 range per channel
4 float2 EncodeVelocityToTexture(float2 In)
5 {
6     // 0.499f is a value smaller than 0.5f to avoid using the full range to use the clear color (0,0) as special value
7     // 0.5f to allow for a range of -2..2 instead of -1..1 for really fast motions for temporal AA
8     return In * (0.499f * 0.5f) + 32767.0f / 65535.0f;
9 }
10 // see EncodeVelocityToTexture()
11 float2 DecodeVelocityFromTexture(float2 In)
12 {
13     const float InvDiv = 1.0f / (0.499f * 0.5f);
14     // reference
15 //    return (In - 32767.0f / 65535.0f ) / (0.499f * 0.5f);
16     // MAD layout to help compiler
17     return In * InvDiv - 32767.0f / 65535.0f * InvDiv;
18 }

VelocityBuffer在TAA里用来reproject移动的物体，包括蒙皮动画和位移旋转动画等。

posted on 2017-07-21 23:11  crazii  阅读(...)  评论(... 编辑 收藏