Shader:模拟LCD/CRT屏幕RGB像素显示效果

在玩《战地 2042》时发现一个模拟 RGB 像素显示的大屏幕:远观内容为完整图像,贴近观察是发光的 RGB 像素点。该效果很有趣,在 Unity 中复现一个玩玩。

实现的效果

截图

动图(GIF)

本文包含的内容

本文用 Unity 实现,但部分内容参考自 Youtube/Jam2go 的 Unreal Engine 教程。
UE 材质编辑器和 Unity 的 ShaderGraph 有一些区别,但区别不是很大。

本文主要内容:

  1. 实现 RGB 像素显示
  2. 解决摩尔纹问题

实现 RGB 像素显示

原理

LCD 或 CRT 屏幕像素显示原理很简单:每个完整像素由三个折射/发光元件(子像素)组成,每个元件(子像素)负责 RGB 三原色中的一色,三个发光元件(子像素)可以独立调节明暗,光线混合在一起便可显示一个完整像素的 RGB 颜色。

根据屏幕材质及 RGB 三个元件(子像素)的摆放方式(Pixel geometry)不同,衍生出了标准 RGB 排列、RGB Delta 排列、Pentile 排列、钻石排列等排列方式。

图片转自 WIKI 百科,作者:Pengo

Shader 模拟该效果:首先将片元采样的 RGB 颜色分开,之后将 RGB 三种颜色按照指定的排列位置显示出来。

创建一个像素排列图

使用绘图工具创建一个(或多个)子像素排列图,用于后续采样。

这张(或多张)图的要求为:

  • 可以表示子像素的排列;
  • 无限拼接;
  • 为 RGB 像素并排显示留出足够的偏移量。

这是我用 PhotoShop 画的一张排列图:

其参数为:标准 RGB 排列,子像素外边距 20px,圆角。

由于在标准 RGB 排列下三个子像素排列完全相同,因此我只需要一张图。后面采样时,UV 加一个 Offset 即可。

其他排列酌情准备一张或多张图。

子像素采样排列图

为了让 RGB 能够错开显示,我采样了三次子像素图,并通过 Offset 值把 UV 错开,三个结果分别用于 RGB 中的一色:

本文采用标准 RGB 排列,如果使用其他排列图,需要自行调整 Offset 或采样方法,确保三个子像素可以分开并重复拼接。

子像素叠加纹理颜色

分别取 RGB 三个颜色,与三个子像素相乘:

注意:此处简单相乘与真实世界不符:
真实世界的单个子像素内部是一体的,不能再细分区域调节明暗了;
在此处追求与真实世界一致没有意义,不仅增加复杂运算(比如选取子像素“最合适明暗”的算法),且观感上也没太大区别。

颜色相加得到片元颜色

当片元位于 R 子像素区域时,G 和 B 的值均为黑色(0,0,0),其他子像素同理,因此片元颜色 = R + G + B。

结果如下:

摩尔纹

问题

虽然上文已经有像素效果了,但摄像机位于某些角度或距离时,图像会产生摩尔纹:

由于摩尔纹的存在,当摄像机远离时,并没有我看不到像素点欸的“视网膜屏”的感受。

解决摩尔纹 & 实现远处清晰

我们利用一个取巧的解决摩尔纹问题:根据距离渐变,在 X 米之内显示像素,X 米之外渐变为原本的 Texture 颜色,并叠加一个 power 控制渐变的过渡。

我的子像素排列图中黑色较多(即子像素间距过大),为了让渐变全图的亮度与像素图一致,因此对 Texture 叠加了一个用参数控制的 Lerp 黑色。

如果子像素紧紧排列没有空隙,则不需要变暗这么多。

反之,也可以提升下像素模式的亮度。

另外,远处清晰的需求也自然实现。

效果

近中远过渡(右下角到左上角)

动图

梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/10150.html
欢迎加入梓喵出没博客交流群:313732000

我来吐槽

*

*

0位绅士参与评论

  1. 广树01-18 11:15 回复

    好有意思!话说首页的轨迹banner都下了啊