Unity中的Shader都是要通过ShaderLab的基本语法进行编写。

        一、  下面我们先从Shaderlab基本语法开始入手

ShaderLab基本结构大致3个代码块儿(一、二、三)

(一) 属性  【Properties】

Shader “name”{

                          【Properties】//属性
                           }

unity 自定义类继承 unity自定义shader_c#

属性模块允许我们在可视化面板当中为材质添加要使用的原材料。

(二) Subshader算法   

unity 自定义类继承 unity自定义shader_unity 自定义类继承_02

        SubShader是专门为GPU渲染所编写的Shader的片段在ShaderLab中至少有一个SubShader,当然也可多个。

但是,显卡每次渲染处理的时候只能选择一个SubShaders执行。那多个SubShader的作用是为了不同硬件的渲染支持,为了Shader能在比较老的图形显卡中也能支持。一般比较越往下的SubShader要简化,运算指令要简单。

(三) 【FallBack】//后退

  作用是:如果SubShader里的所有算法都不能执行的话,就会后退回到最初始的状态 可以认为是默认(一般是所有硬件都支持的渲染方式)     

比如:  FallBack "Diffuse"   返回到漫反射的状态   

                二、Unity中的三种Shader介绍

unity 自定义类继承 unity自定义shader_着色器_03

 

unity 自定义类继承 unity自定义shader_着色器_04

 

 (一) surface shaders, 表面着色器(默认创建的Shader类型)

      Unity当中被推荐和鼓励使用的Shader,当你在Unity当中创建一个Shader时,默认的就是Surface Shader 。由于图型管线只识别vertex shaders   and  fragment shader这两种形式。Surface Shader 是在vertex shaders   and  fragment shader上面的的一种包装,最 终Unity 引擎还是会把Surface Shader 编译成能够被硬件识别和调用的vertex shaders   and  fragment shader.。Surface Shader 让我们可以不用去关心这些顶点和片段程序的细节,可以直接得到我们想要的着色器。这个着色器处理了很多光照细节。

unity 自定义类继承 unity自定义shader_unity_05

 

   (二)vertex and fragment shaders 顶点和片元着色器

      针对于比较细节上的处理,偏向于底层,可编程图形管线当中能够编写Shader的部分有两个:vertex shaders和 fragment shader。

unity 自定义类继承 unity自定义shader_c#_06

 

(三)fixed function shaders.固定功能管线着色器

unity 自定义类继承 unity自定义shader_着色器_07

   比如光照、纹理采样。 所有硬件平台都可支持,针对硬件能够执行的基本命令的Shader,当然,功能有限,但是,速度最快。

 

unity 自定义类继承 unity自定义shader_unity_08

unity 自定义类继承 unity自定义shader_着色器_09

 

unity 自定义类继承 unity自定义shader_游戏引擎_10

 

unity 自定义类继承 unity自定义shader_unity 自定义类继承_11

 

           三、Unity中的三种自定义Shader代码编写                   

     (一)我们以fixed function shaders固定功能管线着色器

 首先物体受光照影响表现:

unity 自定义类继承 unity自定义shader_游戏引擎_12

Shader "MyCustom/MyShader" {
	Properties {//属性
	// 属性名字  界面显示名  类型     值
		_Color("MyColor",color) = (1,0,0,1)
		_AmbientColor("AmbientColor",color) = (1,0,0,1)
		_SpecularColor("SpecularColor",color) = (1,0,0,1)
		_Shininess("Shininess",range(0,8)) = 3
		_Emission("EmissionColor",color) = (1,1,1,1)
		_MainTexture("MainTexture",2d) = ""
	}
	SubShader {//shader算法
		pass//通道(存储图像的色彩)
		{
			//color(1,0,0,1) //()表示直接赋值,固定值
			//color[_Color]//【】中括号表示使用参数值
			material
			{	//漫反射 必须依照光照,与灯光配合,将光打到物体表面反射光,我们才能看到物体
				diffuse[_Color]//漫反射命令,要想受光照影响,必须启用光照 lighting on
				ambient[_AmbientColor]//环境光
				specular[_SpecularColor]//高光
				shininess[_Shininess]//滑动条高光反射系数,配合启用高光的命令separateSpecular on 
				emission[_Emission]//自发光
			}
			lighting on//启动光照
			separateSpecular on //启用高光
			SetTexture[_MainTexture]//设置纹理
			{
			//与材质效果混合 double 是图片亮度的表现
			combine Texture*primary double
			}
		}
	}
// Fallback "Diffuse"  //固定功能管线着色器,几乎所有硬件都支持,所以这句话可以不要
}

