cocos creator 3.7.2使用shader实现图片扫光特效

简介

功能:图片实现扫光效果

引擎:cocos Creator 3.7.2

开发语言:ts

完整版链接

链接https://lengmo714.top/284d90f4.html

效果图

shader代码

effect 复制代码
// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
CCEffect %{
  techniques:
  - passes:
    - vert: sprite-vs:vert
      frag: sprite-fs:frag
      depthStencilState:
        depthTest: false
        depthWrite: false
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
          blendDstAlpha: one_minus_src_alpha
      rasterizerState:
        cullMode: none
      properties:
        alphaThreshold: { value: 0.5 }

        # 自定义
        lightColor: { value: [1.0, 1.0, 0.0, 1.0], editor: {
          type: color,
          tooltip: "光束颜色" }}
        lightCenterPoint: { value: [0.2, 0.2], editor: { 
          tooltip: "光束中心点坐标" }}
        lightAngle: { value: 36.0, editor: { 
          tooltip: "光束倾斜角度" }}
        lightWidth: { value: 0.2, editor: { 
          tooltip: "光束宽度" }}
        enableGradient: { value: 1.0, editor: { 
          tooltip: "是否启用光束渐变。0:不启用,非0:启用" }}
        cropAlpha: { value: 1.0, editor: { 
          tooltip: "是否裁剪透明区域上的光。0:不启用,非0:启用" }}
        enableFog: { value: 0.0, editor: { 
          tooltip: "是否启用迷雾效果。0:不启用,非0:启用" }}
}%

CCProgram sprite-vs %{
  precision highp float;
  #include <builtin/uniforms/cc-global>
  #if USE_LOCAL
    #include <builtin/uniforms/cc-local>
  #endif

  in vec3 a_position;
  in vec2 a_texCoord;
  in vec4 a_color;

  out vec4 color;
  out vec2 uv0;

  vec4 vert () {
    vec4 pos = vec4(a_position, 1);

    #if USE_PIXEL_ALIGNMENT
      pos = cc_matView * pos;
      pos.xyz = floor(pos.xyz);
      pos = cc_matProj * pos;
    #else
      pos = cc_matViewProj * pos;
    #endif

    uv0 = a_texCoord;
    color = a_color;

    return pos;
  }
}%

CCProgram sprite-fs %{
  precision highp float;
  #include <builtin/internal/embedded-alpha>
  #include <builtin/internal/alpha-test>

  in vec4 color;

  #if USE_TEXTURE
    in vec2 uv0;
    #pragma builtin(local)
    layout(set = 2, binding = 11) uniform sampler2D cc_spriteTexture;
  #endif

  #if ENABLE_LIGHT
    uniform Light {
      // 光束颜色
      vec4 lightColor;

      // 光束中心点坐标
      vec2 lightCenterPoint;
      
      // 光束倾斜角度
      float lightAngle;

      // 光束宽度
      float lightWidth;

      // 启用光束渐变
      // ps:编辑器还不支持 bool 类型的样子,因此用float来定义
      float enableGradient;

      // 裁剪掉透明区域上的光
      // ps:编辑器还不支持 bool 类型的样子,因此用float来定义
      float cropAlpha;   

      // 是否启用迷雾效果
      // ps:编辑器还不支持 bool 类型的样子,因此用float来定义
      float enableFog;
    };

    /**
    * 添加光束颜色
    */
    vec4 addLightColor(vec4 textureColor, vec4 lightColor, vec2 lightCenterPoint, float lightAngle, float lightWidth) {
      // 边界值处理,没有宽度就返回原始颜色
      if (lightWidth <= 0.0) {
        return textureColor;
      }

      // 计算当前 uv 到 光束 的距离
      float angleInRadians = radians(lightAngle);

      // 角度0与非0不同处理
      float dis = 0.0;
      if (mod(lightAngle, 180.0) != 0.0) {
        // 计算光束中心线下方与X轴交点的X坐标
        // 1.0 - lightCenterPoint.y 是将转换为OpenGL坐标系,下文的 1.0 - y 类似
        float lightOffsetX = lightCenterPoint.x - ((1.0 - lightCenterPoint.y) / tan(angleInRadians));

        // 以当前点画一条平行于X轴的线,假设此线和光束中心线相交的点为D点
        // 那么 D.y = uv0.y
        // D.x = lightOffsetX + D.y / tan(angle)
        float dx = lightOffsetX + (1.0 - uv0.y) / tan(angleInRadians);

        // D 到当前 uv0 的距离就是
        // dis = |uv0.x - D.x|
        float offsetDis = abs(uv0.x - dx);

        // 当前点到光束中心线的的垂直距离就好算了
        dis = sin(angleInRadians) * offsetDis;
      } else {
        dis = abs(uv0.y - lightCenterPoint.y);
      }
      
      float a = 1.0 ;
      // 裁剪掉透明区域上的点光
      if (bool(cropAlpha)) {
        a *= step(0.01, textureColor.a);
      }

      // 裁剪掉光束范围外的uv(迷雾效果)
      if (!bool(enableFog)) {
        a *= step(dis, lightWidth * 0.5);
      }

      // 加入从中心往外渐变的效果
      if (bool(enableGradient)) {
        a *= 1.0 - dis / (lightWidth * 0.5);
      }

      // 计算出扩散范围内,不同 uv 对应的实际扩散颜色值
      vec4 finalLightColor = lightColor * a;

      // 混合颜色:在原始图像颜色上叠加扩散颜色
      //return textureColor * textureColor.a + finalLightColor;

        #if ENABLE_ORIGINCOLOR
          finalLightColor = textureColor + textureColor * a;
        #else
          finalLightColor = textureColor + finalLightColor;
          finalLightColor.a = textureColor.a;
        #endif

        return finalLightColor;
      }
  #endif
    
  vec4 frag () {
    vec4 o = vec4(1, 1, 1, 1);

    #if USE_TEXTURE
      o *= CCSampleWithAlphaSeparated(cc_spriteTexture, uv0);
    #endif

    o *= color;
    ALPHA_TEST(o);

    #if ENABLE_LIGHT
      o = addLightColor(o, lightColor, lightCenterPoint, lightAngle, lightWidth);
    #endif
    
    return o;
  }
}%

