当前位置:   article > 正文

《Unity Shader入门精要》笔记:初级篇(4)_unity 正片叠底

unity 正片叠底
  • 本篇博客主要为个人学习所编写读书笔记,不用于任何商业用途,以及不允许任何人以任何形式进行转载。
  • 本篇博客会补充一些扩展内容(例如其他博客链接)。
  • 本篇博客还会提供一些边读边做的效果截图。文章内所有数学公式都由Latex在线编辑器生成。
  • 本篇博客主要提供一个“glance”,知识点的总结。如有需要请到书店购买正版。
  • 博客提及所有官方文档基于2022.2版本,博客会更新一些书中的旧的知识点到2022.2版本。
  • 个人博客网址:《Unity Shader入门精要》笔记:初级篇(4) - Sugar的博客,如文章转载中出现例如传送门失效等纰漏,建议直接访问原博客网址。

  • 如有不对之处欢迎指正。
  • 我创建了一个游戏制作交流群:637959304 进群密码:(CSGO的拆包密码)欢迎各位大佬一起学习交流,不限于任何平台(U3D、UE、COCO2dx、GamesMaker等),以及欢迎编程,美术,音乐等游戏相关的任何人员一起进群学习交流。

透明效果

  • 透明通道(Alpha Channel):当开启透明混合后,透明度为1时表示该像素是完全不透明,当其为0时,表示像素完全不会显示。
  • Unity中用两种方法来实现透明效果:
    1、透明度测试(Alpha Test),这种方法无法得到真正的半透明效果。 只要一个片元的透明度不满足条件,那么对应的片元会被直接舍弃。因此舍去片元的操作不会对颜色缓冲产生任何影响,所以不需要关闭深度写入。
    2、透明度混合(Alpha Blending),可以得到真正的半透明效果。用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。该方法只会关闭深度写入,不会关闭深度测试,此时深度缓冲是只读的。此时渲染顺序会很重要,如果先渲染前方物体,然后渲染后方物体,则前方物体先进入颜色缓冲,随后后方物体进入颜色缓冲并与前方物体进行混合,这样混合结果会完全相反,导致后方物体看起来在前一样。
  • 深度缓冲:帮助程序判断物体的前后位置以判断是否渲染。但如果要使用透明度混合,就必须要关闭深度写入(ZWrite)。
  • 渲染队列(render queue):使用Queue标签来决定我们的模型将归于哪个渲染队列。

  • 透明度测试标签:Tags{“Queue”=”AlphaTest”}
    透明度混合标签:Tags{“Queue”=”Transparent”}并搭配ZWrite Off关闭深度写入来使用。
  • 透明度测试的代码也可以看我的HLSL博客的最后一个,里面有用到透明度测试来实现一个消融效果的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

66

67

68

69

70

71

72

73

74

75

Shader "Example/Shader05"

{

    Properties

    {

        _MainTex ("Texture", 2D) = "white" {}

        _Color("Color Tint",Color) = (1,1,1,1)

        _Cutoff("Alpha Cutoff",Range(0,1)) = 0.5

    }

    SubShader

    {

//先把队列设置为AlphaTest队列进行透明度测试,Rendertype标签可以让Unity把这个Shader归入到提前定义的组以指明该Shader是一个使用了透明度测试的Shader。IgnoreProjector设置为True代表不会受投影器的影响。

        Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}

        Pass

        {

            Tags {"LightMode" = "ForwardBase"}

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #include"Lighting.cginc"

            #include "UnityCG.cginc"

            fixed4 _Color;

            sampler2D _MainTex;

            float4 _MainTex_ST;

            fixed _Cutoff;

            struct a2v

            {

                float4 vertex : POSITION;

                float3 normal : NORMAL;

                float2 texcoord : TEXCOORD0;

            };

            struct v2f

            {

                float4 pos : SV_POSITION;

                float2 uv : TEXCOORD2;

                float3 worldNormal : TEXCOORD0;

                float3 worldPos : TEXCOORD1;

            };

            v2f vert (a2v v)

            {

                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                return o;

            }

            fixed4 frag(v2f i) : SV_Target

            {

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex,i.uv);

//书中此处用.a通道达不到演示的效果,可以直接使用rgb的任意一个通道来代替演示

                clip(texColor.b - _Cutoff);

                fixed3 albedo = texColor.rgb * _Color.rgb;

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));

                return fixed4(ambient + diffuse,1.0);

            }

            ENDCG

        }

    }

}

  • 透明度混合:混合命令
  • 混合命令的操作传送门(例如加减乘除),混合过程不可编程但可根据提供方法高度自由设置。

  • 常见混合类型

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

//正常(Normal),即透明度混合

Blend SrcAlpha OneMinusSrcAlpha

//柔和相加(soft Additive )

Blend OneMinusDstColor One

//正片叠底( Multiply),即相乘

Blend DstColor Zero

//两倍相乘(2xMultiply)

Blend DstColor SrcColor

//变暗(Darken)

BlendOp Min

Blend one one

//变亮(Lighten )

BlendOp Max

Blend One One

//滤色(screen)

Blend oneMinusDstColor One

//等同于

Blend One OneMinusSrcColor

