Unity 版本:
2021.2/china_support/instantgame/staging 8bd2ddd0516e
问题:
使用 Addressable 加载的场景中,UI 的纹理没有丢失,但是其他 GameObject 中的 Sprite Renderer 的材质纹理丢失了,提示如图
Material does not have a _MainTex texture property. It is required for SpriteRenderer.
但是在监视器中看这个 Sprite Renderer 组件,很显然的是,这个组件的 Sprite 属性是有值的
然后在监视器中更换这个物体的材质,随便换任何一个其他材质,都不会再弹出找不到纹理的警告
然后再换回原来的材质,发现它也是能够找到纹理的
这个错误具体的表现就是,物体 A B C 用的材质 M1,物体 D E F 用的材质 M2,M1 和 M2 在场景加载之后都说找不到纹理,物体 A B C D E F 都是洋红;然后从 A B C 中任选一个物体,将它的材质从 M1 换到别的材质再换回来,物体 A B C 就会恢复正常,物体 D E F 不变,还是洋红;然后从 D E F 中任选一个物体,将它的材质从 M2 换到别的材质再换回来,物体 D E F 就会恢复正常
不论材质 M1 M2 是自定义的着色器还是 Unity 的默认着色器,比如 Sprite/Default,都会有这个问题
即使假设通过在编辑器里来回更换材质的方式,让材质从洋红恢复成正常了,也会有个问题是,换回来之后,自定义的着色器会出错,而 Unity 的默认着色器,比如 Sprite/Default,不会再出错
就非常神奇
并且只在 AA 包的 WebGL 构建中会出现这个 bug,在 Use Asset Database 和 Simulate Groups 模式都不会有问题
失败的尝试 1
感觉是因为材质是使用 Instance 的形式加载的,所以一个材质 Instance 会控制所有使用这个材质的物体
然后我猜可能是因为材质 Instance 在加载的时候可能是比纹理加载得更早,所以材质 Instance 初始化的时候找不到纹理,就变洋红了。之后我在编辑器中操作的话,这个时候纹理也早就加载完了,所以我再更换材质,新材质初始化的时候就能找到纹理了
于是我做了一些测试
测试 1
protected void Start()
{
StartCoroutine(TestCo());
}
private IEnumerator TestCo()
{
yield return new WaitForEndOfFrame();
Debug.Log("!!!!!!!!!!!!");
Shader oldSha = spriteRenderer.material.shader;
spriteRenderer.material = new Material(oldSha);
}
结果:
在执行完 spriteRenderer.material = new Material(oldSha); 之后,依然有找到主纹理的警告消失,材质依然是洋红
测试 2
protected void Start()
{
StartCoroutine(TestCo());
}
private IEnumerator TestCo()
{
yield return new WaitForSeconds(3f);
Debug.Log("!!!!!!!!!!!!");
spriteRenderer.material.SetTexture("_MainTex", spriteRenderer.sprite.texture);
}
结果:
在执行完 SetTexture 之后,提示没有找到主纹理的警告消失,但是材质依然是洋红
测试 3:
protected void Start()
{
StartCoroutine(TestCo());
}
private IEnumerator TestCo()
{
yield return new WaitForEndOfFrame();
Debug.Log("!!!!!!!!!!!!");
Shader oldSha = spriteRenderer.material.shader;
spriteRenderer.material = new Material(oldSha);
spriteRenderer.material.SetTexture("_MainTex", spriteRenderer.sprite.texture);
}
结果:
在执行完 SetTexture 之后,提示没有找到主纹理的警告消失,但是材质依然是洋红
测试 4:
protected void Start()
{
StartCoroutine(TestCo());
}
private IEnumerator TestCo()
{
yield return new WaitForEndOfFrame();
Debug.Log("!!!!!!!!!!!!");
spriteRenderer.material.SetTexture("_MainTex", spriteRenderer.sprite.texture);
Shader oldSha = spriteRenderer.material.shader;
spriteRenderer.material = new Material(oldSha);
}
结果:
在执行完 SetTexture 之后,依然有找到主纹理的警告消失,材质依然是洋红
这都不行的话,只能说明我的假设有问题
我想想,AA 是基于 AB 的,而 AB 里面一个常见的操作就是先加载一个包的依赖包,再加载这个包
于是我觉得确实应该和资源加载顺序无关把……?
搜帖子
这个人具体指的是 UnityWebRequest.GetTexture() 无法正常工作,跟我的稍微有点不一样,并且他也没有得到回答
这里说把 Auto Graphics APIs 切换成 false,或者为 true 但是 lightmap quality = low
我都试过了,没有效果
失败的尝试 2
看到一个人说是在 build 的时候有问题
然后说是因为 #include "UnityCG.cginc" 导致的问题
我不用 build,我就把我的着色器改了一下
以前:
Shader "Unlit/UnlitGrid"
{
Properties
{
[PerRendererData] _MainTex ("Texture", 2D) = "white" {}
_MainTexScale ("Main Texture Scale", float) = 1
_GridSize ("Grid Size", float) = 1
[FloatRange] _GridLineSize ("Grid Line Size", Range(0, 1)) = 0.02
_LineColor ("Line Color", Color) = (0.7, 0.7, 0.7, 1)
_ReachableTint ("Reachable Tint", Color) = (0.9, 0.9, 0.9, 1)
_UnreachableTint ("Unreachable Tint", Color) = (0.6, 0.6, 0.6, 1)
_TintCenter("Tint Center", Vector) = (0, 0, 0, 0)
_TintRadius("Tint Radius", float) = 1
_TintPower("Tint Power", float) = 0
_TintSpreadTime("Tint Spread Time", float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float4 worldSpacePos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _MainTexScale;
float _GridSize;
float _GridLineSize;
float4 _LineColor;
float4 _ReachableTint;
float4 _UnreachableTint;
vector _TintCenter;
float _TintRadius;
float _TintPower;
float _TintSpreadTime;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
o.worldSpacePos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 add_tint(fixed4 col, float2 ipos, float2 fpos)
{
float itime = floor(_TintSpreadTime); // integer time
float ftime = frac(_TintSpreadTime); // fraction time
float2 tint_center_to_ipos = ipos - floor(_TintCenter/_GridSize);
float dist_tint_center_to_ipos = abs(tint_center_to_ipos.x) + abs(tint_center_to_ipos.y);
float stationary_reachable = step(dist_tint_center_to_ipos, itime + 0.001);
float spreading_reachable = step(dist_tint_center_to_ipos, itime + 1.001) - step(dist_tint_center_to_ipos, itime + 0.001);
// move
float2 move_dir = tint_center_to_ipos/(length(tint_center_to_ipos) + 0.1f);
float2 tint_grid_center = float2(0.5, 0.5) - move_dir * (0.5f - ftime/2.0);
// scale
float2 fpos_to_grid_center = fpos - tint_grid_center;
float dist_fpos_to_grid_center = max(abs(fpos_to_grid_center.x), abs(fpos_to_grid_center.y));
spreading_reachable *= step(dist_fpos_to_grid_center, ftime/2.0);
// add tint
float radius_reachable = step(dist_tint_center_to_ipos, _TintRadius + 0.001);
float reachable = (stationary_reachable + spreading_reachable) * radius_reachable;
fixed4 tint = col * _UnreachableTint * (1.0 - reachable) + col * _ReachableTint * reachable;
return lerp(col, tint, _TintPower);
}
fixed4 add_grid(fixed4 col, float2 fpos)
{
float scaled_line_size = _GridLineSize/_GridSize;
float2 bl = step(float2(scaled_line_size, scaled_line_size), fpos); // bottom-left
float2 tr = step(float2(scaled_line_size, scaled_line_size), float2(1.0, 1.0) - fpos); // top-right
float grid_brightness = 1.0 - bl.x * bl.y * tr.x * tr.y;
col = col * (1.0 - grid_brightness) + _LineColor * grid_brightness;
return col;
}
fixed4 frag (v2f i) : SV_Target
{
float2 st = i.worldSpacePos.xy / _GridSize;
float2 st_world = i.worldSpacePos.xy/_MainTexScale;
float2 ipos = floor(st); // integer
float2 fpos = frac(st); // fraction
fixed4 col = tex2D(_MainTex, st_world);
col = add_tint(col, ipos, fpos);
col = add_grid(col, fpos);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
现在,把 #include "UnityCG.cginc" 给去掉了:
Shader "Unlit/UnlitGrid"
{
Properties
{
[PerRendererData] _MainTex ("Texture", 2D) = "white" {}
_MainTexScale ("Main Texture Scale", float) = 1
_GridSize ("Grid Size", float) = 1
[FloatRange] _GridLineSize ("Grid Line Size", Range(0, 1)) = 0.02
_LineColor ("Line Color", Color) = (0.7, 0.7, 0.7, 1)
_ReachableTint ("Reachable Tint", Color) = (0.9, 0.9, 0.9, 1)
_UnreachableTint ("Unreachable Tint", Color) = (0.6, 0.6, 0.6, 1)
_TintCenter("Tint Center", Vector) = (0, 0, 0, 0)
_TintRadius("Tint Radius", float) = 1
_TintPower("Tint Power", float) = 0
_TintSpreadTime("Tint Spread Time", float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 worldSpacePos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _MainTexScale;
float _GridSize;
float _GridLineSize;
float4 _LineColor;
float4 _ReachableTint;
float4 _UnreachableTint;
vector _TintCenter;
float _TintRadius;
float _TintPower;
float _TintSpreadTime;
#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldSpacePos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 add_tint(fixed4 col, float2 ipos, float2 fpos)
{
float itime = floor(_TintSpreadTime); // integer time
float ftime = frac(_TintSpreadTime); // fraction time
float2 tint_center_to_ipos = ipos - floor(_TintCenter/_GridSize);
float dist_tint_center_to_ipos = abs(tint_center_to_ipos.x) + abs(tint_center_to_ipos.y);
float stationary_reachable = step(dist_tint_center_to_ipos, itime + 0.001);
float spreading_reachable = step(dist_tint_center_to_ipos, itime + 1.001) - step(dist_tint_center_to_ipos, itime + 0.001);
// move
float2 move_dir = tint_center_to_ipos/(length(tint_center_to_ipos) + 0.1f);
float2 tint_grid_center = float2(0.5, 0.5) - move_dir * (0.5f - ftime/2.0);
// scale
float2 fpos_to_grid_center = fpos - tint_grid_center;
float dist_fpos_to_grid_center = max(abs(fpos_to_grid_center.x), abs(fpos_to_grid_center.y));
spreading_reachable *= step(dist_fpos_to_grid_center, ftime/2.0);
// add tint
float radius_reachable = step(dist_tint_center_to_ipos, _TintRadius + 0.001);
float reachable = (stationary_reachable + spreading_reachable) * radius_reachable;
fixed4 tint = col * _UnreachableTint * (1.0 - reachable) + col * _ReachableTint * reachable;
return lerp(col, tint, _TintPower);
}
fixed4 add_grid(fixed4 col, float2 fpos)
{
float scaled_line_size = _GridLineSize/_GridSize;
float2 bl = step(float2(scaled_line_size, scaled_line_size), fpos); // bottom-left
float2 tr = step(float2(scaled_line_size, scaled_line_size), float2(1.0, 1.0) - fpos); // top-right
float grid_brightness = 1.0 - bl.x * bl.y * tr.x * tr.y;
col = col * (1.0 - grid_brightness) + _LineColor * grid_brightness;
return col;
}
fixed4 frag (v2f i) : SV_Target
{
float2 st = i.worldSpacePos.xy / _GridSize;
float2 st_world = i.worldSpacePos.xy/_MainTexScale;
float2 ipos = floor(st); // integer
float2 fpos = frac(st); // fraction
fixed4 col = tex2D(_MainTex, st_world);
col = add_tint(col, ipos, fpos);
col = add_grid(col, fpos);
return col;
}
ENDCG
}
}
}
对结果还是没有影响,还是洋红
尝试把出错的物体不用 Addressable 加载场景,而是加载预制体
然后我尝试不把出错的物体放在场景中,而是放在预制体中,然后等到场景加载的时候再加载这个物体,还是不行
尝试将 Shader 加入 Include Shader
看到别人都在说要将 Shader 加入 Include Shader 否则打包的时候识别不到 Shader,就可能包里面没有 Shader
stackoverflow.com/questions/4…
我试了一下,也没有解决我的问题
解决方法:使用 Shader.Find()
使用 #14 的脚本解决了问题……就是 Unity 的问题,解决方法真的很 hacky,从材质那里获得 Shader 的名字,根据这个名字再找一遍 Shader 赋回给材质 Shader.Find 是在构建的工程中寻找的,所以这至少说明资源是成功加载的……?或者像这个帖子所说的一样,在打包的时候会向目标平台构建着色器,但是实际上在设置着色器的时候就会有问题……?不懂,真是天坑
对于我来说,就是:
protected void Start()
{
Material mat = spriteRenderer.material;
mat.shader = Shader.Find(mat.shader.name);
}