1225

Twitter:@dn0t_ GitHub:@ogrew

【週刊p5js】work03

var loopCount = 40;
var colorArray = ["#BDA8AD", "#DEB3AD", "#F4EFEB", "#ECE3DA", "#ECC5C0", "#A19BA9"];
var decorationColor = 200;

function setup() {
  createCanvas(windowWidth, windowHeight);
  colorMode(RGB);
  smooth();
  angleMode(DEGREES);  
  strokeCap(SQUARE);
  frameRate(1);
}

function grain() {
  noStroke();
  fill(decorationColor);
  for (let i = 0; i < 2000; i++) {
    ellipse(random(width), random(height), 2);
  }
}

function draw() {
  var colorPalette = shuffle(colorArray);

  let bgColor = colorPalette.pop();
  background(bgColor);

  let cx = width/2;
  let cy = height/2;

// ---------------------------------------------- //

    grain()

// ---------------------------------------------- //
  let rectColor = colorPalette.pop();
  noStroke();
  fill(rectColor);
  rect(100,         random(200,400), 20, random(100,400));
  rect(300,         random(200,400), 20, random(100,400));
  rect(500,         random(200,400), 20, random(100,400));
  rect(width - 100, random(200,400), 20, random(100,400));
  rect(width - 300, random(200,400), 20, random(100,400));
  rect(width - 500, random(200,400), 20, random(100,400));

// ---------------------------------------------- //

  noFill();

  for(let i = 1; i < loopCount/2; i++) {
    push();
    translate(cx, cy);
    drawingContext.setLineDash([]);
    stroke(decorationColor,190);
    noFill();
    strokeWeight(1);

    let startY = random(-cy*2, cy*2);
    let endY = random(-cy*2, cy*2);
    bezier(
      -width, startY, 
      -width/2, 1000*sin(2*i),
      width/2,  -500*cos(2*i),
      width, endY
    );
    bezier(
      -width + 3, startY + 3, 
      -width/2 + 3, 1000*sin(2*i) + 3,
      width/2 + 3,  -500*cos(2*i) + 3,
      width + 3, endY + 3
    );

    let startX = random(-cx*2, cx*2);
    let endX = random(-cx*2, cx*2);
    bezier(
      startX, -height, 
      1000*sin(2*i), -height/2,
      -500*cos(2*i), height/2,
      endX, height, 
    );
    bezier(
      startX + 3, -height + 3, 
      1000*sin(2*i) + 3, -height/2 + 3,
      -500*cos(2*i) + 3, height/2 + 3,
      endX + 3, height + 3, 
    );

    pop();
  }

// ---------------------------------------------- //

  let c1 = colorPalette.pop();
  let c2 = colorPalette.pop();
  for(let i = 1; i < loopCount; i++) {
    if(random() < 0.3) {
      continue;
    }

    strokeWeight(int(random(10,60)));
    let l1 = random(1,10);
    let l2 = random(1,10);
    let margin1 = random(5,20);
    let margin2 = random(5,20);

    if(random() < 0.1) {
      drawingContext.setLineDash([]);
    } else {
      drawingContext.setLineDash([l1, margin1, l2, margin2]);
    }

    let r = i * i;
    let start = random(0, 360);
    let end = random(start, start + 360);

    let rotateNum = random(0,180);

    push();
    translate(cx, cy);
    rotate(rotateNum);
    stroke(c1);
    arc(0, 0, r*0.95, r*0.95, start, end);
    stroke(c2);
    arc(0, 0, r, r, start, end);
    pop();

  }

}

f:id:taiga006:20200216145655j:plain

メモ

  • 今回のモチベは「破線書きたいな、どう書くんだろ。」
  • ググったところp5jsのレポジトリでこんなissueを発見。
  • 「p5js、というかprocessing自体には専用のメソッドはないがネイティブのsetLineDash()を使えばできるよ!」
  • できた、わーい。
  • そこから次は「vertexを使って背景を作りたいな。」
  • けれどいまいち使いこなせず、断念。
  • ここ1週間くらいTwitterのProcessing界隈ではeraseのブームが来ているが、それもなにか使おうと思ったもののネタが思いつかず、断念。
  • 結局bezier関数でお茶を濁すことにしたのだけれど、これが結構ハマった。
  • 今回は配色に頭を使いたくなかったのでココで拝借。

ということで非常に満足のいく作品が作れた。 本当はアニメーションとかさせることでもっとかっこよくできることは目に見えてるんだけど、あくまでこの取組では静止画を作っていきたいのでやりませんでした。興味ある人はコピってやってみてください。

【Unity】スマホの画面タッチで回転させたいしピンチイン・ピンチアウトさせたい

f:id:taiga006:20200215144820g:plain

●学んだことメモ

「対象のオブジェクトをフリックで回転、それからピンチイン・ピンチアウトできるスクリプト書いて~」って言われて着手。 最初はデバッグしながら進めたかったので「マウスのクリックで擬似的にやるか~」と思って Input.GetMouseButtonDown とか使って書き始める。 その時書いてたのがこれ。(長くなるのでコード自体は載せない。)

問題が2つ。

①回転は実装できてもピンチイン・ピンチアウトはできない(マウスポインターは2つない)

これは書き始めてすぐに思った。 まいどまいど、ビルドして実機で確認するのは面倒だったのでなんとかならないかと思ってググったところ、GodTouchを発見。

Unityエディタ上でタッチの動作を確認できるAssetです。iOS/Android/エディタで同じ挙動になります。
(上記リンクサイトより)

これでやろうかなーと思ったが、Assetを入れるほどのことでもないような気がしたのと、なんとか自分の力だけでやりたかったので、もう少し調査することに。 そして、UnityRemoteを知る。

要はビルドすることなく接続された端末で動作確認できる。(ただし、デバイス上で動いているのではなくUnityエディタで擬似的に動かしている=パフォーマンスは落ちる)

これなら心置きなくマウスの実装をスクリーンタッチの実装に移植できる。

ちなみにUnityRemoteの導入は特に詰まることはないと思うけど、ココのサイトが親切丁寧。

①解決。

②マウスを使った実装を実機を使った実装に移植すると変な感じ

スクリーンタッチの実装に移植して、実機で動きを見てて②に衝突。UnityRemoteのせいかもしれない。何よりスクリーンから指を離した後の慣性による回転ー>停止がうまく動作しない。

ログを吐かせて見た感じ、スクリーンタッチによる操作の場合、指を動かしているフェーズ(Touch.Moved)は最後の数フレーム分動いてないバッファのような物を持ってしまうっぽい?すごい速さで指動かしてみたりしたけど駄目だった。

ひとまず、慣性による緩やかな回転ー>停止は諦めて、回転の実装はこれで終わり。

長々書いてるけど、ここまで30分くらいでできるのでUnityは便利だし、何より先人たちの知見がいっぱいネットに落ちている🙏🙏🙏

次はピンチイン・ピンチアウトの実装だけど、参考に載せたサイトなどを見ながら実装。結局やっていることは前フレームと今フレームの差分をあてがってあげるだけなので回転と一緒。

可読性のためにt2.touchのTouchPhaseで分岐しているので、このコードだと正しくは2本指のうち最初にタッチした方の指だけを動かした場合はピンチイン・ピンチアウトは動作しない。(が、そんなことでユーザは躓くことはないだろうと言う算段でこの実装。)

ちなみに、TouchPhaseは他にもある。

TouchPhase 意味
Began 画面に指が触れたとき
Moved 画面上で指が動いたとき
Stationary 指が画面に触れているが動いてはいないとき
Ended 画面から指が離れたとき
Canceled システムがタッチの追跡をキャンセルしました

以上、ここまでで調べる時間含めて2時間くらい。お疲れさまでした。

参考

starmine2011.hatenablog.jp

Unityでマウス操作でオブジェクトを回転させるspphire9.wordpress.com

blog.narumium.net

mam2apo.xsrv.jp

www.tempura.blog

assetstore.unity.com

【週刊p5js】work02

function setup() {
  colorMode(RGB);
  angleMode(DEGREES);

  textFont("Sawarabi Mincho");
  
  createCanvas(windowWidth, windowHeight);
  pixelDensity(2);
  frameRate(1);
}

function mousePressed() {
  resizeCanvas(windowWidth, windowHeight);
  redraw();
}

function grain() {
  noStroke();
  fill(255);
  for (let i = 0; i < 1000; i++) {
    ellipse(random(width), random(height), 1);
  }
}

