ShaderGallery Plugin Integration / 插件集成
About / 关于
ShaderGallery 是从 ShaderEditor 独立出来的插件:
其最主要的特点是:
- 功能简化,和
ShaderEditor相比,能够让任何使用这都轻松上手使用 - 所见即所得,为自己的游戏,快速的浏览,挑选,使用
Shader特效
ShaderGallery 旨在帮助对 Shader 并没有很深入认识的朋友,在使用 Creator 进行游戏制作时,可以像 购物 一样,自由 挑选,试用特效,最终找到最适合自己游戏的特效。
Tips / 提示
下文中所有的内容,基于
Creator v3.1.1,注意不同版本,可能会有些许差异。这篇文章,其实只是为了提及个问题,不过我想写的丰富一点,应该更能引擎官方发主要,好得到解答
Shortcomings / 缺点
虽然上面的简介,让人觉得插件功能十分强大,但是实际上,现在插件还是有一些明显的不足之处。
-
插件的
网页版,独立于Creator编辑器,对于ShaderEditor,独立于Creator进行Shader的制作和编辑,还是很有用的,但是ShaderGallery更主要的还是要结合Creator编辑器使用,用户对于网页版的需求相对较低 -
除了
网页版,ShaderGallery也有插件版,但是目前为止 (v1.3.0) ,插件版和Creator的交互度很低,低到插件版仅仅只是一个Launcher / 启动器而已 -
ShaderGallery在让用户挑选特的时,提供了一些内置的静态图片和骨骼动画用于预览特效,同时也支持让用户载入自己的美术资源,进行特效的预览,但是部分用户提出:单独的美术资源预览,脱离游戏场景,无法整体的感知特效配合美术资源,在最终游戏中能够达到的效果
Deep Integration / 深度集成
上面的缺点,想要一一解决,一个最基础的,最重要的点,就是:
大幅提高
ShaderGallery插件版和Creator编辑器的集成度
Core / 核心
ShaderGallery 使用的开发技术不同于商店中的其他插件,更确切的说,使用的不是官方所推荐的 主流 做法。
[就问你6不6] cocos2dx 入侵 Creator 插件系统 - 0
[就问你6不6] cocos2dx 入侵 Creator 插件系统 - 1
[就问你6不6] cocos2dx 入侵 Creator 插件系统 - 2
[就问你6不6] cocos2dx 入侵 Creator 插件系统 - 3
[就问你6不6] cocos2dx 入侵 Creator 插件系统 - 4
[就问你6不6] creator 入侵 Creator 插件系统 - 5
[很快啊-就问你6不6] cocos2d-x 入侵 Creator 插件系统 - 6
虽然,这种做法,在自己看来有以下的几个优点:
- 只要会
Creator v1/2,即使不会html / css / vue / node.js / ...也可以开发进行插件,因为插件直接就是用Creator制作而成 - 开发出的插件,除了可以作为插件在
Creator中运行(这是理所当然的), 还可以脱离引擎,直接运行在网页,甚至作为原生的App运行 (当然这需要一点点适配,但是真的只是一点点,不是亿点点) - 对
Creator 插件系统所用到的一些技术没有直接的依赖,如vue 或是 electron之类,几乎不会因为Creator引擎升级之类的,出现奇怪的问题,换句话说,就是对Creator各版本的兼容性比较友好
其实这种做法的核心原理,就一句话:
把
Creator制作发布的web项目,作为插件,嵌入到插件系统的面板中。就好比,你的 Creator 编辑器里,有个插件,插件肚子里,又怀了个 Creator 项目。
当然,实际要做到这样的效果,还是要有不少骚操作的,特别是要在不改一行引擎代码的前提下,实现这个效果。
这种做法,有优点,缺点自然也是有的,其中最重要的一点就是:
因为做法的 非主流,在插件模式下,和 Creator 编辑器的集成还是有水土不服的情况,并且很难解决。
Dock vs Float / 停靠 vs 浮动
目前 ShaderGallery 和 ShaderEditor 一样,在插件模式下,仅仅支持 Float 模式,就是只能够 以独立的窗口模式运行,在 dock / 停靠 模式下,无法正常的加载运行(如果显示器够大,甚至有双屏的话,float 也没啥问题,但如果是笔记本的话,就显得空间不够用了 )。
造成这个问题的原因,就是上面提到过的,插件的实现方式,并不是那种主流的方式。
之前也咨询过官方人员,得到的回复,也是:
插件在
float模式下,和编辑器场景处于不同进程,不会有什么问题,但是dock模式下,插件会与场景编辑器的环境发生冲突,因此 不建议在场景进程中去使用场景,这样会出现未知情况,破坏场景编辑器的环境
在实际的尝试后,也确实如此,插件无法正常加载使用,虽然总觉得还差那么一点就可以实现,但是就是没有办法确实的去解决这个问题,很可惜。
碰巧最近开始在 Creator v3.x 中尝试插件的集成优化,突然想到,之前的问题是在 v2.x 版本中提出的,v3.x 的插件系统设计和实现都有别于 v3.x ,那么会不会这个问题在 v3.x 中能够解决呢。
于是简单的进行了尝试,虽然还是失败,无法加载,但这一次却出现了不同于之前的,比较可以解决的报错,在一番折腾之后,终于第一次,在 dock 模式下,看到了加载后的插件,并且也可以和 网页版 和 插件的 float 模式 一样,正常的使用。
Mode Switch / 模式切换
貌似 dock 的问题,被比较好的解决了,但是在后续实际的测试时,还是发现了一些问题。
Startup Dock / 启动即停靠
Float to Dock / 浮动切停靠

