ThreeJs实现裸眼3D地球仪

海哥  论坛元老 | 2025-4-15 14:22:49 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1589|帖子 1589|积分 4767

一、实现结果

使用Three.js实现裸眼3D地球仪
      
  二、实当代码

代码如下:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <title>3D Earth</title>
  5.     <style>
  6.         body { margin: 0; }
  7.         canvas { display: block; }
  8.     </style>
  9. </head>
  10. <body>
  11.     <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
  12.     <script>
  13.         // 初始化场景、相机和渲染器
  14.         const scene = new THREE.Scene();
  15.         const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  16.         const renderer = new THREE.WebGLRenderer();
  17.         renderer.setSize(window.innerWidth, window.innerHeight);
  18.         document.body.appendChild(renderer.domElement);
  19.         // 创建地球几何体
  20.         const geometry = new THREE.SphereGeometry(5, 50, 50);
  21.         // 加载纹理
  22.         const textureLoader = new THREE.TextureLoader();
  23.         const earthTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg');
  24.         const normalTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg');
  25.         // 创建材质
  26.         const material = new THREE.MeshPhongMaterial({
  27.             map: earthTexture,
  28.             normalMap: normalTexture,
  29.             normalScale: new THREE.Vector2(0.8, 0.8),
  30.             specular: new THREE.Color('grey'),
  31.             shininess: 5
  32.         });
  33.         // 创建地球网格
  34.         const earth = new THREE.Mesh(geometry, material);
  35.         scene.add(earth);
  36.         // 添加光照
  37.         const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  38.         scene.add(ambientLight);
  39.         const pointLight = new THREE.PointLight(0xffffff, 1.5);
  40.         pointLight.position.set(10, 10, 10);
  41.         scene.add(pointLight);
  42.         // 设置相机位置
  43.         camera.position.z = 15;
  44.         // 添加自动旋转动画
  45.         function animate() {
  46.             requestAnimationFrame(animate);
  47.             earth.rotation.y += 0.002;
  48.             renderer.render(scene, camera);
  49.         }
  50.         // 处理窗口大小变化
  51.         window.addEventListener('resize', onWindowResize, false);
  52.         function onWindowResize() {
  53.             camera.aspect = window.innerWidth / window.innerHeight;
  54.             camera.updateProjectionMatrix();
  55.             renderer.setSize(window.innerWidth, window.innerHeight);
  56.         }
  57.         // 添加鼠标交互
  58.         let isDragging = false;
  59.         let previousMousePosition = {
  60.             x: 0,
  61.             y: 0
  62.         };
  63.         document.addEventListener('mousedown', (e) => {
  64.             isDragging = true;
  65.             previousMousePosition = {
  66.                 x: e.clientX,
  67.                 y: e.clientY
  68.             };
  69.         });
  70.         document.addEventListener('mousemove', (e) => {
  71.             if (!isDragging) return;
  72.             const deltaMove = {
  73.                 x: e.clientX - previousMousePosition.x,
  74.                 y: e.clientY - previousMousePosition.y
  75.             };
  76.             earth.rotation.y += deltaMove.x * 0.005;
  77.             earth.rotation.x += deltaMove.y * 0.005;
  78.             previousMousePosition = {
  79.                 x: e.clientX,
  80.                 y: e.clientY
  81.             };
  82.         });
  83.         document.addEventListener('mouseup', () => {
  84.             isDragging = false;
  85.         });
  86.         // 启动动画
  87.         animate();
  88.     </script>
  89. </body>
  90. </html>
复制代码
这个示例代码包含以下重要功能:

  • 创建了一个基本的Three.js场景,包含:

    • 球体几何图形
    • 地球纹理贴图(颜色贴图和法线贴图)
    • 光影结果(环境光 + 点光源)

  • 重要特性:

    • 地球主动迟钝旋转
    • 支持鼠标拖拽交互旋转
    • 相应式窗口大小调整
    • 法线贴图实现表面细节
    • 适当的光照结果

  • 使用阐明:

    • 必要网络连接加载纹理贴图
    • 可以替换纹理贴图URL使用自界说贴图
    • 通过调整SphereGeometry参数控制地球精度
    • 修改rotation速率可以改变旋转速率
    • 调整camera.position.z改变观察距离

  • 扩展发起:

    • 添加云层(使用透明贴图的第二个球体)
    • 添加星空背景
    • 添加标记点或国家界限
    • 添加放大/缩小功能
    • 添加旋转控制按钮

