Unity着色器shader开发知识

简介

    • 着色器
    • 第一个Unity着色器
    • 图形管线
    • 坐标空间变换
    • 第一个Unity光照着色器
    • 实现镜面反射
    • 表面着色器


着色器

什么是着色器
着色器是通过代码来模拟物体表面在微观等级上发生的事情,使得我们眼睛看到的最终图像感觉很真实。换个层面讲,着色器是运行在 GPU 上的一段代码。

渲染是透视绘图
绘图过程可以分为:勾勒轮廓阶段、绘图阶段

固定函数渲染管线、可编程渲染管线

着色器的类型
1、顶点着色器—vertex shader:在每个顶点上执行的着色器
2、片元着色器—fragment shader:在每个最终图像中可能出现的像素上的着色器
3、无光照着色器—unlit shader:将 vertex 和 pixel 着色器放在一个文件内
4、表面着色器—surface shader:包含 vertex 和 fragment 着色器的功能。
5、图像特效着色器—image-effect shader:实现屏幕特效,诸如抗锯齿、环境光遮蔽、模糊、溢光等。
6、计算着色器—compute shader:进行一些计算的着色器,实现诸如物理模拟、图像处理、光线追踪等。

坐标系统
每个着色器中的计算都是在特定的坐标系统下面进行的。Shader中的坐标系统主要有如下几个:
1、本地空间(对象空间):指的是带渲染模型的相对坐标系。
2、世界空间:指的是整个带渲染场景的坐标系。
3、视图空间:从观察者(相机)的视角来看的相应的坐标系。
4、剪裁空间:范围从-1.0到1.0
5、屏幕空间:二维的坐标系统
6、切线空间:用来计算法线贴图
在着色器中,经常性地需要从一个坐标空间转换到另一个坐标空间,选择合适的坐标空间将会减少这些转换操作,从而使得计算更加方便,渲染更加快速。

光源类型
Unity中有以下几种光源类型:
1、点光源:一个点向周围相等地发射光,强度随距离衰减
2、方向光源(平行光源):发出的每条光线都是平行的,没有强度衰减
3、区域光源(面光源):只能在烘焙的时候使用,光从一个区域内发出。

渲染类型
前向渲染:在前向渲染中,场景的信息输入到渲染器中,每个三角面都被光栅化,对应每个光源都有一个着色通道。
延迟渲染:将光照/渲染计算推迟到第二步进行计算。我们这样做的目的是为了避免多次(超过1次)渲染同一个像素。


第一个Unity着色器

定义颜色

Shader "Unlit/MonoChromeShader"
{
	Properties
	{
		_Color("_Color", Color) =  {1,0,0,1};
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"
			
            fixed4 _Color;
            
			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
			};
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				return _Color;
			}
			ENDCG
		}
	}
}


图形管线

图形API:
OpenGL
Metal
Vulkan
Direct3D

图形管线(渲染管线)通用结构:
Unity着色器shader开发知识_第1张图片

栅格化器

无光照着色器的结构

数据流:
Unity着色器shader开发知识_第2张图片

顶点数据结构体:

struct appdata
			{
				float4 vertex : POSITION;
			};

顶点函数:

v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				return o;
			}

片元数据结构体:

struct v2f
			{
				float4 vertex : SV_POSITION;
			};

片元函数:

fixed4 frag (v2f i) : SV_Target
			{
				return _Color;
			}

添加顶点颜色支持:

Shader "Unlit/MonoChromeShader"
{
	Properties
	{
		_Color("_Color", Color) =  (1,0,0,1)
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

            fixed4 _Color;


			struct appdata
			{
				float4 vertex : POSITION;
				float4 color : COLOR;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float4 color : COLOR;
			};


			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.color = v.color;
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				return i.color;
			}
			ENDCG
		}
	}
}


坐标空间变换

对象空间(Object Space)
世界空间(World Space)
相机空间(Camera Space)
剪裁空间(Clip Space)
标准化设备坐标(Normalized Device Space)
屏幕空间(Screen Space)


第一个Unity光照着色器

漫反射(Diffuse)
镜面反射(Specular)
环境光(Ambient)

