【3D本地分屏】踩坑和经验

修改于昨天 10:1935 浏览开发心得
不长,随便写的,ai也干了。
现象:本地双人分屏模式下,部分移动设备出现画面异常:
设备 A(🐉768g):左半屏出现竖条纹/花屏,严重阻碍P1。
设备 B(🐔9400e):按钮周围出现小范围黑色方块,影响较小。
影响范围:部分移动 GPU(Mali / Adreno都有)。
排查过程:嗒啦啦干的。
1.NanoVG 非凸路径导致 stencil 冲突(人话就是按钮用了什么东西冲突了)(这怎么可能呢)
2.nvgRadialGradient shader 在移动 GPU 异常(不懂,执行的结果是移除所有渐变,改为纯色,最终无效)
3.自定义按钮绘制代码有问题(同1,有问题早就爆了[表情_捂脸哭]
4.VirtualControls 第二个 NanoVG 上下文 GL 状态冲突(尝试标空,让其避免冲突。结果没有用。)
5.主 NanoVG 上下文导致问题(同理,执行的操作是分屏时跳过主上下文 nvgBeginFrame/nvgEndFrame,但是还是失败了)
6.3D多视口 IntRect 裁切有问题 (最后的稻草了。改成了交替渲染,单数帧渲染你的,双数帧渲染我的。最后不花屏了。就是画面像喝多了一样乱抽)
结论:最终确认为第六点。嗒啦啦不禁感慨:renderer:SetNumViewports(2) + Viewport.rect = IntRect(半屏) 在部分移动 GPU 上可能存在驱动兼容性问题。引擎的多视口裁切依赖 glViewport + glScissor 切换,某些移动 GPU 驱动对此处理不当,导致帧缓冲数据污染口牙。
解决方法直接粘了吧,省点事——
[表情_叹气]
## 解决方案:RenderToTexture + 正交拼合(方案 A)
### 原理
不使用引擎的多视口 + IntRect 裁切,而是:
1. 两个游戏相机各自渲染到独立的 `Texture2D`(RenderTarget)
2. 用一个全屏正交相机 + 合成场景,将两张 RT 纹理贴到左右两个 quad 上输出
```
原方案(花屏):
  renderer → viewport0 (IntRect 左半) → 相机1
           → viewport1 (IntRect 右半) → 相机2
新方案(RTT 拼合):
  RenderTexture1 ← viewport → 相机1
  RenderTexture2 ← viewport → 相机2
  renderer → viewport0 (全屏) → 正交相机 → 合成场景
                                             ├─ Quad左 (贴RT1)
                                             └─ Quad右 (贴RT2)
```
### 关键实现细节
```lua
-- 创建 RenderTexture
local rt = Texture2D.new()
rt:SetNumLevels(1)
rt:SetSize(halfW, screenH, Graphics:GetRGBAFormat(), TEXTURE_RENDERTARGET)
rt.filterMode = FILTER_BILINEAR
-- 注意:Graphics:GetRGBAFormat() 是类方法(大写 G + 冒号)
-- 不是 graphics:GetRGBAFormat()(实例方法会报错)
-- 设置 RenderSurface
local surface = rt:GetRenderSurface()
surface:SetUpdateMode(SURFACE_UPDATEALWAYS)
surface:SetNumViewports(1)
surface:SetViewport(0, Viewport:new(scene, camera))
```
不过因为有额外合成一次的关系,会导致画面会被后处理两次,结果就是会修理后分屏的画面会变暗。需要留意。
那至于到底是为什么,只能交给专业人士了。我哪知道这些啊,我就是一要饭的。
TapTap
2