unity优化程序员unity3D技术分享

顶点与片段着色器

2016-08-11  本文已影响2711人  半闲书屋半闲人

一、顶点与片段着色器简介

Vertex and FragmentShader:最强大的Shader类型,也是本系列的重点,下文中简称V&FShader,属于可编程渲染管线.使用的是CG/HLSL语法。分为2个部分vertex顶点部分和Fragment像素部分。下面依然通过写几个简单的Shader来学习。

二、 CG语言一些关键词和常用函数解释

1、Cg顶点程序必须在结构中传递顶点数据。几种常用的顶点结构定义在文件UnityCG.cginc中。在大部分情况下仅仅使用它们就够了。结构如下:

1、appdata_base: 包含顶点位置,法线和一个纹理坐标。
2、appdata_tan:包含顶点位置,切线,法线和一个纹理坐标。
3、appdata_full:包含位置、法线、切线、顶点色和两个纹理坐标。
4、appdata_img:包含位置和一个纹理坐标。

2、如果你想访问个别的顶点数据,你必须自己声明顶点结构。结构中的成员必须是属于以下列表中的:

1、float4 vertex:顶点位置
2、float3 normal:顶点法线
3、float4 texcoord:第一UV坐标
4、float4 texcoord1:第二UV坐标
5、float4 tangent:切线向量(用在法线贴图中)
6、float4 color:每个顶点(per-vertex)颜色

3、内置矩阵

1、UNITY_MATRIX_MVP:当前模型投影矩阵。(注:模型矩阵为 本地->世界)
2、UNITY_MATRIX_MV:当前模型视图矩阵
3、UNITY_MATRIX_V:当前视图矩阵
4、UNITY_MATRIX_P:当前投影矩阵
5、UNITY_MATRIX_VP:当前视图
投影矩阵
6、UNITY_MATRIX_T_MV:转置模型视图矩阵
7、UNITY_MATRIX_IT_MV:逆转置模型
视矩阵
8、UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3:纹理变换矩阵

4、内置向量

1、UNITY_LIGHTMODEL_AMBIENT:当前环境色

三、图形渲染的流程

20140929143233_9843.jpg

这是GPU对游戏物体进行渲染时的流程,解释一下为:

1、Transform:要渲染的物体在空间中的位置变换,从局部坐标-世界坐标-观察坐标系-视口坐标系
2、TexGen:表示纹理坐标生成,当需要对游戏对象进行贴图时,需要确定贴图部分的纹理位置
3、Lighting:表示光照处理
4、Vertex Shader:表示顶点着色,主要是处理图形中的所有顶点位置
5、Culling:表示剔除,将游戏物体的部分不渲染
6、Depth Test:表示深度测试,判断游戏对象之间的深度和遮挡
7、Texturing:表示纹理处理,贴图
8、Fog:表示雾效果,雾参数
9、Fragment Shader:表示片段着色,对游戏对象的颜色进行处理
10、Alpha Test:表示透明测试
11、Blending:表示混合

四、Unity3d 着色器语法(Shader)

Shader "name" { [Properties] Subshaders [Fallback] } 定义了一个着色器。着色器拥有一个 Properties 的列表。着色器包含一个子着色器的列表(SubShaders)。并且至少包含一个(SubShader)。当加载一个着色器时,Unity 将遍历这个列表,获取第一个能被用户机器支持的着色器。如果没有子着色器被支持,Unity 将尝试使用降级 Shader(Fallback )。

1、着色器文件中的 Properties 块定义了这些参数:

1、name ("display name", Range (min, max)) = number:定义浮点数范围属性。
2、name ("display name", Color) = (number,number,number,number):定义颜色属性。
3、name ("display name", 2D) = "name" { options }:定义2D纹理属性。
4、name ("display name", Rect) = "name" { options }:定义长方形(非2次方)纹理属性。
5、name ("display name", Cube) = "name" { options }:定义立方贴图纹理属性。
6、name ("display name", Float) = number:定义浮点数属性。
7、name ("display name", Vector) = (number,number,number,number):定义一个四元素的容器(Vector4)属性。

2、Subshader { [Tags] [CommonState] Passdef [Passdef ...] } 通过可选标签,通用状态和一个Pass 定义的列表构成了子着色器。

3、Pass { [Name and Tags] [RenderSetup] [TextureSetup] } 基本通道命令包含一个可选的渲染设置命令的列表和可选的被使用的纹理的列表。

