プログラミング/JavaScript/three.js/再入門 のバックアップ差分(No.2)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

#contents

* 準備 [#gf36364d]

https://cdnjs.com/libraries/three.js

へ行き、Copy Script Tag ボタン </> を押すと

 LANG:html
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js" 
  integrity="sha512-dLxUelApnYxpLt6K2iomGngnHO83iUvZytA3YjDUCjT0HDOHKXnVYdf3hU4JjM8uEhxf9nD1/ey98U3t2vZ0qQ==" 
  crossorigin="anonymous" referrerpolicy="no-referrer"></script>

が手に入る。

そこでテスト用には、

 LANG:html
 <!DOCTYPE html>
 <html lang="ja">
 <head>
 <meta charset="utf-8">
 <style>
   body { margin: 0; }
 </style>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js" 
     integrity="sha512-dLxUelApnYxpLt6K2iomGngnHO83iUvZytA3YjDUCjT0HDOHKXnVYdf3hU4JjM8uEhxf9nD1/ey98U3t2vZ0qQ==" 
     crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 </head>
 <body>
 
 <!-- ここに html を書く -->
 <canvas id="canvas1" width="800", height="600">
 
 <script>
 window.addEventListener("DOMContentLoaded", setup);
 function setup() {
 
 // ここにコードを書く
 }
 </script>
 </body>
 </html>

のようなひな形を使えば良さそう。

* 立方体のチュートリアル [#c97f1541]

** レンダリングの基本 [#u21e2247]

公式チュートリアル:~
https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene

一部こちらも参考にさせていただいて:~
https://ics.media/entry/14771/

three.js で描画するには以下の手順を踏むことになる

+ 描画先を指定してレンダラーを作る
+ シーンを作る
-- シーンにオブジェクトや光源を追加する
+ カメラを作る
+ シーンとカメラを指定してレンダリングする

ここでは、

 LANG:html
 <canvas id="canvas1" width="800", height="600">

に書き込むことにする。

 LANG:js
 // ここにコードを書く
 
 // 描画先の canvas エレメント
 const canvas = document.querySelector("#canvas1");
 
 // レンダラーを作成 (描画先を指定した)
 const renderer = new THREE.WebGLRenderer({canvas: canvas});
 renderer.setSize( canvas.width, canvas.height );
 renderer.setPixelRatio(window.devicePixelRatio);
 
 // カメラを作成 (画角、アスペクト比、描画開始距離、描画終了距離)
 const camera = new THREE.PerspectiveCamera( 
    45, canvas.width / canvas.height, 0.1, 10000 );
 camera.position.set(0, 0, +1000); // x, y, z
 
 // シーンを作成
 const scene = new THREE.Scene();
 
 // ここでシーンにオブジェクトや光源を追加する
 // setup_scene(scene);
 
 // レンダリング
 renderer.render(scene, camera);

これで正しくレンダリングされる。~
ただし、オブジェクトも光源もないシーンなので真っ暗なまま。

** オブジェクトと光源を追加してみる [#z005ed48]

 LANG:js
 // ここでシーンにオブジェクトや光源を追加する
 setup_objects(scene);
 setup_lights(scene);
 
 function setup_lights(scene) {
   // 平行光源
   const light = new THREE.DirectionalLight(0xff80ff);
   light.intensity = 1;
   light.position.set(1, 1, 1);
   scene.add(light); // シーンに追加
 
   // 環境光
   const ambient = new THREE.AmbientLight( 0x80ffff );
   ambient.intensity = 0.2;
   scene.add(ambient); // シーンに追加
 }
 
 function setup_objects(scene) {
    // 箱を作成
   const geometry = new THREE.BoxGeometry(300, 300, 300);              // 形状
   const material = new THREE.MeshStandardMaterial({color: 0x8080ff}); // 単色の材質
   const box = new THREE.Mesh(geometry, material);  // 形状と材質を指定してメッシュを作成
   box.rotation.x = 3.14/4;
   box.rotation.y = 3.14/4;
   scene.add(box); // シーンに追加
 }

これで立方体が表示された。
 
&ref(box1.png);

** アニメーションさせる [#s11c3846]

一定時間間隔でシーンを変更しつつ renderer.render を呼ぶための機構が備わっている。

 LANG:js
 // レンダリング
 renderer.render(scene, camera);

としていた部分を、

 LANG:js
  function renderFrame() {
    renderer.render( scene, camera );
 
    scene.update(); // シーンを更新する
 
    // 次フレームの描画を予約
    requestAnimationFrame( renderFrame );
  }
  
  // 次フレームの描画を予約
  requestAnimationFrame( renderFrame );

とするとともに、オブジェクトの追加時に

 LANG:js
  function setup_objects(scene) {
    // 箱を作成
    const geometry = new THREE.BoxGeometry(300, 300, 300);              // 形状
    const material = new THREE.MeshStandardMaterial({color: 0x8080ff}); // 単色の材質
    const box = new THREE.Mesh(geometry, material);  // 形状と材質を指定してメッシュを作成
    box.rotation.x = 3.14/4;
    box.rotation.y = 3.14/4;
    scene.add(box); // シーンに追加
  
    // シーンの更新方法を指定(箱を回転させる)
    scene.update = function() {
     box.rotation.x += 0.01;
     box.rotation.y += 0.01;
    }
  }

のようにシーンの更新方法を登録しておく。

これでアニメーションが行われる。

&attachref(box1.gif);

** ここまでのコード [#bea92dc5]

 LANG:html
 <!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8">
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js" 
     integrity="sha512-dLxUelApnYxpLt6K2iomGngnHO83iUvZytA3YjDUCjT0HDOHKXnVYdf3hU4JjM8uEhxf9nD1/ey98U3t2vZ0qQ==" 
     crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 </head>
 <body>
 
 <canvas id="canvas1" width="800", height="600"></canvas>
 
 <script>
 window.addEventListener("DOMContentLoaded", init);
 
 function init() {
   
    // 描画先の canvas エレメント
    const canvas = document.querySelector("#canvas1");
    
    // レンダラーを作成 (描画先を指定した)
    const renderer = new THREE.WebGLRenderer({canvas: canvas});
    renderer.setSize( canvas.width, canvas.height );
    renderer.setPixelRatio(window.devicePixelRatio);
    
    // カメラを作成 (画角、アスペクト比、描画開始距離、描画終了距離)
    const camera = new THREE.PerspectiveCamera( 
       45, canvas.width / canvas.height, 0.1, 10000 );
    camera.position.set(0, 0, +1000); // x, y, z
    
    // シーンを作成
    const scene = new THREE.Scene();
    
    // ここでシーンにオブジェクトや光源を追加する
    setup_objects(scene);
    setup_lights(scene);
    
    // レンダリング
    renderer.render(scene, camera);
   
   function renderFrame() {
     renderer.render( scene, camera );
  
     scene.update(); // シーンを更新する
  
     // 次フレームの描画を予約
     requestAnimationFrame( renderFrame );
   }
   
   // 次フレームの描画を予約
   requestAnimationFrame( renderFrame );
 }
   
 function setup_lights(scene) {
   // 平行光源
   const light = new THREE.DirectionalLight(0xff80ff);
   light.intensity = 1;
   light.position.set(1, 1, 1);
   scene.add(light); // シーンに追加
    
   // 環境光
   const ambientLight = new THREE.AmbientLight( 0x80ffff );
   ambientLight.intensity = 0.2;
   scene.add( ambientLight );
 }
 
 function setup_objects(scene) {
   // 箱を作成
   const geometry = new THREE.BoxGeometry(300, 300, 300);              // 形状
   const material = new THREE.MeshStandardMaterial({color: 0x8080ff}); // 単色の材質
   const box = new THREE.Mesh(geometry, material);  // 形状と材質を指定してメッシュを作成
   box.rotation.x = 3.14/4;
   box.rotation.y = 3.14/4;
   scene.add(box); // シーンに追加
 
   // シーンを更新する(箱を回転させる)
   scene.update = function() {
    box.rotation.x += 0.01;
    box.rotation.y += 0.01;
   }
 }
 
 </script>
 
 </body>
 </html>

のようなひな形を使えば良さそう。
* 任意形状のメッシュを生成 [#k98c0e43]

 LANG:js
 function setup_objects(scene) {
 
   // 正方形の頂点セット
   // 実際には2つの三角形を組み合わせて正方形にしているため
   // (0,0,0) と (100,100,0) が2回表れる
   const vertices = new Float32Array( [
           0,   0,   0,
         100,   0,   0,
         100, 100,   0,
 
         100, 100,   0,
           0, 100,   0,
           0,   0,   0,
   ] );
 
   const geometry = new THREE.BufferGeometry();
   // 頂点あたりの引数の数を itemSize = 3 として指定
   geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
   geometry.computeVertexNormals();  // これを忘れると表示されない
   const material = new THREE.MeshStandardMaterial( { color: 0xff0000 } );
   material.side = THREE.DoubleSide; // 裏側も描画
   const mesh = new THREE.Mesh( geometry, material );
   scene.add(mesh);
 
   // シーンを更新する(箱を回転させる)
   scene.update = function() {
    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.02;
    mesh.rotation.z += 0.005;
   }
 }

&attachref(square1.gif);

* ExtrudeGeometry で厚みのある形状 [#u23e7cb1]

https://threejs.org/docs/#api/en/geometries/ExtrudeGeometry

 LANG:js
 function setup_objects(scene) {
  
   const h = 120, w = 80;
   
   const shape = new THREE.Shape();
   shape.moveTo( 0,0 );
   shape.lineTo( 0, w );
   shape.lineTo( h, w );
   shape.lineTo( h, 0 );
   shape.lineTo( 0, 0 );
   
   const extrudeSettings = {
   	steps:           2, // 押し出し方向の分割数
   	depth:         160, // 押し出し長さ
   	bevelEnabled: true,
   	bevelThickness: 30, // 押し出し方向
   	bevelSize:      30, // 面内方向
   	bevelOffset:    20, // 外形からの距離(って何だ?)
   	bevelSegments:   1  // 大きくすると丸くなる
   };
   
   const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
  
   geometry.computeVertexNormals();  // これを忘れると表示されない
   const material = new THREE.MeshStandardMaterial( { color: 0xffffff } );
   material.side = THREE.DoubleSide; // 裏側も描画
   const mesh = new THREE.Mesh( geometry, material );
   scene.add(mesh);
 
   // シーンを更新する(箱を回転させる)
   scene.update = function() {
    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.02;
    mesh.rotation.z += 0.005;
   }
 }

右は bevelSegments = 10 としたもの。

&attachref(extruded1.gif,,66%);
&attachref(extruded2.gif,,66%);


Counter: 4949 (from 2010/06/03), today: 5, yesterday: 0