like coffeeの進捗ダメです

Unity, Processingとか

MENU

Processingでスライムを描画してみた

Hello New Year !! (挨拶)

新年一回目の更新です!


今回は, 先日投稿したツイートが思いのほかいいねがあったのでソースコードを紹介しておきたいと思います!


ソースコード

float verNoise;
float vertex = 8; //最大頂点数
float viscosity = 30; //粘度
color col = #03B9FF;

void setup() {
  size(500, 500);
  noStroke();
}

void draw() {
  background(255);
  slime((int)(1*vertex-1)+1, abs(sin(frameCount*0.1)-0.5)*viscosity);
  verNoise+=.005;
}

void slime(int ver, float vis) { //ver頂点数 vis粘度
  pushMatrix();
  translate(width/2, height/2);
  rotate(frameCount*.01);
  fill(col);
  beginShape();
  for (int theta=0; theta<360; theta++) {
    float r = 150+sin(radians(theta*ver))*vis;
    vertex(cos(radians(theta))*r, sin(radians(theta))*r);
  }
  endShape(CLOSE);
  popMatrix();
}


主にはslime関数により描画処理が行われており, グローバル変数の値を変えることでスライムの描画を調節します.

変数vertexはスライムが伸びた際の最大頂点数を示し, 変数viscosityの値を大きくすると伸び具合 (粘度)が設定できます.


f:id:Eddie_Le_Garden:20200109232847p:plain
↑viscosity=60の場合



割と単純なソースコードですが, プロパティを変えるだけで色々な描画結果になるのでぜひお試しください~!!

HSVでグリッドな床シェーダーを作ってみた

かなり久しぶりの投稿です...!

今回は, 先月の学内プロコン用に作ったシェーダーを作った際の工夫を書いてきます!



イメージとしてはplaneオブジェクトにグリッド線の描画し, さらにBloomエフェクトを設定して色相を動的に変更していく感じです

※本シェーダーではPost Processing Stack を必要とします


Surfaceシェーダ作成

実際に書いたシェーダーが下記になります↓

Shader "Custom/HsvGrid"
{
	Properties{
		_GridThickness("Grid Thickness", Float) = 0.1
		_GridSpacing("Grid Spacing", Float) = 9.0
		_Freq("frequency", Range(1,3)) = 1
		_Bloom("Bloom", float) = 7
	}
	SubShader{
		Tags{ "Render" = "Opaque" }
		LOD 200

		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows
		#pragma target 3.0

		struct Input {
			float3 worldPos;
		};

		//HSB→RGB
		fixed3 hsv2rgb(fixed3 c)
		{
			fixed4 K = fixed4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
			fixed3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
			return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
		}

		float _GridThickness; //グリッド線の太さ
		float _GridSpacing; //グリッドの間隔
		float _Freq; //色相が変化する早さ
		float _Bloom; //Bloomエフェクト用の係数

		void surf(Input IN, inout SurfaceOutputStandard o) {
			float _Hue = _Time * _Freq; //色相

			//グリッド線
			o.Albedo = (frac(IN.worldPos.x / _GridSpacing) < _GridThickness
				|| frac(IN.worldPos.z / _GridSpacing) < _GridThickness) ? hsv2rgb(fixed3(_Hue % 1, 1, 1))*_Bloom : fixed3(0, 0, 0);
		}
		ENDCG
		}
	FallBack "Diffuse"
}


これをPlaneオブジェクトに適用します↓

f:id:Eddie_Le_Garden:20191207140216p:plain


グリッド線のジャギー対策

この時点だと上記のキャプチャから遠くのグリッド線にジャギーが生じてしまうことが確認できます

今回はこれを, むろ小径さん(@murosyoukei)のツイートを参考に改善していきます





このツイートを基に改善したシェーダーがこちらです↓

