Shader CG语言

Shader介绍

Shader是可编程图形管线的算法片段,它主要分为两类,Vertex Shader和Fragment Shader。

圣典shader总目录(在最下方)

vs自动补全代码,语法高亮显示插件

入门指导博客

相关书籍:

  • 《Unity Shaders and Effects Cookbook》,下载,博客 ,英文书(有一定英文基础)
  • 《unity shader入门精要》   下载 , 彩色插图 ,源码 ,第4章勘误章.pdf(勘误列表);  适合初学者学习
  • 《GPU 编程与CG 语言之阳春白雪下里巴人》,下载,可以帮助你了解硬件,此书作者水平很高
  • 《Real-Time Rendering 3rd》,下载,这本书更多资料,博客,相关介绍,笔记,经典之作,不过不适合入门,《Real-Time Rendering 4th》,将于2018年8月15号面世
  • 《Physically Based Rendering:From Theory to Implementation》(PBRT),pbrt网站,下载(第三版),勘误表,书上的例子,Wikipedia网页
  • 《Advanced Global Illumination》,Wikipedia网页,下载
  • 《untiy3d ShaderLab实战详解》 下载,适合入门学习
  • 《3D数学基础:图形与游戏开发》  下载,如果真的想学好shader,学数学是必须的,比较全面,适合入门学习
  • 《GPU编程精粹》 知乎专栏,《GPU Gems》1~3 (Web版)、《GPU Pro》1~7 以及《GEM Zen》组成的GPU精粹系列书籍,书籍,这个大神可以试试,初学者不太适合学习
  • 《Unity5.X从入门到精通》 下载
  • 《全局光照技术:从离线到实时渲染》

相关网站:

  • Unity CG Wiki Book,CG编程
  • Unity官方Shader手册 
  • 风雨冲博客
  • Unity3D精华备忘录

渲染管线

       渲染管线也称为渲染流水线,是显示芯片内部处理图形信号相互独立的并行处理单元。一个流水线式一序列可以并行和按照固定顺序进行的阶段。每个阶段都从它的前一阶段接收输入,然后把输出发给随后的阶段,就像一个在同一时间内,不同阶段不同的汽车一起制造的装配线,传统的图形硬件流水线以流水方式处理大量的顶点、几何图元和片段。

Shader Language

基于OpenGL的OpenGL Shading Language, 简称GLSL。语法体系自成一家。

OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。


OpenGL是行业领域中最为广泛接纳的 2D/3D 图形 API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。OpenGL是独立于视窗操作系统或其它操作系统的,亦是网络透明的。在包含CAD、内容创作、能源、娱乐、游戏开发、制造业、制药业及虚拟现实等行业领域中,OpenGL帮助程序员实现在 PC、工作站、超级计算机等硬件设备上的高性能、极具冲击力的高视觉表现力图形处理软件的开发。


基于DirectX的High Level Shading Language,简称HLSL。移植性较差。
DirectX,(Direct eXtension,简称DX)是由微软公司创建的多媒体编程接口。由C++编程语言实现,遵循COM。被广泛使用于Microsoft Windows、Microsoft XBOX、Microsoft XBOX 360和Microsoft XBOX ONE电子游戏开发,并且只能支持这些平台。最新版本为DirectX 12,创建在最新的Windows10。


还有NVIDIA公司的C for Graphic ,简称Cg语言。可以被OpenGL和Direct3D广泛支持的图形处理器编程语言。

Shader Reference(圣典)

  • SurfaceShader(表面着色器):Untiy自己发扬光大的一项使书写门槛降低和更容易的技术。把Shader的复杂性包装起来,书写过程更便捷和易用。
  • Vertex Shader and Fragment Shader(顶点着色器&片段着色器):顶点着色器---->产生纹理坐标,颜色,点大小,雾坐标,然后把它们传递给裁剪阶段。片段着色器---->进行纹理查找,决定什么时候执行纹理查找,是否进行纹理查找,及把什么作为纹理坐标。
  • FixedFunction Shader(固定功能着色器):Unity为Shader的书写自带的一层壳,Unity已经在内部为我们做了大量的工作,我们只要稍微记住一些关键字、一些规范就可以实现很多不错的效果。固定功能着色器是我们初学Unity Shader的最贱几篇文章中的主要学习对象。而后面的表面着色器、顶点着色器以及片段着色器就是在固定功能着色器的基础上嵌套了CG语言的代码而成的更加复杂的着色器。

区别

  1. 没有嵌套CG语言,也就是代码段中没有CGPROGARAM和ENDCG关键字,就是固定功能着色器。
  2. 嵌套了CG语言,代码段中有surf函数的,就是表面着色器。
  3. 嵌套了CG语言,代码段中有#pragma vertex name和  #pragma fragment frag 声明的,就是顶点着色器&片段着色器

