シェーダーで条件分岐は遅いらしいのでベクトル演算に置き換える(追記あり)

一般的にシェーダーでの条件分岐は遅いという話がある

今回作ったシェーダーではブレンドモードや使用するマスクのチャンネルをアプリから送信してシェーダー内で利用するということをした

これを条件分岐を使って素直に実装するとこんな感じになる(空で書いたので動くか不明)

fixed3 blendColor(fixed3 src, fixed4 dest, float blend, int mode) {
    float alpha = dest.a * blend;
    fixed3 blended_dest = dest.rgb * alpha;
    if (mode == 0) {
        return lerp(src, dest, alpha);
    } else if (mode == 1) {
        return src + blended_dest;
    } else if (mode == 2) {
        return src - blended_dest;
    } else if (mode == 3) {
        return src * blended_dest;
    }
    return src;
}

fixed useMask(fixed4 mask, int use_mask_number) {
    if (use_mask_number == 0) {
        return 1.0 - mask.r;
    } else if (use_mask_number == 1) {
        return 1.0 - mask.g;
    } else if (use_mask_number == 2) {
        return 1.0 - mask.b;
    } else if (use_mask_number == 3) {
        return 1.0 - mask.a;
    }
    return 0.0;
}

これの modeuse_mask_number を使用したいチャンネルが1.0のベクトルで渡すことで、if文を行列とベクトル演算に置き換えることができる

fixed3 blendColor(fixed3 src, fixed4 dest, float blend, float4 mode) {
    float alpha = dest.a * blend;
    fixed3 blended_dest = dest.rgb * alpha;
    // GLESでは非正方行列が使用できないので使わないところは0で埋める
    return mul(mode, fixed4x4(lerp(src, dest, alpha), 0,
                                src + blended_dest, 0,
                                src - blended_dest, 0,
                                src * blended_dest, 0)).rgb;
}

fixed useMask(fixed4 mask, float4 use_mask_vector) {
    return 1.0 - dot(mask, use_mask_vector);
}

本当に早くなっているかわからないけど、条件分岐は遅いという話を信じてベクトル演算の方を使用している

※5/24追記 シェーダーをアタッチしたオブジェクトを処理落ちするだけ複製してから、ifバージョンと上記の行列バージョンで比較してみたところ

ifバージョン: 16fps

matrixバージョン: 12fps

でifバージョンのほうが高速でした、遅いとは言ってもすべての計算をしてから行列演算をするよりかは速いようです...

書き方の違いはあれどglslでもhlslでも利用できるが、制限として4次元までしかこの方法は使用できない(float5やvec5なんてないよね?ないはず)

Unityのマテリアルエディタ拡張でテクスチャのプロパティを表示する

最近Unityを触っていてマテリアルエディタを拡張したくなったのでテクスチャのプロパティを表示するところから始めてみた

最初は自前でUIを組み立ててどうやらするのかと思ってその方面で調べていたけど、標準のテクスチャプロパティのスタイルであれば TextureProperty 関数を呼ぶだけで表示できることが分かったのでそれを使用した

using UnityEngine;
using System.Collections;
using UnityEditor;

public class CardShaderInspector : MaterialEditor
{

    public override void OnInspectorGUI()
    {
        if (!isVisible) { return; }
        MaterialProperty mask1 = GetMaterialProperty(targets, "_Mask1Tex");
        // 第三引数をtrueにするとタイリングとオフセットのUIも表示される
        TextureProperty(mask1, "Mask1", false);
    }
}

ここに行き着くのに二時間もかかってしまった・・

windowsにgccをインストールするメモ

go-glというgolangopenglラッパーをgo getしようとしたところ、cgoを利用しているようでgccが必要という旨が表示されたのでインストールした

MSYS2/MinGW-w64 (64bit/32bit) インストール手順 メモ · GitHub こちらをみて64bitMsys2インストール

pacman -Syuu
pacman -S base-devel
pacman -S mingw-w64-x86_64-toolchain

このコマンドで開発環境インストール 途中のインストールを指定するところはALLにした

C:\msys64\mingw64\bin

上記gcc等開発ツール一式がインストールされるので、こちらを環境変数のPATHに加えた

そのあとgo get -uすれば問題無くインストールできた

XPS15が届いた

2/28に注文して今日届いた www.dell.com

帰宅後一通りフィルムを貼ったりセットアップをした

このフィルムを購入したが、ベゼル部分までフィルムの幅があるので端の方に空気が入らざるを得ない感じで少し残念だった

http://amzn.asia/enuhOYN

本体は片手で持てるぐらい軽いのでとても満足している

スペックのよさげなPCが手に入ったので3D系で何かやりたいな

ボクセルコーントレーシングの2bounce以上について考えていた

今日はボクセルコーントレーシングで2Bounce以上はどうやって実現するんだろうと考えてました

