Help us understand the problem. What is going on with this article?

Unity ShaderLab ノート

Pref.

Unity ShaderLabの個人的備忘録です。

Unity shaderの基本はCg/HLSL
基本的にはこれらを使えば基礎的なものは作れるはず...
間違いがあれば指摘して頂けると幸いです。

とても分かりやすい記事をありがとうございます。
<参考サイト>
http://nn-hokuson.hatenablog.com/

<公式ドキュメント>
https://docs.unity3d.com/ja/current/Manual/SL-SurfaceShaders.html

描画系Shader

レンダリングパイプライン

Input Assembly Vertex Surface Lightning Render Target Output
種類 できること
Vertex Shader 頂点シェーダー ポリゴン頂点を移動
Fragment Shader フラグメント
Surface Shader サーフェスシェーダー ライティングやシャドウを簡単に実装し,低レベルの簡単な絵作りができる

変数の型

説明
float 高精度 浮動小数点値 32bit
複雑な関数などに利用
half 中精度 16bit
-60000 ~ 60000小数点以下約3桁
方向 オブジェクト空間位置に利用
fixed 低精度 11bit
-2.0 ~ 2.0 1/256精度
色情報 単純な制御に利用
説明
float3 x, y, z を含む3Dベクトル
half4 x, y, z, w または r, g, b, a を含む
float4x4 4x4変換行列
正方行列しかサポートしないものがあるので注意が必要

shaderプロパティ

以下のようにプロパティを記述することでUnity Editor上のインスペクタから変数を変更できます.
ココのこと↓
42ewgfqre.PNG

Range

range.PNG

Properties {
    _Value("Value", Range(0, 10)) = 1
}

Float

float.PNG

Properties {
    _Fvalue("Float Value", float) = 1.5
}

Int

int.PNG

Properties {
    _Ivalue("Int Value", int) = 5
}

Bool toggle

bool.PNG

Properties {
    [MaterialToggle] _IsShowGrid ("Is show Grid", int) = 0
}

Color

Screen Shot 2019-05-21 at 14.22.16.png

Properties {
    _Color ("Color", Color) = (1,1,1,1)
}

PowerSlider属性

以下のようにプロパティに属性をつけると以下の場合0.01刻みになる.

Properties {
    [PowerSlider(0.01)] _Strebgth("Strength", Range(0.0, 1.0)) = 0.999
}

基礎的な関数

関数名 説明 GLSL関数
dot dot(x, y) 2ベクトルの内積を求める
floor floor(x) 小数値の整数部分を返す
frac frac(x) 小数値の小数部分を返す fract
abs abs(x) 絶対値を返す
saturate saturate(x) xを0 ~ 1にクランプ
clamp clamp(x, a, b) xをa ~ bにクランプ clamp
lerp lerp(x, y, s) 線形補間 x + s(y - x) mix
sqrt sqrt(x) 平方根 √x
mul mul(x, y) 行列乗算
step step(y, x) y<=xなら1,y>xなら0
min min(x, y) xかyを比べ小さい方を返す
max max(x, y) xかyを比べ大きい方を返す

途中で描画処理を終了する

ディゾルブとかに使えるやつ

関数名
discard

Surface Shader input構造体

型? 入力変数 説明
float2 uv_MainTex テクスチャuv座標
float3 worldPos ワールド座標
float2 screenPos スクリーン座標
float3 viewDir 視線方向

Unity ShaderLab における定義済み値

基本的に変数名の前に_(アンダーバー)が付いている

変数名 説明
_Time float4 (x→y→z→wの順に早くなっていく)
_Time.x 時間 t/20
_Time.y 時間 t
_Time.z 時間 t*2
_Time.w 時間 t*3
変数名 説明
_SinTime float4 時間の正弦 (t/8, t/4, t/2, t)
_CosTime float4 時間の余弦 (t/8, t/4, t/2, t)
unity_DeltaTime float4 デルタ時間: (dt,1/dt,smoothDt,1/smoothDt)

公式ドキュメント
https://docs.unity3d.com/jp/460/Manual/SL-BuiltinValues.html

Surface Shader output構造体

出力変数 説明
fixed3 Albedo 表面の色
fixed3 Normal 法線情報
fixed3 Emission 発光色
half Specular 鏡面情報
fixed Gloss 艶情報
fixed Alpha 透明度

Vertex Shader input構造体

含まれる情報
appdata_base 位置, 法線, 1つのテクスチャ座標
appdata_tan 位置, 接戦, 法線, 1つのテクスチャ座標
appdata_full 位置, 接戦, 法線, 4つのテクスチャ座標

Vertex shaderのセマンティックス

