前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >cocosCreator使用shader实现图片扫光特效

cocosCreator使用shader实现图片扫光特效

作者头像
南锋
发布2024-03-08 10:10:51
1890
发布2024-03-08 10:10:51
举报
文章被收录于专栏:淡忘的博客淡忘的博客

cocosCreator使用shader实现图片扫光特效

南锋2024-03-072024-03-07

简介

功能:图片实现扫光效果 引擎:cocos Creator 3.7.2 开发语言:ts

shader代码

代码语言:javascript
复制
// 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代码

代码语言:javascript
复制
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下载地址

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-03-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • cocosCreator使用shader实现图片扫光特效
    • 简介
      • shader代码
        • 使用方法
          • ts代码
            • 完整demo
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档