function draw() {

  var bgColor1 = ConvertColorcode2RBG('#FD6585');
  var bgColor2 = ConvertColorcode2RBG('#0D25B9');
  var graColor3 = ConvertColorcode2RBG('#FFA8A8');
  var graColor4 = ConvertColorcode2RBG('#FCFF00');
  var graColor5 = ConvertColorcode2RBG('#F6D242');
  var graColor6 = ConvertColorcode2RBG('#FF52E5');
  var graColor7 = ConvertColorcode2RBG('#E288F9');
  var graColor8 = ConvertColorcode2RBG('#FFC988');

  setGradientBG(bgColor1, bgColor2);

  noFill();
  stroke(200,200,200,200);
  ellipse(width/2, height/2, width*.7);
  ellipse(width/2, height/2, width*.63);

  let num = 10;

  for (let i = 0; i < num/2; i++) {
    let w = random(100, width - 100);
    let h = random(100, height - 100);
    let l1 = random(30);
    let l2 = random(60,210);
    setGradientBox(graColor3, graColor4, [w, h], l1, l2);
  }

  for (let i = 0; i < num/2; i++) {
    let w = random(100, width - 100);
    let h = random(100, height - 100);
    let l1 = random(20);
    let l2 = random(80,230);
    setGradientBox(graColor5, graColor6, [w, h], l1, l2);
  }

  for (let i = 0; i < num; i++) {
    let w = random(100, width - 100);
    let h = random(100, height - 100);
    let l1 = random(10);
    let l2 = random(100,250);
    setGradientBox(graColor7, graColor8, [w, h], l1, l2);
  }

  let cells = 11;

  let offset = width / 14;
  let margin = offset / 5;
  let w = (width  - offset * 2 - margin * (cells - 1)) / cells;
  let h = (height - offset * 2 - margin * (cells - 1)) / cells;


  stroke(240);
  strokeWeight(2);
  noFill();

  for (let i = 0; i < cells; i++) {
    for (let j = 0; j < cells; j++) {
      if (i == 5 || j == 5) {
        continue;
      }
      let rotate_num = int(random(4)) * 90;
      let shape_num = int(random(5));
      let length = random((w+h)/2*0.25, (w+h)/2);
      let x = i*(w+margin) + offset;
      let y = j*(h+margin) + offset;

      rectMode(CENTER);

      push();
      let cx = x + w/2;
      let cy = y + h/2;
      translate(cx, cy);
      rotate(rotate_num);
      drawShape(shape_num, length, w, h);
      pop();    
    }    
  }

  grain();
  drawText("空\n\n\n\n\n\n\n\n\n\n\nだ");
}

function drawText(tt) {
  push();
  translate(width/2, height/2);
  rectMode(CENTER);
  fill(20);
//  rect(0, 10, width - 100, 50); // yoko
  rect(15, 0, 50, width - 100); // tate
  fill(255);
  textSize(46);
  textAlign(CENTER, CENTER);
  text(tt, 0,0);
  pop(); 
}

function drawShape(shape_num, length, tate, yoko) {
  if (shape_num == 0) {
    if(random()<0.3) {
      noStroke();
      fill(240);
    }
    triangle(-length/2, -length/2, length/2, -length/2, -length/2, length/2);
  } else if (shape_num == 1){
    if(random()<0.3) {
      noStroke();
      fill(240);
    }
    rectMode(CENTER);
    rect(0, 0, length, length);
    rotate(45);
    rect(0, 0, length/2, length/2);
  } else if (shape_num == 2) {
    if(random() < 0.3) {
      noStroke();
      fill(240);
      ellipse(0, 0, length/2, length/2);
    } else {
      noFill();
      stroke(240);
      ellipse(0, 0, length, length);
      if (random() < 0.5) {
        noStroke();
        fill(240);
        ellipse(random(-5,5), random(-5,5), length/3, length/3);
      }
    }
  } else if (shape_num == 3) {
    var r = random();
    if(r < 0.333) {
      arc(-length/2, -length/2, length*2, length*2, 0, 90);
    } else if (r < 0.666) {
      fill(240);
      arc(-length/2, -length/2, length*2, length*2, 0, 90, CHORD);
    } else {
      fill(240);
      arc(-length/2, -length/2, length*2, length*2, 0, 90, PIE);
    }
  } else if (shape_num == 4) {
    let coff = random(0.25, .75);
    line(-yoko/2 * coff,-tate/2 * coff,yoko/2 * coff, tate/2 * coff);
    line(-yoko/2 * coff, tate/2 * coff,yoko/2 * coff,-tate/2 * coff);
    if(random() < 0.5) {
      rectMode(CENTER);
      rect(0, 0, tate/4, yoko/4);
    } 
  }
}

