[JavaScript] 地球と月のミニチュア作成記事

はじめに

MDNのThree.jsに関する解説サンプルの中で、宇宙に地球を描くというのがありますが、それを応用し、魔法陣の上に、ミニチュア的な、地球と月を描き公転と自転をさせるエフェクトを実装してみましたので、そのメモです。

1. 小さな地球と月の模型を作成する目的

地球と月のミニチュア模型を作成することには、いくつかの目的があります。まず、3Dグラフィックスの基礎を学ぶことができます。

特に、Three.jsを使用して、リアルな3Dオブジェクトの作成、アニメーション、カメラ操作、ライティングの設定方法を実践的に学ぶことができます。

このプロジェクトを通じて、自転と公転の同期や、アニメーションの制御について深く理解することができます。月が地球の周りを回りながら自転している状態を再現することは、天文学的な現象をシミュレートするための良い練習です。

また、スケールの調整やスポットライトによる強調で、よりリアルで魅力的なビジュアルを作り出す技術も習得できます。

実際に、このアイデアの一部は、MDNの公式サイトで提供されている「地球を描くサンプル」に触発されて始まりました。

サンプルを見て、地球と月を小さな模型として作成する方法を学び、さらに自分のオリジナルなアニメーションを加えて、動的なシーンを作成する方法に挑戦することを決めました。

このサンプルがきっかけで、Three.jsを使った天体シミュレーションに興味を持ち、地球と月のモデルを作るアイデアが生まれました。

このプロジェクトを通して、3Dグラフィックスの基本的なスキルを磨きつつ、動きのあるリアルなシーンを作成する楽しさを実感できるはずです。

2. 地球と月の基本的なセットアップ

このセクションでは、地球と月のジオメトリを作成し、それぞれにテクスチャを適用する方法と、自転と公転の基本的な設定方法について説明します。まずは、地球と月の形状を作成し、それに適切なテクスチャをマッピングすることで、リアルな見た目を作り上げます。その後、それぞれの自転と公転を設定して、動きが加わるようにします。

地球と月のジオメトリ、テクスチャの設定

地球と月は、球体(SphereGeometry)を使って作成します。地球のジオメトリは比較的大きめに、月のジオメトリは地球に比べて小さめに設定し、それぞれにテクスチャを適用します。テクスチャは、地球の表面のディテールを再現し、月には月面のクレーターや模様を適用します。

// 地球のジオメトリとテクスチャの設定
const earthGeometry = new THREE.SphereGeometry(5, 32, 32);  // 半径5の地球
const earthTexture = config.imgageList.find((item) => item.name === 'earth')?.texture;  // 地球のテクスチャを設定
const earthMaterial = new THREE.MeshStandardMaterial({ map: earthTexture });
const earth = new THREE.Mesh(earthGeometry, earthMaterial);
config.scene.add(earth);  // シーンに追加

// 月のジオメトリとテクスチャの設定
const moonGeometry = new THREE.SphereGeometry(1.5, 32, 32);  // 半径1.5の月
const moonTexture = config.imgageList.find((item) => item.name === 'moon')?.texture;  // 月のテクスチャを設定
const moonMaterial = new THREE.MeshStandardMaterial({ map: moonTexture });
const moon = new THREE.Mesh(moonGeometry, moonMaterial);
config.scene.add(moon);  // シーンに追加

それぞれの自転と公転の設定

地球と月を作成したら、次はそれぞれの自転と公転のアニメーションを設定します。地球の自転は、地球自身が回転する動きです。一方、月の公転は月が地球の周りを回る動きです。月は地球の周りを回るだけでなく、自転もしているので、その同期を取る必要があります。

const orbitRadius = 15;  // 月と地球の距離(公転半径)
let angle = 0;  // 回転角度

