ビジュアル

Three.jsで作る、雷が光る3Dストームエフェクト

投稿日2026/06/22

更新日2026/6/20

暗い空に雲が渦巻き、雨が激しく降り注ぎ、稲妻がランダムに閃く――そんな嵐の夜をThree.jsの3D空間で再現したデモです。

15000個のパーティクルで雨を表現し、テクスチャ付きの雲メッシュを25枚配置してゆっくり回転させることで、重厚感のある雲海を作り出しています。

PointLightのパワーをランダムに変化させることで稲妻のフラッシュを再現し、FogExp2で遠景がぼやけることで奥行きのある空間が広がります。

ヒーローセクションの背景やホラー系サイト、天気をテーマにしたコンテンツなどに活用できます。

Code コード

<canvas id="kumonosu-canvas"></canvas>
body {
	margin: 0;
	overflow: hidden;
	background-color: #000;
}
#kumonosu-canvas {
	display: block;
	width: 100vw;
	height: 100vh;
}
let scene, camera, renderer, cloudParticles = [],
	flash, rain, rainGeo, rainCount = 15000;

function init() {
	scene = new THREE.Scene();
	camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
	camera.position.z = 1;
	camera.rotation.x = 1.16;
	camera.rotation.y = -0.12;
	camera.rotation.z = 0.27;
	scene.add(new THREE.AmbientLight(0x555555));
	let directionalLight = new THREE.DirectionalLight(0xffeedd);
	directionalLight.position.set(0, 1, 0);
	scene.add(directionalLight);
	flash = new THREE.PointLight(0x062d89, 30, 500, 1.7);
	flash.position.set(200, 300, 100);
	scene.add(flash);
	// JS内での取得IDも kumonosu-canvas に変更
	const kumonosuCanvasElement = document.getElementById('kumonosu-canvas');
	renderer = new THREE.WebGLRenderer({
		canvas: kumonosuCanvasElement,
		antialias: true
	});
	scene.fog = new THREE.FogExp2(0x11111f, 0.002);
	renderer.setClearColor(scene.fog.color);
	renderer.setSize(window.innerWidth, window.innerHeight);
	// 雨の生成
	rainGeo = new THREE.Geometry();
	for (let j = 0; j < rainCount; j++) {
		let rainDrop = new THREE.Vector3(Math.random() * 400 - 200, Math.random() * 500 - 250, Math.random() * 400 - 200);
		rainDrop.velocity = 0;
		rainGeo.vertices.push(rainDrop);
	}
	let rainMaterial = new THREE.PointsMaterial({
		color: 0xaaaaaa,
		size: 0.1,
		transparent: true
	});
	rain = new THREE.Points(rainGeo, rainMaterial);
	scene.add(rain);
	// 雲の生成
	let loader = new THREE.TextureLoader();
	loader.load("https://assets.codepen.io/682745/cloud2.png", function(texture) {
		let cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
		let cloudMaterial = new THREE.MeshLambertMaterial({
			map: texture,
			transparent: true
		});
		for (let i = 0; i < 25; i++) {
			let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
			cloud.position.set(Math.random() * 800 - 400, 500, Math.random() * 500 - 450);
			cloud.rotation.x = 1.16;
			cloud.rotation.y = -0.12;
			cloud.rotation.z = Math.random() * 360;
			cloud.material.opacity = 0.6;
			cloudParticles.push(cloud);
			scene.add(cloud);
		}
		animate();
	});
	window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
	cloudParticles.forEach(i => {
		i.rotation.z -= 0.002;
	});
	rainGeo.vertices.forEach(p => {
		p.velocity -= 0.1 + Math.random() * 0.1;
		p.y += p.velocity;
		if (p.y < -200) {
			p.y = 200;
			p.velocity = 0;
		}
	});
	rainGeo.verticesNeedUpdate = true;
	rain.rotation.y += 0.002;
	if (Math.random() > 0.93 || flash.power > 100) {
		if (flash.power < 100) {
			flash.position.set(Math.random() * 400, 300 + Math.random() * 200, 100);
		}
		flash.power = 50 + Math.random() * 500;
	}
	renderer.render(scene, camera);
	requestAnimationFrame(animate);
}
init();
https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.min.js