Dock to Float / 停靠切浮动
以上三种用例,在测试的时候,都没有发现特别的问题。
Dock to Dock / 停靠切停靠
这种情况下,出现了和之前 v2.x 比较类似的报错,后来进一步测试发现,以上三种情况,第一次切换是正常的,但是如果再接着进行切换,同样也会出现报错 – 也就是说,第一次的加载插件是没问题的,但是再次切换模式的时候,就会出错。
在经过一些调查,怀疑是在切换模式的时候,内嵌插件包含的引擎代码重复加载出现的错误,于是想要通过控制这个部分来尝试解决,但是在查看了文档和论坛后,没有找到关于这一块的说明,因此这里想要请教下:
Question.01
v3.x中,插件在float/dock模式之间,相互进行切换,有什么全局消息之类的通知,或是在插件被加载的时候,可以判断的方式吗?
Resize / 缩放
在停靠模式下,有时用户会需要调节插件部分窗体的大小,不同于 float / 模式 下,插件时一个独立的 Panel,窗体大小发生变化的时候,内部插件,也会像游戏适配一样,自动的进行适配缩放,dock / 停靠 模式下,父容器的缩放,并没有带动内部的插件进行缩放。
不过这一点,在扒源码后,使用了插件系统提供的 resize 函数,自己进行手动触发缩放,得到了解决:
exports.listeners = {
resize() {
// ......
cc.view._resize();
}
};
原以为到这里就解决了缩放的问题,但是在使用中,又意外的发现,在 dock / 停靠 模式下,当插件处于非激活状态,比如切换到了 Console 面板,查看日志的时候,调整窗体大小,会出现报错的情况。
好在,这也能够通过插件系统提供的消息函数来解决:
exports.listeners = {
hide() {
},
show() {
}
};
就像前面提到的一样,出现这些问题的原因,是插件的实现选择了非主流的做法,如果是正统的,按照官方的规范开发的插件,自然是不会有这样的问题的,正所谓有得必有失。
Interaction / 交互
在一定程度上解决了 dock 问题后,插件开始真正的有了插件的样子,但是这还远远不够,接下来需要做的,就是 插件 和 Creator 编辑器 的深入交互了。
Plugin System / 插件系统
在开始交互前,需要明确一下插件系统的一些概念:
对于 ShaderGallery 是这个样子的:
Creator Editor // Creator 编辑器
┣━ Scene // Creator 中的 场景编辑器
┣━ Assets // Creator 中的 资源试图部分
┣━ Hierarchy // Creator 中的 节点数部分
┣━ ...... // Creator 编辑器中的各个面板部分
┣━ Gallery // 用户自定移动插件主体
┣━ main // 自定义插件,入口程序,运行在 主进程,被 Creator 加载,并调用其 load 函数
┣━ panel // 自定义插件,面板,可以有多个,运行在 渲染进程,主要用于显示插件
┣━ SSRGallery // Gallery 插件,Creator 发布的 `web` 项目,被加载到 panel 中显示
看完上面的图,接着要实现的一些,所谓的交互,其实也就是 从某一个起点向某一个目标发送消息,随便举两个例子:
- 选中场景编辑器中的任意节点,在插件中,输出被选节点的信息
- 插件中点击某个按钮,在 资源管理器 中新建一个文件
对于 ShaderGallery 而言,这两个需求其实就是:
Scene >>> SSRGallerySSRGallery >>> Assets
当然,实际的实现,可能就没那么容易了。
不过在实际学习实践后发现,v3.x 中的插件系统比 v2.x 还是成熟,先进了许多。
最基础的,也是最核心的一点,那就是 Message / 消息,万物皆用消息来通信,串联。
Creator to Plugin
首先是从 Creator 一端到 插件 的交互。
这样的需求,通常是需要在 Creator 中进行某个操作 时候触发的,就像上面例子里的,场景中选择了某个节点对象。
就如文档中写的,这类消息通常属于 broadcast / 广播消息,只要接收这样的广播就行了,比如一个 选择了某个节点 的广播。
那么问题就变成了,这个广播到底是什么呢。
Message DevTools / 消息调试
v2.x 中,比较痛苦的,就是去 猜 (打印) 这样的消息,或者就是靠前人的总结:
但这一次,v3.x 中提供了强大的 Message DevTools 工具,想知道是什么消息,再也不用去猜,实际操作一遍,看一眼就行了。
可以看到,实际操作以后,触发的一些消息都会被显示出来,这里可以明显的看到,广播的消息是 selection:select 。
知道了消息,按照文档操作,就可以顺利的拿到消息通知了:
// package.json
{
"contributions": {
"messages": {
"selection:select": {
"methods": [
"selectionSelect"
]
}
}
}
}
// main.ts
exports.methods = {
selectionSelect(node, uuid) {
console.log("selectionSelect called");
console.log(node);
console.log(uuid);
// output: node f31kvgxshJmIxJnCUl4kD0
}
};
Tips / 提示
消息的接收,可以在
主进程 / main进行,也可以在某个渲染进程 / panel中进行,只要根据自己的插件业务逻辑需要,具体可以参考文档:
Data Send/ 数据发送
当我们得到想要广播消息事件回调后,还远远不够,回顾上面的图片,此时我们还停留在 main / 主进程 的位置。
我们要做的,是把 发生了么,涉及哪些数据 这样的信息,传递到我们的插件中。
在 v3.x 插件系统,主动发送某条消息到某个功能(扩展),需要使用 Send / 发送 接口:
// package.json
{
"contributions": {
"messages": {
"sceneNodeSelect": {
"methods": [
"default.sceneNodeSelect"
]
}
}
}
}
// main.ts
Editor.Message.send('ssr-shaderfx-gallery', 'sceneNodeSelect', uuid);
// ssr-shaderfx-gallery/panels/index.ts
exports.methods = {
sceneNodeSelect(uuid) {
console.log("sceneNodeSelect called");
console.log(uuid);
}
};
像这样,我们就可以将数据在不同进程之间相互传递了。
Scene Script / 场景脚本
虽然自己的插件并没有使用,但是在研究的过程中也尝试了一下。
场景脚本在 v2.x 中开始就一直存在:
最大的亮点就是:
简单来说,在这里,你就拥有了 cc 的环境,就可以像平时写代码一样地对节点进行操作,而不需要引用编辑器那一套 API。
比如说可以:
// v2.x 语法例子
node.removeFromParent(true); // 从场景中移除
node.addComponent(cc.Label); // 给节点加一个组件
还是非常方便的。
你要做的,只是在 Creator 编辑器发生某些你感兴趣的变化时,监听事件,并将数据传递到这个场景脚本中,即可。
传递的方式,也很简单:
Editor.Message.request('scene', 'execute-scene-script', {
name: string; // 要调用的场景脚本所处包名
method: string; // 要调用的场景脚本中的函数名
args: any[]; // 要调用的场景脚本时传递的参数
});
Tips / 提示
但是这里有一个点,要注意,最好不要在场景脚本中,将原生对象,比如一个
cc.Node对象,再次传输给其他的,比如panels / 渲染进程。
实际尝试后,编辑器也确实就卡死了,无法继续使用,只能强制重启。
Data Request / 数据请求
到这里,我们其实可以看到,数据传输的时候,插件系统并不推荐(或者说是禁止)用传输原生对象这种方式,而实际上,也是如此,传输的大多是比较简单的 json 对象,其中见得最多的,就是 uuid。
因为有了 uuid 我们就可以按需,去请求我们想要的对象的信息,方法也是很简单,对应前面的 send / 发送 接口,这里用的是 request / 请求 接口。
// ts 例子
const info = await Editor.Message.request('scene', 'query-node', uuid);
// js 例子
Editor.Message.request("scene", 'query-node', uuid).then(info => {}).catch(err => {});
请求获取到的结果,基本都是 json ,至于具体内容,就要通过打印或者断点调试来查看了。
这里再举个 ShaderGallery 的实际例子
在插件中,使用插件界面中控件
适时调整 Shader特效的同时,需要让场景编辑器中被选中,并且启用同步特效的节点,同样可以实时刷新预览。
这里还是老样子,先通过消息调试工具,来看一下修改 effect 中的参数时,大致发生了什么事:
可以看到,这里主要牵涉到了两个接口 preview-material 以及 material-inspector:change-dump。
接着就是只要依葫芦画瓢,照着样子,发送对应的消息请求就可以了。
实际操作后,基本没啥问题,但是期间碰到了一些小问题,这里也提出一下:
Question.02
视频中可以看到,在
Message DevTools中,当参数过程时,在界面中显示时,没有提供垂直滚动功能,导致无法预览所有数据细节。这个是不是有问题?
Question.03
一次数值属性的修改,如
TilingOffset的x属性,从1改为2。在
Message DevTools中,可以看到如下的消息序列:
renderer request preview-material
renderer request preview-material
renderer broadcast material-inspector:change-dump这里的,
preview-material,有在material-inspector:change-dump出现前,会有3次,甚至4次,且这n次发送的数据参数,完全一样。就实际通过代码控制属性的修改来看,
1次preview-material+material-inspector:change-dump就可以实现效果。是不是这里插件系统的实现有些问题?
Question.04
通过
preview-material+material-inspector:change-dump组合,可以实现修改属性 (场景编辑器中可以看到效果),但是属性面板的对应属性数值,却不会改变 (这个其实可以理解)。当最后调用
save-asset以后,属性面板的对应属性数值会刷新改变。这里主要想问下,有没有什么方法,能够通过消息,控制到这个属性面板里的对应值,也可以实时变化 (就像手动在改变属性值一样) ?
Question.05
ShaderGallery不光支持对3d对象的实时Shader特效预览,还做了对各种2d对象的支持。
在实现过程中,发现一个问题,Spine 动画对象,在通过代码方式 (或是直接拖放材质更新的方式),material + effect后,会出现奇怪的问题
- 代码确实生效,运行后可以看到,材质已经更换成功
- 在 Creator 场景编辑中,拖放材质后,
Spine节点内容会消失不可见- 这时候,随便点个比如
Debug Slot或是Debug MeshSpine动画就会恢复正常可见,并且可以看到更新的材质也已经确实生效了- 然后,这时候如果调节一下材质的某个
Uniform属性,场景编辑器中动画又会不可见,这时候再一次刷一下Debug Slot之类的,就又会恢复正常- 顺便一提,
Dragon 龙骨动画,更换材质或是调节参数后,场景编辑器中不会消失不可见,但是材质效果却看不到,只有实际运行才能看到- 重启 Creator 编辑器后,
SpineDragon都可以在 场景编辑器 中看到带有材质的效果,但是同样的,只要再重新变换材质,或是调节参数,前者立刻原地消失,后者就是保持没有效果
想要问下,这个是不是编辑器的问题 ?
Conclusion / 总结
得益于 v3.x 的插件系统设计,现在的插件来发比起 v2.x` 其实要方便许多,其实只要摸到了门道以后,什么都能做出来,只要:
- 确定一下想要什么功能
- 自己在
Cretor里操作一下 - 记得打开
Message DevTools看一下Creator怎么做的 - 自己也照着发消息做一下,再加入自己需要的业务逻辑
- 基本你就有了你想要的小功能
- 同类的小功能汇集一下,简单的插件就出来了
ShaderEditor 和 ShaderGallery 都会继续更新,接下来的版本都会朝着 和 Creaotr 编辑器的重度集成 方向进行。
因为一些比较麻烦的问题得到了一定程度的解决,接下来,应该能够做到,在 ShaderEditor 和 ShaderGallery 中的操作,实时的反馈到 Creator 编辑器 中,做到更加强大的支持 WYSIWYG / 所见即所得 的插件,让用户更加方便的使用。
Creator v3.x 中 2D 对象是会预览,编辑(开发中)
https://www.bilibili.com/video/BV1H44y187Ro/
Creator v3.x 中 3D 对象是会预览,编辑(开发中)
https://www.bilibili.com/video/BV1RM4y137nZ/












