摘要
本文主要探讨3D场景转场效果的shader实现方案。
设计思路
-
预渲染阶段:在转场开始前,通过相机捕捉当前3D场景画面
-
转场初始化:
-
将捕捉的场景图像设置为UI背景
-
使用该背景覆盖原始3D场景
-
-
转场执行:
-
对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;
}
}%