Shader

此文章目的:掌握Shader的基本使用

Color自发光:物体自身颜色

Ambient环境光:环境光对物体的影响

Diffuse漫反射:光源对物体表面整体的颜色的影响

Specular高光反射:光源对物体表面局部的高亮颜色的影响

颜色相乘:颜色叠加

实现凹凸、阴影效果可通过两种方式:高度贴图、法线贴图

为什么需要切线空间:不同的模型,模型的坐标系不一样,因而Shader不能通用

法线贴图:有关方向的计算统一放在切线空间或世界空间下计算

基础知识

Shader语法出错或代码无效将显示紫色

Shader的基本结构:

Shader 路径

{

属性{}  //可省略,意义:供其他人调节

SubShader//可有多个

{
  Properties //属性
  pass{} //通道(存储以及处理图像的色彩)
}

Fallback  //后备Shader,可省略:制定一个已经存在的Shader,SubShader都不执行时,执行此Shader

}
View Code

C#函数不同,Shader在函数的开头要指定形参和返回值语义

Mesh Filter : 存储一个Mesh(网格,模型的网格,就是模型的由哪些三角面组成,组成一个什么样子的模型,三角面的一些顶点信息)
Mesh Renderer:用来渲染一个模型的外观,就是样子, 按照 mesh给它皮肤,给它颜色
    通过Material(材质)控制模型渲染的样子

    Material
        贴图(可以没有,可以是一个单纯的颜色)
        Shader(贴图显示的方式:是波浪还是平滑等)

书籍
    unity shader 入门精要(乐乐程序猿)
    unity 3d shaderlab开发实战详解(第二版)
    unity 5.x shaders and effects cookbook(中文版 unity着色器和屏幕特效开发秘籍)
    
CG语言教程官网
    http://http.developer.nvidia.com/CgTutorial/cg_tutorial_frontmatter.html
    
一些网站
    www.shadertoy.com
    http://blog.csdn.net/poem_qianmo?viewmode=contents
    
数学函数在线演示
    http://zh.numberempire.com/graphingcalculator.php
    
UnityCG.cginc中一些常用的函数
    
    //摄像机方向(视角方向)
    float3 WorldSpaceViewDir(float4 v)      根据模型空间中的顶点坐标 得到 (世界空间)从这个点到摄像机的观察方向
    float3 UnityWorldSpaceViewDir(float4 v) 世界空间中的顶点坐标==》世界空间从这个点到摄像机的观察方向
    float3 ObjSpaceViewDir(float4 v)         模型空间中的顶点坐标==》模型空间从这个点到摄像机的观察方向
    //光源方向
    float3 WorldSpaceLightDir(float4 v)     模型空间中的顶点坐标==》世界空间中从这个点到光源的方向
    float3 UnityWorldSpaceLightDir(float4 v)     世界空间中的顶点坐标==》世界空间中从这个点到光源的方向
    float3 ObjSpaceLightDir(float4 v)     模型空间中的顶点坐标==》模型空间中从这个点到光源的方向
    //方向转换
    float3 UnityObjectToWorldNormal(float3 norm) 把法线方向 模型空间==》世界空间
    float3 UnityObjectToWorldDir(float3 dir) 把方向 模型空间=》世界空间
    float3 UnityWorldToObjectDir(float3 dir) 把方向 世界空间=》模型空间

什么是OpenGL、DirectX
shader可以认为是一种渲染命令 ,由opengl 或者dx进行解析,来控制渲染丰富多彩的图形

OpenGL 使用GLSL 编写shader
DirectX 使用HSSL 编写shader
英伟达 CG 编写shader(跨平台)

Unity Shader的分类
使用的是ShaderLab编写Unity中的Shader
1,表面着色器 Surface Shader(Unity独有的着色器,可以认为是对顶点/片元着色器的封装,方便编写)
2,顶点/片元着色器 Vertex/Fragment Shader(较基本着色器,故较强大)
3,固定函数着色器 Fixed Function Shader(被弃用了)