Shader---->路径(直接决定shader在material里出现的路径 

Shader "Custom/LogoShader" {

}

 

Properties---->属性面板

2D:一张2的阶数大小的贴图,这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终显示出来。

Cube:即Cube map texture(立方体文理),简单说就是6张有联系的2D贴图的结合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应的采样。

对于贴图来说,默认值可以是空字符或者"White"、"Black"、"Gray"、"Bump"中的一个,另外{},它只对2D、Rect、Cube贴图有关,当我们需要打开特定选项时可以把其写在这对花括号内。如果需要同时打开多个选项,可以使用空白分隔,

name ("display name", 2D) ="name" { options }

:包含在纹理属性的大括号中的选项Options是可选的,可能选项如下:

  1. TexGen纹理生产类型:即纹理的自动生成纹理坐标时的模式,可以是ObjectLinear, EyeLinear,SphereMap, CubeReflect, CubeNormal的其中之一;这些模式和OpenGL纹理生成模式相对应。注意如果使用自定义顶点程序,那么纹理生成将被忽略。如下面的例子。
  2. LightmapMode光照贴图模式:如果我们给出这个选项,纹理将能被渲染器的光线贴图属性所影响。纹理不能被使用在材质中,而是取自渲染器的设定。
_MainTex ("Albedo (RGB)", 2D) = "white" {TexGen ObjectLinear}
关键字 类型 对应Cg类型
Float 浮点数 float _MyFloat ("My float", Float) = 0.5
Range 浮点数 (在指定范围内) float _MyRange ("My Range", Range(0.01, 0.5)) = 0.1
Color 浮点四元组 float4 _MyColor ("Some Color", Color) = (1,1,1,1)
Vector 浮点四元组 float4 _MyVector("Some Vector",Vector) = (1,1,1,1)
2D 2的阶数大小的贴图 sampler2D _MyTexture ("Texture", 2D) = "white" {options}
Rect 非2的阶数大小的贴图 sampler2D _MyRect("My Rect", Rect) = "white" {options}
Cube CubeMap samplerCube _MyCubemap ("Cubemap", Cube) = "" {options}
Shader "Custom/LogoShader" 
{ 
    Properties { 
    _Range ("My Range", Range (0.02,0.15)) = 0.07 // sliders 
    _Color ("My Color", Color) = (.34, .85, .92, 1) // color 
    _2D ("My Texture 2D", 2D) = "" {} // textures 
    _Rect("My Rectangle", Rect) = "name" { } 
    _Cube ("My Cubemap", Cube) = "name" { } 
    _Float ("My Float", Float) = 1 
    _Vector ("My Vector", Vector) = (1,2,3,4) 
    } 
}

 

SubShader---->unity中的每一个着色器都包含一个subshader的列表,当unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器。呈现效果,可以多个,先从第一个开始,如果第一个方案不能达到,就执行第二个方案

Shader "MyShader" {
    Properties {
        _MyTexture ("My Texture", 2D) = "white" { }
        // other properties like colors or vectors go here as well
    }
    SubShader {
        // here goes the 'meat' of your
        // - surface shader or
        // - vertex and program shader or
        // - fixed function shader
    }
    SubShader {
        // here goes a simpler version of the SubShader
        // above than can run on older graphics cards
    }
}

 

Unity Shader里面的Tag分为两种,一种是自着色器(SubShader)Tags,一种是通道(Pass)Tags。SubShader中的标签设置是特定的,和Pass中使用的标签是不一样的。而对于状态设置来说,其使用的语法是相同的。但是,如果我们在SubShader进行了这些设置,那么将会用于所有的Pass。

  • Tags---->SubShader标签(使用队里标签来确定对象的绘制顺序。shader决定起对象属于哪个渲染队列,这样所有透明的shader能保证在所有不透明的shader后渲染。)
    • Background:最先被调用的渲染,通常用来渲染背景(天空盒)。渲染队列值 1000。
    • Geometry(default):默认值,大多数物体使用此队列,用来渲染不透明的物体。渲染队列值 2000。
    • AlphaTest: alpha tested的物体使用此队列。它是与几何一个独立的队列,因为在绘制所有实体后,渲染经过alpha tested的对象更有效率。渲染队列值 2450。
    • Transparent:这个渲染队列是在Geometry和Alpha Test之后,以从后往前的顺序渲染的。任何alpha混合(alpha-blended)(即不写入深度缓冲区depth buffer的shader)应该在这里。例如玻璃,粒子特效。渲染队列值 3000。
    • Overlay:此渲染队列用于叠加效果。任何最后呈现的东西都用在这里(例如:镜头光晕)。渲染队列值 4000。

:Tags标记在Subshader节内,而不是Pass;渲染顺序是先从渲染队列值小的开始渲染。"RenderType"---->标签(Untiy可以运行时替换符合特定RenderType的所有Shader。Camera.RenderWithShaderCamera.SetReplacementShader配合使用。Camera.RenderWithShader或Camera.SetReplacementShader不要求标签只能是RenderType,RenderType只是Unity内部用于Replace的一个标签而已,你也可以自定义全新的标签用于Replace。比如,你为自己的ShaderA.SubShaderA1(会被unity选取到的SubShader,常为Shader文件中的第一个SubShader)增加Tag为"Distort"="On",然后将"Distort"作为参数replacementTag传给函数。此时,作为replacementShader的实参的ShaderB.SubShaderB1中若有一模一样的"Distort"="On",且这A的材质参数包含B所需材质参数,则SubShaderB1将代替SubShaderA1用于本次渲染。具体可参考:Rendering with Replaced Shaders。 

Queue

队列类型,渲染顺序。

Background=1000

Geometry=2000(默认)

AlphaTest=2450

Transparent=3000

Overlay=4000

自定义:"Queue"="3100"

               "Queue"="Transparent+100"

RenderType 渲染类型。内建值包括:
Opaque:不透明(法线、自发光、反射、地形Shader)
Transparent:半透明(透明、粒子、字体、地形添加通道Shader)
TransparentCutout:遮罩透明(透明裁切、双通道植物Shader)
Background:天空盒Shader
Overlay:GUI纹理、光晕、闪光Shader
TreeOpaque:地形引擎——树皮
TreeTransparentCutout:地形引擎——树叶
TreeBillboard:地形引擎——公告牌(始终面向摄像机)式树木
Grass:地形引擎——草
GrassBillboard:地形引擎——公告牌(始终面向摄像机)式草
DisableBatching 禁用批处理,是否禁用Batch(打包、合并),可用值:
True:禁用
False:不禁用(默认)
LODFading:当LOD fade开启的时候禁用,一般用在树木上面
ForceNoShadowCasting 是否强制不投射阴影,当这个值为True的时候,使用这个Shader的对象便不会投射阴影。
一般用于透明对象,或者不想继承其他shader阴影的时候
IgnoreProjector 无视投影器,当这个值为True的时候,对象便不受投射器影响(不接受Projector组件的投影)。
一般用于半透明对象,因为让投射器影响它们不是什么好事情。
CanUseSpriteAtlas 可使用精灵集,当这个值为False的时候,不能使用精灵集。
PreviewType 材质的预览形式,默认显示为球体,可以使用Plane(2D平面)或Skybox(天空盒)
Pass Tags
LightMode

光照模式:
Always:
总是渲染,不使用光照
ForwardBase:
用于前向渲染,使用环境光、主平行光、顶点/SH(球谐函数)光照以及光照贴图
ForwardAdd:
用于前向渲染,额外使用每像素光,每个光照一个通道
Deferred:
用于延迟着色,渲染G-Buffer
ShadowCaster:

渲染对象的深度到阴影贴图或者深度纹理

MotionVectors:

用来计算逐对象式运动向量

PrepassBase:
用于(旧版)延迟光照,渲染法线和高光指数
PrepassFinal:
用于(旧版)延迟光照,合并贴图、光照和自发光来渲染最终色彩
Vertex:
当对象不受光照贴图影响的时候,用来渲染(旧版)顶点发光。
使用所有的顶点光照
VertexLMRGBM:
当对象接受光照贴图影响的时候,用来渲染(旧版)顶点发光。
适用于使用RGBM编码光照贴图的平台(PC&主机)
VertexLM:
当对象接受光照贴图影响的时候,用来渲染(旧版)顶点发光。
适用于使用double-LDR编码光照贴图的平台(移动平台)

PassFlags 标志渲染管线如何传递数据给通道
OnlyDirectional:
只有主平行光、环境光和光照探测器的数据会传递给通道
仅用于LightMode为ForwardBase
RequireOptions 标志通道至于在某些外部条件满足时才会被渲染
SoftVegetation:
当Quality Setting中的Soft Vegetation选项被开启时,才会渲染通道
Culling & Depth Testing
状态名称 设置指令 解释
Cull Cull Back|Front|Off

设置剔除模式,剔除背面(背向摄像机的面)|正面

(朝向摄像机的面)|关闭剔除   默认(CullBack)

ZTest

ZTest Less|Greater|LEqual|

Equal|NotEqual|Always|GEqual

设置深度时使用的函数,少于|大于|小于或等于|

等于|不等|一直|大于或等于  默认(LEqual)

ZWrite ZWrite On|Off 深度记录(默认)|关闭深度写入
Blend Blend SrcFactor DstFactor 开启并设置混合模式

Blend

语法

  1. Blend Off  关闭混合。
  2. Blend SrcFactor DstFactor   配合和启用混合,生成的颜色乘以SrcFactor,已在屏幕上的颜色乘以DstFactor,然后两者相加。
  3. Blend SrcFactor DstFactor,SrcFactorA DstFactorA  与上述操作相同,但是混合alpha通道要使用不同的因子。
  4. BlendOp Min|Max|Sub|RevSub   不将混合颜色相加,而是对它们进行不同的操作。
  5. Add---->FinalColor = SrcFactor*SrcColor + DstFactor*DstColor(加法)
  6. Sub---->FinalColor = SrcFactor*SrcColor - DstFactor*DstColor(减法,源-目标)
  7. RevSub---->FinalColor = DstFactor*DstColor - SrcFactor*SrcColor(减法,目标-源)

以下所有属性对SrcFactor(源因子)或DstFactor(目标因子)都可用。Source指的是被计算的颜色,Destination是已经在屏幕上的颜色。

:设置好计算模式之后,就可以设置混合因子了,有两个公式,注意必须选择下面某个公式,Blend模式才算打开,不然默认关闭的。

经过Blending操作后,

混合颜色=缓存颜色*SrcFactor+目标颜色*DstFactor,风宇冲博客。

混合Alpha值=缓存Alpha值*SrcFactorA+目标Alpha值*DstFactorA。

看第一个公式,没有设置计算Alpha值的混合因子,其他只是把SrcFactorA=SrcFactor,DstFactorA=DstFactor了,相当于如果不写就默认用前面两个参数。

One 值为1,使用此设置来让源或是目标颜色完全的通过。
Zero 值为0,使用此设置来删除源或目标值。
SrcColor 此阶段的值是乘以源颜色的值。
SrcAlpha 此阶段的值是乘以源alpha的值。
DstColor 此阶段的值是乘以帧缓冲区源颜色的值。
DstAlpha 此阶段的值是乘以帧缓冲区源alpha的值。
OneMinusSrcColor 此阶段的值是乘以(1-source color)。
OneMinusSrcAlpha 此阶段的值是乘以(1-source alpha)。
OneMinusDstColor 此阶段的值是乘以(1-destination color)。
OneMinusDstAlpha 此阶段的值是乘以(1-destination alpha)。

以下是最常见的混合模式,例如:

  1. Blend SrcAlpha OneMinusSrcAlphea (透明混合
  2. Blend One One(叠加)
  3. Blend OneMinusDstColoe One(软叠加)
  4. Blend DstColor Zero(相乘)
  5. Blend DstColor SrcColor(2x 相乘)
Shader "Custom/LogoShader" {
    Properties
    {
        // Header creates a header text before the shader property.
        [Header(Material Property Drawer Example)]
        // Space creates vertical space before the shader property.
        [Space]

        _MainTex ("Main Tex", 2D) = "white" {}
        _SecondTex ("Second Tex", 2D) = "white" {}

        // Large amount of space
        [Space(50)]

		//混合状态的定义
		//[HideInInspector] _Mode ("__mode", Float) = 0.0
		//[HideInInspector] _SrcBlend ("__src", Float) = 1.0
		//[HideInInspector] _DstBlend ("__dst", Float) = 0.0
		//[HideInInspector] _ZWrite ("__zw", Float) = 1.0

        // Toggle displays a **float** as a toggle. 
        // The property value will be 0 or 1, depending on the toggle state. 
        // When it is on, a shader keyword with the uppercase property name +"_ON" will be set, 
        // or an explicitly specified shader keyword.
        [Toggle] _Invert ("Invert color?", Float) = 0

        // Will set "ENABLE_FANCY" shader keyword when set
        [Toggle(ENABLE_FANCY)] _Fancy ("Fancy?", Float) = 0

        // Enum displays a popup menu for a **float** property. 
        // You can supply either an enum type name 
        // (preferably fully qualified with namespaces, in case there are multiple types), 
        // or explicit name/value pairs to display. 
        // Up to **7** name/value pairs can be specified
        [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend Mode", Float) = 1
        [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend Mode", Float) = 1
        [Enum(Off, 0, On, 1)] _ZWrite ("ZWrite", Float) = 0
        [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest ("ZTest", Float) = 0
        [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull Mode", Float) = 1

        // KeywordEnum displays a popup menu for a **float** property, and enables corresponding shader keyword. 
        // This is used with "#pragma multi_compile" in shaders, to enable or disable parts of shader code. 
        // Each name will enable "property name" + underscore + "enum name", uppercased, shader keyword. 
        // Up to **9** names can be provided.
        [KeywordEnum(None, Add, Multiply)] _Overlay ("Overlay mode", Float) = 0

        // PowerSlider displays a slider with a non-linear response for a Range shader property.
        // A slider with 3.0 response curve
        [PowerSlider(3.0)] _Shininess ("Shininess", Range (0.01, 1)) = 0.08
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" }
        Blend [_SrcBlend] [_DstBlend]
        ZWrite [_ZWrite]
        ZTest [_ZTest]
        Cull [_Cull]

        Pass
        {
		    //设置通道名称
			Name "FORWARD" 
            CGPROGRAM
            // Need to define _INVERT_ON shader keyword
            #pragma shader_feature _INVERT_ON
            // Need to define _INVERT_ON shader keyword
            #pragma shader_feature ENABLE_FANCY
            // No comma between features
            #pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _SecondTex;
            float4 _SecondTex_ST;
            float _Shininess;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv.zw = TRANSFORM_TEX(v.uv, _SecondTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv.xy);

                // Use #if, #ifdef or #if defined
                #if _INVERT_ON
                col = 1 - col;
                #endif

                // Use #if, #ifdef or #if defined
                #if ENABLE_FANCY
                col.r = 0.5;
                #endif

                fixed4 secCol = tex2D(_SecondTex, i.uv.zw);

                #if _OVERLAY_ADD
                col += secCol;
                #elif _OVERLAY_MULTIPLY
                col *= secCol;
                #endif

                col *= _Shininess;

                return col;
            }
            ENDCG
        }
    }
}

 

LOD

LOD是Level of Detail的简写,确切地说是Shader Level of Detail的简写,因为Unity中还有一个模型的LOD概念,这是两个不同的东西,这里介绍的是Shader中的LOD,模型的LOD。

设置:单个设置Shader.maximumLOD;全局设置Shader.globalMaximumLOD;

原理:小于指定值的shader和SubShader才能被使用。

Shader LOD 就是让我们设置一个数值,这个数值决定了我们能用什么样的Shader。可以通过Shader.maximumLOD或者Shader.globalMaximumLOD 设定允许的最大LOD,当设定的LOD小于SubShader所指定的LOD时,这个SubShader将不可用。通过LOD,我们就可以为某个材质写一组SubShader,指定不同的LOD,LOD越大则渲染效果越好,当然对硬件的要求也可能越高,然后根据不同的终端硬件配置来设置 globalMaximumLOD来达到兼顾性能的最佳显示效果。

Unity内建Shader定义了一组LOD的数值,我们在实现自己的Shader的时候可以将其作为参考来设定自己的LOD值:

  1. VertexLit及其系列=100
  2. Decal,Reflective VertexLit=150
  3. Diffuse=200
  4. Diffuse Detail,Reflective Bumped Unlit,Reflective Bumped VertexLit=250
  5. Bumped,Specular=300
  6. Bumped Specular=400
  7. Parallax=500
  8. Parallax Specular=600
public Shader targetShader;

    private void Start () 
    {
        // 全局的值会被Shader本地址覆盖
        Shader.globalMaximumLOD = 300;
        if (targetShader != null)
        {
            targetShader.maximumLOD = 600;
        }
    }

 

Shader Programs

  • CGPROGARAM开始到ENDCG结束,如果SubShader有Pass通道,就要写到pass里面。
  • 编译指令
Shader中,编译指令分为两种,一种是常规的变异指令,也就是顶点片元着色器(Vetex & Fragment Shader)使用的编译指令,另一种就是表面着色器(Surface Shader)使用的编译指令。二者都使用#pragma语句来编写,并且都需要写在CGPROGRAM和ENDCG之间。区别在于,VF编译指令写在Pass里面,而表面着色器编译指令写在SubShader里面,表面着色器会自行编译到多通道里去,并且需要使用#pragma surface …指令来标识这是一个表面着色器。
#pragma vertex name 编译name函数为顶点着色器
#pragma fragment name 编译name函数为片元着色器
#pragma geometry name 编译name函数为DX10的几何着色器
注:会自动开启#pragma target 4.0
#pragma hull name 编译name函数为DX10的壳着色器
注:会自动开启#pragma target 5.0
#pragma domain name 编译name函数为DX10的域着色器
注:会自动开启#pragma target 5.0
#pragma target name 表明编译目标
参考着色器编译目标等级
#pragma only_renderers space_separated_names 只为指定的渲染平台渲染着色器
包括下列值:
d3d9:Direct3D 9
d3d11:Direct3D 11/12
glcore:OpenGL 3.x/4.x
gles:OpenGL ES 2.0
gles:OpenGL ES 3.x
metal:IOS&Mac Metal
d3d11_9x:Direct3D 11 9.x特性等级一般用于WSA平台
xbox360:Xbox 360
xboxone:Xbox One
ps4:PlayStation 4
psp2:PlayStation Vita
n3ds:Nintendo 3DS
wiiu:Nintendo Wii U
#pragma exclude_renderers space_separated_names 排除指定的渲染平台
参数同上
#pragma multi_compile... 参考Shader山下(二十一)多重变体(Multiple Variants)
或者Unity官方文档:多重着色器变体
#pragma enable_d3d11_debug_symbols 生成d3d11的调试信息
可以在VS2012(或以上)使用图形调试器调试shader
#pragma hardware_tier_variants renderer_name 针对所选渲染器的每个硬件层级
生成每个已编译的Shader的多重Shader硬件变体
参考Shader山下(二十一)多重变体(Multiple Variants)
或者Unity官方文档:多重着色器变体

表面编译指令

 
#pragma surface surfFunc lightingModel [optional params]  
surfaceFunction(必选) 表面着色器函数
lightModel(必选) 光照模型函数,内置模型:
Standard:基于物理的漫反射模型
StandardSpecular:基于物理的高光模型
Lambert:不基于物理的漫反射模型
BlinnPhong:不基于物理的高光模型
也可以自己写,命名规则:Lighting...
...为在编译指令里填写的名称
例如#pragma surface surf Custom
光照模型函数名就要写成:
LightingCustom
具体参考表面着色器中的自定义光照模型
alpha或者alpha:auto 透明度混合
对于简单的光照模型(例如Lambert和BlinnPhong)使用alpha:fade
对于基于物理的光照模型使用alpha:premul
alpha:blend 透明度混合
alpha:fade 传统透明度混合(参考Shader山下(十八)混合(Blend)命令)
alpha:premul 预乘透明度混合
alphatest:variable_name 透明度测试,并使用variable_name作为裁切阈值
keepalpha 对于默认的不透明Shader,会无视光照模型返回的透明度值,直接把1.0写入Alpha通道。
使用keepalpha选项,允许在不透明Shader里保留光照模型返回的透明度值。
decal:add 附加的贴花shader,这意味着对象在其他表面的上面并使用添加方法进行混合。
decal:blend 半透明贴花shader,这意味着对象在其他表面的上面并使用透明度方法进行混合。
vertex:vertex_function 自定义顶点函数
finalcolor:color_function 自定义的最终颜色修改函数
finalgbuffer:gbuffer_function 自定义的改变GBuffer内容的延迟路径
finalprepass:prepass_function 自定义的预通道基础路径
addshadow 生成一个阴影投射通道
一般用于自定义顶点函数,这样的话,就可以对阴影投射使用程序化的顶点动画
一般情况下,shader并不需要任何特殊的阴影处理,因为它们可以使用Fallback里的阴影投射通道
fullforwardshadows 支持前向渲染路径里的所有光照阴影
默认情况下只支持一个平行光的阴影
如果需要点光源(point)或者聚光灯(spot)的阴影,那么就要使用这个选项
tessellate:tessellate_function 使用DX11的GPU镶嵌,tessellate_function计算镶嵌参数
参考表面着色器镶嵌
exclude_path:path 不生成指定渲染路径的通道
可选项:
deferred
forwad
prepass
noshadow 禁用阴影
noambient 禁用环境光或者光探头
novertexlights 禁用前向渲染中的光探头或者每顶点光照
nolightmap 禁用所有的光照贴图
nodynlightmap 禁用动态光照贴图
nodirlightmap 禁用平行光照贴图
nofog 禁用内置雾效
nometa 不生成元通道
光照贴图和动态全局光照使用元通道来提取表面信息
noforwardadd 禁用前置渲染的附加通道
这样就让shader支持一个完全平行光,而其他的光使用每顶点或者SH(球谐函数)计算
同样让shader变得更轻
softvegetation 在Quality Setting里的Soft Vegetation被开启的时候,才会被渲染
interpolateview 在顶点着色器中计算视图方向并插入它(默认在像素着色器中计算)
这样使得Shader变得更快,不过需要多使用一个纹理插值。
halfasview 传递半角向量给光照模型(默认是视图向量)
会在每个顶点计算并归一化半角向量
这样更快,但是并不完全正确。
approxview 5.0中被interpolateview取代
dualforward 在前向渲染路径中使用双光照贴图

编译指令的一些常见例子:

#pragma surface surfaceFunction lightModel [optionalparams]
// #pargma 关键词 函数名 光照模型 [其它选项]

// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
#pragma surface surf Lambert 
#pragma surface surf Lambert alpha
#pragma surface surf Lambert addshadow


// 使用model 3.0 可以得到一个更好的光照效果, 默认是2.0
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0

//编译指令:不使用GLES渲染器编译
#pragma exclude_renderers gles
			
			
// ---------编译指令:着色器编译多样化--------
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP 
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _PARALLAXMAP
// Need to define _INVERT_ON shader keyword
#pragma shader_feature _INVERT_ON
// Need to define _INVERT_ON shader keyword
#pragma shader_feature ENABLE_FANCY


			
//--------着色器编译多样化快捷指令------------
//编译指令:编译正向渲染基础通道(用于正向渲染中,应用环境光照、主方向光照和顶点/球面调和光照)所需的所有变体。
//这些变体用于处理不同的光照贴图类型、主要方向光源的阴影选项的开关与否
#pragma multi_compile_fwdbase
//编译指令:编译几个不同变种来处理不同类型的雾效(关闭/线性/指数/二阶指数/)
#pragma multi_compile_fog
#pragma multi_compile ___ UNITY_HDR_ON
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
//编译指令:编译正向渲染基础通道所需的所有变体,但同时为上述通道的处理赋予了光照实时阴影的能力。
#pragma multi_compile_fwdadd_fullshadows
//快捷编译指令:进行阴影投射相关的多着色器变体的编译
#pragma multi_compile_shadowcaster
// No comma between features
#pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY


//跳过如下变体的编译,简化编译过程
#pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
#pragma skip_variants SHADOWS_SOFT
//编译指令:告知编译器顶点和片段着色函数的名称


#pragma vertex vert
#pragma fragment frag

           
//包含辅助CG头文件
#include "UnityCG.cginc"
#include "UnityStandardCore.cginc"

Include

数据类型

float 32位浮点数据,一个符号位。浮点数据类型被所有的profile。
half 16位浮点数据。
int 32位整形数据,有些profile会将int类型作为float类型使用。
fixed 12位定点数,被所有的fragment profiles所支持。
bool 布尔数据,通常用于if和条件操作符,布尔数据类型被所有profiles支持。
simpler*

sampler,sampler1D,sampler2D,sampler3D,samplerCUBE,samplerRECT。DirectX profiles不支

持samplerRECT类型,除此之外这些类型被所有pixelprofiles和NV40 vertex program proflie所支持。

string

字符类型,该类型不被当前存在的profile所支持,实际上也没有必要在Cg程序中用到字符类型,但是你可

以通过Cg runtime API声明该类型变量,并赋值;因此,该类型变量可以保存Cg文件的信息。(几乎不使用)

//向量最长不能超过 4 元, 即在 Cg 程序中可以声明 float1 、 float2 、 float3 、float4 
//类型的数组变量,但是不能声明超过 4 元的向量。
//在Cg中,向量、矩阵与数组是完全不同的,向量和矩阵是内置的数据类型,而数组则是一种数据结构。
float4 array = float4(1.0, 2.0, 3.0, 4.0);//四元向量
float2 a = float2(1.0, 1.0);
float4 b = float4(a, 0.0, 0.0);

float1x1 matrix1;//等价于 float matirx1; x 是字符,并不是乘号!
float2x3 matrix2;// 表示 2*3 阶矩阵,包含 6 个 float 类型数据
float4x2 matrix3;// 表示 4*2 阶矩阵,包含 8 个 float 类型数据
float4x4 matrix4;//表示 4*4 阶矩阵,这是最大的维数

float2x3 matrix5 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};

sampler2D _MainTex;
Pass
  • 通道可以设置名称,例如:Name "FORWARD" ,Pass Tags在上面表格里面已介绍过了。
  • Render Setup(渲染设置)

1.Material{Material Block(材质块)}

          定义一个使用顶点光照管线的材质

Shader "Custom/LogoShader" {
   Properties {
        _Color ("Main Color", Color) = (1,1,1,0)
        _SpecColor ("Spec Color", Color) = (1,1,1,1)
        _Emission ("Emmisive Color", Color) = (0,0,0,0)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.7
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader {
        Pass {
            Material {

                //漫反射颜色构成,这是对象的基本颜色
			    Diffuse [_Color]
				//环境色颜色构成,这是当对象被RenderSettings中设定的环境色所照射时对象所表现的颜色。
                Ambient [_Color]
				//加亮时的光泽度,在0和1之间。0的时候你会发现更大的高亮也看起来像漫反射光照,1的时候你会获得一个细微的亮斑。
                Shininess [_Shininess]
				//对象反射高光的颜色。
                Specular [_SpecColor]
				//自发光颜色,当不被任何光照所照到时,对象的颜色。
                Emission [_Emission]

				//或者
                //Diffuse (1,1,1,1)
                //Ambient (1,1,1,1)
            }
            Lighting On
            SeparateSpecular On
            SetTexture [_MainTex] {
                Combine texture * primary DOUBLE, texture * primary
            }
        }
    }
}

2.Lighting  On|Off

开启或者关闭顶点光照

3.Cull  Black|Front|Off

设置多边形剔除模式

4.ZTest  Less|Greater|LEqual|GEqual|Equal|NotEqual|Always

设置深度测试模式

关于相机的深度贴图_CameraDepthTexture:

默认材质都自带RenderType的Tag;

自定义shader只有添加RenderType标签才会将深度写到_CameraDepthTexture。

5.ZWrite  On|Off

设置深度写模式

6.Fog { Fog Block}

设置雾参数

7.AlphaTest  Less|Greater|LEqual|GEqual|Equal|NotEqual|Always

开启alpha测试

固定管线:使用AlphaTest命令

动态管线:使用clip(alpha - cutoff)指令来实现

Alpha检测在ps完成计后,即将写入帧之前,通过和一个固定的数值比较,来决定当前ps的计算结果到底要不要写入帧中。

// inside SubShader
Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" "IgnoreProjector"="True" }

// inside CGPROGRAM in the fragment Shader:
clip(textureColor.a - alphaCutoffValue);

AlphaTest抗锯齿:

// inside SubShader
Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" "IgnoreProjector"="True" }

// inside Pass
AlphaToMask On

8.Blend  SourceBlendMode DestBlendMode

设置alpha混合模式,shader渲染的最后一步,决定怎样将当前计算结果写入到帧缓存中。

9.Color

设置当顶点光照关闭时所使用的颜色

10.ColorMask  RGB|A|0|any combination of R, G, B, A

设置颜色写遮罩,设置为0将关闭所有颜色通道的渲染

11.Offset   OffsetFactor,OffsetUnits

设置深度偏移,对Z深度的偏移。

可以让像素看起来更靠前或更靠后,当两个面重叠时,可以手动指定谁相对靠前一些,而且不会战胜Z-Fitting。

Offset只会对ZTest的条件做修正,但是并不会改变最后的Z缓冲。

12.SeparateSpecular  On|Off

开启或关闭顶点光照相关的平行高光颜色

13.ColorMaterial   AmbientAndDiffus | Emission

当计算顶点光照时使用没顶点颜色

  • Texture Setup(纹理设置)---圣典

SetTexture[TexturePropertyName{ Texture Block }],分配一个纹理,Texture Name必须定义为一个纹理属性。如何应用纹理被定义在TextrueBlock中。纹理块控制纹理如何被应用。如上面Pass通道里面的Material代码例子。

combine src1*src2 将源1和源2的元素相乘。结果会比单独输出任何一个都要暗
combine src1 + src2 将源1和源2的元素相加。结果回避单独输出任何一个都要亮
combine src1 - src2 源1减去源2
combine src1 +- src2 先相加,然后减去0.5(添加了一个符号)
combine src1 lerp (src2)src3

使用源2的透明度通道值在源3和源1中进行差值,注意差值是反向的:

当透明度值是1时使用源1,透明度为0时使用源3

combine src1 * src2 + src3 源1和源2的透明度相乘,然后加上源3
combine src1 * src2 +- src3 源1和源2的透明度相乘,然后和源3座符号加
combine src1 * src2 - src3 源1和源2的透明度相乘,然后和源3相减

GrabPass (用于获取当前屏幕的纹理)

有两种方式将GrabPass放入到SubShader里面:

GrabPass{} 能捕获当前屏幕的内容到一个纹理中,纹理能在后续通道中通过_GrabTexture进行访问。:这种形式的捕获通道将在每一个使用该通道的对象渲染中执行昂贵的屏幕捕获操作。

GrabPass{ "TextureName" } 能捕获屏幕内容到一个纹理中,但只会在每帧中处理第一个使用给定纹理名的纹理的对象的渲染过程中产生捕获操作。纹理在未来的通道中可以通过给定的纹理名访问。当你在一个场景中拥有多个使用GrabPass的对象时将提高性能。

Shader "Custom/GrabPass"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Overlay" }//把渲染队列拉到最高overlay
        LOD 100

        //
        GrabPass {} // 截图通道, 后面使用_GrabTexture访问截屏纹理
        // end 
        Pass
        {
            name "ONE"

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            
            sampler2D _GrabTexture;//使用前重新声明一下
            float4 _GrabTexture_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _GrabTexture);//使用
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                //fixed4 col = tex2D(_GrabTexture, i.uv);//这个会使画面倒置了
				float4 col = tex2D(_GrabTexture,float2(1-i.uv.x,1-i.uv.y));
                return col;
            }
            ENDCG
        }
    }
}

 

 

UsePass (实际上不是Pass,而是调用其他的Pass的指令)

       某些着色器重用其他着色器中已存在的通道,减少重复的代码。例如,在许多像素光照着色器中,阴影色或顶点光照通道在在相应的顶点光照着色器中是相同的。UsePass命令只是包含了另一个着色器的给定通道。例如当如下的命令可以使用内置的高光着色器中的名叫"Base"的通道:

:Unity内部会把所有Pass的名称转换成大写字母的表示,因此,在使用UsePass命令时必须使用大写形式的名字)

UsePass "Specular/BASE"
Shader "Unlit/myshader1"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Pass
        {
            Name "MYPASS"

            CGPROGRAM
         }
      }
}