//线性减淡(Linear Dodge )Blend One One

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

66

67

68

69

70

71

72

73

74

75

76

77

Shader "Example/Shader05"

{

    Properties

    {

        _MainTex ("Texture", 2D) = "white" {}

        _Color("Color Tint",Color) = (1,1,1,1)

        _AlphaScale("Alpha Scale",Range(0,1)) = 0.5

    }

    SubShader

    {

//进入Transparent

        Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}

        Pass

        {

            Tags {"LightMode" = "ForwardBase"}

//关闭深度写入,开启混合模式

            ZWrite Off

            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #include"Lighting.cginc"

            #include "UnityCG.cginc"

            fixed4 _Color;

            sampler2D _MainTex;

            float4 _MainTex_ST;

            fixed _AlphaScale;

            struct a2v

            {

                float4 vertex : POSITION;

                float3 normal : NORMAL;

                float2 texcoord : TEXCOORD0;

            };

            struct v2f

            {

                float4 pos : SV_POSITION;

                float2 uv : TEXCOORD2;

                float3 worldNormal : TEXCOORD0;

                float3 worldPos : TEXCOORD1;

            };

            v2f vert (a2v v)

            {

                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                return o;

            }

            fixed4 frag(v2f i) : SV_Target

            {

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex,i.uv);

                fixed3 albedo = texColor.rgb * _Color.rgb;

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));

//乘法即可

                return fixed4(ambient + diffuse,texColor.a * _AlphaScale);

            }

            ENDCG

        }

    }

}

  • 开启深度写入的半透明效果:使用两个Pass进行操作,一个Pass开启深度写入但不输出颜色,把该模型的深度值写入到深度缓冲中;第二个Pass进行正常透明度混合,由于上一个Pass已经得到逐像素的正确深度信息,所以第二个Pass就可以进行正常的透明度混合。这种方法的缺点在于性能需求高。

1

2

3

4

5

6

//在上述代码中新加入一个Pass即可,ColorMask用于设置颜色通道的写掩码(write mask),设置为0时意味着Pass不写入任何颜色通道,也就不会输出任何颜色。

Pass

{

        ZWrite On

        ColorMask 0

}

  • 双面渲染的透明效果:可以使用Cull指令来控制需要剔除那个面的渲染图元。
  • Cull Back丨Front丨Off 代表物体朝向摄像机的背面,正面不会被渲染。以及关闭剔除功能。
  • 透明度混合的双面渲染:因为透明度混合关闭了深度写入,所以可以使用两个Pass,一个渲染背面,一个渲染正面,而Unity会顺序执行各个Pass,所以可以保证背面总是在正面之前被渲染

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

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

Shader "Example/Shader05"

{

    Properties

    {

        _MainTex ("Texture", 2D) = "white" {}

        _Color("Color Tint",Color) = (1,1,1,1)

        _AlphaScale("Alpha Scale",Range(0,1)) = 0.5

    }

    SubShader

    {

        Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}

        Tags {"LightMode" = "ForwardBase"}

        Pass

        {

            Cull Front

            ZWrite Off

            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #include"Lighting.cginc"

            #include "UnityCG.cginc"

            fixed4 _Color;

            sampler2D _MainTex;

            float4 _MainTex_ST;

            fixed _AlphaScale;

            struct a2v

            {

                float4 vertex : POSITION;

                float3 normal : NORMAL;

                float2 texcoord : TEXCOORD0;

            };

            struct v2f

            {

                float4 pos : SV_POSITION;

                float2 uv : TEXCOORD2;

                float3 worldNormal : TEXCOORD0;

                float3 worldPos : TEXCOORD1;

            };

            v2f vert (a2v v)

            {

                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                return o;

            }

            fixed4 frag(v2f i) : SV_Target

            {

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex,i.uv);

                fixed3 albedo = texColor.rgb * _Color.rgb;

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));

//这里我多加了点亮度和透明度来提高显示的效果,否则我自己的素材显示不太明显

                return fixed4(ambient + diffuse,texColor.a * _AlphaScale) + fixed4(0.2,0.2,0.2,0.3);

            }

            ENDCG

        }

        Pass

        {

            Cull Back

            ZWrite Off

            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #include"Lighting.cginc"

            #include "UnityCG.cginc"

            fixed4 _Color;

            sampler2D _MainTex;

            float4 _MainTex_ST;

            fixed _AlphaScale;

            struct a2v

            {

                float4 vertex : POSITION;

                float3 normal : NORMAL;

                float2 texcoord : TEXCOORD0;

            };

            struct v2f

            {

                float4 pos : SV_POSITION;

                float2 uv : TEXCOORD2;

                float3 worldNormal : TEXCOORD0;

                float3 worldPos : TEXCOORD1;

            };

            v2f vert (a2v v)

            {

                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                return o;

            }

            fixed4 frag(v2f i) : SV_Target

            {

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex,i.uv);

                fixed3 albedo = texColor.rgb * _Color.rgb;

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));

                return fixed4(ambient + diffuse,texColor.a * _AlphaScale);

            }

            ENDCG

        }

         

    }

}

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/116331
推荐阅读
相关标签
  

闽ICP备14008679号