Unityshader中属性的类型有哪些
        _Color("Color",Color)=(1,1,1,1)
        _Vector("Vector",Vector)=(1,2,3,4)
        _Int("Int",Int)= 34234
        _Float("Float",Float) = 4.5
        _Range("Range",Range(1,11))=6
        _2D("Texture",2D) = "red"{}
        _Cube("Cube",Cube) = "white"{}
        _3D("Texure",3D) = "black"{}
        
从应用程序传递到顶点函数的语义有哪些a2v
POSITION 顶点坐标(模型空间下的)
NORMAL 法线( 模型空间下)
TANGENT 切线(模型空间)
TEXCOORD0 ~n 纹理坐标
COLOR 顶点颜色

从顶点函数传递给片元函数的时候可以使用的语义
SV_POSITION 剪裁空间中的顶点坐标(一般是系统直接使用)
COLOR0 可以传递一组值 4个
COLOR1 可以传递一组值 4个
TEXCOORD0~7 传递纹理坐标

片元函数传递给系统
SV_Target 颜色值,显示到屏幕上的颜色

什么是光照模型
光照模型就是一个公式,使用这个公式来计算在某个点的光照效果

标准光照模型(分为逐顶点、逐像素)
在标准光照模型里面,我们把进入摄像机的光分为下面四个部分
自发光
高光反射 
Blinn光照模型 
Specular=直射光  * pow( max(cosθ,0),10)  θ:是反射光方向和视野方向(摄像机到点间的向量)的夹角
Blinn-Phong光照模型
Specular=直射光  * pow( max(cosθ,0),10)  θ:是法线和x的夹角  x 是平行光和视野方向的平分线
漫反射 Diffuse = 直射光颜色 * max(0,cos夹角(光和法线的夹角) )  cosθ = 光方向· 法线方向
环境光(间接光,反射光一直反射)

Tags{ "LightMode"="ForwardBase" }
只有定义了正确的LightMode才能得到一些Unity的内置光照变量
#include "Lighting.cginc"
包含unity的内置的文件,才可以使用unity内置的一些变量

normalize() 用来把一个向量,单位化(原来方向保持不变,长度变为1)
max() 用来取得函数中最大的一个
dot 用来取得两个向量的点积
_WorldSpaceLightPos0 取得平行光的位置
_LightColor0取得平行光的颜色
UNITY_MATRIX_MVP 这个矩阵用来把一个坐标从模型空间转换到剪裁空间
_World2Object 这个矩阵用来把一个方向从世界空间转换到模型空间
UNITY_LIGHTMODEL_AMBIENT用来获取环境光

半兰伯特光照模型
Diffuse = 直射光颜色 *( cosθ *0.5 +0.5 )
兰伯特光照模型
Diffuse = 直射光颜色 * max(0,cos夹角(光和法线的夹角) )  cosθ = 光方向· 法线方向

shader中的各种空间坐标
http://blog.csdn.net/lyh916/article/details/50906272
什么是切线空间
http://blog.csdn.net/bonchoix/article/details/8619624

pixel = (normal+1)/2

normal = pixel*2 - 1

结构体:传递多个参数、返回多个值、解决片元函数不能直接取顶点数据的问题(一个结构体里的顶点数据复制给另一个结构体,片元函数从另一个结构体取得值)
View Code

 

以下是顶点片段着色器代码示例

Shader格式

