unity的优点之一是强大的跨平台性,本篇文章给出了一些常见的因为平台不同而造成的差异。
之前提到过OPenGL和DirectX的屏幕空间坐标的差异。在水平方向上,两者的数值变化方向是相同的,但在竖直方向上,两者是相反的。在OpenGL中,(0,0)点对应了屏幕的左下角,而在DirectX中,(0,0)点对应了左上角。
需要注意的是,我们不仅可以把渲染结果输出到屏幕上,还可以输出到不同的渲染目标中,这时我们需要使用渲染纹理(Render Texture)来保存这些渲染结果。
大多数情况下,这样的差异并不会造成什么影响,但当需要使用渲染到纹理技术,把屏幕图像渲染到一张纹理中时,如果不采取任何措施,就会出现纹理翻转的情况。幸运的是unity在背后为我们处理了这种翻转问题——当在DirectX平台上使用渲染到纹理技术时,unity会为我们翻转屏幕图像纹理,以便在不同平台达到一致性。
在一种特殊的情况下unity不会为我们进行这个翻转操作,就是开启了抗锯齿(在Edit->Project Settings->Quality->Anti Aliasing中开启)并在此时使用了渲染到纹理技术。在这种情况下,unity首先渲染得到屏幕图像,再由硬件进行抗锯齿处理后,得到一张渲染纹理供我们进行后续处理。此时得到的输入屏幕图像并不会被unity翻转,也就是说此时对屏幕图像的采样坐标是需要符合DirectX平台规定的。如果我们的屏幕特效只需要处理一张渲染图像,我们仍然不需要在意纹理的翻转问题,这是因为我们调用Graphics.Blit函数时,unity已经为我们对屏幕图像的采样坐标进行了处理,我们只需要按正常的采样过程处理屏幕图像即可。但如果同时需要处理多张渲染图像(前提是开启了抗锯齿),例如需要同时处理屏幕图像和法线纹理,这些图像的竖直方向的朝向可能是不同的(只有在DirectX这样的平台上才有这样的问题)。这种时候,我们就需要在顶点着色器中翻转某些渲染纹理(例如深度纹理或其他由脚本传递过来的纹理)的纵坐标,使之都符合DirectX平台的规则。例如:
其中UNITY_UV_STARTS_AT_TOP用于判断当前平台是否是DirectX类型的平台,而当在这样的平台下开启了抗锯齿后,主纹理的纹素大小在竖直方向上会变成负值,以方便我们对主纹理进行正常的采样。因此我们可以通过判断_MainTex_TexelSize是否小于0来检验是否开启了抗锯齿。如果是,我们就需要对除主纹理外的其他纹理的采样坐标进行竖直方向上的翻转。
我们在Windows平台下编译某些在Mac平台下工作良好的shader时,可能会看到类似下面的报错信息:
上面的报错信息都是因为DirectX9/11对shader的语义更加严格造成的。例如造成第一个报错信息的原因是,shader中可能存在下面这样的代码:
float4 v=float4(0.0);
在OpenGL平台上,上面的代码是合法的,他将得到一个4个分量都是0.0的float4类型的变量,但在DirectX 11平台式,我们必须提供和变量类型相匹配的参数数目。
面对第二个报错信息,往往出现在表面着色器中的顶点函数有一个使用了out修饰符的参数。如果出现这样的报错信息,可能因为在顶点函数中没有对这个参数的所有成员变量都进行初始化。应该使用类似下面的代码对这些参数进行初始化:
除了上述两点语义不同外,DirectX 9/11也不支持在顶点着色器使用tex2D函数。tex2D是一个对纹理进行采样的函数,之所以不支持,因为顶点着色器阶段shader无法得到uv偏导,而tex2D函数需要这样的偏导信息(和纹理采样时使用的数学运算有关)。如果我们的确需要在顶点着色器中访问纹理,需要使用tex2Dlod函数来代替,如:
tex2Dlod(tex,float4(uv,0,0));
而且还需要添加#pragma target 3.0,因为tex2Dlod是shader model 3.0中的特性。
前面说过一些语义在某些平台下是等价的,例如SV_POSITION和POSITION。但在另一些平台上,这些语义是不等价的。为了让shader能够在所有平台正常工作,应该尽可能使用下面的语义描述shader的输入输出变量。
使用SV_POSITION描述顶点着色器输出的顶点位置。一些shader使用了POSITION语义,而这些shader无法在索尼PS4平台上或使用了细分着色器的情况下正常工作。
使用SV_Target来描述片元着色器的输出颜色,一些shader使用了COLOR或者COLOR0语义,同样这些shader无法在索尼PS4正常工作。
上面只给出一些最常见的平台差异造成的问题,如果发现shader在平台A下工作良好,在平台B下出现了问题,可以去unity官方文档找资料(http://docs.unity3d.com/Manual/SL-PlatformDifferences.html)中寻找更多资料。