计算基本光照_漫反射部分
在这里插入图片描述
在这里插入图片描述

实现漫反射
添加纹理属性
添加环境光

Shader "Unlit/DiffuseShader"
{
	Properties
	{
		_Color("_Color", Color) =  (1,0,0,1)
		_DiffuseTex("Texture", 2D) = "white"{}
		_Ambient("Ambient", Range(0, 1))= 0.25
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase"}
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"
			#include "UnityLightingCommon.cginc"

            fixed4 _Color;
			sampler2D _DiffuseTex;
			float4 _DiffuseTex_ST;
			float _Ambient;

			struct appdata
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float3 worldNormal : TEXCOORD1;
				float2 uv : TEXCOORD0;
			};
		
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				float3 worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldNormal = worldNormal;
				o.uv = TRANSFORM_TEX(v.uv, _DiffuseTex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				float3 normalDirection = normalize(i.worldNormal);
				float4 tex = tex2D(_DiffuseTex, i.uv);
				float nl = max(_Ambient, dot(normalDirection, _WorldSpaceLightPos0.xyz));
				float4 diffuseTerm = nl * _Color * tex * _LightColor0;
				return diffuseTerm;
			}
			ENDCG
		}
	}
}


实现镜面反射

在这里插入图片描述
在这里插入图片描述
在之前漫反射的基础上,增加镜面反射

Shader "Custom/SpecularShader"
{
	Properties
	{
		_Color("_Color", Color) =  (1,0,0,1)
		_DiffuseTex("Texture", 2D) = "white"{}
		_Ambient("Ambient", Range(0, 1))= 0.25
		_SpecColor("Specular Material Color", Color) = (1,1,1,1)
		_Shininess("Shininess", Float) = 10
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase"}
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"
			#include "UnityLightingCommon.cginc"

            fixed4 _Color;

			sampler2D _DiffuseTex;
			float4 _DiffuseTex_ST;

			float _Ambient;

			float _Shininess;

			struct appdata
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float3 worldNormal : TEXCOORD1;
				float2 uv : TEXCOORD0;
				float4 vertexWorld : TEXCOORD2;
			};


			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.vertexWorld = mul(unity_ObjectToWorld, v.vertex);
				float3 worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldNormal = worldNormal;
				o.uv = TRANSFORM_TEX(v.uv, _DiffuseTex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				float3 normalDirection = normalize(i.worldNormal);
				float3 viewDirecttion = normalize(UnityWorldSpaceViewDir(i.vertexWorld));
				float3 lightDirection = normalize(UnityWorldSpaceLightDir(i.vertexWorld));
				//采样纹理
				float4 tex = tex2D(_DiffuseTex, i.uv);
				//漫反射计算
				float nl = max(_Ambient, dot(normalDirection, _WorldSpaceLightPos0.xyz));
				float4 diffuseTerm = nl * _Color * tex * _LightColor0;
				//镜面反射计算
				float3 reflectionDirection = reflect(-lightDirection, normalDirection);
				float3 specularDot = max(0.0, dot(viewDirecttion, reflectionDirection));
				float3 specular = pow(specularDot, _Shininess);
				float4 specularTerm = float4(specular, 1) * _SpecColor * _LightColor0;
				//计算最终颜色
				float4 finalColor = diffuseTerm +specularTerm;
				return finalColor;
			}
			ENDCG
		}
	}
}

支持多个光源

Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase"}
		    LOD 100
		
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase

另一个pass

Tags { "RenderType"="Opaque" "LightMode" = "ForwardAdd"}
			Blend one one 
		    LOD 100
		
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdadd

表面着色器

Unity着色器shader开发知识_第3张图片

光照模型/光照函数 Light.cginc
Unity着色器shader开发知识_第4张图片

在这里插入图片描述

表面着色器的数据流
Unity着色器shader开发知识_第5张图片

编辑表面着色器
添加第二个Albedo纹理