Shader "myshader"{//这里指定shader的名字,不要求跟文件名保持一致

    Properties{
        //属性名称(显示的属性名称,值类型)= 值(初始值,更新值在inspector面板取得)
        _Color("Color",Color)=(1,1,1,1) //float4
        _Vector("Vector",Vector)=(1,2,3,4) //float4
        _Int("Int",Int)= 34234 //float
        _Float("Float",Float) = 4.5 //float
        _Range("Range",Range(1,11))=6 //float
        _2D("Texture",2D) = "red"{} //sampler2D
        _Cube("Cube",Cube) = "white"{} //samplerCube
        _3D("Texure",3D) = "black"{} //sampler3D
    }
    
    //SubShader可以写很多个 显卡运行效果的时候,从第一个SubShader开始,如果第一个SubShader里面的效果都可以实现,那么就使用第一个SubShader,如果显卡这个SubShader里面某些效果它实现不了,它会自动去运行下一个SubShader
    //所以先把显卡难显示的放在前面
    SubShader{
        //至少有一个Pass;pass有自己的类型,属性在pass内使用需要重新定义
        Pass{

            //在这里编写shader代码  HLSLPROGRAM
            CGPROGRAM
            //使用CG语言编写shader代码
            float4 _Color; //float half fixed
            //fixed4
            float3 t1;// half3 fixed3
            float2 t;//half2 fixed2
            float t2;
            float4 _Vector;
            float _Int;
            float _Float;
            float _Range; 
            sampler2D _2D;
            samplerCube _Cube;
            sampler3D _3D;
            //float  32位来存储
            //half  16  -6万 ~ +6万
            //fixed 11 -2 到 +2 
                
            ENDCG
        }
    }

    Fallback "VertexLit"
}
View Code
Shader "secondshader can run"{
//基本结构
    SubShader{
        Pass{

            CGPROGRAM
            //顶点函数 这里只是声明了,顶点函数的函数名
        //基本作用是 完成顶点坐标(相对模型)从模型空间到剪裁空间的转换(从游戏环境转换到视野相机屏幕上)
#pragma vertex vert
            //片元函数 这里只是声明了,片元函数的函数名
        //基本作用  返回模型对应的屏幕上的每一个像素的颜色值
#pragma fragment frag
            float4 vert(float4 v : POSITION) :SV_POSITION {//通过语义告诉系统,我这个参数是干嘛的, 比如POSITION是告诉系统我需要顶点坐标
                //SV_POSITION这个语义用来解释说明返回值, 意思是返回值是剪裁空间下的顶点坐标
                //float4 pos = mul(UNITY_MATRIX_MVP,v);
                //return pos;
                return mul(UNITY_MATRIX_MVP,v);  //UNITY_MATRIX_MVP是一个矩阵,返回UNITY_MATRIX_MVP和V的乘积
            }
            fixed4 frag() :SV_Target {
                return fixed4(1,0.5,0.5,1);
            }


            ENDCG
        }
    }
    Fallback "VertexLit"
}
View Code

Use struct  //使用结构体解决:传递多个参数、返回多个值、解决片元函数不能直接取顶点数据的问题(一个结构体里的顶点数据复制给另一个结构体,片元函数从另一个结构体取得值)

Shader "Use struct"{
    SubShader{
        Pass{
            CGPROGRAM
    //声明函数
    #pragma vertex vert
    #pragma fragment frag
            
            //application to vertex
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;//告诉unity吧模型空间下的法线方向填充给normal
                float4 texcoord : TEXCOORD0;//告诉unity把第一套纹理坐标填充给texcoord
            };

            struct v2f {
                float4 position:SV_POSITION;
                float3 temp:COLOR0;//这个语义可以由用户自己定义,一般都存储颜色(返回值必须要有语义)
            };
                
            v2f vert(a2v v) { 
                v2f f;
                f.position = mul(UNITY_MATRIX_MVP,v.vertex);
                f.temp = v.normal;
                return f;
            } 

            fixed4 frag(v2f f) :SV_Target{  //片元函数不能直接取顶点数据,才有了temp
                return fixed4(f.temp,1);
            }

            ENDCG
        }
    }
    Fallback "VertexLit"
}
View Code

