Raspberlyのブログ

Raspberlyのブログ

Unityネタをメインとした技術系ブログです。にゃんこ大戦争や日常なども。そろそろブログタイトル決めたい

勉強会レポ : Unity道場 2月 ~シェーダを書けるプログラマになろう~

勉強会のレポート(メモ)です。
参加したのはこちら、「Unity道場 2月 ~シェーダを書けるプログラマになろう~」

meetup.unity3d.jpハッシュタグ : #Unity道場

 

f:id:Raspberly:20190225233016j:plain

 

 

f:id:Raspberly:20190226000204p:plain

 

 

放送アーカイブはこちらから
このブログ記事だけでなく、動画も視聴することをオススメします。

www.twitch.tv

 

今回のUnity道場の解説記事。

qiita.com

qiita.com

 

 

 

 

 

 

シェーダを書けるプログラマになろう
三部構成にしました。大事なのはpart1、寝ないで聞きましょう。

 

そもそも理解とは

これは境界の把握だとぼくは思っています。
理解するコツは、それができないことはなにかを知ることです。
人に質問すると、「あれができる」「これができるだけ」だけ返ってくる。
それだと境界がぼやっとしてくる、なのでできないことを知らないとだめです。

特徴を抑える話をします


part1 シェーダを理解しよう

今回は8つのステップに分けて説明します。

f:id:Raspberly:20190226000531p:plain



〇〇シェーダはたくさんありますが、今回は頂点シェーダとフラグメントシェーダについて。
シェーダというのはこの2つから始まっていて、シェーダの中心となるため。

描画とは

 モニタ上の画素に点を打つこと。これを8ステップで行います。

 

ステップ1

3Dモデルの準備、これは絶対必要。
3Dモデルとは、どの頂点を結んで面にするのかという三角形の情報。
これを準備します

ステップ2

transformの値を4x4行列に変換します、この行列モデル行列といいます。
結構複雑ですが、一番下は[0001]固定です。

ステップ3

描画位置を決定する。
どの辺に頂点がいくか計算する。

ステップ4

3頂点の処理をしたら右回りか左回りか確定する。
そしてどっちが裏か表か決める。裏なら描画しない。
逆にいうと裏側でもステップ4までくるということです。

ステップ5

描画の点を確定する。
3頂点をつないだ三角形の内側の画素を調べるて確定する。

ステップ6

描画すると決まった時、デプスバッファと比較して既に書いた点より後ろにあるかを調べる。
後ろにあるなら描画しない。

ステップ7

打つべき色を確定する。
テクスチャや影、他からの影やフォグなどを考慮する。

ステップ8

点を打つ。ブレンド関数が使える。
ここでデプスバッファを更新する。

 

このうち、上の2つのステップをCPU、他をGPUが担当しています。
ステップ3が頂点シェーダ、ステップ7がフラグメントシェーダの仕事になります。

 

 

一発では覚えられないのでぜひ復習してください。


シェーダでできない例

2点間で線を引きたい

これはステップ1の話になるのでできない。シェーダーではできない。

半透明描画をしたい

これはステップ8で対応するもの。
そもそも半透明とは、すでに書いてある点と書こうとしている点を足して割らないとできないこと。
シェーダーで何かする話ではない。
blend関数で設定可能だが、これは設定を書いているだけで厳密にはシェーダーではない。

余談

半透明とデプスバッファの問題

不透明を半透明の後に描画するのは難しい。
透明度のデプスバッファが更新されるため、奥に書かれ半透明にならない。
かといって更新しないと、半透明の部分より手前に来てしまう。
現在は半透明は不透明のあとに描画するようにどのゲームエンジンもやっています。


シェーダを観察していこう

頂点シェーダは大体vert、フラグメントシェーダはfragになります。
Unityと普通のシェーダーと何が違うのかというと、どのゲームエンジンでも共通の部分があります。
Unityでは、コードの上の方にいろいろ書けて楽になっている。

重要ポイント

セマンティクス

POSITIONなどのマーキングはセマンティクスとよばれるものです。
これはGPUにこの変数はポジションである情報を伝える。
これがないとGPUは動きようがなくなる、

補完

二つの線分の途中の値を計算し選出すること。これはGPUがすごい頑張る。
頂点シェーダは3つしか出力されていないので、その補完を行います。


サーフェスシェーダーとは

頂点シェーダとフラグメントシェーダがないと絵がでない。
頂点シェーダは大体同じようなことを書くため省略したくなる。
フラグメントシェーダは複雑なわりにいつも同じような書き方になる。
そのため、楽な記述で生成してくれるのがサーフェイスシェーダです。
これはUnity専用の機能。

ただしサーフェスをいきなり見るとなにがなんだがわからなくなる。
頂点シェーダとフラグメントシェーダを生成しているものと覚えておきましょう。

