【Unity Shader】(四) ------ 纹理之法线纹理、单张纹理及遮罩纹理的实现

笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题。


【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现

【Unity Shader】(五) ------ 透明效果之半透明效果的实现及原理

在游戏中,我们除了能看到游戏物体的形体轮廓,还能看到物体的一些具体外观,包括颜色,凹凸等。而实现这一步的就是使用 纹理。与纹理相对应的技术就是 纹理映射技术 ,相当于把一张图贴在物体表面,然后 逐纹素 地控制颜色

纹理映射坐标:纹理映射坐标定义了一个顶点在纹理中对应的2D坐标。由于常用 U 来表示横向坐标, V 来表示纵向坐标,所以纹理映射坐标也是我们常常见到的 UV坐标。 顶点 UV 坐标通常会被归一化至 【0,1】范围内。当然纹理采样时使用的坐标也不一定在这个范围内。

另外值得注意的是,OpenGL 与 DirectX 的二维坐标系是不一样的,OpenGL中原点位于左下角,DirectX原点位于左上角。当然Unity 会帮我们处理这个差异,同时一般情况下,Unity 采用的纹理空间是符合 OpenGL传统的。

需要注意的是:本文着重讲述纹理采样的原理,由于实现的shader中的光照模型计算如同上文中,并不完整。所以不能直接运用于项目

 

一. 单张纹理

先看一下我们要实现的效果

?

shader 的一些书写方式本文便不再赘述,同时本文的计算光照的方式都能够在上一篇文章中找到,如果忘了,可以先复习一下

【Unity Shader】(三) ------ 漫反射和高光反射的实现

1.1. 实现单张纹理

新建一个场景,去掉天空盒子;新建一个 Capsule 与 Material,命名为 SingleTexture;

I. 先定义 Properties 语义块

?

其中 _MainTex 的纹理用来表示纹理贴图,这里我们用这张纹理贴图来代替物体的漫反射颜色。

II. 为了控制 Properties 中的属性,我们在CG代码片中定义与之相匹配的变量

?

在Unity中,一般使用 纹理名_ST 来代表某个纹理的属性

_MainTex_ST 代表 _MainTex 这个纹理的属性:S(Scale)缩放,T(Translation)平移。

_MainTex_ST.xy 代表 缩放值;_MainTex_ST.zw 代表 偏移值

?

III. 定义输入输出结构体

?

uv 变量存储了纹理坐标,以便在片元着色器中进行采样

IV. 顶点着色器

?

黄色框中,我们使用了 _MainTex_ST 对顶点纹理坐标进行变换,得到最终的纹理坐标。先使用 _MainTex_ST.xy 对顶点纹理坐标进行缩放,然后使用 _MainTex_ST.zw 进行偏移。而 TRANSFORM_TEX 则是封装了这个计算方式的内置函数,我们可以在 UnityCG.cginc 中找到它的定义

?

很显然,参数一为顶点纹理坐标,参数二为纹理名

V. 片元着色器

?

此处光照模型使用的是 Blinn-Phong 模型,所以光照计算方面与之前并没有太大的差异, 如果读者对光照模型不太了解,可以翻看我的前一篇文章。

这个片元着色器主要使用 Cg 函数 tex2D(_MainTex,i.uv) 对纹理进行了采样,然后以采样结果与颜色属性相乘,乘积结果作为反射率。其余的光照计算基本无异。而关于tex2D 的解释如下

?

?

