半小时学会制作三维扩散光圈(three.js实战2)

Posted 点燃火柴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了半小时学会制作三维扩散光圈(three.js实战2)相关的知识,希望对你有一定的参考价值。

1.demo效果

在这里插入图片描述
在这里插入图片描述

2. 实现思路

使用CylinderGeometry创建圆柱,圆柱的顶面和底面隐藏,侧面使用纹理贴图材质。在render函数中,使圆柱的半径不断变大,使圆柱的材质可见度不断降低,从而实现扩散的光圈效果

3. 实现要点

3.1 创建圆柱

  • 创建圆柱几何体
    使用THREE.CylinderGeometry类创建圆柱几何体

  • 创建圆柱材质
    这里分别创建圆柱的侧面、顶面和底面的材质,放到一个数组中,侧面材质使用加载的纹理作为纹理贴图,是否透明属性transparent设置为true;顶面和底面的材质的opacity属性设置为0,表示不可见。

  • 创建圆柱网格对象
    使用上面创建的几何体和材质使用THREE.Mesh直接创建即可,然后添加到场景中

示例代码如下

//创建圆柱
let geometry = new THREE.CylinderGeometry(4, 4, 4, 64);

//加载纹理
let texture = new THREE.TextureLoader().load('../assets/textures/texture01.png');
texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复
texture.repeat.set(1, 1);
texture.needsUpdate = true;

let materials = [
  //圆柱侧面材质,使用纹理贴图
  new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.DoubleSide,
    transparent: true
  }),
  //圆柱顶材质
  new THREE.MeshBasicMaterial({
    transparent: true,
    opacity: 0,
    side: THREE.DoubleSide
  }),
  //圆柱底材质
  new THREE.MeshBasicMaterial({
    transparent: true,
    opacity: 0,
    side: THREE.DoubleSide
  })
];
cylinderMesh = new THREE.Mesh(geometry, materials);

scene.add(cylinderMesh);

3.2 圆柱扩散动画

这里定义一个记录圆柱半径的cylinderRadius变量,和记录材质可见度的变量,然后半径不断扩大,可见度不断降低,让后把这两个变化的属性设置到圆柱对象上,最后在render中调用该函数即可

let cylinderRadius = 0;
let cylinderOpacity= 1;
//圆柱光圈扩散动画
function cylinderAnimate() {
  cylinderRadius += 0.01;
  cylinderOpacity-= 0.003;
  if (cylinderRadius > 4) {
    cylinderRadius = 0;
    cylinderOpacity= 1;
  }
  if (cylinderMesh) {
    cylinderMesh.scale.set(1 + cylinderRadius, 1, 1 + cylinderRadius); //圆柱半径增大
    cylinderMesh.material[0].opacity = cylinderOpacity; //圆柱可见度减小
  }
}

4. demo代码

<!DOCTYPE html>

<html>

<head>
  <title>光圈扩散</title>
  <script type="text/javascript" src="../three/build/three.js"></script>
  <script type="text/javascript" src="../three/examples/js/controls/OrbitControls.js"></script>
  <script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>

