球体文字 ·Text Sphere· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么OrbitControls 相机轨道交互requestAnimationFrame渲染循环与resize自适应效果说明本案例演示球体文字效果基于 WebGL 实现「球体文字」可视化效果附完整可运行源码核心用到 OrbitControls。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念Scene / Camera / WebGLRenderer构成最小渲染闭环大场景可开logarithmicDepthBuffer缓解 Z-fighting。OrbitControls提供轨道旋转/缩放开启enableDamping后需在 animate 中controls.update()。阅读下方完整源码时建议从init/load/animate三条主线入手再深入 shader 与工具函数。实现步骤搭建 Scene、PerspectiveCamera、WebGLRenderer挂载 canvas 并处理resize创建 OrbitControls及 Raycaster 等交互控件若源码包含在requestAnimationFrame循环中更新状态并 renderCesium 为viewer.render或自动渲染代码要点import * as THREE from threeimport { 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.jsconst DOM document.getElementById(box) const scene new THREE.Scene() const camera new THREE.PerspectiveCamera(75, DOM.clientWidth / DOM.clientHeight, 0.1, 1000) camera.position.set(1, 2, 3) const renderer new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true }) renderer.setSize(DOM.clientWidth, DOM.clientHeight) DOM.appendChild(renderer.domElement) const controls new OrbitControls(camera, renderer.domElement) controls.enableDamping true controls.dampingFactor 0.01animate() function animate() { controls.update() renderer.render(scene, camera) requestAnimationFrame(animate) }window.onresize () { renderer.setSize(DOM.clientWidth, DOM.clientHeight) camera.aspect DOM.clientWidth / DOM.clientHeight camera.updateProjectionMatrix() }scene.add(new THREE.AxesHelper(1000))scene.add(new THREE.AmbientLight(0x404040, 5));let directionalLight new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.castShadow true; directionalLight.position.set(0, 50, 0);scene.add(directionalLight);const TEXT [ three.js, tres.js, react-three-fiber, cesium, javascript, html, babylon, webgl, glsl, shader, css, vue, vite, ];// 创建球体几何体 const radius 2; const segments 64; const rings 64; const geometry new THREE.SphereGeometry(radius, segments, rings);const widthSegments 32; // 横向细分段数 const heightSegments 32; // 纵向细分段数// 生成顶点数据 const positions []; for (let phiIndex 0; phiIndex heightSegments; phiIndex) { const phi (phiIndex * Math.PI) / heightSegments; for (let thetaIndex 0; thetaIndex widthSegments; thetaIndex) { const theta (thetaIndex2Math.PI) / widthSegments;// 计算点的坐标 const x radiusMath.sin(phi)Math.cos(theta); const y radiusMath.sin(phi)Math.sin(theta); const z radius * Math.cos(phi);positions.push(x, y, z); } }// 创建球体材质 const material new THREE.MeshBasicMaterial({ color: 0x00ff00, // 球体的颜色 transparent: true, // 开启透明 opacity: 0, // 设置透明度 });// 创建球体网格 const sphere new THREE.Mesh(geometry, material); scene.add(sphere);const font await new Promise((resolve) new FontLoader().load(https://z2586300277.github.io/three-editor/dist/files/font/cn1.json, (f) resolve(f)))const totalCount positions.length;const savePos []; const textMeshes []; // 存储文本网格的数组// 创建并布局文本网格 for (let i 0; i totalCount; i 3) { const x positions[i]; const y positions[i 1]; const z positions[i 2];const pos new THREE.Vector3(x, y, z);// 遍历文本数组 const index THREE.MathUtils.randInt(0, TEXT.length - 1); const textGeometry new TextGeometry(TEXT[index], { font, size: 0.1 /字体大小/, depth: 0.001 /文本厚度/, curveSegments: 1 /曲线点数 (5降低优化性能)/, bevelEnabled: true /是否开启斜角/, bevelThickness: 0.001 /斜角深度/, bevelSize: 0.001 /斜角与原始文本轮廓之间的延伸距离/, bevelSegments: 1 /斜角的分段数 (3降低优化性能)/, bevelOffset: 0 /斜角偏移/, });// 计算文本几何体的边界框 textGeometry.computeBoundingBox();if (textGeometry) { // 根据文本几何体计算布局位置 const textWidth textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x; const textHeight textGeometry.boundingBox.max.y - textGeometry.boundingBox.min.y; const textCenterX -textWidth / 2; const textCenterY -textHeight / 2; // 平移到球体表面 textGeometry.translate(textCenterX, textCenterY, 0);// 创建文本网格 const textMaterial new THREE.MeshBasicMaterial({ color: 0xffffff }); // 使用基础材质 const textMesh new THREE.Mesh(textGeometry, textMaterial);// 获取球体表面的法线向量 const normal new THREE.Vector3(pos.x, pos.y, pos.z).normalize(); // 将文本网格平移到球体表面 textMesh.position.copy(normal.multiplyScalar(radius));// 调整文字朝向球心 textMesh.lookAt(new THREE.Vector3(pos.x2, pos.y2, pos.z * 2));const isClose savePos.some( (p) p.distanceTo(textMesh.position) 0.8 ); // 根据距离调整密度因子 if (!isClose) { // 将文本网格添加到球体上 sphere.add(textMesh); // 存储文本网格到数组中 textMeshes.push(textMesh); savePos.push(textMesh.position); } } }完整源码GitHub小结本文提供球体文字完整 Three.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库