完整代码:

 1 Shader "Unity/Custom/01-SingleTexture"
 2 {
 3     Properties
 4     {
 5         _Color("Color Tint",Color) = (1,1,1,1)
 6         _MainTex("Main Tex",2D) = "while"{}
 7         _Specular("Specular",Color) = (1,1,1,1)
 8         _Gloss("Gloss",Range(8.0,256)) = 20
 9
10     }
11     SubShader
12     {
13         Pass
14         {
15             Tags { "LightMode"="ForwardBase" }
16
17
18             CGPROGRAM
19             #pragma vertex vert
20             #pragma fragment frag
21             #include "Lighting.cginc"
22
23             fixed4 _Color;
24             sampler2D _MainTex;
25             float4 _MainTex_ST;
26             fixed4 _Specular;
27             float _Gloss;
28
29             struct a2v{
30
31                 float4 vertex : POSITION;
32                 float3 normal : NORMAL;
33                 float4 texcoord : TEXCOORD0;
34             };
35
36             struct v2f{
37
38                 float4 pos : SV_POSITION;
39                 float3 worldnormal : TEXCOORD0;
40                 float3 worldPos : TEXCOORD1;
41                 float2 uv : TEXCOORD2;
42             };
43
44             v2f vert(a2v v)
45             {
46                 v2f o;
47                 o.pos = UnityObjectToClipPos(v.vertex);
48                 o.worldnormal = UnityObjectToWorldNormal(v.normal);
49                 o.worldPos = UnityObjectToClipPos(v.vertex).xyz;
50
51                 //o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
52                 o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
53
54                 return o;
55             }
56
57             fixed4 frag(v2f i) : SV_Target
58             {
59
60                 fixed3 worldnormal = normalize(i.worldnormal);
61                 fixed3 worldlight = normalize(UnityWorldSpaceLightDir(i.worldPos));
62
63                 fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;
64
65                 fixed3 ambient =  UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
66
67                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldnormal,worldlight));
68
69                 fixed3 reflectDir = normalize(reflect(-worldlight,worldnormal));
70                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
71                 //计算得到矢量h
72                 fixed3 halfDir = normalize(worldlight + viewDir);
73
74                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldnormal,halfDir)),_Gloss);
75
76
77                 return fixed4(ambient + diffuse + specular,1.0);
78             }
79             ENDCG
80
81         }
82
83     }
84
85     FallBack "Specular"
86 }

保存,进入Unity 查看效果。当然还有附上一张纹理。

?

二. 凹凸映射

另一种常见的纹理应用就是 凹凸映射 。凹凸映射就是为了使用一张纹理来修改模型表面法线,来为模型提供更多的细节。当然,这并不会真的改变模型的顶点位置,仅仅是使得模型看起来是 “不平滑的” ,更加的真实。

凹凸映射常用的两种方法:

  • 高度映射。使用一张高度纹理来模拟表面位移,然后得到修改后的法线值。
  • 法线映射。使用一张法线纹理直接存储表面法线。

2.1 高度纹理

高度纹理图存储是强度值,表示表面局部的海拔,颜色越浅表示越向外凸起,颜色越深表示越向内凹进去。这样就可以很形象地看出模型的凹凸,不过这样的计算会更加复杂,在实时计算时并不能直接得到表面法线,而是计算像素的灰度值得到。本文着重讲述的是法线纹理,所以高度映射技术便不再赘述了。

2.2 法线纹理

前文已经提到法线纹理存储的是表面法线方向,法线方向的分量范围在【-1.1】,而像素分量范围在【0,1】。所以为了让两者一致,我们需要做一个简单的映射。相必这个方式大家都有学过

那么可以预知的便是,当我们在shader中对法线纹理采样后,就必须对其进行反映射,得到原先的法线方向。

需要注意的是,这个方向是有着空间之异的。对于模型自带的顶点法线,则是定义在模型空间的,这个纹理称为 模型空间的法线纹理。不过,一般制作法线纹理时,我们一般会采样 切线空间(tangent space)

切线空间:对于每个顶点,它都有一个属于自己的切线空间,切线空间原点就是该顶点本身,Z 轴则是顶点法线方向。X 轴为切线方向。Y 轴可以由法线和切线叉积而得。也称为 副切线副法线。而存储在切线空间的纹理则称为 切线空间的纹理。

?上图是一张法线纹理。许多使用过法线纹理但不太了解其原理的朋友或许都有一个疑问:为什么普通的纹理都是红颜六色的,但是法线纹理大都像上图一样是一片蓝色的?

  • 模型空间的法线纹理,所有法线的坐标都是在模型空间,每个点存储的法线方向都是各异的,经过映射之后就变成了RGB(x,y,z) ,而x,y,z并不一致,所以对应着不同的颜色。所以模型空间的法线纹理看起来是五颜六色的。
  • 切线空间的法线纹理,所有法线的坐标都是在各自的切线空间,新的法线方向就是 Z 轴,即(0,0,1),经过映射就是(0.5,0.5,1)浅蓝色。所以切线空间的法线纹理看上去大部分都是蓝色的,这也说明了顶点的大部分法线是和模型本身法线一样的。

两种法线纹理的优劣·:

模型空间的法线纹理 :

① 直观,简单

② 可以提供平滑的边界部分。

切线空间的法线纹理 :

① 自由度很高:模型空间的法线纹理是 绝对法线信息 ,即只能用于创建它的那个模型,应用于它处就会出错。而切线空间的法线纹理 是 相对法线信息 ,应用于不同的网格都可以得到一个不错的效果

② 可以制作UV动画:可以通过移动UV来实现一个动画,而模型空间下的纹理则会完全错误。

③ 可以压缩。切线空间下的纹理,法线 Z 方向总是正方向,所以只存储XY方向就可以通过推导得到 Z 方向。而模型空间下的纹理则不行

④ 可以重复利用

由于法线方向存储于切线空间,所以在实际计算光照时会有两种计算方式:① 把光照方向,视角方向转换至切线空间,进行光照;② 把采样得到的法线方向转换至世界空间,计算光照;从效率角度,① 优于 ② ,从通用性来看,② 优于 ①。

本文会先给出第一种方法的实践,第二种以后我会补充回来,读者也可以自行实现。

2.3 切线空间下计算光照

新建一个材质和Capsule,命名为NormalTextureTangentSpace

I. 定义 Properties 语义块

?

其中 _BumpMap 表示法线纹理,_BumpScale 控制凹凸程度

II. 为了控制 Properties 中的属性,我们定义与之相匹配的变量

?

III. 修改输入输出结构体

?

?

因为切线空间是由顶点法线与切线构建的,所以在输入结构体添加一个切线变量,使用 TANGENT 语义。

因为我们是在切线空间下计算光照,所以在输出结构体中添加两个变量来存储转换空间后的光照方向和视角方向

IV. 定义顶点着色器

?

我们使用了两张纹理,所以 uv 变量修改为 float4 类型,其中,xy分量存储 _MainTex 的纹理坐标,zw分量存储 _BumpMap 的纹理坐标。然后为了对光照方向和视角方向转换至切线空间,我们需要一个变换矩阵 rotaion,而 TRANGENT_SPACE_ROTATION 则是Unity内帮我们实现了计算过程的内置宏,它会返回我们所需 rotation,我们可以在UnityCG.cginc 中找到它的定义。

?

V. 修改片元着色器

?

我们在顶点着色器中已经对光照方向和视角方向做了转换空间的工作,所以片元着色器中只需要对法线纹理进行采样,然后计算光照就可以了。tex2D 函数的定义在前文已经给出。然后使用Unity内置函数 UnpackNormal 得到正确的法线方向。然后对得到的法线向量的 xy 分量乘于 _BumpScale 就可以得到 法线的 xy 分量。再计算出 z 分量,就得到了正确的法线方向。

VI. 保存,查看效果

不同 _BumpScale 下的效果:

?

需要注意的是:

使用法线纹理时,注意其类型是否为 Normal map

如果不是,则要在 shader 里面进行以下的更改

把?

更改为

?

如果不进行修改,Unity 也提醒你

?

因为如果法线纹理类型不是 Normal map 时,我们需要手动对采样结果的 xy 分量进行反映射。而如果是 Normal map 类型,则使用 UnpackNormal 函数。因为,当法线纹理类型设置成 Normal map 时,Unity 会根据平台的不同而对该法线纹理进行压缩,此时 _BumpMap 的 rgb 分量已经不是切线空间下的 xyz 分量了。所以此时再进行以上的手动计算就会得到错误的结果。

而 UnpackNormal 函数则可以在 UnityCG.cginc 中找到其定义?

?

其中 DXT5nm 是一种压缩格式