Diffuse Vertex  //漫反射+环境光

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
//漫反射+环境光
Shader "Diffuse Vertex"{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)  //物体自身的颜色
    }


        SubShader{
            Pass{
                Tags{ "LightMode" = "ForwardBase" }
                CGPROGRAM

    #include "Lighting.cginc" //取得第一个直射光的颜色 _LightColor0 第一个直射光的位置_WorldSpaceLightPos0 
        #pragma vertex vert
        #pragma fragment frag
                fixed4 _Diffuse;
            
            //application to vertex
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;   //模型空间下的坐标
            };

            struct v2f {
                float4 position:SV_POSITION;
                fixed3 color : COLOR;
            };
                
            v2f vert(a2v v) { 
                v2f f;
                f.position = mul(UNITY_MATRIX_MVP,v.vertex);  //把坐标从模型空间转换到剪裁空间
                ///一下代码可在frag函数中执行
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;  //获取环境光的颜色

                fixed3 normalDir = normalize( mul( v.normal, (float3x3) unity_WorldToObject) ); //获得模型空间到世界空间的法线方向

                fixed3 lightDir =  normalize( _WorldSpaceLightPos0.xyz);//获得点的光方向;对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光

                fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir, lightDir), 0) *_Diffuse.rgb;  //取得漫反射颜色和物体颜色的混合色
                f.color = diffuse + ambient;
                return f;
            } 

            fixed4 frag(v2f f) :SV_Target{  //输出到屏幕
                return fixed4(f.color,1);
            }

            ENDCG
        }
    }
    Fallback "Diffuse"
}
View Code

Diffuse Fragment //漫反射+环境光

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Diffuse Fragment"{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)
    }
        SubShader{
            Pass{
                Tags{ "LightMode" = "ForwardBase" }
                CGPROGRAM
    #include "Lighting.cginc" //取得第一个直射光的颜色 _LightColor0 第一个直射光的位置_WorldSpaceLightPos0 
        #pragma vertex vert
        #pragma fragment frag
                fixed4 _Diffuse;
            
            //application to vertex
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;
            };

            struct v2f {
                float4 position:SV_POSITION;
                fixed3 worldNormalDir : COLOR0;
            };
                
            v2f vert(a2v v) { 
                v2f f;
                f.position = mul(UNITY_MATRIX_MVP,v.vertex);

                f.worldNormalDir = mul(v.normal, (float3x3) unity_WorldToObject);
                
                return f;
            }

            fixed4 frag(v2f f) :SV_Target{
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 normalDir = normalize(f.worldNormalDir);

                fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光

                fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir, lightDir), 0) *_Diffuse.rgb;  //取得漫反射的颜色
                fixed3 tempColor = diffuse + ambient;
                return fixed4(tempColor,1);
            }

            ENDCG
        }
    }
    Fallback "Diffuse"
}
View Code

Diffuse Fragment HalfLambert  //漫反射+环境光,(半兰伯特光照模型:光照不到的地方变成弱光)

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
//半兰伯特光照模型
Shader "Diffuse Fragment HalfLambert"{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)
    }
        SubShader{
            Pass{
                Tags{ "LightMode" = "ForwardBase" }
                CGPROGRAM
    #include "Lighting.cginc" //取得第一个直射光的颜色 _LightColor0 第一个直射光的位置_WorldSpaceLightPos0 
        #pragma vertex vert
        #pragma fragment frag
                fixed4 _Diffuse;
            
            //application to vertex
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;
            };

            struct v2f {
                float4 position:SV_POSITION;
                fixed3 worldNormalDir : COLOR0;
            };
                
            v2f vert(a2v v) { 
                v2f f;
                f.position = mul(UNITY_MATRIX_MVP,v.vertex);

                f.worldNormalDir = mul(v.normal, (float3x3) unity_WorldToObject);
                
                return f;
            }

            fixed4 frag(v2f f) :SV_Target{
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 normalDir = normalize(f.worldNormalDir);

                fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光
                float halfLambert = dot(normalDir, lightDir) *0.5 +0.5  ;//光的最小值为0.5
                fixed3 diffuse = _LightColor0.rgb * halfLambert  *_Diffuse.rgb;  //取得漫反射的颜色
                fixed3 tempColor = diffuse + ambient;
                return fixed4(tempColor,1);
            }

            ENDCG
        }
    }
    Fallback "Diffuse"
}
View Code

