UnityShader入门学习——Unity的Shader

Posted 番茄猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UnityShader入门学习——Unity的Shader相关的知识,希望对你有一定的参考价值。

1 Unity Shader介绍

1.1 Unity Shader的基础:ShaderLab


1.2 Unity Shader属性块

Shader ""

	Properties
	
		_Int("Int", Int) = 2
		_Float("Float", float) = 1.5
		_Range("Range", range(0.0, 2.0)) = 1.0
		_Color("Color", Color) = (1, 1, 1, 1)
		_Vector("Vector", Vector) = (1, 4, 3, 8)
		_MainTex("Texture", 2D) = "white"
		_3D("3D", 3D) = "black"
	


1.3 Unity Shader SubShader

Tags

Tags可以写在SubShader的一开始(所有的Pass用),也可以写在Pass块的内部(该Pass用)

渲染设置

同Tags一样也可以写在Pass中或者写在Pass外面(SubShader一开始)

Pass介绍

Pass里面可以定义Pass名称
Pass里面的Tags还可以有额外的设置

还有CG语言所写的代码,主要是顶点片元着色器,使用以下关键字包裹
CGPROGRAM
ENDCG

FallBack

2 SurfaceShader介绍

SurfaceShader实际上是在顶点、片元着色器的基础上又进行了一层的封装,我们可以通过Show GenerateCode来查看到。(我们可以看到编译后的顶点、片元着色器是非常复杂的)

SurfaceShader的结构和前面的顶点、片元着色器的结构是一样的。主要区别在于SubShader中。


3 UnityShader != 真正的Shader

Unity Shader实际上指的就是一个ShaderLab文件。以.shader作为后缀的一种文件。在Unity shader里面,我们可以做的事情远多于一个传统意义上的Shader。

在传统的shader中,我们仅可以编写特定类型的Shader,例如顶点着色器,片元着色器等。在Unity Shader中,我们可以在同一个文件里面同时包含需要的顶点着色器和片元着色器代码。

在传统shader中,我们无法设置一些渲染设置,例如是否开启混合,深度测试等,这些是开发者在另外的代码中自行设置的。而Unity shader中,我们通过一行特定的指令就可以完成这些设置。

在传统shader中,我们需要编写冗长的代码设置着色器的输入和输出,要小心的处理这些输入输出的位置对应关系等。而在Unity shader中,我们只需要在特定语句块中声明一些属性,就可以依靠材质来方便的改变这些属性。而对于模型自带的数据(如顶点,纹理坐标,法线等),Unity Shader也提供了直接访问的方法,不需要开发者自行编码来传给着色器。

关于UnityShader的入门学习

1.逐顶点的漫反射Shader

