首页 > 编程语言 > 详细

Unity shader_feature实现shader功能合并

时间:2020-03-12 17:46:39      阅读:107      评论:0      收藏:0      [点我收藏+]

前提:有个需求为切换顶点动画样式,例如有sin波动、cos波动、cos(θ+x)波动等等...
这时候你会怎么做?

是不是脚本中设置各种case,每个case加载对应的shader。这种方法可以用,但在实际开发中,根本不可取。因为可能会有大量Shader被编译,造成内存的大量占用。那么该怎么做呢?

常用的两种做法

? 1.使用multi_complie或shader_feature来定义宏,根据不同的宏指令编译出多套Shader,Unity内建shader大体也是这么做的。
? 2.有外部传入参数,在shader内部if判断,选择执行哪部分运算。
因为在shader种使用if、for很影响效率,所以第二种方法使用较少,用于case较少的时候。
接下来主要谈一下第一种方法的利与弊。

使用multi_complie

该指令可以达到上述效果,但他会无脑的进行组合编译,如果宏指令太多,会产生非常多的variant。
? 当你使用

#pragma multi_compile Red Green Blue

会产生三个variant,因为你定义了三个宏
? 当你使用

#pragma multi_compile Red Green Blue
#pragma multi_compile Pink Yellow 

会产生6个variant(RedPink,RedYellow,GreenPink,GreenYellow,BluePink,BlueYellow),因为他们之间会两两组合。

? 当你使用

#pragma multi_compile Red Green Blue
#pragma multi_compile Pink Yellow 
#pragma multi_complie Brown Purple Black

会产生323个variant。可见这个产生变体的数量规模是很大的。
如何查看一个shader产生的变体数量?
选中shader文件,点击compile and show code右边的小箭头就可以看到。
技术分享图片
优势也很明显:
? 打ab包的时候,Unity会把shader中所有的multi_complie定义的变体全部打包,shader可以正常显示。但shader_feature就不那么尽人意了。
需要注意:
? 其中指定的第一个关键字是默认生效的。
? 使用multi_compile声明的都为全局关键字,一个项目种全局关键字最多只能有256个,内建shder大约已经用了60个。
? 注意FallBack最好不要FallBack内建shader,也会增加很多变体。

使用shader_feature

该指令的效果和用法基本都与上面的一样。同时它就是为了multi_compile打包时的爆炸编译的问题。
实现:
shader代码

Shader "Custom/NewSurfaceShader" {
    Properties {
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        
        pass
        {
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            //#pragma surface surf Standard fullforwardshadows

            #include "UnityCG.cginc"

            //#pragma shader_feature Red Green Blue
            #pragma multi_complie_local __ Red Green Blue
            //#pragma multi_compile __ Pink */
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 2.0
            #pragma vertex vert
            #pragma fragment frag

            struct v2f
            {
                float4 vertex:POSITION;
                fixed4 color:COLOR;

            };
        
            v2f vert(appdata_base i)
            {
                v2f o;
                o.vertex=UnityObjectToClipPos(i.vertex);
                o.color=fixed4(1,1,1,1);
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                #if Red
                return i.color=fixed4(1,0,0,1);
                #elif Blue
                return i.color=fixed4(0,0,1,1);
                #else
                return i.color=fixed4(0,1,0,1);
                #endif
            }
            ENDCG
        }
    }
    //FallBack "Diffuse"
}

C#代码进行外部控制:

/*
    author:@
    Last modified data:
    funtion todo:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shader_featureTest : MonoBehaviour {
    public enum ColorMode
    {
        Red,
        Blue,
        Green
    }

    public ColorMode colorMode = ColorMode.Green;
    Material mt;
    // Use this for initialization
    void Start () {
        mt = GetComponent<MeshRenderer>().material;
    }
    
    // Update is called once per frame
    void Update () {
        print(colorMode.ToString());
        switch (colorMode)
        {

            case ColorMode.Red:
               
                mt.shaderKeywords = new string[1] { colorMode.ToString() };
                break;
            case ColorMode.Blue:
                mt.shaderKeywords = new string[1] { colorMode.ToString() };
                
                break;
            case ColorMode.Green:
                mt.shaderKeywords = new string[1] { colorMode.ToString() };
               
                break;
            default:
                break;
        }
    }
}

把材质赋予随便一个物体上,运行时切换就可以达到效果。在multi_complie下使用EnableKeywords和DisableKeywords有事会失败,这里建议直接使用shaderKeywords属性来设置(希望有大神可以告诉为什么那两个方法会失败,很是疑惑

看到这么一条,还没有尝试:
在脚本这么用
Material.EnableKeyword 和 DisableKeyword
Shader.EnableKeyword 和 DisableKeyword 控制keyword起效
注意:
? 5.4中用Shader.EnableKeyword设置了全局使用默认的key, 用Material.EnableKeywor设置单个不使用默认值无效
? 用Shader.EnableKeyword设置了全局不使用默认的key, 用Material.EnableKeywor设置单个使用默认值起效
? EnableKeyword 和 DisableKeyword 最好组合使用 比如一组有三个,必须写1个enable2个disable

不管有多少个关键字,总会产生一个variant,大大降低了编译出来的shader变体。
但是打ab包的时候,如果shader和所使用的材质不在一个ab包内,那么材质的shader中所有的变体都不会进入ab包中。在打包后代码中动态切换keywords,要把使用到的shader变体也打入包中才可以。
为了让变体在运行时可以更好的处理,Unity5.x之后引入了一个shader变体集合:ShaderVariantCollection,ShaderVariantCollection的使用之后会讲,今天简单给大家介绍一下这两种方式。

Unity shader_feature实现shader功能合并

原文:https://www.cnblogs.com/w199753/p/12469952.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!