// アニメーション関数
function animate() {
  angle += 0.01;  // 公転の角度を進める

  // 月の公転
  moon.position.x = earth.position.x + orbitRadius * Math.cos(angle);  // 月の位置を更新
  moon.position.z = earth.position.z + orbitRadius * Math.sin(angle);  // 月の位置を更新
  moon.position.y = earth.position.y;  // 月は一定の高さに保つ

  // 地球の自転
  earth.rotation.y += 0.01;  // 地球の自転

  // 月の自転(公転と同じ周期で自転させる)
  moon.rotation.y += 0.01;  // 月の自転

  config.renderer.render(config.scene, config.camera);
  requestAnimationFrame(animate);  // 次のフレームで再度呼び出し
}

animate();  // アニメーション開始

解説:

  • 地球の自転: 地球のrotation.yを少しずつ増加させることで、地球が自転しているように見せます。
  • 月の公転: 月は地球の周りを回るので、月の位置をMath.cosMath.sinを使って更新しています。これにより、月が円軌道を描くように動きます。
  • 月の自転: 月は公転しながら自転もしているため、moon.rotation.yを回転させて、月が自転する動きを加えています。

3. 自転と公転の同期

地球と月のシステムにおいて、自転と公転は非常に重要な要素です。特に月は、公転と自転の周期が一致しているため、月は常に地球に同じ面を向けています。このセクションでは、月の自転と公転を同期させる方法について説明します。

公転と自転の周期を合わせる

月が地球の周りを回る公転と、月が自分自身で回転する自転は、実際にはほぼ同じ周期です。月は約27.3日で地球を一周し、同じく約27.3日で自転しています。このため、月は自転しながら地球の周りを公転しても、常に同じ面を地球に向けることになります。

Three.jsでこの同期を実現するためには、月の自転の速度と公転の速度を一致させる必要があります。これにより、月の自転と公転が同期し、リアルな挙動を再現できます。

let angle = 0;  // 回転角度(公転)
let rotationSpeed = 0.01;  // 自転と公転の速度を同じにするため、速度を設定

// アニメーション関数
function animate() {
  angle += rotationSpeed;  // 公転の角度を進める

  // 月の公転
  moon.position.x = earth.position.x + orbitRadius * Math.cos(angle);
  moon.position.z = earth.position.z + orbitRadius * Math.sin(angle);
  moon.position.y = earth.position.y;

  // 地球の自転
  earth.rotation.y += 0.01;  // 地球の自転

  // 月の自転(公転と同じ速度で自転)
  moon.rotation.y += rotationSpeed;  // 月の自転を公転と同期させる

  config.renderer.render(config.scene, config.camera);
  requestAnimationFrame(animate);  // 次のフレームで再度呼び出し
}

animate();  // アニメーション開始

月が地球の周りを回りつつ、月自体も自転する設定

月の自転は、月が公転する過程で自然に行われます。月の自転速度を公転速度と同じに設定することで、月が回転しつつ地球の周りを回るような動きを再現できます。これにより、月は地球に対して常に同じ面を向けて回転している状態を作り出せます。

// 月の自転と公転を同期させるために、月の自転速度と公転速度を同じに設定
let angle = 0;
let rotationSpeed = 0.01;

function animate() {
  angle += rotationSpeed;  // 公転の角度を進める

  // 月の位置を更新(公転)
  moon.position.x = earth.position.x + orbitRadius * Math.cos(angle);
  moon.position.z = earth.position.z + orbitRadius * Math.sin(angle);
  moon.position.y = earth.position.y;  // 月の高さは一定

  // 地球の自転
  earth.rotation.y += 0.01;

  // 月の自転を公転と同期させる
  moon.rotation.y += rotationSpeed;  // 自転を加速させる

  config.renderer.render(config.scene, config.camera);
  requestAnimationFrame(animate);  // 次のフレームで再度呼び出し
}

animate();  // アニメーション開始

