什么是着色器
着色器是通过代码来模拟物体表面在微观等级上发生的事情,使得我们眼睛看到的最终图像感觉很真实。换个层面讲,着色器是运行在 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次)渲染同一个像素。
定义颜色
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
栅格化器
无光照着色器的结构
顶点数据结构体:
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)
漫反射(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
编辑表面着色器
添加第二个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));
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"
}
自定义光照模型
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"
}