尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Three.js 3D地球可视化实战:卫星轨道与数据标注的配置与验证

发布时间:2026/9/26 17:36:35

资讯中心
01
ARTICLE

Three.js 3D地球可视化实战:卫星轨道与数据标注的配置与验证

Three.js 3D地球可视化实战:卫星轨道与数据标注的配置与验证
1. 从一张贴图球到可交互地球这个场景到底在做什么Three.js 做 3D 地球可视化很多人第一步就卡在「球转起来了但卫星轨道和数据标注怎么接上去」。这篇就围绕两个核心模块展开卫星轨道绘制和数据标注跟随。你最终会得到一个能在浏览器里跑起来的原型——地球自转、卫星沿椭圆轨道运动、标注点跟着卫星在屏幕上移动点击还能弹出信息。适合谁看有基础 JavaScript 经验、用过 Three.js 创建过简单场景、想往航天/地理数据可视化方向做的开发者。不需要图形学背景但需要你能看懂 Vector3、相机投影这些基础概念。我试过用纯 Canvas 2D 画轨道再叠加到 3D 场景上结果坐标对不上、缩放就错位。后来统一用 Three.js 的世界坐标转屏幕坐标方案标注跟随才稳定下来。下面按「场景初始化 → 轨道参数 → 标注锚点 → 浏览器验证」的顺序走每一步都给可复制的配置。核心检索词先明确Three.js 3D 地球可视化、卫星轨道、数据标注。这三个词贯穿全文你照着配就能跑。2. 前置准备TaoToken 接入与项目骨架2.1 为什么这里要提 TaoToken做可视化原型时我经常需要调模型来生成轨道参数、解析 TLE 数据、或者让模型帮我写标注文案。TaoToken 是一个模型调用入口你可以把它理解成「统一拿 Key、统一调模型」的地方。官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 这个不加 UTM。如果你只是纯前端画轨道不调模型这一章可以快速扫过。但如果你想让卫星轨道参数动态生成、或者标注内容由模型产出就需要先拿到 Key。2.2 拿 Key 和项目初始化先去 API Keys 页面创建一个 Keyhttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。创建后复制保存后面调模型会用到。项目骨架用最简的 HTML ES Module 方式不折腾构建工具!DOCTYPE html html langzh-CN head meta charsetUTF-8 / titleThree.js 3D 地球可视化/title style body { margin: 0; overflow: hidden; background: #000; } #app { width: 100vw; height: 100vh; display: block; } #label-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .label { position: absolute; padding: 4px 8px; background: rgba(0, 255, 200, 0.15); border: 1px solid #00ffc8; color: #00ffc8; font-size: 12px; border-radius: 4px; transform: translate(-50%, -100%); white-space: nowrap; } /style /head body canvas idapp/canvas div idlabel-layer/div script typemodule src./main.js/script /body /htmllabel-layer是标注容器绝对定位盖在 canvas 上pointer-events: none让鼠标事件穿透到 canvas避免挡住轨道交互。2.3 安装 Three.js用 npm 的话npm install three不想装包就直接用 CDN在main.js顶部import * as THREE from https://unpkg.com/three0.160.0/build/three.module.js; import { OrbitControls } from https://unpkg.com/three0.160.0/examples/jsm/controls/OrbitControls.js;版本建议锁 0.160 以上Vector3.project和InstancedMesh的行为在这个版本比较稳定。3. 可复制配置地球、轨道、卫星、标注四件套3.1 场景初始化与地球模型先搭场景、相机、渲染器再放地球。地球用SphereGeometry分段数给 64 足够再高对性能没明显收益。const canvas document.getElementById(app); const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.set(0, 8, 18); const renderer new THREE.WebGLRenderer({ canvas, antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); const controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true; controls.dampingFactor 0.05; // 地球 const earthRadius 5; const earthGeometry new THREE.SphereGeometry(earthRadius, 64, 64); const earthTexture new THREE.TextureLoader().load( https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg ); const earthMaterial new THREE.MeshPhongMaterial({ map: earthTexture, shininess: 8, }); const earth new THREE.Mesh(earthGeometry, earthMaterial); scene.add(earth); // 光照 const ambient new THREE.AmbientLight(0x404040, 1.2); const sunLight new THREE.DirectionalLight(0xffffff, 1.5); sunLight.position.set(10, 6, 10); scene.add(ambient, sunLight);地球纹理用官方示例的贴图避免自己找图踩跨域坑。setPixelRatio限制到 2高分屏上不会因为像素比过高掉帧。3.2 卫星轨道椭圆参数与 TubeGeometry 渲染轨道用椭圆参数方程算点再用Line或TubeGeometry渲染。Line更轻TubeGeometry有粗细、视觉更好但顶点多。原型阶段先用Line。// 轨道参数半长轴 a、半短轴 b、倾角 inclination const orbitConfig { a: 9, // 半长轴 b: 6, // 半短轴 inclination: THREE.MathUtils.degToRad(35), // 轨道倾角 segments: 256, }; function createOrbitPoints(config) { const points []; for (let i 0; i config.segments; i) { const t (i / config.segments) * Math.PI * 2; const x Math.cos(t) * config.a; const z Math.sin(t) * config.b; // 绕 X 轴旋转实现倾角 const y z * Math.sin(config.inclination); const zRot z * Math.cos(config.inclination); points.push(new THREE.Vector3(x, y, zRot)); } return points; } const orbitPoints createOrbitPoints(orbitConfig); const orbitGeometry new THREE.BufferGeometry().setFromPoints(orbitPoints); const orbitMaterial new THREE.LineBasicMaterial({ color: 0x00ffc8, transparent: true, opacity: 0.6, }); const orbitLine new THREE.Line(orbitGeometry, orbitMaterial); scene.add(orbitLine);这里的关键是倾角处理先在 XZ 平面画椭圆再绕 X 轴旋转inclination角度得到倾斜轨道。segments给 256闭合曲线足够平滑。3.3 卫星物体与沿轨道运动卫星用一个小的SphereGeometry加发光材质位置每帧根据参数方程更新。const satelliteGeometry new THREE.SphereGeometry(0.18, 16, 16); const satelliteMaterial new THREE.MeshBasicMaterial({ color: 0xffcc00 }); const satellite new THREE.Mesh(satelliteGeometry, satelliteMaterial); scene.add(satellite); let elapsed 0; const speed 0.6; // 角速度 function updateSatellite(delta) { elapsed delta * speed; const t elapsed; const x Math.cos(t) * orbitConfig.a; const z Math.sin(t) * orbitConfig.b; const y z * Math.sin(orbitConfig.inclination); const zRot z * Math.cos(orbitConfig.inclination); satellite.position.set(x, y, zRot); }卫星位置和轨道点用同一套参数方程保证卫星始终贴在轨道线上。如果两处公式不一致卫星会「飘出」轨道这是最常见的视觉 bug。3.4 数据标注世界坐标转屏幕坐标标注用 HTML 元素叠加核心是Vector3.project(camera)把世界坐标转成 NDC再映射到屏幕像素。const labelLayer document.getElementById(label-layer); const labelEl document.createElement(div); labelEl.className label; labelEl.textContent SAT-01; labelLayer.appendChild(labelEl); const tempVec new THREE.Vector3(); function updateLabel(object3D, element) { tempVec.setFromMatrixPosition(object3D.matrixWorld); tempVec.project(camera); const halfW window.innerWidth / 2; const halfH window.innerHeight / 2; const x tempVec.x * halfW halfW; const y -tempVec.y * halfH halfH; // 判断是否在相机前方 if (tempVec.z 1) { element.style.display none; return; } element.style.display block; element.style.left ${x}px; element.style.top ${y}px; }tempVec.z 1表示点在相机背后要隐藏标注否则会出现「标注跑到屏幕另一侧」的诡异现象。这个判断很多人会漏。3.5 标注锚点挂在卫星还是挂在地面站标注锚点有两种常见需求跟随卫星动态和固定在地球表面某经纬度静态。跟随卫星直接传satellite对象固定点需要经纬度转三维坐标。function latLngToVector3(lat, lng, radius) { const phi (90 - lat) * (Math.PI / 180); const theta (lng 180) * (Math.PI / 180); return new THREE.Vector3( -radius * Math.sin(phi) * Math.cos(theta), radius * Math.cos(phi), radius * Math.sin(phi) * Math.sin(theta) ); } // 地面站标注 const stationPos latLngToVector3(39.9, 116.4, earthRadius); const stationMarker new THREE.Mesh( new THREE.SphereGeometry(0.08, 8, 8), new THREE.MeshBasicMaterial({ color: 0xff4466 }) ); stationMarker.position.copy(stationPos); scene.add(stationMarker);经纬度转三维坐标的公式里phi是极角、theta是方位角注意lng 180的偏移否则标注会整体旋转 180 度。4. 验证请求在浏览器里确认轨道运动与标注跟随4.1 渲染循环与验证动作把更新逻辑放进requestAnimationFrame用Clock拿 delta 保证不同帧率下速度一致。const clock new THREE.Clock(); function animate() { requestAnimationFrame(animate); const delta clock.getDelta(); earth.rotation.y delta * 0.05; updateSatellite(delta); updateLabel(satellite, labelEl); controls.update(); renderer.render(scene, camera); } animate();打开浏览器你应该看到地球缓慢自转、卫星沿倾斜椭圆轨道运动、黄色标注框跟着卫星移动。这是第一个验证点。4.2 用模型对话验证轨道参数如果你想让模型帮你生成一组轨道参数或者解析一段 TLE 数据可以用模型对话页面https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。把「给我一组近地轨道卫星的 a、b、倾角参数用于 Three.js 椭圆轨道」丢进去拿到参数后直接替换orbitConfig。调 API 的话请求体大致这样const res await fetch(https://taotoken.net/api/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${YOUR_API_KEY}, }, body: JSON.stringify({ model: gpt-4o-mini, messages: [ { role: user, content: 给一组 Three.js 椭圆轨道参数半长轴、半短轴、倾角近地轨道。 } ], }), }); const data await res.json(); console.log(data.choices[0].message.content);拿到返回后把数值填进orbitConfig刷新页面看轨道形状是否合理。这是第二个验证点参数变化后轨道和卫星位置同步更新。4.3 验证标注跟随的边界情况把相机拉到地球背面观察标注是否消失。如果标注还在屏幕上乱飘检查tempVec.z 1的判断是否生效。再把相机拉近拉远标注应该始终贴在卫星位置不偏移。第三个验证点点击卫星弹出信息。用Raycaster做点击检测const raycaster new THREE.Raycaster(); const mouse new THREE.Vector2(); renderer.domElement.addEventListener(click, (event) { const rect renderer.domElement.getBoundingClientRect(); mouse.x ((event.clientX - rect.left) / rect.width) * 2 - 1; mouse.y -((event.clientY - rect.top) / rect.height) * 2 1; raycaster.setFromCamera(mouse, camera); const hits raycaster.intersectObject(satellite); if (hits.length 0) { labelEl.textContent SAT-01 点击命中; } });点击卫星后标注文案变化说明射线检测和标注系统打通了。5. 本篇常见错排查5.1 标注位置偏移或抖动最常见原因是用了canvas.width而不是window.innerWidth。canvas.width是渲染缓冲尺寸受setPixelRatio影响和 CSS 像素不一致。统一用window.innerWidth / innerHeight做映射或者用renderer.domElement.clientWidth。另一个原因是标注更新在renderer.render之后导致标注用的是上一帧的矩阵。把updateLabel放在render之前或者手动调satellite.updateMatrixWorld()。5.2 卫星飘出轨道检查轨道点生成和卫星位置更新是否用了同一套参数方程。常见错误是轨道点用了a、b卫星位置用了a、a或者倾角旋转顺序不一致。把两处公式抽成同一个函数传参调用就不会分叉。5.3 轨道线不闭合或有缺口segments循环时i segments会重复首尾点i segments则闭合处有缺口。用i segments并确保t从 0 到2π完整覆盖。如果还有缺口检查BufferGeometry.setFromPoints是否被正确调用。5.4 纹理加载失败或跨域本地直接打开 HTML 文件时TextureLoader加载远程纹理可能被 CORS 拦截。用本地服务器跑比如npx serve或python -m http.server。纹理路径用相对路径或同源地址。5.5 性能掉帧标注数量多的时候每个标注都创建一个 DOM 元素会拖慢渲染。超过 50 个标注建议用InstancedMesh画点或者用 Canvas 2D 画标注层。轨道线用Line而不是TubeGeometry顶点数差一个量级。如果轨道计算复杂比如多卫星、摄动模型把计算放进 Web Worker主线程只负责渲染。原型阶段单卫星不需要但你要扩展到星座可视化时这一步迟早要做。6. 下一步从原型到可交付到这里你已经有了一个能跑的地球 轨道 标注原型。接下来可以做的接入真实 TLE 数据算轨道、用InstancedMesh批量渲染星座、把标注层换成 Canvas 2D 提升性能。如果你要长期做编码和 Agent 类任务比如让模型持续帮你生成轨道参数、解析数据、写标注文案可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的 API 参数说明。最后给一个实用技巧调试轨道时把orbitConfig.segments临时调到 16轨道变成折线能一眼看出参数方程哪里写错。调好再改回 256。这个笨办法帮我省了不少排查时间。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。