Phaser 4.0 RC2 更新深度解读:渲染节点、Shader 制服与关键修复全解析
【免费下载链接】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
导读:本文基于 changelog/v4/4.0-rc/CHANGELOG-v4.0-rc.2.md 展开,系统梳理 Phaser 4.0 Release Candidate 2 相对 RC1 的三项新特性、一项 API 变更与七项修复。你将掌握如何在游戏启动时通过
renderNodes注入自定义渲染节点、用initialUniforms与setUniform精确控制 Shader 制服,以及addDynamicTexture新增的forceEven参数对纹理质量的实战影响,并结合仓库源码理解每条变更的底层实现。
RC2 更新总览:一次面向渲染管线的收敛
Phaser 4.0 RC2 是 4.0 正式版发布前的第二个候选版本,其更新重心几乎全部落在 WebGL 渲染管线与 Shader 系统上。RC1 之后,开发团队在三天内完成了 11 项调整,包括 3 项新特性、1 项参数扩展和 7 项缺陷修复。从变更内容看,RC2 主要解决三件事:
- 补齐 Shader 制服的设置路径:新增
initialUniforms配置与Shader#setUniform方法,让用户不再依赖setupUniforms()一个入口; - 开放渲染节点注册时机:
RenderConfig#renderNodes使自定义 Render Node 可以在游戏启动(game boot)时即被注册; - 修正一批与过滤(Filter)、容器(Container)、动态纹理(DynamicTexture)相关的坐标与层级问题。
下文逐一深入每条变更,并给出对应源码位置供查阅。
新特性一:RenderConfig#renderNodes—— 启动期注册自定义渲染节点
RC2 允许通过RenderConfig#renderNodes在游戏启动时向 WebGL 渲染器添加自定义 Render Node。其定义位于 src/core/Config.js:
/** * @const {Object<Phaser.Types.Core.RenderNodesConfig>} Phaser.Core.Config#renderNodes * A map of custom Render Nodes to be added to the WebGL Renderer. * The values will be added to the RenderNodeManager, using the keys as the names. */ this.renderNodes = GetValue(renderConfig, 'renderNodes', {}, config);对应的类型声明在 src/core/typedefs/RenderConfig.js。配置的消费点在 src/renderer/webgl/renderNodes/RenderNodeManager.js:
Object.entries(game.config.renderNodes).forEach(function (entry) { var name = entry[0]; var constructor = entry[1]; this.addNodeConstructor(name, constructor); }, this);用法:在 Phaser 游戏配置对象中传入一个{ 节点名: 构造函数 }映射,RenderNodeManager 初始化时会以节点名注册这些构造函数。注册后的节点可通过renderer.renderNodes.getNode('自定义名称')获取并使用,与内置节点(如Camera、ShaderQuad、各类 Filter 节点)处于同一命名空间。
const config = { type: Phaser.AUTO, width: 800, height: 600, renderNodes: { MyCustomNode: MyCustomNodeConstructor } };从源码结构看,RenderNodeManager内置了从FilterBarrel、FilterBlur到ListCompositor、SubmitterQuad等数十个节点(见 RenderNodeManager.js),renderNodes配置正是为第三方扩展预留的注册通道——这是 Phaser 4 全新 RenderNode 架构(见 src/renderer/webgl/renderNodes 目录)开放给用户的第一道正式入口。
新特性二:ShaderQuadConfig#initialUniforms—— 创建时初始化 Shader 制服
此前,自定义 Shader 的制服只能在setupUniforms()回调中设置,而该回调在每次渲染时都会执行(见 src/gameobjects/shader/Shader.js 的文档说明:"runs every time the shader renders")。对于值固定不变的制服,这种重复设置属于冗余开销。
RC2 新增的initialUniforms配置让这些值在 Shader 创建时一次性写入。类型声明位于 src/gameobjects/shader/typedefs/ShaderQuadConfig.js:
/** * @property {object} [initialUniforms] - An object containing the initial uniform values to set. * The keys are the uniform names, and the values are the uniform values. * This is used to set up the shader before it is rendered for the first time. */实现路径:在 Shader.js 的构造函数中,配置对象被逐项取出并调用setUniform写入:
var initialUniforms = GetFastValue(config, 'initialUniforms', {}); Object.entries(initialUniforms).forEach(function (entry) { this.setUniform(entry[0], entry[1]); }, this);用法示例:通过this.add.shader()传入配置对象,即可在创建时绑定固定制服:
this.add.shader({ key: 'myShader', initialUniforms: { uIntensity: 0.5, uColor: [ 1.0, 0.0, 0.0, 1.0 ] } }, 400, 300, 512, 512);值得注意的是,仓库中的渐变对象 src/gameobjects/gradient/Gradient.js 已经在使用initialUniforms配置自己的内置 Shader,可作为参考实现。
新特性三:Shader#setUniform—— 一次性设置单个制服
与initialUniforms配套,RC2 为Shader游戏对象新增了实例方法Shader#setUniform(name, value),实现位于 src/gameobjects/shader/Shader.js:
/** * @method Phaser.GameObjects.Shader#setUniform */ setUniform: function (name, value) { this.renderNode.programManager.setUniform(name, value); }该方法是对Shader#renderNode.programManager.setUniform的封装,其意义在于:当你只需在某个时机(而非每帧)更新一个制服时,不必把所有逻辑塞进setupUniforms()——后者会在每次渲染时重复执行,可能造成多余写入。
用法:
// 在 Shader 创建后任意时刻动态更新制服 shader.setUniform('uTime', this.game.loop.getDuration()); shader.setUniform('uMix', 0.75);从底层看,Shader对象持有一个ShaderQuad渲染节点(src/gameobjects/shader/Shader.js),节点内将setUniform绑定到ProgramManager的方法(见 src/renderer/webgl/renderNodes/ShaderQuad.js):
this.setUniform = this.programManager.setUniform.bind(this.programManager);ProgramManager负责 Shader 程序的创建、变体管理与制服队列写入,所有 Filter 节点的制服上传(如FilterVignette、FilterBlur、FilterShadow等)最终都汇聚到这一机制。
API 变更:TextureManager#addDynamicTexture新增forceEven参数
RC2 将addDynamicTexture的尺寸处理规则显式参数化:新增可选布尔参数forceEven。方法签名与实现见 src/textures/TextureManager.js:
/** * @param {number} [width=256] - The width of this Dynamic Texture in pixels. Defaults to 256 x 256. * @param {number} [height=256] - The height of this Dynamic Texture in pixels. Defaults to 256 x 256. * @param {boolean} [forceEven=true] - If the width and height are odd numbers, should they be forced to be even? * Ignored if an instance is passed as the key. */ addDynamicTexture: function (key, width, height, forceEven) { if (typeof(key) === 'string' && !this.exists(key)) { if (forceEven === undefined) { forceEven = true; } texture = new DynamicTexture(this, key, width, height, forceEven); } ... }forceEven默认值为true,其实际逻辑在DynamicTexture内部(src/textures/DynamicTexture.js):
setSize: function (width, height, forceEven) { if (forceEven === undefined) { forceEven = true; } if (forceEven) { width = Math.floor(width); height = Math.floor(height); if (width % 2 !== 0) { width++; } if (height % 2 !== 0) { height++; } } ... }实战要点:
- 当
forceEven为true(默认)时,奇数宽高会被向上取整为偶数(如 63 → 64),文档注释明确说明这"显著提升渲染质量"(见 DynamicTexture.js); - 若你的业务确实需要奇数尺寸纹理(例如精确对位的像素级贴图),可显式传入
false关闭强制取整; - 该参数同时出现在
DynamicTexture#setSize中,即创建后的尺寸调整同样遵循此规则。
// 默认行为:奇数会被取整为偶数 this.textures.addDynamicTexture('player', 64, 64); // 需要奇数尺寸时显式关闭 this.textures.addDynamicTexture('tile', 17, 17, false);修复详解:七项缺陷修正背后的机制
1. 修复被过滤对象的父级变换(如容器内的遮罩)
RC2 修复了带过滤(Filter)的对象在继承父级(如 Container)变换时矩阵应用错误的问题。相关代码路径在 src/renderer/webgl/renderNodes/Camera.js:当相机聚焦于被过滤对象时,会接收parentTransformMatrix并与相机的matrixExternal相乘,再判断是否为恒等矩阵以决定是否分解应用。遮罩(Mask)与过滤器组合使用的场景(FilterList#addMask,见下文修复 4)正是这一矩阵传递链条的受益者。
2. 修复相机抖动(Camera Shake)
修复了相机shake效果在 RC2 前可能出现的偏移或异常表现。相机变换相关的核心实现在 src/renderer/webgl/renderNodes/Camera.js 与 src/cameras/2d 目录下,RC2 确保抖动矩阵在过滤/父级变换存在时仍能正确叠加。
3. 为Camera#filters与GameObject#filters补充 typedef
filters属性采用{ internal, external }双结构:internal对应渲染到内部缓冲的过滤器,external对应渲染到外部缓冲的过滤器。RC2 为该结构补齐了 JSDoc typedef,便于 TypeScript 用户与 IDE 获得完整类型提示。过滤器的运行主体位于 src/filters 目录(FilterList、Controller及各滤镜实现)。
4. 修复FilterList#addMask文档
FilterList位于 src/filters/Controller.js 及其关联文件中,其addMask方法用于将遮罩作为过滤器链的一环接入。RC2 修正了该方法文档中参数与返回值的描述错误,属于 API 文档质量修复。
5. Layer 与 Container 的displayList传递修正
在 Layer 和 Container 对象中,传入RenderWebGLSteps的displayList现在使用该对象自身的子项列表,而非错误引用的其他列表。这保证了嵌套层级对象的渲染步骤遍历顺序正确,与 src/renderer/webgl/renderNodes/ListCompositor.js 中"作为嵌套显示层级一部分渲染时向下传递累积变换矩阵"的设计相呼应。
6. 修复DynamicTexture#draw中 Group 成员与偏移对象的定位
RC2 修复了将 Group 成员或带有偏移(offset)属性的对象绘制到 DynamicTexture 时的定位错误。相关实现位于 src/textures/DynamicTexture.js 的绘制命令系统:绘制时会根据对象的父容器计算变换矩阵(见startCapture中通过parentContainer.getWorldTransformMatrix()计算父级变换的逻辑,DynamicTexture.js),并在绘制命令中缓存与恢复被覆盖的属性。修复后,Group 内成员的世界坐标偏移能够被正确还原到纹理上。
7. 修复 Shadow 滤镜方向
Shadow 滤镜(src/filters/Shadow.js)的光源方向在 RC2 中得到修正。底层渲染节点 src/renderer/webgl/renderNodes/filters/FilterShadow.js 中,光源位置在传入 GPU 时执行了 Y 轴反转以匹配 WebGL 纹理坐标约定:
programManager.setUniform('lightPosition', [ controller.x, 1 - controller.y ]); programManager.setUniform('decay', controller.decay); programManager.setUniform('power', controller.power / samples); programManager.setUniform('color', controller.glcolor); programManager.setUniform('samples', samples); programManager.setUniform('intensity', controller.intensity);RC2 修复前,光源方向与预期存在偏差;修复后阴影投射方向与控制器设定的x、y光源位置严格一致。
升级到 RC2 的实践建议
- Shader 制服管理:将固定值制服从
setupUniforms()迁入initialUniforms,将一次性动态更新改用setUniform调用,减少每帧冗余写入,保持setupUniforms()只负责真正随时间变化的制服(如时间戳、交互参数)。 - 动态纹理尺寸:除非确有奇数尺寸需求,否则保留
forceEven默认值true,以获得更好的渲染质量;需要奇数尺寸时显式传false,同时注意DynamicTexture#setSize同样受该参数约束。 - 自定义渲染节点:若基于 RenderNode 架构开发自定义渲染器(如新的批处理节点或提交器),可利用
renderNodes配置在启动期注册,避免运行时手动addNodeConstructor。 - 回归验证:升级后重点回归测试三类场景——容器内遮罩与滤镜组合、相机 shake 效果、Group 成员绘制到 DynamicTexture 的定位,它们是 RC2 修复集中的高危区域。
延伸阅读
- RC2 完整变更清单:changelog/v4/4.0-rc/CHANGELOG-v4.0-rc.2.md
- Shader 游戏对象源码:src/gameobjects/shader/Shader.js
- ShaderQuad 渲染节点:src/renderer/webgl/renderNodes/ShaderQuad.js
- 渲染节点管理器:src/renderer/webgl/renderNodes/RenderNodeManager.js
- 动态纹理实现:src/textures/DynamicTexture.js 与 src/textures/TextureManager.js
- 滤镜渲染节点目录:src/renderer/webgl/renderNodes/filters
- 其余 4.0 RC 阶段变更记录:changelog/v4/4.0-rc
【免费下载链接】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),仅供参考