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下载地址

相关推荐
web1478621072329 分钟前
C# .Net Web 路由相关配置
前端·c#·.net
m0_7482478030 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖34 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案141 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_748254881 小时前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营1 小时前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css
joan_852 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui