端午节前我们水完了,通过Shader多种过度效果。
这篇我们接着水下Cocos的Shader的Uniform变量,通过变量和全局变量来实现多种效果。
**商店地址免费下载:**Cocos Store
全局战争迷雾效果
]
迷雾点击效果
体验链接:Cocos Creator | 2D-fog-test
历史水文:
1.0 减少变量数量
可以通过在Shader的Property中target 来减少Uniform个数,通过一个float4 mixParam来实现mix1到mix4的参数控制
同时可以在片元中使用Shared-UBO,方便调用。
vec4 frag () {
vec4 col = texture(cc_spriteTexture, uv0);
float range = mix(uv0.x,uv0.y,mixParam.z);
vec4 mixCol =
step(range,mixParam.x)*mix(color,color1,range/mixParam.x)
+(step(mixParam.x,range)*step(range,mixParam.y))*mix(color1,color2,(range-mixParam.x)/(mixParam.y-mixParam.x))
+(step(mixParam.y,range)*step(range,1.))*mix(color2,color3,(range-mixParam.y)/(1.-mixParam.y));
col *= mix(color,mixCol,mixParam.w);
return col;
}
2.0 优化浮点数精度
2D可以使用低精度的浮点数,各精度浮点值如下,通过降低浮点值来优化性能。
高精度:highp
最高精度浮点值;一般是 32 位(就像常规编程语言中的 float)。
完整的 float 精度通常用于世界空间位置、纹理坐标或涉及复杂函数(如三角函数或幂/取幂)的标量计算。
中等精度:mediump
中等精度浮点值;通常为 16 位(范围为 –60000 至 +60000,精度约为 3 位小数)。
半精度对于短矢量、方向、对象空间位置、高动态范围颜色非常有用。
低精度:lowp
最低精度的定点值。通常是 11 位,范围从 –2.0 到 +2.0,精度为 1/256。
固定精度对于常规颜色(通常存储在常规纹理中)以及对它们执行简单运算非常有用。
这里是2D的Shader,使用了mediump来减少带宽和显存占用。
CCProgram sprite-vs %{
precision mediump float;
#include <builtin/uniforms/cc-global>
in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;
out vec2 uv0;
out vec4 color;
vec4 vert () {
vec4 pos = vec4(a_position, 1.);
pos = cc_matViewProj * pos;
uv0 = a_texCoord;
color = a_color;
return pos;
}
}%
CCProgram sprite-fs %{
precision mediump float;
#include <builtin/internal/embedded-alpha>
#include <shared-ubos>
in vec4 color;
in vec2 uv0;
#pragma builtin(local)
layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture;
vec4 frag () {
vec4 col = texture(cc_spriteTexture, uv0);
float range = mix(uv0.x,uv0.y,mixParam.z);
vec4 mixCol =
step(range,mixParam.x)*mix(color,color1,range/mixParam.x)
+(step(mixParam.x,range)*step(range,mixParam.y))*mix(color1,color2,(range-mixParam.x)/(mixParam.y-mixParam.x))
+(step(mixParam.y,range)*step(range,1.))*mix(color2,color3,(range-mixParam.y)/(1.-mixParam.y));
col *= mix(color,mixCol,mixParam.w);
return col;
}
3.0 合理设置材质变量
避免使用材质自带的setproperty,如果使用请带上pass的序号,不然会历遍所有pass,开销高
可以替换获取材质的pass和变量的handle,setUniform 设置
initUniforms() {
/* use Material for single instance, sharedMaterial for shared instance */
const mat = this.sp.sharedMaterial;
for (var i = 1; i <= 4; i++) {
const pass = mat.passes[0];
const handle = pass.getHandle("mix" + i);
const slider = this.node.getChildByName("Slider" + i).getComponent(Slider);
slider.progress = pass.getUniform(handle, null);
slider.node.on("slide", ((s: Slider) => {
pass.setUniform(handle, s.progress);
}), this);
}
}
在update(pass和handle可以提前缓存)或者slider等场景中推荐使用setUniform
4.0 使用全局变量
通过引入全局变量,可以实现2D/3D全局雾效/光照。
shader
CCProgram sprite-fs %{
precision mediump float;
#include <builtin/uniforms/cc-global>
#include <builtin/internal/embedded-alpha>
#include <Filters>
in vec4 color;
in vec2 uv0;
in vec2 pos0;
#pragma builtin(local)
layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture;
const vec3 ringCol = vec3(0.5,0.2,0.8);
const float ringWidth = 50.;
void fog(inout vec4 col,vec2 pos){
float fogDis = distance(pos,cc_fogBase.xy);
float mixF = smoothstep(cc_fogBase.z-ringWidth,cc_fogBase.z,fogDis);
vec3 fogCol = (Blued(col.rgb)+cc_fogColor.xyz)*0.5;
col.rgb =mix(col.rgb+ringCol*mixF*1.5,fogCol,mixF);
}
vec4 frag () {
vec4 col = texture(cc_spriteTexture, uv0);
fog(col,pos0);
return col;
}
可以使用代码控制 全局变量
const tempV2_0 = new Vec2();
@ccclass('fogCtrl')
export class fogCtrl extends Component {
onEnable() {
this.node.on(Node.EventType.TOUCH_END,this.onClickCanvas,this);
}
onDisable(){
this.node.off(Node.EventType.TOUCH_END,this.onClickCanvas,this);
const fog = director.getScene().globals.fog;
Tween.stopAllByTarget(fog);
}
onClickCanvas(event:Touch){
event.getUILocation(tempV2_0);
const fog = director.getScene().globals.fog;
fog.fogStart = tempV2_0.x;
fog.fogEnd = tempV2_0.y;
fog.fogDensity = 0;
tween(fog).to(2,{fogDensity:2000},{easing:'sineIn'}).start()
}
}
也可以用来控制角色+战争迷雾
const tempV3_0 = new Vec3();
const tempV3_1 = new Vec3();
const tempV2_0 = new Vec2();
@ccclass('fogMoveCtrl')
export class fogMoveCtrl extends Component {
@property speed=10;
@property density = 150;
_fog:FogInfo;
_move = false;
_dir = 1;
onEnable() {
this._fog=director.getScene().globals.fog;
this._fog.fogDensity = this.density;
tempV3_1.set(this.node.worldPosition);
this._fog.fogStart = tempV3_1.x;
this._fog.fogEnd = tempV3_1.y;
const canvas = director.getScene().getChildByName("Canvas");
canvas.on(Node.EventType.TOUCH_END,this.moveChar,this);
}
onDisable() {
const canvas = director.getScene().getChildByName("Canvas");
canvas.off(Node.EventType.TOUCH_END,this.moveChar,this);
}
moveChar(event:Touch){
tempV3_1.x = this.node.worldPosition.x;
tempV3_1.y = this.node.worldPosition.y;
event.getUILocation(tempV2_0);
tempV3_0.x = tempV2_0.x;
tempV3_0.y = tempV2_0.y;
const length = Vec3.distance(tempV3_0,tempV3_1);
if(length>5){
const direction = (tempV3_1.x-tempV3_0.x)>0?1:-1;
if(this._dir!=direction){
this.node.setScale(direction,1,1);
this._dir=direction;
}
this._move = true;
const time = length/this.speed;
Tween.stopAllByTarget(this.node);
tween(this.node).to(time,{worldPosition:tempV3_0}).call(()=>{
this._move = false;
}).start();
}
}
update(deltaTime: number) {
if(this._move){
tempV3_1.set(this.node.worldPosition);
this._fog.fogStart = tempV3_1.x;
this._fog.fogEnd = tempV3_1.y;
}
}
}
战争迷雾效果
]
迷雾的全局颜色可以在scene面板设置,或者通过代码设置
代码:(随后上线store)
2D-fog.zip (1.8 MB)