最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • three.js 实现风暴云特效

    正文概述 掘金(alphardex)   2021-06-28   1015

    前言

    大家好,这里是 CSS兼WebGL 魔法使——alphardex。

    本文我们将用three.js来实现风暴云特效,以下是最终实现的效果图

    three.js 实现风暴云特效

    让我们开始吧!

    预备知识

    为了实现这个特效,我们先简要了解一下FBM吧

    FBM中文意思是分形布朗运动,另一种称呼是分形噪声(说明它也属于噪声的一种)。它常用于描绘各种自然之中的形状(山脉、云层、河流等)。概念是在一个for循环内叠加几次噪声(往往是6次,相当于一个八度octave),并在叠加的同时升高频率,降低振幅。以下是一个简易的fbm实现的噪声图案

    three.js 实现风暴云特效

    #pragma glslify:centerUv=require(../modules/centerUv)
    #pragma glslify:snoise=require(glsl-noise/simplex/2d)
    
    uniform float uTime;
    uniform vec2 uMouse;
    uniform vec2 uResolution;
    
    varying vec2 vUv;
    varying vec3 vPosition;
    
    #define OCTAVES 6
    
    float fbm(vec2 p){
        float sum=0.;
        float amp=.5;
        for(int i=0;i<OCTAVES;i++){
            float noise=snoise(p)*amp;
            sum+=noise;
            p*=2.;
            amp*=.5;
        }
        return sum;
    }
    
    void main(){
        vec2 cUv=centerUv(vUv,uResolution);
        vec2 p=cUv*3.;
        float noise=fbm(p);
        vec3 color=vec3(noise);
        gl_FragColor=vec4(color,1.);
    }
    

    准备工作

    笔者的three.js模板:点击右下角的fork即可复制一份

    为了将着色器模块化,需要用到glslify

    同时也需要安装如下的npm包:glsl-noise

    正片

    场景搭建

    创建一张铺满屏幕的平面,作为画布

    class CloudySky extends Base {
      clock!: THREE.Clock;
      cloudySkyMaterial!: THREE.ShaderMaterial;
      params!: any;
      constructor(sel: string, debug: boolean) {
        super(sel, debug);
        this.clock = new THREE.Clock();
        this.cameraPosition = new THREE.Vector3(0, 0, 1);
        this.params = {
          velocity: 5,
          skyColor: "#324678",
        };
      }
      // 初始化
      init() {
        this.createScene();
        this.createOrthographicCamera();
        this.createRenderer();
        this.createCloudySkyMaterial();
        this.createPlane();
        this.createLight();
        this.trackMousePos();
        this.addListeners();
        this.setLoop();
      }
      // 创建材质
      createCloudySkyMaterial() {
        const cloudySkyMaterial = new THREE.ShaderMaterial({
          vertexShader: cloudySkyVertexShader,
          fragmentShader: cloudySkyFragmentShader,
          side: THREE.DoubleSide,
          uniforms: {
            uTime: {
              value: 0,
            },
            uMouse: {
              value: new THREE.Vector2(0, 0),
            },
            uResolution: {
              value: new THREE.Vector2(window.innerWidth, window.innerHeight),
            },
            uVelocity: {
              value: this.params.velocity,
            },
            uSkyColor: {
              value: new THREE.Color(this.params.skyColor),
            },
          },
        });
        this.cloudySkyMaterial = cloudySkyMaterial;
        this.shaderMaterial = cloudySkyMaterial;
      }
      // 创建平面
      createPlane() {
        const geometry = new THREE.PlaneBufferGeometry(2, 2, 100, 100);
        const material = this.cloudySkyMaterial;
        this.createMesh({
          geometry,
          material,
        });
      }
      // 动画
      update() {
        const elapsedTime = this.clock.getElapsedTime();
        const mousePos = this.mousePos;
        if (this.cloudySkyMaterial) {
          this.cloudySkyMaterial.uniforms.uTime.value = elapsedTime;
          this.cloudySkyMaterial.uniforms.uMouse.value = mousePos;
        }
      }
    }
    

    顶点着色器直接用默认的就可以了

    片元着色器

    思路也是基本的fbm写法,只是在外层连续应用了16次(这样特别烧显卡,但是实现的效果很炫酷,帅就完事了),并且加上了随着时间的x轴位移

    #pragma glslify:centerUv=require(../modules/centerUv)
    #pragma glslify:snoise=require(glsl-noise/simplex/3d)
    #pragma glslify:invert=require(../modules/invert)
    
    uniform float uTime;
    uniform vec2 uMouse;
    uniform vec2 uResolution;
    uniform float uVelocity;
    uniform vec3 uSkyColor;
    
    varying vec2 vUv;
    varying vec3 vPosition;
    
    #define OCTAVES 6
    
    float fbm(vec3 p){
        float sum=0.;
        float amp=1.;
        for(int i=0;i<OCTAVES;i++){
            vec3 r=p/amp*.2;
            float noise=snoise(r)*amp;
            sum+=noise;
            amp*=.5;
        }
        return sum;
    }
    
    void main(){
        vec2 cUv=centerUv(vUv,uResolution);
        vec2 p=cUv;
        vec3 ray=vec3(0.);
        vec3 eye=normalize(vec3(p,2.));
        float displacement=uTime*uVelocity;
        ray.x+=displacement;
        float cloud=0.;
        float sum=0.;
        for(int i=0;i<16;i++){
            ray+=eye;
            sum=fbm(ray);
            sum=clamp(sum,0.,1.)*.1;
            cloud+=sum;
        }
        vec3 color=uSkyColor+cloud;
        gl_FragColor=vec4(color,1.);
    }
    

    最终效果如下

    three.js 实现风暴云特效

    项目地址

    Cloudy Sky


    起源地下载网 » three.js 实现风暴云特效

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元