最近我在 Unity 中开发了一款 LED 墙壁渲染器,并已在 Asset Store 上发布。更有趣的部分并不是编写 UI(虽然它仍然很好!),而是渲染设置。以下是一些可能对其他人有用的实现注意事项。

1. 不要渲染每个 LED 为几何体

该板块被表示为一个逻辑纹理,例如 192 x 108 发射器。内容首先被组合到纹理中,然后 shader 重构可见的 LED 细胞。

该 shader 使用板块 UV、逻辑分辨率和发射器单元坐标来绘制 LED 形状。这样就可以支持圆形、正方形或六边形发射器,而不需要生成数千个网格。

有用的分离是:

  • C# 拥有板块分辨率、渲染纹理、布局、时间和源更新。
  • shader 拥有发射器重构、间隔、衰减、亮度响应、缝隙和距离混合。

这也避免了大显示器上的巨大 GameObject 或网格数量的问题。

2. 硬件缺陷更好地作为一个单独的遮罩

缺陷并没有被烘焙到源内容中。板块有一个单独的缺陷纹理/遮罩,shader 在呈现最终 LED 输出时采样这个缺陷。

这个遮罩可以编码如下内容:

  • 死的发射器
  • dim 发射器
  • 卡住的颜色
  • 闪烁参数
  • 线或柜台故障

源纹理保持清洁。缺陷通道修改了模拟硬件输出。这使得重用相同的内容在不同板块条件下变得更容易,并且通过种子使过程缺陷变得确定。

3. 多面板板块组合一次,然后切割

对于视频墙或长条板,各个面板不应独立组合相同的内容。这会导致同步和对齐问题。

我最终使用的设置是:

  1. 找到子板块控制器。
  2. 从所有子逻辑分辨率中计算一个主分辨率。
  3. 添加可选的边框像素。
  4. 将布局一次性组合到一个主 RenderTexture 中。
  5. 将主纹理切割成每个面板的渲染纹理。
  6. 将每个切片传入子板块。

每个子板块仍然拥有其材质、shader设置和缺陷配置,但内容保持连续在整个墙壁上。

4. 跨管道shader需要共享的核心逻辑

板块shader支持 Built-in、URP 和 HDRP。最不痛苦的设置是将 LED 数学放在共享 HLSL 包括中,并且使每个管道的通道尽可能地薄。

共享包包括处理发射器重构、缝隙数学、亮度响应和缺陷应用。每个 shader 通道处理管道特定的包包括、标签、混合状态和输出约定。

我还添加了检查器测试,检查 shader 源代码是否有回归,例如:

  • HDRP 包括顺序
  • 正确的通道标签
  • 缺陷逻辑存在于 Built-in 通道中
  • 缝隙宽度保持在发射器单位中,而不是任意 UV 缩放

这不是高级测试,但它捕捉了通常只有在导入到另一个渲染管道后才会出现的 shader 漏洞。

主要的架构性教训是保持系统分层:C# 中的逻辑板块组合、硬件模拟通过遮罩和板块状态以及 shader 中的可视 LED 重构。这样做使实现更容易测试,并且在板块大小和渲染管道之间保持一致性变得更加容易。