海哥 发表于 2025-4-15 14:22:49

ThreeJs实现裸眼3D地球仪

一、实现结果

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

代码如下:
<!DOCTYPE html>
<html>
<head>
    <title>3D Earth</title>
    <style>
      body { margin: 0; }
      canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
      // 初始化场景、相机和渲染器
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
      const renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);

      // 创建地球几何体
      const geometry = new THREE.SphereGeometry(5, 50, 50);

      // 加载纹理
      const textureLoader = new THREE.TextureLoader();
      const earthTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg');
      const normalTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg');

      // 创建材质
      const material = new THREE.MeshPhongMaterial({
            map: earthTexture,
            normalMap: normalTexture,
            normalScale: new THREE.Vector2(0.8, 0.8),
            specular: new THREE.Color('grey'),
            shininess: 5
      });

      // 创建地球网格
      const earth = new THREE.Mesh(geometry, material);
      scene.add(earth);

      // 添加光照
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
      scene.add(ambientLight);

      const pointLight = new THREE.PointLight(0xffffff, 1.5);
      pointLight.position.set(10, 10, 10);
      scene.add(pointLight);

      // 设置相机位置
      camera.position.z = 15;

      // 添加自动旋转动画
      function animate() {
            requestAnimationFrame(animate);
            earth.rotation.y += 0.002;
            renderer.render(scene, camera);
      }

      // 处理窗口大小变化
      window.addEventListener('resize', onWindowResize, false);

      function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
      }

      // 添加鼠标交互
      let isDragging = false;
      let previousMousePosition = {
            x: 0,
            y: 0
      };

      document.addEventListener('mousedown', (e) => {
            isDragging = true;
            previousMousePosition = {
                x: e.clientX,
                y: e.clientY
            };
      });

      document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;

            const deltaMove = {
                x: e.clientX - previousMousePosition.x,
                y: e.clientY - previousMousePosition.y
            };

            earth.rotation.y += deltaMove.x * 0.005;
            earth.rotation.x += deltaMove.y * 0.005;

            previousMousePosition = {
                x: e.clientX,
                y: e.clientY
            };
      });

      document.addEventListener('mouseup', () => {
            isDragging = false;
      });

      // 启动动画
      animate();
    </script>
</body>
</html> 这个示例代码包含以下重要功能:

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

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

[*] 重要特性:

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

[*] 使用阐明:

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

[*] 扩展发起:

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

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

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

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

// 加载纹理
const textureLoader = new THREE.TextureLoader();
const earthTexture = textureLoader.load('earth_texture.jpg');
const normalTexture = textureLoader.load('earth_normal.jpg');

// 创建材质
const material = new THREE.MeshPhongMaterial({
    map: earthTexture,          // 基础颜色贴图
    normalMap: normalTexture,   // 法线贴图
    normalScale: new THREE.Vector2(0.8, 0.8), // 法线强度
    specular: new THREE.Color('grey'), // 高光颜色
    shininess: 5                // 高光强度
});
[*] 材质类型选择:

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

[*] 纹理映射:

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

[*] 材质参数:

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

[*] 性能优化:

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

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

// 鼠标拖动交互
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };

document.addEventListener('mousedown', (e) => {
    isDragging = true;
    previousMousePosition = { x: e.clientX, y: e.clientY };
});

document.addEventListener('mousemove', (e) => {
    if (!isDragging) return;

    const deltaMove = {
      x: e.clientX - previousMousePosition.x,
      y: e.clientY - previousMousePosition.y
    };

    earth.rotation.y += deltaMove.x * 0.005;
    earth.rotation.x += deltaMove.y * 0.005;

    previousMousePosition = { x: e.clientX, y: e.clientY };
});

document.addEventListener('mouseup', () => {
    isDragging = false;
});
[*] 交互原理:

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

[*] 数学转换:

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

[*] 坐标系注意:

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

[*] 性能优化:

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

https://i-blog.csdnimg.cn/direct/49972640166f458cb3bb3f413535c92f.gif

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: ThreeJs实现裸眼3D地球仪