shader
GPU上で描画処理のために実行されるプログラム
実用的な応用:反射モデル
ベクタ表現:図形の頂点の座標変換をする頂点シェーダー
ラスタ表現:ピクセルに色をつけるpixel shader
全体の流れ
https://gyazo.com/18a5be15bfdc9e0db2ae021a6e83fbf7
コンピュータグラフィックス 改訂新版 p.55
学習リソース
shaderを学ぶ
from いやというほどわかる低水準3Dグラフィックス Direct3D12 p.10ぐらい〜
映像業界のレンダラ(例 RenderMan)で使われるアーティスト向けの機能
PCのGPUでは固定パイプラインを拡張する目的でリアルタイムシェーダーが利用されるようになり、頂点変換とピクセル色の決定がプログラマブルになった(制限はある。あくまでフィルタのような働き)
本書ではシェーダーとはリアルタイムシェーダーのこと
こういうシェーダーが高級言語でかけるようになったのはDirectX 9.0から
基素.iconMMDはDirectX 9.0
シェーダーの種類はパイプラインのどこを置き換えるかにって分類
頂点シェーダー
pixel shader
など
プログラマから見た描画
1. グラフィクスライブラリを通じて、バッファに以下の情報を与える
必要な情報
頂点列
属性
シェーダー本体
シェーダーへの定数パラメータ
Direct3DでいうConstantBuffer
OpenGLでいうUniform
2. ドローコールを呼ぶ
パイプラインのなかでシェーダーによって頂点列が処理される
実際には多数のシェーダーインスタンスが並列動作する
最も初歩的で多様なプラットフォームで動作するShaderModel 1.0の場合を例に
頂点シェーダーは
最もパイプラインの浅い所に位置
アプリケーションからライブラリを通して入力された頂点について動作
1頂点を1スレッドが処理
1スレッドに対応する頂点の属性がわたる
頂点シェーダーのできること
アプリケーションから渡した定数パラメータを読む
定数は書き換え不可
変換済みの頂点ベクトルと、頂点属性をパイプライン後段に出力
一つのポリゴンの頂点が全てrasterizerに入力されると
ラスタライザはポリゴンをピクセルに分割する
するとビューポート上でのピクセル位置がわかる
位置に応じて、頂点シェーダからの入力のうち頂点座標以外の他の値も補間してピクセルシェーダの入力とする
実例
頂点シェーダがラスタライザに直線を渡してきたとする
(1, 1), k=100
(-1, -1), k=0
するとラスタライザは中間のピクセルを(0, 0) k=50と補間してpixel shaderを呼び出す
pixel shaderは
ラスタライズされたピクセルに対して動作
1ピクセルを1スレッドが処理
1スレッドには頂点シェーダーの出力のうち、rasterizerが補間した値が入る
ピクセルシェーダのできること
アプリケーションから渡した定数パラメータ(変更不可)を読む
テクスチャを読む
1つのプログラムからは(概ね)1カラー値を出力
RGBAのカラーを表すベクトル1つ
位置の変更不可
リアルタイムシェーダはプログラマブルとは言っても意外と制約が大きい
ハードウェアパイプラインに割り込む形で実行するため
頂点シェーダー、ラスタライザ、ピクセルシェーダーはそれぞれ用途の決められた専用のレジスタに接続されていると考えよ
ストリーミング可能なパラメータはレジスタによって制限がある
構造上CPUのスレッドのようにはできない
シェーダのスレッドはパイプライン中にシェーダーやラスタライザを通じてストリーミング動作する
しかし、定数パラメータはシェーダのバイナリにコードと一緒にリンクされまとめてそれぞれの演算器にアップロードされて終わったら消える
もし定数パラメータをを書き換えられたとしても、他のスレッドからは値が読めない
もし書き換えた定数パラメータを他のスレッドから読めたとしても、シェーダは並列動作するのでその値を同期できない
Q. 制限を外す方法は?
A. パラメタライズドテクスチャを使う
事前計算した値をテクスチャに入れ、ピクセルシェーダで読む
Q. もっとド派手にグニャ〜っとしたりメラメラしたりしたいのですが
A. アプリケーション全体でのサポートが必要
アプリケーションからシェーダの出力をさらにテクスチャとして使うMulti Pass Renderingがメジャー
ピクセルシェーダから複数の値が出力できるようになった(Multi Render Target)を使えばShader Modelによっては出力カラーのレジスタを拡張して複数のカラー値を異なるレンダーターゲットに出力する
こうした技術を組み合わせて高度な反射モデルやエフェクトを作る
Q. 頂点シェーダは行列演算をするだけでは?
そう。よくある処理をソフトで提供し、ハードウェアの固定パイプライン処理を大幅に削減する
これらもする
反射モデルの実装のためにハーフベクトルの計算
ボーンスキニングの計算
なので書き換えることはほぼない
table:まとめ
できること できないこと
頂点シェーダ 頂点の変換 定数パラメータの変更
ピクセルシェーダー ポリゴン内のピクセルのRGBAの決定 定数パラメータの変更
テクスチャから任意の位置の値を読む
https://learning.unity3d.jp/2042/
https://youtu.be/wUx_Y9BgC7k
シェーダを理解しよう 安原 祐二
シェーダプログラムに興味がある、でもどこから始めたらいいのかわからない・・そんな方に、始めの一歩を踏み出してもらうための基礎をお伝えします。また、応用例をベースに、GPUの仕組みについてもお話しします
https://gyazo.com/53f24f631386a390aad8b87277acd217
設定変更可の部分はプログラマブルではなく、厳密にはシェーダーではない
描画とは画素に色付きのdotを打つことを8ステップに分解
step 1
頂点と三角形の情報を準備
頂点ごとに
座標
法線ベクトル
UV(テクスチャ)の座標
三角点列
step 2
transformの値をモデル行列を作って描画エンジンに渡す
step 3
カメラの位置から見たとき、どの座標のpixelを描画するか確定させる
これを使って計算する
step1のモデルの頂点情報
step2のモデル行列
カメラ行列
頂点シェーダーを書く=step 3を実行する
step 4 処理現象の工夫
面には裏表を定義できる(右回りか左回りか)。裏表を判定する。裏なら描画しない
shader#629f7a7e774b170000f6bd41を使う
step 5
描画するべき面(点の集合)を確定する。頂点を繋いだ中の点を描画することにする
GPUの仕事
step 6 処理減少の工夫
step5で決めた描画点を、深度バッファと比較して、手前に描画済みの点があるかを判定する
手前に描画済みの点があるなら描画するだけ時間の無駄
step 7 pixelの色を確定させる
テクスチャ、ライティング、他の物体のシャドウが落ちるか、フォグ
pixel shaderの役割
step 8 pixelをうつ
ブレンド関数を指定(アルファの指定ができる)
深度バッファを更新
シェーダーでできないこと
線を引きたい
https://gyazo.com/3e82405b5d4c35ff647b83a5028fbfb6
三角形じゃないのでstep1で対応が必要
半透明の描画がしたい
半透明とは
すでにかいてある後ろの色を拾ってきて
ピクセルシェーダの出力とblendする
つまりstep8でやる
シェーダのBlend関数はプログラマブルではない
不透明を半透明の跡に描画するのは難しい
https://gyazo.com/be64ccf77d436e23bdf4ada91699fbda
最小のシェーダー
Unityのシェーダーも普通のシェーダーも青い部分は一緒
https://gyazo.com/5f69bb64f9be28226b953107d9b02a87
セマンティクス
https://gyazo.com/cfda6e8de895afb0122146794d172115
これがないとGPUはこの値がなんなのかわからない
補完
頂点シェーダはuvを返す
フラグメントシェーダでuvを使ってテクセルをフラグメントシェーダで反映するひろう
実際にはこのuvはGPUが補完した値
頂点シェーダは頂点しか実行していない。その座標を渡しても頂点の間は描画できない
https://gyazo.com/7b2d1c971d69b1253114a328a80de052
Surface shader
シェーダの記述を楽にするもの
解決する課題
頂点シェーダーはどんなシェーダーでも大体同じものをかく
ピクセルシェーダーは、大抵複雑になる
しかしいつも同じ定型句がある
影が落ちる
陰影をつける
フォグをかける
https://gyazo.com/2437fec350f807f25198fb43591999da
いきなりSurface shaderを見てもわからないかも
ピクセルシェーダがMip mapで適切なサイズの画像を選択する仕組み