HTML5テクニカルノート
three.js入門 02: フォンマテリアルとライトを使う
- ID: FN1704011
- Technique: HTML5 / JavaScript
- Library: three.js r84
「three.js入門 01: 3次元空間で立方体を回す」は、できるだけ少ないコードで3次元空間に立方体をつくって、アニメーションで回しました。本稿はこのコード002「3次元空間につくった立方体をアニメーションで回す」に手を加えます。立方体のマテリアルを差し替え、シーンにライトを置きましょう。
01 立方体の素材をフォンマテリアルに差し替える
「three.js入門 01」のコード002では、立方体のマテリアルとしてMeshNormalMaterial
のオブジェクトを与えていました。これをフォンマテリアルのMeshPhongMaterial()
コンストラクタで差し替えます。引数は、プロパティとその値を納めたオブジェクトです。ここでは、color
プロパティで色を定めることにしましょう。この値は関数(createCube())に引数(color)として加えました。このマテリアルは、正確にはブリンフォン(Blinn-Phong)鏡面反射モデルを用いているとのことです(Wikipedia「Blinn–Phong shading model」参照)。
// var cube = createCube(side, side, side); var cube = createCube(side, side, side, 0x0000FF); // function createCube(width, height, depth) { function createCube(width, height, depth, color) { var geometry = new THREE.BoxGeometry(width, height, depth); // var material = new THREE.MeshNormalMaterial(); var material = new THREE.MeshPhongMaterial({color: color}); var cube = new THREE.Mesh(geometry, material); return cube; }
ここでコードを実行すると、立方体が見えません。MeshNormalMaterial
のオブジェクトは少し変わっていて、カラーを発色しました。けれども、普通のマテリアルは光を当てなければ、暗闇に紛れてしまうのです。
02 シーンにライトを加える
シーンにライトを加えましょう。光を放つ光源にはいくつかの種類があります(Wikipedia「3次元コンピュータグラフィックス」の「ライティング(照光、Lighting)」参照)。基本的なのは、太陽光と同じ平行光源(directional light)です(図001)。拡散することなく平行に進み、距離によって弱まることがありません。
図001■3次元表現で使われる光源の種類
*Tcpp's fileより引用
平行光源のコンストラクタDirectionalLight()
には、第1引数に色が渡せます(デフォルト値0xFFFFFF)。ライトのオブジェクトのObject3D.position
プロパティを参照して、Vector3.set()
メソッドで3次元空間の位置が決められます。関数から返されたオブジェクトは、変数(light)に納めたうえで、シーン(scene)に加えました。これで、青い立方体がライトに照らされて回ります(図002)。
var light = createLight(0xFFFFFF, 10, 0, 25); scene.add(light); function createLight(color, x, y, z) { var light = new THREE.DirectionalLight(color); light.position.set(x, y, z); return light; }
図002■青い立方体がライトに照らされて回る
03 JavaScriptコードを<head>要素に移す
「three.js入門 01」のコード002は、<script>
要素を<body>
要素の中に置きました。コードから<body>
要素を参照したためです。けれど、<head>
要素に含めたほうが管理はしやすいでしょう。イベントリスナーを使えば、DOMが参照できるまで待てます。HTMLドキュメントの読み込みと解析を終えたとき起こるイベントがDOMContentLoaded
です(「DOMContentLoaded周りの処理を詳しく調べてみました」参照)。つぎのように初期化の関数(init())を定めて、イベントリスナーに加えます。これで、JavaScriptコードは<head>
要素に移せます。
var scene; // = new THREE.Scene(); var camera; // = new THREE.PerspectiveCamera(30, width / height, 1, 1000); var renderer; // = createRenderer(width, height); var cube; // = createCube(side, side, side, 0x0000FF); function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(30, width / height, 1, 1000); renderer = createRenderer(width, height); cube = createCube(side, side, side, 0x0000FF); var light = createLight(0xFFFFFF, 10, 0, 25); camera.position.z = 100; scene.add(cube); scene.add(light); update(); } // update(); window.addEventListener('DOMContentLoaded', init);
書き改めたスクリプトは、つぎのコード001にまとめました。合わせて、サンプル001をjsdo.itに掲げておきます。
コード001■フォンマテリアルの立方体にライトを当てて回す
var width = window.innerWidth;
var height = window.innerHeight;
var side = Math.min(width, height) / 50;
var scene;
var camera;
var renderer;
var cube;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(30, width / height, 1, 1000);
renderer = createRenderer(width, height);
cube = createCube(side, side, side, 0x0000FF);
var light = createLight(0xFFFFFF, 10, 0, 25);
camera.position.z = 100;
scene.add(cube);
scene.add(light);
update();
}
function createRenderer(width, height) {
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
return renderer;
}
function createCube(width, height, depth, color) {
var geometry = new THREE.BoxGeometry(width, height, depth);
var material = new THREE.MeshPhongMaterial({color: color});
var cube = new THREE.Mesh(geometry, material);
return cube;
}
function createLight(color, x, y, z) {
var light = new THREE.DirectionalLight(color);
light.position.set(x, y, z);
return light;
}
function update() {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
requestAnimationFrame(update);
renderer.render(scene, camera);
}
window.addEventListener('DOMContentLoaded', init);
サンプル001■three.js r84: Rotating a cube with light
作成者: 野中文雄
作成日: 2017年4月20日
Copyright © 2001-2016 Fumio Nonaka. All rights reserved.