用threejs模拟太阳系运动三维模型

本文介绍了如何利用three.js库模拟太阳系八大行星的运行轨迹,包括设置行星参数、创建场景、添加星球、自转和公转动画。作者分享了实现思路和关键代码段,尽管模型并非完全精确,但展示了基本的3D图形技术应用。
摘要由CSDN通过智能技术生成

最近在学习threejs,觉得非常有趣。于是决定用这个来模拟太阳系各行星的运行轨迹。

关于threejs的基础知识就不再赘述了,大家可以查看官网:threejs官方网站

本文的demo可以从下面下载:threejs模拟太阳系八大行星公转及自转三维模型

大家也可以通过以下地址观看效果:threejs模拟太阳系八大行星公转及自转三维模型效果

(可以通过鼠标和滚轴,切换视角和视野缩放)

下面介绍我的实现思路:

(1)设置太阳及八大行星参数

先查询太阳及八大行星的半径、自转周期、公转周期,各行星绕太阳公转椭圆轨道的近日点和远日点。并设置如下数组:

//行星参数
        const stars = [
            { name: '太阳', radius: 69.550, textureImg: 'Sun.png', centerPosition: { x: 0, y: 0, z: 0 }, rotationSpeed: Math.PI / 100 / 25.5/*自转速度*/, },
            { name: '水星', radius: 2.440, textureImg: 'Mercury.png', centerPosition: { x: 0, y: 0, z: 57909 / 500 }, rotationSpeed: Math.PI / 100 / 58/*自转速度*/, revolutionRadiusX: 69816.9 / 500, revolutionRadiusY: 46001.2 / 500, revolutionDiviseLength: 87.9/365*revolutionSpeedRatio/*公转速度有关,越大,转速越慢*/, revolutionDiviseInd: 0 },
            { name: '金星', radius: 6.051, textureImg: 'Venus.png', centerPosition: { x: 0, y: 0, z: 108200 / 500 }, rotationSpeed: Math.PI / 100 / 243/*自转速度*/, revolutionRadiusX: 108942 / 500, revolutionRadiusY: 107476 / 500, revolutionDiviseLength: 224.701/365*revolutionSpeedRatio, revolutionDiviseInd: 0 },
            { name: '地球', radius: 6.371, textureImg: 'Earth.png', centerPosition: { x: 0, y: 0, z: 147000 / 500 }, rotationSpeed: Math.PI / 100 / 1/*自转速度*/, revolutionRadiusX: 149600 / 500, revolutionRadiusY: 149580 / 500, revolutionDiviseLength: revolutionSpeedRatio, revolutionDiviseInd: 0 },
            { name: '火星', radius: 3.396, textureImg: 'Mars.png', centerPosition: { x: 0, y: 0, z: 227940 / 500 }, rotationSpeed: Math.PI / 100 / 1.05/*自转速度*/, revolutionRadiusX: 249200 / 500, revolutionRadiusY: 206600 / 500, revolutionDiviseLength: 686.971/365*revolutionSpeedRatio, revolutionDiviseInd: 0 },
            { name: '木星', radius: 69.911, textureImg: 'Jupiter.png', centerPosition: { x: 0, y: 0, z: 778330 / 500 }, rotationSpeed: Math.PI / 100 / 0.375/*自转速度*/, revolutionRadiusX: 817000 / 500, revolutionRadiusY: 741000 / 500, revolutionDiviseLength: 11.862*revolutionSpeedRatio, revolutionDiviseInd: 0 },
            { name: '土星', radius: 60.268, textureImg: 'Saturn.png', centerPosition: { x: 0, y: 0, z: 1429400 / 500 }, rotationSpeed: Math.PI / 100 / 0.4/*自转速度*/, revolutionRadiusX: 1514500 / 500, revolutionRadiusY: 1355250 / 500, revolutionDiviseLength: 29.4571*revolutionSpeedRatio, revolutionDiviseInd: 0 },
            { name: '海王星', radius: 24.622, textureImg: 'Neptune.png', centerPosition: { x: 0, y: 0, z: 4496000 / 500 }, rotationSpeed: Math.PI / 100 / 0.667/*自转速度*/, revolutionRadiusX: 4553946 / 500, revolutionRadiusY: 4452940 / 500, revolutionDiviseLength: 164.8*revolutionSpeedRatio, revolutionDiviseInd: 0 },
            { name: '天王星', radius: 25.362, textureImg: 'Uranus.png', centerPosition: { x: 0, y: 0, z: 28709900 / 500 }, rotationSpeed: Math.P / 100 / 0.65/*自转速度*/, revolutionRadiusX: 30044197.04 / 500, revolutionRadiusY: 2748938.461 / 500, revolutionDiviseLength: 84.0205*revolutionSpeedRatio, revolutionDiviseInd: 0 }
        ]

