十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Phaser 3.55.2 版本修复详解:Shape 游戏对象 WebGL 填充渲染中的纹理串扰(Texture Bleed)问题

Phaser 3.55.2 版本修复详解:Shape 游戏对象 WebGL 填充渲染中的纹理串扰(Texture Bleed)问题 Phaser 3.55.2 版本修复详解Shape 游戏对象 WebGL 填充渲染中的纹理串扰Texture Bleed问题【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser导读本篇文章围绕 Phaser 3.55.2代号 Ichika2021 年 5 月 27 日发布修复的核心缺陷展开FillPathWebGL、IsoBoxWebGLRenderer和IsoTriangleWebGLRenderer三个渲染函数导致大多数 Shape 游戏对象的填充部分错误地拾取了显示列表中前一个对象的纹理Issue #5720。读者将理解该 Bug 的成因——填充渲染在 WebGL 批处理时错误地将上一个对象激活的纹理绑定到了当前绘制调用——并掌握 Phaser 3 WebGL 渲染管线中填充路径 索引批处理 纹理绑定的底层原理以及 3.55.2 之后在 src/gameobjects/shape 下对应的修复实现。版本背景3.55.2 在 Phaser 3 生命周期中的位置Phaser 3 的 3.55 系列是 3.x 时代重要的稳定分支。3.55.2 作为该系列的一个补丁版本发布于 2021 年 5 月 27 日仅包含一条 Bug Fix聚焦性极强。在变更日志 changelog/v3/3.55.2/CHANGELOG-v3.55.2.md 中记录了本次修复的核心信息Fixed an issue inFillPathWebGL,IsoBoxWebGLRendererandIsoTriangleWebGLRendererfunctions which caused the filled versions of most Shape Game Objects to pick-up the texture of the previous object on the display list. Fix #5720 (thanks samme)翻译过来即是在FillPathWebGL、IsoBoxWebGLRenderer和IsoTriangleWebGLRenderer三个函数中存在一个缺陷它导致大多数 Shape 游戏对象的填充版本在渲染时拾取了显示列表中前一个对象的纹理。该问题由社区成员 samme 报告Issue #5720。值得注意的是Phaser 3 的 Shape 游戏对象包含 Rectangle、Arc、Star、Ellipse、Polygon、Curve、IsoBox、IsoTriangle 等大量子类因此大多数 Shape 游戏对象受影响的范围极广这个问题在混合使用 Shape 填充对象与贴图对象的场景下会直接表现为视觉上的花屏或纹理错乱。问题表象填充形状继承了前一个对象的纹理在 Phaser 3 的 WebGL 渲染模式下游戏对象按显示列表顺序逐个提交到 GPU 批处理队列。正常的绘制流程中每个对象要么绑定自己的纹理如 Sprite、Image要么以无纹理状态绘制纯色如 Shape 的填充、Graphics 的 fillStyle。在该 Bug 存在时任何先于某个填充 Shape 渲染的、带有纹理的游戏对象例如一张图片或一个精灵会把它的纹理状态残留在渲染管线中随后渲染的填充 Shape 在批处理时错误地沿用了这个纹理导致纯色填充区域被该纹理覆盖或污染呈现为形状颜色丢失、出现上个对象的图案的异常画面。该问题在以下场景中尤为明显显示列表中贴图对象Sprite / Image紧邻其后的 Polygon、Star、Ellipse 等填充形状同一帧内频繁创建/销毁 Shape 对象导致批处理状态切换更频繁使用 IsoBox / IsoTriangle 绘制等距风格isometric图形并与普通贴图混排。深入源码三个问题函数的渲染路径要准确理解修复内容需要逐一分析变更日志点名的三个函数在仓库中的实际实现。1. FillPathWebGL所有填充 Shape 的公共路径FillPathWebGL是 Shape 系统在 WebGL 下填充路径的公共工具函数位于 src/gameobjects/shape/FillPathWebGL.js。它被 Rectangle、Arc、Star、Ellipse、Polygon、Curve 等多个 Shape 的 WebGL 渲染器共同引用。例如src/gameobjects/shape/polygon/PolygonWebGLRenderer.js 在isFilled为真时调用FillPathWebGL(drawingContext, submitter, calcMatrix, src, alpha, dx, dy)src/gameobjects/shape/arc/ArcWebGLRenderer.js、src/gameobjects/shape/star/StarWebGLRenderer.js、src/gameobjects/shape/ellipse/EllipseWebGLRenderer.js、src/gameobjects/shape/curve/CurveWebGLRenderer.js、src/gameobjects/shape/rectangle/RectangleWebGLRenderer.js 同理。从源码约 L24-L64可以看到它的核心逻辑var FillPathWebGL function (drawingContext, submitter, calcMatrix, src, alpha, dx, dy) { var fillTintColor Utils.getTintAppendFloatAlpha(src.fillColor, src.fillAlpha * alpha); var path src.pathData; var pathIndexes src.pathIndexes; var length path.length; var pathIndex, pointX, pointY, x, y; var vertices Array(length * 2); var colors Array(length); var verticesIndex 0; var colorsIndex 0; for (pathIndex 0; pathIndex length; pathIndex 2) { pointX path[pathIndex] - dx; pointY path[pathIndex 1] - dy; // Transform the point. x calcMatrix.getX(pointX, pointY); y calcMatrix.getY(pointX, pointY); vertices[verticesIndex] x; vertices[verticesIndex] y; colors[colorsIndex] fillTintColor; } submitter.batch( drawingContext, pathIndexes, vertices, colors, src.lighting ); };该函数本身不做三角剖分——注释明确说明这非常类似于 FillPath RenderNode但它已经能访问 Earcut 索引因此无需自行计算。它直接消费 Shape 在构建时预计算好的pathData顶点序列与pathIndexesEarcut 三角化后的索引序列将每个顶点乘以变换矩阵后连同统一的填充色调fillTintColor一起通过submitter.batch(...)提交到批处理队列。问题的关键在于submitter.batch(...)这一调用。当批处理器在渲染纯色三角形时如果它错误地把当前绑定的纹理来自上一个已渲染对象当作本次绘制的纹理来源就会出现变更日志描述的pick-up the texture of the previous object现象。2. IsoBoxWebGLRenderer等距箱体的三面填充IsoBoxWebGLRenderer位于 src/gameobjects/shape/isobox/IsoBoxWebGLRenderer.js负责等距箱体的 WebGL 绘制。从源码可以看到它依次渲染三个可见面顶面Top Face、左面Left Face、右面Right Face每个面由两个三角形fillTriNode.run(...)构成// Top Face if (src.showTop) { tint Utils.getTintAppendFloatAlpha(src.fillTop, alpha); // x0..x3, y0..y3 由 size / projection 等参数计算得出 fillTriNode.run(drawingContext, calcMatrix, submitterNode, x0, y0, x1, y1, x2, y2, tint, tint, tint, lighting); fillTriNode.run(drawingContext, calcMatrix, submitterNode, x2, y2, x3, y3, x0, y0, tint, tint, tint, lighting); }三个面的色调分别来自fillTop、fillLeft、fillRight几何尺寸则由size / 2与size / src.projection计算得出。它同样通过submitterNode进行批处理提交与 FillPathWebGL 共享同一批处理基础设施。3. IsoTriangleWebGLRenderer等距三角形的填充IsoTriangleWebGLRenderer位于 src/gameobjects/shape/isotriangle/IsoTriangleWebGLRenderer.js逻辑与 IsoBox 类似但增加了isReversed是否反向分支用于控制顶面在正向/反向模式下是否绘制// Top Face if (src.showTop reversed) { tint Utils.getTintAppendFloatAlpha(src.fillTop, alpha); // ... 计算顶点后通过 fillTriNode.run 提交两个三角形 }左面与右面则根据reversed采用不同的顶点排列但最终同样走fillTriNode.run(...)提交到submitterNode。根因剖析批处理提交与纹理状态的耦合三个函数的共同点在于它们都以纯色三角形的方式提交数据却复用了一个不区分纹理来源的批处理提交入口。在 WebGL 渲染中纹理绑定gl.bindTexture是 GPU 的全局状态批处理器必须显式管理当前批次使用哪个纹理以及何时必须刷新批次并解绑/切换纹理。对照仓库中后续版本Phaser 4 的 RenderNode 体系的实现可以进一步印证这一架构在 src/renderer/webgl/renderNodes/BatchHandlerTriFlat.js 中三角形批处理器持有_emptyTextures、vertexCount、renderOptions等状态并通过batchTextures(glTexture, renderOptions)见 src/renderer/webgl/renderNodes/BatchHandlerQuad.js L726、L877、L960-L980维护纹理批次的去重与绑定。若填充路径的提交路径在纯色、无纹理场景下未显式清空或指定纹理状态就会沿用上个批次残留的纹理。同样在 src/renderer/webgl/renderNodes/FillPath.jsPhaser 4 中与FillPathWebGL对应的 RenderNode 实现可以看到现代实现把路径点简化detail 阈值→ Earcut 三角化 → 同色顶点共享 / 异色逐三角形展开 →submitterNode.batch(...)做了更严格的分层并区分同色共享顶点与异色展开三角形两条提交路径从设计上避免了纹理状态串扰的可能性。需要说明的是由于当前仓库的快照已包含修复后的 3.55.2 代码FillPathWebGL等函数已正确处理纯色批处理我们无法直接从仓库还原 Bug 当时的污染代码但从 Issue #5720 的描述、三个函数的共同批处理入口以及 Phaser 4 渲染架构对纹理批处理的显式管理可以清晰地推断出该缺陷源于填充路径的批处理提交未正确隔离/重置纹理状态。修复范围与影响哪些代码实际被修改变更日志点名的三个函数对应仓库中的源文件如下变更日志中的函数仓库源文件FillPathWebGLsrc/gameobjects/shape/FillPathWebGL.jsIsoBoxWebGLRenderersrc/gameobjects/shape/isobox/IsoBoxWebGLRenderer.jsIsoTriangleWebGLRenderersrc/gameobjects/shape/isotriangle/IsoTriangleWebGLRenderer.js由于FillPathWebGL被 src/gameobjects/shape/arc/ArcWebGLRenderer.js、src/gameobjects/shape/star/StarWebGLRenderer.js、src/gameobjects/shape/ellipse/EllipseWebGLRenderer.js、src/gameobjects/shape/curve/CurveWebGLRenderer.js、src/gameobjects/shape/polygon/PolygonWebGLRenderer.js 等多处复用这一个文件的修复实际上一次性覆盖了绝大多数 Shape 填充对象的渲染路径IsoBoxWebGLRenderer与IsoTriangleWebGLRenderer则针对等距图形做独立修复。修复后所有纯色填充的 Shape 在批处理时不再继承前一个对象的纹理形状颜色恢复正常。如何验证与复现验证当前仓库中的渲染路径读者可在当前仓库中直接查看修复后的实现确认纯色填充的提交逻辑阅读 src/gameobjects/shape/FillPathWebGL.js 中submitter.batch(drawingContext, pathIndexes, vertices, colors, src.lighting)的调用注意colors数组全部由fillTintColor填充色叠加 alpha填充阅读 src/gameobjects/shape/isobox/IsoBoxWebGLRenderer.js 与 src/gameobjects/shape/isotriangle/IsoTriangleWebGLRenderer.js观察三个面的fillTriNode.run(...)提交对照 src/gameobjects/shape/polygon/PolygonWebGLRenderer.js 中isFilled与isStroked双分支调用FillPathWebGL/StrokePathWebGL的结构理解填充与描边在提交上的分界。用最小示例复现3.55.2 之前版本在 3.55.2 之前的版本中以下场景可稳定触发纹理串扰创建一个带有纹理的 Image紧接着创建一个填充的 Polygon 或 Star并在同一场景中渲染。若 Bug 存在Polygon/Star 的填充区域会显示 Image 的纹理图案升级到 3.55.2 后该现象消失填充区域恢复为纯色。由于当前仓库快照即为修复后的代码直接运行仓库构建产物不会复现该问题适合作为回归验证用例对照 tests/gameobjects/shape 下的 Shape 渲染测试结构可自行添加贴图对象 填充 Shape 相邻渲染的回归测试。升级建议若项目仍停留在 Phaser 3.55.0 / 3.55.1且渲染画面中出现纯色形状被上个对象纹理覆盖的异常优先升级到 3.55.2该版本为 Patch 级别升级成本低且不引入新的 API 变更可放心合入涉及大量 Shape 填充对象尤其是 Polygon、Star、Arc 以及 IsoBox / IsoTriangle 等距图形的项目建议升级后做一轮视觉回归重点检查贴图对象与填充形状混排的场景。小结Phaser 3.55.2 虽然只包含一条 Bug Fix却精准修复了 WebGL 渲染管线中一个覆盖面极广的缺陷填充 Shape 在批处理时错误拾取前一个对象的纹理。通过FillPathWebGL这一公共函数的一处修复同时解决了普通 Shape 与 IsoBox / IsoTriangle 等距图形的问题而该问题在 Phaser 4 的 RenderNode 架构中通过显式的纹理批处理管理src/renderer/webgl/renderNodes 下的 BatchHandler 系列从架构上得到了根治。对开发者而言理解这一修复不仅有助于排查渲染异常也能更深入地掌握 Phaser WebGL 批处理与纹理状态管理的底层机制。【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表