那么,完整代码如下:

  1 Shader "Unity/Custom/01-NormalTexture-Tangent Space"
  2 {
  3     Properties
  4     {
  5         _Color("Color Tint",Color) = (1,1,1,1)
  6         _MainTex("Main Tex",2D) = "while"{}
  7         _BumpMap("Normal Map",2D) = "bump"{}
  8         _BumpScale("Bump Scale",Float) = 1.0
  9         _Specular("Specular",Color) = (1,1,1,1)
 10         _Gloss("Gloss",Range(8.0,256)) = 20
 11
 12     }
 13     SubShader
 14     {
 15         Pass
 16         {
 17             Tags { "LightMode"="ForwardBase" }
 18
 19
 20             CGPROGRAM
 21             #pragma vertex vert
 22             #pragma fragment frag
 23             #include "Lighting.cginc"
 24             #include "UnityCG.cginc"
 25
 26             fixed4 _Color;
 27             sampler2D _MainTex;
 28             float4 _MainTex_ST;
 29             sampler2D _BumpMap;
 30             float4 _BumpMap_ST;
 31             float _BumpScale;
 32             fixed4 _Specular;
 33             float _Gloss;
 34
 35             struct a2v{
 36
 37                 float4 vertex : POSITION;
 38                 float3 normal : NORMAL;
 39                 float4 tangent : TANGENT;
 40                 float4 texcoord : TEXCOORD0;
 41             };
 42
 43             struct v2f{
 44
 45                 float4 pos : SV_POSITION;
 46                 float4 uv : TEXCOORD0;
 47                 float3 lightDir : TEXCOORD1;
 48                 float3 viewDir : TEXCOORD2;
 49             };
 50
 51             v2f vert(a2v v)
 52             {
 53                 v2f o;
 54                 o.pos = UnityObjectToClipPos(v.vertex);
 55
 56                 o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
 57                 o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
 58
 59                 TANGENT_SPACE_ROTATION;
 60
 61                 o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;
 62                 o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex)).xyz;
 63
 64                 return o;
 65             }
 66
 67             fixed4 frag(v2f i) : SV_Target
 68             {
 69                 //光源方向归一化
 70                 fixed3 tangentLightDir = normalize(i.lightDir);
 71                 //视角方向归一化
 72                 fixed3 tangentViewDir = normalize(i.viewDir);
 73
 74                 //对法线纹理取样
 75                 fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw);
 76                 //切线空间下的法线
 77                 fixed3 tangentNormal;
 78
 79                 //手动反映射
 80                 //tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;
 81
 82                 tangentNormal = UnpackNormal(packedNormal);
 83                 tangentNormal.xy *= _BumpScale;
 84
 85
 86
 87                 tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy,tangentNormal.xy)));
 88
 89                 fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;
 90
 91                 fixed3 ambient =  UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
 92
 93                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(tangentNormal,tangentLightDir));
 94
 95                 //计算得到矢量h
 96                 fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
 97
 98                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(tangentNormal,halfDir)),_Gloss);
 99
100                 return fixed4(ambient + diffuse + specular,1.0);
101             }
102             ENDCG
103
104         }
105
106     }
107
108     FallBack "Specular"
109 }

三. 遮罩纹理

法线纹理是十分常见且重要的纹理,讲完了法线纹理,我们现在讲另外一种非常有用的纹理:遮罩纹理

遮罩可以保护某些区域不受修改,比如我们上一篇光照原理中实现的高光反射则是对于所有像素而言的,现在我希望物体某部分更强烈一些,而另一部分则更弱一些,此时我们就可以用到遮罩纹理了。

遮罩纹理的使用流程:① 采样,得到纹素值  ② 使用其中一个或多个通道的值来与表面属性相乘  ③ 当通道的值为0时,可以保护表面不受该属性影响

现在我们来实现,对高光反射进行遮罩。计算在切线空间,代码与之前相差不多,就不赘述了

