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 >>> SSRGallery
SSRGallery >>> 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 Mesh
Spine
动画就会恢复正常可见,并且可以看到更新的材质也已经确实生效了- 然后,这时候如果调节一下材质的某个
Uniform
属性,场景编辑器中动画又会不可见,这时候再一次刷一下Debug Slot
之类的,就又会恢复正常- 顺便一提,
Dragon 龙骨动画
,更换材质或是调节参数后,场景编辑器中不会消失不可见,但是材质效果却看不到,只有实际运行才能看到- 重启 Creator 编辑器后,
Spine
Dragon
都可以在 场景编辑器 中看到带有材质的效果,但是同样的,只要再重新变换材质,或是调节参数,前者立刻原地消失,后者就是保持没有效果
想要问下,这个是不是编辑器的问题 ?
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/