threejs+vue3+js旋转词云

发布于:2024-12-18 ⋅ 阅读:(94) ⋅ 点赞:(0)

title: threejs
date: 2024-12-11 09:50:41
tags: threes

Threejs

双行可展示旋转词云显示。

一、简单案例——旋转球体

以下代码使用vue3+js+threejs技术站进行的搭建,其中包含了场景创建、相机创建、渲染器创建、物体材创建等相关流程,构建了一个简单的立体球效果

笔记

<template>
  <div class="app-container">
    <div ref="threeJsContainer" class="three-container"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
import { render } from "less";

//1.three创建场景
const scene = new THREE.Scene();

//2.创建相机(透视相机,有近大远小的效果)
const camera = new THREE.PerspectiveCamera(
  45, //视角,越大视野越大
  window.innerWidth / window.innerHeight, //宽高比
  0.1, //近平面(相机最近能看到的物体是什么)
  1000 //远平面(相机最远能看到的物体是什么)
);

//3.创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight); //设置渲染的宽高
document.body.appendChild(renderer.domElement); //将画布加载到body当中

//4.创建几何体
// const geometry = new THREE.BoxGeometry(1, 1, 1);
const geometry = new THREE.SphereGeometry(1, 32, 32);

//5.创建材质
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
//设置父元素材质为线框模式
material.wireframe = true;

//6.创建网格(创建物体)
const cube = new THREE.Mesh(geometry, material);
cube.position.set(2, 0, 0); //局部坐标,依赖与父亲元素,相对父元素的位置
cube.scale.set(2, 2, 2); //设置立方体的放大(xyz轴都放大两倍),相对于父元素来说
cube.rotation.x = Math.PI / 4; //180/4=45度(物体本身旋转的角度)但是要是父元素旋转了45度,那么字元素也会45+45旋转

//7.将网格添加到场景中
scene.add(cube);

//8.设置相机位置
camera.position.z = 5;
camera.position.y = 2;
camera.lookAt(0, 0, 0); //相机看向原点,默认也是原点

//添加坐标辅助器(用于感知物体的位置)
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper); //将坐标系添加到场景当中

//添加轨道控制器(可以拉远缩近查看)
const controls = new OrbitControls(camera, renderer.domElement);
//设置带阻尼的惯性(让滑动物体之后不会马上停下来)
controls.enableDamping = true; //自动旋转
controls.dampingFactor = 0.05; //设置阻尼系数,越大惯性月小

//渲染函数
function animate() {
  controls.update(); //调用轨道控制器可以拉大或者减小相关的图形
  requestAnimationFrame(animate);
  //旋转
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  //渲染
  renderer.render(scene, camera);
}

//执行相关的动画函数
animate();

//监听窗口的变化,完成自适应操作
window.addEventListener("resize", () => {
  //重置渲染器宽高比
  renderer.setSize(window.innerWidth, window.innerHeight);
  //重置相机宽高比
  camera.aspect = window.innerHeight / window.innerHeight;
  //更新相机的投影矩阵
  camera.updateProjectionMatrix();
});
</script>

<style scoped>
* {
  margin: 0;
  padding: 0;
}

canvas {
  display: block;
  position: fixed;
  left: 0;
  top: 90px;
  width: 100%;
  height: 100%;
}
</style>

二、简单案例

单行旋转词云

笔者这个案例的文档使用的是官方提供的在线json地址,优点是简单方便,缺点是不支持中文显示。

在线json文库:“https://threejs.org/examples/fonts/helvetiker_regular.typeface.json”

只展示了name这一个单行属性。

<template>
  <div class="container">
    <div ref="threeContainer" class="three-container"></div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import * as THREE from "three";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

const threeContainer = ref(null);

