Three.js - 模拟太阳、地球、月亮的运动

简介

本节我们简单的模拟地球绕着太阳转,月球绕着地球转。从月球的角度看,它是在地球的 "局部空间 "中绕着地球转,地球和月球合成一组是在全局空间绕着太阳转。

基础场景

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="canvas" width="1000" height="500"></canvas>
    <script type="module">
 // 官网地址      
         import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/build/three.module.js'      
         import { OrbitControls } from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/examples/jsm/controls/OrbitControls.js'
 const canvas=document.querySelector('#canvas')

         const scene=new THREE.Scene();

         const fov = 40 // 视野范围      
         const aspect = 2 // 相机默认值 画布的宽高比    canvas.width/canvas.height  
         const near = 0.1 // 近平面      
         const far = 1000 // 远平面

         const camera=new THREE.PerspectiveCamera(fov,aspect,near,far);
         camera.position.set(0,-30,50);
         camera.up.set(0,0,1);
         camera.lookAt(0,0,0);

         const controls = new OrbitControls(camera, canvas);
         controls.update();

        // 渲染器      
        const renderer = new THREE.WebGLRenderer({ canvas, antialias: true })

 // 纹理加载器
        const loader = new THREE.TextureLoader();

        const color = 0xffffff        
        const intensity = 1
        // 创建光源
        const light = new THREE.PointLight (color, intensity)
        scene.add(light);

 function animation  (time) {        
            time *= 0.001
            objects.forEach((obj) => { 
                    obj.rotation.y = time
                    //obj.rotation.x = time
                }
                )
        // 加载渲染器        
            renderer.render(scene, camera)
        // 开始动画        
           requestAnimationFrame(animation)      
        }

        animation();
    </script>
</body>
</html>

添加背景

  • 添加星空背景,修改背景展示图片纹理。

  • const bgTexture = loader.load('../img/4.jpg')  
    scene.background = bgTexture

     添加太阳

  • // 物体网格对象      
    const objects = []
    // 一球多用        
    const radius = 2        
    const widthSegments = 36        
    const heightSegments = 36        
    const sphereGeometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments)
    // 太阳        
    const sunTexture = loader.load('../img/1.jpg')        
    const sunMaterial = new THREE.MeshBasicMaterial({ map: sunTexture })        const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial)       
     // 放大3倍       
     sunMesh.scale.set(3, 3, 3)       
     scene.add(sunMesh)        
    // 放入控制对象        
    objects.push(sunMesh)
    • 创建一个球几何体,太阳、地球、月亮都是球形,我们可以公用一个球体。

    • 使用基础材质加载太阳纹理。因为灯光是点光源,发光点在中心,太阳也在中心,使用其他材质是无法接收光源。

    • 太阳比其他球体大,放大3倍。

    • // 网格对象 旋转    
      objects.forEach((obj) => {obj.rotation.y = time })

      在渲染循环中添加,使网格对象(objects)中的物体旋转。

    • 添加地球

    •  // 地球    
      const earthTexture = loader.load('../img/3.jpg')   
       const earthMaterial = new THREE.MeshPhongMaterial({      map: earthTexture    })    
      const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial)    earthMesh.position.x = 20   
       scene.add(earthMesh)    
      // 放入控制对象    
      objects.push(earthMesh)
      View Code

      这里重复使用sphereGeometry球几何体,创建.MeshPhongMaterial()材质。将其定位在太阳的左边 20个单位。

      • 可以看到太阳和地球都在自转,但地球并没有绕着太阳转。

      • 如果我们通过计算的方式修改地球的全局坐标围绕太阳转是可以的,但是这样很麻烦。这里我们添加一个新场景太阳系,把地球和太阳都放入场景中,旋转太阳系这个场景,因为太阳在中心,实现的效果就是地球围绕太阳转。

      •  // 太阳系 物体对象    
        const solarSystem = new THREE.Object3D()    
        scene.add(solarSystem)    
        objects.push(solarSystem)
        solarSystem.add(sunMesh)    
        solarSystem.add(earthMesh)

        添加月球

      • 同样的月球要围绕地球转,添加一个地月系到太阳系中旋转。
      • // 地月系 物体对象    
        const landOrbit = new THREE.Object3D()   
        landOrbit.position.x = 20    
        solarSystem.add(landOrbit)    
        objects.push(landOrbit)

        定位地月系位置到原来地球的位置放入太阳系中,取消地球的定位和取消放入太阳系中

      • // 月球    
        const moonTexture = loader.load('../img/2.jpg')    
        const moonMaterial = new THREE.MeshPhongMaterial({ map: moonTexture })    const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial)    moonMesh.scale.set(0.5, 0.5, 0.5)    
        moonMesh.position.x = 5    
        objects.push(moonMesh)
        // 加入地月系    
        landOrbit.add(earthMesh)    
        landOrbit.add(moonMesh)

        定位月球在地球左边5个单位,并缩小体积。然后全部加入地月系中。

posted on 2025-03-31 18:13  #知了  阅读(120)  评论(0)    收藏  举报