Shader "Custom/HsvGrid"
{
	Properties{
		_GridThickness("Grid Thickness", Float) = 0.1
		_GridSpacing("Grid Spacing", Float) = 9.0
		_Freq("frequency", Range(1,3)) = 1
		_Bloom("Bloom", float) = 7

		_Center("Center", Vector) = (0,0,0,0) //変更点1
		_Range("Renge", Float) = 0.05 //変更点2
	}
		SubShader{
		Tags{ "Render" = "Opaque" }
		LOD 200

		CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0

		struct Input {
		float3 worldPos;
	};

	//HSB→RGB
	fixed3 hsv2rgb(fixed3 c)
	{
		fixed4 K = fixed4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
		fixed3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
		return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
	}

	float _GridThickness;
	float _GridSpacing;
	float _Freq;
	float _Bloom;

	float4 _Center; //変更点1
	float _Range; //変更点2

	void surf(Input IN, inout SurfaceOutputStandard o) {
		float _Hue = _Time * _Freq; //色相
		float _DepthThick = (distance(fixed3(_Center.x, 0, _Center.z), IN.worldPos)*_Range); //変更点3

		//グリッド線
		o.Albedo = (frac(IN.worldPos.x / _GridSpacing) < _GridThickness + _DepthThick //変更点4
			|| frac(IN.worldPos.z / _GridSpacing) < _GridThickness + _DepthThick) ? hsv2rgb(fixed3(_Hue % 1, 1, 1))*_Bloom : fixed3(0, 0, 0);
	}
	ENDCG
	}
		FallBack "Diffuse"
}


変更点1, 2ではそれぞれ, MainCameraの位置とその距離に応じてグリッド線を太くするための係数を示します
surf関数では実際にMainCameraとの距離を求め, _DepthThick (変更点3) に加算する太さを代入しています



各プロパティの値は大体こんな感じに設定しました↓

f:id:Eddie_Le_Garden:20191207001751p:plain


次に, 上記のシェーダーにMainCameraの座標を渡すスクリプトを作成します

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PosShader : MonoBehaviour
{
    [SerializeField] Renderer mat;

    void Update()
    {
        mat.material.SetVector("_Center", transform.position);
    }
}


このスクリプトをMainCameraにアタッチし, インスペクターから"mat"にPlaneオブジェクトを指定します.


これで実行すると大体こんな感じになるかと思います↓



右のGame画面からも視点が線に近づくにつれ細くなっていることが確認できると思います.


まとめ

完全にジャギーを消すにはさらに色々と改善しなければならない点はあると思いますが, とりあえず簡単な動きだけ実装しました

今後何かいい方法が思いついたらまた投稿したいと思います!


今回, むろ小径さんにはジャギーの改善以外にも色々お世話になりました
本当にありがとうございます...!



下記参考

hsva-unity/HSVRangeShader.shader at master · greggman/hsva-unity · GitHub

Unity grid floor shader · GitHub

むろ小径 on Twitter: "RGB各要素の数値を1.0以上に設定すれば大丈夫なはずです…!
単純に値に100掛けたりするだけでいい感じになります(その場合0.0になる要素が無いようにすると白い部分が出来て光ってる感が出やすくなります)(既に知っていたらすみません)… "

[備忘録]Processingで簡単なテクスチャを作ってみた

Hello Autumn !! (挨拶)


少しずつ日没も早まり秋っぽくなってきましたね!

今日も変わらず研究室ではUnityでプログラムを書いてました (´・ω・)


そのなかで, 今日はUI用のテクスチャを自作する必要があったのですが, Photo ShopやGimpなどは少し扱ったことがある程度で個人的に少し抵抗があるんですよね...


「何か他に慣れ親しんだもので簡単に済ませられないかな...」 と考えたところ

「せや、Processingで作ろう!」


という考えに行きついたため, その方法を備忘録的にまとめておきたいと思います!


ということで下記が簡単なコードです

PGraphics img;
int density = 300;
int r = 200;

void setup() {
  size(512, 512);
  background(0);

  img = createGraphics(width, height);

  img.beginDraw(); //テクスチャへの描画開始
  img.translate(width/2, height/2);
  img.strokeWeight(8); //ふわふわ具合
  for (int i=0; i<density; i++) {
    float angle = 360*i/density;
    for (int j=0; j<r; j++) {
      img.stroke(255, map(j, 0, r, 255, 0));
      img.point(cos(angle)*j, sin(angle)*j);
    }
  }
  
  img.endDraw(); //テクスチャへの描画終了

  image(img, 0, 0); //画像をアプレットに表示
  img.save("texture.png"); //テクスチャを保存
}


