人工言語入門 A 2010
Processingによる3Dプログラミング
今日の内容
Processingで3DCGプログラミング
- 3Dの座標系
- OpenGLとは
- 2Dのアニメーションを3Dに拡張してみる
- 3D座標で図形を描く
- 視点の移動
- 3Dのを用いた高度なアニメーション
コンピュータで3Dを表現するには
コンピュータ画面で3Dを表現したい
- コンピュータのディスプレイは、2D (縦横に並んだピクセル)
- 奥行は擬似的に表現するしかない
- 画面に、立体や空間などの3次元の存在を投影して描画する = 3DCG (3次元グラフィックス)
2次元平面に3次元の存在を投影するには、様々な数学的な知識が必要
- Processingではこうした演算を自動的に行うことが可能
- 3次元の座標系をそのまま使用できる
- 高速な表示のためのライブラリ(OpenGL)も標準で使用可
3D空間の座標系
X (幅)、 Y (高さ) に加えて、奥行を表現する座標軸 Z が加わる。
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); } } 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; }
サンプルファイルのダウンロード
今日とりあげた全てのサンプルは下記からダウンロードしてください。