0

More than 5 years have passed since last update.

# 初めてのThree.js 1章　マテリアル　ライト　影の追加

Last updated at Posted at 2017-11-27

## はじめに

three.jsを学ぶため、
オライリー本「初めてのThree.js」をまとめることで内容を咀嚼していこう思う。

――WebGLのためのJavaScript 3Dライブラリ

## はじめのまとめ

• code sample
• マテリアル　ライト　影の追加
• code sample
• アニメーションの追加
• 統計情報の追加

`code sample`

script.js
``````
// once everything is loaded, we run our Three.js stuff.
function init() {
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0xEEEEEE));
renderer.setSize(window.innerWidth, window.innerHeight);
// create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 20);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
// rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
// add the plane to the scene
// create a cube
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
// position the cube
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
// add the cube to the scene
var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
// position the sphere
sphere.position.x = 20;
sphere.position.y = 4;
sphere.position.z = 2;
// add the sphere to the scene
// position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-20, 30, -5);
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement);
// call the render function
renderer.render(scene, camera);
}
``````

### マテリアル　ライト　影の追加

script.js
``````        // add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-20, 30, -5);
``````

`THREE.SpotLight`は自分の位置(`spotLight.position.set(-20, 30, -5);`)から光を照らします。

script.js
``````        // create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 20);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);

// create a cube
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

// position the sphere
sphere.position.x = 20;
sphere.position.y = 4;
sphere.position.z = 2;

``````

マテリアルを前回の`MeshBasicMaterial`から`MeshLambertMaterial`に変更しています。
このマテリアルと`MeshPhongMaterial` `MeshStandardMaterial`が光源を計算に含めるものです。

Three.jsでは影の描写はデフォルトでは無効化されています。

script.js
``````        renderer.setClearColor(new THREE.Color(0xEEEEEE));
renderer.setSize(window.innerWidth, window.innerHeight);
``````

script.js
``````       plane.receiveShadow = true;
...
...
``````

script.js
``````        // add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-20, 30, -5);
``````

## 統計情報・アニメーションの追加

`code sample`

script.js
``````    // once everything is loaded, we run our Three.js stuff.
function init() {
var stats = initStats();
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0xEEEEEE));
renderer.setSize(window.innerWidth, window.innerHeight);
// create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
// rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
// add the plane to the scene
// create a cube
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
// position the cube
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
// add the cube to the scene
var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
// position the sphere
sphere.position.x = 20;
sphere.position.y = 0;
sphere.position.z = 2;
// add the sphere to the scene
// position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-20, 30, -5);
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement);
// call the render function
var step = 0;
renderScene();
function renderScene() {
stats.update();
// rotate the cube around its axes
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
cube.rotation.z += 0.02;
// bounce the sphere up and down
step += 0.04;
sphere.position.x = 20 + ( 10 * (Math.cos(step)));
sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
// render using requestAnimationFrame
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
}
``````

• `requestAnimationFrame`関数
ブラウザによって定義された感覚で呼び出される関数が設定でき、必要なものをその関数内で自由に描画できる。利用するにはレンダリングを処理する関数を作成して、引数として渡すだけ。
``````        function renderScene() {
// render using requestAnimationFrame
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
``````

renderScene関数内で を再び呼び出してアニメーションが実行され続けるようにしています。
シーンを完全に作成し終わったあとで、renderer.renderを呼び出す代わりに一度renderScene関数を呼び出してアニメーションを開始します。

``````        // add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement);

// render the scene ←こっちではなくて
renderer.render(scene, camera);

// call the render function　←こっち
var step = 0;
renderScene();
``````

### 統計情報の追加

アニメーションが実行されるフレームフレートに関する情報を表示してくれるヘルパーライブラリーを追加します。

``````   <script type="text/javascript" src="../libs/stats.js"></script>

<div id="Stats-output"></div>
``````

``````        function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
``````

``````var stats = initStats();
``````

``````      function renderScene() {
stats.update();
...
// render using requestAnimationFrame
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
``````

これによって左上に統計情報が表示されるようになる。

### アニメーションの追加

• 立方体を回転させる
``````function renderScene(){
...
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
cube.rotation.z += 0.02;
...

requestAnimationFrame(renderScene);
renderer.render(scene, camera);
``````

`renderScene関数`が呼ばれるたびにrotationプロパティのそれぞれの軸の値を0.02ずつ増やすと、立方体がすべての軸に対してなめらかに回転します。

• ボールを移動する
``````        function renderScene() {
stats.update();
...
// bounce the sphere up and down
step += 0.04;
sphere.position.x = 20 + ( 10 * (Math.cos(step)));
sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
// render using requestAnimationFrame
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
``````

`Math.cos関数``Math.sin関数`を使用すればstep変数を元に軌跡を作成できる。
`step　+=　0.04` によって弾む球の速さを定義できる。

• dat.GUIを導入する
index.html
``````　　　　　　<!-- head　内で読み込む -->
<script type="text/javascript" src="../libs/dat.gui.js"></script>
``````
``````        //プロパティとデフォルト値を設定
var controls = new function () {
this.rotationSpeed = 0.02;
this.bouncingSpeed = 0.03;
};
//オブジェクトを作成したdat.GUIに渡して2つのプロパティの範囲を設定する
var gui = new dat.GUI();

//renderSceneループの中で2つのプロパティを直接参照して、datGUIのUIで値を変更したらすぐに反映される様にする
...
// 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)));
...
``````

dat.GUIというライブラリを使用するとコード内の変数の値を変更するための単純なUIコンポーネントを簡単に作成できます。

• ブラウザサイズが変更されたら出力を自動的にリサイズする
``````    function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}

// イベントリスナーの登録
``````

``````    var camera;
var scene;
var renderer;

function init(){
...
// create a scene, that will hold all our elements such as objects, cameras and lights.
scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
renderer = new THREE.WebGLRenderer();
...
}
``````

### まとめ

Three.jsでは、はじめにThree.Sceneオブジェクトを作成する必要があり、それからシーンオブジェクトにカメラ、ライト、描画したいオブジェクトを追加します。
さらに基本的なシーンを拡張して影とアニメーションを追加します。必要があれば、ヘルパーライブラリを追加します。

Register as a new user and use Qiita more conveniently

1. You get articles that match your needs
2. You can efficiently read back useful information
3. You can use dark theme
What you can do with signing up
0