PGraphics型のimgが実際に作成するテクスチャで, createGraphics関数により初期化されています


テクスチャに描画処理を行うにはPGraphics型のインスタンス名.beginDraw()と.endDraw()の間に処理を記述していきます

また, テクスチャに書き込む際の描画処理は「PGraphics型のインスタンス名.関数名()」にする必要があります


例: ellipse(50,50,50,50) → img.ellipse(50,50,50,50)


そして最後に, 「インスタンス名.save("ファイル名"); 」でテクスチャを画像として保存します


これでできたテクスチャがこれです. (見やすいように背景を黒くして置いてあるが実際は透明)
f:id:Eddie_Le_Garden:20190907000812p:plain


Unityに入れてみるとこんな感じ
f:id:Eddie_Le_Garden:20190907000945p:plain



今回はあえて簡単な描画にしましたがもっとProcessingっぽいものを書き出すと楽しいと思います!


まぁ、特別こだわりがない限りシェーダーやPhoto Shopでやった方がいいと思いますけど (;´・ω・)

情報科学生のクリエイティブコーディング入門 part.3

更新が遅くなってしまいました... 汗

今回はProcessingでデジタル時計を作っていきたいと思います.


f:id:Eddie_Le_Garden:20190817143938g:plain


ソースコードは下記のとおりです.

int num = 7; //花びらの枚数
PFont font; //フォント

void setup() {
  size(500, 500);
  background(0, 10, 20);
  strokeWeight(5);
  rectMode(CENTER);
  colorMode(HSB,360,100,100);
  
  font = loadFont("DSEG7ClassicMini-Regular-48.vlw"); //フォントファイル
  textAlign(CENTER); //中央揃え
  textFont(font,48); //文字サイズの設定
}

void draw() {
  pushMatrix();
  translate(width/2, height/2);
  
  noStroke();
  fill(209,99,7,10); //RGB(0,10,20)
  rect(0,0,width-1,height-1);
  
  sinFlower();
  popMatrix();
  
  display();
}

//sin波模様
void sinFlower(){
  rotate(frameCount*0.01);
  float r = sin(frameCount*0.05)*width/2; //sin波  
  
  stroke(map(abs(r),0,width/2,0,360),99,99); //中心からの距離で色を決定
  for (int i=0; i<num; i++) {
    float angle = radians(360*i/num);
    point(cos(angle)*r, sin(angle)*r);
  }
}

//時刻の表示
void display(){
  String hour = String.format("%02d",hour());
  String minute = String.format("%02d",minute());
  String second = String.format("%02d",second());
  String ms = String.format("%02d",20+millis()/6000);
  
  fill(209,99,7);
  noStroke();
  rect(width/2,height/2,255,60);
  fill(0,0,99,50);
  text("88:88:88",width/2,height/2+25);
  fill((map((frameCount*0.7)%359,0,width/2,0,359)),99,99);
  text(hour+":"+minute+":"+second,width/2,height/2+25);
}

フォントの設定

Processingでは hour(), minute(), second() 関数を利用することで簡単に現在時刻を取得することができます.
今回, 時刻を表示するフォントはこちらを利用させていただきました.
www.keshikan.net

このフォントは数字が0~9まで同じ大きさで作られているため, サイズによるずれが生じない点がとてもよかったです.


ファイルをダウンロード・解凍したら, そのなかの "DSEG7ClassicMini-Regular.ttf" ファイルをインストールしましょう.
windowsでのインストール方法は下記を参考にします.

opentype.jp



インストールができたらProcessingを起動します.
ツール>フォントの作成を開き, インストールしたフォントを探します.

f:id:Eddie_Le_Garden:20190817150851p:plain


今回はサイズを48にしておき "OK"を押下します.
すると, 現在のスケッチのフォルダ内に"data"というフォルダができ, その中にフォントのvlmファイルが生成されます.


追記: インストールしたフォントが見つからない場合は, フォントをインストールする際に, "すべてのユーザーに対してインストール"を選択することで解決することがあります.
(僕はそうでした)