完整代码:

  1 Shader "Unity/Custom/01-MaskTexture"
  2 {
  3     Properties
  4     {
  5         _Color("Color Tint",Color) = (1,1,1,1)
  6         _MainTex("Main Tex",2D) = "while"{}
  7         _BumpMap("Normal Map",2D) = "bump"{}
  8         _BumpScale("Bump Scale",Float) = 1.0
  9         _SpecularMask("Specular Mask",2D) = "while"{}
 10         _SpecularScale("Specular Scale",Float) = 1.0
 11         _Specular("Specular",Color) = (1,1,1,1)
 12         _Gloss("Gloss",Range(8.0,256)) = 20
 13
 14     }
 15     SubShader
 16     {
 17         Pass
 18         {
 19             Tags { "LightMode"="ForwardBase" }
 20
 21
 22             CGPROGRAM
 23             #pragma vertex vert
 24             #pragma fragment frag
 25             #include "Lighting.cginc"
 26             #include "UnityCG.cginc"
 27
 28             fixed4 _Color;
 29             sampler2D _MainTex;
 30             float4 _MainTex_ST;
 31             sampler2D _BumpMap;
 32             float _BumpScale;
 33             sampler2D _SpecularMask;
 34             float _SpecularScale;
 35             fixed4 _Specular;
 36             float _Gloss;
 37
 38             struct a2v{
 39
 40                 float4 vertex : POSITION;
 41                 float3 normal : NORMAL;
 42                 float4 tangent : TANGENT;
 43                 float4 texcoord : TEXCOORD0;
 44             };
 45
 46             struct v2f{
 47
 48                 float4 pos : SV_POSITION;
 49                 float2 uv : TEXCOORD0;
 50                 float3 lightDir : TEXCOORD1;
 51                 float3 viewDir : TEXCOORD2;
 52             };
 53
 54             v2f vert(a2v v)
 55             {
 56                 v2f o;
 57                 //o.pos = UnityObjectToClipPos(v.vertex);
 58                 o.pos = UnityObjectToClipPos(v.vertex);
 59
 60                 o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
 61
 62                 TANGENT_SPACE_ROTATION;
 63
 64                 o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;
 65                 o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex)).xyz;
 66
 67                 return o;
 68             }
 69
 70             fixed4 frag(v2f i) : SV_Target
 71             {
 72                 //光源方向归一化
 73                 fixed3 tangentLightDir = normalize(i.lightDir);
 74                 //视角方向归一化
 75                 fixed3 tangentViewDir = normalize(i.viewDir);
 76
 77                 //对法线纹理贴图取样
 78                 fixed4 packedNormal = tex2D(_BumpMap,i.uv);
 79                 //切线空间下的法线
 80                 fixed3 tangentNormal;
 81
 82                 tangentNormal = UnpackNormal(packedNormal);
 83                 tangentNormal.xy *= _BumpScale;
 84                 //反映射
 85                 tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy,tangentNormal.xy)));
 86
 87
 88
 89                 fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;
 90
 91                 fixed3 ambient =  UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
 92
 93                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(tangentNormal,tangentLightDir));
 94
 95                 //计算得到矢量h
 96                 fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
 97
 98                 //高光遮罩
 99                 fixed3 specularMask = tex2D(_SpecularMask,i.uv).r * _SpecularScale;
100
101                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(tangentNormal,halfDir)),_Gloss) * specularMask;
102
103
104                 return fixed4(ambient + diffuse + specular,1.0);
105             }
106             ENDCG
107
108         }
109
110     }
111
112     FallBack "Specular"
113 }

这里需要注意的是:

① 这里三张纹理共用了 _MainTex_ST ,而不是一张纹理对应一个 _ST 变量。因为随着纹理越来越多,我们会迅速占满顶点着色器中可以使用的插值寄存器。而很多时候,我们并不需要对纹理进行平铺和位移,或者很多纹理使用同一种平铺,那么我们就可以对这些纹理使用同一个纹理坐标。

② 这张遮罩图我们只使用了 r 分量,那么有很多空间都是浪费了,因为一般遮罩纹理的 rgba 存储的是不同的表面属性,善用遮罩纹理,可以创作出高自由度的材质,就可以实现更强的画面效果。

最后给出三种纹理的对比图

?

总结

纹理是十分重要的一环,它可以决定你看到的事物有多细腻逼真。

另外再强调一次,本文实现的 shader 仅供学习,因为光照计算并不完整,所以不能直接运用于项目之中

如果对光照不太了解的朋友,可以去翻看我的前一篇文章【Unity Shader】(三) ------ 漫反射和高光反射的实现

最后,希望本文能对你有所帮助!!!路漫漫其修远兮 !!!

本文实现的 Shader 和纹理

原文地址:https://www.cnblogs.com/BFXYMY/p/9715341.html