unity 自定义类继承 unity自定义shader_c#_13

Properties 属性

Material 材质

Lighting光照

Settexture设置纹理

Pass通道(存储图像的色彩,色彩为什么是RGB,因为RGB是计算机颜色的三原色

表面着色器surface shaders没有Pass通道,因为它是vertex and fragment shaders 的包装,vertex and fragment shaders顶点片元着色器有Pass通道

      (二)表面着色器surface shaders的Shader代码案例

       如果想要实现些稍微复杂的效果, 就要用到表面着色器。表面着色器一般会用到CG代码块儿。

unity 自定义类继承 unity自定义shader_着色器_14

 代码如下:

Shader "Custom/NewSurfaceShader" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    	///_Normalmap ("Normalmap", 2D) = "Normal" {}
	    _Cubemap ("Cubemap", CUBE) = "Cube" {}//CUBE unity的立方体贴图
		_Glossiness ("Smoothness", Range(0,1)) = 0.5
		_Metallic ("Metallic", Range(0,1)) = 0.0
	}
	SubShader {
		Tags { "RenderType"="Opaque" }//描述渲染类型,当前是不透明的物体//Tags {"queue" = "transparent"}//透明的物体		
		LOD 200 //层级细节		
		CGPROGRAM//代表当前是CG代码块,开始写CG语言了
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows//编译指令
       //#pragma编译指令告诉我们surface关键词是一个表面着色器 ,  //surf是调用的方法 ,下面有一个surf方法   
       //Standard  光照表现   基于物理的光照模型,就是我们现在所说的全局光照,物体与物体之间的影响,
                        //(5.0之前是漫反射 Lambert只是受到光照而已,5.0之后实现了次时代的效果)
       //fullforwardshadows 阴影表现(平行光、点光、聚光都是有阴影的)
		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0 //表示GPU硬件支持3.0 不写这句话默认是2.0
		sampler2D _MainTex;//CG 中的图片类型,sampler2D是CG语言的一个类, //上面 属性Properties 里面声明属性_MainTex时图片表现是2D,                
    sampler2D _Normalmap;  //但是在CG里面,如果想让CG认识_MainTex,必须在CG代码块儿里面重新声明成sampler2D类型
        samplerCUBE _Cubemap;
		struct Input { // 类似于有一个传入值
			float2 uv_MainTex;//记录uv纹理坐标,在CG中使用图片需要记录uv纹理坐标 
           /// float2 uv_Normalmap;
            float3 worldRelfect;//牵扯到反射效果,记录XYZ轴的相关影像效果                     
		};
		half _Glossiness;//CG中的浮点型
		half _Metallic;
		fixed4 _Color;//CG中的四阶向量
      //5.0之后光照用的Standard,所以用SurfaceOutputStandard ,如果不是Standard用SurfaceOutput就可以了
		void surf (Input IN, inout SurfaceOutputStandard o) {//IN传进来(UV的传入),inout声明的o值传出去
			// 下面是一个公式 (主纹理,uv信息),Color表示把颜色应用在uv的所有的点上,有相应的表现
			 fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			 o.Albedo = c.rgb; //在表面着色器里使物体受到光照的话用o.Albedo,它表示漫反射, //把拿到的图片的rgb信息应用到漫反射表现效果上                          
             o.Emission=texCUBE(_Cubemap,IN.worldRelfect).rgb; //是立方体贴图反射周围环境的命令,这是没有法线贴图时反射效果的代码写法
         o.Normal=UnpackNormal(tex2D (Normalmap, IN.uv_Normalmap)); //是法线贴图    
         // Metallic and smoothness come from slider variables
			o.Metallic = _Metallic;//金属光泽表现
			o.Smoothness = _Glossiness;//高光光泽度
			o.Alpha = c.a;
		}
		ENDCG  //CG语言代码块儿结束
	}
	FallBack "Diffuse"//如果SubShader里的所有算法都不能执行的话,就会后退回到最初始的状态     
}