下記のように実行するとインストールしたフォントが使用できてることが確認できます.

PFont font; //フォント

void setup() {
  size(500, 200);
  background(0);
  strokeWeight(5);

  font = loadFont("DSEG7ClassicMini-Regular-48.vlw"); //フォントファイル
  textAlign(CENTER); //中央揃え
  textFont(font, 48); //文字サイズの設定

  text("hello world", width/2, height/2);
}


実行結果
f:id:Eddie_Le_Garden:20190817151734p:plain


模様

今回はsin波を描画し, rotate()で回転させることで模様を描画しています.
f:id:Eddie_Le_Garden:20190817154618p:plain


また, 下記のコードを追加で記述することで簡単に模様を変えることができるので色々なバリエーションが楽しめます.

//三角波模様
void triangleFlower(){
  rotate(frameCount*0.01);
 float r = triangleWave(90,frameCount*0.5)*width;
  
  stroke(map(abs(r),0,width/2,0,360),99,99); //中心からの距離で色を決定
  for (int i=0; i<num; i++) {
    float angle = radians(360*i/num);
    point(cos(angle)*r, sin(angle)*r);
  }
}

//三角波
float triangleWave(float wl, float t) { 
  return abs((t+wl/2)%wl/wl-0.5);
}


f:id:Eddie_Le_Garden:20190817160941p:plain

模様を変えるにはdraw()内のsinFlower()をtriangleFlower()に書き換える必要があります.


他にもパーリンノイズを用いたり, frameCountに乗算する値を変えるだけで簡単に模様が変わるので, ぜひ好みに遊んでみてもらえればと思います!



最近はTwitter#つぶやきProcessingというタグでコードをツイートすることが流行っているみたいです.
基本的にコードは1ツイートで収まるようにするので, なかなか文字制限が難しいところではありますがすごく面白いので積極的に参加していきたいですね!

情報科学生のクリエイティブコーディング入門 part.2

今回はHSBカラーモデルを用いたプログラムの例を挙げていきたいと思います.


そもそも, HSBカラーとは何なのかは以下のページをみて頂くのが良いかと思います.

www.webcolordesign.net


このブログのヘッダー画像もHSBカラーモデルによって描かれています.

f:id:Eddie_Le_Garden:20190806000543p:plain


そしてソースコードは以下の通りです.

int pixel = 5; //背景の粗さ
int num = 80; //円の数
Circle[] list = new Circle[num];

void setup() {
  size(720, 300);
  noStroke();
  colorMode(HSB, 360, 100, 100, 100); //カラーモードをHSBに変更

  for (int i=0; i<list.length; i++) 
    list[i] = new Circle();

  /*背景*/
  for (int i=0; i<width; i+=pixel) {
    for (int j=0; j<height; j+=pixel) {
      fill(map(i, 0, width, 0, 360), 99, map(j, 0, height, 0, 40)); //座標の位置から色を決定する
      rect(i, j, pixel, pixel);
    }
  }

  blendMode(ADD);
  for (Circle c : list) c.draw();
}

class Circle {
  float x, y; //平面座標
  int size; //円の大きさ(直径)

  Circle() {
    x = random(width); //0~720(画面の横幅)内でランダムに決定する
    y = random(height); //0~300(画面の縦幅)内でランダムに決定する
    size = (int)random(20, 50);
  }
  
  //円の描画処理
  void draw() {
    fill(map(x, 0, width, 0, 360), 99, 99, 40); //x座標の位置から自身の色を決定する
    ellipse(x, y, size, size);
  }
}

colorMode

ProcessingではデフォルトでカラーモードをRGBに設定しています.

ProcessingでHSBカラーモデルを使用するにはcolorMode関数を用います.
第1引数に HSB, 第2引数に 色相(H)の範囲, 第3引数に彩度(S)の範囲, 第4引数に明度(B)の範囲, 第5引数にアルファ値 (透明度)の範囲を指定します.


今回は

colorMode(HSB, 360, 100, 100, 100);

とあるので, 0~360度にかけて色が一周するようにHSBを設定しています.


