CGプログラミング演習
3 パターン、テクスチャの生成
ここまで2回にわたって講義を進めてきました。
1回目の講義では、Processing の基本を学びました。
2回目の講義では、「変数」「繰り返し」「乱数」を利用することで、コンピュータの計算能力を生かしたグラフィックの描画を学びました。
3回目の今日は、さらにコンピュータの計算能力を活用していきます。
1 さらにコンピュータの計算能力を引き出す
- for 文は、とても強力な構文です。それは、単純な処理だろうと、複雑な処理だろうと、あるまとまった処理をひたすらに繰り返すことを可能にします。
- for 文をさらに強力なものにしているのは、for 文をさらに繰り返すことが可能である点です。
2 前回学んだ構文(おさらい)
- for 文の構成要素は……
- 初期化式:初期化の際の条件式
- 継続条件式:繰り返しを継続する条件式
- 再初期化式:繰り返されるたびに実行される式
for (初期化式; 継続条件式; 再初期化式) { 文; }
- for 文の例
// for 文を用いた繰り返しの例 1 // 100回「+」の文字を出力する int i; for (i = 0; i < 100; i = i + 1) { // print 関数を利用すると、メインウインドウの下に、変数の内容が出力されます print("+"); }
// for 文を用いた繰り返しの例 2 // 0から99までの数を出力する int i; for (i = 0; i < 100; i = i + 1) { print(i + ", "); }
3 便利な関数の紹介
- ここまで取り上げた関数(命令)の他にも、Processing はさまざまな関数を用意しています。
- ここではそのうちのいくつかを取り上げます。
3.1 アンチエイリアシング/不透明度の指定/線の幅の指定/ファイルの書き出し
// 描画結果をアンチエイリアシングする。 smooth(); // 線や色に不透明度を設定する。 // stroke, fill などの色を指定する関数に 4番目の引数として 0〜100 までの値を与えると、 // 与えた数値に応じて、0〜100% までの不透明度を設定できる。 // ここでは、10% の白を設定している。 stroke(255, 255, 255, 10); fill(255, 255, 255, 10); // HSBでも同様に不透明度を指定する場合には、colorMode 関数の引数の数を増やす必要がある。 // これまでは、「colorMode(HSB, 360, 100, 100);」のように引数が 4つだったが、これを 5つに変更する。 colorMode(HSB, 360, 100, 100, 100); // 最後に「, 100」を追加し、100段階で不透明度できるようにした。 // 線の幅を指定する。 // 下の例では、線幅を 10ピクセルに指定しています。 strokeWeight(10); // 描画内容を画像ファイルとして書き出す // 書き出したファイルはプロジェクトフォルダの中に tiff 画像として保存されます。 saveFrame();
3.2 新たな描画関数の紹介
3.2.1 直線をつなげて描画する
// 塗りつぶさない noFill(); beginShape(); // ここから描画開始 vertex(0, 10); // 座標を指定する... vertex(10, 20); // ... vertex(10, 30); // ... vertex(20, 40); // ... endShape(); // ここで描画終了
// 塗りつぶさない noFill(); // 曲線を(点をつなげて)描画する beginShape(); // ここから描画開始 curveVertex(0, 10); // 座標を指定する... curveVertex(10, 20); // ... curveVertex(10, 30); // ... curveVertex(20, 40); // ... endShape(); // ここで描画終了
- 関数は、まだまだたくさん用意されています。
- この授業でも、折りに触れて関数を紹介していきますが、これ以外にどんな関数があるのか確認したくなったら、マニュアルを参照しましょう。
- Processing 1.0 日本語 API マニュアル(日本語で書かれた Processing の APIマニュアル)
4 繰り返しの繰り返し
4.1 単純な繰り返し
- for 文を利用し、色相を変化させながら〈横〉方向に点を描くにはどうすればよいか?
// 初期設定 size(140, 140); // 背景色に白を設定(RGB) background(255, 255, 255); // 変数の宣言 int w = width, h = height, i; // HSBを使用 *不透明度の範囲もあわせて指定 colorMode(HSB, w, 100, 100, 100); // 色相を変化させながら点を描いていく for (i = 0; i < w; i++) { stroke(i, 100, 100, 100); point(i, 0); }
- それでは、これを〈縦〉方向の点の連なりに変更するにはどうすればよいか、考えてみてください
4.2 繰り返しの繰り返し(ネストされた繰り返し)
- 先ほどの例では、for 文に含まれる
i
を、point
関数に与える引数(x, y)のどこに割り振るかで、描画される点を、縦方向・横方向のどちらに連ねるかをコントロールできました。 - ここでひとつ考えて欲しいことがあります。
- さきほどの〈縦〉方向の繰り返しを、〈横〉方向にも繰り返すとどうなるでしょうか?
縦方向の繰り返しを、横方向に繰り返した描画結果
// 初期設定 size(140, 140); // 背景色に白を設定(RGB) background(255, 255, 255); // HSBを使用 *不透明度の範囲もあわせて指定 // 彩度(Saturation)、明度(Brightness)、不透明度(Alpha)の値の変化幅を、 // キャンバスサイズに連動させている。 colorMode(HSB, width, width, height, height); // 変数の宣言 int x, y; // 色相を変化させながら点を描いていく for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { // 点の色の設定 // x の値で、色相(Hue)の値を定める。 // 彩度(Saturation)、明度(Brightness)、不透明度(Alpha)の値は、常に最高値とする。 stroke(x, width, height, height); // 点を描画する point(x, y); } }
- このように「繰り返し」の中に入れられた「繰り返し」を「ネストされた繰り返し」といいます。
- 繰り返しを繰り返すことで、さらにコンピュータの処理能力を引き出すことができるようになり、応用の範囲も広がります。
XY方向への変化に色相、彩度、明度、不透明度の値を割り当てた例。
// 初期設定 size(140, 140); // 背景色に白を設定(RGB) background(255, 255, 255); // HSBを使用 *不透明度の範囲もあわせて指定 // 色相(Hue)、彩度(Saturation)、明度(Brightness)、不透明度(Alpha)の値の変化幅を、 // キャンバスサイズに連動させている。 colorMode(HSB, width, width, height, height); // 変数の宣言 int x, y; // 色相を変化させながら点を描いていく for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { // 点の色の設定 // x の値で、色相(Hue)の値を定める。 // y の値で、彩度(Saturation)、不透明度(Alpha)の値を定める。 stroke(x, y, height, y); // 点を描画する point(x, y); } }
- ここで、カラーモードを RGB に変更して、同じことをしてみます。
XY方向の変化にRGの値を連動させてみる。
// 初期設定 size(140, 140); // 背景色に白を設定(RGB) background(255, 255, 255); // 変数の宣言 int x, y; // RGを変化させながら点を描いていく for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { // 点の色の設定 stroke(x, y, y); // 点を描画する point(x, y); } }
- さらに、これをドットパターンにしてみます。
- ドットパッターンにするためには、x と y を「x++」と 1ずつ増加させるのではなく、たとえば「x = x + 2」とします。
ドットパターンを描画してみる
// 初期設定 size(140, 140); // 背景色に白を設定(RGB) background(255, 255, 255); // 変数の宣言 int x, y; // RGを変化させながら点を描いていく for (y = 0; y < height; y = y + 2) // y を 2つずつ増加させる { for (x = 0; x < width; x = x + 2) // x を 2つずつ増加させる { // 点の色の設定 stroke(x, y, y); // 点を描画する point(x, y); } }
4.3 演習
- さきほどのドットパターンを、2ピクセル刻みから、別の数値に変更してみてください。
- さらに、色の指定を別な方法にアレンジしてみてください。
ドットを 4ピクセル刻みに変更しただけの例
5 ネストされた繰り返しの応用
- 繰り返しによって描かれるグラフィックを、さらに繰り返してみます。
5.1 演習
- 下の2つの描画結果を見てください。1番目は、同心円を繰り返しによって描画したものです。
- これを、2番目のように、x, y 方向に繰り返してみてください。
同心円を描画することを、繰り返すにはどうすればよいか? = 同心円の描画を x, y 方向に繰り返すには?
- ヒント 1
- 最初の同心円は、以下のプログラムで描画されています。これに手を加えて2番目の結果を得るようにします。
// 初期設定 size(300, 300); // 背景色に黒を設定(RGB) background(0, 0, 0); // 描画結果をアンチエイリアシングする smooth(); // 変数の宣言 int x, y, i; // 同心円の色を青緑に設定し、100%の不透明度を与える fill(128, 255, 255, 100); for (i = 0; i < 50; i = i + 10) { // 最大直径50ピクセルで、10ピクセルきざみに小さくなる同心円を描く ellipse(25, 25, i, i); }
- ヒント 2
- 同心円を繰り返すには、同心円の大きさだけ x, y 方向を大きくしてやる必要があります。
- それには、for 文の中で、x, y の増加数を指定します。
for (y = 0; y < height; y = y + 50) { for (x = 0; x < width; x = x + 50) { ... } }
5.2 ランダムな繰り返しを、繰り返しの中に放り込んでみる
ランダムに四角形を描くことを、x, y方向に繰り返す
// 初期設定 size(300, 300); // 背景色に黒を設定(RGB) background(0, 0, 0); // 描画結果をアンチエイリアシングする smooth(); // HSBモードの指定 colorMode(HSB, 100, 100, 100); // 線を描画しない noStroke(); // 変数の宣言 int x, y, i; // 以降の描画結果を x、y 方向にそれぞれ 25ピクセルずらす translate(15, 15); for (y = 0; y < height; y = y + 100) { for (x = 0; x < width; x = x + 100) { // ランダムに四角形を描画する for (i = 0; i < 8; i++) { // 色相をランダムに設定して…… fill(random(40, 50), 100, 100, random(90, 100)); // 四角形の左上の点と、上下・左右の大きさをランダムにする。 rect(x + random(30), y + random(30), random(50), random(50)); } } }
5.3 演習
- 上の例にならい、今度はランダムに三角形を描くプログラムを作成してみてください。
- 三角形を描画する関数の使用法は下記の通りです。
// 三角形 // みっつの頂点がそれぞれ(300, 125)(225, 175)(375, 175)の三角形を描きます triangle(300, 125, 225, 175, 375, 175);
ランダムに三角形を描くことを、x, y方向に繰り返す
// 初期設定 size(300, 300); // 背景色に黒を設定(RGB) background(0, 0, 0); // 描画結果をアンチエイリアシングする smooth(); // HSBモードの指定 colorMode(HSB, 100, 100, 100); // 線を描画しない noStroke(); // 変数の宣言 int x, y, i; // 以降の描画結果を x、y 方向にそれぞれ 25ピクセルずらす translate(25, 25); for (y = 0; y < height; y = y + 100) { for (x = 0; x < width; x = x + 100) { // ランダムに三角形を描画する for (i = 0; i < 16; i++) { // 色相をランダムに設定して…… fill(random(0, 50), 100, 100, 100); // 三角形を構成する 3つの点(x, y)をランダムにする。 triangle(x + random(50), y + random(50), x + random(50), y + random(50), x + random(50), y + random(50)); } } }
5.4 ネストされた繰り返しが生み出すテクスチャ
- キャンバスサイズを極端に大きくしてみます。
- コンピュータは、与えられた命令をひたすら計算します。
- x, y軸方向に沿って周期的に繰り返されるグラフィックが、あるテクスチャを構成していることに注意してください。
ランダムに三角形を描くことを、ひたすら繰り返す。
x, y軸方向に沿って周期的に繰り返される描画が、あるテクスチャを生じさせている。
ランダムに曲線を描くことを、繰り返す。
// 初期設定 size(700, 700); // 背景色に黒を設定(RGB) background(0); // 描画結果をアンチエイリアシングする smooth(); // HSBモードの指定 colorMode(HSB, 100, 100, 100); strokeWeight(1); // を描画しない noFill(); // 変数の宣言 int x, y, i; // 以降の描画結果を x、y 方向にそれぞれ 25ピクセルずらす translate(25, 25); for (y = 0; y < height; y = y + 100) { // ここから曲線の描画を開始して、 beginShape(); for (x = 0; x < width; x = x + 100) { // 色相をランダムに設定して…… stroke(random(40, 50), 100, 100, 100); // ひたすら曲線のポイントを追加し、 for (i = 0; i < 16; i++) { curveVertex(x + random(50), y + random(50)); } } // ここで曲線の描画を終了する。 endShape(); }
6 演習
- 先ほど作成したプログラムをもとに、色やカタチを調整した、バリエーションを作成してみてください。
- 少し数値を変えるだけでも、おもしろい効果が得られます。
- さらに for 文をネストしたり、描画するカタチを円と線の組み合わせにしたり、線幅を変更したりと、いろいろな方法が考えられます。
- キャンバスサイズ等は問いません
- 作成したプログラムの最終行に
saveFrame();
関数を配置し、できあがった TIFF 画像を提出してください。 - 画像ファイルは、Processing のプロジェクトフォルダの中に保存されています。
- 提出時には、画像ファイルの名称を自分の出席番号に書き換えてください。
7 中間課題に向けて
7.1 今日学んだこと
- 本日の授業では、for 文をネストすることにより、x, y 軸に沿って、ある、まとまった処理を繰り返すことを学びました。
- それによって描画されるグラフィックは、ある種のテキスタイルのように、テクスチャを生じさせました。
7.2 中間課題に向けて
- その上で、さらにコンピュータディスプレイが、x, y軸方向に並んだピクセルから成り立っていることを考えてみてください。
- 今回作成したプログラムは、x, y軸方向に沿って、あるグラフィックを描画するものでしたが、同じ方法で、ある画像(ピクセルの集合)を、x, y 方向に読み取ることも可能です。
- すると、x, y 軸方向に所定の画像を読み込みんで、その結果をもとにあるグラフィックを描画することもできるようになります。
- 中間課題では、ある画像を変換し、それをもとに印刷用のデータとして PDF を出力するプログラムを作成します。
以前に紹介したサンプルプログラムも、元の画像ファイルを読み取って、それをもとに別のグラフィックを描画するものでした。