ThreeJs实现裸眼3D地球仪

一、实现效果

使用Three.js实现裸眼3D地球仪

二、实现代码

代码如下:

html 复制代码
<!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>

这个示例代码包含以下主要功能:

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

    • 球体几何图形

    • 地球纹理贴图(颜色贴图和法线贴图)

    • 光影效果(环境光 + 点光源)

  2. 主要特性:

    • 地球自动缓慢旋转

    • 支持鼠标拖拽交互旋转

    • 响应式窗口大小调整

    • 法线贴图实现表面细节

    • 适当的光照效果

  3. 使用说明:

    • 需要网络连接加载纹理贴图

    • 可以替换纹理贴图URL使用自定义贴图

    • 通过调整SphereGeometry参数控制地球精度

    • 修改rotation速度可以改变旋转速度

    • 调整camera.position.z改变观察距离

  4. 扩展建议:

    • 添加云层(使用透明贴图的第二个球体)

    • 添加星空背景

    • 添加标记点或国家边界

    • 添加放大/缩小功能

    • 添加旋转控制按钮

注意:由于纹理加载需要时间,首次加载可能会看到短暂的空白场景。实际使用时建议:

  1. 使用本地纹理文件

  2. 添加加载进度提示

  3. 使用更高分辨率的贴图

  4. 添加错误处理

可以将代码保存为HTML文件直接运行(需要网络连接),也可以部署到Web服务器使用本地资源。

三、重点代码片段

1. 地球材质创建(核心渲染)

javascript 复制代码
// 加载纹理
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                // 高光强度
});
  1. 材质类型选择

    • 使用 MeshPhongMaterial(冯氏材质),这是实现光照交互的关键

    • 支持高光反射效果,适合表现具有反光特性的地球表面

  2. 纹理映射

    • map:基础颜色贴图,直接显示地球表面图像

    • normalMap:法线贴图,通过RGB值模拟表面凹凸细节(无需增加几何体复杂度)

  3. 材质参数

    • normalScale:控制法线贴图的强度(值越大凹凸感越强)

    • specular + shininess:组合控制高光效果(金属感/塑料感调节)

  4. 性能优化

    • 纹理尺寸建议保持2的幂次(如1024x512),否则可能触发Three.js的自动缩放

    • 可以添加 bumpMapspecularMap 实现更复杂的表面细节


2. 交互旋转实现(核心交互)

javascript 复制代码
// 鼠标拖动交互
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;
});
  1. 交互原理

    • 通过监听鼠标事件实现拖拽操作

    • 计算两次鼠标位置的差值(deltaMove)转换为旋转量

  2. 数学转换

    • delta.x 影响 Y 轴旋转(水平拖动→左右旋转)

    • delta.y 影响 X 轴旋转(垂直拖动→上下旋转)

    • 0.005 是灵敏度系数,值越大拖动反应越灵敏

  3. 坐标系注意

    • Three.js使用右手坐标系,Y轴向上

    • 旋转顺序遵循物体自身坐标系(可能导致万向节锁问题,复杂交互需要四元数)

  4. 性能优化

    • 使用 requestAnimationFrame 保证动画流畅性

    • 避免在事件回调中直接修改DOM

相关推荐
excel32 分钟前
webpack 模块图 第 三 节
前端
徐_三岁34 分钟前
Vue 3中的 setup
前端
excel37 分钟前
webpack 模块图 第 二 节
前端
—Qeyser6 小时前
用 Deepseek 写的uniapp血型遗传查询工具
前端·javascript·ai·chatgpt·uni-app·deepseek
codingandsleeping6 小时前
HTTP1.0、1.1、2.0 的区别
前端·网络协议·http
小满blue6 小时前
uniapp实现目录树效果,异步加载数据
前端·uni-app
天天扭码8 小时前
零基础 | 入门前端必备技巧——使用 DOM 操作插入 HTML 元素
前端·javascript·dom
咖啡虫8 小时前
css中的3d使用:深入理解 CSS Perspective 与 Transform-Style
前端·css·3d
拉不动的猪9 小时前
设计模式之------策略模式
前端·javascript·面试
旭久9 小时前
react+Tesseract.js实现前端拍照获取/选择文件等文字识别OCR
前端·javascript·react.js