注意:由于纹理加载必要时间,初次加载可能会看到短暂的空白场景。现实使用时发起:

  • 使用当地纹理文件
  • 添加加载进度提示
  • 使用更高分辨率的贴图
  • 添加错误处理
可以将代码生存为HTML文件直接运行(必要网络连接),也可以部署到Web服务器使用当地资源。
三、重点代码片段

1. 地球材质创建(焦点渲染)

  1. // 加载纹理
  2. const textureLoader = new THREE.TextureLoader();
  3. const earthTexture = textureLoader.load('earth_texture.jpg');
  4. const normalTexture = textureLoader.load('earth_normal.jpg');
  5. // 创建材质
  6. const material = new THREE.MeshPhongMaterial({
  7.     map: earthTexture,          // 基础颜色贴图
  8.     normalMap: normalTexture,   // 法线贴图
  9.     normalScale: new THREE.Vector2(0.8, 0.8), // 法线强度
  10.     specular: new THREE.Color('grey'), // 高光颜色
  11.     shininess: 5                // 高光强度
  12. });
复制代码

  • 材质类型选择

    • 使用 MeshPhongMaterial(冯氏材质),这是实现光照交互的关键
    • 支持高光反射结果,得当表现具有反光特性的地球表面

  • 纹理映射

    • map:底子颜色贴图,直接表现地球表面图像
    • normalMap:法线贴图,通过RGB值模拟表面凹凸细节(无需增加几何体复杂度)

  • 材质参数

    • normalScale:控制法线贴图的强度(值越大凹凸感越强)
    • specular + shininess:组合控制高光结果(金属感/塑料感调治)

  • 性能优化

    • 纹理尺寸发起保持2的幂次(如1024x512),否则可能触发Three.js的主动缩放
    • 可以添加 bumpMap 或 specularMap 实现更复杂的表面细节


2. 交互旋转实现(焦点交互)

  1. // 鼠标拖动交互
  2. let isDragging = false;
  3. let previousMousePosition = { x: 0, y: 0 };
  4. document.addEventListener('mousedown', (e) => {
  5.     isDragging = true;
  6.     previousMousePosition = { x: e.clientX, y: e.clientY };
  7. });
  8. document.addEventListener('mousemove', (e) => {
  9.     if (!isDragging) return;
  10.     const deltaMove = {
  11.         x: e.clientX - previousMousePosition.x,
  12.         y: e.clientY - previousMousePosition.y
  13.     };
  14.     earth.rotation.y += deltaMove.x * 0.005;
  15.     earth.rotation.x += deltaMove.y * 0.005;
  16.     previousMousePosition = { x: e.clientX, y: e.clientY };
  17. });
  18. document.addEventListener('mouseup', () => {
  19.     isDragging = false;
  20. });
复制代码

  • 交互原理

    • 通过监听鼠标变乱实现拖拽利用
    • 计算两次鼠标位置的差值(deltaMove)转换为旋转量

  • 数学转换

    • delta.x 影响 Y 轴旋转(程度拖动→左右旋转)
    • delta.y 影响 X 轴旋转(垂直拖动→上下旋转)
    • 0.005 是敏捷度系数,值越大拖动反应越敏捷

  • 坐标系注意

    • Three.js使用右手坐标系,Y轴向上
    • 旋转顺序遵循物体自身坐标系(可能导致万向节锁问题,复杂交互必要四元数)

  • 性能优化

    • 使用 requestAnimationFrame 包管动画流畅性
    • 避免在变乱回调中直接修改DOM



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表