Specular Vertex //漫反射+环境光+高光 ,Blinn光照模型

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
//漫反射+高光反射(+控制高光大小和高光颜色)(代码基于04)
Shader "Specular Vertex"{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)
        _Specular("Specular Color",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8,200)) = 10

    }
        SubShader{
            Pass{
                Tags{ "LightMode" = "ForwardBase" }
                CGPROGRAM
    #include "Lighting.cginc" //取得第一个直射光的颜色 _LightColor0 第一个直射光的位置_WorldSpaceLightPos0 
        #pragma vertex vert
        #pragma fragment frag
                fixed4 _Diffuse;
                fixed4 _Specular;
                half _Gloss;
            
            //application to vertex
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;
            };

            struct v2f {
                float4 position:SV_POSITION;
                fixed3 color : COLOR;
            }; 
                
            v2f vert(a2v v) { 
                v2f f;
                f.position = mul(UNITY_MATRIX_MVP,v.vertex);

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 normalDir = normalize( mul( v.normal, (float3x3) unity_WorldToObject) );

                fixed3 lightDir =  normalize( _WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光

                fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir, lightDir), 0) *_Diffuse.rgb;  //取得漫反射的颜色

                fixed3 reflectDir = normalize(reflect(-lightDir, normalDir));

                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(v.vertex, unity_WorldToObject).xyz);

                fixed3 specular = _LightColor0.rgb *  _Specular.rgb * pow(max(dot(reflectDir, viewDir), 0), _Gloss);

                f.color = diffuse + ambient + specular;
                return f;
            } 

            fixed4 frag(v2f f) :SV_Target{
                return fixed4(f.color,1);
            }

            ENDCG
        }
    }
    Fallback "Diffuse"
}
View Code

Specular Fragment  //漫反射+环境光+高光 ,Blinn光照模型

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Specular Fragment"{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)
        _Specular("Specular Color",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8,200)) = 10

    }
        SubShader{
            Pass{
                Tags{ "LightMode" = "ForwardBase" }
                CGPROGRAM
    #include "Lighting.cginc" //取得第一个直射光的颜色 _LightColor0 第一个直射光的位置_WorldSpaceLightPos0 
        #pragma vertex vert
        #pragma fragment frag
                fixed4 _Diffuse;
                fixed4 _Specular;
                half _Gloss;
            
            //application to vertex
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;
            };

            struct v2f {
                float4 position:SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldVertex :TEXCOORD1;
            }; 
                
            v2f vert(a2v v) { 
                v2f f;
                f.position = mul(UNITY_MATRIX_MVP,v.vertex);
                f.worldNormal = mul(v.normal, (float3x3) unity_WorldToObject);
                f.worldVertex = mul(v.vertex, unity_WorldToObject).xyz;
                return f;
            } 

            fixed4 frag(v2f f) :SV_Target{

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 normalDir = normalize(f.worldNormal);

                fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光

                fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir, lightDir), 0) *_Diffuse.rgb;  //取得漫反射的颜色

                fixed3 reflectDir = normalize(reflect(-lightDir, normalDir));

                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertex );

                fixed3 specular = _LightColor0.rgb *  _Specular.rgb * pow(max(dot(reflectDir, viewDir), 0), _Gloss);

                fixed3 tempColor = diffuse + ambient + specular;

                return fixed4(tempColor,1);
            }

            ENDCG
        }
    }
    Fallback "Diffuse"
}
View Code

 Specular Fragment//漫反射+环境光+高光,Blinn-Phong  光照模型

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
//Blinn-Phong光照模型
Shader "Specular Fragment BlinnPhong"{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)
        _Specular("Specular Color",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8,200)) = 10

    }
        SubShader{
            Pass{
                Tags{ "LightMode" = "ForwardBase" }
                CGPROGRAM
    #include "Lighting.cginc" //取得第一个直射光的颜色 _LightColor0 第一个直射光的位置_WorldSpaceLightPos0 
        #pragma vertex vert
        #pragma fragment frag
                fixed4 _Diffuse;
                fixed4 _Specular;
                half _Gloss;
            
            //application to vertex
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;
            };

            struct v2f {
                float4 position:SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float4 worldVertex :TEXCOORD1;
            }; 
                
            v2f vert(a2v v) { 
                v2f f;
                f.position = mul(UNITY_MATRIX_MVP,v.vertex);
                //f.worldNormal = mul(v.normal, (float3x3) _World2Object);
                f.worldNormal = UnityObjectToWorldNormal(v.normal);
                f.worldVertex = mul(v.vertex, unity_WorldToObject);
                return f;
            } 

            fixed4 frag(v2f f) :SV_Target{

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 normalDir = normalize(f.worldNormal);

                //fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光
                fixed3 lightDir = normalize( WorldSpaceLightDir(f.worldVertex).xyz );
                
                fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir, lightDir), 0) *_Diffuse.rgb;  //取得漫反射的颜色

                //fixed3 reflectDir = normalize(reflect(-lightDir, normalDir)); 

                //fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertex );
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex));

                fixed3 halfDir = normalize(viewDir + lightDir);

                fixed3 specular = _LightColor0.rgb *  _Specular.rgb * pow(max(dot(normalDir, halfDir), 0), _Gloss);

                fixed3 tempColor = diffuse + ambient + specular;

                return fixed4(tempColor,1);
            }

            ENDCG
        }
    }
    Fallback "Diffuse"
}
View Code

