从3D地球开始带你入门Three.js

522 阅读4分钟

看了小米su7的3D互动体验网页我直接一整个亚麻呆住了,那是相当的酷炫啊,激动的心颤抖的手我也来写个3D地球来练练手。

小米su7: gamemcu.com/su7/

1. Three.js

Three.js 是一个基于 WebGL 的 JavaScript 库,它简化了在网页上创建和展示 3D 图形的过程。WebGL(Web Graphics Library)是一个JavaScript API,用于在任何兼容的网络浏览器中渲染交互式2D和3D图形,而无需使用插件。

2. 3D地球制作

2.1 初始化设置 (init 函数)

  • 创建画布:获取页面中的 <canvas> 元素作为 Three.js 渲染的目标。
  • 配置相机:设置了视角、宽高比、近裁剪面和远裁剪面。
  • 设定场景背景色:将场景的背景颜色设置为白色。
  • 创建组:为了方便管理多个对象,可以将它们添加到一个组里,然后一起操作。
  • 加载纹理并创建地球:通过 TextureLoader 加载地球的纹理图片,创建球体几何体,并用带有纹理映射的材质包裹这个几何体,形成地球模型。
  • 初始化渲染器:设置抗锯齿,并根据窗口大小调整渲染器尺寸。
  • 监听鼠标事件:添加了一个监听器来捕捉鼠标的移动,以实现视角随鼠标移动的功能。
function init(){
            canvas = document.getElementById('webglcanvas');
            camera = new THREE.PerspectiveCamera(60, // fov 视角
            window.innerWidth / window.innerHeight, // aspect 宽高比
            1, 
            2000); // 透视相机

            // 相机离scene的距离
            camera.position.z = 500;

            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xffffff);

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

            let loader = new THREE.TextureLoader(); // 简单的加载器
            loader.load('land_ocean_ice_cloud_2048.jpg',function(texture){
                let geometry = new THREE.SphereGeometry(100,32,32); // 球的半径 宽 高
                let material = new THREE.MeshBasicMaterial({
                    map:texture,
                }); // 材质
                let mesh = new THREE.Mesh(geometry,material); // 网格
                group.add(mesh);
                renderer = new THREE.WebGLRenderer({
                    canvas:canvas,
                    antialias:true, // 抗锯齿
                }); // 渲染器
                renderer.setSize(window.innerWidth,window.innerHeight);
                
                document.addEventListener('mousemove',onDocumentMouseMove,false);
            });
        }

2.2 动画循环 (animate 函数)

动画函数是 Three.js 应用程序的核心部分,它通常包含一个递归调用的 requestAnimationFrame,确保每帧都会更新和重新渲染场景。在这个例子中,我们让地球持续自转,并且根据鼠标的位置调整相机的角度,从而让用户感觉像是在围绕地球旋转。

function animate(){
            // 屏幕的刷新 60帧/秒
            group.rotation.y += 0.01; // 旋转 0.01 弧度 360度 / 60 帧
            requestAnimationFrame(animate); // 递归
            render();
        }

2.3 渲染 (render 函数)

每次动画帧时,都会调用 render 函数来更新相机的位置,并将最新的场景内容渲染到屏幕上。

function render(){
            camera.position.x += (mouseX - camera.position.x) * 0.05;
            camera.position.y += (-mouseY - camera.position.y) * 0.05;
            camera.lookAt(scene.position);
            renderer.render(scene,camera);
        }

2.4 交互(onDocumentMouseMove函数)

onDocumentMouseMove 函数用于处理鼠标移动事件,并更新全局变量 mouseXmouseY,以便在 Three.js 场景中实现基于鼠标的交互

function onDocumentMouseMove(event){
            mouseX = (event.clientX - windowHalfX);
            mouseY = (event.clientY - windowHalfY);
        }

3. 关键组件

  • 场景 (Scene)scene = new THREE.Scene(); 在 Three.js 中,所有的物体都必须放在一个场景内。
  • 相机 (Camera)camera = new THREE.PerspectiveCamera(...) 定义了从哪个角度查看场景。透视相机模拟了人眼的视觉效果。
  • 渲染器 (Renderer)renderer = new THREE.WebGLRenderer({...}) 将场景与相机组合起来,在画布上显示最终图像。
  • 几何体 (Geometry) 和 材质 (Material)geometry = new THREE.SphereGeometry(...) 和 material = new THREE.MeshBasicMaterial({...}) 分别定义了地球的形状和表面属性。
  • 加载器 (Loader)loader = new THREE.TextureLoader() 用于加载外部资源,如图片或模型文件。
  • 监听器 (Event Listener)document.addEventListener('mousemove', onDocumentMouseMove, false) 监听鼠标的移动事件,使得用户可以通过鼠标控制视角。

4. 效果展示

be3f1cdd3ab63805bc76b68ca08ca748.gif

5. 源码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D-Earth</title>
    <!-- 画地球 选择框架 加速 -->
    <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
</head>
<body>
    <canvas id="webglcanvas"></canvas>
    <script>
        // 3D 地球
        let canvas, // 3D 容器
        camera,// 3D 相机
        scene, // 3D 场景
        renderer, // 3D 渲染器
        group; // 组合
        
        var mouseX=0,mouseY=0; // mousemove 坐标
        let windowHalfX = window.innerWidth / 2; // 球心
        let windowHalfY = window.innerHeight / 2;
        init();
        animate();
        
        // 准备
        function init(){
            canvas = document.getElementById('webglcanvas');
            camera = new THREE.PerspectiveCamera(60, // fov 视角
            window.innerWidth / window.innerHeight, // aspect 宽高比
            1, 
            2000); // 透视相机

            // 相机离scene的距离
            camera.position.z = 500;

            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xffffff);

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

            let loader = new THREE.TextureLoader(); // 简单的加载器
            loader.load('land_ocean_ice_cloud_2048.jpg',function(texture){
                let geometry = new THREE.SphereGeometry(100,32,32); // 球的半径 宽 高
                let material = new THREE.MeshBasicMaterial({
                    map:texture,
                }); // 材质
                let mesh = new THREE.Mesh(geometry,material); // 网格
                group.add(mesh);
                renderer = new THREE.WebGLRenderer({
                    canvas:canvas,
                    antialias:true, // 抗锯齿
                }); // 渲染器
                renderer.setSize(window.innerWidth,window.innerHeight);
                
                document.addEventListener('mousemove',onDocumentMouseMove,false);
            });
        }

        function onDocumentMouseMove(event){
            mouseX = (event.clientX - windowHalfX);
            mouseY = (event.clientY - windowHalfY);
        }

        function animate(){
            // 屏幕的刷新 60帧/秒
            group.rotation.y += 0.01; // 旋转 0.01 弧度 360度 / 60 帧
            requestAnimationFrame(animate); // 递归
            render();
        }

        function render(){
            camera.position.x += (mouseX - camera.position.x) * 0.05;
            camera.position.y += (-mouseY - camera.position.y) * 0.05;
            camera.lookAt(scene.position);
            renderer.render(scene,camera);
        }
        
    </script>
</body>
</html>

6. 总结

这个示例展示了如何利用 Three.js 构建一个基本但完整的 3D 场景,并通过简单的交互方式增强了用户体验。喜欢的就点个赞再走吧!