4、Name and tags 名称和标签:一个通道能定义它的 Name 和任意数量的Tags(用于向渲染引擎传递通道的意图的名称/值的字符串)。

5、Render Setup 渲染设置:通道设定显示硬件的各种状态。这些命令如下:

1、Material { Material Block }:定义一个使用顶点光照管线的材质。
2、Lighting On | Off:开启或关闭顶点光照。
3、Cull Back | Front | Off: 设置多边形剔除模式。
4、ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always):设置深度测试模式。
5、ZWrite On | Off:设置深度写模式。
6、Fog { Fog Block }:设置雾参数。
7、AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) CutoffValue:开启 alpha 测试。
8、Blend SourceBlendMode DestBlendMode:设置 alpha 混合模式。
9、Color Color value:设置当顶点光照关闭时所使用的颜色。
10、ColorMask RGB | A | 0 | any combination of R, G, B, A:设置颜色写遮罩。设置为0将关闭所有颜色通道的渲染。
11、Offset OffsetFactor , OffsetUnits:设置深度偏移。
12、SeparateSpecular On | Off:开启或关闭顶点光照相关的平行高光颜色.
13、ColorMaterial AmbientAndDiffuse | Emission:当计算顶点光照时使用每顶点颜色。

6、Texture Setup 纹理设置:在完成渲染设定后,你能指定一定数量的纹理和当使用 SetTexture 命令时所采用的混合模式:

1、SetTexture texture property { [Combine options] }:纹理设置 配置了 固定函数多纹理管线,当自定义fragment shaders 被使用时,将忽略这个设置。
2、Per-pixel Lighting:每像素光照。每像素光照管线通过多次通道渲染对象来完成。Unity渲染对象一次来获取阴影色和任何顶点光照。然后再在额外的并行通道中渲染出每像素光照的效果。
3、Per-vertex Lighting:每顶点光照。每顶点光照是标准的Direct3D/OpenGL光照模式,通过计算每个顶点的光照来完成。Lighting on命令开启光照。光照被材质块,颜色材质和平行高光命令所影响。

7、有几个特殊的通道能用于反复利用普通功能或是实现几种高端的特效:

1、UsePass:包含来自其他着色器的通道。
2、GrabPass:捕获屏幕到一个纹理,通常使用在靠后的通道中。

8、顶点颜色和灯光(Color, Material, Lighting)是对任何已渲染过后的几何体所添加的第一步效果。这个操作处在顶点级别,用于计算在纹理被应用之前被使用的基础颜色。顶层命令控制是否采用固定函数光照,和一些控制选项,细节如下:

1、Color Color:设定对象的纯色。颜色即可以是括号中的四值(RGBA),也可以是被方框包围的颜色属性名。
2、Material { Material Block }:材质块被用于定义对象的材质属性。
3、Lighting On | Off:定义材质块中的设定是否有效,你必须使用 Lighting On 命令开启光照,而颜色则通过 Color 命令直接给出。
4、SeparateSpecular On | Off:这个命令会添加高光光照到着色器通道的末尾,因此贴图对高光没有影响。只在光照开启时有效。
5、ColorMaterial AmbientAndDiffuse | Emission:使用每顶点的颜色替代材质中的颜色集。AmbientAndDiffuse 替代材质的阴影光和漫反射值;Emission 替代材质中的光发射值。

9、Material Block 材质块,包含材质如何和光线产生作用的设定。这些属性都是可以被忽略的,默认为值都被设定为黑色(不产生作用):

1、Diffuse Color:漫反射颜色构成。这是对象的基本颜色。
2、Ambient Color:环境色颜色构成.这是当对象被RenderSettings. 中设定的环境色所照射时对象所表现的颜色。
3、Specular Color:对象反射高光的颜色。
4、Shininess Number:加亮时的光泽度,在0和1之间。0的时候你会发现更大的高亮也看起来像漫反射光照,1的时候你会获得一个细微的亮斑。
5、Emission Color:自发光颜色,当不被任何光照所照到时,对象的颜色。
6、最终的计算效果是:Ambient * RenderSettings ambient setting + (Light Color * Diffuse + Light Color * Specular) + Emission。

10、剔除(Culling)是一种通过避免渲染背对观察者的几何体面来提高性能的优化措施。所有几何体都包含正面和反面。剔除基于大多数对象都是封闭的事实;如果你有一个立方体,你不会看到背离你的那一面(总是只有一面在你的前方),因此我们不需要绘制出背面。因此也被称做背面剔除。另一个使得渲染看起来正确的是深度测试(Depth Testing)。深度测试确保只有场景内的对象的最靠近的表面参与绘制。

