
ボーンの作成
ボーンに沿って曲がるようなチューブ状のメッシュを作成する。
ボーンとなるベジエ曲線を作成し、セクション数ごとに分割した地点の座標を取得する。
//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件のフィードバック
コメントは停止中です。