lcc-render可调自定义渲染框架!附源码仓库
共 5115字,需浏览 11分钟
·
2020-10-24 01:53
作者:Nomat 来源:Cocos官方论坛
原文:https://forum.cocos.org/t/topic/99268
lcc-render
Cocos Creator 自定义渲染框架,更便捷,更自由的构建渲染效果。
前言
最近在 Cocos 论坛上看到很多人发的 Shader 效果,自己也想使用这些效果。但是发现大家发的 Shader 在 Creator 里面并不是太好使用,大家的 Shader 并没有考虑到 Creator 自己的合图与渲染合批功能,使用限制比较大。于是就有了这个项目。
本人最早是做 cocos2dx 的,接触 creator 没有多久,基本算是直接用吧,可能下面的代码会有更好的实现方式。
安装
安装十分简单,只要把这个项目作为 Creator 插件放到插件目录就可以了,具体请查看 Creator 插件包(https://docs.cocos.com/creator/manual/zh/extension/your-first-extension.html)。
使用
如果你想自己用插件中已经有的效果你可以直接在节点上添加效果组件,如图:
你可以直接添加一个以render.Effect*
开始的效果组件,当然添加完后,一般需要再把渲染的图片拖动到自动添加的 render.ShaderSpriteFrame 组件里面。如图:
好了,渲染效果应该已经出来了,你可以通过修改render.Effect*
组件上的参数改变渲染效果。
当然,如果你想要定制你的渲染,那么就需要看看下面的文档了。其实渲染效果的基本参数都可以在render.Effect*
里面设置,比如这个马赛克效果组件: * 当然上面只是框架上附带的一些懒人包效果,多谢 Cocos 论坛上提供效果的大佬们。* 再看框架设计前,你应该具备一些基本的 shader 知识。
框架设计
框架并不是单个渲染组件,而是把节点作为渲染的容器,各种渲染参数通过组件的方式加入渲染系统中。渲染组件主要分为:
* 渲染系统RenderSystem
这类组件继承了RenderComponent
组件,主要负责渲染组织和刷新流程等操作。具体比如更新材质,属性,形状,顶点等。
* 着色器组件ShaderComponent
着色器组件就是具体的渲染数据或则控制数据,比如 SpriteFrame, Color, Float, Vec2, Vec3, Vec4, Macro 等。这类组件与向着色器传递的数据相关。
1、传递什么数据到 Shader 中?
框架通过着色器组件
组织需要向 Shader 传递的数据。
比如我们需要渲染一张图片那么ShaderSpriteFrame
组件应该是需要加入到渲染系统的,这个组件会负责把图片的数据传递到 Shader 里面,但是如果我们需要做Shader遮罩
那么我们可能需要再添加一个 ShaderSpriteFrame
来把遮罩图片的数据传递进去。
如果再想自定义下颜色,我们再加一个 ShaderColor
组件吧,传递数据的大小是可控的,不需要的数据就不传。
2、如何传递数据到 Shader 中?
一般我们向 Shader 中传递数据的方式有两种:
* uniform 以常量的方式传递,在 Creator 中我们可以通过获取渲染组件的材质直接设置属性的值。优势是简单;缺点是不利于渲染合批。
* attribute 顶点数据的方式传递,在现在的 Creator 中我们不自定义渲染的类是办不到的。优势是可以合批渲染;缺点是现在 Creator 中不好实现,会消耗更多的内存。
但是特别是在需要大量渲染的地方,渲染合批是很重要的。所以框架使用了 自定义数据传递方式
,我们可以在着色器组件中选择每个数据传递的方式。当然有些数据是应该用指定的方式传递的,这类数据不能切换方式。我们可以根据一个效果图对比:
=>这是使用 uniform 方式传递数据的效果
Draw Call
数量少得多。3、如何自定义数据传递方式?
#if USE_TEXTURE
uniform sampler2D texture;
#endif
通过宏定义我们可以动态裁剪 Shader 代码。比如我们在 Shader 的片段着色器写入下面的代码:
#if ATTR_COLOR
in vec4 color;
#elif UNIF_COLOR
uniform UNIF_COLOR {
vec4 color;
};
#else
vec4 color = vec4(1,1,1,1);
#endif
如果我们想使用顶点传递颜色(顶点可以使用不同的颜色),那么我们可以在材质上定义ATTR_COLOR
为true
,UNIF_COLOR
为false
,然后通过顶点传递数据。如果我们想使用常量,可以定义ATTR_COLOR
为false
,UNIF_COLOR
为true
,然后定义常量。当然还有个默认的值,如果我们都定义为false
的话。在使用数据的时候我们也可以通过
if ATTR_COLOR || UNIF_COLOR
// ... ... 这是如果传递了数据到着色器的操作
#endif
那么顶点着色器该怎么传递这些数据呢(这个框架当前基本没有考虑顶点着色器使用数据的情况,好像大部分效果都没有使用到)很简单。
// 定义颜色
#if ATTR_COLOR
in vec4 a_color;
out vec4 color;
#endif
...
void main(){
...
#if ATTR_COLOR
color = a_color; // 就把颜色传递过去了
#endif
...
}
哈哈,看着是不是感觉还是要写很多东西,但是我们有宏,可以简化这些操作。
############## 顶点着色器
// 定义颜色
LCC_VERT_VALUE_DEFINE(COLOR, vec4, color)
...
void main(){
...
LCC_VERT_VALUE_PASS(COLOR, color)
...
}
############## 片段着色器
LCC_FRAG_VALUE_DEFINE(COLOR, vec4, color, vec4(1.0,1.0,1.0,1.0))
...
void main(){
...
gl_FragColor = color; // 这里color就谁便用了
...
}
由于还没有怎么搞清楚插件怎么定义 shader 的 include 文件。所以现在框架都是手动添加的,具体的 defines 文件路径 lcc-render/framework/src/render/build/lcc-defines.inc
4、着色器组件上如何选择传递的方式?
在着色器组件上的变量基本上都定义了 2 种方式,如图: UNIFORM
常量格式
Unif Macro表示这个常量使用的宏,Name是宏名称,Check Only表示这个常量的宏只作为检测使用。
所谓检测使用 表示只有前面定义了这个宏为true的时候,这个常量才启用,传递其值 这个用在多个数据绑定上,比如:
#if USE_TEXTURE
in vec2 a_uv;
out vec2 uv;
#endif
只有在定义了USE_TEXTURE
才会传递a_uv
, 没有纹理,他的 UV 也没有作用。
Unif Name
表示这个常量在 Shader 中的名称。
ATTRIBUTE
顶点数据顶点数据的Attr Macro
与Name
和上面常量意义相同,特别注意的是如果是通过顶点传递数据,可以给每个顶点分配不一样的数据,比如给图片的四个点设置不同的颜色
着色器组件介绍
ShaderSpriteFrame
这个组件和图片相关,如果你的渲染效果需要图片的话需要添加这个组件,需要多少张图片就可以添加多少个。
Apply Shape
是否应用当前图片的尺寸,如果选择,那么渲染的尺寸以下面的设置为准(如果整个渲染系统中没有组件应用形状,则会用节点矩形的形状
)。Shape Type
形状的类型,可以直接使用节点的形状也可以自定义。Trim
和Sprite
组件一致,配合上面的形状可以实现Sprite
中的 Simple 模式。Apply UV
应用这张图片的 UV 到 Shader 中。Custom UV
可以定义 UV 顶点的顺序。Apply UVRect
应用 UV 在合图后的 rect 矩形到 Shader 中,再也不用关闭合图了,但是你可能要计算真实UV与图片UV的关系,宏定义提供了宏函数
。Apply Frame Size
这个可以算是传递图片的像素尺寸到 Shader 中,一些效果比如高斯模糊需要。
ShaderColor
这个组件和颜色有关,如果你的渲染效果需要传递颜色的话,需要添加这个组件。 * Apply Node Color
直接应用节点的颜色。* Color Type
可以定义单色,也可以定义每个顶点颜色。* Vertex Colors
每个顶点的颜色, 顺序是 左下, 右下, 左上, 右上。可以在修改的时候直接看变化。
ShaderFloat/ShaderVec2/ShaderVec3/ShaderVec4
这一些数值的着色器组件只有数据类型不一样,具体用法包含在ShaderColor
里面。
ShaderMacro
这个着色器组件主要是可以自由定义 Shader 中的宏。
Macro Name
定义的宏的名称。Check Macro
如果不为空,则会检测这个宏是否为true
, 如果为true
才会定义这个组件的宏。Value Type
宏的值类型,有Value
数值和Bool
布尔。
注意 Shader 中的宏,定义值的方式。
#pragma define LAYERS range([4, 5])#pragma define METALLIC_SOURCE options([r, g, b, a])
「Effect 语法」1 * Bool
布尔值。* Value
数值。
ShaderEffect*系列具体效果组件
这些组件基本上就是在组装多个着色器组件,并且统一控制他们,没有什么特别。可以看看框架的 ShaderEffect*组件类源码。
这些组件基本上就是在组装多个着色器组件,并且统一控制他们,没有什么特别。可以看看框架的ShaderEffect*组件类源码。当前框架中内置的效果组件:
EffectFlashLight 扫光效果,可以配置扫光速度,角度,数量,间距,宽度等参数。 EffectFluxaySuper 流光效果,可以配置速度。 EffectGaussianBlur 高斯模糊,因为如果太大会有性能问题,所以没有开放配置接口。 EffectGlowInner 内发光效果,可以配置颜色,宽度,阈值和闪烁等。 EffectGlowOutter 外发光效果,和内发光效果差不多。 EffectMosaic 马赛克效果,可以配置程度(0-1)。 EffectOutline 外轮廓线效果,可以配置颜色,宽度,闪烁等。 EffectPhoto 照片效果,可以配置老照片/变灰,程度等。 EffectRoundCornerCrop 圆角裁剪效果,可以配置程度等。 EffectSpriteMask Shader遮罩效果,配置原图和遮罩图等,为了最好的效果,请关闭图片的自动裁剪,并且最好大小一样。
其实,在添加了这些内置效果组件后,你同样可以再添加其他的着色器组件,比如马赛克组件是没有设置颜色的,你完全可以自己在节点上添加一个ShaderColor组件以控制颜色。
源码仓库:https://gitee.com/nomat/lcc-render
感谢社区Nomat大佬的干货分享,如果你也有好的文章,欢迎来公众号与大家交流学习,我们一起成长!