UnityShader之Glitch Art效果

码途觅雪鹤
• 阅读 2861

【博物纳新】是UWA旨在为开发者推荐新颖、易用、有趣的开源项目,帮助大家在项目研发之余发现世界上的热门项目、前沿技术或者令人惊叹的视觉效果,并探索将其应用到自己项目的可行性。很多时候,我们并不知道自己想要什么,直到某一天我们遇到了它。

更多精彩内容请关注:lab.uwa4d.com


导读

电视信号受到干扰,产生画面抖动、色彩漂移等现象,这种电子设备成像故障产生的效果,被应用在赛博朋克等科幻类型的影视游戏作品中。逐渐成为一种特有的风格艺术:故障艺术(Glitch Art)。育碧在其3A大作《看门狗》系列中,频繁的采用了这种表现手法。日本知名Unity大师Keijiro的开源库项目KinoGlitch模拟了这一风格。
UnityShader之Glitch Art效果

该项目主要模拟了两种类型的效果:Analog Glitch和Digital Glitch。
UnityShader之Glitch Art效果
(无特效时场景)

开源库链接:https://lab.uwa4d.com/lab/5b5d1c86d7f10a201feaa37f


Analog Glitch

这种Glitch效果类型可以分为以下四种效果:

1、Scan Line Jitter
UnityShader之Glitch Art效果
(_scanLineJitter设定为0.5时 效果图)

这种效果是以像素为单位横向拉伸不同程度地拉伸物体,从而形成抖动。可以通过后处理的方式来实现。在Shader中进行采样的时候,采样点为原图位置横向偏移一些的点。可以通过一个float类型的变量来控制偏移量。
UnityShader之Glitch Art效果
(_scanLineJitter设定为1时 效果图)

这个效果的实现重点在于采样的随机性,这样抖动的效果更加逼真。并且偏移量处在一个限定的范围内,即使抖动也能基本看出原本的模型样貌。作者设计了一个较为复杂运算来模拟随机效果,并将偏移量限定在特定范围内:

//AnalogGlitch.cs中设定变量用于控制偏移量
[SerializeField, Range(0, 1)]
float _scanLineJitter = 0;

//AnalogGlitch.shader
//计算具体偏移量
float jitter = nrand(v, _Time.x) * 2 - 1;
jitter *= step(_ScanLineJitter.y, abs(jitter)) * _ScanLineJitter.x;

float nrand(float x, float y){
  return frac(sin(dot(float2(x, y), float2(12.9898, 78.233))) * 43758.5453);
}
//根据偏移量进行采样
half4 src1 = tex2D(_MainTex, frac(float2(u + jitter, v)));

2、Horizontal Shake

这种效果用于进行横向的抖动,通过设定一个float类型的偏移量。绘制时根据偏移量进行采样即可:

//AnalogGlitch.cs中设定变量用于控制偏移量
_material.SetFloat("_HorizontalShake", _horizontalShake * 0.2f);
//AnalogGlitch.shader
//计算具体偏移
float shake = (nrand(_Time.x, 2) - 0.5) * _HorizontalShake;

