UnityShader

文章目录

  • 一、shader基本介绍
  • 二、Shaderlab基本结构
  • 三、CG语言介绍
    • 语法区别
  • 四、vertexShader介绍
    • 关于语意的一些说明
    • C#索引器
    • mvp变换
    • 顶点颜色变换
    • 世界坐标 使用[函数转换](https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html)
    • 顶点位移
  • 五、FixFunctionShader介绍
  • 六、SurfaceShader介绍
  • 七、光处理
    • 光处理方法总结
  • 八、使用fragment光处理
    • 使用saturate限制范围(0,1)
    • 光处理vertex与fragment比较
  • 九、 使用fragment边缘泛光渲染
  • 十、 fragment纹理采样
  • 十一、实现水波仿真效果
  • 十二、阿尔法混合
  • 十三、凹凸映射
  • 十四、使用cube纹理,实现更逼真效果

一、shader基本介绍

shader可分为vertex与fragment
1、vertex称为定点着色器,负责对模型中每个定点进行定义,可包括位置、法向量、切向量等,vertex可去到所有模型中的定点,并传递给fragment进行像素颜色返回
2、fragment称为片段着色器,是对于每个定点间进行过度处理,可认为是对于每个需渲染的像素的处理,一个像素对应一个fragment,所以在fragment中处理事物会十分消耗资源。

二、Shaderlab基本结构

shader“name”{
	[Properties] //提供一些变量提供给编辑器调控
	SubShaders //Shader渲染方案,可以写多个,优先执行靠前的方案,如果执行有问题,则会选择下一个执行
	[FallBack] //所有方案都没有执行成功,调用自带的基本方案
}

三、CG语言介绍

Shader "Sbin/vf1"{
	SubShader{
		pass{
			CGPROGRAM //CG语言起始,大写表示
				#pragma vertex vert //定义顶点着色器函数
				#pragma fragment frag //定义片段着色器函数,两个函数都需要编写
				#define TE FL4(fl4.ab, fl3.zy);
				
				struct rec
				{
					float4 pos;
					float2 uv;
				}; //声明结构体,与C中相同

				typeof float4 FL4; //别名

				void vert(in float2 objPos:POSTION, out float4 pos:POSTION, out float4 col:COLOR){ //in代表输入,out代表输出,inout代表输入并且输出,:后跟着语意
					pos float4(objPos, 0, 1);
					col = float4(0, 0, 0, 1);
				}

				void frag(inout float4 col:COLOR){
					//col = folat4(1, 0, 0, 1);
					float r = 1;
					float g = 0;
					float b = 0;
					float a = 1;
					col = float4(r, g, b, a);
					
					float2 f12 = float(1, 0);
					float3 f13 = float(1, 0, 1);
					float4 f14 = float(1, 1, 0, 1);

					FL4 f1 = TE // 使用xyzw或rgba取得分量,swizzle操作可以颠倒、组合、重复顺序,但是每次取值rgba和xyzw只能选一种
					col = f1;
					
					float2x4 M2x4 = (f14, 0, 1, 0, 1); //矩阵定义
					col = M2x4[0];

					float arr[4] = {1, 2, 3, 4}; //数组不可以使用swizzle,只能使用[角标],从0开始,参数传递按照值拷贝方式
					
					
				}
			ENDCG
		}
	}
}

语法区别

  1. float 32位精度
  2. half 16位精度
  3. fixed 9位有符号定点数
  4. bool 等同于C#中的bool
  5. int 32位精度,描述整数
  6. cg profile不支持指针,枚举,联合,case

内建函数
数学
几何
纹理
导数

  • tips:可以include “库目录加文件名”调用已有函数(直接写函数名即可)
  • cg语言具体参考网址
  • 定义多维变量,后边跟数字代表几阶,最高为4

四、vertexShader介绍

语意:

语意名 含义
POSITION 输出坐标点
COLOR 颜色
TEXCOORD 纹理

