murnana's diary

のんびり書きます。マサカリまってます(震えながら

勉強会「【はじめてのUnityShader】君の手でキャラクターの見た目を彩ろう!」に行ってきた

supporterzcolab.com

まんてらさんによるUnityシェーダー講座。内容は Unity上でのシェーダーが初心者の方 向けでした。

この記事の趣旨

「講演内容を見直したい」「もうちょっと詳しく知りたい」人向けです。

著者知識も混ぜつつ書きます。あと、分からなかったらマニュアル読めよ という暴力をふるう プログラマなので、ちまちまマニュアルのリンクを貼ります。

判りやすいのと正確さは別の話ですが、正確さに欠けていたら…マサカリください。私も知りたいです。

記事で書くこと

  • Unityでのシェーダーの構造(ShaderLabをざっくりと)
  • 頂点シェーダとフラグメントシェーダーで、モデルを1色に染める方法

記事で書かないこと

前提知識
  • Unityとは
  • Unityの基本的な使い方
  • UnityのHierarchyについて
  • コンピューターグラフィックスで使用される座標変換
そのほか
  • Properties について (次回内容のはずなので書きません)
  • テクスチャの貼り方 (次回内容なので書きません)
  • 開発環境の構築手順
  • 講演内容の再現手順
  • 宣伝

Unityシェーダー事始め

シェーダーは 画面に映像を出力する為の設計図です。本村・クリストファー・純也 さん曰く、料理のレシピに似ている

  • https://cgworld.jp/feature/1607-gtmf2016.html
  • カレーを作る手順は料理のレシピ
  • コンピュータグラフィックを描く手順はシェーダー
    • 正確には シェーダーを交えたレンダーパイプラインがレシピあたると思うがそんな細かいことはおいておこう

Unity の Matreialについて

https://docs.unity3d.com/Manual/class-Material.html

とりあえず、モデルにシェーダーを適用させるために必要なモジュールくらいでOK。

Shaderファイルについて

https://docs.unity3d.com/Manual/SL-Reference.html

Unityのシェーダーは「ShaderLab」言語で書かれています。
https://docs.unity3d.com/Manual/SL-Shader.html

ShaderLabはだいたい以下の形をとります。

Shader "MannteraSample" {
    SubShader {
        Pass {
            CGPROGRAM   // Cg言語で書く
            ENDCG
        }
    }
}
Shader

マテリアルの名前みたいなものです。アッパーキャメルで名前を付けると、大文字部分で区切るみたいです。これスラッシュじゃなかったっけ…? スラッシュで階層区切りができます。大文字区切りなんてないんや

e.g. `ManteraSample/Shader` だと、Materialは「ManteraSample > Shader」で選択可能。

なーんにも書かれていないシェーダーファイルは、「Not supported」から選択できます。

SubShader

https://docs.unity3d.com/Manual/SL-SubShader.html

Pass をまとめている親玉です。

同じシェーダーでもGraphics の設定やデバイスによって分けたい時などに、SubShader を複数作って分けることができます。

Pass

レンダーパイプライン内で実行される、シェーダ-プログラム本体です。 ここに、頂点シェーダーやフラグメントシェーダーを書きます。

Cgで書く - Cg、HLSLとは

まんてらさんはCgって言ってたけど、どっちでもいいっぽいです。
https://docs.unity3d.com/Manual/SL-ShaderPrograms.html

補足:

まじかー 書くならHLSLがよさそうですね。

Pass 内に書かれたマクロ CGPROGRAM ENDCG 内で書ける、シェーダー言語の一種です。

OpenGL には GLSLDirectX には HLSL という言語が使われます。CgNVIDIAが開発したシェーダー言語だそうです(でも古いって聞いたゾ)。

シェーダーに入力する頂点データの宣言

まず、Vertex Shader に頂点データを流し込みます。

頂点データは複数の引数で受け取ることもできますが、長くなりがちなので 構造体 として宣言を行い、1つの構造体を引数として受け取る事が多いです。

今回は以下の形で受け取ります。

struct appdata {
  float4 vertex : POSITION;
};

頂点の座標のみを受け取る構造体です。

float4 は4次元ベクトルであることを表します。 3次元ではない理由は、行列計算の都合があるためです。
(この辺のことは座標変換についての別記事を書く予定です)

POSITION は頂点座標である事を表します。この部分は セマンティクス ( Semantics ) といいます。 セマンティクスは色々ありますが、今回は説明を省きます。

頂点シェーダーからの出力と、フラグメントシェーダーが受け取るデータの宣言

もう一つ、頂点シェーダーが出力し、フラグメントシェーダーが受け取る構造体も宣言します。

正確にはフラグメントシェーダーが受け取るかもしれないデータ、ですが。

struct v2f
{
    float4 pos : SV_POSITION;
};

SV_POSITION は座標変換後の座標が入ります。

シェーダーのエントリーポイントを宣言

一つのシェーダーファイルに2つのシェーダーを収める為、宣言が必要です。

##pragma vertex vert
##pragma fragment frag

公式ドキュメント にある「HLSL snippets」を読むとわかる人は何となくつかめると思います。

##pragma vertex が頂点シェーダーの宣言 (vert がエントリーポイント)、##pragma fragment がフラグメントシェーダーの宣言(frag がエントリーポイント)です。

頂点シェーダー を書く

ここで、座標変換などを行います。

v2f vert(appdata v)
{
  v2f _out = (v2f)0;
  _out.pos = UnityObjectToClipPos(v.vertex);
  return _out;
}

appdatav2f は先ほど宣言した構造体です。

UnityObjectToClipPos 関数は、ざっくりいうと3次元の情報である頂点座標を、2D画面につぶしてくれる関数です。
詳しい話は https://docs.unity3d.com/Manual/SL-BuiltinFunctions.html で、どうぞ。

フラグメントシェーダー を書く

ここで最終的な色を決めます。

float4 frag(v2f _in) : SV_Target
{
  float4 col=(float4)0;
  col=float4(1,1,1,1);
  return col;
}

SV_Target は出力するデータを表すセマンティックスです。

今、これは単色(白色)を出力しています。
col=float4(1,1,1,1) の部分を変えれば色が変わります。


講演はここまででした。
テクスチャ貼ったりするのは次回だそうです。

Windowsの高DPI対応とか、ディスプレイの大きさとかってしんどい

高DPIの設定だと、ディスプレイの正確なピクセル数が取得できない問題。

そもそもDPIとはなんぞ…ということでまとめる

scrapbox.io

ふむふむ、要するに解像度のことか。

高DPI環境の簡易テスト方法

Windowsの設定にある、ディスプレイの解像度とスケールを変えればいい

改善前: SystemParametersInfo 関数を使用していた

SystemParametersInfo を使用して、メインディスプレイの大きさを調べていた。
残念ながらこの関数、何も設定していないと常に 96dpi で計算してしまう…

改善後: SetProcessDPIAware を呼び出す

GetDeviceCapsが常にDPI96を返す問題と解決方法について · GitHub

Windows 7 以降の対応をすれば良いので、遠慮なく呼び出した。 manifestファイルはないので一旦無視。

その他考察

Display Scaling in Windows 10

Microsoftの中の人たちが考えている、高解像度ディスプレイの対応について。

Display Scaling in Windows 10 | Ask the Core Team

細かくは読んでない ><

「Basic concepts and terms」にある画像を見てみると色々書いてある。 (画像だから気軽にGoogle先生できない。つらい)
しれっとpixcel/inchって書いてるのに、なぜか160「DPI」と書かれている。良いのか…?

Physical PixelsEffective Pixels 。ざっくり理解だと

  • Physical Pixels はディスプレイのドットに対して正確なピクセルのこと
  • Effective Pixels はどんなディスプレイ上でも、画面上に表示される大きさは同じ値なら同じ大きさになる

ということらしい。

Vieewing Distanceはとりあえずおいておく。

最後の Scale Factor が、Physical PixelsをEffective Pixelsに変換するための倍率のことのようだ。
Windowsの設定にあるスケールってこれのこと…?だろうか…?

関連するけどまだ読めてない奴ら

まだ読めてない ><
今は読む必要ないかな…と思って…

blogs.windows.com

docs.microsoft.com

UnitTest練習も兼ねてコンソールゲームを作ってみる 2日目

murnana.hatenablog.comの続き

大したことしていない…

コード分析のwarningがうるさいので切る · murnana/windows-console-game@adeb0c3 · GitHub hogeって出しただけ · murnana/windows-console-game@84fe0fc · GitHub

5桁のWarningってなんだと思ったら、コード分析結果でした。

コンソールは WriteConsole 関数 辺りを見ればよさそう。文字出力と色と関数が紹介されていたので。

UnitTest練習も兼ねてコンソールゲームを作ってみる 1日目

github.com

サイト途中放置して始めてしまった。

モチベーション

学生時代、初めて作ったゲームが学校から提供されたライブラリを使用したコンソールゲームでした。

今回はそのライブラリを作る気で進めます。
折角TDDの本読破したので、Visual Studio単体テストを振り回したい。

進捗

プロジェクト作成

Visual Studio Comminity 2017 でプロジェクトを作成。
プロジェクトはとりあえず3部構成。

サンプルプログラム用の単体テストは…とりあえず無視。頭混乱しそうなので。 プロジェクト ファイルを追加します。 · murnana/windows-console-game@f0c8410 · GitHub

プロジェクトの設定

WarningLevelをEnableAllWarningsにしたり、出力先を設定したり。
プロジェクト設定の変更 · murnana/windows-console-game@0f8a47b · GitHub

ビルドすると(予想通り)標準ライブラリからWarningが大量に出てくるので、#pragma warningでそっと閉じる
標準ライブラリでついてくるwarning外し · murnana/windows-console-game@4bbfd80 · GitHub


眠いのでここまで。
描画はコンソールゲーム制作 第1章 描画(4)よりWriteConsoleOutputを使用する予定。
音はまだわからぬ。XAudioくらいしか知らない…

Github Pagesにページを作りたい

Sphinx拡張は諦めました。が、

study-with-〇〇で言語ごとにまとめていたが、あれ?これまとめてホームページですって言い張れば良いのでは?と思い立った次第です。
Sphinx拡張でビルダーをつくりたい 1日目 - murnana's diary

これは諦めていないので、別の方法を考えてみます。
幸い、Node.jsを使ってJavaScriptをこねこねすることは特別勉強しなくてもできるので、そっち方面で考えてみます。

※考えただけで、できたとは一言も言っていない。

ドキュメントどうする問題

今はreStructuredTextで書いています。
これをどうするか。

おそらくこのあたりです。
.jsxでドキュメントを保存しておくのは精神的にもきついものがあるので、理想は.mdで保存し、Reactに読み込ませる…
ってまた変換かー。面倒だなー。

それならいっそコンバートさせたものを使ったほうが良さそうです。
.mdから.jsxなんて夢みたいなもの…

www.npmjs.com

これかな…?
とりあえず保留。

そのほか

力任せにwebpackがいいのか、それともjsファイル分割も考慮するのか(Pixi.jsのようなWebGLもやりたいので)…
SCSSに挑戦するのか…


とりあえずドキュメントなんとかしたい