|
WebGLは、OpenGLというパソコン用の3D API(グラフィックスカードの能力を引き出し、三次元の絵を作り出すためのAPI)を、Webブラウザに移植したものでした。WebGLはこのOpenGL ESをベースに、Webブラウザ向けに微調整されて出来た規格なのです。いわば、OpenGL ES for Webとでも言えます。
Three.jsは、WebGLのためのJavaScriptライブラリなので、HTML5で3Dコンテンツを制作するためのJavaScriptライブラリになっています。Mr.doob氏が中心となって開発されており、オープンソースソフトウェアとして個人・商用でも無償で利用できます。前のページで見た通り、Three.jsのライブラリを利用すると、プログラムの記述が極端に少なくて済みます。
このページでは、JavaScript ライブラリであるThree.js を用いたWebGL の初級程度の利用法を紹介します。ここでは、OpenGLでのシェーディング言語、および、WebGL そのものの説明は行いません。WebGLについては、WebGLのページを読んでください。JavaScript の初歩的な知識があるといいかも知れません。
Last updated: 2019.3.16
Three.js ライブラリを用いた3D CG の基本 |
まず最初に作成すべきファイルは、スケルトンのhtml ページです。
Three.jsの公式ページの説明では、Three.jsを書き始める時のhtmlのスケルトン・ページは以下のようになっています。
// 例1
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>My first three.js app</title>
<style>
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
...
// Our Javascript will go here.
...
</script>
</body>
</html>
Three.js の解説書として有名な『初めてのThree.js」(Jos Dirksen著)では、スケルトン・ページの書き方は以下のように設定されています。
// 例2
<!DOCTYPE html>
<html>
<head>
<title>Basic skeleton</title>
<meta charset=utf-8>
<script type="text/javascript" src="../libs/three.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
// Div which will hold the WebGL_Output
<div id="myWebGL">
</div>
<script type="text/javascript">
// once everything is loaded, we run our Three.js stuff.
function init() {
...
// here we'll put the Three.js stuff
...
}
window.onload = init
</script>
</body>
</html>
どちらを採用すべきは各自の好みに委ねます。
<script src="js/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
// 例3
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/101/three.min.js"></script>
<script>
// ページの読み込みを待つ
window.addEventListener('load', init);
function init() {
// ここに、JavaScript の処理コードを書く
}
</script>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>
var scene = new THREE.Scene();
// add a camera // THREE.PerspectiveCamera(fov, aspect, near, far) var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); // place the camera at z of 100 camera.position.z = 100;
// add a renderer var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); // add the renderer element to the DOM so it is in our page:example1 document.body.appendChild( renderer.domElement ); // add the output of the renderer to the html element:example2 document.getElementById("myWebGL").appendChild(renderer.domElement);
/* we need to add a light so we can see our cube - its almost as if we're turning on a lightbulb within the room */ var light = new THREE.PointLight(0xFFFF00); /* position the light so it shines on the cube (x, y, z) */ light.position.set(10, 0, 25); scene.add(light);
/* we're creating a cube to put in our scene - don't worry if you don't follow this part, we'll cover geometry and materials in future posts */ var geometry = new THREE.BoxGeometry(20, 20, 20); var material = new THREE.MeshLambertMaterial({color: 0xfd59d7}); var cube = new THREE.Mesh(geometry, material); scene.add(cube);
<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
</head>
<style>
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
</style>
<body>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.BoxGeometry( 20, 20, 20);
var material = new THREE.MeshLambertMaterial( { color: 0xfd59d7 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 100;
var light = new THREE.PointLight( 0xFFFF00 );
light.position.set( 10, 0, 25 );
scene.add( light );
var render = function () {
requestAnimationFrame( render );
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
<body>
<canvas id="myCanvas"></canvas>
</body>
Three.js ライブラリGeometryの使用法 |
// 球体を作成 const geometry = new THREE.SphereGeometry(300, 30, 30); const material = new THREE.MeshStandardMaterial({color: 0xFF0000}); // メッシュを作成 const mesh = new THREE.Mesh(geometry, material); // 3D空間にメッシュを追加 scene.add(mesh);
<script>
// ページの読み込みを待つ
window.addEventListener('load', init);
// サイズを指定
const width = 960;
const height = 540;
function init() {
// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#myCanvas')
});
renderer.setSize(width, height);
// シーンを作成
const scene = new THREE.Scene();
// カメラを作成
const camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
camera.position.set(0, 0, +1000);
// 球体を作成
const geometry = new THREE.SphereGeometry(300, 30, 30);
const material = new THREE.MeshStandardMaterial({color: 0xFF0000});
// メッシュを作成
const mesh = new THREE.Mesh(geometry, material);
// 3D空間にメッシュを追加
scene.add(mesh);
// 平行光源
const directionalLight = new THREE.DirectionalLight(0xFFFFFF);
directionalLight.position.set(1, 1, 1);
// シーンに追加
scene.add(directionalLight);
tick();
// 毎フレーム時に実行されるループイベントです
function tick() {
// メッシュを回転させる
mesh.rotation.y += 0.01;
// レンダリング
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
}
</script>
var geometry = new THREE.TorusGeometry( 10, 3, 16, 100 );
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var torus = new THREE.Mesh( geometry, material );
scene.add( torus );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 30, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// add cube
var geometry = new THREE.BoxGeometry( 20, 20, 20);
var material = new THREE.MeshNormalMaterial();
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
// update cube vertices
for (var i = 0, l = geometry.vertices.length; i
Three.js ライブラリMaterialの使用法 |
描画物体のマテリアルに画像を使用する方法について説明します。マテリアルとは描画物体の質感設定のことです。見栄えを決める「マテリアル」を指定して、たとえば、着色や画像・陰影の割り当て、ライティングの反射などを適用できます。マテリアルに画像を使うには読み込み処理を作る必要があります。'THREE.TextureLoader'クラスを使って次のように指定します。地球儀のような球体が描画されます。
// 画像を読み込む var loader = new THREE.TextureLoader(); var texture = loader.load('image/earthmap.jpg'); // マテリアルにテクスチャーを設定 var material = new THREE.MeshStandardMaterial({ map: texture });
// add icosahedron var geometry = new THREE.OctahedronGeometry( 20 ); var color = new THREE.Color( "#7833aa" ); var material = new THREE.MeshPhongMaterial( {color: color.getHex()} ); var mesh = new THREE.Mesh( geometry, material ); scene.add( mesh );
Three.js でのAnimationの設定 |
以上までに、
mesh のposition & rotation// call the render function var step = 0; var scalingStep = 0; var controls = new function () { this.rotationSpeed = 0.02; this.bouncingSpeed = 0.03; this.scalingSpeed = 0.03; }; ... render(); function render() { stats.update(); // rotate the cube around its axes cube.rotation.x += controls.rotationSpeed; cube.rotation.y += controls.rotationSpeed; cube.rotation.z += controls.rotationSpeed; // bounce the sphere up and down step += controls.bouncingSpeed; sphere.position.x = 20 + (10 * (Math.cos(step))); sphere.position.y = 2 + (10 * Math.abs(Math.sin(step))); // scale the cylinder scalingStep += controls.scalingSpeed; var scaleX = Math.abs(Math.sin(scalingStep / 4)); var scaleY = Math.abs(Math.cos(scalingStep / 5)); var scaleZ = Math.abs(Math.sin(scalingStep / 7)); cylinder.scale.set(scaleX, scaleY, scaleZ); // render using requestAnimationFrame renderer.render(scene, camera); requestAnimationFrame(render); } ...
音声付き3DCGアニメーションをWebGLで再現する |
最初に。音声データを3D表現する例を取り上げてみます。Three.js公式ホームページにあるWebAudioのSound Visualizerの例を修正してみました。
webAudio_visualizerのexampleを再生青柳氏が開発して提供するMikuMikuDanceのMMDLoader sample appsはこのGitHubサイトにあります。この中のMikuMikuDanceを再生(Safariでは音声が出ません)音声を出すためには、自分のPCでAppsを展開して、再生してください。上の例では、Web Audio APIを用いて音声を処理しますので、再生してもこれらに対応していないブラウザでは音声が出ません。FireFoxやChromeでは音声が出ますが、Safariやスマホなどでは音声が出ません。
カメラの移動とコントロール |
Three.jsには多数のカメラカメラコントロールがあり、シーン内のカメラを自由に移動させることができます。これらのコントロールのうち、以下のコントロールがよく使用されます。
<script type="text/javascript" src="js/TrackBallControlls.js"></script>
...
var trackballControls = new THREE.TrackballControls(camera);
trackballControls.rotateSpeed = 1.0;
trackballControls.zoomSpeed = 1.0;
trackballControls.panSpeed = 1.0;
var clock = new THREE.Clock();
function render() {
stats.update();
var delta = clock.getDelta();
trackballControls.update(delta);
//webGLRenderer.clear();
// render using requestAnimationFrame
requestAnimationFrame(render);
webGLRenderer.render(scene, camera)
}
// <div id="WebGL-output"></div>でWebGLに描画するとき
<script type="text/javascript" src="js/FlyControls.js"></script>
...
var flyControls = new THREE.FlyControls(camera);
flyControls.movementSpeed = 25;
flyControls.domElement = document.querySelector("#WebGL-output");
flyControls.rollSpeed = Math.PI / 24;
flyControls.autoForward = true;
flyControls.dragToLook = false;
var clock = new THREE.Clock();
function render() {
stats.update();
var delta = clock.getDelta();
flyControls.update(delta);
webGLRenderer.clear();
// render using requestAnimationFrame
requestAnimationFrame(render);
webGLRenderer.render(scene, camera)
}
...
<script type="text/javascript" src="./js/controls/FirstPersonControls.js"></script>
...
var camControls = new THREE.FirstPersonControls(camera);
camControls.lookSpeed = 0.4;
camControls.movementSpeed = 20;
camControls.noFly = true;
camControls.lookVertical = true;
camControls.constrainVertical = true;
camControls.verticalMin = 1.0;
camControls.verticalMax = 2.0;
camControls.lon = -150;
camControls.lat = 120;