0x00 背景
开发环境:win10 & unity2018.4.1f & unity5.4.6,本项目不使用HDR和抗锯齿。
项目上线了windows平台的项目(别问我为什么,咱也不敢说,咱也不敢问),由Unity5.4.6升级到Unity2018的过程中,遇到了各种各样的坑,本文为避坑指南1。由于查这几个问题查到吐血,前后用了3天的时间,本文充满了怨气,行文非常啰嗦,需要快速解决问题的,可以直接拉到最后看结论。
0x01 法线贴图
项目在unity2018出了新的android和IOS的包替换之后,想起来还有个windows平台还没有换包,同样的工程,Switch to PC,出包,然后噩梦就来了,QA反馈了新手引导战斗中一个特效变黑的问题。
查看这个特效的shader,发现计算法线的部分不规范
fixed4 frag(v2f i):COLOR
{
//Fragment Code
float4 col = tex2D(_MainTex, i.texcoord);
clip(col.a - 0.05);
float4 mask = tex2D(_MaskTex, i.texcoord);
float4 normalTex = tex2D(_NormalTex, i.texcoord);
float3 normalR = UnpackNormal(normalTex);
// 以下是原来计算法线的代码,推断是shaderforge之类的软件自动生成的,替换成unpacknormal之后显示即正常了
// float3 normalR = float3( 2.0 * normalTex.rg - 1.0, 0.0);
// normalR.z = sqrt(1 - pow(dot(normalR, normalR), 2.0));
0x02 Graphics设置
QA继续反馈,下图中的矩形区域中应该显示数码兽形象而不应该是黑色。本以为还是法线惹的祸,排查之后,发现这里并没有使用法线贴图。
翻来覆去,发现由于unity5.4.6升级到unity2018后,Graphics设置发生了变化,pc平台下的默认设置恢复成了default(下图左),项目原本的设置应该为下图右。
由于开启了HDR,颜色值的计算可能会超出[0,1]的范围,导致最终结果显示为黑色。关于HDR后续还会细说。
修改设置后,重新打包,进入游戏。It’s ok now!0x03 MSAA(多重采样抗锯齿)
QA继续反馈,进入副本会黑屏。我也很无奈…继续看问题:
然而通过FrameDebugger抓drawcall发现,图中黑屏的部分已经被正确渲染出来了,不知道被什么东西挡住了
drawcall1:
drawcall2:
陷
入
僵
局
。
。
。
后来看到这两篇文章:
https://forum.unity.com/threads/allow-hdr-creating-huge-decrease-in-performance.521483/https://forum.unity.com/threads/game-rendering-as-black-in-unity-2017-1-on-galaxy-s6-when-hdr-is-enabled.494102/
不由得又开始打HDR的主意,然而设置中已经关了HDR,哪里还会有呢?会不会是场景同学做的新场景的Camera中打开了HDR?于是写了个脚本查了一下,并没有。
然而却发现了一个新的嫌疑对象:MSAA,由于在设置中已经关闭了抗锯齿,可以看到下面有一行warning:告诉你,因为你关闭了抗锯齿,MSAA即使打开也没用。总觉得这里有种此地无银三百两的感觉呢?
为什么怀疑MSAA呢?我也不知道,也许就是男人的第六感吧!顺手google了一下MSAA和HDR:
https://issuetracker.unity3d.com/issues/lwrp-msaa-does-not-work-when-allow-hdr-is-disabled
没想到你竟然是这样的MSAA,居然会在HDR生效之后,才生效!!
然而,场景上的Camera并没有Allow HDR的啊,上面用脚本检查过了。
那么问题来了,什么时候MSAA和HDR才能在一起呢?
百思不得其解,于是又开始用FrameDebugger抓drawcall玩,看到这样的图景:
这分明是3个camera的绘制结果,然而场景中只有一个camera,别的camera哪来的?
这时突然反应过来,camera除了随场景创建之外,还有另一种情况,那就是代码动态创建!!!
在项目中搜索
AddComponent<Camera>()
看到了这些结果:
其中最醒目的必然是UICamera了(当前项目使用UICamera来渲染所有的2D UI)
在创建之后并没有MSAA和HDR的踪迹,难道是我的错觉?默认是false?空谈误国,实干兴邦!于是打印log查看,结果allowHDR和allowMSAA的默认值都是true.
我这里只想发黑人问号脸?Excuse me ??? 还有这样的操作?默认给开启HDR和MSAA,不可能的,我在Unity的设置中中已经关闭了,这里Camera默认值为true会生效吗?然而事实很残酷,是的,确实有效。绕过了Unity的设置。What the fuck?!!
不过好奇的我,不太明白为什么在老版本上(unity5.4.6)并没有这个问题,于是我发现:
好的,unity这一波操作真的是猛如虎!!我服了。
0x04 结论
- 检查场景中的Camera有没有同时开启HDR和MSAA,脚本拿去不谢。
[MenuItem("Assets/GameTools/检查所有的Camera", false, 10)]
static void CheckSceneCameraEnableHDRAndMSAA()
{
//找到所有的场景文件
string[] scenes = AssetDatabase.FindAssets("t:Scene", new string[] { "Assets/ArtContent/Scene" });
for (int i = 0; i < scenes.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(scenes[i]);
UnityEngine.SceneManagement.Scene scene = CheckSceneReference.GetScene(path);
GameObject[] gos = scene.GetRootGameObjects();
for (int j = 0; j < gos.Length; j++)
{
Camera cam = gos[j].GetComponentInChildren<Camera>();
if (cam != null && cam.allowHDR && cam.allowMSAA)
{
Debug.Log("CheckSceneCameraEnableHDRAndMSAA Find GameObjects: " + path + ", root_name: "+ gos[j].name);
}
}
}
}
- 检查所有动态添加Camera的脚本,有没有设置
m_UICam.allowHDR = false;
m_UICam.allowMSAA = false;