HTML / CSS / JS
ビジュアル
2026/06/22
2026/6/20
暗い空に雲が渦巻き、雨が激しく降り注ぎ、稲妻がランダムに閃く――そんな嵐の夜をThree.jsの3D空間で再現したデモです。
15000個のパーティクルで雨を表現し、テクスチャ付きの雲メッシュを25枚配置してゆっくり回転させることで、重厚感のある雲海を作り出しています。
PointLightのパワーをランダムに変化させることで稲妻のフラッシュを再現し、FogExp2で遠景がぼやけることで奥行きのある空間が広がります。
ヒーローセクションの背景やホラー系サイト、天気をテーマにしたコンテンツなどに活用できます。
<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
このデモは、Three.jsの3Dシーンにパーティクル(雨)、テクスチャ付きメッシュ(雲)、PointLight(雷)を組み合わせて嵐の情景を描画します。
主な機能は以下のとおりです。
THREE.Geometryで15000個の頂点を持つポイントクラウドを生成し、各頂点に個別の速度を持たせて落下させます。画面下に到達した雨粒は上部にリセットされ、無限に降り続けます。opacity: 0.6の半透明で重なり合うことで厚みのある雲海を表現しています。THREE.PointLightのpowerをランダムに50〜550の範囲で変化させることで、稲妻の閃光を再現しています。発生確率は毎フレーム約7%で、位置もランダムに移動します。THREE.FogExp2(指数フォグ、密度0.002)で遠景を霧がかった状態にし、奥行き感と雰囲気を強調しています。rainCount(デフォルト15000)を変更すると、雨の密度が変わります。減らすと軽い雨、増やすと豪雨の雰囲気になります。PointsMaterialのsize(デフォルト0.1)を変更すると、雨粒の見た目の大きさが変わります。animate関数内のp.velocity -= 0.1 + Math.random() * 0.1の値を変更すると、雨の落下速度を調整できます。25を変更すると、雲の密度が変わります。i.rotation.z -= 0.002の値を変更すると、雲の回転の速さが変わります。Math.random() > 0.93の値を小さくすると雷が頻繁に発生し、大きくすると穏やかになります。flashのPointLightのカラー(デフォルト0x062d89、青系)を変更すると、稲妻の色味が変わります。白(0xffffff)にするとリアルな雷に近づきます。FogExp2の密度(0.002)を大きくするとフォグが濃くなり、視界が狭まります。loader.loadのURLを差し替えると、雲の見た目を変えられます。THREE.Geometryとverticesを使っています。これらはr125以降で非推奨、r150で完全に削除されたため、新しいバージョンのThree.jsでは動作しません。アップグレードする場合はTHREE.BufferGeometryへの書き換えが必要です。cdnjs.cloudflare.com)からThree.js r124を読み込んでいます。本番環境ではローカルホスティングを推奨します。assets.codepen.io)から読み込んでいます。このURLが利用できなくなると雲が表示されず、animateも呼び出されないため画面が真っ黒になります。本番では画像をローカルに配置してください。rainCountや雲の枚数を減らすことで軽減できます。verticesNeedUpdate: 毎フレームrainGeo.verticesNeedUpdate = trueを設定して頂点データの更新を通知しています。これは旧API固有の処理です。