CocosCreator受击闪白效果 可合批 | 社区征文

效果预览

前期准备

ccc的shader语法是yaml格式的,如果这方面不熟悉的同学可以去如下链接学习一下

YAML 101 · Cocos Creator

精灵的渲染

首先我们熟悉一下默认精灵的shader代码,笔者用ccc版本是2.4.5,其默认精灵的shader代码如下:

// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.  
 
CCEffect %{
  techniques:
  - passes:
    - vert: vs
      frag: fs
      blendState:
        targets:
        - blend: true
      rasterizerState:
        cullMode: none
      properties:
        texture: { value: white }
        alphaThreshold: { value: 0.5 }
}%
 
 
CCProgram vs %{
  precision highp float;
 
  #include <cc-global>
  #include <cc-local>
 
  in vec3 a_position;
  in vec4 a_color;
  out vec4 v_color;
 
  #if USE_TEXTURE
  in vec2 a_uv0;
  out vec2 v_uv0;
  #endif
 
  void main () {
    vec4 pos = vec4(a_position, 1);
 
    #if CC_USE_MODEL
    pos = cc_matViewProj * cc_matWorld * pos;
    #else
    pos = cc_matViewProj * pos;
    #endif
 
    #if USE_TEXTURE
    v_uv0 = a_uv0;
    #endif
 
    v_color = a_color;
 
    gl_Position = pos;
  }
}%
 
 
CCProgram fs %{
  precision highp float;
  
  #include <alpha-test>
  #include <texture>
 
  in vec4 v_color;
 
  #if USE_TEXTURE
  in vec2 v_uv0;
  uniform sampler2D texture;
  #endif
 
  void main () {
    vec4 o = vec4(1, 1, 1, 1);
 
    #if USE_TEXTURE
      CCTexture(texture, v_uv0, o);
    #endif
 
    o *= v_color;
 
    ALPHA_TEST(o);
 
    gl_FragColor = o;
  }
}%

核心思路

闪白的思路是,在properties里声明一个addColor的字段

然后用颜色混合公式:

color.rgb = color.rgb * (1 - addColor.a) + addColor.rgb * addColor.a;

需要注意的是,cocos的uniform需要包一下,笔者就被耽搁了一阵,后来查文档才知道。

  uniform Constant {
    vec4 addColor;
  };

然后在代码里

// 稍微带原本颜色的混合
spr.getMaterial(0).setProperty("addColor", cc.color(255,255,255,150));
// 纯白
spr.getMaterial(0).setProperty("addColor", cc.color(255,255,255,255));

运行结果

看着是实现功能了

But!!不能合批,如果节点数很多,那项目就炸了!

思考一下

因为修改了uniform的属性,会导致不能合批,这个在官方教程里有讲,虽然有一些技术是可以实现(后面了解到了,有兴趣的同学可以自行去学习),那有没有比较简单的方法可以在不改变合批的情况下去做闪白效果呢?

其他方案

在上述贴出来的精灵的渲染中有行代码

o *= v_color;

这个v_color就是顶点色,是Node里去设置的,如果我们能改它的值去替代我们的addColor是不是就可以了呢?

o.rgb = o.rgb * (1.0 - v_color.a) + v_color.rgb * v_color.a;

这样可以用顶点色的alpha去控制颜色从贴图色过渡到目标色了。
这样的 o 我只处理的rgb,并没有处理a,因为o.a = v_color.a的话,颜色过度到目标色的同时又会对透明度产生影响,只能讲a牺牲透明属性了。

这样做之后修改节点的颜色可以设置变色的颜色,修改透明度从1到255可以设置源贴图到纯色过渡,受击变白变红都可以自行调解,代价就是透明通道不再生效。

最终代码

最后附上修改后的完整代码

// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.  
 
CCEffect %{
  techniques:
  - passes:
    - vert: vs
      frag: fs
      blendState:
        targets:
        - blend: true
      rasterizerState:
        cullMode: none
      properties:
        texture: { value: white }
        alphaThreshold: { value: 0.5 }
}%
 
 
CCProgram vs %{
  precision highp float;
 
  #include <cc-global>
  #include <cc-local>
 
  in vec3 a_position;
  in vec4 a_color;
  out vec4 v_color;
 
  #if USE_TEXTURE
  in vec2 a_uv0;
  out vec2 v_uv0;
  #endif


 
  void main () {
    vec4 pos = vec4(a_position, 1);
 
    #if CC_USE_MODEL
    pos = cc_matViewProj * cc_matWorld * pos;
    #else
    pos = cc_matViewProj * pos;
    #endif
 
    #if USE_TEXTURE
    v_uv0 = a_uv0;
    #endif
 
    v_color = a_color;
 
    gl_Position = pos;
  }
}%
 
 
CCProgram fs %{
  precision highp float;
  
  #include <alpha-test>
  #include <texture>
 
  in vec4 v_color;
 
  #if USE_TEXTURE
  in vec2 v_uv0;
  uniform sampler2D texture;
  #endif
 
  void main () {
    vec4 o = vec4(1, 1, 1, 1);
 
    #if USE_TEXTURE
      CCTexture(texture, v_uv0, o);
    #endif

    o.rgb = o.rgb * (1.0 - v_color.a) + v_color.rgb * v_color.a;
 
    ALPHA_TEST(o);

    gl_FragColor = o;
  }
}%

最后的话

感觉自己写了挺多渲染效果,但又感觉自己啥都不会,所以想开始写作记录自己项目中实现的一些效果,写的过程中自己也能更清晰回顾一遍。

最后还得感谢一下麒麟子大佬!传授了一些自身的写作经验,可以让我更快捷得投入到写作本身。

有兴趣的同学可以关注一下我的公众号。

image

感谢各位的观看,希望在渲染的道路上与君共勉,相互成长!

3赞

楼主,mix就是混合函数,有空可以多看看glsl内置函数

好的,谢谢

受击 还原? 切换材质球吗