Shader "Mocha/04 Diffuse Vertex"{//逐顶点的漫反射
    
    Properties{
    
    _Diffuse("Diffuse Color",Color)=(1,1,1,1)
    }


    SubShader{
    
        Pass{
            //只有定义了正确的LightMode才能得到一些Unity的内置光照变量
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
#include  "Lighting.cginc"    //取得第一个直射光的颜色_LightColor0 Unity内置  取得第一个直射光的位置 _WorldSpaceLightPos0

            fixed3 _Diffuse;

            //顶点函数 这里只是声明了顶点函数的函数名
            //基本作用 完成顶点坐标从模型空间到剪裁空间的转换(从游戏环境到相机视野屏幕上)
#pragma vertex vert
            //片元函数 这里只是声明了片元函数的函数名
            //基本作用 返回模型对应的屏幕上的每一个像素的颜色值
#pragma fragment frag
            
            //使用结构体存储
            //a2v 即 application to vertex
            struct a2v{ 
                float4 vertex:POSITION;//告诉Unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;//告诉Unity把模型空间下的法线方向填充给normal
            };

            //使用结构体存储
            struct v2f{
                float4 position:SV_POSITION;//告诉Unity存储剪裁空间下的顶点坐标
                fixed3 color:COLOR;//存储颜色语义
            };

            v2f vert(a2v v){
                v2f f;

                f.position=mul(UNITY_MATRIX_MVP,v.vertex); //将模型空间坐标转换到剪裁空间坐标

                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;    //获取到Unity环境光

                fixed3 normalDir=normalize(mul(v.normal,(float3x3)_World2Object));//将模型空间转换到世界空间,再将向量量化

                //_World2Object 在左侧世界空间转模型空间,在右侧模型空间转世界空间

                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 "VertexLit"

}

2.逐像素(片元)的漫反射Shader

 

Shader "Mocha/06 Diffuse Fragment HalfLambert"{//逐像素(片元)的半兰伯特光照
    
    Properties{
    
    _Diffuse("Diffuse Color",Color)=(1,1,1,1)
    }


    SubShader{
    
        Pass{
            //只有定义了正确的LightMode才能得到一些Unity的内置光照变量
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
#include  "Lighting.cginc"    //取得第一个直射光的颜色_LightColor0 Unity内置  取得第一个直射光的位置 _WorldSpaceLightPos0

            fixed3 _Diffuse;

            //顶点函数 这里只是声明了顶点函数的函数名
            //基本作用 完成顶点坐标从模型空间到剪裁空间的转换(从游戏环境到相机视野屏幕上)
#pragma vertex vert
            //片元函数 这里只是声明了片元函数的函数名
            //基本作用 返回模型对应的屏幕上的每一个像素的颜色值
#pragma fragment frag
            
            //使用结构体存储
            //a2v 即 application to vertex
            struct a2v{ 
                float4 vertex:POSITION;//告诉Unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;//告诉Unity把模型空间下的法线方向填充给normal
            };

            //使用结构体存储
            struct v2f{
                float4 position:SV_POSITION;//告诉Unity存储剪裁空间下的顶点坐标
                fixed3 wordNormalDir:COLOR;//存储颜色语义
            };

            v2f vert(a2v v){
                v2f f;

                f.position=mul(UNITY_MATRIX_MVP,v.vertex); //将模型空间坐标转换到剪裁空间坐标

                f.wordNormalDir=mul(v.normal,(float3x3)_World2Object);

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

                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;    //获取到Unity环境光

                fixed3 normalDir=normalize(f.wordNormalDir);//将模型空间转换到世界空间,再将向量量化

                //_World2Object 在左侧世界空间转模型空间,在右侧模型空间转世界空间

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

                float halfLambert=dot(normalDir,lightDir)*0.5+0.5;    //半兰伯特光照算法

                fixed3 diffuse=_LightColor0.rgb*halfLambert*_Diffuse.rgb;//取得漫反射的颜色

                fixed3 tempColor=diffuse + ambient;

                return fixed4(tempColor,1);
            }


            ENDCG
        }
    
    }
    Fallback "VertexLit"

}

 

3.逐顶点的高光反射Shader

 

Shader "Mocha/07 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{
            //只有定义了正确的LightMode才能得到一些Unity的内置光照变量
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
#include  "Lighting.cginc"    //取得第一个直射光的颜色_LightColor0 Unity内置  取得第一个直射光的位置 _WorldSpaceLightPos0

            fixed3 _Diffuse;
            fixed4 _Specular;
            half _Gloss;

            //顶点函数 这里只是声明了顶点函数的函数名
            //基本作用 完成顶点坐标从模型空间到剪裁空间的转换(从游戏环境到相机视野屏幕上)
#pragma vertex vert
            //片元函数 这里只是声明了片元函数的函数名
            //基本作用 返回模型对应的屏幕上的每一个像素的颜色值
#pragma fragment frag
            
            //使用结构体存储
            //a2v 即 application to vertex
            struct a2v{ 
                float4 vertex:POSITION;//告诉Unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;//告诉Unity把模型空间下的法线方向填充给normal
            };

            //使用结构体存储
            struct v2f{
                float4 position:SV_POSITION;//告诉Unity存储剪裁空间下的顶点坐标
                fixed3 color:COLOR;//存储颜色语义
            };

            v2f vert(a2v v){
                v2f f;

                f.position=mul(UNITY_MATRIX_MVP,v.vertex); //将模型空间坐标转换到剪裁空间坐标

                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;    //获取到Unity环境光

                fixed3 normalDir=normalize(mul(v.normal,(float3x3)_World2Object));//将模型空间转换到世界空间,再将向量量化

                //_World2Object 在左侧世界空间转模型空间,在右侧模型空间转世界空间

                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,_World2Object).xyz);//获取到相机视角方向单位向量

                fixed3 specular=_LightColor0.rgb*_Specular*pow(max(dot(reflectDir,viewDir),0),_Gloss);//计算的到高光颜色(其中_Gloss为高光参数 根据效果需要更改数值 一般取大于10的数值)

                f.color=diffuse + ambient+specular;

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

                return fixed4(f.color,1);
            }


            ENDCG
        }
    
    }
    Fallback "VertexLit"

}

 

4.逐像素(片元)的高光反射Shader

Shader "Mocha/08 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{
            //只有定义了正确的LightMode才能得到一些Unity的内置光照变量
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM

#include  "Lighting.cginc"    //取得第一个直射光的颜色_LightColor0 Unity内置  取得第一个直射光的位置 _WorldSpaceLightPos0

            fixed3 _Diffuse;
            fixed4 _Specular;
            half _Gloss;

            //顶点函数 这里只是声明了顶点函数的函数名
            //基本作用 完成顶点坐标从模型空间到剪裁空间的转换(从游戏环境到相机视野屏幕上)
#pragma vertex vert
            //片元函数 这里只是声明了片元函数的函数名
            //基本作用 返回模型对应的屏幕上的每一个像素的颜色值
#pragma fragment frag
            
            //使用结构体存储
            //a2v 即 application to vertex
            struct a2v{ 
                float4 vertex:POSITION;//告诉Unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;//告诉Unity把模型空间下的法线方向填充给normal
            };

            //使用结构体存储
            struct v2f{
                float4 position:SV_POSITION;//告诉Unity存储剪裁空间下的顶点坐标
                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)_World2Object);
                f.worldVertex=mul(v.vertex,_World2Object).xyz;
                return f;
            }
            fixed4 frag(v2f f) : SV_Target{

                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;    //获取到Unity环境光

                fixed3 normalDir=normalize(f.worldNormal);//将模型空间转换到世界空间,再将向量量化

                //_World2Object 在左侧世界空间转模型空间,在右侧模型空间转世界空间

                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*pow(max(dot(reflectDir,viewDir),0),_Gloss);//计算的到高光颜色(其中_Gloss为高光参数 根据效果需要更改数值 一般取大于10的数值)

                fixed3 tempColor=diffuse + ambient+specular;

                return fixed4(tempColor,1);
            }


            ENDCG
        }
    
    }
    Fallback "VertexLit"

}

 

以上是关于UnityShader入门学习——Unity的Shader的主要内容,如果未能解决你的问题,请参考以下文章

关于UnityShader的入门学习

Unity Shader入门精要学习笔记 - 第11章 让画面动起来

Unity Shader入门总结

Unity Shader入门教程

Unity Shader入门精要学习笔记 - 第9章 更复杂的光照

UnityShader入门精要-3.3 UnityShader的结构