shader_shaderlab - CSDN
精华内容
参与话题
  • ShaderGraph从入门到实战

    千人学习 2019-09-27 10:02:05
    大智和你一起学习ShaderGraph,在实战中探索。 课程内容 ShaderGraph的基本使用 丰富的实战案例: · 全息效果 · 边缘光效果 · 溶解效果 ·&...
  • Shader开发从入门到精通

    万人学习 2020-03-15 19:43:15
    Shader编程从入门到精通视频教程,该课程主要分享2D中的Shader与3D中的Shader编程,具体功能包括颜色配置、纹理、UV动画、滤镜等。
  • Shader入门教程(一)

    千次阅读 2019-11-23 17:07:19
    学习Unity有一段时间了,都说Unity想要进阶得学会Shader编程,因此花了一阵子来学习Shader编程。学了之后才发现,Shader并没有我原先想的那么复杂,掌握它的原理和语法后,我们也能用shader编写出自己想要的特效,好...

    学习Unity有一段时间了,都说Unity想要进阶得学会Shader编程,因此花了一阵子来学习Shader编程。学了之后才发现,Shader并没有我原先想的那么复杂,掌握它的原理和语法后,我们也能用shader编写出自己想要的特效,好了,下面我开始详细介绍shader的入门知识。

    我在这篇文章中主要介绍的内容有 
    ①Shader基础知识 
    ②Unity中Shader知识介绍 
    ③Surface Shader语法

    Shader基础知识

    什么是Shader?

    在讲什么是Shader之前我们先看看下面两段代码 

    这里写图片描述

     

    这两段代码实现的功能都是提取 2D 图像上每个像素点的颜色值,第一段代码是用c++写的,在cup上面运行,它需要循环遍历每个像素点,第二段代码是CG代码,在GPU上面运行,它只需要一行代码就能实现同样的功能。GPU是专门用来进行图形处理的,而Shader,就是GPU执行的一段针对3D对象进行操作的程序。

    维基百科上对shader的解释是这样(https://zh.wikipedia.org/wiki/%E7%9D%80%E8%89%B2%E5%99%A8

    Shader(着色器)应用于计算机图形学领域,指一组供计算机图形资源在执行渲染任务时使用的指令,用于计算图像的颜色或明暗。但近来,它也能用于处理一些特殊效果,或者视频后处理。通俗地说,着色器告诉电脑如何用特有的一种方法去绘制物体。

    程序员将着色器应用于图形处理器(GPU)的可编程流水线,来实现三维应用程序。这样的图形处理器有别于传统的固定流水线处理器,为GPU编程带来更高的灵活性和适应性。以前固有的流水线只能进行一些几何变换和像素灰度计算。现在可编程流水线还能处理所有像素、顶点、纹理的位置、色调、饱和度、明度、对比度并实时地绘制图像。着色器还能产生如模糊、高光、有体积光源、失焦、卡通渲染、色调分离、畸变、凹凸贴图、边缘检测、运动检测等效果。

    OpenGL的渲染流程

    知道了什么是shader,我们再来了解一下shader的种类,首先我先介绍一下OpenGL的渲染流程

     

    这里写图片描述

    上图便是OpenGL的渲染流程,其中每一步是干什么的我就不在这篇文章中介绍了,有兴趣的可以看看这篇博客(http://blog.csdn.net/lxdfigo/article/details/8457850),将这个流程简化之后是这样的 
    顶点变换 → 图元装配和光栅化 → 片元纹理映射和着色 → 写入帧缓存

     

    在顶点变换和片元着色这两步时,我们就可以对其编程,进行各种操作,其他的部分我们是没法进行编程的。我们的shader就是作用于顶点变换和片元着色这两个部分的。

    shader的种类

    知道了shader起作用的地点,我们现在可以了解一下shader的种类了。

    shader按管线分类一般分为固定渲染管线与可编程渲染管线。固定渲染管线就是功能固定的管线,比如物体表面光的折射,反射的算法是固定无法修改的,我们只能对这些功能进行配置,比如开启或关闭反射效果,雾化效果等。因为这种管线功能固定,无法在程序上对物体细节的表现给予更多更自由的控制,无法达到更多我们想要的画面效果。所以现在的显卡都是可编程渲染管线,也就是曾经那些我们固定无法修改的部门现在可以编程去修改,自由度高了之后,我们也就能实现更多自己想要的特效了。

    shader的开发语言

    知道了shader的种类,我在来说说shader的开发语言

    HLSL: 主要用于Direct3D。平台:windows。

    GLSL: 主要用于OpenGL。 平台:移动平台(iOS,安卓),mac(only use when you target Mac OS X or OpenGL ES 2.0)

    CG:与DirectX 9.0以上以及OpenGL 完全兼容。运行时或事先编译成GPU汇编代码。CG比HLSL、GLSL支持更多的平台,Unity Shader采用CG/HLSL作为开发语言。

    Unity中Shader知识介绍

    shader在GPU的渲染流程

     

    这里写图片描述

     

    进入GPU运算首先进行的是Vertex Processor顶点处理器,这个部分就需要我们使用Vertex Shader顶点着色器,顶点着色器运算的结果会交给Pixel Processor像素处理器,也就是片段处理器,在这个部分我需要为像素处理编写Pixel Shader像素着色器程序,这部分计算完后就输出了最终我们可以用于在屏幕上的颜色信息,我们把它叫做Frame Buffer帧缓冲。帧缓冲存储的是计算机依次显示所要的数据。

    Unity中shader的类型

    ①Fixed function shader :属于固定渲染管线 Shader, 基本用于高级Shader在老显卡无法显示时的回滚。使用的是ShaderLab语言,语法与微软的FX files 或者NVIDIA的 CgFX类似。

    ②Vertex and Fragment Shader:最强大的Shader类型,属于可编程渲染管线. 使用的是CG/HLSL语法。

    ③Surface Shader:Unity3d推崇的Shader类型,使用Unity预制的光照模型来进行光照运算。使用的也是CG/HLSL语法。

    我们先了解一下这三种shader的异同点。

    相同点: 
    ①都必须从唯一一个根Shader开始 
    ②Properties参数部分,作用及语法完全相同 
    ③具体功能都在SubShader里(Subshader会自上而下运行第一个硬件能支持的) 
    ④SubShader都可以打标签 
    ⑤都可以回滚 
    ⑥都可以处理基本的功能,例如光照漫反射(Diffuse)以及镜面反射(Specular)。但是Vertex and Fragment和Surface都能实现Fixed function实现不了的高级功能,例如基于uv计算的效果等等。

    不同点 
    ①Fixed function shader以及Vertex and Fragment Shader在subshader下面还有pass{}结构,但是Surface Shader,已经将具体内容打包在光照模型了,不能加pass{} 
    ②Fixed function shader每句代码之后没有分号“;”, 但是V&F shader以及Surface shader每句代码之后都必须加分号“;” 
    ③核心结构不同 
    Fixed function shader的SunShader中的结构为

    Material{} 
    ……
    SetTexture[_MainTex]{
        ……
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    Vertex and Fragment Shader的核心结构为

    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag   
    ……       
    #include "UnityCG.cginc"
    ENDCG
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Surface Shader的核心结构是

    CGPROGRAM
    #pragma surface surf Lambert
    ……
    ENDCG
    • 1
    • 2
    • 3
    • 4

    可以看到这三种shader的Subshader内的编码实现是不一样的,这三种shader的结构如下图,他们的不同点都在SubShader里面 

    这里写图片描述

     

    因为Unity推荐Surface Shader,所以文章直接分析Surface Shader的用法,其他两种shader就不做过多介绍了。

    Surface Shader语法

    在Unity的项目面板中直接创建一个Stander surface shader,默认生成的代码如下

    Shader "Custom/DiffuseShader" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)       //设置一个默认的颜色值
            _MainTex ("Albedo (RGB)", 2D) = "white" {}  //默认的白色纹理
            _Glossiness ("Smoothness", Range(0,1)) = 0.5  //默认的光泽度
            _Metallic ("Metallic", Range(0,1)) = 0.0    //金属光泽度
        }
        SubShader {
            Tags { "RenderType"="Opaque"}
            LOD 200
    
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf Standard fullforwardshadows
    
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
    
    
            fixed4 _Color;
            sampler2D _MainTex;
            half _Glossiness;
            half _Metallic;
    
    
            struct Input {
                float2 uv_MainTex;
            };
    
    
    
            void surf (Input IN, inout SurfaceOutputStandard o) {
                // Albedo comes from a texture tinted by color
                fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                // Metallic and smoothness come from slider variables
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    接下来我来介绍一下这段代码

    Properties {}

    Properties{}是定义着色器属性的,在这里定义的属性将被作为输入提供给所有的子着色器。属性定义的格式如下

    _Name(“Display Name”, type) = defaultValue[{options}]

    _Name代表的是属性名,如Color,MainTex,Glossiness ,Metallic 等

    ”Display Name”则是在Inspector中显示的名字

    type代表属性:

        Color - 一种颜色,由RGBA(红绿蓝和透明度)四个量来定义;
        2D - 一张2的阶数大小(256,512之类)的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来;
        Rect - 一个非2阶数大小的贴图;
        Cube - 即Cube map texture(立方体纹理),简单说就是6张有联系的2D贴图的组合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应点的采样;
        Range(min, max) - 一个介于最小值和最大值之间的浮点数,一般用来当作调整Shader某些特性的参数(比如透明度渲染的截止值可以是从0至1的值等);
        Float - 任意一个浮点数;
        Vector - 一个四维数;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这段默认Properties在Inspector中的显示效果如下 

    这里写图片描述

     

    SubShader{}

    Tags :tags标签是三种类型的shader都具有的标签,它决定了硬件什么调用该子着色器

    Tags标签里面默认的“RenderType”=”Opaque”,是告诉系统应该在渲染非透明物体时调用这个SubShader
    “RenderType”=”Transparent”表示在渲染含有透明效果的物体时调用该Sunshader,
    
    Tags里面还有许多其他的我们可选的标签
    ①.”Queue”:定义渲染顺序。预制的值有这些 
        ”Background”。值为1000。比如用于天空盒。
        ”Geometry”。值为2000。大部分物体在这个队列。不透明的物体也在这里。
        ”AlphaTest”。值为2450。已进行AlphaTest的物体在这个队列。 
        ”Transparent”。值为3000。透明物体。 
        ”Overlay”。值为4000。比如镜头光晕。 
        用户可以定义任意值,比如”Queue”=”Geometry+10”
    ②“RenderType”:定义渲染类型。预制的值有这些
        ”Opaque”:绝大部分不透明的物体都使用这个; 
        ”Transparent”:绝大部分透明的物体、包括粒子特效都使用这个; 
        ”Background”:天空盒都使用这个; 
        ”Overlay”:GUI、镜头光晕都使用这个; 
    ③”ForceNoShadowCasting”:定义物体是否有阴影效果
        “true”。表示有阴影
        “false”。表示没有阴影
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    LOD:Level of Detail的缩写,它表示着色器的细节层次效果。在某些硬件比较差的系统上,我们可以设置一个低一点的值,减少细节的显示。Unity内置shader的LOD值如下

    • VertexLit kind of shaders = 100
    • Decal, Reflective VertexLit = 150
    • Diffuse = 200
    • Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
    • Bumped, Specular = 300
    • Bumped Specular = 400
    • Parallax = 500
    • Parallax Specular = 600

    CGPROGRAM 到ENDCG这一部分就这这个shader的核心内容了

    #pragma surface surf Standard fullforwardshadows
    • 1

    这段编译指令声明了我们要写一个Surface Shader,并指定了光照模型。它的写法是这样的

    #pragma surface surfaceFunction lightModel [optionalparams]
    • 1
    • surface - 声明的是一个表面着色器
    • surfaceFunction - 着色器代码的方法的名字
    • lightModel - 使用的光照模型。

    这段代码默认的surfaceFunction为surf,我们可以在源码的底部看到在这儿声明了的surf函数。默认的lightModel为Standard。

    下面我先介绍一下lightModel光照模型

    • Lambert:该光照模型能很好的表示粗糙表面的光照,但不能表现出镜面反射高光

    • Toon:最近在游戏中常用的风格之一即是Toon shading(又称 cel shading).这是一种非逼真渲染风格,通过改变了光在一个模型上反射实际情况来给人以手绘的感觉

    • BlinnPhong:仿真镜面反射材料

    • Standard:Unity5中默认的光照模式是Standard, 其引入了 物理渲染 (PBR), 但是与其它光照模型没有什么不同。相比于朗伯反射, PBR提供了一个更加逼真的光线物体作用模型,PBR考虑了材料的物理属性, 比如能量守恒以及光的散射

    接下来的这段代码

       fixed4 _Color;
       sampler2D _MainTex;
       half _Glossiness;
       half _Metallic;
    • 1
    • 2
    • 3
    • 4

    我们可以发现 _Color,_MainTex,_Glossiness,_Metallic都shader属性的声明,在上面的Properties 中已经声明过了这些属性,但是在这段CG程序,要想访问在Properties中所定义的变量的话,必须使用和之前变量相同的名字再次进行声明,其实就是链接在上面properties中声明的属性。

    我再来介绍一下shader中常用的数据类型

    3种基本数值类型:float、half和fixed。 
    这3种基本数值类型可以再组成vector和matrix,比如half3是由3个half组成、float4x4是由16个float组成。

    float:32位高精度浮点数。 
    half:16位中精度浮点数。范围是[-6万, +6万],能精确到十进制的小数点后3.3位。 
    fixed:11位低精度浮点数。范围是[-2, 2],精度是1/256。 
    Sampler2D:2D纹理属性

    接下来就是Input结构体

    struct Input {
        float2 uv_MainTex;
    };
    • 1
    • 2
    • 3

    这个结构体和surf函数中的另一个参数inout结构体是相对的,一个代表输入,一个代表输出。我们可以这样理解这两个结构体,你定义输入数据结构(Inputs Struct)、编写自己的Surface函数处理输入、最终输出修改过后的SurfaceOutput。Input其实是需要我们去定义的结构,所以我们可以把所需要参与计算的数据都放到这个Input结构中,传入surf函数使用

    默认的Input结构体中有一个uv_MainTex参数,代表了纹理的UV值,我们便可以在surf函数中直接使用这个参数了。

    知道了Input的结构体,我们在来看看Output的结构体

    struct SurfaceOutput
    {
        fixed3 Albedo;  // diffuse color  漫反射的颜色值。
        fixed3 Normal;  // tangent space normal, if written 法线坐标
        fixed3 Emission;  //自发光颜色
        half Specular;  // specular power in 0..1 range 镜面反射系数
        fixed Gloss;    // specular intensity   光泽系数
        fixed Alpha;    // alpha for transparencies  透明度系数
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    现在我们在来看看surf函数里面的内容,就已经能够看懂了

    我们现在在来看看surf函数里面的代码,就能知道里面是什么意思了

            void surf (Input IN, inout SurfaceOutputStandard o) {
                fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;               //将物体显示的漫反射颜色设置成在纹理的颜色值
                o.Metallic = _Metallic;         //将物体显示的金属光泽设置成在properties中定义的光泽
                o.Smoothness = _Glossiness;     //设置物体显示的光滑度
                o.Alpha = c.a;                  //设置物体显示的透明度
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tyuiof/article/details/52754300
    展开全文
  • Shader学习建议

    千次阅读 2019-03-11 21:27:32
    而游戏中酷炫逼真的效果又是由shader来控制实现的。所以想要提高自己技能就必须啃下shader这个硬骨头。 以下提供本人学习shader的心路历程。由于每个人学习方式不同,所以下面建议不适应所有人。学习过程如下: ...

    作为一名从业六年的游戏开发人员,搭过框架也做过优化。但是对图形渲染这块不了解。而游戏中酷炫逼真的效果又是由shader来控制实现的。所以想要提高自己技能就必须啃下shader这个硬骨头。

    以下提供本人学习shader的心路历程。由于每个人学习方式不同,所以下面建议不适应所有人。学习过程如下:
    1.作为一名客户端开发人员,首先要会应用shader做出上级分配的任务才是优先级最高的事情。几乎所有游戏引擎都提供了shader的上层封装,这也就更方便我们应用shader了。如:unity引擎中提供了unity shader,它是在底层图形api接口上做的一层封装,我们可以手写unity shader或者用unity的shader graph来拖拽实现想要的效果。unity shader的学习可以参考《Unity Shader入门精要》这本书,也可以参考本人unity shader专栏,里面是对《Unity Shader入门精要》学习的总结。

    2.会应用shader后就需要去了解底层的实现了。虽然引擎帮我们封装了接口,也提供了工具去写引擎定制的shader来帮我们实现想要的效果。但是作为unity长期用户来说,unity的bug还真不少,谁知道某一天会不会在渲染这个给你来一个bug,虽然引擎最终会修复,但也是漫长的等待。此时就必须对引擎的渲染底层有所了解,这样出问题了知道是哪里的问题并立马进行修复或者给出替代解决方案,这一点很重要。

    3.底层api选择:现在市面上主要有苹果公司的metal,微软公司的direct 3d以及跨平台的opengl。metal主要是针对苹果的a系列处理器做了优化,在苹果产品上的确性能很高。direct 3d主要在微软产品上应用,而且曾经跟opengl有场你死我活的api之争。但是很多开发者和硬件厂商还是选择支持opengl,就因为它的跨平台和高性能的特性。所以毫无悬念,本人这里也是选择opengl作为底层图形api学习的标准。

    4.opengl的学习资料:首先要了解opengl的发展历程,这个https://www.cnblogs.com/George1994/p/6418013.html链接中记录了大部分的opengl版本变化,最新的opengl已经发布到4.6了,详细的版本信息可以参照opengl官网。现在市面上比较受欢迎的书籍就是《OpenGL超级宝典(中文第5版3.3或者英文第七版4.5)》和《OpenGL编程指南(中文第九版4.5)》。建议先学习opengl超级宝典第五版,虽然现在opengl已经到最新的4.6了,而超级宝典第五版里面只是到3.3,但是并没有关系,因为3.3到4.6之间的核心架构都没变,只是引进了一些新的功能以及改善了某些功能的实现而已。而且书中细节讲解的很清晰,还有大量的例子来佐证,非常适合opengl初学者。当看完超级宝典第五版后建议再学习下opengl编程指南第九版,该书针对opengl4.5版本,不仅引入了很多有意思和高大上的技能讲解,可以继续更深层次学习3.3往后的版本技能。还可以当做api参考书,无疑是opengl界的新华字典。

    5.开始学习之旅啦!!!我会建立两个专栏,分别是opengl超级宝典第五版和opengl编程指南第九版。里面会总结学习的心得。有兴趣的朋友可以关注下。专栏会在周末空闲时间不定期更新,虽然历程有些漫长,但是静下心来慢慢撸,总会撸完的。

    展开全文
  • Shader各种效果

    千次阅读 2018-05-16 09:09:41
    1.Shader1.0的Alpha测试Shader "Hidden/AlphaTestShader1.0" { Properties { _MainTex ("Texture", 2D) = "white" {} _AlphaTest("Alpha值",float) = 0 } ...

    1.Shader1.0的Alpha测试

    Shader "Hidden/AlphaTestShader1.0"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    		_AlphaTest("Alpha值",float) = 0
    	}
    	SubShader
    	{
    		AlphaTest Greater [_AlphaTest]
    		Pass
    		{
    			SetTexture[_MainTex]
    			{
    				combine texture
    			}
    		}
    	}
    }
    

    2.Shader2.0

    2.1 轮廓自发光

            两个Pass,一个渲染原本的贴图,一个渲染颜色,将顶点的xy方向扩大。

    Shader "Custom/OutLine2.0"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    		_TestColor("轮廓自发光颜色",Color)=(1,1,1,1)
    		_Width("轮廓宽度",Float)=1.1
    	}
    	SubShader
    	{
    		// No culling or depth
    		//Cull Off ZWrite Off ZTest Always//后期屏蔽的
    
    		Pass
    		{
    
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				float4 vertex : SV_POSITION;
    			};
    
    			float _Width;/*****************************/
    			v2f vert (appdata v)
    			{
    				v2f o;
    				
    				v.vertex.xy *= _Width;/*********************/
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = v.uv;
    				return o;
    			}
    			
    			sampler2D _MainTex;
    
    			Vector _TestColor;/************************/
    			fixed4 frag (v2f i) : SV_Target
    			{
    				fixed4 col = tex2D(_MainTex, i.uv);
    				// just invert the colors
    				//col.rgb = 1 - col.rgb;
    				return fixed4(_TestColor);/*********************/
    				//return col;
    			}
    			ENDCG
    		}
    
    			Pass
    			{
    				ZTest Always
    				CGPROGRAM
    				#pragma vertex vert
    				#pragma fragment frag
    
    				#include "UnityCG.cginc"
    
    				struct appdata
    				{
    					float4 vertex : POSITION;
    					float2 uv : TEXCOORD0;
    				};
    
    				struct v2f
    				{
    					float2 uv : TEXCOORD0;
    					float4 vertex : SV_POSITION;
    				};
    
    				v2f vert(appdata v)
    				{
    					v2f o;
    					o.vertex = UnityObjectToClipPos(v.vertex);
    					o.uv = v.uv;
    					return o;
    				}
    
    				sampler2D _MainTex;
    
    				fixed4 frag(v2f i) : SV_Target
    				{
    					fixed4 col = tex2D(_MainTex, i.uv);
    				// just invert the colors
    				//col.rgb = 1 - col.rgb;//后期屏蔽的
    				
    				return col;
    				}
    				ENDCG
    			}
    	}
    }
    

    2.2 Alpha测试

    Shader "Hidden/AlphaTestShader2.0"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    		_AlphaValue("Alpha值",float)=0
    	}
    	SubShader
    	{
    		// No culling or depth
    		//Cull Off ZWrite Off ZTest Always
    			Blend SrcAlpha OneMinusSrcAlpha//打开Alpha通道
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				float4 vertex : SV_POSITION;
    			};
    
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = v.uv;
    				return o;
    			}
    			
    			sampler2D _MainTex;
    
    			float _AlphaValue;
    			fixed4 frag (v2f i) : SV_Target
    			{
    				fixed4 col = tex2D(_MainTex, i.uv);
    
    			if (col.a < _AlphaValue)
    			{
    				return fixed4(0, 0, 0, 0);
    			}
    			else
    			{
    				return col;
    			}
    			}
    			ENDCG
    		}
    	}
    }
    

    3.Shader2.0 的UV动画

    3.1 UV滚动(流动)

    Shader "Custom/River"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    		_SpeedY("Y向流动速度",Range(0,10))=1.0
    		_SpeedX("X向流动速度",Range(0,20)) = 0
    	}
    	SubShader
    	{
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				float4 vertex : SV_POSITION;
    			};
    
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = v.uv;
    				return o;
    			}
    			
    			sampler2D _MainTex;
    
    
    			float _SpeedY;/*增***********************/
    			float _SpeedX;/*增***********************/
    			fixed4 frag (v2f i) : SV_Target
    			{
    				float2 tempUV = i.uv;/*增***********************/
    				tempUV.x += _Time.x*_SpeedX;/*增***********************/
    				tempUV.y += _Time.y*_SpeedY;/*增***********************/
    
    				fixed4 col = tex2D(_MainTex, tempUV);/*改***********************/
    				
    				return col;
    			}
    			ENDCG
    		}
    	}
    }
    

    3.2 UV波动(wave)

    Shader "Custom/Wave"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    		_Arange("波动幅度",float) = 1
    		_Frenquncy("波动频率",float)=0.5
    		_Speed("波动速度", float) = 0.5
    	}
    	SubShader
    	{
    		
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				float4 vertex : SV_POSITION;
    			};
    
    			float _Arange;/*增******************************/
    			float _Frenquncy;/*增******************************/
    			float _Speed;/*增******************************/
    			v2f vert(appdata v)
    			{
    
    				v2f o;
    
    				float timer = _Time.y*_Speed;/*增******************************/
    				float waver = _Arange * sin(timer + v.vertex.x*_Frenquncy);/*增******************************/
    
    				v.vertex.y = v.vertex.y + waver;/*增******************************/
    
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = v.uv;
    				return o;
    			}
    			
    			sampler2D _MainTex;
    
    			
    
    			fixed4 frag (v2f i) : SV_Target
    			{
    				fixed4 col = tex2D(_MainTex, i.uv);
    				// just invert the colors
    				//col.rgb = 1 - col.rgb;
    				return col;
    			}
    			ENDCG
    		}
    	}
    }
    

    3.3 UV旋转(Loading)

    Shader "Custom/Loading_Icon"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    		_RotateSpeed("旋转速度",float) = 15.0
    	}
    	SubShader
    	{
    		// No culling or depth
    		//Cull Off ZWrite Off ZTest Always
    
    		Blend SrcAlpha OneMinusSrcAlpha//打开Alpha通道
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				float4 vertex : SV_POSITION;
    			};
    
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = v.uv;
    				return o;
    			}
    			
    			sampler2D _MainTex;/**增******************************/
    			float _RotateSpeed;/**增******************************/
    			fixed4 frag (v2f i) : SV_Target
    			{
    				/**增******************************/
    				float2 tempUV = i.uv;
    
    				tempUV -= float2(0.5, 0.5);//1.平移到原点
    										  
    				if (length(tempUV) > 0.5)//防止对角线多余的长度显示
    				{
    					return fixed4(0, 0, 0, 0);
    				}
    
    				/*2.绕z轴旋转******************************/
    				float2 finalUV = 0;
    				float angle = _Time.x*_RotateSpeed;
    
    				finalUV.x = tempUV.x*cos(angle) - tempUV.y*sin(angle);
    				finalUV.y = tempUV.x*sin(angle) + tempUV.y*cos(angle);
    
    				finalUV += float2(0.5, 0.5);//3.将贴图平移回原位置
    				/**增******************************/
    				fixed4 col = tex2D(_MainTex, finalUV);/**改******************************/
    				
    				return col;
    			}
    			ENDCG
    		}
    	}
    }
    

    3.4 屏幕高斯效果

    3.4.1 Shader

    Shader "Custom/MyShader"
    {
    	Properties
    	{
    		_MainTex ("贴图", 2D) = "white" {}
    		_Amnient("高斯模糊程度",Float) = 0.001
    	}
    	SubShader
    	{
    		// No culling or depth
    		//Cull Off ZWrite Off ZTest Always
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				float4 vertex : SV_POSITION;
    			};
    
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = v.uv;
    				return o;
    			}
    			
    			sampler2D _MainTex;
    
    			float _Amnient;
    			fixed4 frag (v2f i) : SV_Target
    			{
    				float2 tempUV = i.uv;/*增**********************/
    				float ambient = _Amnient;/*增**********************/
    				fixed4 col = tex2D(_MainTex, tempUV);/*改**********************/
    				// just invert the colors
    				//col.rgb = 1 - col.rgb;
    				fixed4 col2 = tex2D(_MainTex, tempUV + float2(-ambient, 0));/*增**********************/
    				fixed4 col3 = tex2D(_MainTex, tempUV + float2(0,-ambient));/*增**********************/
    				fixed4 col4 = tex2D(_MainTex, tempUV + float2(ambient, 0));/*增**********************/
    				fixed4 col5 = tex2D(_MainTex, tempUV + float2(0,ambient));/*增**********************/
    
    				col = (col + col2 + col3 + col4 + col5) / 5.0;/*增**********************/
    				return col;
    			}
    			ENDCG
    		}
    	}
    }
    

    3.4.2 C#

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 需要挂载到相机上
    /// </summary>
    public class CameraMove : MonoBehaviour {
    
        // Use this for initialization
        //public Shader myShader;
        public Material material;
    	void Start () {
            //material = new Material(myShader);
    	}
    	
    	// Update is called once per frame
    	void Update () {
    		
    	}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source">拦截到相机所渲染的图片</param>
        /// <param name="destination">更改后返回的图片,重新交给引擎</param>
        private void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            Graphics.Blit(source, destination, material);
        }
    }
    

    4. Surface5.0

    4.1 UV 滚动

    Shader "Custom/TestParameter" {
    	Properties {
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf Lambert vertex:MyVertex
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    
    		struct Input {
    			float2 uv_MainTex;
    			float3 myColor;
    		};
    
    		
    		fixed4 _Color;
    
    		void MyVertex(inout appdata_base v,out Input o)
    		{
    			UNITY_INITIALIZE_OUTPUT(Input, o);
    			o.myColor = _Color.rgb*abs(v.normal);
    		}
    
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
    			o.Albedo = c.rgb*IN.myColor;
    			
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    4.2 高光

    Shader "Custom/CustomLighting" {
    	Properties {
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_SpeclPower("高光强度",float) = 1
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf Simple
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    
    		struct Input {
    			float2 uv_MainTex;
    		};
    
    
    		fixed4 _Color;
    
    		
    		UNITY_INSTANCING_BUFFER_START(Props)
    			// put more per-instance properties here
    		UNITY_INSTANCING_BUFFER_END(Props)
    
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    			o.Albedo = c.rgb;
    			
    			o.Alpha = c.a;
    		}
    
    		float _SpeclPower;
    		///自定义的灯光入口函数
    		half4 LightingSimple(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
    		{
    			float NDotL = dot(lightDir, s.Normal);
    
    			half4 result = 0;
    			//result.rgb = s.Albedo* _LightColor0*NDotL*atten;//漫反射
    
    
    			half3 H = viewDir - lightDir;
    			float HDotN = dot(H, s.Normal);
    
    			result.rgb = s.Albedo* _LightColor0*NDotL*atten+HDotN* s.Albedo* _LightColor0*_SpeclPower;
    			result.a = s.Alpha;
    
    			return result;
    		}
    
    		ENDCG
    	}
    	FallBack "Diffuse"
    

    }

    4.3 法线贴图

            可以使对比度增强,使凸的地方看起来更凸。

    Shader "Custom/NormalMap" {
    	Properties {
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_NormalMap("法线贴图", 2D) = "white" {}
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf Lambert
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    		sampler2D _NormalMap;
    		struct Input {
    			float2 uv_MainTex;
    			float2 uv_NormalMap;
    		};
    
    	
    		fixed4 _Color;
    
    		
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    			
    			o.Normal= UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
    			o.Albedo = c.rgb;
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    4.4 边缘自发光

    Shader "Custom/NormalOutLine" {
    	Properties {
    		_Color ("自发光颜色", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_NormalTex("法线贴图", 2D) = "white" {}
    		_EmisionPower("自发光强度",float) = 1
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf Lambert
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    		sampler2D _NormalTex;
    		struct Input {
    			float2 uv_MainTex;
    			float2 uv_NormalTex;
    
    			float3 viewDir;
    		};
    
    		
    		fixed4 _Color;
    		float _EmisionPower;
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
    			o.Albedo = c.rgb;
    
    			//读取法线
    			float3 tempNormal= UnpackNormal(tex2D(_NormalTex, IN.uv_NormalTex));
    			
    			o.Normal = tempNormal;
    			//算出法线和视角的点乘
    			float tempFloat=1- clamp(dot(IN.viewDir, tempNormal),0, 1);//clamp()让取值变到一个范围
    			
    			o.Emission = _Color *pow(tempFloat,_EmisionPower);
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    4.5 Fog

        当需要在某个物体周围呈现雾效,而不是整个场景中呈现雾效,就需要写Shader。

    Shader "Custom/TestFog" {
    	Properties {
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_FogStart("雾的起点",float) = 1
    			_FogEnd("雾的终点",float) = 1
    			_FogColor("雾的颜色",Color)=(1,1,1,1)
    	}
    		SubShader{
    			Tags { "RenderType" = "Opaque" }
    			LOD 200
    
    			CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf   Lambert    vertex:MyVertex    finalcolor:FinalColor
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    
    		struct Input {
    			float2 uv_MainTex;
    
    			float fogData;
    		};
    
    		
    		fixed4 _Color;
    		float _FogStart;
    		float _FogEnd;
    		fixed4 _FogColor;
    		void FinalColor(Input IN,SurfaceOutput o,inout fixed4 color)
    		{
    			//color *= float4(1, 0, 0, 1);
    
    			color = lerp(_FogColor, color, IN.fogData);
    		}
    
    		
    		void MyVertex(inout appdata_full v, out Input data)
    		{
    			UNITY_INITIALIZE_OUTPUT(Input, data);//初始化
    			
    			float tempZ = _FogEnd - length(UnityObjectToViewPos(v.vertex).xyz);
    
    			data.fogData = tempZ/(_FogEnd- _FogStart);
    		}
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    			o.Albedo = c.rgb;
    			
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    4.6 菲尼尔反射

    Shader "Custom/TestFresnel" {
    	Properties {
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_CubeMap("CubeMap",Cube) = ""{}
    		_Rate("折射率",float) = 1
    
    		_FresnelBias("菲尼尔偏移",float) = 1
    			_FresnelScale("菲尼尔缩放系数",float) = 1
    			_FresnelPower("菲尼尔指数",float) = 0.5
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf Lambert vertex:MyVertex
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    		samplerCUBE _CubeMap;
    		struct Input {
    			float2 uv_MainTex;
    			float3 worldRefl;//反射
    
    			float refract;//折射
    			float reflectFact;//定义的反射系数
    
    		};
    
    		
    		fixed4 _Color;
    		float _Rate;
    		float _FresnelBias;
    		float  _FresnelScale;
    		float	_FresnelPower;
    		void MyVertex(inout appdata_full v, out Input data)
    		{
    			UNITY_INITIALIZE_OUTPUT(Input, data);//初始化
    
    			//右世界变成物体的
    			float3 localNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
    			//入射角
    			float3 viewDir = -WorldSpaceViewDir(v.vertex);
    
    			data.refract = refract(viewDir, localNormal, _Rate);
    
    			data.reflectFact = _FresnelBias + _FresnelScale * pow(1 + dot(viewDir, localNormal), _FresnelPower);
    		}
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			//fixed4 cflect = tex2D (_MainTex, IN.worldRefl);//反射
    			//fixed4 cfract = tex2D(_MainTex, IN.refract);
    
    			fixed4 cflect = texCUBE(_CubeMap, IN.worldRefl);//反射
    			fixed4 cfract = texCUBE(_CubeMap, IN.refract);
    
    
    			o.Albedo = IN.reflectFact*cflect.rgb + (1 - IN.reflectFact)*cfract.rgb;
    			
    			
    			o.Alpha = cflect.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    4.7 BRDF

            双向反射分布函数(Bidirectional Reflectance Distribution Function,BRDF)用来定义给定入射方向上的辐射照度(irradiance)如何影响给定出射方向上的辐射率(radiance)。更笼统地说,它描述了入射光线经过某个表面反射后如何在各个出射方向上分布--这可以是从理想镜面反射到漫反射、各向同性(isotropic)或者各向异性(anisotropic)的各种反射。

    Shader "Custom/TestBRDF" {
    	Properties {
    		_SpeColor ("高光颜色", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_SpecPower("高光强度",float)=1
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf  BRDFLigthing
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    
    		struct Input {
    			float2 uv_MainTex;
    		};
    
    		
    		fixed4 _SpeColor;
    		float _SpecPower;
    
    		#define PI 3.1415926
    		half4 LightingBRDFLigthing(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
    		{
    			float3 H = normalize(lightDir + viewDir);
    			float3 N = normalize(s.Normal);
    			
    			float d = (_SpecPower + 2)*pow(dot(N, H),_SpecPower) / 8.0;
    
    			float f = _SpeColor + (1 - _SpeColor)*pow(1 - dot(H, N), 5);
    
    			float k = 2 / (sqrt(PI*(_SpecPower + 2)));
    
    			float v = 1 / (dot(N, lightDir)*(1 - k) + k)*(dot(N, viewDir)*(1 - k) + k);
    
    
    			float all = d * f*v;
    			float diff = dot(lightDir, N);
    
    			float tempResult = all + (1 - all)*diff;
    
    			half4 finalColor = 0;
    			finalColor.rgb = tempResult * s.Albedo*_LightColor0.rgb;
    
    			finalColor.a = s.Alpha;
    
    			return finalColor;
    		}
    
    
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
    			o.Albedo = c.rgb;
    			
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    5. CubeMap

    5.1 真反射

        利用CubeMap做真反射;新建一个相机,对准需要反射的内容,新建一个Render Texture,并将此Render Texture赋予反射摄像机的Target Texture;新建一个材质球(标准材质球即可),在贴图通道赋予新建的Render Texture,最后将材质赋予需要有反射性的物体,该物体就会实时反射后一个新建摄像机的内容。但是真反射非常消耗性能。


    5.2 假反射

            也需要建一个需要反射出的内容的CubeMap,一般需要反射的为天空盒。

    Shader "Custom/FalseRelf" {
    	Properties {
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_CubeMap("CubeMap",Cube) = ""{}
    		_CubePower("CubePower",float) = 1
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf Lambert
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    		
    	samplerCUBE _CubeMap;
    		struct Input {
    			float2 uv_MainTex;
    
    			float3 worldRefl;//反射角
    		};
    
    		
    		fixed4 _Color;
    		float _CubePower;
    		
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    
    			o.Emission= texCUBE(_CubeMap, IN.worldRefl)*_CubePower;
    			o.Albedo = c.rgb;
    			
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    

    }

    5.3 折

            也需要建一个需要折射看到的内容的CubeMap。

    Shader "Custom/Refract" {
    	Properties {
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_Rate("折射率",float) = 1
    		_CubeMap("CubeMap",Cube) = ""{}
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
    		#pragma surface surf Lambert vertex:MyVertex
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		sampler2D _MainTex;
    		samplerCUBE _CubeMap;
    		struct Input {
    			float2 uv_MainTex;
    
    			float3 refr;
    		};
    
    		float _Rate;
    		void MyVertex(inout appdata_full v,out Input data)
    		{
    			UNITY_INITIALIZE_OUTPUT(Input, data);//初始化
    
    			//右世界变成物体的
    			float3 localNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
    
    			//入射角
    			float3 viewDir=- WorldSpaceViewDir(v.vertex);
    
    			data.refr= refract(viewDir, localNormal, _Rate);
    		}
    		fixed4 _Color;
    		
    		
    		void surf (Input IN, inout SurfaceOutput o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    
    			o.Emission= texCUBE(_CubeMap, IN.refr).rgb;
    			o.Albedo = c.rgb;
    
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    展开全文
  • Unity3D Shader 入门

    万次阅读 多人点赞 2015-06-16 15:37:19
    Shader的种类Unity Shader 是将传统的硬件Shader(由 Cg / HLSL编写)嵌入到独有的描述性结构中而形成的一种代码生成框架,最终会自动生成各硬件平台自己的Shader,从而实现跨平台。Unity Shader 分为 表面着色器...

    什么是Shader

    Shader(着色器)是一段能够针对3D对象进行操作、并被GPU所执行的程序。Shader并不是一个统一的标准,不同的图形接口的Shader并不相同。OpenGL的着色语言是GLSL, NVidia开发了Cg,而微软的Direct3D使用高级着色器语言(HLSL)。而Unity的Shader 是将传统的图形接口的Shader(由 Cg / HLSL编写)嵌入到独有的描述性结构中而形成的一种代码生成框架,最终会自动生成各硬件平台自己的Shader,从而实现跨平台。

    Unity Shader 其实并不难,初学者往往很迷惑是因为它有太多固定的命令和结构,而这些命令又需要我们对3D渲染有一定的了解才能知道它们是做什么的。


    Shader种类

    OpenGL和Direct3D都提供了三类着色器:

    • 顶点着色器:处理每个顶点,将顶点的空间位置投影在屏幕上,即计算顶点的二维坐标。同时,它也负责顶点的深度缓冲(Z-Buffer)的计算。顶点着色器可以掌控顶点的位置、颜色和纹理坐标等属性,但无法生成新的顶点。顶点着色器的输出传递到流水线的下一步。如果有之后定义了几何着色器,则几何着色器会处理顶点着色器的输出数据,否则,光栅化器继续流水线任务。
    • 像素着色器(Direct3D),常常又称为片断着色器(OpenGL):处理来自光栅化器的数据。光栅化器已经将多边形填满并通过流水线传送至像素着色器,后者逐像素计算颜色。像素着色器常用来处理场景光照和与之相关的效果,如凸凹纹理映射和调色。名称片断着色器似乎更为准确,因为对于着色器的调用和屏幕上像素的显示并非一一对应。举个例子,对于一个像素,片断着色器可能会被调用若干次来决定它最终的颜色,那些被遮挡的物体也会被计算,直到最后的深度缓冲才将各物体前后排序。
    • 几何着色器:可以从多边形网格中增删顶点。它能够执行对CPU来说过于繁重的生成几何结构和增加模型细节的工作。Direct3D版本10增加了支持几何着色器的API, 成为Shader Model 4.0的组成部分。OpenGL只可通过它的一个插件来使用几何着色器。

    Unity Shader 分为 表面着色器(Surface Shader)和 顶点片段着色器(Vertex And Fragment Shader)。

    • 表面着色器(Surface Shader)是Unity提出的一个概念。编写着色器与光照的交互是复杂的,光源有很多类型,不同的阴影选项,不同的渲染路径(正向和延时渲染),表面着色器将这一部分简化。Unity建议使用表面着色器来编写和光照有关的Shader。
    • 顶点片段着色器(Vertex And Fragment Shader)和OpenGL,Direct3D中的顶点着色器和片段着色器没有什么区别。顶点片段着色器比表面着色器使用更自由也更强大,当然光照需要自行处理。Unity也允许在里面编写几何着色器,一般用得不多。

    Shader程序结构

    这里写图片描述

    Shader语法:

    //Shader语法:
    Shader "name" { [Properties] Subshaders [Fallback] [CustomEditor] }
    
    //Properties 语法
    Properties { Property [Property ...] }
    
    // Subshader 语法
    Subshader { [Tags] [CommonState] Passdef [Passdef ...] }
    
    // Pass 语法
    Pass { [Name and Tags] [RenderSetup] }
    
    // Fallback 语法
    Fallback "name"
    • 属性定义(Property Definition):定义Shader的输入,这些输入可以在材质编辑的时候指定
    • 子着色器(SubShader):一个Shader可以有多个子着色器。这些子着色器互不相干且只有一个会在最终的平台运行。编写多个的目的是解决兼容性问题。Unity会自己选择兼容终端平台的Shader运行。
    • 回滚(Fallback):如果子着色器在终端平台上都无法运行,那么使用Fallback指定的备用Shader,俗称备胎。
    • Pass:一个Pass就是一次绘制。对于表面着色器,只能有一个Pass,所以不存在Pass节。顶点片段着色器可以有多个Pass。多次Pass可以实现很多特殊效果,例如当人物被环境遮挡时还可以看到人物轮廓就可以用多Pass来实现。
    • Cg代码:每个Pass中都可以包含自定义的Cg代码,从CGPROGRAM开始到ENDCG结束。

    基本的表面着色器示例:

        Shader "Custom/NewShader" {
            Properties {
                _MainTex ("Base (RGB)", 2D) = "white" {}
            }
            SubShader {
                Tags { "RenderType" = "Opaque" }
                LOD 200
    
                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"
        }

    基本的顶点片段着色器示例:

    Shader "VertexInputSimple" {
      SubShader {
        Pass {
          CGPROGRAM
          #pragma vertex vert
          #pragma fragment frag
          #include "UnityCG.cginc"
    
          struct v2f {
              float4 pos : SV_POSITION;
              fixed4 color : COLOR;
          };
    
          v2f vert (appdata_base v)
          {
              v2f o;
              o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
              o.color.xyz = v.normal * 0.5 + 0.5;
              o.color.w = 1.0;
              return o;
          }
    
          fixed4 frag (v2f i) : SV_Target { return i.color; }
          ENDCG
        }
      } 
    }

    Shader 输入

    Shader的输入有两个来源,一是通过属性定义,一是通过Shader.SetGlobalXXX方法全局设置。

    • 属性定义变量:属性定义中的变量是Shader参数的主要设置方式。 它是随材质变化的,每个使用该Shader的材质都可以在Inspector或者脚本中设置这些参数。这些参数除了在Shader的Properties段中定义外,还需要在Cg中声明方可使用。例如上面表面着色器的例子中我们定义了_MainTex这个类型为2D的属性,还需要在Cg中声明 sampler2D _MainTex。

    • 全局变量:Shader有一组SetGlobalXXX方法,可以对Shader的在Cg中定义而没有在属性中定义的uniform变量进行设置。这个设置是全局的,所有定义了该uniform的Shader都会受到影响。例如我们希望场景随着时间变化而改变颜色,就可以给场景所使用到的Shader设置统一的全局颜色变量,然后在脚本中通过设置该颜色来改变场景的颜色。在角色释放技能时场景变黑也可以使用这个方法。

    Unity shader 中允许定义的属性类型有:

    关键字 类型 对应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” {}
    Rect 非2的阶数大小的贴图 sampler2D _MyRect(“My Rect”, Rect) = “white” {}
    CUBE CubeMap samplerCUBE _MyCubemap (“Cubemap”, CUBE) = “” {}

    注:CubeMap 是6张有联系的2D贴图的组合主要用来做反射效果(比如天空盒和动态反射)


    SubShader

    SubShader中除了Pass,有两个标签值得关注:LOD和Tags

    LOD

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

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

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

    • VertexLit及其系列 = 100
    • Decal, Reflective VertexLit = 150
    • Diffuse = 200
    • Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
    • Bumped, Specular = 300
    • Bumped Specular = 400
    • Parallax = 500
    • Parallax Specular = 600

    Tag

    SubShader可以被若干的标签(tags)所修饰,而硬件将通过判定这些标签来决定什么时候调用该着色器。
    比较常见的标签有:

    • Queue
      这个标签很重要,它定义了一个整数,决定了Shader的渲染的次序,数字越小就越早被渲染,早渲染就意味着可能被后面渲染的东西覆盖掉看不见。
      预定义的Queue有:
    名字 描述
    Background 1000 最早被调用的渲染,用来渲染天空盒或者背景
    Geometry 2000 这是默认值,用来渲染非透明物体(普通情况下,场景中的绝大多数物体应该是非透明的)
    AlphaTest 2450 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑
    Transparent 3000 以从后往前的顺序渲染透明物体
    Overlay 4000 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效)
    • RenderType
      “Opaque”或”Transparent”是两个常用的RenderType。如果输出中都是非透明物体,那写在Opaque里;如果想渲染透明或者半透明的像素,那应该写在Transparent中。这个Tag主要用ShaderReplacement,一般情况下这Tag好像也没什么作用。

    CommonState

    SubShader中可以定义一组Render State,基本上就是一些渲染的开关选项,他们对该SubShader的所有的Pass都有效,所以称Common。这些Render State也可以在每个Pass中分别定义,将在Pass中详细介绍。


    Pass

    Render State

    Render State主要就是控制渲染过程的一些开关选项,例如是否开启alpha blending ,是否开启depth testing。
    常用的Render State有:

    • Cull
      用法:Cull Back | Front | Off
      多边形表面剔除开关。Back表示背面剔除,Front表示正面剔除,Off表示关闭表面剔除即双面渲染。有时候如裙摆,飘带之类很薄的东西在建模时会做成一个面片,这就需要设置Cull Off来双面渲染,否则背面会是黑色。

    • ZWrite
      用法:ZWrite On | Off
      控制当前对象的像素是否写入深度缓冲区(depth buffer),默认是开启的。一般来说绘制不透明物体的话ZWrite开启,绘制透明或半透明物体则ZWrite关闭。
      深度缓冲区:当图形处理卡渲染物体的时候,每一个所生成的像素的深度(即 z 坐标)就保存在一个缓冲区中。这个缓冲区叫作 z 缓冲区或者深度缓冲区,这个缓冲区通常组织成一个保存每个屏幕像素深度的 x-y 二维数组。如果场景中的另外一个物体也在同一个像素生成渲染结果,那么图形处理卡就会比较二者的深度,并且保留距离观察者较近的物体。然后这个所保留的物体点深度保存到深度缓冲区中。最后,图形卡就可以根据深度缓冲区正确地生成通常的深度感知效果:较近的物体遮挡较远的物体。
      理解了深度缓冲区也就理解了为什么绘制透明或半透明物体需要关闭ZWrite, 如果不关闭,透明物体的depth也会被写入深度缓冲区,从而会剔除掉它后面的物体,后面的物体就不会被渲染,看不见后面的物体还能叫透明吗?因此我们使用Alpha blending的时候需要设置ZWrite Off。

    • ZTest
      用法:ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)
      控制如何进行深度测试,也就是上面说的图形处理卡比较二者的深度的比较方法。默认是LEqual。
      值得一提的是使用Aplha blending的时候ZWrite需要关闭但是ZTest是要开启的,因为如果透明物体前面还有不透明物体,透明物体还是应该被遮挡剔除的。

    • Blend
      混合。控制了每个Shader的输出如何和屏幕上已有的颜色混合。
      用法:
      Blend Off: 关闭混合
      Blend SrcFactor DstFactor:最终颜色 = Shader产生的颜色 × SrcFactor + 屏幕上原来的颜色 × DstFactor
      Blend SrcFactor DstFactor, SrcFactorA DstFactor:和上面一样,只是Alpha通道使用后面两个参数计算
      常用的Blend模式有
      Blend SrcAlpha OneMinusSrcAlpha // Alpha blending
      Blend One One // Additive
      Blend OneMinusDstColor One // Soft Additive
      Blend DstColor Zero // Multiplicative
      Blend DstColor SrcColor // 2x Multiplicative
      具体参考这里

    Unity5开始下列固定功能的Shader命令被标记为过时了,这些命令的功能现在建议在Shader(Cg)中通过代码来实现,这里列出是为了方便阅读以前写的Shader:

    • Lighting On | Off
    • Material { Material Block }
    • SeparateSpecular On | Off
    • Color Color-value
    • ColorMaterial AmbientAndDiffuse | Emission
    • Fog { Fog Block }
    • AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) CutoffValue
    • SetTexture textureProperty { combine options }

    Surface Shader

    Surface Shader 隐藏了很多光照处理的细节,它的设计初衷是为了让用户仅仅使用一些指令(#pragma)就可以完成很多事情,并且封装了很多常用的光照模型和函数。相比底层的Vertex And Fragment Shader,Suface Shader的限制比较多,它只能有一次Pass。如果做一些常规的功能又需要光照,可以用Surface Shader写,比较快速便捷。如果要写比较高级的Shader还是建议使用Vertex Shader 和 Fragment Shader。
    Surface Shader主要有两部分组成,一个是#pragma后面的指令,一个是surf函数。
    pragma的语法是 #pragma surface surfaceFunction lightModel [optionalparams]
    - surfaceFunction 通常就是名为surf的函数, 函数名可以自己取
    surf函数原型是:void surf (Input IN, inout SurfaceOutput o)
    - lightModel是Unity内置的光照模型,可以是Lambert,Blinn-Phong等。
    - optionalparams: 包含很多指令 详细参数参考这里

    surf函数主要有一个Input结构的输入和SurfaceOutput结构的输出。

    Input

    Input 结构需要在Shader中定义。它可以包含如下字段, 如果你定义了这些字段就可以在surf函数中使用它们(好神奇的黑科技)

    • 多个贴图的uv坐标,名字必须符合格式uv+贴图名。例如 float2 uv_MainTex
    • float3 viewDir - 视图方向( view direction)值。为了计算视差效果(Parallax effects),边缘光照(rim lighting)等,需要包含视图方向( view direction)值。
    • float4 with COLOR semantic - 每个顶点(per-vertex)颜色的插值。
    • float4 screenPos - 屏幕空间中的位置。 为了反射效果,需要包含屏幕空间中的位置信息。比如在Dark Unity中所使用的 WetStreet着色器。
    • float3 worldPos - 世界空间中的位置。
    • float3 worldRefl - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。 请参考这个例子:Reflect-Diffuse 着色器。
    • float3 worldNormal - 世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。
    • float3 worldRefl; INTERNAL_DATA - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。
    • float3 worldNormal; INTERNAL_DATA -世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。

    SurfaceOutput

    SurfaceOutput 描述了表面的特性(光照的颜色反射率、法线、散射、镜面等),这个结构是固定的,不需要在Shader中再定义。

    struct SurfaceOutput {
        half3 Albedo;       //反射率,一般就是在光照之前的原始颜色
        half3 Normal;       //法线
        half3 Emission;     //自发光,用于增强物体自身的亮度,使之看起来好像可以自己发光
        half Specular;      //镜面
        half Gloss;         //光泽
        half Alpha;         //透明
    };

    Unity5 由于引入了基于物理的光照模型,所以新增加了两个Output

    struct SurfaceOutputStandard
    {
        fixed3 Albedo;      // base (diffuse or specular) color
        fixed3 Normal;      // tangent space normal, if written
        half3 Emission;
        half Metallic;      // 0=non-metal, 1=metal
        half Smoothness;    // 0=rough, 1=smooth
        half Occlusion;     // occlusion (default 1)
        fixed Alpha;        // alpha for transparencies
    };
    struct SurfaceOutputStandardSpecular
    {
        fixed3 Albedo;      // diffuse color
        fixed3 Specular;    // specular color
        fixed3 Normal;      // tangent space normal, if written
        half3 Emission;
        half Smoothness;    // 0=rough, 1=smooth
        half Occlusion;     // occlusion (default 1)
        fixed Alpha;        // alpha for transparencies
    };

    Unity提供了一些基本的SurfaceShader的例子,有助于我们理解输入输出是如何被使用的。
    Unity提供的SurfaceShader的例子


    Vertex Shader

    如果不想使用Surface Shader而直接编写opengl和Direct3D中常见的顶点着色器和片段着色器,可以通过Cg代码段嵌入到Pass中:

      Pass {
          // ... the usual pass state setup ...
    
          CGPROGRAM
          // compilation directives for this snippet, e.g.:
          #pragma vertex vert
          #pragma fragment frag
    
          // the Cg/HLSL code itself
    
          ENDCG
          // ... the rest of pass setup ...
      }

    其中vert就是顶点着色器函数,frag就是片段着色器函数。一般来说,可以在顶点着色器中进行的计算就不应该放到片段着色器中去算,因为顶点着色器是逐顶点计算的而片段着色器是逐像素计算的,一个模型顶点总比表明像素少很多吧。

    编写顶点和片段着色器一般需要包含Unity预定义的一个帮助文件UnityCG.cginc,里面预定义了一些常用的结构和方法。Windows版Unity这个文件位于({unity install path}/Data/CGIncludes/UnityCG.cginc。 Mac版位于/Applications/Unity/Unity.app/Contents/CGIncludes/UnityCG.cginc

    在代码中我们只需要添加 #include "UnityCG.cginc"就可以使用里面的结构和方法。

    Input

    顶点着色器的原型是 v2f vert (appdata v)
    appdata 是输入,可以自己定义也可以使用Unity预定义的。Unity在UnityCG.cginc预定义了三种常用的输入结构:appdata_base,appdata_tan,appdata_full。

    struct appdata_base {
        float4 vertex : POSITION;
        float3 normal : NORMAL;
        float4 texcoord : TEXCOORD0;
    };
    
    struct appdata_tan {
        float4 vertex : POSITION;
        float4 tangent : TANGENT;
        float3 normal : NORMAL;
        float4 texcoord : TEXCOORD0;
    };
    
    struct appdata_full {
        float4 vertex : POSITION;
        float4 tangent : TANGENT;
        float3 normal : NORMAL;
        float4 texcoord : TEXCOORD0;
        float4 texcoord1 : TEXCOORD1;
        float4 texcoord2 : TEXCOORD2;
        float4 texcoord3 : TEXCOORD3;
    #if defined(SHADER_API_XBOX360)
        half4 texcoord4 : TEXCOORD4;
        half4 texcoord5 : TEXCOORD5;
    #endif
        fixed4 color : COLOR;
    };

    我们注意到这些结构的字段和表面着色器中的字段不同,后面多了一个冒号和一个标签。这是该字段的语义,用于告诉GPU这个字段的数据应该去哪里读写。GPU毕竟是为了图形计算而特别设计的东西,很多东西都是固定的,我们只要记得有这么几个名字可以用行了。

    类型 名字 标签 备注
    float4 vertex POSITION 顶点在模型坐标系下的位置
    float3 normal NORMAL 顶点的法向量
    float4 tangent TANGENT 顶点的切向量
    float4 color COLOR 顶点色
    float4 texcoord TEXCOORD0 顶点的第一个uv坐标
    float4 texcoord1 TEXCOORD1 顶点的第二个uv坐标,最多可以到5

    Output

    顶点着色器的输出是也是一个可以自己定义的结构,但是结构内容也是比较固定的,一般包含了顶点投影后的位置,uv,顶点色等,也可以加一些后面片段着色器需要用到但是需要在顶点着色器中计算的值。这个输出就是后面片段着色器的输入。

     struct v2f 
     {
        float4 pos : SV_POSITION;
        half2 uv   : TEXCOORD0;
     };

    可以使用的字段有:

    类型 标签 描述
    float4 SV_POSITION 顶点在投影空间下的位置,注意和输入的模型坐标系下的位置不同,这个字段必必须设置,这个坐标转换是顶点着色器的重要工作
    float3 NORMAL 顶点在视图坐标系下的法向量
    float4 TEXCOORD0 第一张贴图的uv坐标
    float4 TEXCOORD1 第二张贴图的uv坐标
    float4 TANGENT 切向量,主要用来修正法线贴图Normal Maps
    fixed4 COLOR 第一个定点色
    fixed4 COLOR1 第二个定点色
    Any Any 其他自定义的字段

    坐标变换

    顶点着色器有一项重要的工作就是进行坐标变换。顶点着色器的输入中的坐标是模型坐标系(ObjectSpace)下的坐标,而最终绘制到屏幕上的是投影坐标。
    在我们Shader里面只需要一句话就可以完成坐标的转换,这也是最简单的顶点着色器:

    v2f vert(appdata v) {
              v2f o;
              o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
              return o;
    }

    用UNITY_MATRIX_MVP矩阵乘以顶点在模型坐标系下的坐标就得到投影坐标。
    UNITY_MATRIX_MVP是Unity内建的模型->视->投影矩阵, Unity内建矩阵如下:

    • UNITY_MATRIX_MVP:当前模型->视图->投影矩阵。(注:模型矩阵为 本地->世界)
    • UNITY_MATRIX_MV:当前模型->视图矩阵
    • UNITY_MATRIX_V:当前视图矩阵
    • UNITY_MATRIX_P:当前投影矩阵
    • UNITY_MATRIX_VP:当前视图->投影矩阵
    • UNITY_MATRIX_T_MV:转置模型->视图矩阵
    • UNITY_MATRIX_IT_MV:逆转置模型->视矩阵, 用于将法线从ObjectSpace旋转到WorldSpace。为什么法线变化不能和位置变换一样用UNITY_MATRIX_MV呢?一是因为法线是3维的向量而- UNITY_MATRIX_MV是一个4x4矩阵,二是因为法线是向量,我们只希望对它旋转,但是在进行空间变换的时候,如果发生非等比缩放,方向会发生偏移。
    • UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3:纹理变换矩阵

    下面简单介绍一下里面提到的几个坐标系:
    模型坐标系:也叫物体坐标系,3D建模的时候每个模型都是在自己的坐标系下建立的,如果一个人物模型脚底是(0,0,0) 点的话它的身上其它点的坐标都是相对脚底这个原点的。
    世界坐标系:我们场景是一个世界,有自己的原点,模型放置到场景中后模型上的每个顶点就有了一个新的世界坐标。这个坐标可以通过模型矩阵×模型上顶点的模型坐标得到。
    视图坐标系:又叫观察坐标系,是以观察者(相机)为原点的坐标系。场景中的物体只有被相机观察到才会绘制到屏幕上,相机可以设置视口大小和裁剪平面来控制可视范围,这些都是相对相机来说的,所以需要把世界坐标转换到视图坐标系来方便处理。
    投影坐标系:场景是3D的,但是最终绘制到屏幕上是2D,投影坐标系完成这个降维的工作,投影变换后3D的坐标就变成2D的坐标了。投影有平行投影和透视投影两种,可以在Unity的相机上设置。
    屏幕坐标系 : 最终绘制到屏幕上的坐标。屏幕的左下角为原点。

    除了内建矩阵,Unity还内建了一些辅助函数也可以在顶点着色器里面使用:

    • float3 WorldSpaceViewDir (float4 v):根据给定的局部空间顶点位置到相机返回世界空间的方向(非规范化的)
    • float3 ObjSpaceViewDir (float4 v):根据给定的局部空间顶点位置到相机返回局部空间的方向(非规范化的)
    • float2 ParallaxOffset (half h, half height, half3 viewDir):为视差法线贴图计算UV偏移
    • fixed Luminance (fixed3 c):将颜色转换为亮度(灰度)
    • fixed3 DecodeLightmap (fixed4 color):从Unity光照贴图解码颜色(基于平台为RGBM 或dLDR)
    • float4 EncodeFloatRGBA (float v):为储存低精度的渲染目标,编码[0..1)范围的浮点数到RGBA颜色。
    • float DecodeFloatRGBA (float4 enc):解码RGBA颜色到float。
    • float2 EncodeViewNormalStereo (float3 n):编码视图空间法线到在0到1范围的两个数。
    • float3 DecodeViewNormalStereo (float4 enc4):从enc4.xy解码视图空间法线

    Fragment Shader

    // TODO


    参考:
    猫都能学会的Unity3D Shader入门指南

    原文地址:http://blog.csdn.net/ring0hx/article/details/46440037

    展开全文
  • Shader,看起来好高级的样子,是的,这是Unity中高级进阶的必备。因此,兄弟我就在此记下我学习官网的一些心得。 此为一。主要介绍些Surface Shaders的知识。具体的大家也可去官网(如下)学习。 ...
  • 【Modern OpenGL】Shader

    千次阅读 2018-07-14 08:29:04
    Shaders正如在上一篇教程中提到的,shader是在GPU中运行的小程序。如上一个教程中实现的最简单的vertex shader和fragment shader,一个shader基本上负责图形渲染流水线中的一个阶段的功能。从根本上来说,shader就是...
  • Unity5.x shader打包AssetBundle总结

    万次阅读 2016-12-18 23:09:00
    unity5.x shader打包AssetBundle总结 最近比较忙,好久没有更新博客了,新项目切换到unity5.x后使用了新的打包机制,在打包shader的时候遇到了一些问题,这里来记录一下吧。
  • 猫都能学会的Unity3D Shader入门指南(一) 原文出处:https://onevcat.com/2013/07/shader-tutorial-1/ 动机 自己使用Unity3D也有一段时间了,但是很多时候是流于表面,更多地是把这个引擎简单地...
  • ShaderShader官方示例

    千次阅读 2018-12-20 15:42:59
    Surface Shader示例 在表面着色器 。此页面上的示例显示如何使用内置照明模型。有关如何实现自定义光照模型的示例,请参阅Surface Shader光照示例。 简单着色器 例 我们将从一个非常简单的Shader开始,并在此基础上...
  • OpenGL--使用Shader

    万次阅读 2018-06-10 17:52:38
    创建Shader 关于在OpenGL中怎么创建Shader这个在很早我博客中就有过详细介绍了。这里全当复习,温故而知新~ 在OpenGL中,存在Program和Shader两个概念,Program相当于当前渲染管线所使用的程序,是Shader的容器,...
  • Shader入门-2

    千次阅读 2018-08-15 17:23:33
    Hello Shader 百行文档不如一个实例,下面给出一段简单的Shader代码,然后根据代码来验证下上面说到的结构和阐述一些基本的Shader语法。因为本文是针对Unity3D来写Shader的,所以也使用Unity3D来演示吧。首先,新建...
  • 什么是Shader

    千次阅读 2011-09-04 23:50:54
    光看字面的意思「Shader」不知道是什麼玩意兒,硬翻成中文「著色器」似乎也難以摸著頭緒!剛開始接觸圖學的我完全搞不懂它有什麼作用,然後盲目地學著OpenGL:P直到老師說:「只要你學會Shader,就可以做到別人辦不...
  • Unity Shader Graph初次尝试

    万次阅读 2020-02-24 09:56:37
    软件环境 Unity Version: 2018.1.2f1 边缘发光材质效果 创建工程 打开Unity并创建一个新工程 ... Package Manager打开包管理器,安装二个依赖包: ...2. Shader Graph Lightweight Render Pipeline ...
  • Unity Shader 基础教程

    万次阅读 多人点赞 2020-07-24 10:12:20
    在Github上看到一篇关于Unity-Shader的教程,感觉还不错,作者写的很好,很适合Unity-Shader的基础入门,我在这里翻译一下,分享给大家,英文水平很烂,大致能明白Unity-Shader是什么,渲染管线的工作流程,以及...
  • 作为一个系统介绍Unity3D中Shader编写的系列文章的开篇,本文的第一部分系列文章的前言,然后第二部分介绍了这个系列文章中我们会使用的游戏场景创建方式,最后一部分讲解了如何在Unity中创建和使用Shader,为后面...
  • 本篇文章中,我们学习了Unity Shader的基本写法框架,以及学习了Shader中Properties(属性)的详细写法,光照、材质与颜色的具体写法。写了6个Shader作为本文Shader讲解的实战内容,最后创建了一个逼真的暴风雪场景...
  • 本次更新放出的Shader为透明系列的3个Shader和标准的镜面高光Shader的两个Shader。由易到难,由入门级到应用级,难度梯度合理。 依然是先放出游戏场景的exe和运行截图。 本期用的模型为妙蛙草。 【可运行...
  • 从这篇文章开始, Shader系列博文将继续开始更新。且在这次重启,这个系列文章会更多专注于实际Shader的书写,力求推出更多具有特色和实用性的Shader,概念性的东西在原则上上是不会再多讲的。 作为可编程Shader...
1 2 3 4 5 ... 20
收藏数 76,266
精华内容 30,506
关键字:

shader