Shader "Unlit/myshader2"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        //Unity内部会把所有Pass的名称转换成大写字母的表示,因此,
        //在使用UsePass命令时必须使用大写形式的名字
        UsePass "Unlit/myshader1/MYPASS"
    }
}

 

Fog { Fog Commands}

Model  Off | Gloal | Linear | Exp | Exp2

定义雾模式。全是全局的,依据雾在渲染设定中是否打开确定可从无变化到平方值。

Color    ColorValue

设定雾的颜色。

Density  FloatValue

以指数的方式,设定雾的密度

Range  FloatValue,FloatValue

为Linear的雾设定远近距离

全局雾:

  RenderSettings.fog = true;
  RenderSettings.fogColor = Color.red;
  RenderSettings.fogMode = FogMode.Linear;
  RenderSettings.fogStartDistance = 0;
  RenderSettings.fogEndDistance = 10;

 

Shader "Custom/LogoShader" {
    Properties {  
        _MainTex ("Base (RGB)", 2D) = "white" {}  
        _From("From", Float) = 0  
        _To("To", Float) = 10  
        _Density("Density", Float) = 10  
  
        _Color ("Color", Color) = (1,1,1,0)   
    }  
    SubShader {  
        Tags { "RenderType"="Opaque" }  
        LOD 200  
  
        Fog { Mode Linear Color[_Color] Range [_From],[_To] Density [_Density]}  
        //Fog { Mode Exp    Color[_Color] Range [_From],[_To] Density [_Density]}  
        //Fog { Mode Exp2   Color[_Color] Range [_From],[_To] Density [_Density]}  
        //Fog { Mode Linear Color (0.87,0.87,0.87,1) Density 0.1  Range 0,300 }
        //Fog{ Mode Linear Color(1, 0, 0) Range 0, 10 }

        CGPROGRAM  
        #pragma surface surf Lambert  
  
        sampler2D _MainTex;  
  
        struct Input {  
            float2 uv_MainTex;  
        };  
  
        void surf (Input IN, inout SurfaceOutput o) {  
            half4 c = tex2D (_MainTex, IN.uv_MainTex);  
            o.Albedo = c.rgb;  
            o.Alpha = c.a;  
        }  
        ENDCG  
    }   
    FallBack "Diffuse"  
}  

 

