URP管线下使用Dither做像素化风格
什么是Dither
基本概念
- v. 犹豫不决;对(录音)进行噪声处理;抖色
- n. 犹豫不决;紧张,颤抖
用有限的颜色来表示出多种色阶变化的技术就叫做Dither
上面那句话其实并不严谨,只是在此方便理解,Dither不是新型技术,它在视频,信号处理,音频等领域都有应用
图形中的应用
基于上述的简单且并不严谨的描述,下图是在一个2x2的像素格中,从左到右依次排列出一个黑白色阶的效果
对应黑白色阶
没看出来?我们将像素格缩小平铺
这下就对味了!
现在我们对Dither在图形上的应用已经有了初步的了解,并且我们可以看得到,2x2的像素格只有5种颜色过渡,那么4x4呢?
- 2x2像素格有5种颜色
- 4x4像素格有17种颜色
- 8x8像素格有65种颜色
有序抖动与无序抖动
这里我们不涉及更深的底层逻辑,直观一些,直接看图
这张图展示了不同算法呈现出的结果,其中下面
这张,就是有序Dither的效果,也是我们下面要实现的效果(有点像素画的感觉哈)
Dither的实现
这里我们的主要目标是先绘制一个2x2像素格的矩阵,然后再想办法将这些像素格填充平铺到屏幕中去
有了目标,下面我们开干!
像素格矩阵
首先我们想要绘制下面这样一个2x2的像素格,对应的矩阵应该是什么样的?
显而易见
平铺到屏幕中
方法其实很简单,只需要将上面那个2x2矩阵作为一个贴图一样目标,再用0,1,0,1,0,1不断重复的坐标值采样它就行了
说起来有点抽象,首先我们先看采样它的值从哪来
i.positionCS.xy
没错,就是它,我们知道裁剪空间下的坐标值,从顶点着色器输出到片段着色器后,它的值就是屏幕上每一个像素的值
且值非常大,不是简单的0-1,而且我们的矩阵只能取到0和1,即0行0列、0行1列.....所以必须将这些值映射为0和1,只需要除以2取余即可
直接输出 i.position.y - 400 后
所以我们就是用它的值,来采样2x2像素矩阵(与其说是采样,不如说是2x2像素矩阵的下标)
下面我们用代码实现一下
[4]先声明一个4x4的矩阵,我们知道这种排列方式是一个中灰色
[10]声明uint2二维整数类型,再将屏幕坐标值除以2取余
[12]通过屏幕坐标的x轴与y轴,查找矩阵的值
half4 frag(Varyings i) : SV_TARGET { float2x2 M2x2 = float2x2(0,1,1,0);uint2 uv = (uint2)i.positionCS.xy%2;return M2x2[uv.x][uv.y];}
最终效果
放大看
效果出现了,我们还可以改变矩阵的排列方式,呈现出不同的颜色状态
half4 frag(Varyings i) : SV_TARGET { float2x2 M2x2 = float2x2(0,1,0,0);uint2 uv = (uint2)i.positionCS.xy%2;return M2x2[uv.x][uv.y];}
黑色会更多
优化代码实现
上面我们已经知道了核心代码如何实现,因为还需要用到不同的矩阵数量以及排列方式(颜色),为了方便,我们直接创建自己的方法便于使用
// 2x2矩阵half Dither2x2_Matrix(uint2 uv ){uv %= 2;float2x2 M2x2 = float2x2(0,1,0,0);return M2x2[uv.x][uv.y];}half4 frag(Varyings i) : SV_TARGET { uint2 uv_gray = (uint2)i.positionCS.xy;half4 c = Dither2x2_Matrix(uv_gray);return c;return 1;}
趁热再写一个4x4的
// 4x4矩阵half Dither4x4_Matrix(uint2 uv ){uv %= 4;float4x4 M4x4 = float4x4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return M4x4[uv.x][uv.y];}half4 frag(Varyings i) : SV_TARGET { uint2 uv = (uint2)i.positionCS.xy;half4 c1 = Dither4x4_Matrix(uv);return c1;}
4x4矩阵采样的效果
这时候我们发现,我们写的4x4矩阵明明是从左往右的斜线呀,为什么显示出来后,是相反的?
主要是因为y轴,屏幕的坐标是以左下角为(0,0)点(OpenGL),但逐行采样矩阵时,却是从左上角开始的,所以就导致了这种情况发生
矩阵转化为数组
像素格元素不但可以用矩阵表示,也可以声明数组,不同的是,矩阵我们可以指定行与列,数组如何指定?
我们只需要用另一种算法作为数组的下标
例如3x3的矩阵
我们可以指定其几行几列,例如2行1列(从0开始),是7
数组
如果用上面那个算法呢?
注意,这里的值仅仅是它们的下标,或者索引值,数组或矩阵内部的值当然可以所以更改
但它们所指定的某一个数是一致的
它们的写法有所不同
// 4x4数组half Dither4x4_Array(uint2 uv ){uv %= 4;float A4x4[16]={1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1};return A4x4[uv.x*4+uv.y];}half4 frag(Varyings i) : SV_TARGET { uint2 uv = (uint2)i.positionCS.xy;half4 c1 = Dither4x4_Array(uv);return c1;}
Dither有序抖动
什么是有序抖动?
其实就是利用这样的矩阵,但看起来很乱不是吗?
它有一个规律,就是每两个数字之间都会相差较大,仔细看,还真是这样
下面我们就模仿这个矩阵的写法,创建一个出来
// 8x8数组half Dither8x8_Array(uint2 uv ){uv %= 8;float A4x4[64]={0,32,8,40,2,34,10,42,48,16,56,24,50,18,58,26,12,44,4,36,14,46,6,38,60,28,52,20,62,30,54,22,3,35,11,43,1,33,9,41,51,19,59,27,49,17,57,25,15,47,7,39,13,45,5,37,63,31,55,23,61,29,53,21};return A4x4[uv.x*8+uv.y];}
等等
数组里这些数值,除了0以外,其他的超过1的不都是白色?
别担心,我们可以用除法将他们映射到0-1区间,除以64看看
// 8x8数组half Dither8x8_Array(uint2 uv ){uv %= 8;float A4x4[64]={0,32,8,40,2,34,10,42,48,16,56,24,50,18,58,26,12,44,4,36,14,46,6,38,60,28,52,20,62,30,54,22,3,35,11,43,1,33,9,41,51,19,59,27,49,17,57,25,15,47,7,39,13,45,5,37,63,31,55,23,61,29,53,21};return A4x4[uv.x*8+uv.y]/64;}half4 frag(Varyings i) : SV_TARGET { uint2 uv = (uint2)i.positionCS.xy;half4 c = Dither2x2_Matrix(uv);return c2;}
这样我们就获得颜色不均的有序Dither效果了
有序抖动Dither的应用
有啥用??????
先给出答案:我们可以配合Clip方法用它来做半透明效果,也就是通过AlphaTest达到半透明效果
相信你已经知道改怎么写了
// 8x8数组half Dither8x8_Array(uint2 uv ){uv %= 8;float A4x4[64]={0,32,8,40,2,34,10,42,48,16,56,24,50,18,58,26,12,44,4,36,14,46,6,38,60,28,52,20,62,30,54,22,3,35,11,43,1,33,9,41,51,19,59,27,49,17,57,25,15,47,7,39,13,45,5,37,63,31,55,23,61,29,53,21};return A4x4[uv.x*8+uv.y]/64;}half4 frag(Varyings i) : SV_TARGET { uint2 uv = (uint2)i.positionCS.xy;half4 c = Dither2x2_Matrix(uv);clip(c2 - _Clip);return c2;}
这样我想到了小米透明电视。。。
放大看看
嘿!像不像MineCraft的玻璃!
像素风格
有序Dither不但可以作为廉价的半透明实现,最明显的作用就是将图像变成像素风格
实现原理
将目标图像(贴图,或者光照等)也传入Dither矩阵的方法中去,并将目标图像的数值与Dither矩阵中的数值做对比(Step/SmoothStep),然后输出即可
代码实现
[18]使用Step方法将有序Dither 与贴图颜色进行对比
[27]将RGB颜色转换为灰度的方法
// 8x8数组half Dither8x8_Array(uint2 uv , float color){uv %= 8;float A4x4[64]={0,32,8,40,2,34,10,42,48,16,56,24,50,18,58,26,12,44,4,36,14,46,6,38,60,28,52,20,62,30,54,22,3,35,11,43,1,33,9,41,51,19,59,27,49,17,57,25,15,47,7,39,13,45,5,37,63,31,55,23,61,29,53,21};half pixel = A4x4[uv.x*8+uv.y]/64;return step(pixel,color);}half4 frag(Varyings i) : SV_TARGET { half4 mainTex = SAMPLE_TEXTURE2D(_MainTex,smp,i.uv);half maintexGray = Luminance(mainTex.rgb);uint2 uv = (uint2)i.positionCS.xy;half4 c2 = Dither8x8_Array(uv,maintexGray);return c2;}
有点意思了
但是现在只是黑白的,毕竟受该方法的限制,我们不能一次性传入RGB进行对比
但是我们可以对每个通道比较最后再合成到一起!
half4 frag(Varyings i) : SV_TARGET { half4 mainTex = SAMPLE_TEXTURE2D(_MainTex,smp,i.uv);uint2 uv = (uint2)i.positionCS.xy;half c2 = Dither8x8_Array(uv,mainTex.r);half c3 = Dither8x8_Array(uv,mainTex.g);half c4 = Dither8x8_Array(uv,mainTex.b);half4 c = half4(c2,c3,c4,1);return c;}
效果一般,真正使用的话,还是需要再做修改
Houdini生成Dither纹理
使用Houdini可以将不同类型的Dither矩阵纹理填入同一张贴图的通道中
这里稍复杂,但节点不多,首先是B通道中填充8x8有序DIther
注意grid节点,需要先把网格设置为8x8的大小,这样每个面都为1个单位,并且x,z的位置也设定好,使得左上角为(0,0)点
Wrangle中的代码
注意Run Over设置为面,我们要取每个面的数值,并使他们为从0到63的排列方式,作为有序Dither矩阵的索引
最后一行输出到b通道
maps_baker节点
输出后的贴图B通道
URP管线下使用Dither做像素化风格相关推荐
- Unity URP管线下多光源渲染
抓手 urp管线下,获得其他多光源的方式和内置管线的不一样. 本文会阐述具体方法,并给出源码. 具体步骤 首先要在pipeline中打开Additional lighting的设置. 然后在shade ...
- Unity Shader - URP Fog - URP 管线下的雾效
文章目录 参考 LitForwardPass.hlsl 临摹使用 Test/URPFog 只要 Fog_Linear 变体的 效果 问题 修复 References 管线:URP URP:7.7.1 ...
- Unity在URP管线下使用TriLib插件加载模型材质不正确的问题
目前使用Unity开发项目绝大部分已经使用URP渲染管线,但是TriLib加载进来的模型默认的还是使用内置渲染管线的材质,这会导致材质无法正常显示,解决办法如下: 1.在Assets目录下新建一个As ...
- AirPlane Race Creator竞速游戏完整项目自定义模型操作说明基于Urp管线
最近一段时间,脑子被门夹了,伤心病狂地去搞引擎去了,之后会回归理性,重新做一些Unity插件的入门讲解 今天讲解的是,完整项目:AirPlane Racer - URP 特别适合某些人学习: 策划 - ...
- unity urp管线扫光效果
urp管线下实现扫光效果 基本思路,还是根据深度还原世界坐标(以下简称world_pos),根据坐标的xyz判断是否在一些范围内,然后进行基于xyz两个坐标轴进行扫光 这里进行一个扩展,让扫光可以沿着 ...
- 如何在Unity中自定义光源,包含URP管线和Build in 管线(一)
如何在Unity中自定义光源,包含URP管线和Build in 管线(一) 众所周知,光照在游戏画面效果上占了很大比例,一个游戏画面好不好,用最简单的理解来说,就是看游戏画面亮不亮,当然这个亮不是不是 ...
- Linux下使用WPS做office的二次开发
Linux下使用WPS做office的二次开发 序 上个版本WPS在Linux上就已经支持二次开发了,可以直接去看官网相关的介绍.https://open.wps.cn/ 我们选择WPS的客户端进行二 ...
- 院士:科研工作者也得养家!非升即走压力下,不得不做短平快的研究
点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 点击进入-> CV 微信技术交流群 本文转载自:募格课堂 | 综合自上游新闻.澎湃新闻.百度百科 如今 ...
- Unity URP管线的PBR材质及Tessallation Shader(Height Map高度贴图)
在使用URP管线的过程中发现默认的URP管线的shader是没有提供height map参数设置的,经过查找才知道URP管线中height map相关的功能需要自己写shader开启Tessallat ...
- Unity - 搬砖日志 - BRP 管线下的自定义阴影尺寸(脱离ProjectSettings/Quality/ShadowResolution设置)
文章目录 环境 原因 解决 CSharp 脚本 效果预览 - Light.shadowCustomResolution 效果预览 - Using Quality Settings 应用 Control ...
最新文章
- 说说你对 SVG 理解?
- Python学习笔记:Day5 编写web框架
- [vue] 怎么缓存当前打开的路由组件,缓存后想更新当前组件怎么办呢?
- 电脑突然卡主动不了了_必看!电脑运行卡或软件卡死无响应,怎么办?
- 春晚“宕机”魔咒失效 火山引擎助抖音成功闯关
- 无法删除文件:无法读源文件或磁盘”
- nginx 基本入门
- nginx反向代理服务器
- premiere调色预设怎么用
- vscode代码自动保存插件_VSCode 云同步扩展设置 Settings Sync 插件
- P2015 二叉苹果树 树形DP
- 重装系统“无法创建新的分区也找不到现有分区”
- 数据结构课程设计(部分选题)
- linux centos java kumo图片合成文字 词云插件 字体乱码问题
- 【vue eslint】报错Component name “xxxxx“ should always be multi-word.eslintvue/四种解决方案
- http请求 状态码204
- 《Arduino开发实战指南:LabVIEW卷》6.6 基于Arduino的弹珠游戏
- 有关逻辑炸弹方面的问题
- phpcms 推荐位获取
- 星载合成孔径雷达导论——合成孔径雷达概述
热门文章
- CTGU 2021春-MySQL数据库实验2:基本查询1-2关,共10小题全代码+信息表+通关截图!
- java实现百度网盘爬虫
- 【debug】Support for password authentication was removed on August 13, 2021.解决
- 2017前端开发手册三-前端职位描述
- SH-SSS丨CUSIDE:分块、模拟未来、解码的流式语音识别新框架
- U8文件服务器备份,u8备份缓存文件在哪
- Android调用自带TTS文本转语音引擎实现离线语音合成
- 简单明了的java反射机制
- 达梦数据库ZYJ实例安装初始化
- 财经APP富途牛牛商业模式分析