設定を変えれるのとプログラマブルは違うということを理解しましょう

 

 

 

 

 


part2 GPUの神秘

tex2Dという関数があります。
これはけっこうおもしろい関数でここにシェーダーの神秘があります。

テクスチャ・画像は縮小に課題がある

拡大はただボケるだけだが縮小は難しい。
縮小するアルゴリズムはいろいろあるが、時間をかけるときれいに縮小できる。

シェーダーでそれをやるのは厳しい。
tex2Dはテクセルを拾ってくることしかできないので、どうしてもだめな縮小になってしまう。

 

無限平面を作る話

地面が書きたい時。どういう風に書いていくか。
必ずカメラに入るように拡大して行う。

テクスチャ座標は大きさにかかわらず01で表現される。
では01をオーバーしたら何が返ってくるのか。
実は折り返された値が返ってくる、つまり繰り返される。


この辺はテクスチャのインポート設定で自動的にrepeatするようになっている。
なのでuv座標にワールド座標など大きな値を入れると繰り返される。

ここで疑問、遠くのものがきれいに縮小されている理由

これはmipmapのおかげです。これは勝手に生成されます。(インポート時の設定)
高品質な縮小画面をあらかじめ作っておきます(ランタイムではなくインポート時に作られる)

 

ここでまた疑問
フラグメントシェーダはtex2Dを呼んでいるだけ、じゃあどうやって最適なmipmapを選択しているのか。
これはちょっと頭に浮かべておいてください。


それはさておき、テクスチャの繰り返しが気になる

整然とテクスチャが繰り返されているのはありえない、不自然すぎてつらい。

なので工夫してみよう
単位範囲ごとにuv座標をずらしてしまう、これを乱数のような概念(ハッシュ)でずらしていく。

地面にはるテクスチャは繰り返される用に作られているが、バラバラにしても意外と大丈夫だった。
これはテクスチャによる。

ただし、これをやるとちらつきが発生する。
なぜちらつくのか、それは間違ったmipmapを引いてきてしまうため。


衝撃の事実

フラグメントは4ピクセル同時に実行している。
必ず4x4で実行するため、シェーダーの同時実行は一歩ずつ完全に同期して行われる。
tex2Dは隣の値も取得している

どうやってmipmapを取得しているのか。
これは4つのuvを取得しているので、適切なmipmapがとれる。

 

なのでさっきの問題を解決するにはddx、ddyをとりtex2Dgradを使う。
ddxは横の隣の差(uvの変化値)を取得する。
ddyは縦との差を取得する。


fwidth

絶対値をとって足す関数がシェーダには用意されている。
縁取りなどけっこうおもしろいことができる。

 

類似の話がunity blogでまとめられています。

blogs.unity3d.com

 

GPUを扱うときの心構え

・完全に同期されていることを知る

・if文はなるべく書かない方がよい
 隣がelseの方にいっていたりすると、true/false両方実行されたりする。

 

 

 

 

 

 

 

 


part3数学講座 行列編

上でもリンクを張りましたがここは動画を見てください。

www.twitch.tv

 

前方ベクトルについて話します。シェーダーで使う行列は全体のほんの一部。


行列には逆行列がある、逆行列は大変ということを感覚的に覚えてください。

モデル行列は回転行列、移動行列で成り立つ。
ではどっちが先なのか、実はrotationが先。
回転してから移動する、なので移動結果が回転によらない。

 

 

ホワイトボードを使った授業形式の講演

f:id:Raspberly:20190226015128j:plain

 

 

ディレクショナルライトがないのでスポットライトで絵作りしている様子。

f:id:Raspberly:20190226015223j:plain

ライトが複数あると描画負荷が高い。

f:id:Raspberly:20190226015322j:plain

 

 

 

タイムライン

 

 

 

 

懇親会の様子

 

GINZAのお寿司

f:id:Raspberly:20190226020050j:plain

徹底的に整列された飲み物達。

f:id:Raspberly:20190226020129j:plain

 突如始まるLookingGlassの展示

f:id:Raspberly:20190226020435j:plain

Unityロゴ付きの提灯、味のあるやさしい明かり。

f:id:Raspberly:20190226020639j:plain

 

 

 

シェーダの基礎から大変わかりやすい内容でした。
(私の中では)シェーダはかなり難しそうな印象で、内部的にどういうプロセスで動いているのかイメージしにくいものでしたが、図と詳しい解説でおおよそ人に説明できるくらいには理解できた気がします。

後は実際に少しずつ書いたり、復習していきましょう。

 

 

間違っている箇所、消してほしいツイートがありましたらコメントにお願いします。

 

 

過去のUnity道場のまとめ

raspberly.hateblo.jp