Javascript
Three.jsはじめました!
edy
更新日:2021/08/12
Three.js を研究してみました。
この記事では、次の事を記載しています。
作ったもの
1.WebGL、Three.jsとは
WebGLとは、ブラウザで3Dグラフィックを表示させるための標準仕様(API)で、非営利団体Khronos Groupで管理されています。
Three.jsは、WebGLを簡単に扱えるようしたJavaScriptライブラリです。Mr.doob氏が開発しオープンソースとしてGitHubに公開されています。
Three.jsは、3Dグラフィックで必要なカメラやライトを備えており、初心者でもJavaScriptが使える人であれば比較的容易にコンテンツが作成可能です。
では早速、Three.jsの基本的な使い方、構成要素を記述します。
以降ではコード例を記載していますが、必要部分のみの抜粋です。コピーしてそのまま動かせるわけでは無いですのでご注意ください。
2.Three.jsの基本構成
2.1. HMTLの雛形
Three.jsのJavaScriptライブラリを読み込みます。
次に続くscriptタグの中に、コンテンツを記述していきます。2.2以降の処理をコーディングします。
またThree.jsは(WebGLも)HTMLのcanvas要素にコンテンツを表示する仕様となっています。
divなどの他のHTML要素には表示されないため注意が必要です。
1 2 3 4 5 6 7 8 9 |
<html> <head> <script src="js/three.js"></script> <script> 3Dコンテンツのコーディング </script> </head> <body> <canvas id="myCanvas"></canvas> </body> </html> |
2.2. Three.jsライブラリ
前述の作ったもののページを作成するにあたって使用した、Three.jsのAPIを記載します。
Three.jsの全てのライブラリを網羅しているわけではありませんが、基本的な部分は記載しました。
2.2.a. Scene
名前の通りThree.jsのオブジェクトの、親となるオブジェクトです。
壁や床、カメラやライト全てのオブジェクトを、シーンに配置します。
1 2 3 4 |
// シーンを生成 scene = new THREE.Scene(); // シーンにカメラを追加 scene.add( new THREE.AmbientLight( 0x404040 ) ); |
2.2.b. Geometory
形、多角形や球体などの事です。Three.jsでは予め、複数のジオメトリが用意されています。
後述しますが、ジオメトリ単体では画面に何も表示されません。後述のメッシュオブジェクト生成時に、ジオメトリを指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// テクスチャ texture = textureLoader.load('../otherresources/plywood_1k_png/plywood_diff_1k.png'); // ジオメトリを生成 geometry = new THREE.BoxBufferGeometry( 30, 0.1, 30 ); // マテリアルを生成 material = new THREE.MeshLambertMaterial( { color: 0xa0adaf } ); // メッシュを生成 const ground = new THREE.Mesh( geometry, material ); material.map = texture; ground.castShadow = false; ground.receiveShadow = true; ground.position.y = -2.5; // シーンにメッシュを追加 scene.add( ground ); |
2.2.c. Material
色や質感、写真などのテクスチャなどの事です。Three.jsでは予め、複数のマテリアルが用意されています。
後述しますが、マテリアル単体では画面に何も表示されません。後述のメッシュオブジェクト生成時に、マテリアルを指定します。
2.2.d. Mesh
形を色を具体的な物体としてまとめる、親となるオブジェクトです。
前述のジオメトリ、マテリアルを指定して、メッシュを生成し、シーンに追加することで、物体がシーンに表示されます。
2.2.e. Camera
名前の通りカメラです。シーン及びシーンに配置された物体は、このカメラを通して表示されます。
Three.jsには大きく分けて2種類のカメラがあります。
画面の手前でも奥でもシーンの中の物体が全て同じ大きさで表示する 平行投影カメラと、奥行きを再現するカメラの透視投影カメラです。
今回は透視投影カメラを使いました。手前の物体は大きく、奥の物体は見えます。
1 2 3 4 |
// 透視投影カメラを生成 camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 ); // 透視投影カメラの位置を設定 camera.position.set( 0, 15, 35 );; |
2.2.f. Light
Three.jsには複数のライトがあります。今回は次のライトを使いました。
全体にまんべんなく光を当てる環境光源、特定の方向から平行にあたる並行光源、
特定の一点に光を当てるスポットライト光源です。
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 |
// 環境光源 // シーンに追加 scene.add( new THREE.AmbientLight( 0x404040 ) ); // スポットライト光源 spotLight = new THREE.SpotLight( 0xffffff ); spotLight.name = 'Spot Light'; spotLight.angle = Math.PI / 5; spotLight.penumbra = 0.3; spotLight.position.set( 10, 10, 5 ); spotLight.castShadow = true; spotLight.shadow.camera.near = 8; spotLight.shadow.camera.far = 30; spotLight.shadow.mapSize.width = 1024; spotLight.shadow.mapSize.height = 1024; // シーンに追加 scene.add( spotLight ); // 並行光源 dirLight = new THREE.DirectionalLight( 0xffffff, 1 ); dirLight.name = 'Dir. Light'; dirLight.position.set( 0, 10, 0 ); dirLight.castShadow = true; dirLight.shadow.camera.near = 1; dirLight.shadow.camera.far = 10; dirLight.shadow.camera.right = 15; dirLight.shadow.camera.left = -15; dirLight.shadow.camera.top = 15; dirLight.shadow.camera.bottom = - 15; dirLight.shadow.mapSize.width = 1024; dirLight.shadow.mapSize.height = 1024; // シーンに追加 scene.add( dirLight ); |
2.2.g. 3D model
Three.jsは外部のモデリングソフトで作成したモデルを読み込み、シーンに配置できます。
今回はBlenderで作成したモデルをシーンの中央に配置しました。
画面中央の椅子やディスプレイは、当社製品をモデリングしたものです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 3Dモデルローダー GLTFLoader の生成 const loader_table = new GLTFLoader().setPath( '../otherresources/' ); // 3D モデルをロード loader_table.load( 'table.glb', function ( gltf ) { const obj = gltf.scene; // シーンに追加 scene.add( obj ); obj.position.set(0.2, -2.5 ,0); render(); } ); |
2.2.h. Shader
個人的に最もエキサイティングなものがこれです。
シェーダとは、3Dグラフィックスで、画面上の頂点色やピクセル色などを操作するプログラムのことです。
シェーダはGLSLという言語で記載するのが一般的です。今回勉強してGLSLで記述しました。
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 |
// シェーダのプログラム(頂点シェーダとフラグメントシェーダ)を作成 // 頂点シェーダ const vertexShader =` //精度の指定 precision mediump float; //modelViewMatrixの宣言 uniform mat4 modelViewMatrix; //projectionMatrixの宣言 uniform mat4 projectionMatrix; //positionの宣言 attribute vec3 position; //uvの宣言 attribute vec2 uv; varying vec2 vUv; void main(){ gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); //フラグメントシェーダにuvを転送 vUv = uv; } `; //フラグメントシェーダ const fragmentShader =` //精度の指定 precision mediump float; //timeを取得 uniform float time; //vUvを取得 varying vec2 vUv; void main(){ //uv座標系で、オブジェクトの中心に原点を設定 vec2 fuv = -1.0 + 2.0 * vUv; //uv座標系を使用して描画色を設定 float r = abs(sin(fuv.s * fuv.t + time / 5.0)); float g = abs(sin(fuv.s * fuv.t + time / 4.0)); float b = abs(sin(fuv.s * fuv.t + time / 3.0)); gl_FragColor = vec4(r,g,b,1.0); } `; //timeを設定 const uniforms = { time:{type:'f',value:1.0} }; // シェーダー用のマテリアルを生成 const shaderMaterial = new THREE.RawShaderMaterial({ uniforms:uniforms, vertexShader:vertexShader, fragmentShader:fragmentShader, }); const geometry3 = new THREE.BoxGeometry( -1, 15, 30 ); wall2 = new THREE.Mesh( geometry3, shaderMaterial ); wall2.position.x = -15; wall2.position.y = 5; scene.add( wall2 ); |
3.まとめ
Three.jsを使った3DのWebページの基本的な作り方は理解できました。
一言でいうと、楽しい!につきます。
ただ、表示するコンテンツの質感については、別途ノウハウが必要なことがわかりました。
コンテンツに応じたカメラの位置や影の落とし方、インタラクティブ性など、業務システム開発とは異なる別次元の知識が必要です。
Webページ描画のパフォーマンスについても同様ですが、今回作成したWebページでは考慮できていません。
今後は自社のWebページに活かせるよう、より深く学ぼうと思います。