three.js建立3D模型展示地球+高亮

你还在为平面而感到没有视觉效果吗?

下面将手把手建立一个3D立体地球,实现自转;那个进行鼠标拖拽以及窗口调整。

直入主题,先想清楚要怎么利用three.js进行搭建

一、制作思路

从拍照视角: 在构建一个引人入胜的3D地球展示时,我们首先需要搭建好舞台。这个"舞台"由三个主要元素构成:场景(scene)、相机(camera)和渲染器(renderer)。场景是所有3D对象的容器;相机决定了从哪个视角观察这些对象;而渲染器则负责将整个3D世界转化为2D图像呈现在屏幕上。

从角色视角:为了确保我们的主角------3D地球(earth)能够以最佳状态展现给观众,我们不仅需要精心设置其几何形状和材质,还可能要添加光源(light)来照亮它,以及实现交互功能,比如让地球自转或通过鼠标拖拽来改变视角。这一切都将在createEarth函数中得以实现,该函数负责创建并配置地球模型。

二、使用Three.js进行构建

要在网页上嵌入3D内容,我们需要引入Three.js库。这是通过在HTML文档的头部加入如下脚本来完成的:

html 复制代码
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"></script>

三、实例代码解析

1. 初始化场景、相机与光源

初始化是构建3D应用的第一步。在这里,我们将设置场景的背景颜色为白色,并创建一个透视相机,它模拟了人类视觉的效果,使得近大远小。同时,我们还需要设置一个WebGL渲染器,并将其尺寸调整为与浏览器窗口匹配。为了让地球看起来更真实,我们还添加了一个方向光,它模仿太阳光,照亮了整个场景。(细心吧~~)

html 复制代码
function init() {
    // 创建场景并设定背景色
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff); // 白色背景

    // 创建透视相机
    const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
    camera.position.z = 500; // 设置相机位置

    // 创建WebGL渲染器
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 添加地球到场景
    createEarth(scene);

    // 添加方向光源
    const light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.set(500, 500, 500).normalize();
    scene.add(light);

    // 监听窗口大小变化
    window.addEventListener('resize', () => onWindowResize(camera, renderer), false);

    // 鼠标事件监听
    document.addEventListener('mousemove', (event) => onMouseMove(event, camera), false);
}

监听窗口和鼠标点击事件,后文给出代码

2. 构建地球模型

地球模型的创建依赖于加载外部的纹理图片,这可以通过Three.js提供的TextureLoader来完成。我们将纹理应用到球体几何体上,从而形成一个逼真的地球表面。此外,我们还设置了材质的高光属性,以增强视觉效果。

html 复制代码
function createEarth(scene) {
    const loader = new THREE.TextureLoader();
    loader.load('./earth.jpg', (texture) => {
        const geometry = new THREE.SphereGeometry(200, 32, 32); // 增加细分段数提高质量
        const material = new THREE.MeshPhongMaterial({
            map: texture,
            shininess: 50 // 提高高光强度
        });

        const earth = new THREE.Mesh(geometry, material);
        scene.add(earth);
    });
}

平面图,需要放到地球模型框架形成3D。有需要自取:

3. 窗口大小调整处理

当用户调整浏览器窗口大小时,我们希望3D场景能够自动适应新的尺寸。为此,我们定义了一个onWindowResize函数,它会更新相机的宽高比和投影矩阵,并调整渲染器的大小。

html 复制代码
 function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();// 更新相机投影矩阵
    renderer.setSize(window.innerWidth, window.innerHeight);
}

4. 鼠标交互

为了让用户体验更加生动,我们实现了基于鼠标的交互功能。通过捕捉鼠标移动事件,我们可以平滑地调整相机的位置,从而让用户从不同角度观察地球。

html 复制代码
function onMouseMove(event) {
    mouseX = (event.clientX - windowHalfX)/10;
    //使鼠标在窗口中心时 mouseY 的值为0,向上移动时为负值,向下移动时为正值。
    mouseY = (event.clientX - windowHalfX)/10;// y 一半
}

5. 动画效果

为了让地球"活"起来,我们需要创建动画循环。Three.js提供了requestAnimationFrame方法,它可以确保动画以每秒60帧的速度流畅播放。在这个循环中,我们会调用render函数来更新场景和相机的状态,并最终将它们渲染到屏幕上。

