学习threejs,使用粒子实现下雪特效

👨‍⚕️ 主页: gis分享者

👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • [1.1 ☘️THREE.Points简介](#1.1 ☘️THREE.Points简介)
      • [1.11 ☘️THREE.PointsMaterial点云材质](#1.11 ☘️THREE.PointsMaterial点云材质)
  • 二、🍀使用粒子实现下雪特效
    • [1. ☘️实现思路](#1. ☘️实现思路)
    • [2. ☘️代码样例](#2. ☘️代码样例)

一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用粒子实现下雪特效,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.Points简介

当我们大量使用粒子时,会很快遇到性能问题,导致页面卡顿,这是因为每添加一个粒子就是一个模型,因为每个粒子对象分别由THREE.js进行管理,所以,three.js提供了另一种方式来处理大量粒子,那就是使用THREE.Points。通过THREE.Points,three.js不再需要管理大量的单个粒子对象,而只需管理THREE.Points实例即可。
创建方法:

var cloud = new THREE.Points(geom, material);

geom:THREE.Geometry对象,用于创建粒子对象

material:THREE.PointCloudMaterial 粒子云材质

1.11 ☘️THREE.PointsMaterial点云材质

概念

设置所有粒子的大小,颜色,顶点颜色,透明度,是否根据相机距离的远近改变大小等属性。

var material = new THREE.PointsMaterial({size: 4, vertexColors: true, color: 0xffffff});
属性

color: PointCloud中所有的粒子的颜色都相同,除非设置了vertexColors且该几何体的colors属性不为空,才会使用colors颜色,否则都使用该属性。

map:在粒子上应用某种材质。

size:粒子的大小。

sizeAnnutation:false,无论相机的位置,所有的粒子大小一致;true,离相机近的粒子更大一些,离相机越远越小。

vetexColors:true,且该几何体的colors属性有值,则该粒子会舍弃第一个属性--color,而应用该几何体的colors属性的颜色。

opacity:粒子透明度。

transparent:是否透明。

blending:渲染粒子时的融合模式。

fog:是否受场景的雾化影响。

二、🍀使用粒子实现下雪特效

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景
  • 3、初始化camera相机,定义相机位置 camera.position.set,定义相机方向lookAt。
  • 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.DirectionalLight平行光源,设置平行光源位置,scene添加平行光源。
  • 5、加载几何模型:添加THREE.AxesHelper坐标辅助工具,scene场景中加入坐标辅助工具。
  • 6、加入controls控制,加入gui控制,定义gui的redraw重绘方法,方法中生成15000个随机粒子,使用THREE.PointMaterial点云材质,该材质使用"snow.png"图片作为纹理,创建render下雨动画,使用requestAnimationFrame执行下雨动画。加入stats监控器,监控帧数信息。

2. ☘️代码样例

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>learn32(使用粒子实现下雪特效)</title>
    <script src="lib/threejs/91/three.js"></script>
    <script src="https://johnson2heng.github.io/three.js-demo/lib/js/controls/OrbitControls.js"></script>
    <script src="https://johnson2heng.github.io/three.js-demo/lib/js/libs/stats.min.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/libs/dat.gui.min.js"></script>
</head>
<style>
    html, body {
        margin: 0;
        height: 100%;
    }

    canvas {
        display: block;
    }
</style>
<body onload="draw()">
</body>
<script>
  var renderer
  var initRender = () => {
    renderer = new THREE.WebGLRenderer({antialias: true})
    renderer.setClearColor(new THREE.Color(0xffffff))
    renderer.setSize(window.innerWidth, window.innerHeight)
    document.body.appendChild(renderer.domElement)
  }
  var scene
  var initScene = () => {
    scene = new THREE.Scene()
  }
  var camera
  var initCamera = () => {
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 200)
    camera.position.set(0, 20, 100)
    camera.lookAt(new THREE.Vector3(0, 30, 0))
  }

  var light
  var initLight = () => {
    scene.add(new THREE.AmbientLight(0x404040))

    light = new THREE.DirectionalLight(0xffffff)
    light.position.set(1, 1, 1)
    scene.add(light)
  }

  var initModel = () => {
    var helper = new THREE.AxesHelper(500)
    scene.add(helper)
  }

  var stats
  var initStats = () => {
    stats = new Stats()
    document.body.appendChild(stats.dom)
  }

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

  var render = () => {
    //产生雨滴动画效果
    var vertices = cloud.geometry.vertices
    vertices.forEach(function (v) {
      v.y = v.y - (v.velocityY)
      v.x = v.x - (v.velocityX) * .5
      if (v.y <= -60) v.y = 60
      if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1
    })
    //设置实时更新网格的顶点信息
    cloud.geometry.verticesNeedUpdate = true
    renderer.render(scene, camera)
  }

  var gui, cloud
  var initGui = () => {
    gui = {
      "size": 2,
      "transparent": true,
      "opacity": 0.6,
      "vertexColors": true,
      "color": 0xffffff,
      "sizeAttenuation": true,
      "rotateSystem": false,
      redraw: function () {
        if (cloud) {
          scene.remove(cloud)
        }
        createParticles(gui.size, gui.transparent, gui.opacity, gui.vertexColors, gui.sizeAttenuation, gui.color)
        //设置是否自动旋转
        controls.autoRotate = gui.rotateSystem
      }
    }
    var datGui = new dat.GUI()
    //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)gui.add(controls, 'size', 0, 10).onChange(controls.redraw);
    datGui.add(gui, 'size',0.1,10).onChange(gui.redraw)
    datGui.add(gui, 'transparent').onChange(gui.redraw)
    datGui.add(gui, 'opacity', 0, 1).onChange(gui.redraw)
    datGui.add(gui, 'vertexColors').onChange(gui.redraw)
    datGui.addColor(gui, 'color').onChange(gui.redraw)
    datGui.add(gui, 'sizeAttenuation').onChange(gui.redraw)
    datGui.add(gui, 'rotateSystem').onChange(gui.redraw)

    gui.redraw()
  }
  var createParticles = (size, transparent, opacity, vertexColors, sizeAttenuation, color) => {
    var texture = new THREE.TextureLoader().load('data/img/snow.png')
    var geom = new THREE.Geometry()
    var material = new THREE.PointsMaterial({
      size: size,
      transparent: transparent,
      opacity: opacity,
      vertexColors: vertexColors,
      sizeAttenuation: sizeAttenuation,
      color: color,
      map: texture,
      depthTest: false  //设置解决透明度有问题的情况
    })

    var range = 120
    for (var i = 0; i < 15000; 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
      geom.vertices.push(particle)
      var color = new THREE.Color(0xffffff)
      //.setHSL ( h, s, l ) h --- 色调值在0.0和1.0之间 s --- 饱和值在0.0和1.0之间 l --- 亮度值在0.0和1.0之间。 使用HSL设置颜色。
      //随机当前每个粒子的亮度
      //color.setHSL(color.getHSL().h, color.getHSL().s, Math.random() * color.getHSL().l);
      geom.colors.push(color)
    }
    cloud = new THREE.Points(geom, material)
    cloud.verticesNeedUpdate = true
    scene.add(cloud)
  }
  var onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    render()
    render.setSize(window.innerWidth, window.innerHeight)
  }
  var animate = () => {
    render()
    stats.update()
    controls.update()
    requestAnimationFrame(animate)
  }
  var draw = () => {
    initRender()
    initScene()
    initCamera()
    initLight()
    initModel()
    initStats()
    initControls()
    initGui()

    animate()

    window.onresize = onWindowResize
  }
</script>
</html>

效果如下:

相关推荐
gis分享者2 天前
学习threejs,使用PointLight点光源
threejs·点光源·pointlight
gis分享者6 天前
学习threejs,使用HemisphereLight半球光
threejs·hemispherelight·半球光
gis分享者10 天前
学习threejs,使用Lensflare模拟镜头眩光
threejs·lensflare·眩光
gis分享者13 天前
学习threejs,tga格式图片文件贴图
threejs·贴图·tga·tgaloader
gis分享者14 天前
学习threejs,pvr格式图片文件贴图
threejs·贴图·pvr
gis分享者1 个月前
学习threejs,使用OrbitControls相机控制器
threejs·相机·相机控制器·orbitcontrols
不系舟1781 个月前
threejs 实现镜面反射,只反射指定物体,背景透明
threejs
gis分享者1 个月前
学习threejs,使用RollControls相机控制器
threejs·相机控制器·rollcontrols
gis分享者1 个月前
学习threejs,使用FlyControls相机控制器
threejs·相机控制器·flycontrols
gis分享者1 个月前
学习threejs,使用TrackballControls相机控制器
threejs·trackball·相机控制器