解説:

  • 公転と自転の周期合わせ: rotationSpeed の値を月の自転と公転に同じ値で設定することで、月が地球の周りを回りながら自転する動きを再現します。この動きが同期することで、月は常に同じ面を地球に向けることができます。
  • 月の自転: moon.rotation.yrotationSpeed を加えることで、月が自転している様子を作り出します。月は公転しながら自転するため、どちらの動きも同期させる必要があります。

4. スケールの調整

このセクションでは、地球と月、そしてその距離感を一貫して調整する方法について説明します。スケールファクターを使用することで、シーン全体を簡単に拡大・縮小でき、月と地球の相対的なサイズや距離感を保ちながら調整することができます。

スケールファクターを使った全体の拡大縮小

地球と月のサイズやそれらの距離を統一的に調整するために、スケールファクターを使います。これにより、月と地球のサイズ、さらにそれらの間の距離も一度に調整することができます。スケールを手動で個別に調整する手間を省き、簡単に全体を拡大・縮小できるようになります。

// スケールファクターを使って全体の拡大縮小を一括で調整
const scaleFactor = 2;  // 拡大縮小の係数。1で元の大きさ、2で2倍に拡大

// 地球のサイズを調整
earth.scale.set(scaleFactor, scaleFactor, scaleFactor);  // 地球のスケールを設定

// 月のサイズを調整
moon.scale.set(scaleFactor * 0.3, scaleFactor * 0.3, scaleFactor * 0.3);  // 月のスケールは地球の約30%

このように、scale.set() を使用して、地球と月のスケールを調整します。スケールファクターを変更することで、すべてのオブジェクトの大きさを簡単に変更できるため、シーン全体のサイズ感を一貫して保つことができます。

距離とサイズ感のバランス

スケールを調整する際には、地球と月の距離感にも気を付ける必要があります。月と地球の距離を調整するためには、orbitRadius(月の公転半径)も一緒にスケールファクターで調整します。これにより、月が地球の周りを回る距離も、地球や月のサイズに合わせて適切に調整できます。

const orbitRadius = 15 * scaleFactor;  // 月と地球の距離もスケールに合わせて調整

// 公転のアニメーション
function animate() {
  angle += 0.01;

  // 月の位置を更新(スケール後の距離を反映)
  moon.position.x = earth.position.x + orbitRadius * Math.cos(angle);
  moon.position.z = earth.position.z + orbitRadius * Math.sin(angle);
  moon.position.y = earth.position.y;

  // 地球と月の自転
  earth.rotation.y += 0.01;
  moon.rotation.y += 0.01;

  config.renderer.render(config.scene, config.camera);
  requestAnimationFrame(animate);
}

animate();  // アニメーション開始

このように、orbitRadius をスケールファクターに基づいて調整することで、月と地球の相対的な距離を保ちながらシーン全体を拡大・縮小できます。スケールファクターが変わると、月と地球の距離も自然に調整されるため、視覚的に不自然な感じを避けることができます。

5. スポットライトでの強調

このセクションでは、スポットライトを使用して、地球と月を強調し、シーンにリアルなライティング効果を加える方法を説明します。スポットライトは特定の位置から集中して光を放ち、対象物を照らすのに適した光源です。これを活用することで、地球と月を際立たせ、シーン全体の雰囲気を向上させることができます。

地球と月にスポットライトを当てる方法

スポットライトは、特定の方向に光を集中させるため、THREE.SpotLightを使用します。地球と月に対して個別にスポットライトを設定し、それぞれに向けて光を当てることで、強調したい部分を明るく照らします。

// 地球用のスポットライト
const spotLightEarth = new THREE.SpotLight(0xffffff, 1, 100, Math.PI / 4, 0.5);
spotLightEarth.position.set(10, 20, 10);  // スポットライトの位置
spotLightEarth.target = earth;  // スポットライトのターゲットを地球に設定
config.scene.add(spotLightEarth);
config.scene.add(spotLightEarth.target);  // 地球をターゲットに設定