时间: 2024-10-10 09:02:55

【Unity Shader】(四) ------ 纹理之法线纹理、单张纹理及遮罩纹理的实现的相关文章

[Unity Shader] 切线空间的法线贴图

书中P153页,求得了世界空间下的切线.副切线.法线后,归一化得到这三个正交分量.按列摆放可得到从切线空间的变换矩阵. 不知道下面的推导过程是否正确,先做个记录.

Unity Shader 知识点总结(二)

紧接着上一篇文章的shader入门知识的总结,本文主要总结shader中的纹理贴图.透明度混合.顶点动画.后期特效处理等操作.如果有什么地方有错,请指出更正,谢谢.本文的代码主要来自开源书:unity入门精要 一.Unity shader中的纹理 1.简单纹理 在unity shader中,纹理的主要作用是用来给模型贴上一个外表,这样得到的模型颜色就具有纹理的颜色混合.在常见的一些shader上,都会有一个_MainTex的选项,这就是我们常常用的主纹理贴图.对于纹理贴图,其对应的需要有纹理坐标

【Unity Shader编程】之十五 屏幕高斯模糊(Gaussian Blur)后期特效的实现

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/51871531 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 本文工程使用的Unity3D版本: 5.2.1  本篇文章将分析如何在Unity中基于Shader实现高斯模糊屏幕后期特效. 首先放出最终的实现效果.如下几幅图,是在Unity中使用本文所实现的Shader得到的高斯模糊屏幕

【Unity Shader】(八) ------ 高级纹理(上)

笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题.    [Unity Shader](三) ------ 光照模型原理及漫反射和高光反射的实现    [Unity Shader](四) ------ 纹理之法线纹理.单张纹理及遮罩纹理的实现    [Unity Shader](五) ------ 透明效果之半透明效果的实现及原理    [Unity Shader](六) ------ 复杂的光

【Unity Shader】(九) ------ 高级纹理之渲染纹理及镜子与玻璃效果的实现

笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ------ 光照模型原理及漫反射和高光反射的实现 [Unity Shader](四) ------ 纹理之法线纹理.单张纹理及遮罩纹理的实现 [Unity Shader](五) ------ 透明效果之半透明效果的实现及原理 [Unity Shader](六) ------ 复杂的光照(上) [Unity

[Unity] Shader(着色器)之纹理贴图

在Shader中,我们除了可以设定各种光线处理外,还可以增加纹理贴图. 使用 settexture 命令可以为着色器指定纹理. 示例代码: Shader "Sbin/ff2" { // 贴图采样 properties { // 变量名("描述名",类型)=值 _Color("主体", color)=(1,1,1,1) _Ambient("环境光", color)=(0.3,0.3,0.3,0.3) _Specular(&quo

【Unity Shader编程】之十四 边缘发光Shader(Rim Shader)的两种实现形态

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/51764028 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 本文工程使用的Unity3D版本: 5.2.1  这篇文章主要讲解了如何在Unity3D中分别使用Surface Shader和Vertex & Fragment Shader来编写边缘发光Shader. 一.最终实现的效果

Shader编程学习笔记(四)——Unity Shader的组织形式(ShaderLab)

Unity Shader的组织形式 Unity Shader的形态 Unity官方手册上讲Unity Shader有三种不同的编写方案,这三种编写方案分别是surface shaders.vertex and fragment shaders和fixed function shaders. 从前面几篇笔记中可以了解到,可编程图形管线中能够编写shader的主要是两个部分:vertex shader和fragment shader,但Unity还有surface shaders和fixed fun

【Unity Shader】使用法线贴图(Normal Map)的Shader

为何要用法线贴图 为了提升模型表现细节而又不增加性能消耗,所以不选择提高模型的面数,而是给模型的材质Shader中使用上法线贴图(Normal Map),通过更改模型上的点的法线方向,增加光影凹凸效果,从而提升模型表现细节.使用法线贴图能使一个三角面表现出凹凸的视觉效果! 法线贴图原理 http://www.cnblogs.com/tekkaman/p/3992352.html 上面的文章解释了很多问题: 法线被存储在切线空间(Tangent Space Normal)中,所以法线贴图看上去呈蓝