unity surface shader

Flow

surface shader flow

Code Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Shader "xxx"
{
Properties
{
...
}
SubShader
{
Tags {...}
LOD ...

CGPROGRAM
#pragma surface <Surface Function> <LightingModel> [options]

struct <Input Struct>
{
...
};

UNITY_INSTANCING_BUFFER_START(Props)
UNITY_INSTANCING_BUFFER_END(Props)

void <surface function name>(<Input Struct> IN, inout <SurfaceOutput> o)
{
...
}
ENDCG
}
FallBack "Diffuse"
}

#pragma surface <Surface Function> <LightingModel> [options]中指定了surface函数名以及光照模型
光照模型封装好了顶点着色器以及像素着色器,surface函数填充<SurfaceOutput>结构,然后用于光照计算

由于对于确定的光照模型而言,所需的数据以及计算流程都是固定的,因此可以直接封装起来
然后将SurfaceOutput的填充交给开发者来做

也可以自己定义顶点着色器,如:

1
#pragma surface surf Lambert vertex:vert

指定函数vert为顶点着色器,surfsurface函数,光照模型为Lambert

BlinnPhong Surface Analysis

示例实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Shader "Custom/SurfaceShaderBlinnPhong" 
{
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.078125
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200

CGPROGRAM
#pragma surface surf BlinnPhong fullforwardshadows
#pragma target 3.0

sampler2D _MainTex;
float _Shininess;

struct Input
{
float2 uv_MainTex;
};

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.Specular = _Shininess;
o.Gloss = c.a;
o.Alpha = 1.0f;
}
ENDCG
}
FallBack "Diffuse"
}

BlinnPhong光照模型的实现可以在Lighting.cginc中找到,其中实现了四个函数:

  • LightingBlinnPhong
  • LightingBlinnPhong_Deferred
  • LightingBlinnPhong_GI
  • LightingBlinnPhong_PrePass

LightingBlinnPhong

LightingBlinnPhong的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
inline fixed4 UnityBlinnPhongLight (SurfaceOutput s, half3 viewDir, UnityLight light)
{
half3 h = normalize (light.dir + viewDir);

fixed diff = max (0, dot (s.Normal, light.dir));

float nh = max (0, dot (s.Normal, h));
float spec = pow (nh, s.Specular*128.0) * s.Gloss;

fixed4 c;
c.rgb = s.Albedo * light.color * diff + light.color * _SpecColor.rgb * spec;
c.a = s.Alpha;

return c;
}

inline fixed4 LightingBlinnPhong (SurfaceOutput s, half3 viewDir, UnityGI gi)
{
fixed4 c;
c = UnityBlinnPhongLight (s, viewDir, gi.light);

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

return c;
}

其中SurfaceOutput的定义也可以在Lighting.cginc中找到

1
2
3
4
5
6
7
8
9
struct SurfaceOutput 
{
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Specular;
fixed Gloss;
fixed Alpha;
};

UnityGIUnityLight的定义在UnityLightingCommon.cginc中找到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct UnityLight
{
half3 color;
half3 dir;
half ndotl; // Deprecated: Ndotl is now calculated on the fly and is no longer stored. Do not used it.
};

struct UnityIndirect
{
half3 diffuse;
half3 specular;
};

struct UnityGI
{
UnityLight light;
UnityIndirect indirect;
};
Microfacet Theory unity _WorldSpaceLightDir in forwardBase lightMode

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×