创建胶囊体和甜圈圈(three.js实战8)

Posted 点燃火柴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建胶囊体和甜圈圈(three.js实战8)相关的知识,希望对你有一定的参考价值。

1. demo效果

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

2. 实现过程

2.1 实现原理

完全对称的几何体可以通过一条样条曲线,扫描360度创建几何体。three.js提供的LatheGeometry类,只需要提供样条曲线的点集,就可以创建出demo中的几何体。

2.2 绘制胶囊体

在这里插入图片描述
上图为绘制胶囊体原理图
绘制胶囊体的样条曲线分为三部分,上半部分四分之一圆弧,中间一条直线,下半部分四分之一圆,接下来看看绘制过程

// 创建胶囊体
function createCapsule() {
  const radius = 4;
  const height = 18;
  // 存放样条曲线的点集
  const points = []

  //上半部分四分之一圆弧
  for (let i = Math.PI / 2; i > 0; i -= 0.1) {
    points.push(
      new THREE.Vector3(
        Math.cos(i) * radius,
        Math.sin(i) * radius + height / 2,
        0
      )
    )
  }

  //中间直线
  for (let i = height / 2; i > -height / 2; i -= 0.1) {
    points.push(
      new THREE.Vector3(
        radius,
        i,
        0
      )
    )
  }

  //下半部分四分之一圆弧
  for (let i = 0; i <= Math.PI / 2; i += 0.1) {
    points.push(
      new THREE.Vector3(
        Math.cos(i) * radius,
        -Math.sin(i) * radius - height / 2,
        0
      )
    )
  }

  // 补充一个点,去掉底部的小洞洞
  points.push(
    new THREE.Vector3(
      0,
      -radius - height / 2,
      0
    )
  )


  // 根据样条曲线创建扫描几何体
  const geom = new THREE.LatheGeometry(
    points,
    200,
    0,
    Math.PI * 2
  )


  // 创建材质
  const meshMaterial = new THREE.MeshPhongMaterial({
    side: THREE.DoubleSide,
    color: 0xfff000
  })
  const mesh = new THREE.Mesh(geom, meshMaterial)
  // 网格对象添加到场景中
  scene.add(mesh)
}

2.3 绘制甜圈圈

在这里插入图片描述
上图为绘制甜圈圈原理图
绘制甜圈圈的样条曲线就是一个圆,然后环绕Y轴旋转一周就可以绘制出几何体,具体如下

function createDoughnut() {
  const Radius = 10;
  const radius = 4;
  const height = 12;


  //绘制一个圆
  const curve = new THREE.EllipseCurve(
    0, 0, // ax, aY
    radius, radius, // xRadius, yRadius
    0, Math.PI * 2, // aStartAngle, aEndAngle
    false, // aClockwise
    0 // aRotation
  );

  const innerCirclePoints = curve.getPoints(100)


  // 存放样条曲线的点集
  const points = []
  innerCirclePoints.forEach(point => {
    point.x = point.x + Radius
    points.push(point)
  })



  //根据样条曲线创建扫描几何体
  const geom = new THREE.LatheGeometry(
    points,
    200,
    0,
    Math.PI * 2
  )


  // 创建材质
  const meshMaterial = new THREE.MeshPhongMaterial({
    color: 0x318eff,
    side: THREE.DoubleSide
  })
  const mesh = new THREE.Mesh(geom, meshMaterial)

  mesh.position.x = 30

  //添加到场景中
  scene.add(mesh)
}

3 demo代码

<!DOCTYPE html>

<html>

<head>
  <title>Example latheGeometry</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">
    let stats, controls;
    let camera, scene, renderer;

    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(55, window.innerWidth / window.innerHeight, 1, 20000);
      camera.position.set(20, 50, 100);
    }

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

      var spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(25, 30, 50);
      spotLight.castShadow = true;
      scene.add(spotLight);
    }


    function initModel() {
      createCapsule();
      createDoughnut();
    }

    // 创建胶囊体
    function createCapsule() {
      const radius = 4;
      const height = 18;
      // 存放样条曲线的点集
      const points = []

      //上半部分四分之一圆弧
      for (let i = Math.PI / 2; i > 0; i -= 0.1) {
        points.push(
          new THREE.Vector3(
            Math.cos(i) * radius,
            Math.sin(i) * radius + height / 2,
            0
          )
        )
      }

      //中间直线
      for (let i = height / 2; i > -height / 2; i -= 0.1) {
        points.push(
          new THREE.Vector3(
            radius,
            i,
            0
          )
        )
      }

      //下半部分四分之一圆弧
      for (let i = 0; i <= Math.PI / 2; i += 0.1) {
        points.push(
          new THREE.Vector3(
            Math.cos(i) * radius,
            -Math.sin(i) * radius - height / 2,
            0
          )
        )
      }

      // 补充一个点,去掉底部的小洞洞
      points.push(
        new THREE.Vector3(
          0,
          -radius - height / 2,
          0
        )
      )


      // 根据样条曲线创建扫描几何体
      const geom = new THREE.LatheGeometry(
        points,
        200,
        0,
        Math.PI * 2
      )


      // 创建材质
      const meshMaterial = new THREE.MeshPhongMaterial({
        side: THREE.DoubleSide,
        color: 0xfff000
      })
      const mesh = new THREE.Mesh(geom, meshMaterial)
      // 网格对象添加到场景中
      scene.add(mesh)
    }

    function createDoughnut() {
      const Radius = 10;
      const radius = 4;
      const height = 12;


      //绘制一个圆
      const curve = new THREE.EllipseCurve(
        0, 0, // ax, aY
        radius, radius, // xRadius, yRadius
        0, Math.PI * 2, // aStartAngle, aEndAngle
        false, // aClockwise
        0 // aRotation
      );

      const innerCirclePoints = curve.getPoints(100)


      // 存放样条曲线的点集
      const points = []
      innerCirclePoints.forEach(point => {
        point.x = point.x + Radius
        points.push(point)
      })



      //根据样条曲线创建扫描几何体
      const geom = new THREE.LatheGeometry(
        points,
        200,
        0,
        Math.PI * 2
      )


      // 创建材质
      const meshMaterial = new THREE.MeshPhongMaterial({
        color: 0x318eff,
        side: THREE.DoubleSide
      })
      const mesh = new THREE.Mesh(geom, meshMaterial)

      mesh.position.x = 30

      //添加到场景中
      scene.add(mesh)
    }

    function initRender() {

      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      })
      //renderer.shadowMap.enabled = true // 显示阴影
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearColor(0x0f2d48); //设置背景色
      renderer.toneMapping = THREE.ACESFilmicToneMapping;
      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 // 是否自动旋转
    }

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

    function render() {
      updateFun()
      requestAnimationFrame(render);
      renderer.render(scene, camera);

    }

    function updateFun() {
      stats.update();
      const delta = clock.getDelta() // 获取自上次调用的时间差
      controls.update(delta) // 相机更新

    }

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

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

</html>

以上是关于创建胶囊体和甜圈圈(three.js实战8)的主要内容,如果未能解决你的问题,请参考以下文章

绘制不断变色的台体,BufferGeometry和ShaderMaterial的黄金组合(three.js实战5)

十分钟快速实战Three.js

使用shader着色器程序创建扩散光圈效果(three.js实战10)

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

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

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