重なり合う波を描画するためのHTMLコードを、Three.jsを使用して作成します。Three.jsはWebGLをラップしたJavaScriptライブラリで、3Dグラフィックスを簡単に描画できます。以下のコードでは、複数の波を表現するためにPlaneGeometryを使い、シェーダーで波の動きをシミュレートします。
-
はじめに
Three.jsは、WebGLの機能を簡単に扱えるJavaScriptライブラリとして広く利用されている。本稿では、Three.jsを用いて複数の波が重なり合う動的な波動のシミュレーションを実装する方法を論じる。特に、本実装ではシェーダープログラムを使用して頂点の動きを制御し、アニメーション化された波の動きを実現している。本稿の目的は、3Dグラフィックスにおける動的な波のシミュレーションの基本概念と、その実装手法について解説することである。 -
背景
WebGLはWebブラウザ上でハードウェアアクセラレーションを用いた3Dグラフィックスを描画するためのAPIであり、Three.jsはその利用を簡素化するためのラッパーライブラリである。特に、Three.jsのシェーダーマテリアル(ShaderMaterial)を使用することで、頂点およびフラグメントシェーダーのカスタマイズが可能となり、様々な視覚効果を作り出すことができる。本稿では、このシェーダープログラミングの手法を用いて、2次元平面上における重なり合う波の動きをシミュレートする。 -
実装方法
3.1 基本構造
シーンの構成は、Three.jsを用いて行う。まず、Sceneオブジェクトと、視野角75度のPerspectiveCameraを初期化する。WebGLRendererは、ブラウザの描画領域のサイズに合わせてレンダリングを行うために使用される。PlaneGeometryは波を表現するための平面を作成し、その上にシェーダーマテリアルを適用することで、重なり合う波の動きを表現する。
3.2 シェーダーの設定
波のアニメーションは、ShaderMaterialを使用してカスタムのシェーダーを定義することにより実現される。ShaderMaterialは、vertexShaderとfragmentShaderを含む2つの主要なシェーダープログラムを提供する。以下、それぞれのシェーダーの動作について解説する。
3.2.1 頂点シェーダー (vertexShader)
頂点シェーダーは、各頂点の位置を制御するプログラムである。ここでは、uniform変数として時間を表すuTimeを定義し、頂点の位置を時間に基づいて変化させる。
pos.z=sin(pos.x×2.0+uTime)×0.5+sin(pos.y×3.0+uTime×0.5)×0.5
この式により、x方向およびy方向に異なる周波数の正弦波が生成され、時間uTimeの増加に伴って波の動きを再現することができる。
3.2.2 フラグメントシェーダー (fragmentShader)
フラグメントシェーダーは、各ピクセルの色を制御するプログラムである。本実装では、波の表面の色を単色で設定している。
3.3 アニメーションの実装
requestAnimationFrameを用いてアニメーションループを実装する。毎フレーム、時間を表すuTimeを更新し、シーン全体をレンダリングする。これにより、リアルタイムで波が動くような視覚効果を作り出す。
-
実験結果
本実装により、平面上に重なり合う波のアニメーションを生成できた。頂点シェーダーを用いて波の動きを制御し、フラグメントシェーダーでその色を設定することにより、単純ながら動的な波の表現を実現した。特に、sin関数を用いることで、滑らかでリアルな波動のアニメーションをシンプルな数式で表現できた点が特徴的である。また、ShaderMaterialを活用することで、CPU側の負荷を抑えながらGPUで効率的にレンダリングを行えた。 -
考察
今回の実装において、シェーダーを利用して波の動きを表現することで、リアルタイム性の高いシミュレーションを実現できた。さらに、異なる周波数の波を重ね合わせることで、より複雑で自然な波動を表現することが可能であった。しかし、波の色や形状などのさらなるカスタマイズや、ユーザーインタラクションを導入することにより、より多様な視覚効果を生み出すことが可能であると考えられる。 -
結論
本稿では、Three.jsを用いて重なり合う波のアニメーションを実装する手法について解説した。シェーダープログラミングを活用することで、シンプルな数学的モデルに基づくリアルタイムの波動シミュレーションを実現できた。本手法は、自然現象のビジュアライゼーションや、インタラクティブなWebコンテンツの開発に応用可能である。今後の展望として、異なるパラメーターや関数を用いた波動の生成、さらにはユーザーの操作に応じた動的な変化の導入が挙げられる。
参考文献
Three.js Documentation: https://threejs.org/docs/
WebGL Fundamentals: https://webglfundamentals.org/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Overlapping Waves with Three.js</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<!-- Three.js ライブラリの読み込み -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// シーン、カメラ、レンダラーのセットアップ
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 波を表現するための平面ジオメトリの作成
const geometry = new THREE.PlaneGeometry(20, 20, 100, 100);
// 波の動きを制御するためのカスタムシェーダーマテリアル
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0.0 } // 時間を表すuniform変数
},
vertexShader: `
uniform float uTime;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
// 頂点のz位置を時間とx、y座標に基づいて変更し、波の動きをシミュレート
pos.z = sin(pos.x * 2.0 + uTime) * 0.5 + sin(pos.y * 3.0 + uTime * 0.5) * 0.5;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
void main() {
// 波の色を設定(今回は固定色)
gl_FragColor = vec4(0.2, 0.5, 0.7, 1.0);
}
`,
wireframe: true // ワイヤーフレームで描画
});
// メッシュの作成とシーンへの追加
const wave = new THREE.Mesh(geometry, material);
scene.add(wave);
// カメラの位置を設定
camera.position.z = 5;
// アニメーションループ
function animate() {
requestAnimationFrame(animate);
// 時間の更新
material.uniforms.uTime.value += 0.05;
// シーンをレンダリング
renderer.render(scene, camera);
}
animate(); // アニメーションの開始
// ウィンドウサイズ変更に対応するためのイベントリスナー
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>