モザイクフィルタを作ってみたところ不可解な境界線が現れてしまいました
画像をモザイクにしようと思ってこんなシェーダーを作成していました
uniform sampler2D tex; void main() { vec2 uv = floor(texCoord * 30.0) / 30.0; gl_FragColor = texture2D(tex, uv); }
実際に使ってみると↓のような見た目になり、なにやらモザイクのセル間に謎の境界線が...
UVを表示してペイントのスポイトで問題の箇所のUVがおかしくなっていないか確認したが問題は見つかりませんでした
実装はどう考えても問題なかったので、それ以外の要因があると2時間ほど頭を抱えていたところ、原因はミップマップがonになっていたからでした
モザイク処理したことによってセル間で急激にUVが切り替わり、境界線でミップマップレベルが大きくなっていたようです
ミップマップ off後
ミップマップには気を付けましょう
シェーダーで条件分岐は遅いらしいのでベクトル演算に置き換えようとしてできなかった話
一般的にシェーダーでの条件分岐は遅いという話がある
今回作ったシェーダーではブレンドモードや使用するマスクのチャンネルをアプリから送信してシェーダー内で利用するということをした
これを条件分岐を使って素直に実装するとこんな感じになる(空で書いたので動くか不明)
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; }
これの mode
や use_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); }
これで高速化できただろう!と思ってましたが、結局最初に書いたifのパターンの方がパフォーマンスが出てました。
こちらのリンク先のとおりであれば、実行中に実際に分岐されない場合ではifの方がパフォーマンスがでるんじゃないかと思いました。(未検証)
But on modern GPUs, they don't cause a performance issue unless they actually do diverge at runtime.
またピクセル毎に分岐するような場合はDivergent分岐と呼ばれるらしくて、こういう時にifのパフォーマンスが悪くなるらしい(uvで偶数奇数を分岐するなど)
ただし、この場合でも算術演算によるブランチングがifと比べて速くなるかは検証していないので不明...
(想像の話しかしてないのでアセンブリ読んでみたいけどどこから参照すればいいのかわからない...)
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というgolangのopenglラッパーを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
帰宅後一通りフィルムを貼ったりセットアップをした
このフィルムを購入したが、ベゼル部分までフィルムの幅があるので端の方に空気が入らざるを得ない感じで少し残念だった
本体は片手で持てるぐらい軽いのでとても満足している
スペックのよさげなPCが手に入ったので3D系で何かやりたいな
ボクセルコーントレーシングの2bounce以上について考えていた
今日はボクセルコーントレーシングで2Bounce以上はどうやって実現するんだろうと考えてました
unityで有名なこちらのアセットを30分ほど眺めてみたところ、どうやらフィードバックループによって実現しているみたいでした
フレーム間で交互にボクセライズとバウンスをしてる箇所
ボクセライズ時に過去のバウンスボリュームを合成している箇所
深く追っていないのでよくわからないのが、カメラを急激に動かした際のポッピングはどう対応しているのだろうか?
今のところ対応箇所を見つけれていない
フィードバックの係数を指定できるようになっているのでそちらで調節する感じなのか??
golangとGmail APIで大量の未読メールを既読にする
きっかけ
メールを3年ぶりに整理しようとしたところ、未読メールが20万件ほど溜まっていたので適当に検索して出てきた未読メールの一括既読を試してみたのですが、どうも件数が多すぎてエラーを吐かれているらしい
ブラウザから一括既読する方法についての記事
発生したエラー
上記の方法でも100件ずつすれば問題ないのですが2000回も反復作業はできないので、gmailのAPIを利用して分割して既読にすることにしました
今回作成したコードはこちら
動作環境
~$ go version go version go1.8.3 linux/amd64
OAuth認証
googleのAPIにアクセスするためには認証をしないといけないのでこちらのクイックスタートを見て認証を終えた(認証部分やアクセストークンの保存等の実装は丸まる拝借した)
https://developers.google.com/gmail/api/quickstart/go
後はマニュアルを見つつ、既読にするコードに変更していく
未読メールを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件既読にする
メールの状態を変更するメソッドは Modify
と BatchModify
があるが、今回は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件ずつ既読にしているので結構時間がかかりますが一日寝かせてみます