为了视觉效果展示方便,所有的长度单位、距离单位、转速等,都进行了比例处理。

  • name:为星球中文名称;
  • radius:半径(单位1000千米);
  • textureImg:纹理贴图;
  • centerPosition:星中心点坐标(其中太阳中心坐标为坐标系原点),,考虑坐标轴视觉范围,进行了一定等比缩放;
  • rotationSpeed:自转速度,其他星球按照地球日等比例计算和地球自传速度的比率;
  • revolutionRadiusX:公转椭圆轨道长轴半径,这个数据依据行星远日点数值计算,不是实际运行轨道,但是可以模拟出等比效果,考虑坐标轴视觉范围,进行了一定等比缩放
  • revolutionRadiusY:公转椭圆轨道短轴半径,这个数据依据行星近日点数值计算,不是实际运行轨道,但是可以模拟出等比效果,考虑坐标轴视觉范围,进行了一定等比缩放。
  • revolutionDiviseLength:公转椭圆轨道曲线切分长度(用于threejs生成curve的切分参数,数值越大,曲线越光滑。此处和公转的转速有关,切分点越多,公转速度越慢)

  • revolutionDiviseInd:公转运行坐标索引(仅八大行星需要此参数)

(2)开始创建场景,架好相机

//设置渲染器
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
//设置控制器
cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
//设置相机位置
camera.position.set(100, 200, 10000);

//增加辅助坐标轴
var axeshelper = new THREE.AxesHelper(6000);//轴辅助,参数为轴大小
scene.add(axeshelper);

//控制器设置
cameraControls.target = new THREE.Vector3(0, 1, 0); //绕目标坐标运动

//GridHelper,坐标格辅助对象. 坐标格实际上是2维线数组.
const gridHelper = new THREE.GridHelper( 12000/*size*/, 100/*divisions*/ );
scene.add( gridHelper );

(3)给场景加入星球

stars.forEach((star, index) => {
    addStar(star, index)
})
function addStar(star, index) {
    const geometry = new THREE.SphereGeometry(star.radius, 100, 100);
    const material = new THREE.MeshBasicMaterial({ /*wireframe: true,*/ map: new       THREE.TextureLoader().load(star.textureImg) });
    const starObj = new THREE.Mesh(geometry, material);
    starObj.position.x = star.centerPosition.x;
    starObj.position.y = star.centerPosition.y;
    starObj.position.z = star.centerPosition.z;
    //将天体加入场景
    scene.add(starObj)

    //设置公转椭圆曲线
    const curve = new THREE.EllipseCurve(
        0, 0, // ax, aY
        star.revolutionRadiusX, star.revolutionRadiusY,           // xRadius, yRadius
        0, 2 * Math.PI,  // aStartAngle, aEndAngle
        false,            // aClockwise
        0                 // aRotation
    );
    const points = curve.getPoints(star.revolutionDiviseLength)


    //设置对象
    stars[index].starObj = starObj;
    stars[index].revolutionPoints = points;
}

这里,首先通过THREE.EllipseCurve获得行星公转周期,然后通过getPoints获得曲线各点坐标。

最后将starObj(加入场景中的星球物体)和revolutionPoints(公转曲线坐标点数组)赋值给stars数组中对应的star对象。

(4)渲染

//渲染
function animate() {
    requestAnimationFrame(animate);
    cameraControls.update();//更新控制器
    renderer.render(scene, camera);

    stars.forEach((star, index) => {
        //自转
        stars[index].starObj.rotation.y += 0.1;
        //公转
        if(index==0) //太阳不参与公转
            return;
        if (star.revolutionDiviseInd >= star.revolutionDiviseLength) {
            stars[index].revolutionDiviseInd = 0;
        } else {
            stars[index].starObj.position.x =    stars[index].revolutionPoints[star.revolutionDiviseInd].x;
            stars[index].starObj.position.z = stars[index].revolutionPoints[star.revolutionDiviseInd].y;
                    star.revolutionDiviseInd++;
        }
    })
}

(5)结尾

整个实现过程并不复杂,需要的一些细心和耐心。但是这个模型并不完美,因为考虑视觉效果,很多数据并没有进行真实比例还原,只能是示意。

半径、自转转速、公转速度、公转路径等之间的单位,也没有完全一致。有兴趣的话,大家可以更改参数让模型更贴近实际。

这里也没有画太阳系在银河系的运行动画,网上看过真实太阳系的运行,还是很震撼的。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值