// 月用のスポットライト
const spotLightMoon = new THREE.SpotLight(0xaaaaaa, 1, 100, Math.PI / 4, 0.5);
spotLightMoon.position.set(10, 15, -10);  // スポットライトの位置
spotLightMoon.target = moon;  // スポットライトのターゲットを月に設定
config.scene.add(spotLightMoon);
config.scene.add(spotLightMoon.target);  // 月をターゲットに設定

解説:

  • THREE.SpotLight: スポットライトを作成するためのクラスです。第一引数は光の色(白色、0xffffff)、第二引数は強度、第三引数は光の範囲(100は広い範囲を照らす)、第四引数は光の広がり角度(ここではMath.PI / 4で45度)、第五引数は光の減衰強度です。
  • position.set(x, y, z): スポットライトの位置を設定します。これを調整することで、光が照射される方向を変えることができます。
  • target: スポットライトの照射対象を設定します。earthmoonをターゲットにすることで、地球と月に光を集中させます。
  • config.scene.add(): シーンにスポットライトを追加することで、光源がシーン内に反映されます。

スポットライトの調整

スポットライトを使うことで、地球と月に強調した光を当てることができますが、必要に応じてスポットライトの強さや角度を調整することも重要です。

  • 光の強さ(強度)はTHREE.SpotLightの第二引数で調整できます。例えば、new THREE.SpotLight(0xffffff, 2)とすることで、光の強さを2倍にできます。
  • 範囲(光の到達距離)は第三引数で調整できます。100と設定すると広い範囲を照らし、50だとその半分の距離を照らします。
  • 角度(光の広がり)はMath.PI / 4(45度)で設定されていますが、例えばMath.PI / 6(30度)にすれば、より狭い範囲に集中した光を当てることができます。

効果の確認

スポットライトを追加することで、地球と月がより立体的に見え、光が当たることでその輪郭や質感が強調されます。これにより、シーンに深みと立体感を加えることができ、リアルな天体のシミュレーションが実現できます。

6. まとめ:

このセクションでは、これまでのステップを通じて作成した地球と月のシミュレーションの最終結果を振り返り、スケーリングやライティングの重要性について解説します。これらの要素を調整することで、シーン全体のバランスを整え、よりダイナミックでリアルなビジュアルを作り上げることができました。

地球と月の基本的なセットアップの確認

まず、地球と月のジオメトリを作成し、それぞれにテクスチャを適用することで、リアルな質感を持つモデルを作成しました。公転と自転を同期させることで、月が地球の周りを回りながら自転する動きを作り、自然な天体の挙動をシミュレートしました。この段階では、地球と月が動き出す基本的なアニメーションが完成しました。

スケーリングと距離感の調整

次に、スケーリングを調整することで、地球と月のサイズ、さらに月と地球の距離感を適切に保ちました。スケールファクターを一つの定数で設定し、シーン全体の拡大・縮小を効率的に行いました。これにより、月と地球の相対的なサイズ感を保ちながら、シーン全体を簡単に調整することができました。

スポットライトによる強調

地球と月に対してスポットライトを使用し、特定の部分を強調することで、シーンに立体感と奥行きが加わりました。スポットライトの位置や強度を調整することで、月や地球の細部がより鮮明に浮かび上がり、視覚的なインパクトを増すことができました。これにより、シーンに深みとリアル感が加わり、目を引くビジュアルを作成しました。

自転と公転の動き

月が地球の周りを回る公転と、月自身が回転する自転の同期を取ることで、月が地球に常に同じ面を向けるリアルな動きを作り出しました。これにより、月と地球の挙動が自然に感じられるようになり、天体のシミュレーションが完成しました。

最終結果

最終的に、地球と月が美しく動くシーンが完成しました。スケーリングとライティングを調整することで、全体のバランスが整い、より魅力的で動的な3Dシーンを作り上げることができました。このシミュレーションを通じて、Three.jsを使った3Dグラフィックスの基本的な技術を学びながら、リアルな天体の動きを再現する方法を実践的に理解することができました。