【问题标题】:How can i wrap a text arround 3D sphere如何在 3D 球体周围环绕文本
【发布时间】:2019-06-26 03:21:17
【问题描述】:

我正在寻找一种将文本环绕在 babylon 或threejs 中的球体的方法。我对改变 javascript 技术持开放态度

【问题讨论】:

  • 到目前为止你尝试了什么?
  • 我都试过了。巴比伦是我最先进的threejs。我已经成功地将图像定义为纹理。但我想在没有纹理的球体上写字
  • 请提供您迄今为止为解决问题所做的尝试以及您遇到的具体障碍

标签: javascript three.js 3d babylonjs


【解决方案1】:

我会看an example of generating text。然后我会分别生成每个字母,记录它们各自的宽度,并使用这些来计算我想要显示的字符串的总宽度

然后我可以将每个网格作为 Object3D 的父对象,并将 Object3D 的旋转 y 设置为

widthSoFar = 0;
for each letter
   obj3d.rotation.y = widthSoFar / totalWidth * Math.PI * 2;
   widthSoFar += widthOfCurrentLetter;

并将字母的 position.z 设置为某个半径,使字母围绕一个圆圈。

什么半径?

circumference = 2 * PI * radius

所以

radius = circumference / (2 * PI)

我们知道我们需要的周长,就是字符串的总宽度。

您可能会发现this tutorial 有助于了解如何使用场景图节点(如 Object3D 节点)来组织场景以满足您的需求。

'use strict';

/* global THREE */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 40;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 1000;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 70;

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('black');

  function addLight(...pos) {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(...pos);
    scene.add(light);
  }
  addLight(-4, 4, 4);
  addLight(5, -4, 4);

  const lettersTilt = new THREE.Object3D();
  scene.add(lettersTilt);
  lettersTilt.rotation.set(
     THREE.Math.degToRad(-15),
     0,
     THREE.Math.degToRad(-15));
  const lettersBase = new THREE.Object3D();
  lettersTilt.add(lettersBase);
  {
    const letterMaterial = new THREE.MeshPhongMaterial({
      color: 'red',
    });  
    const loader = new THREE.FontLoader();
    loader.load('https://threejsfundamentals.org/threejs/resources/threejs/fonts/helvetiker_regular.typeface.json', (font) => {
      const spaceSize = 1.0;
      let totalWidth = 0;
      let maxHeight = 0;
      const letterGeometries = {
        ' ': { width: spaceSize, height: 0 }, // prepopulate space ' '
      };
      const size = new THREE.Vector3();
      const str = 'threejs fundamentals ';
      const letterInfos = str.split('').map((letter, ndx) => {
        if (!letterGeometries[letter]) {
          const geometry = new THREE.TextBufferGeometry(letter, {
            font: font,
            size: 3.0,
            height: .2,
            curveSegments: 12,
            bevelEnabled: true,
            bevelThickness: 0.5,
            bevelSize: .3,
            bevelSegments: 5,
          });
          geometry.computeBoundingBox();
          geometry.boundingBox.getSize(size);
          letterGeometries[letter] = {
            geometry,
            width: size.x / 2, // no idea why size.x is double size
            height: size.y,
          };
        }
        const {geometry, width, height} = letterGeometries[letter];
        const mesh = geometry
            ? new THREE.Mesh(geometry, letterMaterial)
            : null;
        totalWidth += width;
        maxHeight = Math.max(maxHeight, height);
        return {
          mesh,
          width,
        };
      });
      let t = 0;
      const radius = totalWidth / Math.PI;
      for (const {mesh, width} of letterInfos) {
        if (mesh) {
          const offset = new THREE.Object3D();
          lettersBase.add(offset);
          offset.add(mesh);
          offset.rotation.y = t / totalWidth * Math.PI * 2;
          mesh.position.z = radius;
          mesh.position.y = -maxHeight / 2;
        }
        t += width;
      }
      {
        const geo = new THREE.SphereBufferGeometry(radius - 1, 32, 24);
        const mat = new THREE.MeshPhongMaterial({
         color: 'cyan',
        });
        const mesh = new THREE.Mesh(geo, mat);
        scene.add(mesh);
      }
      camera.position.z = radius * 3;
    });
  }

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    lettersBase.rotation.y = time * -0.5;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
<canvas id="c"></canvas>
  <script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>

【讨论】:

  • 这真的很有用,并且帮助我掌握了如何在threejs中添加字母。我想知道是否有办法为字母本身添加一些曲率 - 我注意到了单个字母是“扁平的”,它们不完全适合地球/圆形。我查看了为形状添加曲率的教程,但我很难让它在字母上起作用。
  • 围绕圆柱体弯曲几何的数学公式是here。与其在着色器中进行,不如将数学应用于每个字母的buffergyeometry,尽管我想您也可以尝试在着色器中进行。
  • TextBufferGeometry 有一个错误,似乎该属性已从 threejs 中删除。这就是我使用 TextGeometry 的原因。也许它对某人有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-25
  • 1970-01-01
相关资源
最近更新 更多