雨雪粒子特效(完整可用)

该博客介绍了一个使用Three.js库实现实时三维雨雪效果的示例。通过加载纹理、创建粒子系统和调整参数,用户可以通过GUI控制雨滴和雪花的大小、速度、方向和透明度,实现交互式的雨雪动画。代码中包含了初始化渲染、相机、场景、光照、模型、性能监控、控制器以及GUI设置等关键部分。
摘要由CSDN通过智能技术生成
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type = "text/css">
        html, body{
            margin: 0;
            height: 100%;
        }

        canvas{
            display: block;
        }
    </style>
</head>
<body onload="draw();">
</body>
<script src="../build/extension/weather.js"></script>
<script src="../build/three.js"></script>
<script src="../build/three.extension.js"></script>
<script src="../build/extension/TerrainControls.js"></script>
<script src="../node_modules/three/examples/js/Detector.js"></script>
<script src="../node_modules/three/examples/js/libs/stats.min.js"></script>
<script src="../THREE.MeshLine/demo/js/dat.gui.min.js"></script>
<script src="../node_modules/three/examples/js/controls/OrbitControls.js"></script>
<script>
    var renderer;
    var rainSpeed ;  //雨下的速度
    var rainQuaX;    //雨滴X方向
    var rainQuaZ;    //雨滴Z方向
    var rainRange;   //雨滴范围
    var snowSpeed;   //雪花速度
    var snowQuaX; //雪花方向X
    var snowQuaZ; //雪花方向Z
    var snowRange; //雪花范围
    var camPosVec = new THREE.Vector3();

    var enableView = 0;  //场景设置模式,默认0为自由观察下雨下雪场景,1为固定一小块在摄像头前
    function initRender(){
        //this.render = function ( scene, camera, renderTarget, forceClear )
        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setClearColor(new THREE.Color(0x000000));
        renderer.setSize(window.innerWidth,window.innerHeight);
        document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
    }

    var camera;
    function initCamera() {   //初始化相机
        camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,1,200);
        camera.position.set(0,20,120);
        camPosVec.set(0,0,0);
        camera.lookAt(new THREE.Vector3(0,30,0));
    }

    var scene;
    function initScene() {  //初始化场景
        scene = new THREE.Scene();
    }

    var light;
    function initLight(){  //初始化光
        scene.add(new THREE.AmbientLight(0x404040));
        light = new THREE.DirectionalLight(0xffffff);
        light.position.set(1,1,1);
        scene.add(light)
    }

    function initModel(){  //初始化轴辅助
        var object = new THREE.AxesHelper(500);
        scene.add(object);
    }

    var stats;
    function initStats(){   //初始化性能插件
        stats = new Stats();
        document.body.appendChild(stats.dom);
    }

    var controls;
    function  initControls() {
        controls = new THREE.OrbitControls(camera,renderer.domElement);
        controls.enableDamping = true;
        controls.enableZoom = true;
        controls.autoRotate = false;
        controls.enablePan = true;
    }

    var rainConGui;
    var snowConGui;
    var cloudRain;
    var cloudSnow;
    var disRain;
    var disSnow;

    function initGuiRain() {  //初始化gui
        rainConGui = {
            "开启下雨" : true,
            "雨滴尺寸" : 2,
            "背景透明" : true,
            "不透明度" : 0.6,
            //"vertexColor" : true,
            "雨滴速度" : 8,
            "雨滴方向X" : 0,
            "雨滴方向Z" : 0,
            "雨滴颜色" : 0Xffffff,
            "雨滴距离" : 90,
            //"sizeAttenuation" : true,
            //"rotateSystem" : false,
            rainRedraw : function () {
                if (cloudRain) {
                    if(enableView ==1 ) {
                        camera.remove(cloudRain);
                    }
                    else{
                        scene.remove(cloudRain);
                    }
                }
                createParticlesRain(rainConGui.开启下雨,rainConGui.雨滴速度, rainConGui.雨滴尺寸, rainConGui.背景透明, rainConGui.不透明度, rainConGui.vertexColors, rainConGui.sizeAttenuation, rainConGui.雨滴方向X, rainConGui.雨滴方向Z, rainConGui.雨滴颜色,rainConGui.雨滴距离);
            }
        };
        var rainDatGui = new dat.GUI();
        //将设置属性添加到 rainConGui当中, rainConGui.add(对象,属性,最小值,最大值)
        rainDatGui.add( rainConGui,'开启下雨').onChange( rainConGui.rainRedraw);
        rainDatGui.add( rainConGui,'雨滴速度',8,20).onChange( rainConGui.rainRedraw);
        //datGui.add( rainConGui,'雨滴尺寸',1,10).onChange( rainConGui.redraw);
        //datGui.add( rainConGui,'背景透明').onChange( rainConGui.redraw);
        //datGui.add( rainConGui,'不透明度',0,1).onChange( rainConGui.redraw);
        //datGui.add( rainConGui,'vertexColor').onChange( rainConGui.redraw);
        rainDatGui.add( rainConGui,'雨滴方向X',-1,1).onChange( rainConGui.rainRedraw);
        rainDatGui.add( rainConGui,'雨滴方向Z',-1,1).onChange( rainConGui.rainRedraw);
        rainDatGui.add( rainConGui,'雨滴距离',50,150).onChange( rainConGui.rainRedraw);
        //datGui.addColor( rainConGui,'雨滴颜色').onChange( rainConGui.redraw);
        //datGui.add( rainConGui,'sizeAttenuation').onChange( rainConGui.redraw);
        //datGui.add( rainConGui,'rotateSystem').onChange( rainConGui.redraw);
        rainConGui.rainRedraw();
    }

    function initGuiSnow() {  //初始化雪gui
        snowConGui = {
            "开启下雪" : true,
            "雪花尺寸" : 2,
            "背景透明" : true,
            "不透明度" : 0.6,
            //"vertexColor" : true,
            "雪花速度" : 0.5,
            "雪花方向X" : 0,
            "雪花方向Z" : 0,
            "雪花颜色" : 0Xffffff,
            "雪花距离" : 90,

            //"sizeAttenuation" : true,
            //"rotateSystem" : false,
            snowRedraw : function () {
                if (cloudSnow) {
                    if(enableView == 1) {
                        camera.remove(cloudSnow);
                    }else
                    {
                        scene.remove(cloudSnow)
                    }
                }
                createParticlesSnow(snowConGui.开启下雪,snowConGui.雪花速度, snowConGui.雪花尺寸, snowConGui.背景透明, snowConGui.不透明度, snowConGui.vertexColors, snowConGui.sizeAttenuation, snowConGui.雪花方向X, snowConGui.雪花方向Z, snowConGui.雪花颜色,snowConGui.雪花距离);
            }
        };

        var snowDatGui = new dat.GUI();
        //将设置属性添加到 snowConGui当中, snowConGui.add(对象,属性,最小值,最大值)
        snowDatGui.add( snowConGui,'开启下雪').onChange( snowConGui.snowRedraw);
        snowDatGui.add( snowConGui,'雪花速度',0.5,10).onChange( snowConGui.snowRedraw);
        //datGui.add( snowConGui,'雪花尺寸',0.1,10).onChange( snowConGui.redraw);
        //datGui.add( snowConGui,'背景透明').onChange( snowConGui.redraw);
        //add( snowConGui,'不透明度',0,1).onChange( snowConGui.redraw);
        //datGui.add( snowConGui,'vertexColor').onChange( snowConGui.redraw);
        snowDatGui.add( snowConGui,'雪花方向X',-1,1).onChange( snowConGui.snowRedraw);
        snowDatGui.add( snowConGui,'雪花方向Z',-1,1).onChange( snowConGui.snowRedraw);
        snowDatGui.add( snowConGui,'雪花距离',50,150).onChange( snowConGui.snowRedraw);

        //datGui.addColor( snowConGui,'雪花颜色').onChange( snowConGui.redraw);
        //datGui.add( snowConGui,'sizeAttenuation').onChange( snowConGui.redraw);
        //datGui.add( snowConGui,'rotateSystem').onChange( snowConGui.redraw);
        snowConGui.snowRedraw();
    }


    //生成雨滴粒子的方法
    function createParticlesRain(enableRain,speed,size, transparent, opacity, vertexColors, sizeAttenuation,quaX, quaZ,color,distanceRain) {
        if(enableRain == true) {
            rainQuaX = quaX * 5;
            rainQuaZ = quaZ * 5;
            var angleRain = Math.acos(rainQuaX / Math.sqrt(rainQuaX * rainQuaX + 0.2795850805518647*0.2795850805518647));
            var textureRain = new THREE.TextureLoader().load("/example/textures/1rain.png");  //加载纹理贴图
            //var texture = new THREE.TextureNode();
            if(quaX||quaZ) {
                textureRain.rotation = 1/angleRain;
                textureRain.center.set(0.5, 0.5);
            }
            var geomRain = new THREE.Geometry();   //几何体;
            var materialRain = new THREE.PointCloudMaterial({    //材质定义为点云
                size: size * 2,
                transparent: transparent,
                opacity: opacity,
                vertexColors: true,
                sizeAttenuation: true,
                color: color,
                map: textureRain,
                depthTest: false, //设置解决透明度有问题的情况

            });
            disRain = distanceRain;
            rainSpeed = speed;

            var range = 120;
            rainRange = range / 2;
            for (var i = 0; i < 1500; i++) {
                //添加顶点坐标
                var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2);
                particle.velocityY = 0.1 + Math.random() / 5;
                particle.velocityX = (Math.random() - 0.5) / 3;
                particle.velocityZ = 0;
                geomRain.vertices.push(particle);
                var color = new THREE.Color(0Xffffff);
                //color.setHSL(color.getHSL().h,color.getHSL().s,Math.random()* color.getHSL(),l);
                geomRain.colors.push(color);
                //geomRain.lookAt(0,0,0);
                //geomRain.rotateY(Math.PI/6);
                //geomRain.verticesNeedUpdate = true;
            }
            //生成模型,添加到场景当中
            cloudRain = new THREE.Points(geomRain, materialRain);
            //cloudRain.rotation.x= rainQuaX;
            //cloud.position.set(96389.0-466.53, 2690779.0+23.26, 1000);
            cloudRain.verticesNeedUpdate = true;
            if (enableView == 1) {
                camera.add(cloudRain);
                scene.add(camera);
            } else{
                scene.add(cloudRain);
            }
            //geomRain.rotateZ(Math.PI/4);

        }
    }

    //生成雪花粒子的方法
    function createParticlesSnow(enableSnow,speed,size, transparent, opacity, vertexColors, sizeAttenuation,quaX, quaZ,color,distanceSnow) {
        if(enableSnow == true) {
            var textureSnow = new THREE.TextureLoader().load("/example/textures/snow.png");  //加载纹理贴图
            var geomSnow = new THREE.Geometry();   //几何体;
            var materialSnow = new THREE.PointCloudMaterial({    //材质定义为点云
                size: size,
                transparent: transparent,
                opacity: opacity,
                vertexColors: true,
                sizeAttenuation: true,
                color: color,
                map: textureSnow,
                depthTest: false, //设置解决透明度有问题的情况
            });
            disSnow = distanceSnow;
            snowSpeed = speed;
            snowQuaX = quaX;
            snowQuaZ = quaZ;
            var range = 120;
            snowRange = range / 2;
            for (var i = 0; i < 1500; i++) {
                //添加顶点坐标
                var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2);
                particle.velocityY = 0.1 + Math.random() / 5;
                particle.velocityX = (Math.random() - 0.5) / 3;
                particle.velocityZ = 0;

                geomSnow.vertices.push(particle);
                var color = new THREE.Color(0Xffffff);
                //color.setHSL(color.getHSL().h,color.getHSL().s,Math.random()* color.getHSL(),l);
                geomSnow.colors.push(color);
            }
            //生成模型,添加到场景当中
            cloudSnow = new THREE.Points(geomSnow, materialSnow);
            //cloud.position.set(96389.0-466.53, 2690779.0+23.26, 1000);
            cloudSnow.verticesNeedUpdate = true;
            if(enableView ==1) {
                camera.add(cloudSnow);
                scene.add(camera);
            }
            else{
                scene.add(cloudSnow);
            }
        }
    }

    function renderRain() {
        //产生雨滴动画效果
        var vertices = cloudRain.geometry.vertices;
        vertices.forEach(function (v) {
            //v.y = v.y - (v.velocityY) * rainSpeed ;//* speed;
            //v.x = v.x - (v.velocityX) *.5;
            //(v.y <= -60)v.y = 60;
            //if(v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1;
            v.y = v.y - (v.velocityY) * rainSpeed ;
            if(v.y <= -rainRange)v.y = rainRange;
            v.x = v.x-(v.velocityX+rainQuaX)*.5;
            v.z = v.z-v.velocityZ+rainQuaZ;
            if(v.x >= rainRange ) {
                v.x = -rainRange;
            }
            else if(v.x <= -rainRange) {
                v.x = rainRange;
            }
            if(v.z >= rainRange )
                v.z = -rainRange;
            else if(v.z <= -rainRange)
                v.z = rainRange;
        });

        cloudRain.geometry.verticesNeedUpdate = true;
        //distanceCamera = camera.position.distanceTo(camPosVec)
        //cloudRain.position.set(camera.position.x+(camera.position.x-camPosVec.x)*distanceCamera,camera.position.y+(camera.position.y-camPosVec.y)*distanceCamera,camera.position.z+(camera.position.z-camPosVec.z)*distanceCamera);
        //cloudRain.position.set(camera.position.x,camera.position.y,camera.position.z);
        if(enableView ==1) {
            cloudRain.position.set(0, 0, -disRain);
        }
        renderer.render(scene,camera);
    }

    function renderSnow() {
        //产生雪花动画效果
        var vertices = cloudSnow.geometry.vertices;
        vertices.forEach(function (v) {
            //v.y = v.y - (v.velocityY) * snowSpeed ;
            //v.x = v.x - (v.velocityX) *.5;
            //if(v.y <= -60)v.y = 60;
            //if(v.x <= -60 || v.x >= 60) v.velocityX = v.velocityX * -1;
            v.y = v.y - (v.velocityY) * snowSpeed;
            if(v.y <= -snowRange)v.y = snowRange;
            v.x = v.x-(v.velocityX+snowQuaX)*.5;
            v.z = v.z-v.velocityZ+snowQuaZ;
            if(v.x >= snowRange )
                v.x = -snowRange;
            else if(v.x <= -snowRange)
                v.x = snowRange;
            if(v.z >= snowRange )
                v.z = -snowRange;
            else if(v.z <= -snowRange)
                v.z = snowRange;
        });
        cloudSnow.geometry.verticesNeedUpdate = true;
        //cloudSnow.position.set(camera.position.x,camera.position.y,camera.position.z);
        if(enableView ==1) {
            cloudSnow.position.set(0, 0, -disSnow);
        }
        renderer.render(scene,camera);
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderRain();
        renderSnow();
        renderer.setSize(window.innerWidth,window.innerHeight);
    }

    function animate() {
        controls.update();
        renderRain();
        renderSnow();
        stats.update();
        requestAnimationFrame(animate);
    }

    function draw(){
        //出口函数
        initRender()
        initScene();
        initCamera();
        initLight();
        initModel();
        initControls();
        initStats();
        initGuiRain();
        initGuiSnow();
        animate();
        window.onresize = onWindowResize();
    }
</script>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值