使用方法

  • 手动创建一个材质
  • 将上面shader代码于材质进行绑定
  • 在ts脚本代码中控制扫光的移动

ts代码

ts 复制代码
import { _decorator, CCFloat, Component, Node, Sprite, Material, Vec2 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('NewComponent')
export class NewComponent extends Component {
    @property(Sprite)
    sprite !: Sprite;

    @property({ type: CCFloat, tooltip: "光束宽度" })
    lightWidth = 0.03;
    @property({ type: CCFloat, tooltip: "时间" })
    LoopTime = 1.0;
    @property({ type: CCFloat, tooltip: "TimeInterval" })
    TimeInterval = 2.0;

    /**记录时间 */
    private time: number = 0;
    /**精灵上的材质 */
    private material: Material = null!;
    private startPos = 0;
    private moveLength = 0;
    private Speed = 0;
    private dttime = 0;
    start() {
        this.time = 0;
        this.dttime = 0;
        this.material = this.sprite.getMaterial(0);
        this.startPos = -this.lightWidth / 2;
        this.moveLength = this.lightWidth + 1;
        this.Speed = this.moveLength / this.LoopTime / 2;
        this.time = this.startPos;
    }

    update(dt: number) {
        this.time += dt * this.Speed;
        this.dttime += dt;
        this.material.setProperty("lightCenterPoint", new Vec2(this.time, this.time));          //设置材质对应的属性
        if (this.dttime > this.LoopTime + this.TimeInterval) {
            this.time = this.startPos;
            this.dttime = 0;
        }
    }
}

完整demo

demo下载地址

相关推荐
老华带你飞7 分钟前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计
gopher951124 分钟前
HTML详解
前端·html
Tiny201725 分钟前
前端模块化CommonJs、ESM、AMD总结
前端
吕永强26 分钟前
CSS相关属性和显示模式
前端·css·css3
结衣结衣.31 分钟前
python中的函数介绍
java·c语言·开发语言·前端·笔记·python·学习
全栈技术负责人32 分钟前
前端提升方向
前端
赵锦川33 分钟前
css三角形:css画箭头向下的三角形
前端·css
读心悦36 分钟前
在 TS 的 class 中,如何防止外部实例化
typescript
qbbmnnnnnn37 分钟前
【WebGis开发 - Cesium】如何确保Cesium场景加载完毕
前端·javascript·vue.js·gis·cesium·webgis·三维可视化开发
f8979070701 小时前
layui动态表格出现 横竖间隔线
前端·javascript·layui