海上生明月,天涯共此时。又是一年中秋时,回忆上一次赏月已是那边远的童年时光,繁忙使咱们忘却了假日应有的舒缓。明天在这假期行将开始的时候,让咱们用代码来过个节。
明天的主题是基于threejs画出月球盘绕地球静止的成果,并减少飞跃星空的感觉,如封面图所示。
球体绘制
首先绘制出地球和月球,基于SphereBufferGeometry类绘制三维球体,参数如下:
参数 | 形容 |
---|---|
radius | 该属性定义球体的半径,默认值是50 |
widthSegments | 该属性指定竖直方向上的分段数,段数越多,球体的外表越润滑,默认值是8,最小值是3 |
heightSegments | 该属性指定程度方向上的分段数,段数越多,球体的外表越润滑,默认值是6,最小值是2 |
phiStart | 该属性用来指定从x轴的什么地位开始绘制,取值范畴是0到2*π,默认值0 |
phiLength | 该属性用来指定从phiStart开始画多少,默认2*π(画整球) |
thetaStart | 该属性用来指定从y轴的什么地位开始绘制,取值范畴是0到2*π,默认值0 |
thetaLength | 该属性用来指定从thetaStart开始画多少,默认2*π(画整球) |
首先在网上找一张地球平面图,此处只须要用到后面三个参数即可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/71…
参考
https://codepen.io/isladjan/p…
看完如果感觉乏味,记得点赞珍藏起来。说不定哪天就用上啦~
最初祝大家中秋高兴,假期玩得开心~
专一前端开发,分享前端相干技术干货,公众号:南城大前端(ID: nanchengfe)
发表回复