はじめに
WebGLの知識なしで地球と月を回してみよう!
と言うことで、この記事ではJavaScriptの知識があれば簡単に3Dコンテンツを作成できるので見て行ってください。
大まかな流れ
1.黒い画面を表示
2.球体を表示
3.地球に画像を貼る
4.地球に動きを加える
5.月を作成し動きを加える
Try three.js
セットアップ
この記事ではCDNを使うのでnpm
を使用したい方はこちらに飛んでチェックしてね。
まずindex.html, index.jsこの2つのファイルをつくります。
下記のhtmlをコピペしてindex.jsファイルを作成しthree.jsを使えるように準備しよう。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>try three.js</title>
<link rel="stylesheet" href="style.css" />
</head>
<body style="margin: 0;">
<canvas id="myCanvas" style="width:100%;height:100%;"></canvas>
<!-- three.jsのCDN -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"
integrity="sha512-dLxUelApnYxpLt6K2iomGngnHO83iUvZytA3YjDUCjT0HDOHKXnVYdf3hU4JjM8uEhxf9nD1/ey98U3t2vZ0qQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<script src="index.js"></script>
</body>
</html>
黒い画面を表示
window.addEventListener("load", init);
function init() {
// サイズを指定
const width = 960;
const height = 540;
// シーンを作成
const scene = new THREE.Scene();
// カメラを作成
const camera = new THREE.PerspectiveCamera(45, width / height);
// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector("#myCanvas"),
});
renderer.setSize(window.innerWidth, window.innerHeight);
}
まずthree.jsで最も重要な3つの定数を準備します。
scene
、camera
、renderer
です。
scene
scene
を使用すると、three.jsで何をどこにレンダリングするかを設定できます。ここにオブジェクト、ライト、カメラを配置します。
// シーンを作成
const scene = new THREE.Scene();
camera
3Dではどの視点から空間を撮影するか、という実装をします。この機能は「視点」や「カメラ」と呼ばれます。
当たり前ですがカメラがないと何も映らないので必ず用意しましょう。
// カメラを作成
const camera = new THREE.PerspectiveCamera(45, width / height);
renderer
renderer
は3Dコンテンツをrenderer.setSize()
で指定した大きさでmyCanvas
タグに描画します。
// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector("#myCanvas"),
});
renderer.setSize(window.innerWidth, window.innerHeight);;
一度 Open with Live Serverで画面を確認してみましょう。
このように黒い画面が表示されたらOKです。
次にスポットライトと3Dコンテンツを用意します。
球体を表示
// カメラを作成
// const camera = new THREE.PerspectiveCamera(45, width / height);
// == このコードの下に追加してください。 ==
camera.position.z = 100;
// ===================================
// ジオメトリ作成
const geometry = new THREE.SphereGeometry(15, 32, 16);
// マテリアルを作成
const material = new THREE.MeshPhongMaterial({
color: 0x49ef4,
polygonOffset: true,
polygonOffsetFactor: 1,
polygonOffsetUnits: 1,
});
// 球体メッシュを作成
const earth = new THREE.Mesh(geometry, material);
// 3D空間にメッシュを追加
scene.add(earth);
// 平行光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.9);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// 毎フレーム時に実行されるループイベント
function tick() {
// レンダリング
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
tick();
次に球体を作成しますが、まずどの距離から撮るのかを決めます。
指定しないと0距離で地球を撮影するのでなんの惑星なのかわかりません。
なので100離れた場所から惑星を撮る処理をcamera
の下に記述を追加します。
// カメラを作成
// const camera = new THREE.PerspectiveCamera(45, width / height);
// == このコードの下に追加してください。 ==
camera.position.z = 100;
// ===================================
次にどのような惑星を作るかを決めます。
今回は球体作成のするのでSphereGeometry()
を使用します。
この関数で球体作成、大きさ指定などをしてます。
引数には半径、水平セグメントの数、垂直セグメントの数が入ります。
関数の詳細はこちらを参照してください。
// ジオメトリ作成
const geometry = new THREE.SphereGeometry(15, 32, 16);
次に惑星の色や素材を決めます。
material
は球体の材質を指定します。
今回は鏡面ハイライトと光沢のある表面の素材を使用します。
関数の詳細はこちらです。
// マテリアルを作成
const material = new THREE.MeshPhongMaterial({
color: 0x49ef4,
polygonOffset: true,
polygonOffsetFactor: 1,
polygonOffsetUnits: 1
});
先ほど作ったジオメトリとマテリアルをmesh
で組み合わせます。
組み合わせたものをscene
に追加します。
// 球体メッシュを作成
const earth = new THREE.Mesh(geometry, material);
// 3D空間にメッシュを追加
scene.add(earth);
惑星を照らすスポットライトを作成します。
スポットライトがなくては何も見えないので必ず設定していきましょう。
DirectionalLight()
は特定の方向に光を放射します。
一般的な使用例は、日光のシミュレートです。
太陽の位置は無限であると見なすことができ、太陽からのすべての光線は平行です。
平行光源を指定したらscene
に追加します。
関数の詳細はこちらです。
// 平行光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.9);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
最後にscene
とcamera
をレンダリングするためにtick()
を作成します。
// 毎フレーム時に実行されるループイベント
function tick() {
// レンダリング
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
tick();
もう一度Open with Live Serverで開いたサイトを見ると...
これで球体の3Dコンテンツを作成できました。
この青い球体を地球にしていきましょう!
地球に画像を貼る
先ほど作った青い球体に地球の画像を貼ります。
こちらで高画質な惑星の画像をダウンロードできます。
興味のある方は色々な惑星があるので好きな惑星に変えてみましょう!
マテリアルの中の記述を変更します。
球体に貼りたい画像のパスをmap
に記述してください。
// マテリアルを作成
// const material = new THREE.MeshPhongMaterial( {
// color: 0x49ef4,
// polygonOffset: true,
// polygonOffsetFactor: 1,
// polygonOffsetUnits: 1
// });
// ⬇︎
const material = new THREE.MeshStandardMaterial({
// 画像を指定
map: new THREE.TextureLoader().load("惑星の画像を指定"),
side: THREE.DoubleSide,
});
地球に動きを加える
tick()
が呼び出されたら球体をy軸0.01づつずらす処理を追加します。
// 毎フレーム時に実行されるループイベント
function tick() {
// == 追加 ==
earth.rotation.y += 0.01
// ==========
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
tick();
Open with Live Serverして確認をしましょう。
🌏地球が回りました!
月を作成し動きを加える
最後に月を追加し動かしてみましょう。
地球をつくる流れを思い出しみましょう。
geometry
とmaterial
をつくりmesh
で組み合わせてscene
に追加します。
月を地球の周りに回したいのでposition
で指定します。
指定をしないと地球と被って見えなくなるので気を付けましょう。
const geometry2 = new THREE.SphereGeometry(3, 32, 16);
const material2 = new THREE.MeshStandardMaterial({
map: new THREE.TextureLoader().load("moon.jpg"),
side: THREE.DoubleSide,
});
const moon = new THREE.Mesh(geometry2, material2);
scene.add(moon);
let radius = 30;// 半径
let radian = 0;// 角度
function tick() {
earth.rotation.y += 0.01
// == 追加 ==
moon.position.x = radius * Math.cos(radian);// 月を周回させる
moon.position.z = radius * Math.sin(radian);
radian += 0.01;// 角度に加算する
// ==========
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
tick();
最後にOpen with Live Serverで表示を確認してみましょう!
終わりに
three.jsを触ってみてどうだったでしょうか?
ぜひ、惑星を変えたり増やしたり遊んでみてください!
この記事でもっとthree.jsを触ってみたいと思っていただければ嬉しいです!