前節では基本的なオブジェクトの作成、座標系の移動、回転、拡大縮小を学びました。この節では、Processingの3D空間でライトを使い、立体の見え方や質感を変える方法を学びます。特に、specular()とlightSpecular()の違いは混乱しやすいので、物体側とライト側の設定として分けて理解します。
1. 基本の3D表示
Processingで3Dを使うには、size()の3つ目にP3Dを書きます。まずは、回転する箱を表示してみましょう。
void setup() {
size(400, 400, P3D); // P3Dで3D表示にする
noStroke();
}
void draw() {
background(0);
translate(width/2, height/2, 0); // 原点を画面中央に移動
rotateX(frameCount * 0.01);
rotateY(frameCount * 0.01);
box(150);
}frameCountは、画面が描き直されるたびに増える数です。frameCount * 0.01を回転角度に使うと、少しずつ回転するアニメーションになります。
2. ライト
3Dでは、ライトを使うと立体に陰影がつきます。陰影がつくことで、面の向きや奥行きがわかりやすくなります。まずは一番簡単なlights()を使います。
void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
lights(); // 基本ライトを入れて立体に陰影をつける
translate(width/2, height/2, 0);
rotateX(frameCount * 0.01);
rotateY(frameCount * 0.01);
fill(180);
box(150);
}lights()は、Processingが用意している基本的なライトをまとめて使う命令です。細かい設定をしなくても、立体に明るい面と暗い面ができます。
ポイント:3Dで立体感を出したいときは、まずlights()を入れてみましょう。
3. 環境光
環境光(ambient light)は、方向を持たない光です。全体を均一に照らすため、強い陰影は出ません。画面全体の暗さを少し明るくしたいときに使います。
構文
ambientLight(赤, 緑, 青);void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
ambientLight(80, 80, 80); // 全体を均一に明るくする光
translate(width/2, height/2, 0);
rotateX(frameCount * 0.01);
rotateY(frameCount * 0.01);
fill(200);
box(150);
}ambientLight()は、影をくっきり作るライトではありません。「全体の明るさを底上げする光」と考えるとわかりやすいです。
4. その他のタイプのライト
Processingには、環境光以外にもいくつかのライトがあります。ここでは、方向光と点光源を扱います。
●方向光(directionalLight)
方向光は、一定方向から来る光です。太陽のように、遠くから同じ方向に向かって照らす光だと考えるとわかりやすいです。
構文
directionalLight(赤, 緑, 青, x方向, y方向, z方向);void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
// 最後の3つの値で、光の向きを決める
directionalLight(255, 255, 255, -1, 1, -1);
translate(width/2, height/2, 0);
rotateX(frameCount * 0.01);
rotateY(frameCount * 0.01);
fill(180);
box(150);
}directionalLight()の最後の3つの値は、光の方向を表します。最初は細かく考えすぎず、値を変えると明るくなる面が変わる、ということを確認しましょう。
●点光源(pointLight)
点光源は、電球のように一点から広がる光です。光源の位置を変えると、明るくなる場所も変わります。
構文
pointLight(赤, 緑, 青, x座標, y座標, z座標);void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
// マウスの位置に点光源を置く
pointLight(255, 255, 255, mouseX, mouseY, 200);
translate(width/2, height/2, 0);
fill(120, 170, 255);
sphere(100);
}このサンプルでは、マウスの位置に合わせて光源が動きます。球の明るい部分がマウスに追従することを確認してください。
5. ハイライトとオブジェクトの色
ここでは、lightSpecular()とspecular()を使って、光沢のある表面を作ります。この2つは名前が似ているため混同しやすいですが、担当しているものが違います。
| 命令 | 担当 | 意味 |
|---|---|---|
lightSpecular() | ライト側 | ライトが持っているハイライト用の光の色を決める |
specular() | 物体側 | 物体がどの色・強さで光を反射するかを決める |
lightSpecular()は「光る側」の設定、specular()は「光を受けて反射する側」の設定です。光沢は、ライト側と物体側の両方が関係して見えます。
構文
lightSpecular(赤, 緑, 青); // ライト側のハイライト色
specular(赤, 緑, 青); // 物体側の反射色void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
ambientLight(30, 30, 30);
lightSpecular(255, 255, 255); // ライト側のハイライト色
directionalLight(255, 255, 255, -1, 1, -1);
translate(width/2, height/2, 0);
fill(80, 140, 255);
specular(255, 255, 255); // 物体側の反射色
shininess(30); // 光沢の鋭さ
sphere(100);
}このサンプルでは、ライト側のハイライト色を白にし、物体側も白く反射するように設定しています。そのため、球の表面に白い光沢が現れます。
● specular()の値を変える
次のサンプルでは、左の球は光沢が弱く、右の球は光沢が強くなります。ライト側の設定は同じで、物体側のspecular()だけを変えています。
void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
ambientLight(30, 30, 30);
lightSpecular(255, 255, 255);
directionalLight(255, 255, 255, -1, 1, -1);
translate(130, height/2, 0);
fill(80, 140, 255);
specular(30, 30, 30); // 左の球は反射を弱くする
shininess(30);
sphere(60);
translate(140, 0, 0); // 右の球の位置へ移動
fill(80, 140, 255);
specular(255, 255, 255); // 右の球は反射を強くする
shininess(30);
sphere(60);
}specular()の数値が大きい右の球の方が、ハイライトがはっきり見えます。これは、物体がライトのハイライト成分を強く反射しているからです。
● lightSpecular()の色を変える
次のサンプルでは、ライト側のハイライト色を赤っぽくしています。
void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
ambientLight(30, 30, 30);
lightSpecular(255, 0, 0); // ライト側のハイライト色を赤にする
directionalLight(255, 255, 255, -1, 1, -1);
translate(width/2, height/2, 0);
fill(80, 140, 255);
specular(255, 255, 255);
shininess(30);
sphere(100);
}lightSpecular()の色を変えると、反射して見えるハイライトの色が変わります。
6. 光沢
shininess()は、光沢の鋭さを決める命令です。値が小さいとハイライトは広がり、値が大きいとハイライトは小さく鋭くなります。
void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
ambientLight(30, 30, 30);
lightSpecular(255, 255, 255);
directionalLight(255, 255, 255, -1, 1, -1);
fill(80, 140, 255);
specular(255, 255, 255);
translate(130, height/2, 0);
shininess(3); // 小さい値:ハイライトが広い
sphere(60);
translate(140, 0, 0);
shininess(80); // 大きい値:ハイライトが鋭い
sphere(60);
}| 値 | 見え方 |
|---|---|
shininess()の値が小さい | ハイライトが広く、やわらかい |
shininess()の値が大きい | ハイライトが小さく、鋭い |
7. カメラ
camera()を使うと、3D空間をどこから見るかを設定できます。視点、見る中心、上下方向を指定します。
構文
camera(視点X, 視点Y, 視点Z,
中心X, 中心Y, 中心Z,
上方向X, 上方向Y, 上方向Z);void setup() {
size(400, 400, P3D);
noFill();
stroke(0);
}
void draw() {
background(255);
// カメラ位置、見る中心、上方向を指定する
camera(200, -150, 300,
0, 0, 0,
0, 1, 0);
rotateY(frameCount * 0.01);
box(150);
}最初は、camera()の前半3つが「カメラの位置」、真ん中3つが「どこを見るか」、最後の3つが「どちらを上にするか」と覚えておけば十分です。
8. ortho()
ortho()を使うと、遠近感がつかない表示になります。遠くのものも近くのものも、大きさが変わらずに表示されます。図面やアイソメトリック風の表現に向いています。
void setup() {
size(400, 400, P3D);
ortho(); // 遠近感のない表示にする
}
void draw() {
background(255);
lights();
translate(width/2, height/2, 0);
rotateX(-0.5);
rotateY(0.6);
fill(180);
box(150);
}9. perspective()
perspective()を使うと、遠くのものが小さく見える通常の3Dらしい表示になります。Processingでは初期状態でも遠近感のある表示になっていますが、perspective()を使うと視野角などを調整できます。
perspective()は、視点から広がる見える範囲を設定する。fovは視野角、nearとfarは表示する奥行きの範囲。| 引数 | 意味 | 覚え方 |
|---|---|---|
fov | 視野角 | 広いほど広角レンズのように遠近感が強くなる |
aspect | 画面の縦横比 | float(width)/float(height)でよい |
near | 近くの表示限界 | 近すぎるものを切る位置 |
far | 遠くの表示限界 | 遠すぎるものを切る位置 |
授業では、まずfovだけを変えて、見え方がどう変化するかを確認すれば十分です。nearとfarは「見える奥行きの範囲」と考えておきましょう。
構文
perspective(視野角, 画面の縦横比, 近い面までの距離, 遠い面までの距離);void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(255);
lights();
// マウスの横位置で視野角を変える
float fov = map(mouseX, 0, width, PI/8, PI/2);
// 視野角を変えると、遠近感の強さが変わる
perspective(fov, float(width)/float(height), 10, 1000);
translate(width/2, height/2, 0);
rotateX(-0.4);
rotateY(frameCount * 0.01);
fill(180);
pushMatrix();
translate(-100, 0, 100); // 手前の箱
box(80);
popMatrix();
pushMatrix();
translate(0, 0, 0); // 中央の箱
box(80);
popMatrix();
pushMatrix();
translate(100, 0, -200); // 奥の箱
box(80);
popMatrix();
}マウスを左に動かすと視野角が狭くなり、望遠レンズのような見え方になります。右に動かすと視野角が広くなり、広角レンズのように遠近感が強くなります。
まとめ
| 命令 | 役割 |
|---|---|
lights() | 基本ライトをまとめて入れる |
ambientLight() | 全体を均一に照らす |
directionalLight() | 一定方向から照らす |
pointLight() | 一点から広がる光を作る |
lightSpecular() | ライト側のハイライト色を決める |
specular() | 物体側の反射・光沢の色を決める |
shininess() | 光沢の鋭さを決める |
camera() | 3D空間を見る位置を決める |
ortho() | 遠近感のない表示にする |
perspective() | 遠近感のある表示を調整する |
今日の最重要ポイント:lightSpecular()はライト側、specular()は物体側です。光沢は、ライトがハイライト成分を持ち、物体がそれを反射することで見えるようになります。
