写点什么

基于 threejs 中秋佳节之际带你遨游星空🌃

作者:南城FE
  • 2022 年 9 月 09 日
    广东
  • 本文字数:1936 字

    阅读完需:约 6 分钟

基于threejs中秋佳节之际带你遨游星空🌃

海上生明月,天涯共此时。又是一年中秋时,回想上一次赏月已是那遥远的童年时光,忙碌使我们忘却了假日应有的舒缓。今天在这假期即将开始的时候,让我们用代码来过个节。


今天的主题是基于 threejs 画出月球环绕地球运动的效果,并增加飞跃星空的感觉,如封面图所示。

球体绘制

首先绘制出地球和月球,基于 SphereBufferGeometry 类绘制三维球体,参数如下:



首先在网上找一张地球平面图,此处只需要用到前面三个参数即可new THREE.SphereBufferGeometry(10, 50, 50),效果图如下:




月球图类似,只是会相对地球绘制的球体会小一些。

球体动画

然后是给两个球体增加动画的效果,地球本身的自转效果,月球围绕地球环绕运动的效果。


地球自转效果比较简单,只需要不断修改地球实例的 y 轴的值即可。


planet.rotation.y += 0.002;
复制代码


月球比较复杂,除开自转的同时还需增加一个环线运动效果,这里增加一个 t 值,默认为 0,在动画运动函数中不断增加 t 值,并结合数学三角函数实现环绕效果。


moon.rotation.y -= 0.007;moon.position.x = 15 * Math.cos(t) + 0;moon.position.z = 20 * Math.sin(t) - 35;t += 0.015;
复制代码


最终动画的效果如下所示:


星空轨迹

只有两个球体运动相对单调,所以再增加星空运动的轨迹提示氛围感。由于星星是不断运动飞出屏幕之外的,所以我们要有重新绘制的机制。


绘制星星


let lineTotal = 1000;let linesGeometry = new THREE.BufferGeometry();linesGeometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(6 * lineTotal), 3));linesGeometry.setAttribute("velocity", new THREE.BufferAttribute(new Float32Array(2 * lineTotal), 1));let l_positionAttr = linesGeometry.getAttribute("position");let l_vertex_Array = linesGeometry.getAttribute("position").array;let l_velocity_Array = linesGeometry.getAttribute("velocity").array;
for (let i = 0; i < lineTotal; i++) { let x = THREE.MathUtils.randInt(-100, 100); let y = THREE.MathUtils.randInt(10, 100); if (x < 7 && x > -7 && y < 20) x += 14; let z = THREE.MathUtils.randInt(0, -300);
l_vertex_Array[6 * i + 0] = l_vertex_Array[6 * i + 3] = x; l_vertex_Array[6 * i + 1] = l_vertex_Array[6 * i + 4] = y; l_vertex_Array[6 * i + 2] = l_vertex_Array[6 * i + 5] = z;
l_velocity_Array[2 * i] = l_velocity_Array[2 * i + 1] = 0;}let starsMaterial = new THREE.LineBasicMaterial({ color: "#ffffff", transparent: true, opacity: 0.5, fog: false});let lines = new THREE.LineSegments(linesGeometry, starsMaterial);linesGeometry.getAttribute("position").setUsage(THREE.DynamicDrawUsage);scene.add(lines);
复制代码


增加动画及重置


for (let i = 0; i < lineTotal; i++) {    l_velocity_Array[2 * i] += 0.0049;    l_velocity_Array[2 * i + 1] += 0.005;
l_vertex_Array[6 * i + 2] += l_velocity_Array[2 * i]; l_vertex_Array[6 * i + 5] += l_velocity_Array[2 * i + 1];
if (l_vertex_Array[6 * i + 2] > 50) { l_vertex_Array[6 * i + 2] = l_vertex_Array[6 * i + 5] = THREE.MathUtils.randInt(-200, 10); l_velocity_Array[2 * i] = 0; l_velocity_Array[2 * i + 1] = 0; }}
复制代码

星空背景动画

正常的星空背景都会有一些星云,在此基础上再增加一张背景图的运动使之更加真实。星空背景本质也是一个球体,只是半径相对较大,肉眼看不出来。


const textureSphereBg = loader.load('https://xxx.jpg');textureSphereBg.anisotropy = 16;const geometrySphereBg = new THREE.SphereBufferGeometry(50, 32, 32);const materialSphereBg = new THREE.MeshBasicMaterial({    side: THREE.BackSide,    map: textureSphereBg,    fog: false});sphereBg = new THREE.Mesh(geometrySphereBg, materialSphereBg);sphereBg.position.set(0, 50, 0);scene.add(sphereBg); 
复制代码


然后在整体的动画函数中修改不同方向的数值,使之感觉游荡在太空中的感觉。


sphereBg.rotation.x += 0.002;sphereBg.rotation.y += 0.002;sphereBg.rotation.z += 0.002;
复制代码

最后

整体实现功能就结束了,里面用到大量的 threejs 的相关 API,有兴趣的同学可以去研究研究,最后的完整代码如下:


https://code.juejin.cn/pen/7141241609026273321

参考

https://codepen.io/isladjan/pen/zYqLxeG


看完如果觉得有趣,记得点赞收藏起来。说不定哪天就用上啦~最后祝大家中秋快乐,假期玩得开心~


专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)

发布于: 刚刚阅读数: 4
用户头像

南城FE

关注

还未添加个人签名 2019.02.12 加入

专注前端开发,分享前端知识

评论

发布
暂无评论
基于threejs中秋佳节之际带你遨游星空🌃_前端_南城FE_InfoQ写作社区