unityで有名なこちらのアセットを30分ほど眺めてみたところ、どうやらフィードバックループによって実現しているみたいでした

github.com

フレーム間で交互にボクセライズとバウンスをしてる箇所

github.com

ボクセライズ時に過去のバウンスボリュームを合成している箇所

github.com

深く追っていないのでよくわからないのが、カメラを急激に動かした際のポッピングはどう対応しているのだろうか?

今のところ対応箇所を見つけれていない

フィードバックの係数を指定できるようになっているのでそちらで調節する感じなのか??

golangとGmail APIで大量の未読メールを既読にする

きっかけ

メールを3年ぶりに整理しようとしたところ、未読メールが20万件ほど溜まっていたので適当に検索して出てきた未読メールの一括既読を試してみたのですが、どうも件数が多すぎてエラーを吐かれているらしい

ブラウザから一括既読する方法についての記事

news.livedoor.com

発生したエラー

f:id:kaneta1011:20180209165943p:plain

上記の方法でも100件ずつすれば問題ないのですが2000回も反復作業はできないので、gmailAPIを利用して分割して既読にすることにしました

今回作成したコードはこちら

github.com

動作環境

~$ go version
go version go1.8.3 linux/amd64

OAuth認証

googleAPIにアクセスするためには認証をしないといけないのでこちらのクイックスタートを見て認証を終えた(認証部分やアクセストークンの保存等の実装は丸まる拝借した)

https://developers.google.com/gmail/api/quickstart/go

後はマニュアルを見つつ、既読にするコードに変更していく

godoc.org

未読メールを100件取得する

メールを取得するメソッドはこちら

https://godoc.org/google.golang.org/api/gmail/v1#UsersMessagesService.List

ただし、上記のメソッドをそのまま利用すると未読既読関係なく最新のメールを100件取得してしまうのでクエリパラメータを加える、それが以下のメソッド

https://godoc.org/google.golang.org/api/gmail/v1#UsersMessagesListCall.Q

上記のメソッドに文字列でブラウザのgmail上で利用できる検索ボックスと同じものを指定して取得するメールを限定できる、今回は未読メールなので is:unread を指定しました

以上を踏まえて、未読100件のメールを取得するコードは以下のようになる

mes, err := srv.Users.Messages.List(user).Q("is:unread").Do()
if err != nil {
    log.Fatalf("Error: %v", err)
}

ちなみに、取得時に件数が0の場合はエラーになる

メールを既読にする

APIのスコープを変更する

未読メールには UNREAD というラベルが設定されているので、そのラベルをメールから削除して既読にする

チュートリアルのサンプルではAPIのスコープがReadOnlyになっているので、スコープを gmail.GmailModifyScope に変更しました

config, err := google.ConfigFromJSON(b, gmail.GmailModifyScope)
if err != nil {
    log.Fatalf("Unable to parse client secret file to config: %v", err)
}

一度に100件既読にする

メールの状態を変更するメソッドは ModifyBatchModify があるが、今回は100件一気に変更したいので BatchModify を利用する

https://godoc.org/google.golang.org/api/gmail/v1#UsersMessagesService.Modify

https://godoc.org/google.golang.org/api/gmail/v1#UsersMessagesService.BatchModify

先程取得した100件のメールからIDのスライスを作成して UNREAD ラベルを削除するリクエストの構造体を作成後に実行すれば未読100件の既読が達成できる

ids := []string{}
for _, e := range mes.Messages {
    fmt.Println(e.Id)
    ids = append(ids, e.Id)
}

request := &gmail.BatchModifyMessagesRequest{
    Ids:             ids,
    AddLabelIds:     []string{},
    RemoveLabelIds:  []string{"UNREAD"},
    ForceSendFields: []string{},
    NullFields:      []string{},
}
err = srv.Users.Messages.BatchModify(user, request).Do()
if err != nil {
    log.Fatalf("Error: %v", err)
}

未読0件になるまで繰り返す

実は100件の未読メールを取得する際に、取得件数が0の場合はエラーを返すようになっているので、上記の流れをループすればOK

3秒毎に100件ずつ既読にしているので結構時間がかかりますが一日寝かせてみます

apacheからnginxに乗り換える2

昨日の続き

php-fpmをインストールする

php5.6を使っているのでremiリポジトリを追加後インストールする

sudo yum install yum --enablerepo=remi-php56,remi,epel install php-fpm

その他は下記記事を参考に設定 qiita.com

/etc/nginx/conf.d/default.conf は最終的にこうなった

server {
    listen       80;
    server_name  localhost;
    root   /var/www/html;

    location / {
        index  index.php index.html index.htm;
    }

    location ~ .php$ {
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /var/www/html;
    }
}

文字化け

デフォルトだとutf-8が文字化けして配信されてしまったので /etc/nginx/nginx.conf のhttpブロックの先頭に↓を追加した

charset UTF-8;