はじめに
Three.jsで太陽系っぽい3Dアプリを開発しました。
有名な衛星
有名な衛星も追加しました。
- 地球の月
- 木星のイオ
- 木星のエウロパ
- 木星のガニメデ
- 木星のカリスト
- 土星のエンケラドゥス
コード
solarSystem.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solar System in 3D</title>
<style>
body { margin: 0; }
canvas { display: block; }
#controls { position: absolute; top: 10px; left: 10px; color: white; }
#slider { width: 200px; }
label { color: white; }
</style>
</head>
<body>
<div id="controls">
<label for="speed">速度:</label>
<input type="range" id="speed" name="speed" min="0.1" max="10" value="1" step="0.1">
<br>
<button id="camera-up">上</button>
<button id="camera-down">下</button>
<button id="camera-in">拡大</button>
<button id="camera-out">縮小</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// シーンのセットアップ
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// ライトの設定
const pointLight = new THREE.PointLight(0xffffff, 1, 1000);
pointLight.position.set(0, 0, 0);
scene.add(pointLight);
const ambientLight = new THREE.AmbientLight(0x404040, 1.5);
scene.add(ambientLight);
// 惑星作成関数
function createPlanet(size, color, distance) {
const geometry = new THREE.SphereGeometry(size, 32, 32);
const material = new THREE.MeshPhongMaterial({ color: color });
const planet = new THREE.Mesh(geometry, material);
planet.userData.distance = distance;
scene.add(planet);
return planet;
}
// 軌道作成関数
function createOrbit(distance) {
const curve = new THREE.EllipseCurve(0, 0, distance, distance, 0, 2 * Math.PI, false, 0);
const points = curve.getPoints(50);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xffffff });
const ellipse = new THREE.Line(geometry, material);
ellipse.rotation.x = Math.PI / 2; // XZ平面に回転
scene.add(ellipse);
}
// 衛星作成関数
function createMoon(size, color, distance, planet) {
const geometry = new THREE.SphereGeometry(size, 32, 32);
const material = new THREE.MeshPhongMaterial({ color: color });
const moon = new THREE.Mesh(geometry, material);
moon.userData = { distance: distance, parent: planet };
scene.add(moon);
return moon;
}
// 太陽と惑星の生成
const sun = createPlanet(5, 0xffff00, 0);
const mercury = createPlanet(0.5, 0xaaaaaa, 8);
createOrbit(8);
const venus = createPlanet(0.9, 0xffa500, 12);
createOrbit(12);
const earth = createPlanet(1, 0x0000ff, 16);
createOrbit(16);
const mars = createPlanet(0.7, 0xff4500, 20);
createOrbit(20);
const jupiter = createPlanet(2.2, 0xffa07a, 28);
createOrbit(28);
const saturn = createPlanet(2, 0xf4a460, 35);
createOrbit(35);
// 各惑星の有名な衛星の追加
const earthMoon = createMoon(0.3, 0x888888, 2, earth); // 地球の月
const io = createMoon(0.4, 0xffddaa, 3, jupiter); // 木星のイオ
const europa = createMoon(0.35, 0xaaccff, 4, jupiter); // 木星のエウロパ
const ganymede = createMoon(0.5, 0xcccccc, 5, jupiter); // 木星のガニメデ
const callisto = createMoon(0.45, 0x999999, 6, jupiter); // 木星のカリスト
const titan = createMoon(0.45, 0xffdd88, 4, saturn); // 土星のタイタン
const enceladus = createMoon(0.2, 0xffffff, 2.5, saturn); // 土星のエンケラドゥス
// カメラの位置設定
camera.position.set(30, 30, 50);
camera.lookAt(0, 0, 0);
// 公転周期の比率 (地球 = 1)
const orbitSpeeds = {
mercury: 4.15, // 約88日
venus: 1.62, // 約225日
earth: 1.0, // 約365日
mars: 0.53, // 約687日
jupiter: 0.084, // 約12年
saturn: 0.034, // 約29年
};
// アニメーションループ
let speedMultiplier = 1;
function animate() {
requestAnimationFrame(animate);
speedMultiplier = document.getElementById("speed").value;
// 各惑星の公転を周期比率で調整
mercury.position.x = mercury.userData.distance * Math.cos(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.mercury);
mercury.position.z = mercury.userData.distance * Math.sin(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.mercury);
venus.position.x = venus.userData.distance * Math.cos(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.venus);
venus.position.z = venus.userData.distance * Math.sin(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.venus);
earth.position.x = earth.userData.distance * Math.cos(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.earth);
earth.position.z = earth.userData.distance * Math.sin(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.earth);
mars.position.x = mars.userData.distance * Math.cos(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.mars);
mars.position.z = mars.userData.distance * Math.sin(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.mars);
jupiter.position.x = jupiter.userData.distance * Math.cos(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.jupiter);
jupiter.position.z = jupiter.userData.distance * Math.sin(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.jupiter);
saturn.position.x = saturn.userData.distance * Math.cos(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.saturn);
saturn.position.z = saturn.userData.distance * Math.sin(Date.now() * 0.002 * speedMultiplier * orbitSpeeds.saturn);
// 地球の月の回転
earthMoon.position.x = earth.position.x + earthMoon.userData.distance * Math.cos(Date.now() * 0.005 * speedMultiplier);
earthMoon.position.z = earth.position.z + earthMoon.userData.distance * Math.sin(Date.now() * 0.005 * speedMultiplier);
// 木星の衛星
io.position.x = jupiter.position.x + io.userData.distance * Math.cos(Date.now() * 0.004 * speedMultiplier);
io.position.z = jupiter.position.z + io.userData.distance * Math.sin(Date.now() * 0.004 * speedMultiplier);
europa.position.x = jupiter.position.x + europa.userData.distance * Math.cos(Date.now() * 0.003 * speedMultiplier);
europa.position.z = jupiter.position.z + europa.userData.distance * Math.sin(Date.now() * 0.003 * speedMultiplier);
ganymede.position.x = jupiter.position.x + ganymede.userData.distance * Math.cos(Date.now() * 0.0025 * speedMultiplier);
ganymede.position.z = jupiter.position.z + ganymede.userData.distance * Math.sin(Date.now() * 0.0025 * speedMultiplier);
callisto.position.x = jupiter.position.x + callisto.userData.distance * Math.cos(Date.now() * 0.002 * speedMultiplier);
callisto.position.z = jupiter.position.z + callisto.userData.distance * Math.sin(Date.now() * 0.002 * speedMultiplier);
// 土星の衛星
titan.position.x = saturn.position.x + titan.userData.distance * Math.cos(Date.now() * 0.0015 * speedMultiplier);
titan.position.z = saturn.position.z + titan.userData.distance * Math.sin(Date.now() * 0.0015 * speedMultiplier);
enceladus.position.x = saturn.position.x + enceladus.userData.distance * Math.cos(Date.now() * 0.003 * speedMultiplier);
enceladus.position.z = saturn.position.z + enceladus.userData.distance * Math.sin(Date.now() * 0.003 * speedMultiplier);
renderer.render(scene, camera);
}
animate();
// カメラ操作
document.getElementById("camera-up").addEventListener("click", function() {
camera.position.y += 5;
camera.lookAt(0, 0, 0);
});
document.getElementById("camera-down").addEventListener("click", function() {
camera.position.y -= 5;
camera.lookAt(0, 0, 0);
});
document.getElementById("camera-in").addEventListener("click", function() {
camera.position.z -= 5;
camera.lookAt(0, 0, 0);
});
document.getElementById("camera-out").addEventListener("click", function() {
camera.position.z += 5;
camera.lookAt(0, 0, 0);
});
</script>
</body>
</html>