ボーンの作成
ボーンに沿って曲がるようなチューブ状のメッシュを作成する。
ボーンとなるベジエ曲線を作成し、セクション数ごとに分割した地点の座標を取得する。
//start、end、controlポイントの座標作成 const center2D = new THREE.Vector2(); const ep = new THREE.Vector2( 10,20 ); const cp = new THREE.Vector2( 10,0 ); //ベジエ曲線を作成 const curve = new THREE.QuadraticBezierCurve(center2D, cp, ep); //セクション数に分割した座標の配列を取得 const sect = 4; const bone = curve.getPoints(sect);
※sect数4でgetPointsするとbone配列のサイズは5になる。
分割したボーン間の角度を求める
let zpos = bone[0]; for(let i=0; i<(sect+1); i++){ //zpos(bone[n-1])とbone[n]の角度を求める const diff = new THREE.Vector2().subVectors(bone[i], zpos); const angle = Math.atan2(diff.y, diff.x); }
ボーンに沿った円の座標を取得
const edge = 12; const size = 5; const pt = []; for(let i=0; i<(sect+1); i++){ //上記angleを求める式(省略) pt[i] = []; for(let j=0; j<edge; j++){ const theta = j * 2 * Math.PI / edge; const w = size * Math.cos(theta); //奥行(z軸上の幅) const h = size * Math.sin(theta); //縦 const v = new THREE.Vector2(0, h); //回転させるためベクトルに変換 v.add(bone[i]); //boneを中心に移動 v.rotateAround(bone[i], angle); //angle分回転 pt[i][j] = [v.x, v.y, w]; } }
z-y平面上に半径=sizeの円を描き、z軸で回転させているイメージ。
この時、boneの座標を加算して、各円の回転の中心をboneに持ってきている。
メッシュの作成
前回の記事と同じく、BufferGeometryを使ってジオメトリを作成する。
以下は関数化してまとめたコードの全体。
//ページの読み込みを待つ window.addEventListener('load', init); function init() { /////////////////////////////////////////////// // 画面設定 // ////////////////////////////////////////////// //画面サイズを指定 const width = window.innerWidth; const height = window.innerHeight; //レンダラーを作成 const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector('#myCanvas') }); renderer.setClearColor(new THREE.Color('grey')); document.body.appendChild( renderer.domElement ); renderer.setSize(width, height); //シーンを作成 const scene = new THREE.Scene(); //カメラを作成 const camera = new THREE.PerspectiveCamera(45, width / height); camera.position.set(-50, 50, 100); camera.lookAt(new THREE.Vector3(0, 0, 0)); //ライトを設置 const envlight = new THREE.AmbientLight(0xffffff, 1); scene.add(envlight); /////////////////////////////////////////////// // マテリアル作成 // /////////////////////////////////////////////// //パイプの設定 const sect = 5; const edge = 12; const size = 5; const center2D = new THREE.Vector2(); const ep = new THREE.Vector2( 10, 10 ); const cp = new THREE.Vector2( 10, 0 ); //パイプを作成 const pt = makePipe(sect, edge, size, cp, ep); //メッシュの作成 const geometry = makeGeometry(sect, edge, pt); const material = new THREE.MeshNormalMaterial({ side:THREE.DoubleSide, }); const plane = new THREE.Mesh( geometry, material ); scene.add( plane ); /////////////////////////////////////////////// // 共通関数 // /////////////////////////////////////////////// //パイプ作成 function makePipe(sect, edge, size, cp, ep){ //make bone const curve = new THREE.QuadraticBezierCurve(center2D, cp, ep); const bone = curve.getPoints(sect); let zpos = bone[0]; //set points const pt = []; for(let i=0; i<(sect+1); i++){ //calc angle const diff = new THREE.Vector2().subVectors(bone[i], zpos); const angle = Math.atan2(diff.y, diff.x); //calc coords pt[i] = []; for(let j=0; j<edge; j++){ const theta = j * 2 * Math.PI / edge; const w = size * Math.cos(theta); const h = size * Math.sin(theta); const v = new THREE.Vector2(0, h); v.add(bone[i]); v.rotateAround(bone[i], angle); pt[i][j] = [v.x, v.y, w]; } zpos = bone[i]; } return pt; } //カスタムvertexの作成 function setVertices(sect, edge, pt){ const vert = []; for(let i=0; i<sect; i++){ vert[i] = []; for(let j=0; j<edge; j++){ vert[i][j] = []; vert[i][j][0] = pt[i][j]; vert[i][j][1] = pt[i][(j+1)%edge]; vert[i][j][2] = pt[i+1][(j+1)%edge]; vert[i][j][3] = pt[i+1][j]; } } return new Float32Array(vert.flat(3)); } //カスタムindexの作成 function setIndices(sect, edge){ const num_rect = sect * edge; const order = [0,3,2,2,1,0]; const index = []; for(let i=0; i<num_rect; i++){ for(let j=0; j<order.length; j++){ index.push(order[j]+(4*i)); } } return new Uint16Array(index); } //BufferGeometryの作成 function makeGeometry(sect, edge, pt){ const vertices = setVertices(sect, edge, pt); const indices = setIndices(sect, edge); const geometry = new THREE.BufferGeometry(); geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3)); geometry.setIndex(new THREE.BufferAttribute(indices, 1)); geometry.computeVertexNormals(); return geometry; } /////////////////////////////////////////////// // レンダリング開始 // ////////////////////////////////////////////// render(); function render(){ requestAnimationFrame(render); renderer.render(scene, camera); } }
「three.jsでカスタム図形を作る(3):曲がるパイプを作る」への1件のフィードバック
コメントは停止中です。