Texture  //纹理+环境光+高光,Blinn-Phong  光照模型

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Texture"{
    Properties{
        //_Diffuse("Diffuse Color",Color) = (1,1,1,1)
        _Color("Color",Color)=(1,1,1,1)
        _MainTex("Main Tex",2D) = "white"{}
        _Specular("Specular Color",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(10,200)) = 20
    }
        SubShader{
            Pass{
                Tags{"LightMode" = "ForwardBase"}
                CGPROGRAM
    #include "Lighting.cginc"
    #pragma vertex vert
    #pragma fragment frag

            //fixed4 _Diffuse;
            fixed4 _Color;
            sampler2D _MainTex;  
            float4 _MainTex_ST;  //名称固定,S:Scale,T:Transform
            fixed4 _Specular;
            half _Gloss;
            
            struct a2v{
                float4 vertex:POSITION;
                float3 normal:NORMAL;
                float4 texcoord:TEXCOORD0;  //取得纹理坐标
            };
            struct v2f {
                float4 svPos:SV_POSITION;
                float3 worldNormal:TEXCOORD0;
                float4 worldVertex:TEXCOORD1;
                float2 uv:TEXCOORD2;  //片元函数从这得到纹理坐标
            };

            v2f vert(a2v v) {
                v2f f;
                f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);
                f.worldNormal = UnityObjectToWorldNormal(v.normal);
                f.worldVertex = mul(v.vertex, unity_WorldToObject);
                f.uv = v.texcoord.xy * _MainTex_ST.xy  + _MainTex_ST.zw;  //_MainTex_ST.xy缩放,_MainTex_ST.zw偏移
                return f;
            }
            fixed4 frag(v2f f) :SV_Target{

                fixed3 normalDir = normalize(f.worldNormal);

                fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertex));

                fixed3 texColor = tex2D(_MainTex, f.uv.xy)*_Color.rgb;

                fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(normalDir, lightDir), 0);

                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex));

                fixed3 halfDir = normalize(lightDir + viewDir);

                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(dot(normalDir, halfDir), 0), _Gloss);

                fixed3 tempColor = diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.rgb*texColor;

                return fixed4(tempColor, 1);

            }

            ENDCG
        }
    }
    Fallback "Specular"
}
View Code

