• threejs(12)-着色器打造烟雾水云效果


    一、自己封装水波纹效果

    在这里插入图片描述
    src/main/main01.js

    import * as THREE from "three";
    
    import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
    import gsap from "gsap";
    import * as dat from "dat.gui";
    import vertexShader from "../shaders/water/vertex.glsl";
    import fragmentShader from "../shaders/water/fragment.glsl";
    
    // 目标:设置云烟雾效果
    
    //创建gui对象
    const gui = new dat.GUI();
    
    // console.log(THREE);
    // 初始化场景
    const scene = new THREE.Scene();
    
    // 创建透视相机
    const camera = new THREE.PerspectiveCamera(
      90,
      window.innerHeight / window.innerHeight,
      0.1,
      1000
    );
    // 设置相机位置
    // object3d具有position,属性是1个3维的向量
    camera.position.set(0, 0, 2);
    // 更新摄像头
    camera.aspect = window.innerWidth / window.innerHeight;
    //   更新摄像机的投影矩阵
    camera.updateProjectionMatrix();
    scene.add(camera);
    
    // 加入辅助轴,帮助我们查看3维坐标轴
    const axesHelper = new THREE.AxesHelper(5);
    scene.add(axesHelper);
    
    const params = {
      uWaresFrequency: 14,
      uScale: 0.03,
      uXzScale: 1.5,
      uNoiseFrequency: 10,
      uNoiseScale: 1.5,
      uLowColor: "#ff0000",
      uHighColor: "#ffff00",
      uXspeed: 1,
      uZspeed: 1,
      uNoiseSpeed: 1,
      uOpacity: 1,
    };
    
    const shaderMaterial = new THREE.ShaderMaterial({
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
      side: THREE.DoubleSide,
      uniforms: {
        uWaresFrequency: {
          value: params.uWaresFrequency,
        },
        uScale: {
          value: params.uScale,
        },
        uNoiseFrequency: {
          value: params.uNoiseFrequency,
        },
        uNoiseScale: {
          value: params.uNoiseScale,
        },
        uXzScale: {
          value: params.uXzScale,
        },
        uTime: {
          value: params.uTime,
        },
        uLowColor: {
          value: new THREE.Color(params.uLowColor),
        },
        uHighColor: {
          value: new THREE.Color(params.uHighColor),
        },
        uXspeed: {
          value: params.uXspeed,
        },
        uZspeed: {
          value: params.uZspeed,
        },
        uNoiseSpeed: {
          value: params.uNoiseSpeed,
        },
        uOpacity: {
          value: params.uOpacity,
        },
      },
      transparent: true,
    });
    
    gui
      .add(params, "uWaresFrequency")
      .min(1)
      .max(100)
      .step(0.1)
      .onChange((value) => {
        shaderMaterial.uniforms.uWaresFrequency.value = value;
      });
    
    gui
      .add(params, "uScale")
      .min(0)
      .max(0.2)
      .step(0.001)
      .onChange((value) => {
        shaderMaterial.uniforms.uScale.value = value;
      });
    
    gui
      .add(params, "uNoiseFrequency")
      .min(1)
      .max(100)
      .step(0.1)
      .onChange((value) => {
        shaderMaterial.uniforms.uNoiseFrequency.value = value;
      });
    
    gui
      .add(params, "uNoiseScale")
      .min(0)
      .max(5)
      .step(0.001)
      .onChange((value) => {
        shaderMaterial.uniforms.uNoiseScale.value = value;
      });
    
    gui
      .add(params, "uXzScale")
      .min(0)
      .max(5)
      .step(0.1)
      .onChange((value) => {
        shaderMaterial.uniforms.uXzScale.value = value;
      });
    
    gui.addColor(params, "uLowColor").onFinishChange((value) => {
      shaderMaterial.uniforms.uLowColor.value = new THREE.Color(value);
    });
    gui.addColor(params, "uHighColor").onFinishChange((value) => {
      shaderMaterial.uniforms.uHighColor.value = new THREE.Color(value);
    });
    
    gui
      .add(params, "uXspeed")
      .min(0)
      .max(5)
      .step(0.001)
      .onChange((value) => {
        shaderMaterial.uniforms.uXspeed.value = value;
      });
    
    gui
      .add(params, "uZspeed")
      .min(0)
      .max(5)
      .step(0.001)
      .onChange((value) => {
        shaderMaterial.uniforms.uZspeed.value = value;
      });
    
    gui
      .add(params, "uNoiseSpeed")
      .min(0)
      .max(5)
      .step(0.001)
      .onChange((value) => {
        shaderMaterial.uniforms.uNoiseSpeed.value = value;
      });
    
    gui
      .add(params, "uOpacity")
      .min(0)
      .max(1)
      .step(0.01)
      .onChange((value) => {
        shaderMaterial.uniforms.uOpacity.value = value;
      });
    
    const plane = new THREE.Mesh(
      new THREE.PlaneBufferGeometry(1, 1, 1024, 1024),
      shaderMaterial
    );
    plane.rotation.x = -Math.PI / 2;
    
    scene.add(plane);
    
    // 初始化渲染器
    const renderer = new THREE.WebGLRenderer({ alpha: true });
    
    // 设置渲染尺寸大小
    renderer.setSize(window.innerWidth, window.innerHeight);
    
    // 监听屏幕大小改变的变化,设置渲染的尺寸
    window.addEventListener("resize", () => {
      //   console.log("resize");
      // 更新摄像头
      camera.aspect = window.innerWidth / window.innerHeight;
      //   更新摄像机的投影矩阵
      camera.updateProjectionMatrix();
    
      //   更新渲染器
      renderer.setSize(window.innerWidth, window.innerHeight);
      //   设置渲染器的像素比例
      renderer.setPixelRatio(window.devicePixelRatio);
    });
    
    // 将渲染器添加到body
    document.body.appendChild(renderer.domElement);
    
    // 初始化控制器
    const controls = new OrbitControls(camera, renderer.domElement);
    // 设置控制器阻尼
    controls.enableDamping = true;
    
    const clock = new THREE.Clock();
    function animate(t) {
      const elapsedTime = clock.getElapsedTime();
      shaderMaterial.uniforms.uTime.value = elapsedTime;
      requestAnimationFrame(animate);
      // 使用渲染器渲染相机看这个场景的内容渲染出来
      renderer.render(scene, camera);
    }
    
    animate();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231

    src/shaders/water/fragment.glsl

    precision lowp float;
    
    uniform vec3 uHighColor;
    uniform vec3 uLowColor;
    varying float vElevation;
    uniform float uOpacity;
    
    void main(){
        float a = (vElevation+1.0)/2.0;
        vec3 color = mix(uLowColor,uHighColor,a);
        gl_FragColor = vec4(color,uOpacity);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    src/shaders/water/vertex.glsl

    precision lowp float;
    uniform float uWaresFrequency;
    uniform float uScale;
    uniform float uNoiseFrequency;
    uniform float uNoiseScale;
    uniform float uXzScale;
    uniform float uTime;
    uniform float uXspeed;
    uniform float uZspeed;
    uniform float uNoiseSpeed;
    
    // 计算出的高度传递给片元着色器
    varying float vElevation;
    
    // 随机函数
    float random (vec2 st) {
        return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
    }
    
    // 旋转函数
    vec2 rotate(vec2 uv, float rotation, vec2 mid)
    {
        return vec2(
          cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x,
          cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y
        );
    }
    
    // 噪声函数
    float noise (in vec2 _st) {
        vec2 i = floor(_st);
        vec2 f = fract(_st);
    
        // Four corners in 2D of a tile
        float a = random(i);
        float b = random(i + vec2(1.0, 0.0));
        float c = random(i + vec2(0.0, 1.0));
        float d = random(i + vec2(1.0, 1.0));
    
        vec2 u = f * f * (3.0 - 2.0 * f);
    
        return mix(a, b, u.x) +
                (c - a)* u.y * (1.0 - u.x) +
                (d - b) * u.x * u.y;
    }
    
    
    //	Classic Perlin 2D Noise 
    //	by Stefan Gustavson
    //
    vec4 permute(vec4 x)
    {
        return mod(((x*34.0)+1.0)*x, 289.0);
    }
    
    vec2 fade(vec2 t)
    {
        return t*t*t*(t*(t*6.0-15.0)+10.0);
    }
    
    float cnoise(vec2 P)
    {
        vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
        vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
        Pi = mod(Pi, 289.0); // To avoid truncation effects in permutation
        vec4 ix = Pi.xzxz;
        vec4 iy = Pi.yyww;
        vec4 fx = Pf.xzxz;
        vec4 fy = Pf.yyww;
        vec4 i = permute(permute(ix) + iy);
        vec4 gx = 2.0 * fract(i * 0.0243902439) - 1.0; // 1/41 = 0.024...
        vec4 gy = abs(gx) - 0.5;
        vec4 tx = floor(gx + 0.5);
        gx = gx - tx;
        vec2 g00 = vec2(gx.x,gy.x);
        vec2 g10 = vec2(gx.y,gy.y);
        vec2 g01 = vec2(gx.z,gy.z);
        vec2 g11 = vec2(gx.w,gy.w);
        vec4 norm = 1.79284291400159 - 0.85373472095314 * vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11));
        g00 *= norm.x;
        g01 *= norm.y;
        g10 *= norm.z;
        g11 *= norm.w;
        float n00 = dot(g00, vec2(fx.x, fy.x));
        float n10 = dot(g10, vec2(fx.y, fy.y));
        float n01 = dot(g01, vec2(fx.z, fy.z));
        float n11 = dot(g11, vec2(fx.w, fy.w));
        vec2 fade_xy = fade(Pf.xy);
        vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
        float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
        return 2.3 * n_xy;
    }
    
    
    void main(){
        vec4 modelPosition = modelMatrix * vec4(position,1.0);
    
        float elevation = sin(modelPosition.x*uWaresFrequency+uTime*uXspeed)*sin(modelPosition.z*uWaresFrequency*uXzScale+uTime*uZspeed);
    
        elevation += -abs(cnoise(vec2(modelPosition.xz*uNoiseFrequency+uTime*uNoiseSpeed))) *uNoiseScale;
        
        vElevation = elevation;
        
        elevation *= uScale;
    
        
    
        modelPosition.y += elevation;
    
        gl_Position = projectionMatrix * viewMatrix *modelPosition;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111

    二、使用官方提供的water方法

    在这里插入图片描述

    src/main/main.js

    import * as THREE from "three";
    
    import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
    import gsap from "gsap";
    import * as dat from "dat.gui";
    
    import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
    import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
    
    // 导入water
    import { Water } from "three/examples/jsm/objects/Water2";
    
    // 目标:认识shader
    
    //创建gui对象
    const gui = new dat.GUI();
    
    // console.log(THREE);
    // 初始化场景
    const scene = new THREE.Scene();
    
    // 创建透视相机
    const camera = new THREE.PerspectiveCamera(
      90,
      window.innerHeight / window.innerHeight,
      0.1,
      1000
    );
    // 设置相机位置
    // object3d具有position,属性是1个3维的向量
    camera.position.set(5, 5, 5);
    // 更新摄像头
    camera.aspect = window.innerWidth / window.innerHeight;
    //   更新摄像机的投影矩阵
    camera.updateProjectionMatrix();
    scene.add(camera);
    
    // 加入辅助轴,帮助我们查看3维坐标轴
    const axesHelper = new THREE.AxesHelper(5);
    scene.add(axesHelper);
    
    // const water = new Water(new THREE.PlaneBufferGeometry(1, 1, 1024, 1024), {
    //   color: "#ffffff",
    //   scale: 1,
    //   flowDirection: new THREE.Vector2(1, 1),
    //   textureHeight: 1024,
    //   textureWidth: 1024,
    // });
    // water.rotation.x = -Math.PI / 2;
    
    // scene.add(water);
    
    // 加载场景背景
    const rgbeLoader = new RGBELoader();
    rgbeLoader.loadAsync("./assets/050.hdr").then((texture) => {
      texture.mapping = THREE.EquirectangularReflectionMapping;
      scene.background = texture;
      scene.environment = texture;
    });
    
    // 加载浴缸
    const gltfLoader = new GLTFLoader();
    gltfLoader.load("./assets/model/yugang.glb", (gltf) => {
      console.log(gltf);
      const yugang = gltf.scene.children[0];
      yugang.material.side = THREE.DoubleSide;
    
      const waterGeometry = gltf.scene.children[1].geometry;
      const water = new Water(waterGeometry, {
        color: "#ffffff",
        scale: 1,
        flowDirection: new THREE.Vector2(1, 1),
        textureHeight: 1024,
        textureWidth: 1024,
      });
    
      scene.add(water);
      scene.add(yugang);
    });
    
    const light = new THREE.AmbientLight(0xffffff); // soft white light
    light.intensity = 10;
    scene.add(light);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
    scene.add(directionalLight);
    
    // 初始化渲染器
    const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
    renderer.outputEncoding = THREE.sRGBEncoding;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    
    // 设置渲染尺寸大小
    renderer.setSize(window.innerWidth, window.innerHeight);
    
    // 监听屏幕大小改变的变化,设置渲染的尺寸
    window.addEventListener("resize", () => {
      //   console.log("resize");
      // 更新摄像头
      camera.aspect = window.innerWidth / window.innerHeight;
      //   更新摄像机的投影矩阵
      camera.updateProjectionMatrix();
    
      //   更新渲染器
      renderer.setSize(window.innerWidth, window.innerHeight);
      //   设置渲染器的像素比例
      renderer.setPixelRatio(window.devicePixelRatio);
    });
    
    // 将渲染器添加到body
    document.body.appendChild(renderer.domElement);
    
    // 初始化控制器
    const controls = new OrbitControls(camera, renderer.domElement);
    // 设置控制器阻尼
    controls.enableDamping = true;
    
    const clock = new THREE.Clock();
    function animate(t) {
      const elapsedTime = clock.getElapsedTime();
      requestAnimationFrame(animate);
      // 使用渲染器渲染相机看这个场景的内容渲染出来
      renderer.render(scene, camera);
    }
    
    animate();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
  • 相关阅读:
    树莓派4B部署Yolov5深度学习模型
    环形链表的判断思路
    2021CCPC广州-C. Necklace(二分+贪心)
    MATLAB求解夏普利值
    【数据结构高阶】二叉搜索树
    FastAPI 学习之路(二)
    人工智能知识全面讲解:感知机原理
    Hydra使用教程图文教程(超详细)
    小谈设计模式(12)—迪米特法则
    【桶计数】面试题 01.02. 判定是否互为字符重排
  • 原文地址:https://blog.csdn.net/woyebuzhidao321/article/details/134363796