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

  

原文地址:https://www.cnblogs.com/minggoddess/p/13957809.html