1、Cull Back(不绘制背离观察者的几何体面)| Front(不绘制面向观察者的几何体面,用于由内自外的旋转对象) | Off(显示所有面,用于特殊效果):控制几何体的那一面会被剔除(不绘制)
2、ZWrite On | Off:控制是否将来之对象的像素写入深度缓冲(默认开启),如果你正绘制纯色物体,将此项打开。如果你正绘制半透明效果,关闭深度缓冲。
3、ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always:深度测试如何执行。缺省是LEqual (绘制和存在的对象一致或是在其中的对象;隐藏他们背后的对象)
4、Offset Factor , Units:允许你定义用两个参数深度偏移。因子和单位。Factor 缩放Z的最大斜率,几何体的X和Y也一样,units缩放可计算的深度缓冲值。这允许你迫使一个几何体绘制在另一个的上层,尽管他们实际上是在同一个位置。例如偏移0,-1使得靠近摄像机的几何体忽略几何体的斜率,而偏移-1,-1则会几何体在一个几乎擦过的角度被观察使看起来更近些。

11、纹理(Texturing)在基本的顶点光照被计算后被应用。在着色器中通过 SetTexture 命令来完成。SetTexture 命令在片面程序被使用时不会生效;这种模式下像素操作被完全描述在着色器中。材质贴图可以用来做老风格的混合器效果。你能在一个通道中使用多个SetTexture 命令 - 所有纹理被顺序的应用,如同绘画程序中的层一样。SetTexture 命令必须放置在通道的末尾。

12、SetTexture [TexturePropertyName] { Texture Block }:分配一个纹理,TextureName 必须定义为一个纹理属性。如何应用纹理被定义在 TextrueBlock 中。纹理块控制纹理如何被应用。在纹理块中能执行3种命令:合并,矩阵和不变色。

13、纹理块合并(Combine)命令:

1、combine src1 * src2:将源1和源2的元素相乘。结果会比单独输出任何一个都要暗。
2、combine src1 + src2:将将源1和源2的元素相加。结果会比单独输出任何一个都要亮。
3、combine src1 - src2:源1减去源2。
4、combine src1 +- src2:先相加,然后减去0.5(添加了一个符号)。
5、combine src1 lerp (src2) src3:使用源2的透明度通道值在源3和源1中进行差值,注意差值是反向的:当透明度值是1是使用源1,透明度为0时使用源3。
6、combine src1 * src2 + src3:源1和源2的透明度相乘,然后加上源3。
7、combine src1 * src2 +- src3:源1和源2的透明度相乘,然后和源3做符号加。8、combine src1 * src2 - src3:源1和源2的透明度相乘,然后和源3相减。所有源属性都可以是 Previous(上一次 SetTexture 的结果)、Constant(被 ConstantColor 定义的颜色)、 Primary(来自光照计算的颜色或是当它绑定时的顶点颜色)、Texture(在 SetTexture 中被定义的纹理的颜色)其中的一个。

14、纹理块不变色(ConstantColor)命令:

1、ConstantColor color:定义在combine命令中能被使用的不变颜色。

15、纹理块矩阵(Matrix)命令:

1、matrix [MatrixPropertyName]:使用给定矩阵变换纹理坐标。

16、雾(Fog)参数用于雾命令控制。雾化是通过混合已生成的像素的颜色和基于到镜头的距离来确定的一个不变色来完成。雾化不会改变已经混合的像素的透明度值,只是改变RGB值。

17、Fog { Fog Commands }:在大括号中设定雾命令的内容

1、Mode Off | Global | Linear | Exp | Exp2:定义雾模式。缺省是全局的,依据雾在渲染设定中是否打开确定可从无变化到平方值。
2、Color ColorValue:设定雾的颜色。
3、Density FloatValue:以指数的方式 设定雾的密度。
4、Range FloatValue , FloatValue:为 linear 的雾设定远近距离。

18、透明度测试(Alpha testing)是阻止像素被写到屏幕的最后机会。在最终渲染出的颜色被计算出来之后,可选择通过将颜色的透明度值和一个固定值比较。如果比较的结果失败,像素将不会被写到显示输出中。