Explanation 詳しい説明

仕様

このデモは、Three.jsの3Dシーンにパーティクル(雨)、テクスチャ付きメッシュ(雲)、PointLight(雷)を組み合わせて嵐の情景を描画します。

主な機能は以下のとおりです。

  • 雨パーティクル: THREE.Geometryで15000個の頂点を持つポイントクラウドを生成し、各頂点に個別の速度を持たせて落下させます。画面下に到達した雨粒は上部にリセットされ、無限に降り続けます。
  • 雲の描画: 外部テクスチャ画像を貼った500×500の平面メッシュを25枚、カメラの上方にランダム配置しています。各雲はZ軸周りにゆっくり回転し、opacity: 0.6の半透明で重なり合うことで厚みのある雲海を表現しています。
  • 雷のフラッシュ: THREE.PointLightのpowerをランダムに50〜550の範囲で変化させることで、稲妻の閃光を再現しています。発生確率は毎フレーム約7%で、位置もランダムに移動します。
  • フォグ: THREE.FogExp2(指数フォグ、密度0.002)で遠景を霧がかった状態にし、奥行き感と雰囲気を強調しています。
  • ライティング: 環境光(AmbientLight)とディレクショナルライトで基本照明を設定し、雷用のPointLightが加わる3灯構成です。
  • カメラアングル: カメラを俯瞰気味に傾け(rotation.x = 1.16)、見上げるような構図で嵐を体感できます。

カスタマイズ

  • 雨の量: rainCount(デフォルト15000)を変更すると、雨の密度が変わります。減らすと軽い雨、増やすと豪雨の雰囲気になります。
  • 雨粒のサイズ: PointsMaterialsize(デフォルト0.1)を変更すると、雨粒の見た目の大きさが変わります。
  • 雨の速度: animate関数内のp.velocity -= 0.1 + Math.random() * 0.1の値を変更すると、雨の落下速度を調整できます。
  • 雲の枚数: 雲生成ループの25を変更すると、雲の密度が変わります。
  • 雲の回転速度: i.rotation.z -= 0.002の値を変更すると、雲の回転の速さが変わります。
  • 雷の頻度: Math.random() > 0.93の値を小さくすると雷が頻繁に発生し、大きくすると穏やかになります。
  • 雷の色: flashPointLightのカラー(デフォルト0x062d89、青系)を変更すると、稲妻の色味が変わります。白(0xffffff)にするとリアルな雷に近づきます。
  • フォグの濃さ: FogExp2の密度(0.002)を大きくするとフォグが濃くなり、視界が狭まります。
  • 雲のテクスチャ: loader.loadのURLを差し替えると、雲の見た目を変えられます。

注意点

  • Three.jsの旧API使用: Three.js r124を使用しており、THREE.Geometryverticesを使っています。これらはr125以降で非推奨、r150で完全に削除されたため、新しいバージョンのThree.jsでは動作しません。アップグレードする場合はTHREE.BufferGeometryへの書き換えが必要です。
  • Three.jsの読み込み: CDN(cdnjs.cloudflare.com)からThree.js r124を読み込んでいます。本番環境ではローカルホスティングを推奨します。
  • 雲テクスチャの外部依存: 雲のテクスチャ画像をCodePen Assets(assets.codepen.io)から読み込んでいます。このURLが利用できなくなると雲が表示されず、animateも呼び出されないため画面が真っ黒になります。本番では画像をローカルに配置してください。
  • パフォーマンス: 15000個のパーティクル+25枚の半透明メッシュを毎フレーム更新・描画するため、低スペック端末では処理が重くなる場合があります。rainCountや雲の枚数を減らすことで軽減できます。
  • verticesNeedUpdate: 毎フレームrainGeo.verticesNeedUpdate = trueを設定して頂点データの更新を通知しています。これは旧API固有の処理です。
  • カメラ固定: カメラの位置と回転は固定されており、ユーザー操作による視点変更はできません。OrbitControlsを追加することで自由な視点移動が可能になります。
  • リサイズ対応: ウィンドウリサイズ時にカメラのアスペクト比とレンダラーサイズを更新しています。雨や雲の配置範囲は固定のため、極端なアスペクト比では余白が見える場合があります。