meet unity shader

在我还在上高中的时候,我就开始学了一些 Unity,也尝试制作了一些简单的游戏,那时候更多是出于好玩,后来沉迷 Linux,就逐渐淡忘了游戏开发。

机缘巧合,我现在入手了一台 M1 mbp,接触到了 Apple 家的 Metal,又快速过了一下 Vulkan,也尝试做了一些入门级的项目,更幻想制作一个游戏引擎,所以最近有时间我就在看 Games104 的课程,补充一下相关知识,计划跟完 Games104,就去看一下闫令琪老师的 Games101,主攻一下计算机图形学。

有天中午我无意间看到了 onevcat 大佬写的一篇介绍 unity shader 的文章,并且还分享了一篇使用 shader 模拟物体表面的雪的效果,让我也想跟着做一个。

Unity shader

Unity shader 并不像平常我们见的 OpenGL、Vulkan 和 Metal 的 shader 文件一样,Unity shader 更像是配置文件,它使用特定的结构语法保存各种信息,并和 Unity Editor 中其他对象交互。

一个基础的 Unity shader 的结构是这样的:

1
2
3
4
5
Shader "Custom/myshader" {
Properties {}
SubShader {}
Fallback ""
}

可以看出,一个标准的 Unity shader 拥有四个部分,一个 Shader 的命名,一个属性对象,一个 SubShader 对象,一个 Fallback 字符串。

属性对象是 Unity Editor 和 shader 沟通的桥梁,我们可以在 Properties 中声明输入,从外部接受参数。

SubShader 对象是可以多个重复的,当第一个 SubShader 对象中的代码无法在当前的 GPU 中运行时,Unity 会切换到下一个 SubShader 对象。我们可以在同一份 Shader 文件中对不同的 GPU 实现不同的支持。

Fallback 字符串则是如果 SubShader 都无法运行时,采用的最终的渲染方法。

一个简单的理解就是,从上到下,画面效果是依次降低的。

自定义属性

SubShader

1
2
3
4
5
SubShader {
Tags {}
Pass {
}
}
1
2
3
4
Pass {
CGPROGRAM
ENDCG
}

CGPROGRAM

// TODO:CGPROGRAM 是发送到 GPU 运行的程序,也是一般概念中的 shader。

自定义光照

法线

Shader 代码

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Custom/SnowShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Bump ("Bump", 2D) = "bump" {}
_Snow ("Snow Level", Range(0,1) ) = 0
_SnowColor ("Snow Color", Color) = (1.0,1.0,1.0,1.0)
_SnowDirection ("Snow Direction", Vector) = (0,1,0)
_SnowDepth ("Snow Depth", Range(0,0.3)) = 0.1
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200

CGPROGRAM
#pragma surface surf CustomDiffuse vertex:vert

sampler2D _MainTex;
sampler2D _Bump;
float _Snow;
float4 _SnowColor;
float4 _SnowDirection;
float _SnowDepth;

struct Input {
float2 uv_MainTex;
float2 uv_Bump;
float3 worldNormal;
INTERNAL_DATA
};

inline float4 LightingCustomDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten) {
float difLight = dot (s.Normal, lightDir);
float hLambert = difLight * 0.5 + 0.5;
float4 col;
col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
col.a = s.Alpha;
return col;
}

void vert (inout appdata_full v) {
float4 sn = mul(transpose(unity_ObjectToWorld) , _SnowDirection);
if(dot(v.normal, sn.xyz) >= lerp(1,-1, (_Snow * 2) / 3)) {
v.vertex.xyz += (sn.xyz + v.normal) * _SnowDepth * _Snow;
}
}

void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);

o.Normal = UnpackNormal(tex2D(_Bump, IN.uv_Bump));

if (dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz) > lerp(1,-1,_Snow)) {
o.Albedo = _SnowColor.rgb;
} else {
o.Albedo = c.rgb;
}

o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
}

相关文章
https://onevcat.com/2013/07/shader-tutorial-1/


meet unity shader
https://blog.justforlxz.com/2022/07/21/meet-unity-shader/
作者
小竹
发布于
2022年7月21日
许可协议