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

Posted 点燃火柴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三维空间中创建label标签(three.js实战7)相关的知识,希望对你有一定的参考价值。

1. demo效果

在这里插入图片描述
在这里插入图片描述
如上图,demo中使用CSS2DRenderer创建label,在物体运动中始终保持面向相机,缩放中也正常显示

2. CSS2DRenderer使用流程

2.1 相关文件引入

只需要通过script标签引入CSS2DRenderer文件即可

<script type="text/javascript" src="../three/examples/js/renderers/CSS2DRenderer.js"></script>

2.2 创建CSS2DRenderer渲染器

普通的three.js示例中只需要创建WebGLRenderer渲染器来渲染图形,这一次除了创建WebGLRenderer渲染器还需要创建CSS2DRenderer渲染器,创建过程如下:

//创建CSS2DRenderer渲染器
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
document.getElementById("WebGL-output").appendChild(labelRenderer.domElement);

注意!!! 在使用轨道控制器OrbitControls时,需要将原来绑定在WebGLRenderer的DOM改为绑定在CSS2DRenderer的DOM上,否则轨道控制器无法正常使用

controls = new THREE.OrbitControls(camera, labelRenderer.domElement)

2.3 为Mesh对象添加label

demo分别为地球和月球添加了label,以添加地球的label为例说明一下,首先创建了一个div标签,然后设置该标签的类名、文字、和行内样式。之后使用这个div创建CSS2DObject对象earthLabel,CSS2DObject封装在我们引入的CSS2DRenderer.js中,最后设置earthLabel的位置并添加的Mesh对象earthMesh上

//添加label
const earthDiv = document.createElement('div');
earthDiv.className = 'label';
earthDiv.textContent = '地球';
earthDiv.style.marginTop = '-1em';
earthDiv.style.background = 'none';
const earthLabel = new THREE.CSS2DObject(earthDiv);
earthLabel.position.set(0, earchRadius, 0);
earthMesh.add(earthLabel);

2.4 在render函数中更新CSS2DRenderer对象

与WebGLRenderer一样都需要在render函数中更新,更新方法如下

labelRenderer.render(scene, camera);

3. demo代码

<!DOCTYPE html>

<html>

<head>
  <title>Example 07 - CSS2DRenderer-label</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/renderers/CSS2DRenderer.js"></script>
  <script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script>


  <style>
    body {
      margin: 0;
      overflow: hidden;
    }

    .label {
      color: #FFF;
      font-family: sans-serif;
      padding: 2px;
      background: rgba(0, 0, 0, .6);
    }
  </style>
</head>

<body>

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

  <script type="text/javascript">
    let stats, controls;
    let camera, scene, renderer, labelRenderer;
    let earthMesh, marsMesh;

    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() {
      createEarthMesh();
      createMarshMesh();
    }


    function createMarshMesh() {
      const moonRadius = 4;
      var geom = new THREE.SphereGeometry(moonRadius, 40, 40)
      var planetTexture = new THREE.TextureLoader().load("../assets/textures/planets/Mars_2k-050104.png");
      var normalTexture = new THREE.TextureLoader().load("../assets/textures/planets/Mars-normalmap_2k.png");

      var planetMaterial = new THREE.MeshPhongMaterial();
      planetMaterial.normalMap = normalTexture;
      planetMaterial.map = planetTexture;
      // planetMaterial.shininess = 150;

      marsMesh = new THREE.Mesh(geom, planetMaterial);
      marsMesh.position.set(18, 3, -80)
      scene.add(marsMesh)

      //添加label
      const moonDiv = document.createElement('div');
      moonDiv.className = 'label';
      moonDiv.textContent = '月球';
      moonDiv.style.marginTop = '-1em';
      moonDiv.style.background = 'none';
      const moonLabel = new THREE.CSS2DObject(moonDiv);
      moonLabel.position.set(0, moonRadius, 0);
      marsMesh.add(moonLabel);
    }

    function createEarthMesh() {
      const earchRadius = 10
      var geom = new THREE.SphereGeometry(earchRadius, 40, 40)
      var planetTexture = new THREE.TextureLoader().load("../assets/textures/planets/Earth.png");
      var specularTexture = new THREE.TextureLoader().load("../assets/textures/planets/EarthSpec.png");
      var normalTexture = new THREE.TextureLoader().load("../assets/textures/planets/EarthNormal.png");


      var planetMaterial = new THREE.MeshPhongMaterial();
      planetMaterial.specularMap = specularTexture;
      planetMaterial.specular = new THREE.Color(0x4444aa);


      planetMaterial.normalMap = normalTexture;
      planetMaterial.map = planetTexture;
      //               planetMaterial.shininess = 150;

      earthMesh = new THREE.Mesh(geom, planetMaterial);
      scene.add(earthMesh);

      //添加label
      const earthDiv = document.createElement('div');
      earthDiv.className = 'label';
      earthDiv.textContent = '地球';
      earthDiv.style.marginTop = '-1em';
      earthDiv.style.background = 'none';
      const earthLabel = new THREE.CSS2DObject(earthDiv);
      earthLabel.position.set(0, earchRadius, 0);
      earthMesh.add(earthLabel);
    }

    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);

      //创建CSS2DRenderer渲染器
      labelRenderer = new THREE.CSS2DRenderer();
      labelRenderer.setSize(window.innerWidth, window.innerHeight);
      labelRenderer.domElement.style.position = 'absolute';
      labelRenderer.domElement.style.top = '0px';
      document.getElementById("WebGL-output").appendChild(labelRenderer.domElement);
    }
    //初始化轨道控制器
    function initControls() {
      clock = new THREE.Clock() // 创建THREE.Clock对象,用于计算上次调用经过的时间
      controls = new THREE.OrbitControls(camera, labelRenderer.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);
      labelRenderer.render(scene, camera);
      renderer.render(scene, camera);

    }

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

      const elapsed = clock.getElapsedTime();

      marsMesh.position.set(Math.sin(elapsed) * 50, 0, Math.cos(elapsed) * 50);
      marsMesh.rotation.y += 0.01
    }

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

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

</html>

以上是关于三维空间中创建label标签(three.js实战7)的主要内容,如果未能解决你的问题,请参考以下文章

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

在Three.js中创建一个CubeGrid

在three.js中动态创建二维文本

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

前端库

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