Water.jsを使って水を表現する(Three.js[r145])
Three.jsでリアルな水面を表現したい方へ。
この記事では、Water.jsを使って流れる水の動きや反射を再現する方法を、実際のコードとともに分かりやすく紹介します。
Three.jsでWater2.jsを使うと静止した水を表現でき、Water.jsを使うと流れる水を表現することができます。
本ページではWater.jsを使って流れる水を表現します。
Water.jsを使用するには、
<script src="./js/Water.js"></script>
として使用可能にする必要があります。
マウス左ドラッグで回転、右ドラッグでカメラの移動、ホイールで拡大縮小できます。
スワイプで回転、画面に2本指を触れてなぞるとカメラの移動、ピンチイン/アウトで拡大縮小できます。
ダブルクリック/タップによるフォーカス機能もあります。
ソースコード
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0,user-scalable=yes"> <script src="./js/three.min.js"></script> <script src="./js/ArcballControls.js"></script> <script src="./js/Sky.js"></script> <script src="./js/Water.js"></script> <script> var scene,camera,controls,water; var main = function () { //描画先canvasを取得して幅と高さ取得 let can=document.getElementById('can'); let w = parseInt(can.style.width);//幅取得 let h = parseInt(can.style.height);//高さ取得 //■シーン scene = new THREE.Scene(); //■カメラ //THREE.PerspectiveCamera( 画角(度), アスペクト比, カメラに写る最短距離, カメラに写る最長距離 ); camera = new THREE.PerspectiveCamera(20, w/h, 0.1, 10000); camera.position.set(-30, 80, 200);//カメラの位置を設定 //camera.rotation.set(0,0,0);//カメラの角度を(0度,0度,0度)にする camera.lookAt(new THREE.Vector3(0, 0, 0));//カメラの向きを(0,0,0)座標にする scene.add(camera);//カメラをシーンに追加 //■レンダラー renderer = new THREE.WebGLRenderer({canvas:can, antialias: true});//アンチエイリアス有効 renderer.setSize(w, h); renderer.setClearColor(0x000000, 1);//背景色を設定 //■光源------------------------------------------------ //環境光(すべての物体にすべての方向から与える光)光の当たらない部分でも真っ黒にならない var AmbientLight=new THREE.AmbientLight(0xffffff,0.4); scene.add( AmbientLight );//環境光をシーンに追加 //スポットライト(色,強さ,距離,角度(angle),半影[0-1],減衰[1,1]) const spotLight=new THREE.SpotLight(0xffffff, 2,1000,Math.PI/8, 0.4, 1); spotLight.position.set(100,400,300); spotLight.target.position.set(0,0,0); scene.add(spotLight); scene.add(spotLight.target); //■ランバートシェーディング材質(光源の影響を受ける光沢の無い材質)の作成 let material=new THREE.MeshLambertMaterial({color:0x6699FF}); //■直方体ジオメトリの作成(幅、高さ、奥行き) let boxGeometry=new THREE.BoxGeometry(40,30,20); //■ジオメトリとランバートシェーディング材質からメッシュを作成する let mesh=new THREE.Mesh(boxGeometry,material); scene.add(mesh);//メッシュをシーンに追加 //■空 let sky=new THREE.Sky(); sky.scale.setScalar(50000); sky.material.uniforms.turbidity.value=0.8;// 大気の透明度 sky.material.uniforms.rayleigh.value=0.4;// 入射する光子の数 sky.material.uniforms.mieCoefficient.value=0.005;// 太陽光の散乱度 三重係数 sky.material.uniforms.mieDirectionalG.value=0.8; // 太陽光の散乱度 三重指向性G sky.material.uniforms.sunPosition.value.x= 10000;//太陽の位置 sky.material.uniforms.sunPosition.value.y= 30000;//太陽の位置 sky.material.uniforms.sunPosition.value.z=-40000;//太陽の位置 scene.add(sky); //■水 const waterGeometry = new THREE.PlaneGeometry(1000,1000,1,1); water=new THREE.Water( waterGeometry, { textureWidth: 512, textureHeight:512, // three.js.zipを解凍した「examples\textures\water」にある画像ファイルを使用する waterNormals: new THREE.TextureLoader().load( './three_r145/img/Water_2_M_Normal.jpg', function (texture) { texture.wrapS=THREE.RepeatWrapping; texture.wrapT=THREE.RepeatWrapping; } ), alpha: 0.90, //不透明度 waterColor: 0x3344CC, sunColor: 0xFFFFFF, distortionScale: 3.0, //歪みスケール side:THREE.FrontSide, } ); water.rotation.x=-Math.PI/2; water.position.set(0,-20,0); water.material.uniforms.sunDirection.value.copy( sky.material.uniforms.sunPosition.value ).normalize(); scene.add(water); //■アークボールコントロールの作成(マウスの左右ボタンドラッグ、ホイール等でカメラが動くようになる) controls = new THREE.ArcballControls(camera, renderer.domElement, scene); //adjustNearFarをtrueに設定するとズームされてもカメラの近距離値と遠距離値が調整され可視部分を維持しようとする controls.adjustNearFar=true; controls.enableAnimations=true;//回転やフォーカス操作のアニメーション有効 controls.enableGrid=true;//パン操作の実行中にグリッドが表示 controls.setGizmosVisible(true);//ギズモを表示(球体の回転中心がわかるワイヤーフレーム表示) renderLoop(); } function renderLoop () { requestAnimationFrame( renderLoop ); water.material.uniforms.time.value += 1.0 / 60.0; renderer.render( scene, camera ); } window.addEventListener( 'DOMContentLoaded', main, false ); </script> </head> <body> <canvas id="can" style="width:500px; height:300px;-ms-touch-action:none;touch-action:none;"> </canvas> </body> </html>