Shader "Custom/SurfaceShaderSecondAlbedo" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}

		_SeconeAlbedo ("Second Albedo (RGB)", 2D) = "white" {}
		_AlbedoLerp("Albedo Lerp", Range(0,1)) = 0.5

		_Glossiness ("Smoothness", Range(0,1)) = 0.5
		_Metallic ("Metallic", Range(0,1)) = 0.0
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;

		sampler2D _SeconeAlbedo;
		half _AlbedoLerp;


		struct Input {
			float2 uv_MainTex;
		};

		half _Glossiness;
		half _Metallic;
		fixed4 _Color;

		// #pragma instancing_options assumeuniformscaling
		UNITY_INSTANCING_BUFFER_START(Props)
			// put more per-instance properties here
		UNITY_INSTANCING_BUFFER_END(Props)

		void surf (Input IN, inout SurfaceOutputStandard o) {
			// Albedo comes from a texture tinted by color
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex);

			fixed4 seconeAlbedo = tex2D (_SeconeAlbedo, IN.uv_MainTex);			
			o.Albedo = lerp(c, seconeAlbedo, _AlbedoLerp) * _Color;
			
			// Metallic and smoothness come from slider variables
			o.Metallic = _Metallic;
			o.Smoothness = _Glossiness;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

添加法线纹理

属性中添加

_NormalMap("Normal Map", 2D) = "bump" {}

函数中设定

o.Normal = UnpackNormal(tex2D (_NormalMap, IN.uv_MainTex));

使用不同的内置光照模型
Unity着色器shader开发知识_第6张图片

Shader "Custom/SurfaceShaderSecondModel" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}

		_SpecColor("Specular Material Color", Color) = (1,1,1,1)
		_Shininess("Shininess", Range(0.03, 1)) = 0.07
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf BlinnPhong fullforwardshadows

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;

		float _Shininess;

		struct Input {
			float2 uv_MainTex;
		};

		fixed4 _Color;

		// #pragma instancing_options assumeuniformscaling
		UNITY_INSTANCING_BUFFER_START(Props)
			// put more per-instance properties here
		UNITY_INSTANCING_BUFFER_END(Props)

		void surf (Input IN, inout SurfaceOutput o) {
			// Albedo comes from a texture tinted by color
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			o.Gloss = c.a;
			o.Specular =_Shininess;
			o.Alpha = 1.0;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

自定义光照模型

光照模型函数签名
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

SurfaceOutput 数据结构体
Unity着色器shader开发知识_第7张图片

Shader "Custom/SurfaceShaderCustomModel" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}

		_SpecColor("Specular Material Color", Color) = (1,1,1,1)
		_Shininess("Shininess", Range(0.03, 128)) = 0.07
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Phong fullforwardshadows

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;

		float _Shininess;

		struct Input {
			float2 uv_MainTex;
		};

		fixed4 _Color;

		// #pragma instancing_options assumeuniformscaling
		UNITY_INSTANCING_BUFFER_START(Props)
			// put more per-instance properties here
		UNITY_INSTANCING_BUFFER_END(Props)

		void surf (Input IN, inout SurfaceOutput o) {

			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			o.Alpha = 1.0f;
		}

		inline fixed4 LightingPhong(SurfaceOutput s, half viewDir, UnityGI gi){
			UnityLight light = gi.light;
			float nl = max(0.0f, dot(s.Normal, light.dir));			
			float3 diffuseTerm = nl * s.Albedo.rgb * light.color;

			float3 reflectionDirection = reflect(-light.dir, s.Normal);
			float specularDot = max(0.0, dot(viewDir, reflectionDirection));
			float specular = pow(specularDot, _Shininess);
			float3 specularTerm = specular * _SpecColor.rgb * light.color.rgb;

			float3 finalColor = diffuseTerm.rgb + specularTerm;

			fixed4 c;
			c.rgb = finalColor;
			c.a = s.Alpha;

			#ifdef UNITY_LIGHT_FUNCTION_APPLY_INDIRECT
			c.rgb += s.Albedo * gi.indirect.diffuse;
			#endif

			return c;
		}

		inline void LightingPhong_GI(SurfaceOutput s, UnityGIInput data, inout UnityGI gi){
			gi = UnityGlobalIllumination(data, 1.0, s.Normal);
		}
	
		ENDCG
	}
	FallBack "Diffuse"
}

你可能感兴趣的:(UnityShader)