【开源】便捷,自由,可调自定义渲染框架(不定期更新内置效果)

仓库地址:lcc-render

lcc-render

Cocos Creator自定义渲染框架,更便捷,更自由的构建渲染效果。

前言

没怎么写过文档,可能写得不太好,请谅解。

最近在Cocos论坛上看到很多人发的Shader效果,自己也想使用这些效果。但是发现大家发的Shader在Creator里面并不是太好使用,大家的Shader并没有考虑到Creator自己的合图与渲染合批功能,使用限制比较大。于是就有了这个项目。

本人最早是做cocos2dx的,接触creator没有多久,基本算是直接用吧,可能下面的代码会有更好的实现方式。

安装

安装十分简单,只要把这个项目作为Creator插件放到插件目录就可以了,具体请查看Creator插件包

使用

如果你想自己用插件中已经有的效果你可以直接在节点上添加效果组件,如图:


你可以直接添加一个以Effect*开始的效果组件,当然添加完后,一般需要再把渲染的图片拖动到自动添加的lcc.render.ShaderSpriteFrame组件里面。如图:

avatar

好了,渲染效果应该已经出来了,你可以通过修改Effect*组件上的参数改变渲染效果。当然,如果你想要定制你的渲染,那么就需要看看下面的文档了。

其实渲染效果的基本参数都可以在Effect*里面设置,比如这个马赛克效果组件:

avatar

  • 当然上面只是框架上附带的一些懒人包效果,多谢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方式传递数据的效果



=>这是使用attribute方式传递数据的效果



可以看出使用attribute方式Draw Call 数量少得多。

可能有些人看到上面的2张对比图片有问题。FrameTime在attribute方式下还要大一些,主要原因是由于本身时间太小了,cocos统计的波动时间也差不多这个精度。上面只做了10张图片时候的对比,如果把图片对比数量提高到50张,attribute方式的FrameTime差不多还是上面的时间,但是uniform方式的FrameTime会大4倍左右。

3、如何自定义数据传递方式?

得益于Creator的Shader定义可以使用宏,比如:

#if USE_TEXTURE
uniform sampler2D texture;
#endif

通过宏定义我们可以动态裁剪Shader代码。
比如我们在Shader的顶点着色器写入下面的代码:

#if ATTR_COLOR
in vec4 a_color;
out vec4 color;
#elif UNIF_COLOR
uniform UNIF_COLOR {
	vec4 u_color;
};
out vec4 color;
#else
vec4 D_color = vec4(1,1,1,1);
out vec4 color;
#endif

如果我们想使用顶点传递颜色(顶点可以使用不同的颜色),那么我们可以在材质上定义ATTR_COLORtrue, UNIF_COLORfalse,然后通过顶点传递数据。如果我们想使用常量,可以定义ATTR_COLORfalse, UNIF_COLORtrue,然后定义常量。当然还有个默认的值,如果我们都定义为false的话。

在使用数据的时候我们也可以通过

if ATTR_COLOR || UNIF_COLOR
	// ... ... 这是如果传递了数据到着色器的操作
#endif

那么顶点着色器该怎么传递这些数据呢,很简单:

// 定义颜色
// 【上面的代码段】

...

void main(){
	...
#if ATTR_COLOR
	color = a_color;    // 顶点颜色传递过去了
#elif UNIF_COLOR
    color = u_color;    // 常量颜色传递过去了
#else
    color = D_color;    // 默认颜色传递过去了
#endif
	...
    // 这里也可以使用color变量
    ...
}

然后就是片段着色器如何使用了,更简单:

...
in vec4 color;
...

void main(){
    ...
    gl_FragColor = color; // 使用color颜色
    ...
}

哈哈,看着是不是感觉还是要写很多东西,但是我们有宏,可以简化这些操作。

############## 顶点着色器
// 定义颜色
LCC_VERT_VALUE_DEFINE(COLOR, vec4, color, vec4(1.0,1.0,1.0,1.0))

...

void main(){
	...
// 传递颜色
LCC_VERT_VALUE_PASS(COLOR, color)
	...
    // 这里也可以使用 color
}

############## 片段着色器

// 导入颜色
LCC_FRAG_VALUE_IMPORT(vec4, color)

...