function setGradientBG(c1, c2) {
  noFill();
  for(let i = 0; i < height; i++) {
    var amt = map(i, 0, height, 0, 1);
    var col = lerpColor(c1, c2, amt);
    stroke(col);
    line(0, i, width, i);
  }
}

function setGradientBox(c1, c2, pos, w, h) {
  noFill();
  for(let i = 0; i < h; i++) {
    var amt = map(i, 0, h, 1, 0);
    var col = lerpColor(c1, c2, amt);
    stroke(col);
    line(pos[0], pos[1]-i, pos[0]+w, pos[1]-i);
  }  
}

function ConvertColorcode2RBG(colorcode) {
    if(colorcode.split('')[0] === '#') {
        colorcode = colorcode.substring(1);
  }
  if(colorcode.length !== 6) {
    return false;
  }

  var r = parseInt(colorcode.substring(0, 2), 16);
  var g = parseInt(colorcode.substring(2, 4), 16);
  var b = parseInt(colorcode.substring(4, 6), 16);
  var c = color(r, g, b);
    return c;
}

f:id:taiga006:20200208140237j:plain

メモ

  • グラデーションの配色いい感じのものを決めるにあたっていくつか海外のデザインサイトを見たのだが、どれもColorCode形式でまとめられていたのでRGBに変換するメソッドを書いた。(これが型が合わなくて2日ほど放置していたのはここだけの話。)

  • 見る人が見ればわかるけど@takawo先生のTDSW資料を多大に参考にしている。 『グラフィックのための「動かない」クリエイティブコーディング』 f:id:taiga006:20200208140541j:plain ちょうど僕が裏でTouchDesignerのWS講師をやっていたときのやつですね。

  • フォントを好きなやつ使いたいなというのがそもそものモチベだった。手元のttf,otfファイルをロードしようとするとCORS requestうんちゃら...みたいなエラーが出て困ったがローカルサーバを立ててそこで動かしたら問題なくローカルのファイルにアクセスできた。(参考issue

  • ちなみに上のソースコードはNEORTに上げるようにGoogle Fontに入っているさわらび明朝フォントを使っています。

<link href="https://fonts.googleapis.com/css?family=Sawarabi+Mincho" rel="stylesheet">

の追加をお忘れなく。

blog.creative-plus.net

ナカジさんの記事出てきた。

一言

var let const の違いまだわかってない。

【週刊p5js】work01

function setup() {
  createCanvas(windowWidth, windowHeight);
  pixelDensity(2);
  frameRate(1);
  // noLoop(); // mousePressed用
}

let ColorPattern = [
  ['#493548','#FFC145','#FF6B6C','#5B5F97','#4B4E6D'],
  ['#FFC145','#FF6B6C','#5B5F97','#4B4E6D','#493548'],
  ['#FF6B6C','#5B5F97','#4B4E6D','#493548','#FFC145'],
  ['#5B5F97','#4B4E6D','#493548','#FFC145','#FF6B6C'],
  ['#4B4E6D','#493548','#FFC145','#FF6B6C','#5B5F97']
];

let g = 7;

function grid(){
  let   w = width / g;
  let   h = height / g;

  // グリッド線
  for (let i = 1; i <= g - 1; i++) {
    stroke(150);
    strokeWeight(1);
    line(w * i, 0, w * i, height);
    line(0, h * i, width, h * i);
  }

  // ランダムで白塗り
  for (let i = 0; i < g; i++) {
    let col = int(random(g));
    let row = int(random(g));
    fill(200);
    rect(col * w, row * h, w, h);
  }
}

function grain() {
  for (let i = 0; i < 100000; i++) {
    fill(255, 30);
    circle(random(width), random(height), 2);
  }
}
 
function draw() {
  resizeCanvas(windowWidth, windowHeight);

  let l = ColorPattern.length;
  let p = int(random(l));

  colorP = ColorPattern[p];

  let ll = colorP.length;

  bgColor = colorP[0];
  background(bgColor);

  grid();

  for (let i = 0; i < 85; i++) {
    if (i < 15 || i % 2 == 0){
      continue;
    }

    let Cd = colorP[int(random(ll))];
    while (Cd == bgColor) {
      Cd = colorP[int(random(ll))];
    }
    r = i * 2;

    noStroke();
    
    // 外側の円
    fill(Cd);
    x = random(width);
    y = random(height);
    ellipse(x, y, r);

    // 内側の円2
    fill(bgColor);
    x_diff = x + random(-5,5);
    y_diff = y + random(-5,5);
    ellipse(x_diff, y_diff, r*0.6);
  }

  for(let i = 0; i < 20000; i++) {
    ellipse(random(width), random(height), random(0.75));
  }
}

function mousePressed() {
  redraw();
}

f:id:taiga006:20200202192222j:plain

【Unity】アプリからSNSへのシェア機能をつくる.

f:id:taiga006:20200130173247p:plain:w300

SNSシェア機能と仰々しく書きましたが、つまりはShare Extensionを表示させる方法です。 (ちなみにShare Extensionという用語はAndroid /iOSで共通なんでしょうか?まあどちらにせよ意味は通じると思いますが。)

ググってみるといくつか方法が出てきますが、今回はanchan828さんが公開しているSocical ConnectorをベースにTHE・車輪の再開発をしていきます。(プラグインをそのまま使う方法は他のサイトをご覧ください。)

シェア機能の本体となるスクリプトは以下のようになります。 パット見で分かる通りAndroidはUnityの機能のみで実装ができますが、iOSに関してはネイティブプラグインとして別途実装する必要があります。(後述)

using UnityEngine;

#if UNITY_IPHONE
using System.Runtime.InteropServices;
#endif

    public class SocialShare
    {
    public static void Share (string text, string url) {
#if UNITY_IPHONE
        _ShareiOS(text, url);
#elif UNITY_ANDROID
        _ShareAndroid(text, url);
#endif
    }

#if UNITY_IPHONE
        [DllImport ("__Internal")]
        private static extern void Social_Share (string text, string url);
        
        private static void _ShareiOS(string text, string url) {
            Social_Share(text, url);
        }
#elif UNITY_ANDROID
        private static void _ShareAndroid(string text, string url)
        {
            var clazz = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
            var activity = clazz.GetStatic<AndroidJavaObject> ("currentActivity");

            var intent = new AndroidJavaObject("android.content.Intent");
            intent.Call<AndroidJavaObject>("setAction", "android.intent.action.SEND");
            intent.Call<AndroidJavaObject>("setType", "text/plain");

            if (!string.IsNullOrEmpty(url))
                text += "\t" + url;

            if (!string.IsNullOrEmpty(text))
                intent.Call<AndroidJavaObject>("putExtra", "android.intent.extra.TEXT", text);

            var chooser = intent.CallStatic<AndroidJavaObject>("createChooser", intent, "");
            chooser.Call<AndroidJavaObject>("putExtra", "android.intent.extra.EXTRA_INITIAL_INTENTS", intent);
            activity.Call("startActivity", chooser);
        }
#endif
    }

今回はスクショは投稿しない形で実装したかったのでSocial Connectorからその部分の実装を削って、少し読みやすく整理しています。

ちなみに、スクショ付き機能が入るとAppleだと認証周りをいろいろ調整しないといけないのでちょっと話がややこしくなります。このあたりです。

最初にも書いたようにAndroidに関してはUnityからネイティブのメソッドを直接コールすることが可能です。

https://docs.unity3d.com/jp/460/Manual/PluginsForAndroid.html

そしてiOSプラグインの実装です。Asset下に適当なフォルダを作って(Pluginsとか)以下をSocialShare.mmという名前で保存します。

extern "C" {
    void Social_Share(const char *text, const char *url) {
        // MSStringに変換
        NSString *_text = [NSString stringWithUTF8String:text];
        NSString *_url  = [NSString stringWithUTF8String:url];
        
        NSArray *content = [NSArray arrayWithObjects:_text,_url,nil];

        UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:content applicationActivities:nil];
        [UnityGetGLViewController() presentViewController:activityView animated:YES completion:nil];
    }
}

