开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:2005

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 3032|回复: 49

[蛮牛干货] 巧用Shader,游戏玩法新思路

[复制链接]  [移动端链接]
排名
3
昨日变化

5728

主题

6212

帖子

2万

积分

Rank: 16

UID
1231
好友
185
蛮牛币
14249
威望
30
注册时间
2013-7-29
在线时间
2864 小时
最后登录
2017-12-12

社区QQ达人活力之星原创精华达人突出贡献奖财富之证游戏蛮牛QQ群会员蛮牛妹VIP

发表于 2017-8-10 10:33:30 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
  今天为大家分享一位游戏开发学生与他的小型团队,在为期5天的课堂Game Jam中使用Unity制作小游戏《Color Wars》的过程,以及其中使用着色器为游戏画面添加各种颜色的方法。
  他们制作的《Color Wars》是一款非常简单的2.5D多人对战游戏,玩家可以射击敌人,为敌人或者为场景加上颜色。游戏效果如下:

1.gif

  图形部分
  所有游戏的特效魔法背后,都是最原始的3D模型、图片与人物精灵来组成整个场景。这些组成场景的元素都有其颜色及纹理。

2.jpg

  其中比较棘手的部分是需要在Alpha通道中屏蔽所有元素的颜色。换而言之,默认情况下,屏幕的整个Alpha通道都是黑色的,直到玩家开始喷射油漆,才会使被油漆溅到区域的Alpha通道变为白色。然后图像效果就是其原有颜色与灰度进行混合。
  如下:

3.jpg

4.jpg

  从上图可以看出,使用Projector将喷漆绘制到物体表面并创建颜色遮罩。每个Projector都使用程序化动态生成,在子弹(空中飞行的白点)接触到某个表面时进行初始化。Projector带有一个盒式碰撞体,当子弹落在Projector上时,不会初始化新的Projector,而是让原先的Projector变大。这样漆量会变多,而场景中的Projector数量却保持不变。
  默认情况下,Unity标准着色器会为所有不透明对象的Alpha通道写入1。所以下面使用自定义着色器来替换Unity标准着色器。新建一个标准表面着色器,将其表面函数替换为如下:
[C#] 纯文本查看 复制代码
void surf (Input IN, inout SurfaceOutputStandard o) 
{
        // Albedo 来自带颜色的纹理
        fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
        o.Albedo = c.rgb;
        // Metallic 和 smoothness 来自滑块变量
        o.Metallic = _Metallic;
        o.Smoothness = _Glossiness;
        o.Alpha = 0;  // 我只添加了这一行!
}


  下面这行很重要,用于避免Unity更改自定义的Alpha值。将#pragma那行代码改为如下:
[C#] 纯文本查看 复制代码
CGPROGRAM
#pragma surface surf Standard fullforwardshadows keepalpha
// 添加 "keepalpha" 告诉Unity不要覆盖我们的alpha值!


  注意,该技巧不可用于Unity中的延迟渲染管线,因为它重写了G-Buffer中的Alpha通道来存储遮罩数据。
  油漆喷射
  当子弹撞击某个表面时就会在撞击处动态生成Unity Projector。这些Projector带有自定义材质与自定义着色器。材质纹理是一张带有Alpha通道喷溅形状图,本文示例使用的纹理如下图:

5.jpg

  注意,纹理导入设置中要将Wrap Mode设为“Clamp”而非“Repeat”。用于Projector材质的着色器从Unity提供的ProjectorLight修改而来,代码如下:
[C#] 纯文本查看 复制代码
Shader "Projector/ProjectAlpha"
{
        Properties
        {
                _ShadowTex ("Cookie", 2D) = "gray" {}
        }
        Subshader
        {
                Tags { "Queue"="Transparent"}
                Pass
                {
                        ZWrite Off
                        Blend Zero One, One One
                        Offset -1, -1
 
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #pragma multi_compile_fog
                        #include "UnityCG.cginc"
                         
                   struct Input
                   {
                        float4 vertex : POSITION;
                        float3 normal : NORMAL;
                   };
 
                        struct v2f
                        {
                                float4 uvShadow : TEXCOORD0;
                                UNITY_FOG_COORDS(2)
                                float4 pos : SV_POSITION;
                                fixed nv : COLOR0;
                        };
                         
                        float4x4 unity_Projector;
                        float4x4 unity_ProjectorClip;
                         
                        v2f vert (Input v)
                        {
                                v2f o;
                                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                                o.uvShadow = mul(unity_Projector, v.vertex);
                                UNITY_TRANSFER_FOG(o,o.pos);
 
                                // For me, splatters were being projected on both sides of the
                                // object, so I used the view direction and the surface normal
                                // to check if it was facing the camera.
                                float3 normView = normalize(float3(unity_Projector[2][0], unity_Projector[2][1], unity_Projector[2][2]));
                                float nv = dot(v.normal, normView);
                                // negative values means surface isn't facing the camera
                                o.nv = nv < 0 ? 1 : 0;
                                 
                                return o;
                        }
                         
                        sampler2D _ShadowTex;
                        sampler2D _FalloffTex;
                         
                        fixed4 frag (v2f i) : COLOR
                        {
                                fixed4 texS = tex2Dproj (_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
                                fixed4 res = fixed4(1, 1, 1, texS.a );
                                // Multiply by alpha channel to
                                // remove back-side projection.
                                res.a *= i.nv;
 
                                UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(1,1,1,1));
                                return res;
                        }
                        ENDCG
                }
        }
}


  下面来介绍其中最为重要的混合部分。
  混合原理
  当着色器计算某个像素的颜色时,该颜色必须作用于屏幕上该点已经存在的像素颜色之上。默认情况下,新的像素会完全覆盖原有像素,但新像素也可以与原有像素进行混合。混合通常用于让对象呈透明或半透明效果,当然也可以实现很多其它的炫酷特效。
  关键字Blend可以包含在Subshader或Pass标签中,甚至对同一个着色器的不同Pass进行混合。添加Blend关键字后,必须写入混合因子。混合因子如下:

6.jpg

  Src指向着色器用于计算的颜色。Dst指向屏幕上已有的像素颜色。着色器用于计算的颜色会与第一个因子相乘,而屏幕上已有颜色会与第二个因子相乘。将两个结果相加,就是最终写到屏幕的颜色。
  所以"Blend SrcAlpha One"会将自身Alpha值与当前着色器计算的颜色相乘,此时屏幕上的颜色暂未改动。然后再将屏幕颜色计算后的结果与前者相加。还可以使用逗号分隔两组因子,逗号前的混合选项用于计算颜色,逗号后的混合选项仅计算Alpha通道。可以查阅Unity文档了解更多关于混合的内容。
  用于Projector的着色器就是“Blend Zero One, One One”,“Zero One”移除了飞溅纹理的颜色,使用子弹所飞溅到的表面颜色。“One One”将飞溅物的Alpha值与表面Alpha值相加。
  现在使用上面的着色器与材质来生成Projector,应该将场景视图的Alpha通道设为白色。
  颜色与灰度
  现在可以随意修改Alpha通道,但还未达到最终效果。下面利用Alpha遮罩来创建游戏所需的图像特效。
  首先,创建要使用图像特效的着色器。在Unity中新建默认的Image Effect Shader,然后将片段代码替换为如下:
[C#] 纯文本查看 复制代码
fixed4 frag (v2f i) : SV_Target
{
        fixed4 col = tex2D(_MainTex, i.uv);
 
        // This lines generates a Black&White version of the screen
        fixed3 bnw = dot(col.rgb, float3(0.3, 0.59, 0.11));
        // Switch between B&W and Color based on alpha channel
        col.rgb = lerp(bnw, col.rgb, col.a);
 
        return col;
}


  可以随意更改bnw变量以达到理想的混合效果。最后还需要新建脚本来运行该图像特效。脚本非常简单,代码如下:
[C#] 纯文本查看 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.ImageEffects;
 
[ExecuteInEditMode]
[ImageEffectAllowedInSceneView]
public class AlphaColorSwitch : ImageEffectBase
{
        void OnRenderImage ( RenderTexture source, RenderTexture destination )
        {
                Graphics.Blit ( source, destination, material );
        }
}


  注意,这里用到了ImageEffectBase,该资源在Unity标准资源库中。导入标准资源库后,将脚本绑定到相机(确保将相机的渲染模式设为Forward)上,并将公共的着色器变量设为前面提到的着色器。
  到此就可以向场景中喷射油漆啦!
  已知限制
  本文提到的实现方式还存在一些限制,不一定适合所有的应用场景,但对于《Color War》这款游戏来说已足够。主要存在以下两点限制:
  1、采用Alpha遮罩就意味着没有Alpha通道,也不支持延迟渲染。这也许可以使用模板、命令缓冲区甚至多渲染目标来解决。
  2、项目使用的自定义着色器过多,这种做法并不推荐。如果您的项目可以使用延迟渲染解决其它问题,那么这个问题也就不存在了。
  结语

  本文为大家分享了在Unity中利用着色器来实现喷绘效果的过程,文中的解决方法仅作为一种思路参考,不一定适用于所有项目。大家也可以按照项目的实际需求,来选取更加适合的解决方案。
来源:Unity官方中文社区

[发帖际遇]: 清风 发帖时在路边捡到 2 蛮牛币,偷偷放进了口袋. 幸运榜 / 衰神榜

跟我念“站长妹纸萌萌哒!”我说站长,你说YO!爱你们么么哒~
回复

使用道具 举报

5熟悉之中
941/1000
排名
2432
昨日变化
10

14

主题

165

帖子

941

积分

Rank: 5Rank: 5

UID
159315
好友
3
蛮牛币
4282
威望
0
注册时间
2016-7-28
在线时间
330 小时
最后登录
2017-12-12
QQ
发表于 2017-8-10 10:47:25 | 显示全部楼层
新颖                             

回复 支持 反对

使用道具 举报

5熟悉之中
951/1000
排名
2432
昨日变化
3

9

主题

161

帖子

951

积分

Rank: 5Rank: 5

UID
174370
好友
1
蛮牛币
3445
威望
0
注册时间
2016-10-10
在线时间
301 小时
最后登录
2017-12-8

活力之星

QQ
发表于 2017-8-10 11:26:36 | 显示全部楼层
先码了,休息的时候研究一下。

回复 支持 反对

使用道具 举报

排名
29328
昨日变化
23

1

主题

35

帖子

64

积分

Rank: 2Rank: 2

UID
165351
好友
0
蛮牛币
84
威望
0
注册时间
2016-9-1
在线时间
22 小时
最后登录
2017-10-30
发表于 2017-8-10 11:28:12 | 显示全部楼层
{:106:}

回复

使用道具 举报

3偶尔光临
282/300
排名
6353
昨日变化
59

0

主题

32

帖子

282

积分

Rank: 3Rank: 3Rank: 3

UID
196662
好友
0
蛮牛币
501
威望
0
注册时间
2016-12-28
在线时间
86 小时
最后登录
2017-12-12
发表于 2017-8-10 11:43:24 | 显示全部楼层
感谢分享,日后看

回复

使用道具 举报

7日久生情
2119/5000
排名
614
昨日变化
1

1

主题

271

帖子

2119

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
27816
好友
3
蛮牛币
6615
威望
0
注册时间
2014-6-3
在线时间
689 小时
最后登录
2017-12-12
发表于 2017-8-10 13:11:06 | 显示全部楼层
这个有点意思哈

回复

使用道具 举报

5熟悉之中
536/1000
排名
3398
昨日变化
12

0

主题

36

帖子

536

积分

Rank: 5Rank: 5

UID
178205
好友
0
蛮牛币
1364
威望
0
注册时间
2016-10-25
在线时间
154 小时
最后登录
2017-12-12
发表于 2017-8-10 15:23:20 | 显示全部楼层
这不是之前那个喷漆游戏的原理!!~~哈哈,完了看下

回复 支持 反对

使用道具 举报

3偶尔光临
160/300
排名
11571
昨日变化
9

1

主题

58

帖子

160

积分

Rank: 3Rank: 3Rank: 3

UID
18962
好友
0
蛮牛币
185
威望
0
注册时间
2014-3-26
在线时间
39 小时
最后登录
2017-10-31
发表于 2017-8-10 19:22:20 | 显示全部楼层
不错 创意给力~~~~~~~~~~~~~~

回复

使用道具 举报

5熟悉之中
802/1000
排名
3455
昨日变化

0

主题

207

帖子

802

积分

Rank: 5Rank: 5

UID
168312
好友
0
蛮牛币
1434
威望
0
注册时间
2016-9-13
在线时间
256 小时
最后登录
2017-12-12
发表于 2017-8-10 19:56:23 | 显示全部楼层
路过学习了
[发帖际遇]: 1169895688 发帖时在路边捡到 1 蛮牛币,偷偷放进了口袋. 幸运榜 / 衰神榜

回复

使用道具 举报

3偶尔光临
232/300
排名
8195
昨日变化
4

0

主题

62

帖子

232

积分

Rank: 3Rank: 3Rank: 3

UID
224729
好友
0
蛮牛币
933
威望
0
注册时间
2017-6-2
在线时间
56 小时
最后登录
2017-11-18
发表于 2017-8-11 08:12:03 | 显示全部楼层
感觉不简单

回复

使用道具 举报

3偶尔光临
232/300
排名
8195
昨日变化
4

0

主题

62

帖子

232

积分

Rank: 3Rank: 3Rank: 3

UID
224729
好友
0
蛮牛币
933
威望
0
注册时间
2017-6-2
在线时间
56 小时
最后登录
2017-11-18
发表于 2017-8-11 08:13:20 | 显示全部楼层
楼主有源码吗?可以交流分享吗?

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1005/1500
排名
2858
昨日变化
13

3

主题

282

帖子

1005

积分

Rank: 6Rank: 6Rank: 6

UID
159631
好友
1
蛮牛币
1838
威望
0
注册时间
2016-7-30
在线时间
308 小时
最后登录
2017-12-12
发表于 2017-8-11 08:48:18 | 显示全部楼层
谢谢分享

回复

使用道具 举报

5熟悉之中
861/1000
排名
2415
昨日变化
14

1

主题

83

帖子

861

积分

Rank: 5Rank: 5

UID
121885
好友
0
蛮牛币
1138
威望
0
注册时间
2015-9-9
在线时间
297 小时
最后登录
2017-12-12
QQ
发表于 2017-8-11 08:59:00 | 显示全部楼层
喷射战士?

回复

使用道具 举报

5熟悉之中
695/1000
排名
2890
昨日变化
14

0

主题

83

帖子

695

积分

Rank: 5Rank: 5

UID
161694
好友
0
蛮牛币
1889
威望
0
注册时间
2016-8-11
在线时间
206 小时
最后登录
2017-12-12
QQ
发表于 2017-8-11 09:06:16 | 显示全部楼层
谢谢分享

回复

使用道具 举报

5熟悉之中
725/1000
排名
4247
昨日变化
31

1

主题

282

帖子

725

积分

Rank: 5Rank: 5

UID
122160
好友
0
蛮牛币
1334
威望
0
注册时间
2015-9-10
在线时间
172 小时
最后登录
2017-12-12
发表于 2017-8-11 09:25:06 | 显示全部楼层
感谢分享

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表