今回はいろんな方向から物体に光を当ててみる。
まずは光を当てない状態で物体Xを表示してみる。
<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <script src="three.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> <script> $(document).ready( function() { // Rendererを用意 var renderer = new THREE.WebGLRenderer( { 'canvas' : $('#canvas')[0] } ); // Cameraを用意 var camera = new THREE.PerspectiveCamera(); camera.position.z = 500; // 物体の用意 var geometry = new THREE.CubeGeometry(200, 200, 200); var material = new THREE.MeshLambertMaterial( { color: 0x00ff88 } ) var mesh = new THREE.Mesh( geometry, material ); mesh.rotation.x = 0.5; mesh.rotation.y = 0.5; // Sceneを用意 var scene = new THREE.Scene(); scene.add( mesh ); // render renderer.render( scene, camera ); } ); </script> </head> <body> <canvas id="canvas" style="width:300px; height: 300px; border:solid 1px; margin: 30px;"> CanvasはHTML5の標準機能です。しばし普及に時間がかかりましたが、今や巻き返しの時です。グラフィカルなWebサイトはお好き? 結構。ではますます好きになりますよ。さあ、どうぞ。WebGLを使った3D画像です。んあぁ、おっしゃらないで。IE8で見れない。でも、IEなんて9以前は使えたもんじゃない。どうぞChromeで見てください。余裕の3Dだ。レンダリング能力が違いますよ。 </canvas> </body> </html>
実行結果はこんな感じ。MeshLambertMaterialはnon-shiny surfacesなので、色指定しても光を当てないと黒くなる。
方向を決めて光を当てる、DirectionalLightを当ててみる。
// 光を用意 var light = new THREE.DirectionalLight(0xffffff); light.position.set(1, 1, 1).normalize(); scene.add( light );
1, 1, 1の方向から、0xffffffの光を当ててます。
1, 0, 0の方向から当てると、X軸の方向から光が当たることになるので、上と横はには光は当たらない。
// 光を用意 var light = new THREE.DirectionalLight(0xffffff); light.position.set(1, 0, 0).normalize(); scene.add( light );
逆に0, 1, 0から当てると、上だけ光が当たる。
次に光の色を変えてみる。表面が緑なので黄色(FFFF00)を当てれば黄緑になるはず。
// 光を用意 var light = new THREE.DirectionalLight(0xffff00); light.position.set(1, 1, 1).normalize(); scene.add( light );
若干、黄色が増した。もっとわかりやすいように、白い物体に黄色い光を当ててみる。
// 物体を用意 var geometry = new THREE.CubeGeometry(200, 200, 200); var material = new THREE.MeshLambertMaterial( { color: 0xffffff } ) var mesh = new THREE.Mesh( geometry, material ); mesh.rotation.x = 0.5; mesh.rotation.y = 0.5; // Sceneを用意 var scene = new THREE.Scene(); scene.add( mesh ); // 光を用意 var light = new THREE.DirectionalLight(0xffff00); light.position.set(1, 1, 1).normalize(); scene.add( light );
DirectionalLightの第2引数は光の強さを取る。デフォルトは1なので、これを0.5くらいの弱い光にしてみる。
// 光を用意 var light = new THREE.DirectionalLight(0xffff00, 0.5); light.position.set(1, 1, 1).normalize(); scene.add( light );
0.5くらいの光だとだいぶ弱いらしい。2.0の強い光を当ててみると、下図のようにだいぶ黄色くなる。
小さな球を50個ほどランダムに配置して、光を当ててみる。
// 丸をいくつか用意 for( var i = 0; i < 50; i++ ) { var geometry = new THREE.SphereGeometry(10); var material = new THREE.MeshLambertMaterial( { color: 0xffffff } ) var mesh = new THREE.Mesh( geometry, material ); mesh.position.set( Math.random()*500-250, Math.random()*500-250, Math.random()*500-250 ); scene.add( mesh ); } // 黄色い光 var light = new THREE.DirectionalLight(0xffff00); light.position.set(1, 1, 1).normalize(); scene.add( light );
どちらから光が当たっているかよく分かる。
Ambientは取り巻くとか包囲するという意味。DirectionalLightは一方向から光を当てたけど、AmbientLightは自然光のように全体的に光を当てる。
試しに白い物体(FFFFFF)に、赤いAmbientLight(FF0000)を当ててみる。
// 白いCube var geometry = new THREE.CubeGeometry(200, 200, 200); var material = new THREE.MeshLambertMaterial( { color: 0xffffff } ) var mesh = new THREE.Mesh( geometry, material ); mesh.rotation.x = 0.5; mesh.rotation.y = 0.5; // Sceneを用意 var scene = new THREE.Scene(); scene.add( mesh ); // 赤い光 var light = new THREE.AmbientLight(0xff0000); scene.add( light );
なんか面白みのない赤になった。
赤いAmbientLightに加えて、青いDirectionalLightを当ててみる。
// 赤い光 var light1 = new THREE.AmbientLight(0xff0000); scene.add( light1 ); // 青い光 var light2 = new THREE.DirectionalLight(0x0000ff); light2.position.set(1, 1, 1).normalize(); scene.add( light2 );
紫っぽくなった。
SpotLightは一部だけ光を当てたりできる。試しに白い球を100個ほど描画して、そこに黄色いSpotLightを当ててみる。
// 丸をいくつか用意 for( var i = 0; i < 100; i++ ) { var geometry = new THREE.SphereGeometry(10); var material = new THREE.MeshLambertMaterial( { color: 0xffffff } ) var mesh = new THREE.Mesh( geometry, material ); mesh.position.set( Math.random()*500-250, Math.random()*500-250, Math.random()*500-250 ); scene.add( mesh ); } // 黄色い光 var light = new THREE.SpotLight(0xffff00); light.position = camera.position; scene.add( light );
Lightの光源はカメラの場所(0, 0, 500に設定してある)に置いている。見ての通り、中央付近は明るく周囲は暗い光の当たり方をしている。
distanceを設定して、もう少し光の範囲を狭めてみる。
var light = new THREE.SpotLight(0xffff00); light.position = camera.position; light.distance = 1500; scene.add( light );
distance=1500で照射。distanceを設定すると徐々に光が減退するので、だいぶ暗くなる。
次にtargetを指定して、光の向きを変えてみる。
// 緑の光 var light = new THREE.SpotLight(0x00ff00); light.position = camera.position; light.target.position.set( 0, 250, 0 ); scene.add( light );
気分を変えて光を緑にして、cameraのある0,0,500の位置から、targetで指定した0,250,0(斜め上)に光を向けた。
SpotLightは影も落とせる。試しに影の設定をせずに、平面の上に球が浮いていて、上から青い光が当たる光景を作ってみる。
// 球を作る var sphere = new THREE.SphereGeometry(100); var material = new THREE.MeshLambertMaterial( { color: 0xffffff } ) var mesh = new THREE.Mesh( sphere, material ); mesh.position.set( 0, 100, 0 ); scene.add( mesh ); // 地面を作る var plane = new THREE.PlaneGeometry(300, 300, 10, 10); var mesh = new THREE.Mesh( plane, material ); mesh.rotation.x = -1; mesh.position.set( 0, -50, 0 ); scene.add( mesh ); // 斜め上から青い光 var light = new THREE.SpotLight(0x33ccff); light.position.set( 0, 500, 500 ); light.target.position.set( 0, 0, 0 ); scene.add( light );
影の設定をしていないので、この状態では地面にも等しく光が当たっている。
影の設定をして、球の影が地面に描画されるようにします。影を出すには、RendererのshadowMapEnabledをtrueにして、影を作る側の物体のcastShadowをtrueにして、影を受ける側の物体のreceiveShadowをtrueにして、光のcastShadowをtrueにします。
// Rendererを用意 renderer = new THREE.WebGLRenderer( { 'canvas' : $('#canvas')[0] } ); renderer.setSize(300, 300); renderer.shadowMapEnabled = true; // Cameraを用意 camera = new THREE.PerspectiveCamera(); camera.position.z = 500; // Sceneを用意 scene = new THREE.Scene(); scene.add( camera ); // 球を作る var sphere = new THREE.SphereGeometry(100); var material = new THREE.MeshLambertMaterial( { color: 0xffffff } ) var mesh = new THREE.Mesh( sphere, material ); mesh.position.set( 0, 100, 0 ); mesh.castShadow = true; scene.add( mesh ); // 地面を作る var plane = new THREE.PlaneGeometry(300, 300, 10, 10); var mesh = new THREE.Mesh( plane, material ); mesh.rotation.x = -1; mesh.position.set( 0, -50, 0 ); mesh.receiveShadow = true; scene.add( mesh ); // 青い光 var light = new THREE.SpotLight(0x33ccff); light.position.set( 0, 500, 500 ); light.target.position.set( 0, 0, 0 ); light.shadowCameraVisible = true; light.castShadow = true; scene.add( light ); renderer.render(scene, camera);
これで地面に影が差しました。
余談ですが、RendererのshadowMapEnabledをtrueにする場合、ちゃんとsetSizeをしてないと描画がされなくなるようです。ハマった。。。