Obj-C側で定義したのと同名の関数をC#側で static extern で定義させます。 C#のほうでそのメソッドを呼ぶと、プラグイン側のObj-Cの関数が呼ばれる。

Obj-Cのことがちんぷんかんぷんだったので、少しつまづきました。 (具体的にはarrayWithObjectsの最後にnilが必要だということがわかっておらず、ビルド後に無言クラッシュを食らってしまいしばし立ち往生しました。)

ここまで理解できたら、あとはシェアボタンなどから最初のスクリプトのメソッドを呼び出すようにすれば実装は完了です。お疲れさまでした。

    public void OnClickShareButton()
    {
        string shareText = "テストテストテスト";
        string shareUrl = "https://twitter.com/dn0t_";

        SocialShare.Share(shareText, shareUrl);
    }

f:id:taiga006:20200130173450j:plain:w300

さらにこれを応用させることで「Lv.100ステージクリア!!」「5000PT獲得!!」などのゲームない情報を気軽にユーザがシェアできるようになります。

今回はすでに広く使われているUnityプラグインを手元で再実装することで理解を深めるよい機会になりました。

参考

https://github.com/anchan828/social-connector

https://qiita.com/tkyaji/items/74d485a021c75ed10bca

【Unity】スクリプトからフラクタルな造形。

