Three.js にはいろいろと役に立つクラスが用意されています。今回はそのうちの一つである THREE.LensFlare クラスについて紹介したいと思います。写真や映像に太陽等を写した時に印象的な光の模様が写っていることがあります。これをレンズフレアと言いますが、これを簡単に実現するためのクラスが THREE.LensFlare クラスです。
レンズフレアの素材を準備する
レンズフレア一つ一つの素になる画像を用意します。今回は以下のような 3 種類の画像を Gimp を使って作成しました。
それっぽい素材を作るコツとしては、同一形状で統一することです。今回のように丸なら丸だけ、六角形なら六角形だけというようにします。これは元々レンズフレアがレンズの性質によって発生するもので、同じレンズなら同じ形状のレンズフレアが発生するという仕組みがあるためです。
THREE.LensFlare
さっそく実装してみたコードを見てみましょう。 67 行目からがレンズフレアを作成している部分です。
69 行目から 71 行目で先ほど作成した画像ファイルをテクスチャとしてロードしています。
次に 73 行目で THREE.LensFlare クラスを使ってレンズフレアになる大元のオブジェクトを作成しています。引数は順番に
- テクスチャ
- 描画サイズ(-1 とすることでテクスチャのサイズになる)
- 光源からの距離(0 から 1)
- ブレンディング方法(光なので加算ブレンドが有効でしょう)
- 色
となっています。
次から作成した大元のオブジェクトに子のフレアを add メソッドで追加していきます。引数の最後に透明度の指定が追加されているだけで他は先ほどと同じです。
最後に 80 行目でシーンに追加しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | <div id="div_canvas_1194" style="text-align:center;"> <script> var camera, scene, renderer; init(); initScene(); initLight(); initLensFlare(); animate(); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera( 75, 1, 1, 10000 ); camera.position.z = 1000; scene.add( camera ); div_canvas = document.getElementById( 'div_canvas_1194' ); renderer = new THREE.WebGLRenderer(); renderer.setSize( 500, 500 ); renderer.setClearColorHex( 0x000000, 1 ); div_canvas.appendChild( renderer.domElement ); trackball = new THREE.TrackballControls( camera, renderer.domElement ); } function initScene() { material_green = new THREE.MeshLambertMaterial( { color: 0x00ff00, ambient: 0x00ff00, shading: THREE.FlatShading } ); material_red = new THREE.MeshLambertMaterial( { color: 0xff0000, ambient: 0xff0000, shading: THREE.FlatShading } ); material_blue = new THREE.MeshLambertMaterial( { color: 0x0000ff, ambient: 0x0000ff, shading: THREE.FlatShading } ); material_white = new THREE.MeshLambertMaterial( { color: 0xffffff, ambient: 0xffffff, shading: THREE.FlatShading } ); cubeGeometry = new THREE.CubeGeometry( 100, 100, 100 ); cubeMesh = new THREE.Mesh( cubeGeometry, material_green ); cubeMesh.position.y = 200; scene.add( cubeMesh ); sphereGeometry = new THREE.SphereGeometry( 100, 16, 16 ); sphereMesh = new THREE.Mesh( sphereGeometry, material_red ); sphereMesh.position.x = -200; sphereMesh.position.y = 200; scene.add( sphereMesh ); octahedronGeometry = new THREE.OctahedronGeometry( 100, 2 ); octahedronMesh = new THREE.Mesh( octahedronGeometry, material_blue ); octahedronMesh.position.x = 200; octahedronMesh.position.y = 200; scene.add( octahedronMesh ); planeGeometry = new THREE.PlaneGeometry( 1000, 1000, 15, 15 ); planeMesh = new THREE.Mesh( planeGeometry, material_white ); planeMesh.position.y = -100; planeMesh.rotation.x = -90 * 2 * Math.PI / 360; scene.add( planeMesh ); } function initLight() { point_light = new THREE.PointLight( 0xffffff, 1, 0 ); scene.add( point_light ); ambient_light = new THREE.AmbientLight( 0x444444 ); scene.add( ambient_light ); } function initLensFlare() { texture_00 = THREE.ImageUtils.loadTexture( "http://www.soft-syokunin.com/wp-content/uploads/lens_flare00.png" ); texture_01 = THREE.ImageUtils.loadTexture( "http://www.soft-syokunin.com/wp-content/uploads/lens_flare01.png" ); texture_02 = THREE.ImageUtils.loadTexture( "http://www.soft-syokunin.com/wp-content/uploads/lens_flare02.png" ); lens_flare = new THREE.LensFlare( texture_02, 16, 0, THREE.AdditiveBlending, new THREE.Color( 0xffffff ) ); lens_flare.add( texture_02, 32, 0.2, THREE.AdditiveBlending, new THREE.Color( 0xffffff ), 0.3 ); lens_flare.add( texture_01, 32, 0.4, THREE.AdditiveBlending, new THREE.Color( 0xffffff ), 0.3 ); lens_flare.add( texture_02, 48, 0.5, THREE.AdditiveBlending, new THREE.Color( 0xffffff ), 0.2 ); lens_flare.add( texture_00, 64, 0.7, THREE.AdditiveBlending, new THREE.Color( 0xffffff ), 0.3 ); lens_flare.add( texture_00, 96, 1, THREE.AdditiveBlending, new THREE.Color( 0xffffff ), 0.4 ); scene.add( lens_flare ); } function animate() { // note: three.js includes requestAnimationFrame shim requestAnimationFrame( animate ); render(); } function render() { trackball.update(); renderer.render( scene, camera ); } </script> </div> |
動作と実装
上記のソースコードの動作例が以下です。右ドラックでカメラを移動させたあとにカメラを動かすとそれと連動してレンズフレアが動きます。これだけ簡単に実装出来るだけでも驚きですが、けっこう動きも凝っています。例えば光源を遮るようにオブジェクトが重なるとレンズフレアも薄くなります。
この辺の実装を見る場合は
- three.js/src/extras/plugins/LensFlarePlugin.js
- three.js/src/extras/shaders/ShaderFlares.js
を参考にすると良いでしょう。シェーダを上手に使って実現しているのが分かります。