CocosCreator追光效果+多相机RenderTexture应用 | 社区征文

效果预览

前面的话

参考了《异名》大佬的追光效果,但是他那个只能应用于一张图,但实际游戏开发肯定不止一张图,所以在他的基础上进行了改进,可以做多图的效果,并且可以定义不处理的分组(UI)。

核心思路

根据效果我们需要实现:

  • 光圈的形状和大小可控
  • 光圈的边缘虚化
  • 光圈可操控移动
  • 渲染相机渲染结果输出RenderTexture
  • 主相机渲染最终结果

实现过程

首先我们放一张跟场景一样大的背景图,假设坐标在中心点,那它的uv坐标就是(0.5, 0.5),我们只需要让圆心到边缘的距离大于指定阈值的像素丢弃(discard)或者透明度为0,是不是就能得到一个圆?

      properties:
        radius: {value: 0.1}
        center: { value: [0.5,0.5]}
        
fs
void main() {
  color.a = step(length(v_uv0 - center), radius);
}

length是取模,step是内置函数:step(a, x) = x >= a? 1 : 0;让alpha非0即1.

上面的代码得出的效果只是一个椭圆,因为uv都是从0到1的,如果应用于正方形的图,那就是一个正圆,但长方形的话,因为横纵比不一样,所以这个图片的横纵比我们可以通过参数传进来:

      wh_ratio: { value: 1}
      blur: { value: 0.1}
      
void main() {
    float circle = radius * radius;
    float rx = center.x * wh_ratio;
    float ry = center.y;
    
    float dis = (v_uv0.x * wh_ratio - rx) * (v_uv0.x * wh_ratio - rx) + (v_uv0.y - ry) * (v_uv0.y - ry);
    o.a = smoothstep(circle, circle - blur, dis);
}
this.renderSpr.getMaterial(0).setProperty("wh_ratio", cc.winSize.width / cc.winSize.height)

shader新增了wh_ratio横纵比、blur虚化区域,smoothstep相对step来说除了非0即1外,额外多了一个从0到1过渡的变化.

ts代码中将背景图的横纵比传进去,因为我地图是铺满全屏的,所以直接用cc.winSize了,这样得到的效果如下:

最后再将光圈可操作移动加进去:其实就是将位置center实时传进去

    toucheEvent(evt: cc.Event.EventTouch) {
        let pos = evt.getLocation();
        this.bg.getMaterial(0).setProperty('center', [pos.x / cc.winSize.width, (cc.winSize.height - pos.y) / cc.winSize.height]);
    }

到这里算是算是把核心逻辑实现了,但是如果你想再挂其他图片进去就会发现其他图片不起作用,这个时候我们就需要用RenderTexture来处理了。

我们新增一张空白图renderSpr,将其尺寸设置成场景一样大,并增加Widget组件使其跟随场景缩放。新增分组render并将renderSpr的分组设置成render,新增RenderCamera,使其只捕获default,而MainCamera只渲染render,底图的材质还原成默认精灵的材质,ts中对底图的操作改成对renderSpr的操作

在ts代码里,我们需要新建一个RenderTexture去获取RenderCamera,并将RenderTexture的纹理实时赋给renderSpr,代码如下

    start () {
        this.texture1 = new cc.RenderTexture();
        this.texture1.initWithSize(cc.winSize.width, cc.winSize.height);
        this.renderCamera.targetTexture = this.texture1;
    }
    
    update (dt) {
        let spriteFrame = new cc.SpriteFrame();
        spriteFrame.setTexture(this.texture1);
        this.renderSpr.spriteFrame = spriteFrame;
    }

不出意外,你能得到这样的一个效果:

图被翻转了,有2种方案解决这个问题:

  • renderSpr的scaleY改成-1
  • 在顶点中v_uv0 = vec2(a_uv0.x, a_uv0.y);改成v_uv0 = vec2(a_uv0.x, 1.0 - a_uv0.y);

随后在toucheEvent中(cc.winSize.height - pos.y)改成pos.y,使触摸归正。

最后增加动态调整范围和过渡区域的滑动条,其代码如下:

    onSliderSize(slider:cc.Slider) {
        this.renderSpr.getMaterial(0).setProperty("radius", slider.progress)
    }

    onSliderBlur(slider:cc.Slider) {
        this.renderSpr.getMaterial(0).setProperty("blur", slider.progress * 0.2)
    }

运行效果:

其中"追光效果"的文本和底下调节的UI一个受圆圈影响,一个不受圆圈影响,思考一下是怎么做的吧。

完整工程

工程仓库链接: git@gitee.com:onion92/cocos2d-shader-effect.git

最后的话

有兴趣的同学可以关注一下我的公众号。你们的支持是我创作的动力!

image

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

5赞

感谢分享!

赞!!!!

3.5.2一样可以用吧?强!!