前節では基本的なオブジェクトの作成、座標系の移動、回転、拡大縮小を学びました。この節では、ライティングの演出やカメラの設定を体験します。
5.2.1 ライト
ここでは、processingの3D空間上でライトを使ってみます。ライトといっても、環境光、方向光、スポットライト、ハイライトなど様々な要素がありますが、まずは、一番基本的なライトです。
float theta = 0.0; //角度
//1秒で1回転するように30で割る。度数法だと12°
//更に6で割ると1周期6秒
float rad = (TWO_PI/30.0)/6;
void setup() {
size(400, 400, P3D);
frameRate(30); //1秒30フレーム
noStroke();
}
void draw() {
background(0);
lights(); //基本ライトを設置
//立体の中心を画面中央に移動
translate(width/2, height/2);
rotateX(theta); //X軸に対してtheta分だけ回転
rotateY(theta); //Y軸に対してtheta分だけ回転
box(150, 150, 150); //150x150x150pxの立方体を描画
theta += rad; //時間を進める
if (theta > TWO_PI) theta = 0.0; //1周期分終わったら原点に戻る
}
これで、陰影が付いたことが確認できました。
5.2.2 環境光
次に環境光(ambient light)を再現してみます。環境光は方向性を持たない光です。全体をまんべんなく照らしているので、オブジェクトに陰影は付きません。構文は次の形になります。
//ambientLight(赤, 緑, 青)
ambientLight(red, green, blue);
float theta = 0.0; //角度
//1秒で1回転するように30で割る。度数法だと12°
//更に6で割ると1周期6秒
float rad = (TWO_PI/30.0)/6;
void setup() {
size(400, 400, P3D);
frameRate(30); //1秒30フレーム
noStroke();
}
void draw() {
background(0);
ambientLight(127, 0, 0); //赤の環境光
//立体の中心を画面中央に移動
translate(width/2, height/2);
rotateX(theta); //X軸に対してtheta分だけ回転
rotateY(theta); //Y軸に対してtheta分だけ回転
box(150, 150, 150); //150x150x150pxの立方体を描画
theta += rad; //時間を進める
if (theta > TWO_PI) theta = 0.0; //1周期分終わったら原点に戻る
}
5.2.3 その他のタイプのライト
Processingが提供しているライトのタイプは方向光、点光源やスポットライトなどそれぞれ特色があり、それらを組み合わせて使うこともできます。
●方向光(directionalLight)
方向光(directional light)は一定の方向を持ったライトで、物体をまんべんなく照らします。nx, ny, nzでは、光が向かっている方向を-1.0 ~ 1.0の間で指定します。
//directionalLight(赤, 緑, 青, x方向, y方向, z方向)
directionalLight(red, green, blue, nx, ny, nz);
void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
//立体の中心を画面中央にする
translate(width / 2, height / 2);
//directionalLight(赤, 緑, 青, x方向, y方向, z方向);
//x, y, z方向は光源が照らす方向。-1.0 ~ 1.0
directionalLight(0, 255, 0, 1.0, 1.0, 0.0);
sphere(75); //球を描画
}
●点光源(pointLight)
pointLightは電球のように一箇所から拡散する光です。
//pointLight(赤, 緑, 青, x座標, y座標, z座標);
pointLight(red, green, blue, x, y, z);
void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
//立体の中心を画面中央にする
translate(width / 2, height / 2);
//pointLight(赤, 緑, 青, x座標, y座標, z座標);
pointLight(255, 0, 0, -200, 0, 200);
sphere(75); //球を描画
}
●スポットライト(spotLight)
spotLightはその名の通り、一定方向に強い光をあてるライトです。directionalLightやpointLightと比べると、細かい設定が可能です。
spotLight(red, green, bule, //赤, 緑, 青
x, y, z, //光源のx, y, z座標
nx, ny, nz, //光の方向
angle, //スポットの角度(ここでは20°)
concentration); //光の集まり度合い。数値が小さいと強く一点に集まる
次のサンプルでは、3種類のライトを切り替えることができます【リスト5.2-c】。
float angle = 0.25; //スポットの角度
float diffusion = 0.5; //光が拡散する度合い
void setup() {
size(400, 400, P3D);
noStroke();
}
void draw() {
background(0);
//立体の中心を画面中央にする
translate(width / 2, height / 2);
spotLight(0, 0, 255, //赤, 緑, 青
0, -200, 200, //光源のx, y, z座標
0, 1.0, -1.0, //光源が照らす方向。-1.0 ~ 1.0
angle, //スポットの角度
diffusion); //光が拡散する度合い
sphere(75); //球を描画
}
void keyPressed() {
if (key == CODED) {
if (keyCode == UP)
angle += 0.05; //スポットの角度を拡大
else if (keyCode == DOWN)
angle -= 0.05; //スポットの角度を縮小
else if (keyCode == RIGHT)
diffusion += 5.0; //拡散度合いを拡大
else if (keyCode == LEFT)
diffusion -= 5.0; //拡散度合いと縮小
}
}
5.2.4 ハイライトとオブジェクトの色
様々な種類のライトがありましたが、次は光源の鏡面反射成分を指定するlightSpecular()と、オブジェクトの鏡面反射成分を設定するspecular()を使います。似た名称で混同しやすいのですが、反射成分が光源とオブジェクトのどちらに属しているかの違いです。
//lightSpecular(赤, 緑, 青)
lightSpecular(red, green, blue); //光源の鏡面反射成分
//specular(赤, 緑, 青)
specular(red, green, blue); //オブジェクトの鏡面反射成分
次のコードを実行してみましょう【リスト5.2-d】。
boolean lightFlag = false;
void setup() {
size(400, 400, P3D);
background(0);
noStroke();
}
void draw() {
background(0);
ambientLight(10, 10, 10); //環境光
pushMatrix();
translate(width/2, height/2, 0);
//directionalLight 光源の鏡面反射成分を設定
lightSpecular(255, 255, 255);
//方向光を設定
directionalLight(255, 255, 255, -1, 1, -1);
//反射面の強いハイライトを設定
if (lightFlag == true)specular(255, 255, 255);
else specular(50, 50, 50); //反射面の弱いハイライトを設定
sphere(100);
popMatrix();
}
//lightSpecularの切り替え用フラッグ
void mousePressed() {
if (lightFlag == true) lightFlag = false;
else lightFlag = true;
}
クリックでspecularの値が変わります。例えばspecular(50, 50, 50)の場合、ハイライトは緩やかになり、specular(255, 255, 255)の場合はハイライトが強くなります。
次に、ふたつの球それぞれにspecular()を設定してみます。
float angle = 0.0;
void setup() {
size(400, 400, P3D);
background(0);
noStroke();
}
void draw() {
background(0);
ambientLight(20, 20, 20); //環境光を当てる
//光の鏡面反射成分(ハイライト)を設定
lightSpecular(255, 255, 255);
//方向光を設定
directionalLight(100, 100, 100, 0, 1, -1);
//左の球
pushMatrix();
translate(100, height/2, 0);
specular(255, 0, 0); //オブジェクトの鏡面反射成分
sphere(50);
popMatrix();
//右の球
pushMatrix();
translate(300, height/2, 0);
specular(0, 0, 255); //オブジェクトの鏡面反射成分
sphere(50);
popMatrix();
}
5.2.5 光沢
金属のような光沢はshininess()で設定します。
float angle = 0.0;
void setup() {
size(400, 400, P3D);
background(0);
noStroke();
}
void draw() {
background(0);
ambientLight(20, 20, 20); //環境光を当てる
//光の鏡面反射成分(ハイライト)を設定
lightSpecular(255, 255, 255);
//方向光を設定
directionalLight(100, 100, 100, 0, 1, -1);
//左の球
pushMatrix();
translate(100, height/2, 0);
specular(200, 200, 200); //オブジェクトの鏡面反射成分を設定
shininess(5.0); //オブジェクトの光沢を設定
sphere(50);
popMatrix();
//右の球
pushMatrix();
translate(300, height/2, 0);
specular(200, 200, 200); //オブジェクトの鏡面反射成分を設定
shininess(1.0); //オブジェクトの光沢を設定
sphere(50);
popMatrix();
}
5.2.6 カメラ
ここではカメラを設置して、空間の見え方を設定します。
標準のカメラはcamera()を使います。視点と中心点、天地がどの方向か(通常はYが天)を指定します。
//camera(視点X, 視点Y, 視点Z, 中心点X, 中心点Y, 中心点Z, 天地X, 天地Y, 天地Z)
camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
コードは【リスト5.2-g】になります。camera関数の中の値を変えてどのように見え方が変化するか確認しましょう。
void setup() {
size(400, 400, P3D);
noFill();
stroke(0);
}
void draw() {
background(255);
//基準点を画面中央
translate(width/2, height/2, 0);
camera(90.0, -100.0, 300.0, // 視点X, 視点Y, 視点Z
0.0, 0.0, 0.0, // 中心点X, 中心点Y, 中心点Z
0.0, 1.0, 0.0); // 天地X, 天地Y, 天地Z
box(150);
}
5.2.7 ortho()
パースペクティブ(遠近)がつかない立体です。
//ortho(左, 右, 下, 上);
ortho(left, right, bottom, top);
//ortho(左, 右, 下, 上, 近い面までの距離、遠い面までの距離);
ortho(left, right, bottom, top, near, far);
void setup() {
size(400, 400, P3D);
noFill();
stroke(0);
//ortho(左、右、下、上)
ortho(-width/2, width/2, -height/2, height/2);
}
void draw() {
background(255);
//基準点を画面中央
translate(width/2, height/2, 0);
rotateX(-PI/9.0);
rotateY(-PI/9.0);
box(150);
}
5.2.8 frustum()
パースペクティブが付いた空間になります。次の形で使います。
frustum(左、右、下、上、近い面までの距離、遠い面までの距離)
frustum(left, right, bottom, top, near, far);
【図5.2-m】はその構造を図解したものです。
float scale = 5; //視点の範囲の拡大率
float aspect; //画面の縦横比
void setup() {
size(400, 400, P3D);
noFill();
stroke(0);
//画面の縦横比が変わってもオブジェクトが歪まないように比率を計算
aspect = float(width)/float(height);
//frustum(左、右、下、上、近い面までの距離、遠い面までの距離)
frustum(-scale*aspect, scale*aspect, -scale, scale, 10, 500);
}
void draw() {
background(255);
//基準点を画面中央。z軸方向には-100
translate(width/2, height/2, 0);
rotateX(-PI/9.0); //-20°回転
box(150);
}
5.2.9 perspective()
perspective()はfrustum()とほぼ同じ機能ですが、x座標の視野角(fov)を設定できるのが特徴で、fovの設定を変えると遠近感のつき方が変化します。次の形で使います。
//perspective(視野角、縦横の比率、近い面までの距離、遠い面までの距離)
perspective(foxy, aspect, zNear, zFar);
【図5.2-o】はその構造を図解したものです。
サンプルは、視野角を非常に広い90度にしているために、遠近感が強くなっています。一般的には、30度から60度ぐらいまでが適切かもしれません。
float transZ = 0.0;
float angle = 45.0;
void setup() {
size(400, 400, P3D);
noFill();
stroke(0);
//perspective(視野角、縦横の比率、近い面までの距離、遠い面までの距離)
perspective(radians(angle), float(width)/float(height), 100.0, 800.0);
}
void draw() {
background(255);
translate(width/2, height/2, transZ); //基準点を画面中央、z座標を設定
rotateX(radians(-30.0)); //-30°回転
box(150);
}
//何らかのキーが押された時に実行される
void keyPressed() {
background(255);
//1を押したら視野角45度、2を押したら視野角90度
switch(key) {
case '1':
transZ = 0.0;
angle = 45.0;
perspective(radians(angle), float(width)/float(height), 100.0, 800.0);
println("1");
break;
case '2':
transZ = 140.0;
angle = 90.0;
perspective(radians(angle), float(width)/float(height), 100.0, 800.0);
println("2");
break;
}
}