Three.jsで簡単な動き地球を作ってみた

初めまして!
今年の7月に中途入社したKOOと申します。

エンジニア

KOO

Webの動きを表現するのが好きで、
これからどんどん情報を発信していきたいと思っています。
よろしくお願いいたします!

エンジニア

KOO

さて、今回はThree.jsを使って動くページを作成してみたいと思います。

See the Pen
Three.jsで簡単な動きサイトを作ってみた
by KOO (@Xueni-Gu)
on CodePen.

基本的なテンプレートを設定


// HTML-Three.js ライブラリの読み込み
src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"

// CSS-画面全体のレイアウト設定
body {
  margin: 0; overflow: hidden;
}
canvas {
  display: block;
}
#text-overlay {
    position: absolute;
    top: 50%;
    left: 20%;
    transform: translateY(-50%);
    color: white;
    font-weight: bold;
    font-family: Arial, sans-serif;
    font-size: 36px;
    text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}


// Three.jsのセットアップ
// シーン、カメラ、レンダラーの作成
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);

// ウィンドウのリサイズ処理
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

地球のメッシュを作成

SphereGeometryを作成し、カメラの位置とレンダリングを設定

地球のメッシュを作成


// 地球のジオメトリを作成
const earthGeometry = new THREE.SphereGeometry(1, 64, 64);

// 地球のメッシュを作成
const earth = new THREE.Mesh(earthGeometry);
scene.add(earth);

// カメラの位置を設定
camera.position.set(1, 0, 4); // カメラを少し遠ざける

// レンダリング
renderer.render(scene, camera);

地球のマテリアルを作成


// 地球のジオメトリを作成
const earthGeometry = new THREE.SphereGeometry(1, 64, 64);

// 地球のマテリアルを作成
const earthMaterial = new THREE.MeshPhongMaterial({
    specular: new THREE.Color('grey'),
});

// 地球のメッシュを作成
const earth = new THREE.Mesh(earthGeometry, earthMaterial);
scene.add(earth);

画面が見えるように光も追加

画面が見えるように光も追加


// 環境光を追加
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambientLight);

// 平行光源を追加して太陽光をシミュレート
const sunLight = new THREE.DirectionalLight(0xffffff, 1);
sunLight.position.set(5, 3, 5);
scene.add(sunLight);

地球のテクスチャを作成

地球のテクスチャを作成


// 地球のジオメトリを作成
const earthGeometry = new THREE.SphereGeometry(1, 64, 64);

// 地球のテクスチャを読み込む
const textureLoader = new THREE.TextureLoader();
const earthTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg');
const earthNormalMap = textureLoader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg');
const earthSpecularMap = textureLoader.load('https://threejs.org/examples/textures/planets/earth_specular_2048.jpg');

// 地球のマテリアルを作成
const earthMaterial = new THREE.MeshPhongMaterial({
    map: earthTexture,
    normalMap: earthNormalMap,
    specularMap: earthSpecularMap,
    specular: new THREE.Color('grey'),
    shininess: 10
});

// ....

// アニメーションループ(シーンを継続的に更新し再描画するために、アニメーションループが必要です。)
function animate() {
    requestAnimationFrame(animate);
    // 地球をゆっくり回転させる
    earth.rotation.y += 0.002;
    renderer.render(scene, camera);
}
animate();

これでもう完成ですが、見た目をさらによくするために、雲層と大気圏も作りましょう。

雲層を追加

雲層を追加


//...

// 雲層を作成
const cloudsGeometry = new THREE.SphereGeometry(1.01, 64, 64);
const cloudsTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_clouds_1024.png');
const cloudsMaterial = new THREE.MeshPhongMaterial({
    map: cloudsTexture,
    transparent: true,
    opacity: 0.4 // 雲の不透明度を下げる
});
const clouds = new THREE.Mesh(cloudsGeometry, cloudsMaterial);
earth.add(clouds);

// カメラの位置を少し調整し、センターに移動
camera.position.set(0, 0, 5);

//...

// アニメーションループ
function animate() {
    requestAnimationFrame(animate);
    // 地球をゆっくり回転させる
    earth.rotation.y += 0.002;
    clouds.rotation.y += 0.0023;
    renderer.render(scene, camera);
}
animate();

大気圏を追加

大気圏を追加


// 大気圏の光輪効果を作成
const atmosphereGeometry = new THREE.SphereGeometry(1.1, 64, 64);
const atmosphereMaterial = new THREE.ShaderMaterial({
    vertexShader: `
        varying vec3 vNormal;
        void main() {
            vNormal = normalize(normalMatrix * normal);
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
    `,
    fragmentShader: `
        varying vec3 vNormal;
        void main() {
            float intensity = pow(0.7 - dot(vNormal, vec3(0.0, 0.0, 1.0)), 2.0);
            gl_FragColor = vec4(0.3, 0.6, 1.0, 1.0) * intensity;
        }
    `,
    blending: THREE.AdditiveBlending,
    side: THREE.BackSide
});
const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
scene.add(atmosphere);

最後に背景を追加したら完成です!

星空の背景を追加

星空の背景を追加


// 星空の背景を追加
const starsGeometry = new THREE.BufferGeometry();
const starsMaterial = new THREE.PointsMaterial({color: 0xffffff, size: 0.02});
const starsVertices = [];
for (let i = 0; i < 10000; i++) {
    const x = THREE.MathUtils.randFloatSpread(2000);
    const y = THREE.MathUtils.randFloatSpread(2000);
    const z = THREE.MathUtils.randFloatSpread(2000);
    starsVertices.push(x, y, z);
}
starsGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starsVertices, 3));
const starField = new THREE.Points(starsGeometry, starsMaterial);
scene.add(starField);

おわりに

いかがでしょうか?基本的な考え方は、まずシーン、カメラ、レンダラーを設定し、カメラの位置を調整します。そのあとでSphereGeometryを三つ作成し、それぞれに異なるマテリアルを与えて、同じ場所に配置します。

最後まで読んでいただき、ありがとうございます。これからも頑張ります!

 

記事を読んで興味を持った方はぜひコチラから↓