《Shader从入门到入土5.0》战争迷雾和Uniform

端午节前我们水完了,通过Shader多种过度效果。

这篇我们接着水下Cocos的Shader的Uniform变量,通过变量和全局变量来实现多种效果。

**商店地址免费下载:**Cocos Store

全局战争迷雾效果

101 ]

迷雾点击效果

100

体验链接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

image

4.0 使用全局变量

通过引入全局变量,可以实现2D/3D全局雾效/光照。

100

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;
        }
    }
}

战争迷雾效果

101 ]

迷雾的全局颜色可以在scene面板设置,或者通过代码设置

image

代码:(随后上线store)

2D-fog.zip (1.8 MB)

20赞

占个茅坑,准备偷代码

楼上的别占着不拉啊 :face_with_hand_over_mouth:

占位等编辑+666

拉完了没有我来了

mark~

很牛,mark下

牛B,必须赞。

很牛,mark下

虽然看不懂,还是觉得很牛逼

准备好白嫖姿势

无脑up一下

很牛,mark下

141414 :smiley:

来白嫖了!!!

MARK.

666厉害了

源码已经上传,增加了density


下一篇预告:
RT和解密游戏!(哥哥不要塌房啊!!!!!!)

看见大佬直接mark

:face_with_monocle: :face_with_monocle: :face_with_monocle: :face_with_monocle: :face_with_monocle: :face_with_monocle: