THREE.JS实现3D地球

1,009 阅读6分钟

一、THREE.js简介

Three.js是一个基于WebGL的开源JavaScript库,由Ricardo Cabello(也称为Mr.doob)于2010年创建。 在Three.js中,创建3D场景通常涉及以下几个核心组件:

  • 场景(Scene):是所有3D对象的容器,可以将其想象成一个虚拟的3D空间,所有的3D对象、光源等都放置在这个空间中。

  • 相机(Camera):定义了观察场景的视角。Three.js提供了多种相机类型,最常用的是透视相机(PerspectiveCamera)和正交相机(OrthographicCamera)。

  • 渲染器(Renderer):负责将场景和相机中的内容渲染到屏幕上。Three.js支持多种渲染器,包括WebGL渲染器、Canvas渲染器和SVG渲染器。其中,WebGL渲染器是Three.js的主要渲染器,支持硬件加速的3D图形渲染。

  • 几何体(Geometry):定义了3D对象的形状。Three.js提供了多种内置几何体,如立方体(BoxGeometry)、球体(SphereGeometry)等。

  • 材质(Material):定义了3D对象的外观,包括颜色、纹理等。Three.js提供了多种内置材质,如基础材质(MeshBasicMaterial)、标准材质(MeshStandardMaterial)等。

  • 网格(Mesh):是几何体和材质的组合,表示一个具体的3D对象。

二、话不多说先上效果图,防止老铁提前划走(文末有源码)

recording.gif

三项目实现

创建html文件,在head标签部分引入Three.js库

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D 地球</title>
  <!-- 画地球 选择框架 加速 -->引入three.js
   <script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
</head>

body部分

<canvas id="webglcanvas"></canvas>
  <script>
  // 3d 地球
  // 3D 时间就是镜头拍出的世界,导演
  let canvas, // 3d 容器
    camera, // 镜头
    scene, // 场景 
    renderer, // 渲染器
    group; // 组 
    // 物品
  let mouseX = 0, mouseY = 0; // mousemove 坐标
  let windowHalfX = window.innerWidth / 2;  // 球心
  let windowHalfY = window.innerHeight / 2;

全局变量声明

-   `canvas`: 用于渲染3D场景的`<canvas>`元素。
-   `camera`: 定义场景的透视相机。
-   `scene`: 存储3D场景中的所有对象。
-   `renderer`: 用于渲染场景的渲染器。
-   `group`: 用于组织和管理场景中的对象。
-   `mouseX` 和 `mouseY`: 存储鼠标的当前位置。
-   `windowHalfX` 和 `windowHalfY`: 存储窗口宽度和高度的一半。

核心组件(场景,相机,渲染器,几何体,材质,网格)建造

<body>
    <canvas id="webglcanvas"></canvas>
    <script>
        // 3D 地球
        // 3D 世界就是镜头拍出的世界,导演
        let canvas, // 3D 容器
            camera,// 镜头
            scene,// 场景
            renderer,// 渲染器
            group;// 组
        // 物品
        let mouseX = 0,mouseY = 0;// mousemove 坐标
        let windowHalfX = window.innerWidth / 2; // 球心
        let windowHalfY = window.innerHeight / 2;// 球心
        // 初始化
        init ();

        // 准备
        function init(){
            canvas = document.getElementById('webglcanvas');// DOM
            camera = new THREE.PerspectiveCamera(60,
            window.innerWidth / window.innerHeight,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(200,20,20);// 球体形状
               let material = new THREE.MeshBasicMaterial({map:texture});// 材质
               let mesh = new THREE.Mesh(geometry,material);// 网格
               group.add(mesh);// 组添加网格
               // 渲染器 目标是canvas
               renderer = new THREE.WebGLRenderer({
                canvas:canvas,
                antialias:true
               });
               renderer.setSize(window.innerWidth,window.innerHeight);
            });
            }
    </script>
</body>

  1. 场景 (scene)

    • 使用 new THREE.Scene() 创建了一个新的场景实例,并将其赋值给变量 scene
    • 设置了场景的背景颜色为白色 (new THREE.Color(0xffffff))。
  2. 相机 (camera)

    • 使用 new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000) 创建了一个透视相机实例,并将其赋值给变量 camera
    • 设置了相机的视角为60度,宽高比为窗口的宽高比,近裁剪面为1,远裁剪面为2000。
    • 将相机的位置设置在Z轴上500的位置 (camera.position.z = 500)。
  3. 渲染器 (renderer)

    • 使用 new THREE.WebGLRenderer({ canvas: canvas, antialias: true }) 创建了一个WebGL渲染器实例,并将其赋值给变量 renderer
    • 将渲染器的目标设置为<canvas>元素 (canvas: canvas)。
    • 启用抗锯齿 (antialias: true) 以提高渲染质量。
    • 设置渲染器的大小为窗口的宽度和高度 (renderer.setSize(window.innerWidth, window.innerHeight))。
  4. 几何体 (geometry)

    • 使用 new THREE.SphereGeometry(200, 20, 20) 创建了一个球体几何体实例,并将其赋值给变量 geometry
    • 球体的半径为200,水平和垂直分段数均为20。
  5. 材质 (material)

    • 使用 new THREE.MeshBasicMaterial({ map: texture }) 创建了一个基础材质实例,并将其赋值给变量 material
    • 材质使用了加载的纹理 (map: texture)。texture 是加载的 land_ocean_ice_cloud_2048.jpg 图片的纹理对象。 (需要自娶)
image.png
  1. 网格 (mesh)

    • 使用 new THREE.Mesh(geometry, material) 将几何体和材质组合成一个网格实例,并将其赋值给变量 mesh。`

实例化场景scene处可以注释背景颜色,放一张背景图,效果更佳

 scene = new THREE.Scene();// 实例化 场景
 //scene.background = new THREE.Color(0xffffff);// 背景颜色(注释掉) 
  
   // 设置背景图片
    let loader1 = new THREE.TextureLoader();
  loader1.load('你的图片地址', function(texture) {
    scene.background = texture;
  });

本例背景图(需要自娶)

image.png

动画效果实现

function render() {
  // 更新相机的位置
  camera.position.x += (mouseX - camera.position.x) * 0.05;
  camera.position.y += (-mouseY - camera.position.y) * 0.05;
  // 使相机始终看向场景的中心
  camera.lookAt(scene.position);
  // 旋转场景中的组
  group.rotation.y += 0.005;
  // 渲染场景
  renderer.render(scene, camera);
}
// 定义animate函数,用于创建动画循环
function animate() {
  // 使用requestAnimationFrame方法递归调用animate函数,实现动画循环
  requestAnimationFrame(animate);
  // 调用render函数,更新场景并渲染到屏幕上
  render();
}


平滑效果实现

// 添加鼠标移动事件监听器,当鼠标移动时调用 onDocumentMouseMove 函数
document.addEventListener('mousemove', onDocumentMouseMove, false);
}) 
/**
 * 处理鼠标移动事件的函数
 * @param {MouseEvent} event - 鼠标移动事件对象
 */
function onDocumentMouseMove(event) {
  // 计算鼠标相对于窗口中心的水平偏移量
  mouseX = (event.clientX - windowHalfX);
  // 计算鼠标相对于窗口中心的垂直偏移量
  mouseY = (event.clientY - windowHalfY);
}


// 结束当前作用域
}
/**
 * 动画循环函数,用于更新和渲染场景
 */
function animate() {
  // 使用 requestAnimationFrame 递归调用 animate 函数,实现平滑的动画效果
  requestAnimationFrame(animate);
  // 调用 render 函数,更新场景并渲染到屏幕上
  render();
}


防止有的小伙伴不理解,直接上源码,先去实现再慢慢理解

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D 地球</title>
  <!-- 画地球 选择框架 加速 -->
  <script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
</head>
<body>
  <canvas id="webglcanvas"></canvas>
  <script>
  // 3d 地球
  // 3D 时间就是镜头拍出的世界,导演
  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() {
    canvas = document.getElementById('webglcanvas'); // DOM 
    camera = new THREE.PerspectiveCamera(60,  
    window.innerWidth / window.innerHeight, 1, 2000); // 实例化 相机
    // 相机离scene场景
    camera.position.z = 500;

    scene = new THREE.Scene(); // 实例化 场景
   // 设置背景图片
    let loader1 = new THREE.TextureLoader();
  loader1.load('UFO.png', function(texture) {
    scene.background = texture;
  });



    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(200, 20, 20); // 球体
      let material = new THREE.MeshBasicMaterial({ // 材质
        map: texture
      });
      let mesh = new THREE.Mesh(geometry, material); // 网格
      group.add( mesh );
      // 渲染器 目标是canvas 
      renderer = new THREE.WebGLRenderer({
        canvas: canvas,
        antialias: true
      });
      renderer.setSize(window.innerWidth, window.innerHeight);
    //   renderer.render(scene, camera);
    document.addEventListener('mousemove',onDocumentMouseMove,false)
    }) 
    function onDocumentMouseMove(event) {
      mouseX = (event.clientX - windowHalfX) ;
      mouseY = (event.clientY - windowHalfY) ;
    }

  }
  function animate() {
    // 递归 屏幕的刷帧率 60帧/s
    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);
    // camera.lokAt(scene.position)
    group.rotation.y += 0.005;
    renderer.render(scene, camera);
}







  </script>
</body>
</html>



注意

36行代码处,背景图片,要放入你的图片文件名,我这里是UFO.png

  let loader1 = new THREE.TextureLoader();
  loader1.load('UFO.png', function(texture) {
    scene.background = texture;
  });
 

46行代码处,加载纹理,同样放入你的图片文件名,我这里是land_ocean_ice_cloud_2048.jpg

  loader.load('land_ocean_ice_cloud_2048.jpg', function(texture) {
      let geometry = new THREE.SphereGeometry(200, 20, 20); // 球体
      let material = new THREE.MeshBasicMaterial({ // 材质
        map: texture
      });

图片和erath.html文件同处于一个文件夹。

image.png

觉得还行就给个免费的赞吧

u=1379478407,35950780&fm=253&fmt=auto&app=138&f=JPEG.webp