1、AlphaTest Off:渲染所有像素(缺省)。
2、AlphaTest Greater(大于)| GEqual(大于等于)| Less(小于)| LEqual(小于等于)| Equal(等于)| NotEqual(不等于)| Always(渲染所有像素)| Never(不渲染任何像素) AlphaValue(一个范围在0到1之间的浮点值。也可以是一个指向浮点属性或是范围属性的索引,在后一种情况下需要使用标准的方括号写法标注索引名字,如([变量名])):设定透明度测试只渲染在某一确定范围内的透明度值的像素。

19、混合(Blending)被用于制作透明物体。当图像被渲染时,所有着色器被执行以后,所有贴图被应用后,像素将被写到屏幕。通过 Blend 命令控制和已有的图像合并:

1、Blend Off:关闭混合。
2、Blend SrcFactor DstFactor: 配置并启动混合。产生的颜色被乘以 SrcFactor,已存在于屏幕的颜色乘以 DstFactor,并且两者将被叠加在一起。
3、Blend SrcFactor DstFactor, SrcFactorA DstFactorA:同上,但是使用不同的要素来混合 alpha 通道。4、BlendOp Min | Max | Sub | RevSub:不是添加混合颜色在一起,而是对它们做不同的操作。

20、以下所有属性对SrcFactor或DstFactor都可用。Source 指的是被计算的颜色,Destination 是已经在屏幕上的颜色。

1、One:值为1,使用此设置来让源(Source)或是目标颜色(Destination)完全的通过。
2、Zero:值为0,使用此设置来删除源(Source)或目标值(Destination)。
3、SrcColor:此阶段的值是乘以源颜色(Source)的值。
4、SrcAlpha:此阶段的值是乘以源(Source)alpha 的值。
5、DstColor:此阶段的值是乘以帧缓冲区源颜色(Source)的值。
6、DstAlpha:此阶段的值是乘以帧缓冲区源(Source)alpha 的值。
7、OneMinusSrcColor:此阶段的值是乘以(1 - 源颜色(Source))。
8、OneMinusSrcAlpha:此阶段的值是乘以(1 - 源(Source)alpha)。
9、OneMinusDstColor:此阶段的值是乘以(1 - 目标颜色(Destination))。
10、OneMinusDstAlpha:此阶段的值是乘以(1 - 目标(Destination)alpha)。

21、Tags { "TagName1" = "Value1" "TagName2" = "Value2" }:指定TagName1 的值为 Value1 ,TagName2 的值为 Value2 你可以指定很多你喜欢的标签。通过使用标签(Pass Tags)来告诉渲染引擎在什么时候该如何渲染他们所期望的效果。

22、LightMode 标签定义了光照点中的 Pass 任务。可选值如下:

1、Always:总是渲染。没有光照应用。
2、ForwardBase:用于正向渲染,环境主要方向灯和定点光/SH 等的应用。
3、ForwardAdd:用于正向渲染,附加的像素光被应用,每个光照一个 pass。
4、PrepassBase:用于延迟光照,渲染法线/镜面指数。
5、PrepassFinal:用于延迟光照,通过结合纹理,光照和自发光渲染最终颜色。
6、Vertex:用于顶点光照渲染,当物体没有光照映射时,所有顶点光照被应用。
7、VertexLMRGBM:用于顶点光照渲染,当物体有光照映射的时候使用顶点光照渲染。在平台上光照映射是 RGBM 编码。
8、VertexLM:用于顶点光照渲染,当物体有光照映射的时候使用顶点光照渲染。在平台上光照映射是double-LDR 编码(移动平台,及老式台式CPU)。
9、ShadowCaster:将物体当做阴影产生者来渲染。
10、ShadowCollector:为了正向渲染对象的路径,将对象的阴影收集到屏幕空间缓冲区中。

23、Name "PassName":为当前通道命名 PassName。一个通道能被赋予一个名字以便UsePass 命令能索引到它。

24、BindChannels { Bind "source", target }:允许你指定顶点数据如何映射到显卡中。

25、Source 可以是下面其中一个:

1、Vertex: vertex position 顶点:顶点的位置。
2、Normal: vertex normal 法线:顶点的法线。
3、Tangent: vertex tangent 切线:顶点的切线。
4、Texcoord: primary UV coordinate 主要的UV坐标。
5、Texcoord1: secondary UV coordinate 次要的UV坐标。
6、Color: per-vertex color 颜色:每个顶点颜色。