关于语意的一些说明

  1. 一种语意只能传递一次
  2. 如果返回值为结构体,则不需要为vertex声明语意,根据语意fragment可以直接接收返回值,如果结构体中没有对应语意则采用默认值。
  3. 结构体传参不需要声明inout就会根据语意传递
  4. 顶点输入结构体,只能接收系统给的颜色、法线、切线、位置等,不可自定义
  5. 使用文件导入的方式,进行使用自己之前定义的结构体,include自己定义好的cginc使用自己定义好的结构体,可以引用UnityCG.cginc已经包装好了的部分结构体。
  6. properties shaderlab
    CG语言中无法直接识别properties中内容,需要声明一个相应的变量对应
    CG语言中也可以编写uniform来让提供一个变量,没有声明会默认uniform
uniform float4 _SecondColor; //可以通过csharp脚本赋值,默认为黑(0, 0, 0, 0)

GetComponent<Render>().material.SetVector("_SecondColor", new Vector4(1, 0, 0, 1));

C#索引器

mvp变换

模型->世界->摄像机->投影
Camera.main.projectionMatrix * transform.localToWorldMarix * Camera.main.worldToCameraMatrix;
CG中使用mul函数进行矩阵相乘

顶点颜色变换

使用判断xyz坐标改变颜色语意传递给fragment
使用屏幕空间(-1,1)处理物体 mvp后手动投影变换

世界坐标 使用函数转换

顶点位移

mvp乘以位移顶点

五、FixFunctionShader介绍

Shader"Sbin/vf1"{ //shader名字以层级命名(vf1是名字,前面的为相对路径)
	properties{ //提供编辑器可以改变的属性
		_Color("Color", color) = (1, 1, 1, 1) //属性名(自定义名字,类型) = 默认值
		_Ambient("Ambient", color) = (0.3, 0.3, 0.3, 1)
		_Specular("Specular", color) = (1, 1, 1, 1)
		_Shininess("Shininess", range(0, 8)) = 4 //range范围,返回float
		_Emission("Emission", color) = (1, 1, 1, 1)
		_Constant("ConstantColor", color) = (1, 1, 1, 0.3)
		_MainTex("MainTex", 2d) = ""{} 
		_SecondTex("SecondTex", 2d) = ""{}
	}
	SubShader{
		Tags {"Queue" = "Transparent"} //设置渲染队列标签
		pass{ //pass通道
			Blend SrcAlpha OneMinusSrcAlpha //采用当前目标阿尔法值,与1-当前目标阿尔法值的比例进行阿尔法混合,具体内容查询ShaderLab:Blending
			//color(1, 1, 1, 1) //设置颜色为固定值值1,1,1,1,顺序为红、绿、蓝、阿尔法
			//color[_Color] //设置颜色为变量_Color,[]代表颜色可变,但还是没有立体效果
			material{ //设置材质
				diffuse(_Color) //设置漫反射颜色,或者是说本身的固有色
				ambient[_Ambient] //设置环境光强度
				specular[_Specular] //设置镜面高光强度
				shininess[] //设置镜面高光反射区域
				emission[_Emission] //设置自身发光
			}
			lighting on //固定管线功能,打开光照
			separatespecular on //设置集中高光,在使用specular时开启

			//进行贴图和材质混合
			settexture[_MainTex]
			{
				combine texture * primary double//使用_MainTex贴图,primary是fixfunctionshader自带的,使用之前设置好的材质,相乘代表贴图和材质进行混合,double代表乘以2,quad代表乘以4,参数越大越亮
			}	

			//进行第二个贴图混合,不能使用primary,primary只会和初始顶点光照进行混合,使用previous采用和之前所有材质进行混合,但混合个数也是有限的
			settexture[_SecondTex] 
			{
				//matrix[] //可设置矩阵来进行更复杂的图形运算
				combine texture * previous double, texture * _Constant //阿尔法参数,texture只使用这个贴图的阿尔法,_Constant可调整阿尔法透明度
			}
		}
	}
}

六、SurfaceShader介绍

更容易编写光处理,对vertex和fragment的包装