BindChannels

BindChannels命令允许你指定顶点数据如何映射到显卡中。可编程顶点着色器使用时,BindChannels将没有效果。在这种情况下,绑定受顶点着色器输入控制。默认情况下,Unity3D会为你计算并绑定,但在某些清空下,你要使用自定义绑定。

BindChannels{ Bind "Source" , target }

Source可以是下面其中一个:

  • Vertex:vertex position 顶点:顶点的位置
  • Normal:vertex normal 法线:顶点的法线
  • Tangent:vertex tangent 切线:顶点的切线
  • Texcorrd:primary UV coordinate 主要的UV坐标
  • Texcorrd1:secondary UV coordinate 次要的UV坐标
  • Color:per-vertex color 颜色:每个顶点颜色

Target主要和Sourcel里面的这两个Texcorrd,Texcorrd1不一样

  • Texcoord0Texcoord1, ...: texture coordinates for corresponding texture stage 各个纹理处理阶段的纹理坐标
  • Texcoord: texture coordinates for all texture stages 所有纹理处理阶段的纹理坐标

FallBack---->回滚(当本Shader的所有SubShader都不支持当前显卡,就会使用FallBack语句指定的另一个Shader。FallBack最好指定Unity自己预制的Shader实现,因其一般能够在当前所有显卡运行。当SubShader不能执行时,相当于执行默认值

FallBack "Name"  //回归到指定着色器

FallBack Off  //不降级,也不会出现任何出错报警,没有子着色器也会继续运行

CustomEditor---->

 

Other---->

Unity内置着色器(圣典)

你可能感兴趣的:(CG,unity)