Cocos Creator Shader入门实战(七):RGB不同算法效果的实现,及渲染技术、宏定义、属性参数的延伸配置
引擎:3.8.5
您好,我是鹤九日!
回顾
上篇文章,讲解了Cocos Shader如何通过setProperty
动态设置材质的属性,以及设置属性时候的一些注意事项,比如:
一、CCEffect
部分properties参数的设定后,需要在片段着色器部分以结构体声明下
二、材质的获取,主要有两种方式:
-
通过
customMateiral
获取资源的材质实例 -
通过
getSharedMaterial
获取资源的共享材质
更多详情,可参考:
Cocos Creator Shader入门实战(六):使用setProperty动态设置材质属性,以及材质常用接口
资料
文章讲解到此处,相信您对Cocos Shader入门有了一定程度的了解。
因个人能力水平有限,所编写的内容可能有失偏颇,对您的学习造成不必要的困扰,这里请谅解。
Shader是门不好学的技术,牵扯的东西实在是太多了。
这里提供一些不错的学习资料或工具,希望对成长中的您有所帮助:
The Book of shaders 片段着色器的入门指南
Learn OpenGL 中文版 讲解Open GL的学习使用
CocosCreatorShader 木限东的Shader效果实现实例,这里感谢作者的公开分享。
慎入!史上最强 Cocos Shader 学习资源推荐(建议收藏) Cocos官方推荐的学习资源
Shadertoy教程 Shader在线工具的教程
Shadertoy Tool Shadertoy 在线工具模拟
注:其他的优秀资料有很多,这里就不在一一罗列了;这里再次表示感谢!
前言
抛开Open GL、Cocos引擎约定俗成的规则,将Shader的使用简单理解,其实就三步:
一、构建EffectAsset资源,设定渲染参数、着色器代码片段
二、构建Material材质资源,对EffectAsset进行数据封装,构建渲染的资源实例
三、通过引擎提供的接口setProperty
,动态传递参数
这些,就是Cocos Shader 实现的基础流程。
我相信:您对Shader的理论有所了解的,理是这个理儿,但真正的用起来则是另一码事。
今天的内容,我们将RGB灰度渲染的效果进行拓展,通过不同的RGB公式实现更多的效果。
希望本篇文章能够给您带来帮助。
灰度渲染
RGB灰度渲染,算是Shader中实现的基础渲染效果了。
之前文章中提及过: Sprite组件的Grayscale的实现就是灰度渲染。
依然以builtin-sprite.effect为例:
注:后续的文章不再粘贴CCEffect和CCProgram的参数配置和代码了,只罗列关键部分
// builtin-sprite.effect 片段着色器部分
// 方式1: 加权平均值
float gray = 0.2126 * o.r + 0.7152 * o.g + 0.0722 * o.b;
o.r = o.g = o.b = gray;
除了官方提供的以外,另外有两种方式:
vec4 frag () {vec4 o = vec4(1, 1, 1, 1);o *= CCSampleWithAlphaSeparated(cc_spriteTexture, v_uv0);// 方式1: 取三种颜色的平均值// float gray = (o.r + o.g + o.b)/3.0;// o = vec4(gray, gray, gray, o.a);// 方式2: 取三种颜色的最大值(最小值)// float gray = max(max(o.r, o.g), o.b);// o = vec4(gray, gray, gray, o.a);// 方式3: 加权平均值float gray = 0.2126 * o.r + 0.7152 * o.g + 0.0722 * o.b;o.r = o.g = o.b = gray;return o;}
注: 可自行实现下效果,这里不再贴图展示了。
其他RGB渲染
通过不同的RGB计算公式,除了灰度渲染以外,可以实现很多的效果。先上示意图:
每个Sprite组件对应一个材质实例,一个Effect资源配置。资源的渲染参数配置、顶点着色器都是相同的。
随意罗列一个效果代码的实现:
// 暖色调增强
CCProgram sprite-fs %{// ...vec4 frag () {vec4 o = vec4(1, 1, 1, 1);o *= CCSampleWithAlphaSeparated(cc_spriteTexture, v_uv0);// 暖色调增强o.r = o.r * 1.2;o.g = o.g * 1.1;o.b = o.b * 0.8;o = clamp(o, 0.0, 1.0);return o;}
}%
其他代码的核心逻辑如下:
冷色调增强
o.r = o.r * 0.8;
o.g = o.g * 0.9;
o.b = o.b * 1.2;
o = clamp(o, 0.0, 1.0);
老照片
float _r = o.r * 0.393 + o.g * 0.769 + o.b * 0.189;
float _g = o.r * 0.349 + o.g * 0.686 + o.b * 0.168;
float _b = o.r * 0.272 + o.g * 0.534 + o.b * 0.131;
o = vec4(_r, _g, _b, o.a);
卡通效果
float r = abs(o.g - o.b + o.g + o.r) * o.r;
float g = abs(o.b - o.g + o.b + o.r) * o.r;
float b = abs(o.b - o.g + o.b + o.r) * o.g;
o = vec4(r, g, b, o.a);
冰冻效果
float r = abs(o.r - o.g - o.b) * 1.5;
float g = abs(o.g - o.b - o.r) * 1.5;
float b = abs(o.b - o.r - o.g) * 1.5;
o = vec4(r, g, b, o.a);
赛博朋克
float neon = max(o.r, o.g);
o.r = neon * 1.2;
o.g = neon * 1.5;
o.b = o.b * 0.5;
o.a *= 1.1;
o = clamp(o, 0.0, 1.0);
复古胶片
float _r = o.r * 0.9 + o.g * 0.1;
float _g = o.r * 0.1 + o.g * 0.9 + o.b * 0.1;
float _b = o.b * 0.9 + o.r * 0.1;
o = vec4(_r, _g, _b, o.a);
反相
float _r = 255.0 / 256.0 - o.r;
float _g = 255.0 / 256.0 - o.g;
float _b = 255.0 / 256.0 - o.b;
o = vec4(_r, _g, _b, o.a);
高对比度
float avg = (o.r + o.g + o.b) / 3.0;
o.r = avg < 0.5 ? avg * 0.5 : avg * 1.5;
o.g = avg < 0.5 ? avg * 0.5 : avg * 1.5;
o.b = avg < 0.5 ? avg * 0.5 : avg * 1.5;
o = clamp(o, 0.0, 1.0); // 限制颜色值在0到1之间
如下是编译器的资源配置相关:
注:工程资源相关在文末
延伸
上面的编译器资源截图是有用意的,您可能已经猜到了,答案就是:简化和复用。
这里,针对于RGB不同效果的实现,我们做下延伸,主要有如下几个方面:
一、Chunk封装顶点着色器
二、CCEffect
渲染技术的拓展使用
三、预处理宏定义的使用
四、properties
属性参数的配置
Chunks的封装
Chunks是Cocos引擎提供的封装,简单理解就是include的引用,我们将顶点着色的片段代码提取为Chunk。
然后在CCEffect顶点着色器入口部分,添加入口的引用即可。
简单的示例:
CCEffect %{techniques:- passes:- vert: ../resources/common/sprite-vs:vertfrag: sprite-fs:frag
注:之前的博客提及过,可参考:入门实战(四):预处理宏定义和Chunk 中关于Chunk的说明。
CCEffect渲染技术
Cocos引擎针对于CCEffect
的参数配置,设定了渲染技术Technique。
它的特点是:
一、渲染技术支持设定多个,但实际的运行只有一个。
二、渲染技术中的每个Pass渲染过程,必须带有顶点着色器和片段着色器的入口。
引擎针对于CCEffect参数配置,使用的是YAML,它有一大特性便是支持引用和继承。
因此我们的配置,可以是这样:
- CCEffect部分:
CCEffect %{techniques:# 灰度- name: normalpasses:# 顶点着色器引用通用的Chunk片段- vert: ../resources/common/sprite-vs:vertfrag: normal-fs:frag# 深度、模板测试depthStencilState: &depthStencildepthTest: falsedepthWrite: false# 混合模式blendState: &blendtargets:- blend: trueblendSrc: src_alphablendDst: one_minus_src_alphablendDstAlpha: one_minus_src_alpha# 光栅化状态rasterizerState: &rasterizercullMode: noneproperties: &propertyalphaThreshold: { value: 0.5 }# 老照片- name: brownpasses:- vert: ../resources/common/sprite-vs:vertfrag: brown-fs:frag# 可选参数引用normal部分depthStencilState: *depthStencilblendState: *blendrasterizerState: *rasterizerproperties: *property
注: YAML的引用和继承结构:
引用:
&name
和*name
继承:
&name
和<<: *name
- 顶点片段着色器部分逻辑:
// 老照片
CCProgram brown-fs %{// ...vec4 frag () {vec4 o = vec4(1, 1, 1, 1);o *= CCSampleWithAlphaSeparated(cc_spriteTexture, v_uv0);float _r = o.r * 0.393 + o.g * 0.769 + o.b * 0.189;float _g = o.r * 0.349 + o.g * 0.686 + o.b * 0.168;float _b = o.r * 0.272 + o.g * 0.534 + o.b * 0.131;o = vec4(_r, _g, _b, o.a);return o;}
}%
设定以后,我们便可以通过Material材质属性检查器,选择不同的渲染技术来查看效果了。
注:渲染技术的设定,除非是
iMaterialInfo
初始化,其他不支持运行过程中代码的动态改变。
‘
宏定义
预处理宏定义不仅仅是引擎设定的规则,也是OpenGL的规则之一。
它的主要优点有:
一、不同的预处理开关生成不同组合的代码,实现不同效果
二、避免代码冗余,执行高效
三、属性检查器的宏定义开关,可以更好的控制可视化显示和调试效果。
由于RGB的渲染效果种类有很多,我们这里采用宏定义的范围参数来设定,结构如下:
// 通过range([min, max])设定连续数字的宏定义
#pragma define-meta FACTOR range([-5, 5])
// 通过options([...]) 设定指定数字的宏定义
#pragma define-meta FACTOR options([-3, -2, 5])
这里我们需要在片段着色器部分添加如下逻辑:
注:CCEffect配置采用通用部分即可,无须多个渲染技术了
CCProgram sprite-fs %{// ...#pragma define-mate FILTER_TYPE range([0, 4]);vec4 frag () {vec4 o = vec4(1, 1, 1, 1);o *= CCSampleWithAlphaSeparated(cc_spriteTexture, v_uv0);#if FILTER_TYPE == 1// 老照片效果float _r = o.r * 0.393 + o.g * 0.769 + o.b * 0.189;float _g = o.r * 0.349 + o.g * 0.686 + o.b * 0.168;float _b = o.r * 0.272 + o.g * 0.534 + o.b * 0.131;o = vec4(_r, _g, _b, o.a);#elif FILTER_TYPE == 2 // ...#endifreturn o;}
}%
效果图如下:
properties
属性参数
属性参数的设定,其着色器逻辑部分同宏定义有些类似。这里我们的主要配置如下:
- CCEffect部分,配置定义属性参数:
properties:alphaThreshold: { value: 0.5 }filter_type: {value: 1.0, editor: {tooltip: "RGB类型"}}
- 片段着色器部分,主要逻辑如下:
CCProgram sprite-fs %{// ...// 引擎规定,不允许离散使用Uniform// ARGS为任意命名// 设定以后,引擎会自动将ARGS内的参数与properties的属性相关联uniform ARGS {int filter_type;};vec4 frag () {vec4 o = vec4(1, 1, 1, 1);o *= CCSampleWithAlphaSeparated(cc_spriteTexture, v_uv0);if (filter_type == 1) {// 老照片效果float _r = o.r * 0.393 + o.g * 0.769 + o.b * 0.189;float _g = o.r * 0.349 + o.g * 0.686 + o.b * 0.168;float _b = o.r * 0.272 + o.g * 0.534 + o.b * 0.131;o = vec4(_r, _g, _b, o.a);} else if (filter_type == 2) {// ...}return o;}
}%
- 属性检查器中,我们便可以直接通过不同参数来预览效果了。
总结
延伸部分的例子,可能并不是太恰当,但对于新手而言,了解渲染技术、宏定义以及属性参数是很有益处的。
Demo的示例,可从个人Gitee获取: CocosShaderDemo下的res/rgb
今天的文章,到这里就结束了,这里对于一些热心大佬的网络分享表示感谢!
可能理解有误,欢迎您的指出,如果觉得文章不错,期待您的点赞和留言,感谢!
我是鹤九日,祝您生活愉快!