人工言語入門 A 2010
Processingによる3Dプログラミング
今日の内容
Processingで3DCGプログラミング
- 3Dの座標系
- OpenGLとは
- 2Dのアニメーションを3Dに拡張してみる
- 3D座標で図形を描く
- 視点の移動
- 3Dのを用いた高度なアニメーション
コンピュータで3Dを表現するには
コンピュータ画面で3Dを表現したい
- コンピュータのディスプレイは、2D (縦横に並んだピクセル)
- 奥行は擬似的に表現するしかない
- 画面に、立体や空間などの3次元の存在を投影して描画する = 3DCG (3次元グラフィックス)
2次元平面に3次元の存在を投影するには、様々な数学的な知識が必要
- Processingではこうした演算を自動的に行うことが可能
- 3次元の座標系をそのまま使用できる
- 高速な表示のためのライブラリ(OpenGL)も標準で使用可
コンピュータ画面での3Dを表示する
3D空間の座標系
X (幅)、 Y (高さ) に加えて、奥行を表現する座標軸 Z が加わる。
3Dの座標系
3Dプログラミング基本
まず2Dの図形を回転するプログラムを作成してみる
- translateで画面の中心を座標の原点に
- 以下の処理を繰り返す
- 背景描画
- rotateで回転
- rectを描画
- 回転する角度を更新
float rot=0;
void setup(){
size(400,400);
frameRate(60);
smooth();
fill(63,127,255);
stroke(255);
//四角形を中心を原点に描画するモードに
rectMode(CENTER);
}
void draw(){
background(0);
//画面の中心に原点(0,0)を移動する
translate(width/2,height/2);
//画面の中心を軸にrotだけ回転
rotate(rot);
//四角を描く
rect(0,0,200,200);
//角度を更新
rot += 0.06;
}
現状の回転する四角形のプログラム
- 2D的な視点では平面上で回転している、これを3D的な視点に変更してみる
- 現状では、Z軸を中心軸としてXY平面上に置いてある物体が回転している
- では軸をZ軸ではなく、他の軸(X軸、Y軸)にすると果してどうなるのか
回転する軸を指定してrotateする関数
rotateX(angle); // X軸を中心に回転
rotateY(angle); // Y軸を中心に回転軸を中心に回転
rotateZ(angle); // Z軸を中心に回転軸を中心に回転
3D座標を用いたプログラミングをする際の注意点
レンダラー (描画の際の方式) を指定する必要がある
- P3D – Processing専用の3D描画エンジン
- OpenGL – 3Dグラフィックスのためのプログラムインターフェイス、高速に3D画像を描画できる
P3Dを使用する場合
- size関数に以下の指定をする
size (幅, 高さ, P3D); // size関数にP3Dの指定
OpenGLを使用する場合
- プログラムの先頭でOpenGLのライブラリを読み込み
- size関数にOPENGLの指定をする
import processing.opengl.*; // OpenGLライブラリの読み込み
size(幅, 高さ, OPENGL); // size関数にOPENGLの指定
OpenGLを使用した3次元空間での回転
x軸を中心に回転
import processing.opengl.*;
float rot=0;
void setup(){
size(400,400,OPENGL);
frameRate(60);
fill(63,127,255);
stroke(255);
rectMode(CENTER);
}
void draw(){
background(0);
translate(width/2,height/2);
//X軸を中心に回転させる
rotateX(rot);
rect(0,0,200,200);
rot += 0.06;
}
x,y,z軸をそれぞれ回転
import processing.opengl.*;
// x, y, z それぞれの軸での回転角度
float rotX, rotY, rotZ;
void setup(){
size(400,400,OPENGL);
frameRate(60);
fill(63,127,255);
stroke(255);
rectMode(CENTER);
}
void draw(){
background(0,0,20);
translate(width/2,height/2);
//X軸を中心に回転
rotateX(rotX);
//Y軸を中心に回転
rotateY(rotY);
//Z軸を中心に回転
rotateZ(rotZ);
//四角形を描く
rect(0,0,200,200);
//それぞれの軸の回転角度を更新
rotX += 0.02;
rotY += 0.03;
rotZ += 0.05;
}
3D図形の描画デモ
四角形を3D空間にタイル状に敷き詰める
- for文を2重に入れ子にして、X,Y方向にグリッド状に四角形を敷きつめていく
- ただし個々の四角形はすこしだけ斜めに傾けて立体感を強調する
- マウスの位置によって、座標全体を回転してみる
- まずは単純に描画してみる
import processing.opengl.*;
void setup() {
size(400, 400, OPENGL);
noStroke();
fill(255, 190);
}
void draw() {
background(0);
translate(width / 2, height / 2, 0);
//マウスの位置で座標全体を回転する
rotateX(mouseX / 200.0);
rotateY(mouseY / 100.0);
//四角形描画を中心を原点に
rectMode(CENTER);
//敷きつめるタイルの一片の長さ
int dim = 18;
//XY平面を正方形でタイリング
for (int i = -height / 2; i < height / 2; i += dim) {
for (int j = -width / 2; j < width / 2; j += dim) {
pushMatrix();
translate(i, j);
rotateX(radians(30));
rotateY(radians(30));
rect(0, 0, dim, dim);
popMatrix();
}
}
}
ライティング
Processinには様々なライティングの方法を用いることができる
- ambientLight() – 環境光
- directionalLight() – 一定方向から差し込む平行光
- pointLight() – 点光源
- spotLight() – スポットライト
様々な光を活用しながら、複雑なライティングをしてみる
import processing.opengl.*;
void setup() {
size(400, 400, OPENGL);
noStroke();
fill(255, 190);
}
void draw() {
//環境光
ambientLight(63, 31, 31);
//平行光
directionalLight(255, 255, 255, -1, 0, 0);
//点光源
pointLight(63, 127, 255, mouseX, mouseY, 200);
//スポットライト
spotLight(100, 100, 100, mouseX, mouseY, 200, 0, 0, -1, PI, 2);
background(0);
translate(width / 2, height / 2, -20);
rotateX(mouseX / 200.0);
rotateY(mouseY / 100.0);
int dim = 18;
for (int i = -height / 2; i < height / 2; i += dim * 1.4) {
for (int j = -width / 2; j < width / 2; j += dim * 1.4) {
pushMatrix();
translate(i, j);
rotateX(radians(30));
rotateY(radians(30));
box(dim, dim, dim);
popMatrix();
}
}
}
カメラ
Processingでは何も指定していない時にはカメラ(視点)の場所は、中心点(0, 0, 0)。しかし、camera() 関数を使用することで、視点をコントロールすることができる
camera() 関数
- camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)
- eyeX, eyeY, eyeZ – 視点の位置
- centerX, centerY, centerZ – 注視する中心位置
- upX, upY, upZ – カメラの向き
マウスの位置でカメラの位置をコントロールしてみる
import processing.opengl.*;
void setup() {
size(400, 400, OPENGL);
noStroke();
fill(255, 190);
}
void draw() {
background(0);
ambientLight(63, 31, 31);
directionalLight(255, 255, 255, -1, 0, 0);
pointLight(63, 127, 255, mouseX, mouseY, 200);
spotLight(100, 100, 100, mouseX, mouseY, 200, 0, 0, -1, PI, 2);
//カメラを定義、マウスの位置でカメラの位置が変化する
camera(mouseX, mouseY, 200, width / 2.0, height / 2.0, 0, 0, 1, 0);
translate(width / 2, height / 2, -20);
int dim = 18;
for (int i = -height / 2; i < height / 2; i += dim * 1.4) {
for (int j = -width / 2; j < width / 2; j += dim * 1.4) {
pushMatrix();
translate(i, j);
rotateX(radians(30));
rotateY(radians(30));
box(dim, dim, dim);
popMatrix();
}
}
}
3D空間でのアニメーション
少しずつスピードを変化させながら回転する立方体を作成してみる
import processing.opengl.*;
float a;
int NUM = 128;
float offset = PI / NUM;
color[] colors = new color[NUM];
void setup() {
size(400, 400, OPENGL);
noStroke();
colorMode(HSB, 360, 100, 100, 100);
frameRate(30);
for (int i = 0; i < NUM; i++) {
colors[i] = color(i * 2 + 100, 70, 100, 25);
}
lights();
}
void draw() {
background(0);
ambientLight(63, 31, 31);
directionalLight(255, 255, 255, -1, 0, 0);
pointLight(63, 127, 255, mouseX, mouseY, 200);
spotLight(100, 100, 100, mouseX, mouseY, 200, 0, 0, -1, PI, 2);
translate(width / 2, height / 2, -20);
rotateX(mouseX / 200.0);
rotateY(mouseY / 100.0);
for (int i = 0; i < NUM; i++) {
pushMatrix();
fill(colors[i]);
rotateY(a + offset * i);
rotateX(a / 2 + offset * i);
rotateZ(a / 3 + offset * i);
box(width / 2);
popMatrix();
}
a += 0.01;
}
サンプルファイルのダウンロード
今日とりあげた全てのサンプルは下記からダウンロードしてください。