float nrand(float x, float y){
  return frac(sin(dot(float2(x, y), float2(12.9898, 78.233))) * 43758.5453);
//根据偏移量进行采样
half4 src1 = tex2D(_MainTex, frac(float2(u + shake, v)));

3、Color Drift
UnityShader之Glitch Art效果
(效果图)

这种效果主要用于模拟机器故障时颜色显示出现错乱、偏移、重影的情况。可以通过讲RGB通道进行分离重组的方式进行实现。

//AnalogGlitch.cs中设定变量用于控制偏移量
var cd = new Vector2(_colorDrift * 0.04f, Time.time * 606.11f);
_material.SetVector("_ColorDrift", cd);
//AnalogGlitch.shader
//计算具体偏移
float drift = sin(jump + _ColorDrift.y) * _ColorDrift.x;

//采样原图&根据偏移量进行采样
half4 src1 = tex2D(_MainTex, frac(float2(u , v)));
half4 src2 = tex2D(_MainTex, frac(float2(u + drift, v)));

//将上述的采样结果进行混合
return half4(src1.r, src2.g, src1.b, 1);

4、Vertical Jump
UnityShader之Glitch Art效果
(效果图)

这种效果用于模拟机器故障时,出现纵向跳动的的情况。这种情况的模拟比较简单,可以通过设定一个纵向偏移量,对原图进行采样即可:
UnityShader之Glitch Art效果
(效果图)

在此基础上,可以通过插值,来实现采样过程中只采集局部图片的效果:
UnityShader之Glitch Art效果
(进行插值后效果图)

具体代码如下:

//AnalogGlitch.cs中设定变量用于控制偏移量
_verticalJumpTime += Time.deltaTime * _verticalJump * 11.3f;
 var vj = new Vector2(_verticalJump, _verticalJumpTime);
_material.SetVector("_VerticalJump", vj);

//AnalogGlitch.shader
//进行插值
float jump = lerp(v, frac(v + _VerticalJump.y), _VerticalJump.x);
//根据偏移量进行采样
half4 src1 = tex2D(_MainTex, frac(float2(u, jump)));

可以将上述四种实现效果进行组合:

half4 src1 = tex2D(_MainTex, frac(float2(u + jitter + shake, jump)));
half4 src2 = tex2D(_MainTex, frac(float2(u + jitter + shake + drift, jump)));
return half4(src1.r, src2.g, src1.b, 1);

从而得到一些复杂的效果:
UnityShader之Glitch Art效果
(效果图)


Digital Glitch: Block Damage

UnityShader之Glitch Art效果
(效果图)

这种类型效果是在图像上显示一定大小、颜色的色块,用于模拟电子设备故障部分区域无法正常显示的效果。

可以通过一个噪声图像来辅助制作。首先随机生成一个噪声图像:

void UpdateNoiseTexture(){
var color = RandomColor();
for (var y = 0; y < _noiseTexture.height; y++){
  for (var x = 0; x < _noiseTexture.width; x++){
    if (Random.value > 0.89f)
      color = RandomColor();
    _noiseTexture.SetPixel(x, y, color);
    }
  }
   _noiseTexture.Apply();
}

设定一个float类型的变量_intensity用来控制效果力度。

作者在片元着色器中设计了一套运算,保证当_intensity=1时,图像全部区域产生该效果:
UnityShader之Glitch Art效果

反之,_intensity=0时,没有效果。

具体采样包括:正常图像、前一次刷新时图像、噪声图像。通过这三种图像采集的得到的区域进行混合叠加得到效果:
UnityShader之Glitch Art效果


性能测评

我们对项目进行优化处理,将场景中模型使用的Standard Shader 全部替换为Diffuse Shader。(大家在使用案例测试时要注意其Standard Shader带来的巨大开销)。

使用华为8Plus,开启多线程渲染,同时开启两个效果后,用GOT Online测试了下性能,FPS可达30帧左右。
UnityShader之Glitch Art效果

读者可以尝试将该效果应用于移动端。应用时可以进一步优化,例如简化算法,减少使用sin、dot、pow等函数,采用其他的算法来模拟随机等。


快用UWA Lab合辑Mark好项目!
UnityShader之Glitch Art效果

今天的推荐就到这儿啦,或者它可直接使用,或者它需要您的润色,或者它启发了您的思路......

请不要吝啬您的点赞和转发,让我们知道我们在做对的事。当然如果您可以留言给出宝贵的意见,我们会越做越好。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
1年前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java中比较两个时间的差值
项目背景1.某篇文稿的发布时间是publishDate,例如:2020072118:00:41。2.现要求判断该篇文稿的发布时间是否在近30天之内。publicstaticlongdayDiff(DatecurrentDate,DatepublishDate){LongcurrentTimecurrentDat
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
C++笔记002:VS2010报错:LINK fatal error LNK1123 转换到 COFF 期间失败文件无效或损坏
 原创笔记,转载请注明出处!点击【关注】,关注也是一种美德~错误描述:1已启动生成:项目:FirstCode,配置:DebugWin321生成启动时间为2018/2/521:00:30。1InitializeBuildStatus:1 正在
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究