onMounted(() => {
  /** 创建场景、摄像机、渲染器 */
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(
    100, //视角越大视野越大
    window.innerWidth / window.innerHeight,
    0.1, //相机能看到的恶最近的距离
    1500 //相机能看到的最远的距离
  );
  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setClearAlpha(0); // 设置清除颜色为透明
  threeContainer.value.appendChild(renderer.domElement); //将画布加载到元素中

  // 创建轨道控制器
  const controls = new OrbitControls(camera, renderer.domElement);
  // controls.enableDamping = true; //停后自动旋转
  controls.dampingFactor = 0.05; //设置阻尼系数,越大惯性月小
  controls.enablePan = false; // 禁用平移
  controls.enableRotate = false; // 禁用旋转
  controls.enableZoom = true; // 启用缩放

  //添加坐标辅助器(用于感知物体的位置)
  const axesHelper = new THREE.AxesHelper(5);
  scene.add(axesHelper); //将坐标系添加到场景当中

  function createTextMaterial(color) {
    return new THREE.MeshBasicMaterial({
      color: color, // 指定颜色
      side: THREE.FrontSide, // 只渲染正面
    });
  }
  const fontLoader = new FontLoader();
  fontLoader.load(
    "https://threejs.org/examples/fonts/helvetiker_regular.typeface.json",
    (font) => {
      const sphereRadius = 290;

      const dataList = [
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "测试数据" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Three.js" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "测试数据" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
        { name: "Mapping" },
        { name: "Hello" },
        { name: "World" },
        { name: "Three.js" },
        { name: "Sphere" },
        { name: "Text" },
      ];

      // 创建一个函数来生成文本几何体
      function createTextMesh(text, color) {
        const textGeometry = new TextGeometry(text, {
          font: font,
          size: 6, // 字体大小
          height: 2, // 字体深度
        });
        const textMaterial = new THREE.MeshBasicMaterial({ color: color });
        const textMesh = new THREE.Mesh(textGeometry, textMaterial);
        return textMesh;
      }

      dataList.forEach((item, index) => {
        // const textGeometry = new TextGeometry(item.name, {
        //   font: font,
        //   size: 6, // 增加字体大小
        //   height: 2, // 增加字体深度
        // });

        // 创建一个组来放置name和id文本
        const group = new THREE.Group();

        // 创建name文本
        const nameMesh = createTextMesh(item.name, "#cccccc");
        nameMesh.position.set(0, 0, 0); // 设置name文本的位置
        group.add(nameMesh);

        // 创建id文本
        const idMesh = createTextMesh(item.id.toString(), "#cccccc");
        idMesh.position.set(0, -10, 0); // 设置id文本的位置,使其与name文本不在同一行
        group.add(idMesh);

        // 设置组的整体位置
        const phi = Math.acos(-1 + (2 * index) / dataList.length);
        const theta = Math.sqrt(dataList.length * Math.PI) * phi;
        group.position.setFromSphericalCoords(sphereRadius, phi, theta);

        //设置文字,创建文字
        // const phi = Math.acos(-1 + (2 * index) / dataList.length);
        // const theta = Math.sqrt(dataList.length * Math.PI) * phi;
        // const textColor = item.color || "#cccccc"; // 可以从数据项中获取颜色,或者使用默认颜色
        // const textMaterial = createTextMaterial(textColor);
        // const textMesh = new THREE.Mesh(textGeometry, textMaterial);

        // textMesh.position.setFromSphericalCoords(sphereRadius, phi, theta);
        // scene.add(textMesh);
        textMesh.lookAt(0, 0, 1000);
      });

      scene.rotation.x += Math.PI / 4;
      // 设置相机位置
      camera.position.set(-100, 0, 450);

      function animate() {
        requestAnimationFrame(animate);
        scene.rotation.y += 0.003;
        // scene.rotation.x += 0.002;
        // scene.rotation.z += 0.005;
        // 更新轨道控制器
        // 更新文字朝向摄像机
        dataList.forEach((item, index) => {
          const textMesh = scene.children[index]; // 假设场景中的每个子对象都是文本网格
          textMesh.lookAt(-200, 0, 800); // 使文字网格始终面向摄像机
        });
        controls.update();
        renderer.render(scene, camera);
      }

      animate();

      //监听窗口的变化,完成自适应操作
      // window.addEventListener("resize", () => {
      //   //重置渲染器宽高比
      //   renderer.setSize(window.innerWidth, window.innerHeight);
      //   //重置相机宽高比
      //   camera.aspect = window.innerHeight / window.innerHeight;
      //   //更新相机的投影矩阵
      //   camera.updateProjectionMatrix();
      // });
    }
  );
});
</script>