void main(){
	...
	gl_FragColor = color; // 这里color就随便用了
	...
}
  • 由于还没有怎么搞清楚插件怎么定义shader的include文件。所以现在框架都是手动添加的,具体的defines文件路径 lcc-render/framework/src/render/build/lcc-defines.inc

4、着色器组件上如何选择传递的方式?

在着色器组件上的变量基本上都定义了2种方式,如图:

  • UNIFORM 常量格式
    avatar

    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 顶点数据
    avatar

    顶点数据的Attr MacroName 和上面常量意义相同, 特别注意的是如果是通过顶点传递数据,可以给每个顶点分配不一样的数据,比如给图片的四个点设置不同的颜色

着色器组件介绍

ShaderSpriteFrame

这个组件和图片相关,如果你的渲染效果需要图片的话需要添加这个组件,需要多少张图片就可以添加多少个。
avatar

  • Apply Shape 是否应用当前图片的尺寸,如果选择,那么渲染的尺寸以下面的设置为准(如果整个渲染系统中没有组件应用形状,则会用节点矩形的形状)。
  • Shape Type 形状的类型,可以直接使用节点的形状也可以自定义。
  • TrimSprite组件一致,配合上面的形状可以实现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中的宏。
avatar

  • 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 语法
  • Bool 布尔值。
  • Value 数值。

ShaderEffect*系列具体效果组件

这些组件基本上就是在组装多个着色器组件,并且统一控制他们,没有什么特别。可以看看框架的ShaderEffect*组件类源码。

当前框架中内置的效果组件:

  • EffectFlashLight 扫光效果,可以配置扫光速度,角度,数量,间距,宽度等参数。
  • EffectFluxaySuper 流光效果,可以配置速度。
  • EffectGaussianBlur 高斯模糊,因为如果太大会有性能问题,所以没有开放配置接口。
  • EffectGlowInner 内发光效果,可以配置颜色,宽度,阈值和闪烁等。
  • EffectGlowOutter 外发光效果,和内发光效果差不多。
  • EffectMosaic 马赛克效果,可以配置程度(0-1)。
  • EffectOutline 外轮廓线效果,可以配置颜色,宽度,闪烁等。
  • EffectPhoto 照片效果,可以配置老照片/变灰/反相/冰冻/卡通,程度等。
  • EffectRoundCornerCrop 圆角裁剪效果,可以配置程度等。
  • EffectSpriteMask Shader遮罩效果,配置原图和遮罩图等,为了最好的效果,请关闭图片的自动裁剪,并且最好大小一样
  • EffectDissolve 溶解效果,配置噪音图,程度等。
  • FffectSmoothTransform 平滑过渡效果,配置过渡宽度,过渡方向,程度等。
  • EffectRainDropRipples 下雨波纹效果,配置波纹的密度,动态改变等。

其实,在添加了这些内置效果组件后,你同样可以再添加其他的着色器组件,比如马赛克组件是没有设置颜色的,你完全可以自己在节点上添加一个ShaderColor组件以控制颜色。

结束语

这个框架基本上把Creator向Shader中传递数据的方式简化了,我们可以把更多精力放在写好Shader上面。框架内现在只内置了部分效果,说实话效果太多了,剩下的基本都是体力活了。我只能在有空的时候再添加了。

63赞

牛逼!!虽然我看不懂!

1赞

看不懂但大概可以给个赞先。

牛逼了大佬,这个必须顶

MARK.

:+1::+1::+1::+1::+1::+1:

大佬牛逼……

插眼学习 学习大佬们

闻讯而来,太强了!

大佬 奥利给!

摩拜大佬:+1: ,「Creator星球游戏开发社区」公众号,请求转发你的文章大作!
我的微信号:z6346289

太强了,学习一波

:+1::+1::+1::+1::+1::+1:

如果把这些改成下拉可选列表,就更完美啦
大佬牛逼~

可以,随便转发

不清楚你说的是什么意思? 这是shader中变量的定义,你是说动态读取里面的变量吗?
好像这种暂时还办不到, 这样是为了可以自己定义shader中的变量名称,比如这个color可能需要多个, a_color, a_color1等

大佬牛逼plus i了i了

six six six

秀,天秀,陈独秀,蒂花之秀,造化钟神秀

感谢大佬分享