html 复制代码
function animate() {
    // 加载动画帧 60桢/s
    requestAnimationFrame(animate);
    render();
}
function render() {
    camera.position.x +=(mouseX-camera.position.x )* 0.05;
    camera.position.y +=(mouseX-camera.position.x )* 0.05;
    camera.lookAt(scene.position); // 相机看向场景

    // 旋转地球
    if (earth) {
        earth.rotation.y -= 0.005;
    }
    // 渲染场景
    renderer.render(scene, camera);
}

// 启动动画
init();
animate();

下面再看看效果

完整代码

快去试一下吧,下面有进行注释解释代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D 411</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"></script>
</head>
<body>
    <script>
        let canvas, // 3d 容器
        camera, // 镜头
        scene, // 场景 
        renderer, // 渲染器
        group; // 组 

        // 物品
        let mouseX = 0, mouseY = 0; // mousemove 坐标
        let windowHalfX = window.innerWidth / 2;  // 球心
        let windowHalfY = window.innerHeight / 2;
        
        init();
        animate();

        function init() {
            // 创建场景
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xffffff); // 白色背景

            group = new THREE.Group();// 组
            scene.add(group);

            // 创建相机
            camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
            camera.position.z = 500;

            // 创建渲染器并添加到DOM
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            // 添加地球
            createEarth();

            // 添加光源
            const light = new THREE.DirectionalLight(0xffffff, 1);
            light.position.set(500, 500, 500).normalize();
            scene.add(light);

            // 监听窗口大小改变
            window.addEventListener('resize', onWindowResize, false);
            // 鼠标
            document.addEventListener('mousemove', onMouseMove, false);
        }
        function onMouseMove(event) {

            mouseX = (event.clientX - windowHalfX)/10;
            //使鼠标在窗口中心时 mouseY 的值为0,向上移动时为负值,向下移动时为正值。
            mouseY = (event.clientX - windowHalfX)/10;// y 一半
        }

        function createEarth() {
            // 加载地球纹理
            const loader = new THREE.TextureLoader();
            // 加载指定的纹理图像,并在加载完成后执行回调函数
            loader.load('./earch.jpg', function (texture) {
                // 创建地球几何体和材质
                const geometry = new THREE.SphereGeometry(200, 20,20);
                const material = new THREE.MeshPhongMaterial({
                    map: texture, // 漫反射贴图
                    shininess: 10 // 高光
                });

                // 创建地球网格并添加到场景中
                earth = new THREE.Mesh(geometry, material);
                group.add(earth);
            });
        }

        function onWindowResize() {
            windowHalfX = window.innerWidth / 2;
            windowHalfY = window.innerHeight / 2;
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();// 更新相机投影矩阵
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function animate() {
            // 加载动画帧 60桢/s
            requestAnimationFrame(animate);
            render();
        }

        function render() {
            camera.position.x +=(mouseX-camera.position.x )* 0.05;
            camera.position.y +=(mouseX-camera.position.x )* 0.05;
            camera.lookAt(scene.position); // 相机看向场景

            // 旋转地球
            if (earth) {
                earth.rotation.y -= 0.005;
            }
            // 渲染场景
            renderer.render(scene, camera);
        }
    </script>
</body>
</html>
相关推荐
码界领航5 分钟前
【2025最新版】Chrome谷歌浏览器如何能恢复到之前的旧版本
前端·chrome
乐多_L1 小时前
使用vue3框架vue-next-admin导出表格excel(带图片)
前端·javascript·vue.js
南望无一1 小时前
React Native 0.70.x如何从本地安卓源码(ReactAndroid)构建
前端·react native
Mike_188702783511 小时前
1688代采下单API接口使用指南:实现商品采集与自动化下单
前端·python·自动化
鲨鱼辣椒️面1 小时前
HTML视口动画
前端·html
一小路一1 小时前
Go Web 开发基础:从入门到实战
服务器·前端·后端·面试·golang
堇舟1 小时前
HTML第一节
前端·html
纯粹要努力1 小时前
前端跨域问题及解决方案
前端·javascript·面试
小刘不知道叫啥1 小时前
React源码揭秘 | 启动入口
前端·react.js·前端框架
kidding7232 小时前
uniapp引入uview组件库(可以引用多个组件)
前端·前端框架·uni-app·uview