f:id:taiga006:20200126221703p:plain

f:id:taiga006:20200126221706p:plain

※動きます。

f:id:taiga006:20200126204539g:plain

Inspectorの様子

f:id:taiga006:20200126185649p:plain

メモ

child = new GameObject("Fractal Child").AddComponent<Fractal>();

再帰させたいだけなのでただのGameObjectを作成してこのコンポーネント自体をアタッチしている。

            float t = i / (maxDepth - 1f);
            t *= t;
            ......
            mats[i, 0].color = Color.Lerp(Color.white, Color.green, t);

Color.Lerpを使うと、例えばColor.Lerp(a,b,t)でt(0~1)に対してa~bで線形補間ができる。今回でいうと深度が深くなるにつれて色がはっきりとつくようになっている。

transform.localPosition = direction * (.5f * (1 + childScale));

ややわかりにくいが1というのは今見ているスケールに対応し、それにchildScale分を加えている。そうすることによって子オブジェクトが親億ジェクトにくっついているように見える。

参考

ja.wikipedia.org catlikecoding.com

【Unity】スクリプトからプロシージャルにTerrainもどき。

f:id:taiga006:20200125193650g:plain

こちらの続きです。

Meshを無数に生成しそこにPerlinNoiseをかけることで地形っぽい形状を作り出します。

この部分がキモ。
というか、なるほどー、となった。
「1つの四角 = 2つの三角 = 6つの頂点」

                // 1つ目の三角
                triangles[tris + 0] = vert + 0;
                triangles[tris + 1] = vert + xSize + 1;
                triangles[tris + 2] = vert + 1;
                // 2つ目の三角
                triangles[tris + 3] = vert + 1;
                triangles[tris + 4] = vert + xSize + 1;
                triangles[tris + 5] = vert + xSize + 2;

f:id:taiga006:20200125195443p:plain それからその下のこの部分。
試しに外して動かすとわかるけど、要はその行の最後の頂点と、次の行の最初の頂点はこのアルゴリズムでは同一視されるので、ずらしてあげないとライティングでバグる。

            // 次の行の最初の点をその行の起点とするための操作
            vert++;

参考

www.youtube.com

catlikecoding.com

taiga.hatenadiary.com

【Unity】スクリプトからMeshを描画する。

f:id:taiga006:20200124002517g:plain

特に面白みはないけどスクリプトから動的にMeshを描画することができたので今日は満足。

というかVEXでおんなじようなこと書いたなぁ。

参考

www.youtube.com

【Unity】スクリプトからマテリアルの色(Properties)を変更する

f:id:taiga006:20200122220633g:plain

さきに使ったスクリプト貼っとく。

gist.github.com

学んだこと

スクリプトからプロパティへのアクセス

    id = Shader.PropertyToID("_Color");
    ...
    mat.SetColor(id, Cd);

シェーダーのプロパティへは SetXXX みたいなメソッドでアクセスができるっぽいのだが、この第一引数はstringでも良いらしい。 つまり、mat.SetColor("_Color", Cd); でも問題はない。 ただし、内部的にはidを調べて使っているようなので int id を引数にしたほうが圧倒的に速いとか。

②Remapメソッド

    public static class MathExtensiton
    {
        public static float Remap(this float value, float from1, float to1, float from2, float to2)
        {
            return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
        }
    }