注意:

unity 自定义类继承 unity自定义shader_unity 自定义类继承_15

Properties属性里面的所有东西都是Shaderlab结构,Shaderlab知道这些属性你可以在外面调节,但是如果要在表面着色器的CG代码块里进行Shader使用的话都需要重新声明

上面说到Shader中法线贴图与CubeMap贴图(反射)只能用一个。

为什么呢?是因为如果两个都想用到的时候需要引INTERNAL_DATA的命令。

      如果没有用到法线贴图,想要实现反射时物体表面把图片直接反射过来就可以了,但是如果牵扯到法线、物体表面、又要牵扯到反射效果的话,就不仅仅是物体表面把图片反射过来就行了,还要考虑到法线贴图里面的凹凸细节里面的像素,反射效果就比普通平面效果稍微复杂一些,这时就要借助WorldReflectionVector。

unity 自定义类继承 unity自定义shader_unity 自定义类继承_16

unity 自定义类继承 unity自定义shader_unity_17

unity 自定义类继承 unity自定义shader_着色器_18

下面是详细代码: 

Shader "Custom/NewSurfaceShader" {
	Properties{
		_Color("Color", Color) = (1,1,1,1)
		_MainTex("Albedo (RGB)", 2D) = "white" {}
	   _Normalmap ("Normalmap", 2D) = "Normal" {}
	  _Cubemap("Cubemap", CUBE) = "Cube" {}
	_Glossiness("Smoothness", Range(0,1)) = 0.5
		_Metallic("Metallic", Range(0,1)) = 0.0
	}
		SubShader{
		Tags{ "RenderType" = "Opaque" }	
		LOD 200		
		CGPROGRAM
#pragma surface surf Standard fullforwardshadows//编译指令
				
#pragma target 3.0 
	sampler2D _MainTex;
	sampler2D _Normalmap;
	samplerCUBE _Cubemap;
	struct Input { 
		float2 uv_MainTex;
		float2 uv_Normalmap;
		float3 worldRefl;   
		//法线与反射效果配合需要将添加到Input结构中
		INTERNAL_DATA
	};
	half _Glossiness;//CG中的浮点型
	half _Metallic;
	fixed4 _Color;
	void surf(Input IN, inout SurfaceOutputStandard o) {
		fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
		o.Albedo = c.rgb;                       	
		//不需要法线的反射效果                           
		// o.Emission=texCUBE(_Cubemap,IN.worldRefl).rgb; 
		//下面是法线与反射效果配合,编写完法线命令输出后并结合WorldReflectionVector函数将计算像素中的逐个向量
		o.Normal = UnpackNormal(tex2D(_Normalmap, IN.uv_Normalmap)); //是法线贴图
		o.Emission = texCUBE(_Cubemap, WorldReflectionVector(IN, o.Normal)).rgb;
		o.Metallic = _Metallic;//金属光泽表现
		o.Smoothness = _Glossiness;//高光光泽度
		o.Alpha = c.a;
	}
	ENDCG  
	}
		FallBack "Diffuse"
}

补充如何创建Cubemap

unity 自定义类继承 unity自定义shader_unity 自定义类继承_19

unity 自定义类继承 unity自定义shader_着色器_20