26、Target 可以是下面其中的一个:

1、Vertex: vertex position 顶点:顶点的位置。
2、Normal: vertex normal 法线:顶点的法线。
3、Tangent: vertex tangent 切线:顶点的切线。
4、Texcoord0, Texcoord1, ...: texture coordinates for corresponding texture stage 各个纹理处理阶段的纹理坐标。
5、Texcoord: texture coordinates for all texture stages 所有纹理处理阶段的纹理坐标。
6、Color: vertex color 颜色:顶点颜色。

五、使用顶点和片段着色器写几个小例子

1、颜色的变换

1)、渲染一个面片的颜色

使用unity,Asset>右键创建一个shader>创建一个Material>将shader添加到Material上>在Heriarchy中创建一个Quad>将Material添加到Quad上>打开创建的Shader

//Shader的名字和储存的位置
Shader "Custom/VertexFragmentBase1" {
//子着色器
   SubShader
   {
       //子着色器的Tags值,渲染方式为Opaque,可以渲染大部分不透明的游戏对象
       Tags{"RenderType"="Opaque"}
       //LOD通道
       LOD 200
       //渲染通道
       Pass
       {
           //cg语言开始标识
           CGPROGRAM
           //可以理解为引用定义一个vertex的方法,方法名vert(顶点着色方法)
           #pragma vertex vert
           //片段着色方法
           #pragma fragment frag
           //应用UnityCG库中的cginc,包含大多可以用的结构体
           #include "UnityCG.cginc"
           //自定义一个储存顶点位置的结构体v2f
           struct v2f
           {
               //定义一个float4的顶点位置变量
               float4 pos:POSITION;
           };
           //自定义一个储存颜色的结构体v2c
           struct v2c
           {
               //定义一个fixed4的颜色变量
               fixed4 col:Color;
           };
           //vert方法,将顶点的空间坐标转换为屏幕坐标,appdata_base是UnityCG.cginc中的一个结构体,储存了位置、法线和纹理
           v2f vert(appdata_base v)
           {
               v2f o;
               //将顶点的本地坐标转换为世界坐标(屏幕坐标)
               o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
               return o;
           }
           //片段方法,给游戏对象的所有顶点着色
           v2c frag()
           {
               v2c c;
               //着色
               c.col=fixed4(0,1,1,0);
               return c;
           }
           //cg语言结束标识
           ENDCG
       }
       
   }
}

效果如图:
![~V@])V67WVD(@$A7G8AVUSQ.png](http:https://img.haomeiwen.com/i2381726/204d10d7182c5114.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

2)、实现游戏对象的颜色随程序的运行而变化

使用unity,Asset>右键创建一个shader>创建一个Material>将shader添加到Material上>在Heriarchy中创建一个Quad>将Material添加到Quad上>打开创建的Shader
效果如图:


颜色变换.gif

实现的秘密是将颜色的rgb值由常量改为随程序运行时间变化的变量,实现的代码如下(将frag方法改写):

//片段方法,给游戏对象的所有顶点着色
        v2c frag(v2f IN)
        {
            v2c c;
            fixed r=abs(sin(_Time*10));
            fixed g=abs(cos(_Time*10));
            fixed b=abs(tan(_Time*10));
            c.col=fixed4(r,g,b,1);
            return c;
        }

3)、实现游戏对象的颜色随游戏对象在屏幕的位置的变化而变化

使用unity,Asset>右键创建一个shader>创建一个Material>将shader添加到Material上>在Heriarchy中创建一个Quad>将Material添加到Quad上>打开创建的Shader
效果如图:


颜色随屏幕位置变换.gif

实现的秘密是将颜色的rgb值由常量改为随游戏对象在屏幕上位移变化的变量,实现的代码如下(将frag方法改写):

//片段方法,给游戏对象的所有顶点着色
        v2c frag(v2f IN)
        {
            v2c c;
            //用顶点的xy除以屏幕参数的xy
            c.col=fixed4(IN.pos.xy/_ScreenParams.xy,0,1);
            return c;
        }

2、添加纹理贴图

有了颜色之后,我们如何添加一张纹理贴图呢?还是相同的逻辑,先定义一张纹理贴图,然后获得纹理贴图的顶点坐标和片段颜色,进行赋值处理即可,具体看下面代码:

Shader "Custom/VertexFragmentBase2" {
    Properties {
        //定义一个纹理贴图
        _MainTex ("MainTex", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Pass
        {
            CGPROGRAM
            //声明
            #pragma vertex vert 
            #pragma fragment frag
            #include "UnityCG.cginc"

            //使用sampler2D来储存贴图
            sampler2D _MainTex;
            //_MainTex_ST的ST是SamplerTexture的意思 ,就是声明_MainTex是一张采样图,也就是会进行UV运算
            float4 _MainTex_ST;

            struct v2f 
            {
                float4 pos:POSITION;
                fixed2 uv:TEXCOORD;
            };

            struct v2c
            {
                fixed4 col:Color;
            };

             v2f vert(appdata_base v)
            {
                v2f o;
                //将游戏对象的顶点坐标转换为世界坐标
                o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
                //TRANSFORM_TEX主要作用是拿顶点的uv去和材质球的tiling和offset作运算, 确保材质球里的缩放和偏移设置是正确的
                //v.texcoord就是顶点的uv
                o.uv =TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }

            v2c frag(v2f o)
            {
                v2c c ;
                c.col = tex2D(_MainTex,o.uv);
                return c ;
            }
            ENDCG
            
        }
        
    }
    FallBack "Diffuse"
}

贴出效果图:


Y6U@X1GA(HK(7KI25@G2%OT.png

3、制作动态地球

地球旋转.gif

不细说了,主要看代码,很详细,如何使地球自转,如何制作出云雾效果

Shader "Custom/EarthShader" {
    Properties
    {
        //主贴图(地球)
        _MainTex("MainTex",2D)=""{}
        //云贴图(云)
        _CloudTex("CloudTex",2D)=""{}
    }

    SubShader
    {
        Tags{"RenderType" = "Transparent" "Queue" = "Transparent "}
        LOD 200 
        //混合
        /*
        Alpha Blending,中文译作Alpha混合
        Blending就是控制透明的。处于光栅化的最后阶段。
        这里例如我们给一个模型贴一个材质,那么在某个点计算出来颜色值称为源,而该点之前累积的颜色值,叫目标。

        语法
        Blend Off     不混合
        Blend SrcFactor DstFactor  SrcFactor是源系数,DstFactor是目标系数
        最终颜色 = (Shader计算出的点颜色值 * 源系数)+(点累积颜色 * 目标系数)

        属性(往SrcFactor,DstFactor 上填的值)
        one                          1
        zero                         0
        SrcColor                         源的RGB值,例如(0.5,0.4,1)
        SrcAlpha                         源的A值, 例如0.6
        DstColor                   混合目标的RGB值例如(0.5,0.4,1)
        DstAlpha                         混合目标的A值例如0.6
        OneMinusSrcColor          (1,1,1) - SrcColor
        OneMinusSrcAlpha          1- SrcAlpha
        OneMinusDstColor          (1,1,1) - DstColor
        OneMinusDstAlpha          1- DstAlpha

        运算法则示例:
        (注:r,g,b,a,x,y,z取值范围为[0,1])
        (r,g,b) * a = (r*a , g*a , b*a)
        (r,g,b) * (x,y,z) = (r*x , g*y , b*z)
        (r,g,b) + (x,y,z) = (r+x , g+y , b+z)
        (r,g,b) - (x,y,z)  = (r-x , g-y , b-z)
        */
        
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            //声明
            #pragma vertex vert 
            #pragma fragment frag 
            #include "UnityCG.cginc"

            //储存贴图
            sampler2D _MainTex;
            sampler2D _CloudTex;
            //声明
            float4 _MainTex_ST;

            struct v2f
            {
                float4 pos:POSITION;
                fixed2 uv:TEXCOORD;
            };
            
            v2f vert(appdata_base v )
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }

            fixed4 frag(v2f o):Color
            {
                //地球自转
                fixed x = o.uv.x-_Time;
                fixed2 uv = fixed2(x,o.uv.y);
                fixed4 col=tex2D(_MainTex,uv);
                //云的旋转速度比地球快
                x = o.uv.x -_Time*1.8;
                fixed2 uv2=fixed2(x,o.uv.y);
                fixed4 cloud =tex2D(_CloudTex,uv2);
                //将CloudTex贴图上转变成红色通道(即将红色转变为白色)
                cloud =fixed4(1,1,1,0)*cloud.r;
                return lerp(col,col + cloud,0.5f);
            }
            ENDCG
        
        }
    
    
    }
}
上一篇 下一篇

猜你喜欢

热点阅读