<style scoped>
.container {
  background: url(https://s3.bmp.ovh/imgs/2024/12/12/7143be5923fe6929.png);
  background-size: cover;
  text-align: center;
}
.three-container {
  margin-left: 100px;
  width: 100%;
  height: 90vh;
  overflow: hidden;
}
</style>

三、简单案例——双行旋转词云

这个双行球形词云每个元素显示两行,一行显示id,一行显示name,效果图如开始的图案所示。

由于官方提供的在线链接不支持中文,笔者将相关要使用的字体文件上传到了百度云盘,字体是仿宋字体。

通过网盘分享的文件:FangSong_Regular.zip
链接: https://pan.baidu.com/s/1-eL2SfFMA1xcrUYZtTVgwA?pwd=2025 提取码: 2025

<template>
  <div class="container">
    <div class="left-container">
      <el-button @click="changeSpeed">控制速度按钮</el-button>
    </div>
    <div ref="threeContainer" class="three-container"></div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import * as THREE from "three";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
const status = ref(false)

const threeContainer = ref(null);

onMounted(() => {

  /** 创建场景、摄像机、渲染器 */
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(
    83, //视角越大视野越大
    1000 / 800,
    0.1, //相机能看到的恶最近的距离
    1500 //相机能看到的最远的距离
  );
  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(1000, 800);
  renderer.setClearAlpha(0); // 设置清除颜色为透明
  threeContainer.value.appendChild(renderer.domElement); //将画布加载到元素中

  // 创建轨道控制器
  const controls = new OrbitControls(camera, renderer.domElement);
  // controls.enableDamping = true; //停后自动旋转
  controls.dampingFactor = 0.05; //设置阻尼系数,越大惯性月小
  controls.enablePan = false; // 禁用平移
  controls.enableRotate = false; // 禁用旋转
  controls.enableZoom = true; // 启用缩放

  //添加坐标辅助器(用于感知物体的位置)
  // const axesHelper = new THREE.AxesHelper(5);
  // scene.add(axesHelper); //将坐标系添加到场景当中

  const fontLoader = new FontLoader();
  fontLoader.load(
    "https://threejs.org/examples/fonts/helvetiker_regular.typeface.json",
    (font) => {
      const sphereRadius = 300;

      const dataList = [
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
        { name: "World", id: "123swwww" },
        { name: "Three.js", id: "123swwww" },
        { name: "Sphere", id: "123swwww" },
        { name: "Text", id: "123swwww" },
        { name: "Mapping", id: "123swwww" },
        { name: "Hello", id: "123swwww" },
      ];

      // 创建一个函数来生成文本几何体
      function createTextMesh(text, color) {
        const textGeometry = new TextGeometry(text, {
          font: font,
          size: 6, // 字体大小
          height: 1, // 字体深度
        });
        const textMaterial = new THREE.MeshBasicMaterial({ color: color });
        const textMesh = new THREE.Mesh(textGeometry, textMaterial);
        return textMesh;
      }

      dataList.forEach((item, index) => {
        // 创建一个组来放置name和id文本
        const group = new THREE.Group();

        // 创建name文本
        const nameMesh = createTextMesh(item.name, "#cccccc");
        nameMesh.position.set(0, 0, 0); // 设置name文本的位置
        group.add(nameMesh);

        // 创建id文本
        const idMesh = createTextMesh(item.id.toString(), "#cccccc");
        idMesh.position.set(-10, -10, 0); // 设置id文本的位置,使其与name文本不在同一行
        group.add(idMesh);

        // 设置组的整体位置
        const phi = Math.acos(-1 + (2 * index) / dataList.length);
        const theta = Math.sqrt(dataList.length * Math.PI) * phi;

        group.position.setFromSphericalCoords(sphereRadius, phi, theta);
        scene.add(group);
        group.lookAt(0, 0, 500);
      });

      scene.rotation.z += Math.PI / 3;

      // 设置相机位置
      camera.position.set(0, 0, 500);

      function animate() {
        requestAnimationFrame(animate);
        scene.rotation.y += 0.007;
        // 更新轨道控制器
        // 更新文字朝向摄像机
        dataList.forEach((item, index) => {
          const textMesh = scene.children[index]; // 假设场景中的每个子对象都是文本网格
          textMesh.lookAt(0, 0, 500); // 使文字网格始终面向摄像机
        });
        controls.update();
        renderer.render(scene, camera);
      }

      animate();
    }
  );
});
</script>

<style scoped>
.container {
  background: url(https://s3.bmp.ovh/imgs/2024/12/12/7143be5923fe6929.png);
  background-size: cover;
  text-align: center;
  width: 100%;
  display: flex;

  .left-container {
    width: 350px;
  }

  .three-container {
    width: 1000px;
    height: 92vh;
    overflow: hidden;
    /* background-color: aquamarine; */
  }
}
</style>


网站公告

今日签到

点亮在社区的每一天
去签到