本稿は「18.2: 3D Geometries – WebGL and p5.js Tutorial」YouTube動画を元にしています。
目次
WEBGLモードでの描画
2D図形の描画
p5.jsでは、Webページにキャンバスを作成するcreateCanvas()関数の第3引数に定数WEBGLを指定することで、コンピュータのGPUにアクセスして、その高速な描画機能が利用できるようになります。GPUは描画計算が得意なので、3Dのレンダリング計算に適していますが、p5.jsの2D図形の描画にも使用できます。
function setup() {
// キャンバスをWEBGLモードで作成
createCanvas(400, 300, WEBGL);
}
function draw() {
// キャンバスの背景色
background(200);
fill(255, 0, 0);
noStroke();
rect(0, 0, 50, 100);
}
ここで注目すべきは、赤い矩形の描画位置です。rect()関数では(x,y)位置に(0,0)を指定していますが、矩形はキャンバスのセンターに描画されています。正確に言うと、矩形の左上隅(0,0)がキャンバスのセンター(150,200)と重なっています。
この矩形のセンターとキャンバスのセンターを合わせたい場合には、矩形の幅の半分と高さの半分を、(x,y)から引く必要があります。
rect(0 - 25, 0 - 50, 50, 100);
この矩形は2D図形ですが、3Dの世界にいるので、WEBGLモードのrotateX()関数が使用できます。
// 座標システムの回転に使用する
let angle = 0;
function setup() {
// キャンバスをWEBGLモードで作成
createCanvas(400, 300, WEBGL);
// ラジアンでなく度単位にする
angleMode(DEGREES);
}
function draw() {
// キャンバスの背景色
background(200);
fill(255, 0, 0);
noStroke();
// X軸周りに座標システムを回転
rotateX(angle);
rect(0 - 25, 0 - 50, 50, 100);
// 角度をインクリメント
angle += 1;
}
rotateX()関数は、座標システムをX軸周りに回転させます。
X軸、Y軸、Z軸周り
p5.js(WEBGL)の軸がどの方向を指すのか思い出すときに役立つ記憶術に、”左手の”法則があります。左手の人差し指を右に向け、中指を下に向けると、親指が自動的に自分の方を指します。この3つの指の方向が3つの軸を指しています。点0,0,0 (x, y ,z)はキャンバスの真ん中に位置します。xは右に進むほど大きく、yは下に進むほど大きく、zは手前に来るほど大きくなります。
左手をこの形にして、左手の人差し指を、左手でつまんで時計回りに回します。これがX軸周り(rotateX())です。同様に右手で左手の中指をつまんで時計回りに回します。これがY軸周り(rotateY())です。Z軸周りも同様です。
3Dジオメトリ
ジオメトリ(geometry)は形状といった意味で、日本語で言うと立方体や直方体、円錐体などです。3Dの図形は2Dに比べはるかに複雑なので、その3D図形を構成する形状や頂点の座標、線や面などデータがまとめてジオメトリと呼ばれます。p5.jsの3Dジオメトリは、専用の関数を呼び出すだけで作成できます。
次のコードでは立方体を作成しています。
// 座標システムの回転に使用する
let angle = 0;
function setup() {
// キャンバスをWEBGLモードで作成
createCanvas(400, 300, WEBGL);
// ラジアンでなく度単位にする
angleMode(DEGREES);
// デバッグモード
debugMode();
}
function draw() {
// キャンバスの背景色
background(200);
// デバッグ向けのマテリアル
normalMaterial();
// 3D画面をぐりぐりできる
orbitControl();
// XYZ軸周りに座標システムを回転
rotateX(angle);
rotateY(angle * 1.3);
rotateZ(angle * 0.7);
// 立方体
box(50);
// 角度をインクリメント
angle += 1;
}
ここではまた、 debugMode()関数を使って、この3D空間のXYZ軸とXZ平面を表すグリッドを描画しています。画面に最初表示される、立方体を横切る線がXZ平面です。draw()内でorbitControl()関数を呼び出しているので、画面がマウスのドラッグでぐりぐりできます。するとXZ平面が斜め方向から見られるようになります。
リファレンスメモ
与えられた幅と高さ、奥行きを持つ直方体を描画する。
シンタックス
box([width], [Height], [depth], [detailX], [detailY])
パラメータ
width 数値: 直方体の幅(オプション)。デフォルトは50。
Height 数値: 直方体の高さ(オプション)。指定されない場合はwidth。
depth 数値: 直方体の奥行き(オプション)。指定されない場合はheight。
detailX 整数: x次元の三角形サブディビジョン数(オプション)。4以下。
detailY 整数: y次元の三角形サブディビジョン数(オプション)。4以下。
X軸周りに回転する。
シンタックス
rotateX(angle)
パラメータ
angle 数値: 回転の角度。現在のangleModeに応じて、ラジアンか度で指定する。
debugMode()は、3D空間のスケッチ内で”地面”がどこにあるかを示すグリッドと、正のX、Y、Z方向を示す軸アイコンを追加することで、3D空間を認識しやすくする。パラメータなしで呼び出すとデフォルトのグリッドとアイコンを作成するが、上記サンプルのようにグリッドや軸アイコンのサイズや位置を指定してカスタマイズすることもできる。グリッドは直近に設定されたストロークカラーと重みを使って描画される。これらのパラメータを指定するには、draw()ループの最後でstroke()とstrokeWeight()を呼び出す。
デフォルトでは、グリッドはXZ平面に沿ってスケッチの原点(0,0,0)を通り、軸アイコンは原点からオフセットされる。グリッドも軸アイコンも、現在のキャンバスサイズに応じてサイズが変わる。グリッドはデフォルトのカメラビューと平行なので(線にしか見えない)、orbitControl()を合わせて使用すると、グリッド全体を見ることができる。
「p5.jsで始めるWebGL」を参照。
平面
平面はplane()関数で作成します。
function setup() {
createCanvas(400, 300, WEBGL);
angleMode(DEGREES);
debugMode();
}
function draw() {
background(200);
// デバッグ向けのマテリアル
normalMaterial();
// 3D画面をぐりぐりできる
orbitControl()
// 3D空間のセンターに平面を作成 => 立った平面
plane(100, 80);
// 座標システムを+Z方向に100移動(原点が手前に移動)
translate(0, 0, 100);
// 座標システムをX軸周りに90度回転
rotateX(90);
// 平面を作成 => 寝た平面になる
plane(100, 80);
}
この例では、立った平面と寝た平面を作成しています。下の実行画面をマウスドラッグすると、斜め方向から見て確認できます。
平面はデフォルトで、壁のように立って作成されます。これを地面のように寝かせるには、rotateX(90)を使います。またジオメトリの移動には、draw()関数内でtranslate()関数を使用して、座標システムを毎フレーム移動させる形で行います。
球体
球体はsphere()関数で作成します。
// デフォルトの球体
sphere();
// 座標システムを左上奥に移動
translate(-60, -30, -50);
// 半径30、6の細かさの球体
sphere(30, 6, 6);
sphere()に引数を渡さないと、デフォルトの半径50、細かさ24の球体が作成されます(sphere(50,24,24))。細かさというのはジオメトリを構成するポリゴンの数です。sphere()には第2と第3引数にx方向とy方向のポリゴンの細かさが指定でき、大きいほど球体に近づき、小さいほど角ばった粗い球体になります(最大で24)。
円環体
円環体はtorus()関数で作成します。円環体といってもまったく馴染みがないので、浮き輪やドーナッツ形の立体といった方が分かりやすいでしょう。
// デフォルトの円環(浮き輪、ドーナッツ)
torus();
// 座標システムを上奥に移動
translate(0, -50, -100);
// 座標システムをXとZ軸周りに回転
rotateX(90);
// angleは1ずつ大きくなるのでアニメーションになる
rotateZ(angle);
torus(50, 20, 6, 6);
angle++;
torus()に引数を渡さないと、外側の円の半径が50、内側の円の半径が10、細かさが24の円環が作成されます。6などの小さな数の細かさを指定すると、円環には見えなくなります。
リファレンスメモ
与えられた幅と高さの平面を描画する。
シンタックス
plane([width], [height], [detailX], [detailY])
パラメータ
width 数値: 平面の幅(オプション)。デフォルトは50。
height 数値: 平面の高さ(オプション)。デフォルトは50。
detailX 整数: x次元の三角形サブディビジョン数(オプション)。デフォルトは1。
detailY 整数: y次元の三角形サブディビジョン数(オプション)。デフォルトは1。
*訳者注:p5.js 1.0において、detailXとdetailYは1しか受け付けないようです。1より大きな整数を指定すると、”Cannot draw stroke on plane objects with more than 1 detailX or 1 detailY”という警告が表示され、三角形のポリゴンは作成されません。
与えられた半径の球体を作成する。
detailXとdetaiYパラメータは、球体のx次元とy次元のサブディビジョン数を決める。サブディビジョンの数が多いほど球体は滑らかに見える。推奨値は両方とも24。24より大きな値を使用すると、警告が発生したりブラウザがスローダウンする原因になる。
シンタックス
sphere([radius], [detailX], [detailY])
パラメータ
radius 数値: 円の半径(オプション)
detailX 整数: x次元のサブディビジョン数(オプション)
detailY 整数: x次元のサブディビジョン数(オプション)
与えられた半径とチューブ半径の円環体を描画する。
detailXとdetaiYパラメータは、円環体のx次元とy次元のサブディビジョン数を決める。サブディビジョンの数が多いほど円環体は滑らかに見える。デフォルト値と推奨値はdetailXが24、detaiYが16。4と6といった小さな値を設定すると、円環体でない、新しい形状が作成できる。
シンタックス
torus([radius], [tubeRadius], [detailX], [detailY])
パラメータ
radius 数値: 円環全体の半径(オプション)
tubeRadius 数値: チューブの半径(オプション)
detailX 整数: x次元のセグメント数。大きいほど滑らかなジオメトリになる。デフォルトは24(オプション)
detailY 整数: y次元のセグメント数。大きいほど滑らかなジオメトリになる。デフォルトは16(オプション)