<body>

  <div id="Stats-output"></div>
  <div id="WebGL-output"></div>

  <script type="text/javascript">
    var scene, camera, renderer, cylinderMesh, stats, controls, clock;

    function initScene() {
      scene = new THREE.Scene();
      //用一张图加载为纹理作为场景背景
      scene.background = new THREE.TextureLoader().load("../assets/textures/starry-deep-outer-space-galaxy.jpg");
    }

    function initCamera() {
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(20, 30, 50);
      camera.lookAt(new THREE.Vector3(0, 0, 0));
    }

    function initLight() {
      //添加环境光
      var ambientLight = new THREE.AmbientLight(0x0c0c0c);
      scene.add(ambientLight);

      //添加聚光灯
      var spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(-40, 60, -10);
      spotLight.castShadow = true;
      scene.add(spotLight);
    }

    function initModel() {

      //创建圆柱
      let geometry = new THREE.CylinderGeometry(4, 4, 4, 64);

      //加载纹理
      let texture = new THREE.TextureLoader().load('../assets/textures/texture01.png');
      texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复
      texture.repeat.set(1, 1);
      texture.needsUpdate = true;

      let materials = [
        //圆柱侧面材质,使用纹理贴图
        new THREE.MeshBasicMaterial({
          map: texture,
          side: THREE.DoubleSide,
          transparent: true
        }),
        //圆柱顶材质
        new THREE.MeshBasicMaterial({
          transparent: true,
          opacity: 0,
          side: THREE.DoubleSide
        }),
        //圆柱底材质
        new THREE.MeshBasicMaterial({
          transparent: true,
          opacity: 0,
          side: THREE.DoubleSide
        })
      ];
      cylinderMesh = new THREE.Mesh(geometry, materials);

      scene.add(cylinderMesh);

      initPlane()

    }

    //创建底面
    function initPlane() {
      const planeGeometry = new THREE.PlaneGeometry(50, 50, 1, 1); //创建一个平面几何对象

      //材质
      const planeMaterial = new THREE.MeshLambertMaterial({
        color: 0x080631,
        transparent: true,
        opacity: 0.8
      });
      const plane = new THREE.Mesh(planeGeometry, planeMaterial);


      //设置平面位置
      plane.rotation.x = -0.5 * Math.PI;
      plane.position.set(0, -2, 0);

      //平面添加到场景中
      scene.add(plane);
    }

    //初始化渲染器
    function initRender() {
      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      });
      renderer.setClearColor(0x111111, 1); //设置背景颜色
      renderer.setSize(window.innerWidth, window.innerHeight);
      //renderer.shadowMap.enabled = true; //显示阴影
      document.getElementById("WebGL-output").appendChild(renderer.domElement);
    }
    //初始化轨道控制器
    function initControls() {
      clock = new THREE.Clock(); //创建THREE.Clock对象,用于计算上次调用经过的时间
      controls = new THREE.OrbitControls(camera, renderer.domElement);
      //controls.autoRotate = true; //是否自动旋转
    }

    let cylinderRadius = 0;
    let cylinderOpacity = 1;
    //圆柱光圈扩散动画
    function cylinderAnimate() {
      cylinderRadius += 0.01;
      cylinderOpacity -= 0.003;
      if (cylinderRadius > 4) {
        cylinderRadius = 0;
        cylinderOpacity = 1;
      }
      if (cylinderMesh) {
        cylinderMesh.scale.set(1 + cylinderRadius, 1, 1 + cylinderRadius); //圆柱半径增大
        cylinderMesh.material[0].opacity = cylinderOpacity; //圆柱可见度减小
      }
    }

    //性能监控
    function initStats() {
      stats = new Stats();
      stats.setMode(0); //0: fps, 1: ms
      document.getElementById("Stats-output").appendChild(stats.domElement);
    }

    function render() {

      cylinderAnimate(); //圆柱光圈扩散更新
      stats.update();
      const delta = clock.getDelta(); //获取自上次调用的时间差
      controls.update(delta) //控制器更新
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }

    //页面初始化
    function init() {
      initScene();
      initCamera();
      initLight();
      initModel();
      initRender();
      initStats();
      initControls();
      render();
    }

    window.onload = init;
  </script>
</body>

</html>

以上是关于半小时学会制作三维扩散光圈(three.js实战2)的主要内容,如果未能解决你的问题,请参考以下文章

既有方向又会动的线,包你学会制作按箭头方向流动的线(three.js实战3)

三维场景中创建镜面反射效果(three.js实战9)

三维空间中绘制点线面UV贴图,万能的BufferGeometry(three.js实战4)

三维空间中创建label标签(three.js实战7)

一篇文章教你在三维空间中创建流动线条(three.js实战1)

NLP学不会打我 半小时学会基本操作 11 Seq2Seq 代码实战