HSBを適用すると以降, fill()やstroke(), background()で色を指定する際は (H, S, B) もしくは (H, S ,B ,A) と引数を与えます.
サンプルとして以下のプログラムを実行してみると色が時間(フレーム) 経過と共に変化していくのが確認できると思います.

void setup() {
  size(300, 300);
  colorMode(HSB, 360, 100, 100, 100); //カラーモードをRGBからHSBに変更

  background(209, 99, 7); //RGB( 0, 10, 20)
  noStroke();
}

void draw() {
  fill(frameCount%360, 99, 99); //色彩(H)が0~360の範囲で繰り返す
  ellipse(width/2, height/2, 100, 100);
}

実行結果
f:id:Eddie_Le_Garden:20190806005042g:plain

また, 彩度(S)を色を下げることで白っぽく, 明度(B)を下げることで黒っぽく色が変化するのもHSBの特徴です.

map

map関数とは map(a, b, c, d, e)のとき, 値aを b~cの範囲から d~eの範囲に変えることができる関数です.
(『Processing クイックリファレンス 算術関数』引用)


今回は

/*背景*/
  for (int i=0; i<width; i+=pixel) {
    for (int j=0; j<height; j+=pixel) {
      fill(map(i, 0, width, 0, 360), 99, map(j, 0, height, 0, 40)); //座標の位置から色を決定する
      rect(i, j, pixel, pixel);
    }
  }

とあるように, 画面いっぱいに大きさ pixel の四角を並べた上で, それぞれ x方向に進むほど0~360の範囲で色相を決定し, y方向に進むほど0~40の範囲で明度を決定しています.


f:id:Eddie_Le_Garden:20190807231253p:plain


また, Circleクラスでも同様に描画する円の色相をそれぞれのx座標から決定しています. (明度は99で固定)

blendMode

ProcessingではblendModeにより, 色が重なったときの表示について指定しています.
デフォルトではBLENDと設定されており, 色が重なったとき後に描画される色で上書きされるようになっています. (アルファ値が設定されていない場合)

今回は

blendMode(ADD);

と設定しており, 色が重なった部分が白っぽくなります.


詳しくは以下のページを見てもらうのが分かりやすい思います.
aa-deb.hatenablog.com


まとめ

  • HSBカラーモデルを扱うことでカラフルな色の表現がしやすくなる
  • map関数によりある範囲における値を任意の範囲内で置き換えることができる
  • blendModeはいいぞ


大したプログラムではない割に文章で説明しようとすると分かりづらくなってしまいました... 汗
分かりづらいところがあったら気軽にコメントください (;'∀')

情報科学生のクリエイティブコーディング入門 part.1

夏休みになっても別段遊びに行くことがない休暇を送っております... 泣


今回ご紹介するのは僕が初めてクリエイティブコーディングを意識して書いたプログラムです.

f:id:Eddie_Le_Garden:20190803141207p:plain


そして以下がソースコードです.

//Main
int num = 200; //星の数
Star[] stars = new Star[num];

void setup() {
  size(500, 500);
  background(0, 10, 20); //背景色
  noStroke();

  //インスタンスの生成
  for (int i=0; i<stars.length; i++)
    stars[i] = new Star();
}

void draw() {

  //軌跡を残す
  fill(0, 10, 20, 20);
  rect(0, 0, width, height);

  translate(width/2, height/2); //原点の変更
  rotate(frameCount*0.01); //原点から回転

  for (Star star : stars) star.draw();
}

//Starクラス
class Star {
  float x, y, size; //x座標, y座標, 大きさ
  int col; //星の色

  Star() {
    x = random(-width/2, width/2);
    y = random(-height/2, height/2);
    size = random(1, 3);
    col = color(0, random(30, 255), 255); //水色~青の範囲からランダムに決定
  }

  //描画処理
  void draw() {
    fill(col);
    ellipse(x, y, size, size);
  }
}

Starクラスの説明

class Star {
  float x, y, size; //x座標, y座標, 大きさ
  int col; //星の色

  Star() {
    x = random(-width/2, width/2);
    y = random(-height/2, height/2);
    size = random(1, 3);
    col = color(0, random(30, 255), 255); //水色~青の範囲からランダムに決定
  }