タイトルと直接関係ないけど、Remapのような便利関数はてっきり標準のメソッドとしてあるのかと思ったらない。ということでググった結果、上のような関数があったので拾ってきた。ところで、こういった拡張メソッドにはC#的な書き方があるらしく、最初それをわかっていなかったのでちょっと躓いた。このあたりはまた再度勉強する。

そうそう、Inspectorは普通にこんな感じ。 f:id:taiga006:20200122225121p:plain

③プロパティブロック

 Properties
    {
        _Color("Color", Color) = (1, 1, 1, 1)
    }

ColorはShaderlab側が用意した型の1つでCGPROGRAM内ではfixed4に対応している。 最初、試しにrgbとalphaで別のプロパティとして書こうと思ったのだが、Vectorという型がありはするものの、中身はこちらもfixed4にしか対応していなかった。まあ、不便は特になさそう?

④タグブロック

     Tags {
            "RenderType" = "Transparent"
            "Queue" = "Transparent"
         }

Tag構文についてはあんまり書かない(理解してない)が、Queueタグが描画順を管理する役目で、1000~4000くらいの値で使われる。(もっと大小のある数値が使えるのかは未知。) RenderTypeタグはもっとよくわからないが、基本的に最初のうちは

 Opaque = 不透明
 Transparent = 透明

を使い分ければ良さそう。ちなみにOpaqueはおぱきゅーって読む(読まない)。

⑤Blendブロック

     Blend SrcAlpha OneMinusSrcAlpha

重なった色の合成法について決める構文。これもググったら種類が多い。 SrcColor * SrcFactor + DstColor * DstFactor みたいな公式が出てきた。

SrcColor = Fragment Shaderの算出した色
DstColor = すでにそこに描画されている色

を意味していて、Blend SrcFactor DstFactor という宣言になっているようだ。今回の Blend SrcAlpha OneMinusSrcAlpha が一番基本となる合成方法らしい。面白い、この辺の比較はまた今度やってみる。(やってみたいことがどんどん増えるなぁ。)

一番最初のGIF、録ったとき透過のこと忘れてたので、最後に。

f:id:taiga006:20200122224139g:plain

参考記事

www.shibuya24.info

ja.stackoverflow.com

tsubakit1.hateblo.jp

docs.unity3d.com

q7z.hatenablog.com

際限ない再現性。

昨夜の飲み会は、お別れ会と言うには彼女自身はあっけからんとしていて、お疲れさま会というには彼自身はのんきだった。

僕は途中から、(そう年末から借りっぱなしだった社食の鍵を返すだけの目的で)顔を出したのだがすっかり終電まで飲んでしまった。

焦げて鉄板の隅に追いやられたホルモンと萎びたオイキムチをつつきながらみんなの話を聞いていると、一人また一人と涙を流し始め、なんだか可笑しかった。

可笑しいね、なんて言いながらみんなで何度も乾杯した。

みんながみんなを褒めて、褒め散らかして勝手に泣いて勝手に笑った。

ああいう夜は良い。

ああいう涙は素敵だ。

オーダーミスでテーブルに届いた卵スープがうまかった。

....

昼過ぎに起きて、「そうだ」と思って気まぐれで(とはいえ期間中には必ず行こうと思っていた)「心ある機械たち again」をBankARTに見に行った。

知らなかったが"again"という名前のように2008年に開催された「心ある機械たち」の続編に当たるようである。

たまたまSNSで見かけて面白そうと思っていったけれど、良かった。

ただ相変わらず、みなとみらい線ユーザ以外にとってBankART Stationはアクセスの悪い場所である…。

以下、Tweetで。

■『回転する3頭のシカ』(中央)

■『回る時計・回らない秒針』

■『ソファーの足を回る電球』

■『まっすぐなキュウリたちの午後』

■『全自動土下座珈琲』

■『ベアリング・グロッケンⅡ』

生活に役に立たない、その利便性の無さに、相手は機械でありながら愛おしさを感じてしまう。

入場料600円は安い。

今日この人すごいなと思った作品の作者、小林 椋さんが年齢1個上としってびっくりした。

...

帰り道、久しぶりにみなとみらいの方を歩いたら見覚えのない建物がたくさん立っていた。そびえ立つタワマン(になるだろう建造物)は桜木町からアクセスも良さそうだ。最上階から見える景色は優雅で、そして窮屈だろうなあなんてことを考えながら大さん橋まで歩いた。

参考

bijutsutecho.com

pocopuu.net