贴图前准备  //漫反射+环境光

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Rock"{
    Properties{
        //_Diffuse("Diffuse Color",Color) = (1,1,1,1)
        _Color("Color",Color)=(1,1,1,1)
        _MainTex("Main Tex",2D) = "white"{}
    }
        SubShader{
            Pass{
                Tags{"LightMode" = "ForwardBase"}
                CGPROGRAM
    #include "Lighting.cginc"
    #pragma vertex vert
    #pragma fragment frag

            //fixed4 _Diffuse;
            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            
            struct a2v{
                float4 vertex:POSITION;
                float3 normal:NORMAL;
                float4 texcoord:TEXCOORD0;
            };
            struct v2f {
                float4 svPos:SV_POSITION;
                float3 worldNormal:TEXCOORD0;
                float4 worldVertex:TEXCOORD1;
                float2 uv:TEXCOORD2;
            };

            v2f vert(a2v v) {
                v2f f;
                f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);
                f.worldNormal = UnityObjectToWorldNormal(v.normal);
                f.worldVertex = mul(v.vertex, unity_WorldToObject);
                f.uv = v.texcoord.xy * _MainTex_ST.xy  + _MainTex_ST.zw;
                return f;
            }
            fixed4 frag(v2f f) :SV_Target{

                fixed3 normalDir = normalize(f.worldNormal);

                fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertex));

                fixed3 texColor = tex2D(_MainTex, f.uv.xy)*_Color.rgb;

                fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(normalDir, lightDir), 0);

                fixed3 tempColor = diffuse  + UNITY_LIGHTMODEL_AMBIENT.rgb*texColor;

                return fixed4(tempColor, 1);

            }

            ENDCG
        }
    }
    Fallback "Specular"
}
View Code

Normal Map  //法线贴图,Scale可控

Shader "Rock Normal Map"{
    Properties{
        //_Diffuse("Diffuse Color",Color) = (1,1,1,1)
        _Color("Color",Color) = (1,1,1,1)
        _MainTex("Main Tex",2D) = "white"{} //主纹理贴图
    _NormalMap("Normal Map",2D) = "bump"{}  ////法线贴图,没有指定贴图则采用物体自身
    _BumpScale("Bump Scale",Float)=1  //凹凸参数
    }
        SubShader{
        Pass{
        Tags{ "LightMode" = "ForwardBase" }
        CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag

        //fixed4 _Diffuse;
        fixed4 _Color;
        sampler2D _MainTex;  
        float4 _MainTex_ST;
        sampler2D _NormalMap;  
        float4 _NormalMap_ST;
        float _BumpScale;
        
        struct a2v {
            float4 vertex:POSITION;
            //切线空间的确定是同通过切线和法线确定的
            float3 normal:NORMAL;
            float4 tangent:TANGENT;//tangent.w是用来确定切线空间中坐标轴的方向的 
            float4 texcoord:TEXCOORD0;
        };
        struct v2f {
            float4 svPos:SV_POSITION;
            //float3 worldNormal:TEXCOORD0;
            //float4 worldVertex:TEXCOORD1;
            float3 lightDir : TEXCOORD0;
            float4 uv:TEXCOORD1;  //xy用来存储MainTex纹理坐标 ,zw用来存储NormalMap的纹理坐标,充当法线
        };
        //把所有跟法线相关的运算都放在切线空间下
        v2f vert(a2v v) {
            v2f f;
            f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);
        //    f.worldNormal = UnityObjectToWorldNormal(v.normal);
        //    f.worldVertex = mul(v.vertex, _World2Object);
            f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
            f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;

            TANGENT_SPACE_ROTATION;//调用这个后之后,会得到一个矩阵 rotation 这个矩阵用来把模型空间下的方向转换成切线空间下

            //ObjSpaceLightDir(v.vertex)//得到模型空间下的平行光方向 
            f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); 

            return f; 
        }
        //把所有跟法线方向有关的法线方向是在切线空间下的
        fixed4 frag(v2f f) :SV_Target{

            //fixed3 normalDir = normalize(f.worldNormal);
            fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
            //
            //    fixed3 tangentNormal = normalize(  normalColor.xyz * 2 - 1 ) ; //切线空间下的法线
            fixed3 tangentNormal = UnpackNormal(normalColor);
            tangentNormal.xy = tangentNormal.xy*_BumpScale;
            tangentNormal = normalize(tangentNormal);

            fixed3 lightDir = normalize(f.lightDir);

            fixed3 texColor = tex2D(_MainTex, f.uv.xy)*_Color.rgb;

            fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(tangentNormal, lightDir), 0);

            fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rgb*texColor;

            return fixed4(tempColor, 1);

        }

        ENDCG
    }
    }
        Fallback "Specular"
}
View Code