  //描画処理
  void draw() {
    fill(col);
    ellipse(x, y, size, size);
  }
}

Starクラスはそれぞれの座標と大きさ, 色を属性として持っています.
コンストラクタ内でそれぞれの属性をランダムに決定しています.
(x座標, y座標の範囲が上記のようになる利用は後ほど説明します)

Mainプログラム

frameCount

frameCountとはプログラム実行時から実行したフレームの数を示します

void draw(){
  println(frameCount);
}

Processingではデフォルトでフレームレートを60に設定してあるので, 上記のように実行することで 1, 2, 3... と一秒間に60回カウントします.

translate()

通常Processingで原点は実行画面左上を示しますが, translate()を使用することで引数として与えたx座標, y座標の位置を原点して設定することができます.
今回は(width/2, height/2)を指定しているので実行画面の中心座標を原点として設定しています.
よって以降, プログラムでは座標として原点 (0,0)を指定すると実行画面の中心座標を示すようになります.
f:id:Eddie_Le_Garden:20190804120050p:plain


そのため, コンストラクタで各インスタンス の座標を指定する際はx座標を(-width/2 ~ width/2), y座標を(-height/2 ~ height/2)の範囲で与えることで画面にまんべんなく星を描画することができます.

rotate()

また, rotate()では原点を中心に引数として与えた角度 (弧度法) 分, 実行画面を回転させることができます.
個人的なイメージとしては画用紙の原点にピンを刺し, それを中心に画用紙を回転させる感じです.
今回は実行画面の中心座標を原点とし, frameCount*0.01を引数として与えています. (frameCountに0.01を乗算することで回転する早さをゆっくりにしている)

軌跡の残し方

Mainプログラム内のdraw()では

fill( 0, 10, 20, 20);
rect( 0, 0, width, height);

との記述があります.
fill()内の4番目の引数は色のアルファ値 (透明度)を示しており, 255で不透明, 0で見えなくなります.
今回は4番目の引数に20を指定しているのでとても色の薄い背景色で四角を画面いっぱいに描画しています.
これにより, 毎フレーム透明な背景色のフィルムが重なるように古い描画結果がゆっくりと塗りつぶされていきます.

おわりに

以上で簡単にですがこのプログラムの説明はおわりになります.
文章で説明するのが苦手で分かりづらい点もあると思いますが, それぞれの記述がどのような役割を持つのかはその行をコメントアウトしながら確認してもらうと良いかと思います.


来週は夏コミですね!
まだ行くかは検討中ですが, 色んなクリエイターの方々集まる場なので一度行ってみたいです! \\└(‘ω’)┘////

情報科学生のクリエイティブコーディング入門 part.0


Hello Summer Vacation ! (挨拶)

 

前期の講義も終わり何となく夏休みの実感が出てきました (;´・ω・)

僕は毎年, 学科内のSAなどで後輩たちのプログラミングの講義に携わらせて頂いてるのですが, それももう3年目になります... (遠い目)

 

僕の通う大学では1年のうちはProcessingというプログラミング言語を通してオブジェクト指向や簡単なアルゴリズムなどを学びはじめます.

 

Processingは簡単に言うと描画処理に長けた言語なのですが, JavaPythonなどと比べて構文も簡単で環境構築も容易な点が初学者には良いみたいですね!

実際に他の大学でも同じようにProcessingから入門することがあるみたいです.

 

しかし, 大学の講義内ではProcessingのメディア・アートとしての側面までは説明されないので僕自身, クリエイティブコーディングというものを知ったのは2年生の秋頃でした... (講義内では某猫型ロボットを描画するくらい

 

f:id:Eddie_Le_Garden:20190803020224p:plain

某ネコ型ロボット

 

そこで, 主に学内でメディア・アートに興味を持ってくれた後輩が見てくれることを期待して (紹介するとは言ってない) , 次回から過去に僕が作ったプログラムの紹介とその仕組みについて解説したいと思います. 

 

また, 他にも僕と同じようにProcessingで絵を描いたことがなかった方が, この記事を通してクリエイティブコーディングに興味を持ってくれたら嬉しいなと思います!

 

ということで, 明日から頑張ります...!