Day 10 我們已經把太陽與八大行星全部建立完成。
今天開始讓太陽系真正「動起來」。
這次我們會讓八大行星都加入自己的 rotationSpeed
也就是自轉速度。
今天會完成:
今天完成後每顆行星都會開始旋轉。
index.html
與 Day 10 相同,不需要修改。(完整在 Day 9)
css/style.css
與 Day 10 相同,不需要修改。(完整在 Day 9)
js/main.js
import * as THREE from
"https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js";
// ========================
// Scene
// ========================
const scene =
new THREE.Scene();
scene.background =
new THREE.Color(
0x000000
);
// ========================
// Camera
// ========================
const camera =
new THREE.PerspectiveCamera(
75,
window.innerWidth /
window.innerHeight,
0.1,
1000
);
camera.position.set(
0,
18,
32
);
camera.lookAt(
0,
0,
0
);
// ========================
// Renderer
// ========================
const renderer =
new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(
window.innerWidth,
window.innerHeight
);
renderer.setPixelRatio(
Math.min(
window.devicePixelRatio,
2
)
);
document
.getElementById("scene")
.appendChild(
renderer.domElement
);
// ========================
// Sun
// ========================
const sunGeometry =
new THREE.SphereGeometry(
2,
64,
64
);
const sunMaterial =
new THREE.MeshBasicMaterial({
color: 0xffaa00
});
const sun =
new THREE.Mesh(
sunGeometry,
sunMaterial
);
scene.add(
sun
);
// ========================
// Planet Data
// ========================
const planetData = [
{
name: "Mercury",
size: 0.45,
color: 0xaaaaaa,
distance: 4,
rotationSpeed: 0.008
},
{
name: "Venus",
size: 0.65,
color: 0xd9a066,
distance: 6,
rotationSpeed: -0.003
},
{
name: "Earth",
size: 0.7,
color: 0x2277ff,
distance: 8,
rotationSpeed: 0.01
},
{
name: "Mars",
size: 0.55,
color: 0xcc4422,
distance: 10,
rotationSpeed: 0.009
},
{
name: "Jupiter",
size: 1.3,
color: 0xd8b38a,
distance: 13,
rotationSpeed: 0.02
},
{
name: "Saturn",
size: 1.1,
color: 0xe6c87a,
distance: 16,
rotationSpeed: 0.018
},
{
name: "Uranus",
size: 0.9,
color: 0x66ccdd,
distance: 19,
rotationSpeed: 0.012
},
{
name: "Neptune",
size: 0.85,
color: 0x3355ff,
distance: 22,
rotationSpeed: 0.011
}
];
// ========================
// Create Planets
// ========================
const planets = [];
planetData.forEach(
(data) => {
// 行星球體
const geometry =
new THREE.SphereGeometry(
data.size,
12,
8
);
// 行星本體材質
const material =
new THREE.MeshBasicMaterial({
color: data.color
});
// 建立行星
const planet =
new THREE.Mesh(
geometry,
material
);
// 設定行星位置
planet.position.x =
data.distance;
// ========================
// Wireframe
// ========================
const wireMaterial =
new THREE.MeshBasicMaterial({
color: 0xffffff,
wireframe: true
});
const wire =
new THREE.Mesh(
geometry,
wireMaterial
);
// 稍微放大
// 避免和行星表面重疊
wire.scale.set(
1.03,
1.03,
1.03
);
// 把網格加入行星
planet.add(
wire
);
// 加入場景
scene.add(
planet
);
// 保存資料
planets.push({
mesh: planet,
rotationSpeed:
data.rotationSpeed
});
}
);
// ========================
// Resize
// ========================
window.addEventListener(
"resize",
() => {
camera.aspect =
window.innerWidth /
window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(
window.innerWidth,
window.innerHeight
);
renderer.setPixelRatio(
Math.min(
window.devicePixelRatio,
2
)
);
}
);
// ========================
// Animation
// ========================
function animate() {
requestAnimationFrame(
animate
);
// 太陽自轉
sun.rotation.y +=
0.005;
// 八大行星自轉
planets.forEach(
(planet) => {
planet.mesh.rotation.y +=
planet.rotationSpeed;
}
);
renderer.render(
scene,
camera
);
}
animate();
今天每顆行星都有 rotationSpeed
例如地球:
{
name: "Earth",
size: 0.7,
color: 0x2277ff,
distance: 8,
rotationSpeed: 0.01
}
代表動畫執行時:
planet.mesh.rotation.y +=
planet.rotationSpeed;
地球每一幀都增加 0.01
金星反方向旋轉 rotationSpeed: -0.003 使用負數。
也可以順便看到正負數對旋轉方向的影響。
原本球體是:
new THREE.SphereGeometry(
data.size,
32,
32
);
這樣球體很圓,但是網格也會變得非常密反而不好觀察旋轉。
所以今天暫時改成:
new THREE.SphereGeometry(
data.size,
12,
8
);
網格會變得比較大這樣旋轉就比較容易看出來。
另外建立:
const wireMaterial =
new THREE.MeshBasicMaterial({
color: 0xffffff,
wireframe: true
});
其中 color: 0xffffff 而 wireframe: true 代表只顯示球體的線。
我們並不會改變球體的顏色,其實我們只是在球體的外面增加白色網格,接下來就來說明
今天最重要的新觀念之一:
planet.add(
wire
);
以前我們都是:
scene.add(
planet
);
意思是 Wire 變成 Planet 的子物件所以當 planet.rotation.y += 0.01;
Planet 旋轉時 Wire 也會一起旋轉。
這正是我們今天需要的效果。
再加上這裡:
wire.scale.set(
1.03,
1.03,
1.03
);
也就是比原本行星大一點點,如果彩色球和網格完全一樣大,兩個表面會重疊。
所以讓網格稍微大一點這樣線條就比較清楚。
今天的文章裡只有說到八大行星的網格但並沒有說到太陽的,
大家可以動手試試看自己將太陽也套上網格,至於想要做好的我放在今日小節~
今天最大的重點不只是行星會旋轉
而是讓旋轉看得出來
目前我們完成:
全螢幕場景、太陽、八大行星、不同大小、顏色、距離、自轉速度、白色網格
要注意,這個 Wireframe 是教學用的暫時效果。
到了後面的 Texture:
地球表面、木星條紋、海王星表面、...
加入之後,自轉就能直接從貼圖看出來,到那時候就可以把白色網格移除。
接下來附上太陽網格,把註解 Sun 那段的程式碼覆蓋掉即可
const sunGeometry =
new THREE.SphereGeometry(
2,
32,
16
);
const sunMaterial =
new THREE.MeshBasicMaterial({
color: 0xffaa00
});
const sun =
new THREE.Mesh(
sunGeometry,
sunMaterial
);
const sunwireMaterial =
new THREE.MeshBasicMaterial({
color: 0xffffff,
wireframe: true
});
const sunwire =
new THREE.Mesh(
sunGeometry,
sunwireMaterial
);
sunwire.scale.set(
1.03,
1.03,
1.03
);
sun.add(
sunwire
);
scene.add(
sun
);
完成之後網頁成品如下圖:
「行星公轉:讓八大行星開始繞太陽運行」
Day 11 現在做的是自轉。
Day 12 要做的是公轉。
我們會加入 orbitSpeed 與 angle
並開始使用:
Math.cos()
Math.sin()
計算行星的位置。
這會是將整個網頁從「一排旋轉彩色球」真正變成「太陽系軌道運動」的重要一天。