Normal Map  //法线贴图,Scale、Alpha可控

Shader "Rock Alpha"{
    Properties{
        //_Diffuse("Diffuse Color",Color) = (1,1,1,1)
        _Color("Color",Color) = (1,1,1,1)
        _MainTex("Main Tex",2D) = "white"{}
    _NormalMap("Normal Map",2D) = "bump"{}
    _BumpScale("Bump Scale",Float)=1
        _AlphaScale("Alpha Scale",Float)=1
    }
        SubShader{
        Tags{ "Queue"="Transparent" "IngnoreProjector"="True" "RenderType"="Transparent" }
        Pass{
        Tags{ "LightMode" = "ForwardBase" }

        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

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

        //fixed4 _Diffuse;
        fixed4 _Color;
        sampler2D _MainTex;
        float4 _MainTex_ST;
        sampler2D _NormalMap;
        float4 _NormalMap_ST;
        float _BumpScale;
        float _AlphaScale;

        struct a2v {
            float4 vertex:POSITION;
            float3 normal:NORMAL;
            float4 tangent:TANGENT;//tangent.w是用来确定切线空间中坐标轴的方向的 
            float4 texcoord:TEXCOORD0;
        };
        struct v2f {
            float4 svPos:SV_POSITION;
            //float3 worldNormal:TEXCOORD0;
            //float4 worldVertex:TEXCOORD1;
            float3 lightDir : TEXCOORD0;
            float4 uv:TEXCOORD1;
        };

        v2f vert(a2v v) {
            v2f f;
            f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);
        //    f.worldNormal = UnityObjectToWorldNormal(v.normal);
        //    f.worldVertex = mul(v.vertex, _World2Object);
            f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
            f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;

            TANGENT_SPACE_ROTATION;//调用这个后之后,会得到一个矩阵 rotation 这个矩阵用来把模型空间下的方向转换成切线空间下

            //ObjSpaceLightDir(v.vertex)//得到模型空间下的平行光方向 
            f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); 

            return f; 
        }
        fixed4 frag(v2f f) :SV_Target{

            //fixed3 normalDir = normalize(f.worldNormal);
            fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
            //
            //    fixed3 tangentNormal = normalize(  normalColor.xyz * 2 - 1 ) ; //切线空间下的法线
            fixed3 tangentNormal = UnpackNormal(normalColor);
            tangentNormal.xy = tangentNormal.xy*_BumpScale;
            tangentNormal = normalize(tangentNormal);

            fixed3 lightDir = normalize(f.lightDir);

            fixed4 texColor = tex2D(_MainTex, f.uv.xy)*_Color;

            fixed3 diffuse = _LightColor0.rgb * texColor.rgb * max(dot(tangentNormal, lightDir), 0);

            fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rgb*texColor;

            return fixed4(tempColor,_AlphaScale*texColor.a );

        }

        ENDCG
    }
    }
        Fallback "Specular"
}
View Code

 

posted @ 2016-09-22 18:47  沐风先生  阅读(1009)  评论(0编辑  收藏  举报