我们知道华为手机是自研内核,其GPU的算法不清楚是否与正常的骁龙内核相同,我们项目场景里面水面shader在普通手机上显示正常,但是在华为的手机里面,shader却会出错。后来,经过对此shader各种计算的逻辑,最终找到了问题所在,shader深度计算在华为手机有可能出错。
================================================================================================
对比:
首先,正常的设备效果(可以看到这是个深水)
然后,这是华为手机的效果
看效果,一层叠一层,猜测要么是渐变纹理出错,要么是深度计算出错。
-----------------------------------------------------------------------------------------------------------------------------------------------------
下面我们看一下这个shader:
Shader "Water/SeaWave" {
Properties {
_WaterTex ("WaterTex", 2D) = "black" {}
_BumpTex ("BumpTex", 2D) = "bump" {}
_GTex ("Gradient", 2D) = "white" {} //海水渐变
_WaterSpeed ("WaterSpeed", float) = 0.74 //海水速度
_NoiseRange ("NoiseRange", float) = 6.43
_Refract ("Refract", float) = 0.07
_Specular ("Specular", float) = 1.86
_Gloss ("Gloss", float) = 0.71
_SpecColor ("SpecColor", color) = (1, 1, 1, 1)
_Range ("Range", vector) = (0.13, 1.53, 0.37, 0.78)
}
CGINCLUDE
fixed4 LightingWaterLight(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) {
half3 halfVector = normalize(lightDir + viewDir);
float diffFactor = max(0, dot(lightDir, s.Normal)) * 0.8 + 0.2;
float nh = max(0, dot(halfVector, s.Normal));
float spec = pow(nh, s.Specular * 128.0) * s.Gloss;
fixed4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diffFactor + _SpecColor.rgb * spec * _LightColor0.rgb) * (atten);
c.a = s.Alpha + spec * _SpecColor.a;
return c;
}
ENDCG
SubShader {
Tags { "RenderType"="Transparent" "Queue"="Transparent"}
LOD 200
GrabPass{}
zwrite off
CGPROGRAM
#pragma surface surf WaterLight vertex:vert alpha noshadow
#pragma target 3.0
sampler2D _GTex;
sampler2D _WaterTex;
sampler2D _BumpTex;
sampler2D _CameraDepthTexture;
sampler2D _GrabTexture;
half4 _GrabTexture_TexelSize;
float4 _Range;
half _WaterSpeed;
fixed _Refract;
half _Specular;
fixed _Gloss;
half _NoiseRange;
float4 _WaterTex_TexelSize;
struct Input {
float2 uv_WaterTex;
float4 proj;
float3 viewDir;
};
void vert (inout appdata_full v, out Input i) {
UNITY_INITIALIZE_OUTPUT(Input, i);
i.proj = ComputeScreenPos(UnityObjectToClipPos(v.vertex));
COMPUTE_EYEDEPTH(i.proj.z);
}
void surf (Input IN, inout SurfaceOutput o) {
float2 uv = IN.proj.xy/IN.proj.w;
#if UNITY_UV_STARTS_AT_TOP
if(_WaterTex_TexelSize.y<0)
uv.y = 1 - uv.y;
#endif
fixed4 water = (tex2D(_WaterTex, IN.uv_WaterTex + float2(_WaterSpeed*_Time.x,0))+tex2D(_WaterTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x) + float2(_WaterSpeed*_Time.x,0)))/2;
float4 offsetColor = (tex2D(_BumpTex, IN.uv_WaterTex + float2(_WaterSpeed*_Time.x,0))+tex2D(_BumpTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x) + float2(_WaterSpeed*_Time.x,0)))/2;
half2 offset = UnpackNormal(offsetColor).xy * _Refract;
half m_depth = LinearEyeDepth(tex2Dproj (_CameraDepthTexture, IN.proj).r);
half deltaDepth = m_depth - IN.proj.z;
half4 bott = tex2D(_GrabTexture, uv+offset);
fixed4 waterColor = tex2D(_GTex, float2(min(_Range.y, deltaDepth)/_Range.y,1));
half water_A = 1-min(_Range.z, deltaDepth)/_Range.z;
half water_B = min(_Range.w, deltaDepth)/_Range.w;
float4 bumpColor = (tex2D(_BumpTex, IN.uv_WaterTex+offset + float2(_WaterSpeed*_Time.x,0))+tex2D(_BumpTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x)+offset + float2(_WaterSpeed*_Time.x,0)))/2;
o.Normal = UnpackNormal(bumpColor).xyz;
o.Specular = _Specular;
o.Gloss = _Gloss;
o.Albedo = bott.rgb * (1 - water_B) + waterColor.rgb * water_B;
o.Albedo = o.Albedo * (1 - water.a*water_A) + water.rgb * water.a*water_A;
o.Alpha = min(_Range.x, deltaDepth)/_Range.x;
}
ENDCG
}
}
可以看到这是个深度水。
处理办法:删掉不同的计算,然后打包看效果(虽然蠢但是找不到更好的办法)
后来去掉了根据深度进行透明值处理:
Shader "Water/SeaWave" {
Properties {
_WaterTex ("WaterTex", 2D) = "black" {}
_BumpTex ("BumpTex", 2D) = "bump" {}
_GTex ("Gradient", 2D) = "white" {} //海水渐变
_WaterSpeed ("WaterSpeed", float) = 0.74 //海水速度
_Refract ("Refract", float) = 0.07
_Specular ("Specular", float) = 1.86
_Gloss ("Gloss", float) = 0.71
_SpecColor ("SpecColor", color) = (1, 1, 1, 1)
_Range ("Range", vector) = (0.13, 1.53, 0.37, 0.78)
}
CGINCLUDE
fixed4 LightingWaterLight(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) {
half3 halfVector = normalize(lightDir + viewDir);
float diffFactor = max(0, dot(lightDir, s.Normal)) * 0.8 + 0.2;
float nh = max(0, dot(halfVector, s.Normal));
float spec = pow(nh, s.Specular * 128.0) * s.Gloss;
fixed4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diffFactor + _SpecColor.rgb * spec * _LightColor0.rgb) * (atten);
c.a = s.Alpha + spec * _SpecColor.a;
return c;
}
ENDCG
SubShader {
Tags { "RenderType"="Transparent" "Queue"="Transparent"}
LOD 200
GrabPass{}
zwrite off
CGPROGRAM
#pragma surface surf WaterLight vertex:vert alpha noshadow
#pragma target 3.0
sampler2D _GTex;
sampler2D _WaterTex;
sampler2D _BumpTex;
sampler2D _GrabTexture;
half4 _GrabTexture_TexelSize;
float4 _Range;
half _WaterSpeed;
fixed _Refract;
half _Specular;
fixed _Gloss;
float4 _WaterTex_TexelSize;
struct Input {
float2 uv_WaterTex;
float4 proj;
float3 viewDir;
};
void vert (inout appdata_full v, out Input i) {
UNITY_INITIALIZE_OUTPUT(Input, i);
i.proj = ComputeScreenPos(UnityObjectToClipPos(v.vertex));
}
void surf (Input IN, inout SurfaceOutput o) {
float2 uv = IN.proj.xy/IN.proj.w;
fixed4 water = (tex2D(_WaterTex, IN.uv_WaterTex + float2(_WaterSpeed*_Time.x,0))+tex2D(_WaterTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x) + float2(_WaterSpeed*_Time.x,0)))/2;
float4 offsetColor = (tex2D(_BumpTex, IN.uv_WaterTex + float2(_WaterSpeed*_Time.x,0))+tex2D(_BumpTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x) + float2(_WaterSpeed*_Time.x,0)))/2;
half2 offset = UnpackNormal(offsetColor).xy * _Refract;
half4 bott = tex2D(_GrabTexture, uv+offset);
fixed4 waterColor = tex2D(_GTex, float2(_Range.y,1));
float4 bumpColor = (tex2D(_BumpTex, IN.uv_WaterTex+offset + float2(_WaterSpeed*_Time.x,0))+tex2D(_BumpTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x)+offset + float2(_WaterSpeed*_Time.x,0)))/2;
o.Normal = UnpackNormal(bumpColor).xyz;
o.Specular = _Specular;
o.Gloss = _Gloss;
o.Albedo = bott.rgb + waterColor.rgb;
o.Albedo = o.Albedo * (1 - water.a) + water.rgb * water.a;
o.Alpha = _Range.x;
}
ENDCG
}
//FallBack "Diffuse"
}
打包,效果图如下:
没错了!(当然效果也差了许多,但是节约性能了,效果差就甩给美术吧)
得出结论,深度测试在华为设备上可能出错。
而且强烈建议在设备上不要使用深度的计算,性能节省一点是一点。
要是非要使用深度水,这里有个链接模拟深水 https://blog.youkuaiyun.com/baicaishisan/article/details/79061739