Semantics 説明
POSITION float3, float4 頂点の位置
NORMAL float3 頂点の法線
TEXCOORDn nは0~4 float2, float,3, float4 n番目のUV座標
TANGENT float4 接線
COLOR float4 頂点の色

Vertex shaderの記述例

#pragma surface surf Lambert vertex:vert

:

void vert(inout appdata_full v, out input o){
    UNITY_INITIALIZE_OUTPUT(Input, o);

    //こんな感じに書くとアニメーションができたりもする
    float a = sin(_Time * 100 + v.vertex.x);
    v.vertex.xyz = float3(v.vertex.x + a, v.vertex.y + a, v.vertex.z + a);
    :
}

三項演算子

これを使うことでif文よりも処理が軽く,よりcoolになるらしい(笑
以下の三項演算子では変数colorにxが0.5未満ならfixed3(1, 1, 1)つまり白色が代入され,0.5以上ならばfixed3(0, 0, 0)つまり黒色が代入される.

fixed3 color = (x < 0.5) ? fixed3(1, 1, 1) : fixed3(0, 0, 0);

UnityComputeShader

ComputeShaderとは

CPU側(C#スクリプト)で処理するのに対し,GPU側(ComputeShader)で処理をするときに使うGPU側のプログラム
Shaderと名前はなっているが,描画部分を担っているサーフェスシェーダーとかフラグメントシェーダとは別物.

C#スクリプト側でComputeShaderを定義

ComputeShader型でグローバル変数に定義してあげることで,インスペクタ上でComputeShaderをアタッチ.

[SerializeField] private ComputeShader _computeShader;

グローバル変数上にComputeBuffer型の変数を定義しておく.
これを定義することでComputeShaderのスレッドをComputeBuffer型変数に紐づけて,処理をComputeBuffer型変数で命令させ,最終的にComputeBuffer型変数から結果を取り出す感じ(?)

//グローバル変数として定義
ComputeBuffer testComputeBuffer;

ComputeShaderを書く

例として今回使ったのは以下のComputeShaderファイル「test.compute」

#pragma kernel CSFunction_test

RWStructuredBuffer<int> intBuffer; //ComputeShader上のBuffer領域
int intValue; //C#から値をもらうための変数

[numthreads(6, 1, 1)]
void CSFunction_test (uint3 groupThreadID : SV_GroupThreadID)
{
    intBuffer[groupThreadID.x] = groupThreadID.x * intValue;
}

以下解釈

文章 意味
#pragma kernel CSFunction_test CSFunction_testというカーネルの定義
RWStructuredBuffer intBuffer intBufferという名のC#側に値を戻すときに使うBuffer
int intValue C#側から値をComputeShader側に渡すときに使うint型変数
[numthreads(6, 1, 1)] 属性,カーネルを実行するスレッドの数を定義.意味:6*1*1=6個のthreadを実行する
void CSFunction_test CSFunction_testカーネル.カーネルとはGPUの処理のこと
SV_GroupThreadID セマンティクス:実行しているThreadID
intBuffer[***] = group*** カーネルの処理内容,今回はintBuffer[groupThreadID.x]に自らのThreadID*intValueを代入している

C#からComputeShaderを使う

以下今回使ったC#スクリプトの例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CSTest : MonoBehaviour {

    [SerializeField] private ComputeShader _computeShader;
    int CSFunction_testIndex;
    ComputeBuffer intComputeBuffer;

    // Use this for initialization
    void Start () {
        //カーネルインデックスの保存
        CSFunction_testIndex = _computeShader.FindKernel("CSFunction_test");

        intComputeBuffer = new ComputeBuffer(6, sizeof(int));   //スレッドサイズの保存

        //ComputeShaderにどのカーネルバッファを設定するのか,カーネルバッファの名前の設定
        //C#側で使うComputeBufferの指定
        _computeShader.SetBuffer(CSFunction_testIndex, "intBuffer", intComputeBuffer);

        _computeShader.SetInt("intValue", 1);   //ComputeShaderに値を渡す
        _computeShader.Dispatch(CSFunction_testIndex, 1, 1, 1);  //ComputeShaderの実行

        int[] result = new int[6];  //ComputeShaderの結果受け取り用
        intComputeBuffer.GetData(result);   //結果の取り出し

        for (int i = 0; i < 6; i++) {
            Debug.Log(result[i]);   //結果を出力
        }

        intComputeBuffer.Release(); //バッファの開放
    }
}

実効すると今回はnumThread(6, 1, 1)
intBuffer[groupThreadID.x] = groupThreadID.x * intValue;
を実行しているので,UnityのConsole上に0 ~ 5の6個の結果が出力される.

nmxi
最近は https://www.kemomimi.dev の方に記事書いてます
https://www.kemomimi.dev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした