[unity] 5.5.2 Standard Specular shader 真机上代码调整半透明无效问题。

来源:互联网 发布:数据库管理员考试 编辑:程序博客网 时间:2024/06/08 08:03


项目需要,角色进入草丛要半透明。 已用了 untiy 自带shader (Standard Specular)的Fade 模式。  用代码电脑上调试没问题,结果上了真机就无法半透明。

原因是 unity打包时只会打 shader 被引用到的变体。 如果代码里调用 EnableKeyword 来开关宏, 如果对应的变体没有,则就不起作用了。。。


先附上 调整透明代码:

    public enum BlendMode    {        Opaque,        Cutout,        Fade,       // Old school alpha-blending mode, fresnel does not affect amount of transparency        Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply    }    public static BlendMode GetMaterialWithBlendMode(Material material)    {        if (material.IsKeywordEnabled("_ALPHATEST_ON"))        {            return BlendMode.Cutout;        }        if (material.IsKeywordEnabled("_ALPHABLEND_ON"))        {            return BlendMode.Fade;        }        if (material.IsKeywordEnabled("_ALPHAPREMULTIPLY_ON"))        {            return BlendMode.Transparent;        }        return BlendMode.Opaque;    }    public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)    {        switch (blendMode)        {            case BlendMode.Opaque:                material.SetOverrideTag("RenderType", "");                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);                material.SetInt("_ZWrite", 1);                material.DisableKeyword("_ALPHATEST_ON");                material.DisableKeyword("_ALPHABLEND_ON");                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");                material.renderQueue = -1;                break;            case BlendMode.Cutout:                material.SetOverrideTag("RenderType", "TransparentCutout");                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);                material.SetInt("_ZWrite", 1);                material.EnableKeyword("_ALPHATEST_ON");                material.DisableKeyword("_ALPHABLEND_ON");                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");                material.renderQueue = 2450;                break;            case BlendMode.Fade:                material.SetOverrideTag("RenderType", "Transparent");                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);                material.SetInt("_ZWrite", 0);                material.DisableKeyword("_ALPHATEST_ON");                material.EnableKeyword("_ALPHABLEND_ON");                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");                material.renderQueue = 3000;                break;            case BlendMode.Transparent:                material.SetOverrideTag("RenderType", "Transparent");                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);                material.SetInt("_ZWrite", 0);                material.DisableKeyword("_ALPHATEST_ON");                material.DisableKeyword("_ALPHABLEND_ON");                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");                material.renderQueue = 3000;                break;        }    }    public void RestoreSneakAlpha(GameObject resourceObject)    {        Renderer[] renderers = resourceObject.GetComponentsInChildren<Renderer>(true);        for (int i = 0; i < renderers.Length; i++)        {            Material m = renderers[i].material;            if (GetMaterialWithBlendMode(m) == BlendMode.Fade)            {                Color timerColor = new Color(m.color.r, m.color.g, m.color.b, 1);                m.color = timerColor;            }            SetupMaterialWithBlendMode(m, BlendMode.Opaque);        }    }    public void SetSneakAlpha(GameObject resourceObject, float alpha)    {        Renderer[] renderers = resourceObject.GetComponentsInChildren<Renderer>(true);        for (int i = 0; i < renderers.Length; i++)        {            Material m = renderers[i].material;            if (GetMaterialWithBlendMode(m) == BlendMode.Opaque)            {                Color timerColor = new Color(m.color.r, m.color.g, m.color.b, alpha);                m.color = timerColor;            }            SetupMaterialWithBlendMode(m, BlendMode.Fade);        }    }


于是试了几个办法,把相关变体打印进去:

1. 把开启 fade的材质球 打包进去,

结果:测试项目OK。  实际项目只有个别人物能透明,其他的还是一样, 原来实际项目每个角色 打成了单独的AssetBuddle, shader没有形成依赖,造成每个里面打了一个shader 。  当然想办法调整一下也许是可以的, 但总的感觉不太好。

所以这个方案应该可行,不过需要放几个不相干的 材质球项目里。


2.参照官网 用 ShaderVariantCollection

http://blog.csdn.net/ynnmnm/article/details/44674211
http://www.seven-fire.cn/archives/174
先 到Edit->Project Settings->Graphics里把 用到的shader变体 保存成 一个 ShaderVariantCollection文件。

然后试了2个方法
A.添加到GraphicsSettings的Preload Shaders列表中 
B.放到Resources目录下, 通过代码创建ShaderVariantCollection,并调用WarmUp接口
都无效

奇怪了,和 http://blog.csdn.net/sparrowfc/article/details/50389238 这边文章 问题差不多。


看下面评论, 好像早期版本Standard 用 ShaderVariantCollection 有问题, 可能5.6 之后才修正了?这个可以去官方查一查。

然后 说把对应的 开关 不要用 shader_feature  而用  multi_compile

正好我们项目把 StandardSpecular.shader自己改过一些, 所以方案3


3. 修改 StandardSpecular.shader(我们自己提取标准shader 改了一下), 

把几处(主要是  "LightMode" = "ForwardBase"), 

#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON

改成
#pragma multi_compile _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON


编译时开销多一些,   怕 运行时占内存太多, profile了一下, 发现 也还好,占用内存挺小的。


暂时选用这个方案了。



对了,附带一个 Unity5.x shader打包AssetBundle总结
http://www.2cto.com/kf/201612/578404.html

感觉有参考价值。


阅读全文
0 0
原创粉丝点击