ue上 sceneColorMobile 在android 和ios上表现不同的问题
遇到个比较奇特的问题
一个值 (4.2,0,0) 在ios上和android都在sceneColorMobile写入这个值
ios mobile采样的时候这个值就变成1.8
android PC MAC是不变的
msaa resolve的问题 和msaaresolve无关 有关 从定义宏的方式 和 判断方式可以确认是有关的 也能解释为什么 drawcall中间没有什么设置但rtv和srv的值不一样
METAL_MSAA_HDR_DECODE
倾向是 ios上特殊encode的值不一样 要处理
SceneColor.rgb *= rcp(SceneColor.r*(-0.299)+SceneColor.g*(-0.587)+SceneColor*(-0.114)+1.0);
这是个颜色空间的亮度转换
1.86/(1-1.86x0.299) =4.196
经验证确实如此
//The input scene color has been encoded to non-linear space and needs to decode somewhere if MSAA enabled on Metal platform
bool bMetalMSAAHDRDecode = GSupportsShaderFramebufferFetch && IsMetalMobilePlatform(View.GetShaderPlatform()) && CVarMobileMSAA && CVarMobileMSAA->GetValueOnRenderThread() > 1;
这地方值的变化乍看很像srgb的转换 但因为sceneColorMObile 是rgba16float是不会有srgb格式的rt的 也没有shader里的转换
这样理解好一些 是linear相关的转换 功能上 但encode估计是在msaa resolve的时候做的 这比较能解释的通
哇我好厉害(因为不用一个小时就修出来了,因为ue处理了这件事)
这是spce里的srgb的转换公式 所以注释里说的 linear肯定不是gamma到linear的转换
那三个dot的值 明显是亮度值的转换
目前看还是比较倾向在 msaa resolve 做了这步encode
encode我大概找到了 就是这个
//
// Pre-tonemap before hardware box-filtered resolve.
//
void PreTonemapMSAA_ES2(
float4 InUVPos : TEXCOORD0,
out half4 OutColor : SV_Target0
)
{
#if (COMPILER_GLSL_ES3_1) || (METAL_PROFILE && !MAC)
// On-chip pre-tonemap before MSAA resolve.
OutColor = FramebufferFetchES2();
OutColor.rgb *= rcp(OutColor.r*0.299 + OutColor.g*0.587 + OutColor.b*0.114 + 1.0);
#endif
}
Texture2D InputTexture;
SamplerState InputSampler;
void MSAADecodeAndCopyRectPS(
noperspective float4 UVAndScreenPos : TEXCOORD0,
out half4 OutColor : SV_Target0
)
{
#if (METAL_PROFILE && !MAC)
float2 UV = UVAndScreenPos.xy;
OutColor = Texture2DSample(InputTexture, InputSampler, UV);
OutColor.rgb *= rcp(OutColor.r*(-0.299) + OutColor.g*(-0.587) + OutColor.b*(-0.114) + 1.0);
#endif
}
这段就是encode 和对应的decode了 确实像之前推断的那样在 resolve msaa之前
encode 4.2-1.8
4.2/(4.2x0.299+1) = 1.86
decode
1.86/(1-1.86x0.299) = 4.196
x /(1+x) = y encode
x = y + xy
x - xy = y
x(1-y) = y
x = y/(1-y) decode
完全理清
然后 为什么这样做呢
hdr rgba16float 的rt 里的值可以是特别大比如100 用y = x/(1+x)映射到0-1做msaa 得到的msaa resolve值 更合理 下面是例子
感谢JIN
接下来的问题是ue上 ios和android 的实现流程
ios肯定是上面的流程
android看上去没encode 也没decode 所以推测如果值很大 锯齿会特别明显 可以测下ue下android windows 和 mac应该都会这样
MaterialTemplate.ush
#if POST_PROCESS_MATERIAL MaterialFloat4 Input0 = Texture2DSample(PostProcessInput_0_Texture, PostProcessInput_0_SharedSampler, UV); #if POST_PROCESS_MATERIAL_BEFORE_TONEMAP #if METAL_PROFILE // Decode the input color since the color is encoded for MSAA // The decode instructions might be able to skip with dynamic branch if (bMetalMSAAHDRDecode) { Input0.rgb = Input0.rgb * rcp(Input0.r*(-0.299) + Input0.g*(-0.587) + Input0.b*(-0.114) + 1.0); } #endif #endif // We need to preserve original SceneColor Alpha as it's used by tonemapper on mobile Parameters.BackupSceneColorAlpha = Input0.a; return Input0; #endif// POST_PROCESS_MATERIAL