Shader "Custom/sf" {
	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 {
		// SurfaceShader自动添加pass通道
		Tags { "RenderType"="Opaque" } //不透明标签
		LOD 200 //程序细节
		
		CGPROGRAM //CG语法起始
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows //pragma编译指令,以#开头 surface以SurfaceShader编写,函数名,Standard光照模型,[其他选项],fullforwardshadows阴影类型

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0 //使用硬件shader model 3.0,默认2.0

		sampler2D _MainTex; //二维纹理,对应Properties属性

		struct Input {
			float2 uv_MainTex; //纹理属性结构体必须使用uv或者uv2开头
		};

		//与Properties属性对应
		half _Glossiness;
		half _Metallic;
		fixed4 _Color;

		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 //CG语法结束
	}
	FallBack "Diffuse"
}

七、光处理

forward rendering path details
光照建议使用surfaceshader

  1. 法向量从物体坐标转世界坐标,乘以物体到世界矩阵的逆的转置(unity使用的右手坐标系)
  2. 漫反射,计算入射方向和法向量的夹角,线性
  3. 背面剔除,把法向量和点到摄像机向量点乘,如果小于0则不去渲染
  4. 反射光,计算反射方向和摄像机方向的夹角,线性不好,一般使用多幂,反射方向的计算,2*(归一化入射方向与归一化法向量的点积)*归一化法向量-入射方向

光处理方法总结

  1. Phong:UNITY_LIGHTMODEL_AMBIENT环境光 + 漫反射 + 镜面反射
  2. BlinnPhong:与Phong类似,区别在于计算镜面反射时,不去计算反射方向,而是计算入射方向和摄像机方向相加规范化,与法向量点积代替之前方法
  3. 兰伯特:环境光+漫反射

八、使用fragment光处理

使用saturate限制范围(0,1)

光处理vertex与fragment比较

vertex光处理不真实,但计算量比较小
fragment光处理计算量大大提升,模拟效果比较好
一般使用在fragment处理光
vertex传递物体法向量和点位置
在fragment计算世界法向量和光照向量

  1. 支持点光源计算,unityshadervariables
  2. 阴影处理 fallback “Diffuse” 自动调用系统漫反射阴影处理 autolight.cginc
  3. blend,将多个pass混合处理 blend factors

九、 使用fragment边缘泛光渲染

法向量点击视角方向为0
使用多个pass blend混合 查询blend混合因子等
设计距离公式,实现动态变换颜色fragment

十、 fragment纹理采样

tex2D(sampler2d, uv)
maintex_st计算平铺和偏移,可以使用transform_tex

  • 使用DecodeLightmap(tex2D(unity_Lightmap, uv))采样光照贴图纹理,与之前颜色相乘
    控制程序提供uv,settextureoffset和settexturescale
  • 多图采样叠乘再平均,有多图叠加效果,有模糊效果,使用target3.0可以对tex2D多传递两个值(对x和y的偏导,ddx,ddy)实现多点采样,使用sin函数对uv采样取值,多次叠加实现动态效果
  • 设置位图重复,传递不同uv

十一、实现水波仿真效果

用一个数组迭代,周围8个状态<<2减去自身,成为下一个迭代状态,可以限定一个值区域,uv值可以由左边减去右边除以2计算,通过color传递给shader(注意color只接收0到1范围,注意变换范围传递),状态能量值缩小
computshader gpgpu dx11可以支持,具体代码以后会给出~

十二、阿尔法混合

tags transparent渲染队列
ZWrite off,半透明物体选择深度关闭
Ztest 选择深度测试方式,与深度缓存比较方式,真才能显示像素颜色
如果要渲染一个被遮挡的物体,可以选择其他深度测试来进行渲染,注意zwrite的开关
(*)半透明物体使用camera.setreplaceshader

  • 深度测试会中zwrite会修改渲染好的画面中深度值,从而改变对应画面深度效果

十三、凹凸映射

从灰度产生法线纹理,计算像素上下灰度差,与左右灰度差进行叉乘,作为一个颜色存入图片,即使用法线纹理

十四、使用cube纹理,实现更逼真效果

通过给出的6个纹理面,计算视野到对应像素点反射的方向,采取对应纹理进行渲染

你可能感兴趣的:(Unity,Shader)