cocos 转场动画

摘要

本文主要探讨3D场景转场效果的shader实现方案。

设计思路

  1. 预渲染阶段:在转场开始前,通过相机捕捉当前3D场景画面

  2. 转场初始化

    • 将捕捉的场景图像设置为UI背景

    • 使用该背景覆盖原始3D场景

  3. 转场执行

    • 对3D区域进行空间变换

    • 应用Shader实现转场特效

代码实现

核心代码修改如下:

@ccclass('TransitionTest')
export class TransitionTest extends Component {
    // 材质组
    @property({type:Material})
    mats:Material[]=[];

    // 图片
    @property(Node)
    sNode:Node;

    @property(MenuContainer)
    menu:MenuContainer;


    @property(Node)
    scNode1: Node = null;
    @property(Node)
    scNode2: Node = null;


    
    @property(Camera)
    sourceCamera: Camera = null;
    @property(RenderTexture)
    renderTexture: RenderTexture = null;


    flag: boolean = true;

    isEnd: boolean = true;

    start() {
        this.mats.forEach((m,i)=>{
            const name = m.name;
            this.menu.addMenuItem(name,()=>{
                if(this.isEnd) {
                    this.changeMat(i);
                }
            })
        })
    }

    changeMat(index) {
        this.isEnd = false;
        
        this.sNode.active = true;
        this.sourceCamera.node.active = true;


        // 创建图片准备
        const size = this.sourceCamera.camera.window;
        this.renderTexture.reset({
            width: size.width,
            height: size.height,
        });
        // 设置 Camera 的目标纹理
        this.sourceCamera.targetTexture = this.renderTexture;
        // 创建 SpriteFrame
        const sSprite = new SpriteFrame();
        sSprite.texture = this.renderTexture;


        let start = {num:250};
        let end = {num:0};


        const sp = this.sNode.getComponent(Sprite);
        const mat = this.mats[index];

        tween(start).delay(0.0016).call(() => {
            // 切换场景
            this.sourceCamera.targetTexture = null;
            this.sourceCamera.node.active = false;
            this.scNode1.active = !this.flag;
            this.scNode2.active = this.flag;
            this.flag = !this.flag;
        }).delay(0.0016).call(() => {
            // 设置转场效果
            sSprite.flipUVY = true;
            sp.spriteFrame = sSprite;
            sp.material = mat;
            sp.material.setProperty("subTexture", sSprite.texture);
        }).delay(0.0016).to(2.5,end, {
            onUpdate(target:any, ratio: number) {
                // 设置进度
                sp.material.setProperty("pvalue", 1 - target.num / 250);
            },
        }).delay(0.0016).call(() => {
            // 重置状态
            sp.material.setProperty("pvalue", 0);
            this.sNode.active = false;
            this.isEnd = true;
        }).start();
    }
}

修改shader如下:

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: 
          subTexture:    { value: grey }
          pvalue:    { value: 0.0 }
}%
        
CCProgram sprite-vs %{
  precision highp float;
  #include <builtin/uniforms/cc-global>
  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);
    pos = cc_matViewProj * pos;
    uv0 = a_texCoord;
    color = a_color;
    return pos;
  }
}%

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

  in vec4 color;
  in vec2 uv0;
  #pragma builtin(local)
  layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture;
  uniform sampler2D subTexture;

  uniform Uniform {
    float pvalue;
  };

  vec4 frag () {
    vec4 mainColor = texture(subTexture, uv0);
    vec4 mixColor = vec4(0,0,0,0);
    float progression = pvalue;
    mainColor = BoxTransition(mainColor, mixColor, uv0, progression);
    return mainColor;
   }
 }%

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: 
          subTexture:    { value: grey }
          pvalue:    { value: 0.0 }
}%
        
CCProgram sprite-vs %{
  precision highp float;
  #include <builtin/uniforms/cc-global>
  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);
    pos = cc_matViewProj * pos;
    uv0 = a_texCoord;
    color = a_color;
    return pos;
  }
}%

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

  in vec4 color;
  in vec2 uv0;
  #pragma builtin(local)
  layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture;
  uniform sampler2D subTexture;

  uniform Uniform {
    float pvalue;
  };

  vec4 frag () {
    vec4 mainColor = texture(subTexture, uv0);
    vec4 mixColor = vec4(0,0,0,0);
    float progression = pvalue;
    mainColor = LinearTransition(mainColor, mixColor, uv0, progression,true);
    return mainColor;
   }
 }%

参考文献

  1.    Cocos Shader 转场特效合集!卡牌必备,免费开源!-CSDN博客

  2.    Cocos Store

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随与坏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值