カーネル
書ける形(44)
Section titled “書ける形(44)”| 書き方 | 説明 |
|---|---|
float v = prev[id].R | ローカル変数 |
v = prev[id].R | 代入 |
v += 0.25f | 複合代入 |
n++ | 増減 |
return new Color4(...) | 戻り値のあるメソッド |
if (v > 0.5f) { ... } | 条件による分岐 |
if (...) { } else { } | 二手の分岐 |
if (id.X == 0) { return ...; } | 途中での復帰 |
for (int i = 0; i < 4; i++) | 回数を決めた繰り返し |
while (i < 4) | 条件による繰り返し |
{ ... } | ブロック |
if (...) { if (...) { } } | 条件の入れ子 |
prev[id] | 自分のセルの読み出し |
c.R c.G c.B c.A | 成分の読み出し |
new Color4(r, g, b, a) | セルの値の生成 |
Color4.White | 定数の色 |
Color4.Black | 定数の色の返却 |
prev[id] + Color4.Black | セルどうしの加算 |
prev[id] - Color4.Black | セルどうしの減算 |
prev[id] * 0.5f | セルの定数倍 |
id.X id.Y | 担当セルの座標 |
prev[id.Offset(1, -1)] | 相対位置のセルの読み出し |
new KernelId(1, 2) | 座標の生成 |
0.5f | 小数の値 |
id.X * 2 + 1 | 整数の計算 |
a && b | 真偽の組み合わせ |
!(id.X > 0) | 否定 |
v >= 0.25f && v <= 0.75f | 範囲の比較 |
cond ? a : b | 条件による値の選択 |
-v | 符号の反転 |
(float)n | 整数から小数への変換 |
(int)(v * 4f) | 小数から整数への変換 |
id.X % 4 | 整数の剰余 |
Mathf.Repeat(v, 0.5f) | 小数の折り返し |
new Vector2(x, y) | 2 成分の値の生成 |
v + w, v.magnitude | 2 成分の値の演算 |
private const float Gain = 0.5f; | 型の定数 |
const float gain = 0.5f; | ローカル定数 |
float sample; float matrix; | コンパイル先の予約語と同じ名前 |
Falloff(d) | 補助関数の呼び出し |
Mix(a, b) | 引数を 2 つ取る補助関数 |
Gpu.Pack16x2(v) | 2 つの値の詰め込み |
Gpu.Unpack16x2(c) | 詰めた値の取り出し |
prev[id.Offset(-1000, -1000)] | バッファの外の読み出し |
書けるが値が違う形(2)
Section titled “書けるが値が違う形(2)”エラーは出ません。書けますし、コンパイルもされます。ただし普通の C# と違う値になる条件があります。
| 書き方 | 何が起きるか |
|---|---|
Mathf.Log(f, g) | 底が実行時に 0 や 1 になったときは ±0・±無限になる(C# はどちらも NaN)。 |
Mathf.Pow(f, g) | 底が負のときは NaN になる(C# は指数が整数なら値を返す) |
書けない形(24)
Section titled “書けない形(24)”| 書き方 | 説明 | エラー | 理由 | 外では |
|---|---|---|---|---|
do { } while (c) | 後判定の繰り返し | TUKI0001 | 未実装 | 通る |
switch | 値による分岐 | TUKI0001 | 未実装 | 通る |
break | 繰り返しの脱出 | TUKI0001 | 未実装 | 通る |
continue | 次の周への継続 | TUKI0001 | 未実装 | 通る |
foreach | 並びの走査 | TUKI0001 | 設計 | 通る |
a & b | ビットごとの論理積 | TUKI0001 | 未実装 | 通る |
a << 1 | ビットをずらす | TUKI0001 | 未実装 | 通る |
double d | 倍精度の小数 | TUKI0001 | 未定 | 通る |
Vector3 v | 3 成分の値 | TUKI0001 | 未実装 | 通る |
string s | 文字列 | TUKI0001 | 設計 | 通る |
float[] xs | 配列 | TUKI0001 | 設計 | 通る |
struct Pair { } | 自分で作った値型 | TUKI0001 | 未定 | 通る |
Debug.Log(x) | Unity の API を呼ぶ | TUKI0001 | 設計 | 通る |
Random.value | 乱数 | TUKI0001 | 設計 | 通る |
Time.time | 時刻 | TUKI0001 | 設計 | 通る |
v == w | 2 成分の値どうしの等値 | TUKI0001 | 設計 | 通る |
0f / 0f | NaN になる定数 | TUKI0001 | 設計 | 通る |
1f / 0f | 無限大になる定数 | TUKI0001 | 設計 | 通る |
goto | 任意の位置への移動 | TUKI0001 | 設計 | 断られる |
try / catch | 例外を捕まえる | TUKI0001 | 環境 | 断られる |
out 引数 | 引数で値を返す | TUKI0001 | 未実装 | 断られる |
自分を呼ぶ関数 | 再帰 | TUKI0001 | 設計 | 断られる |
Peek(GpuBuffer2D b, ...) | 補助関数にバッファを渡す | TUKI0001 | 設計 | — |
prev[id.Offset(1, 0)] = c | 他のセルに書く | CS0200 | 設計 | — |
組み込み(45)
Section titled “組み込み(45)”カーネルの中から呼べるものの一覧で、この表に無いものは断られます。
「C# との差」の列には、次の印が付きます。
- 補正 / 同じ値になるよう、コンパイラが式を組み替えています
- 差あり / 組み替えても残る差があります。上の「書けるが値が違う形」に出してあります
Mathf(30)
Section titled “Mathf(30)”| 書き方 | 説明 | C# との差 |
|---|---|---|
Mathf.Abs(f) | 絶対値 | |
Mathf.Acos(f) | 逆余弦 | |
Mathf.Asin(f) | 逆正弦 | |
Mathf.Atan(f) | 逆正接 | |
Mathf.Atan2(f, g) | y,x から角度 | |
Mathf.Ceil(f) | 切り上げ | |
Mathf.Clamp(f, g, h) | 下限と上限で挟む | 補正 |
Mathf.Clamp01(f) | 0..1 で挟む | |
Mathf.Cos(f) | 余弦 | |
Mathf.Deg2Rad | 度→ラジアンの係数 | |
Mathf.Exp(f) | e の冪 | |
Mathf.Floor(f) | 切り捨て | |
Mathf.InverseLerp(f, g, h) | 値が a..b のどこにあるか(0..1) | 補正 |
Mathf.Lerp(f, g, h) | 線形補間(t は 0..1 に丸める) | 補正 |
Mathf.LerpUnclamped(f, g, h) | 線形補間(t を丸めない) | |
Mathf.Log(f) | 自然対数 | |
Mathf.Log(f, g) | 底を指定した対数 | 差あり |
Mathf.Log10(f) | 常用対数 | |
Mathf.Max(f, g) | 大きいほう | |
Mathf.Min(f, g) | 小さいほう | |
Mathf.PI | 円周率 | |
Mathf.Pow(f, g) | 冪乗 | 差あり |
Mathf.Rad2Deg | ラジアン→度の係数 | |
Mathf.Repeat(f, g) | 0..length で折り返す(剰余) | 補正 |
Mathf.Round(f) | 四捨五入(0.5 は偶数側へ) | |
Mathf.Sign(f) | 符号(0 は正として 1) | 補正 |
Mathf.Sin(f) | 正弦 | |
Mathf.SmoothStep(f, g, h) | なめらかな補間(両端で速度 0) | 補正 |
Mathf.Sqrt(f) | 平方根 | |
Mathf.Tan(f) | 正接 |
Vector2(10)
Section titled “Vector2(10)”| 書き方 | 説明 | C# との差 |
|---|---|---|
Vector2.Distance(v, w) | 2 点の距離 | |
Vector2.Dot(v, w) | 内積 | |
Vector2.Lerp(v, w, f) | 線形補間(t は 0..1 に丸める) | 補正 |
Vector2.LerpUnclamped(v, w, f) | 線形補間(t を丸めない) | |
Vector2.Max(v, w) | 成分ごとに大きいほう | |
Vector2.Min(v, w) | 成分ごとに小さいほう | |
Vector2.one | (1, 1) | |
Vector2.right | (1, 0) | |
Vector2.up | (0, 1) | |
Vector2.zero | (0, 0) |
2 成分の値のメンバ(3)
Section titled “2 成分の値のメンバ(3)”| 書き方 | 説明 | C# との差 |
|---|---|---|
v.magnitude | 長さ | |
v.normalized | 長さ 1 にした向き(長さ 0 なら (0,0)) | 補正 |
v.sqrMagnitude | 長さの 2 乗(平方根を取らない) |
Gpu(2)
Section titled “Gpu(2)”| 書き方 | 説明 | C# との差 |
|---|---|---|
Gpu.Pack16x2(v) | 2 つの値を 1 セルに詰める(各 65536 段階) | |
Gpu.Unpack16x2(c) | Pack16x2 で詰めた値を取り出す |
カーネルの内と外の差
Section titled “カーネルの内と外の差”カーネルの中で書けるのは、この言語のうちの狭い一部です。上の表の「外では」の列がその差で、 18 形は普通のメソッドなら書けるのに、カーネルの中では書けません。
エラーの文言は、どちらの理由で断られても同じです
(TUKI0001「Udon に落とせない C# 構文です」)。上の 18 形は Udon では現に書けるので、
文言どおりに読むと原因を取り違えます。断られた形が普通のメソッドでは通るなら、
原因はその形ではなく、カーネルの中に書いたことです。
書き込み先の制限
Section titled “書き込み先の制限”書き込む手段はカーネルの戻り値だけで、その値が自分のセルに書かれます。他のセルへ代入すると、
TUKI 番号ではなく CS0200(読み取り専用への代入)で止まります。バッファの添字が
読み出し専用なので、この言語の検査まで届かず、C# の規則の側で先に止まります。
- 1 セルは 4 成分・各 8 ビット(256 段階)です。細かい値が要るなら
Gpu.Pack16x2で 2 つ詰めます(各 65536 段階) - バッファの外を指す添字は端の値に丸められるので、範囲の検査を自分で書かなくて済みます
- 辺の長さは 16 の倍数にしておくと、対応する環境が広くなります
Gpu.Pack16x2はカーネルの中でしか使えません(外から詰めて渡すことはできません)
色は 8 ビットに丸まります。1 つの色に複数の値を詰めると、その段階数だけ精度が落ちます。
ローカル変数
Section titled “ローカル変数”using UnityEngine;using Tsukimi;
public class ParLocalVariable : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = prev[id].R; return new Color4(v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParAssignment : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = 0f; v = prev[id].R; return new Color4(v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParCompoundAssignment : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = prev[id].R; v += 0.25f; return new Color4(v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParIncrement : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { int n = id.X; n++; return new Color4(n * 0.01f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}戻り値のあるメソッド
Section titled “戻り値のあるメソッド”カーネルの戻り値が、そのセルに書かれます。書き込む手段はこれだけです。
using UnityEngine;using Tsukimi;
public class ParReturn : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(0.5f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}条件による分岐
Section titled “条件による分岐”using UnityEngine;using Tsukimi;
public class ParIf : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = prev[id].R; if (v > 0.5f) { v = 1f; } return new Color4(v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParIfElse : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = prev[id].R; if (v > 0.5f) { v = 1f; } else { v = 0f; } return new Color4(v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}途中での復帰
Section titled “途中での復帰”using UnityEngine;using Tsukimi;
public class ParEarlyReturn : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { if (id.X == 0) { return Color4.Black; } return new Color4(prev[id].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}回数を決めた繰り返し
Section titled “回数を決めた繰り返し”using UnityEngine;using Tsukimi;
public class ParFor : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = 0f; for (int i = 0; i < 4; i++) { v = v + prev[id.Offset(i, 0)].R; } return new Color4(v * 0.25f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}条件による繰り返し
Section titled “条件による繰り返し”using UnityEngine;using Tsukimi;
public class ParWhile : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = 0f; int i = 0; while (i < 4) { v = v + prev[id.Offset(i, 0)].R; i++; } return new Color4(v * 0.25f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParBlock : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = prev[id].R; { v = v * 2f; } return new Color4(Mathf.Clamp01(v), 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}条件の入れ子
Section titled “条件の入れ子”using UnityEngine;using Tsukimi;
public class ParNestedIf : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float v = prev[id].R; if (v > 0.25f) { if (v > 0.75f) { v = 1f; } } return new Color4(v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}自分のセルの読み出し
Section titled “自分のセルの読み出し”id は、そのカーネルが担当するセルの座標です。prev[id] はそのセルの値を読みます。
using UnityEngine;using Tsukimi;
public class ParCellRead : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Color4 c = prev[id]; return new Color4(c.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}成分の読み出し
Section titled “成分の読み出し”各成分は 0 から 1 のあいだの値です。
using UnityEngine;using Tsukimi;
public class ParCellComponents : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Color4 c = prev[id]; return new Color4(c.R + c.G + c.B + c.A, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}セルの値の生成
Section titled “セルの値の生成”4 つの成分から、そのセルへ書く値を作ります。
using UnityEngine;using Tsukimi;
public class ParCellConstruct : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Color4 c = new Color4(0.5f, 0f, 0f, 1f); return new Color4(c.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}組み込みの定数を、そのまま値として使えます。
using UnityEngine;using Tsukimi;
public class ParCellWhite : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(Color4.White.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}定数の色の返却
Section titled “定数の色の返却”定数の色を、そのまま戻り値にできます。
using UnityEngine;using Tsukimi;
public class ParCellBlack : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return Color4.Black; }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}セルどうしの加算
Section titled “セルどうしの加算”using UnityEngine;using Tsukimi;
public class ParCellAdd : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Color4 c = prev[id] + Color4.Black; return new Color4(c.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}セルどうしの減算
Section titled “セルどうしの減算”using UnityEngine;using Tsukimi;
public class ParCellSub : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Color4 c = prev[id] - Color4.Black; return new Color4(c.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}セルの定数倍
Section titled “セルの定数倍”using UnityEngine;using Tsukimi;
public class ParCellScale : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Color4 c = prev[id] * 0.5f; return new Color4(c.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}担当セルの座標
Section titled “担当セルの座標”担当するセルの位置を、整数で取り出せます。
using UnityEngine;using Tsukimi;
public class ParIdXy : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4((id.X + id.Y) * 0.001f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}相対位置のセルの読み出し
Section titled “相対位置のセルの読み出し”Offset で、相対位置のセルを読めます。バッファの外を指した添字は、端の値に丸められます(下の「数の性質」)。
using UnityEngine;using Tsukimi;
public class ParIdOffset : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id.Offset(1, -1)].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}座標を自分で組み立てて、任意のセルを指せます。
using UnityEngine;using Tsukimi;
public class ParIdConstruct : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { KernelId k = new KernelId(1, 2); return new Color4(prev[k].R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}末尾に f を付けて、小数の定数を書きます。
using UnityEngine;using Tsukimi;
public class ParFloatLiteral : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(0.5f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParIntArith : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { int n = id.X * 2 + 1; return new Color4(n * 0.001f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}真偽の組み合わせ
Section titled “真偽の組み合わせ”using UnityEngine;using Tsukimi;
public class ParBoolLogic : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { bool b = id.X > 0 && id.Y > 0; return new Color4(b ? 1f : 0f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParNot : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { bool b = !(id.X > 0); return new Color4(b ? 1f : 0f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParComparisonChain : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { bool b = prev[id].R >= 0.25f && prev[id].R <= 0.75f; return new Color4(b ? 1f : 0f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}条件による値の選択
Section titled “条件による値の選択”using UnityEngine;using Tsukimi;
public class ParTernary : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(id.X > 32 ? 1f : 0f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}using UnityEngine;using Tsukimi;
public class ParNegate : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(-(-prev[id].R), 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}整数から小数への変換
Section titled “整数から小数への変換”using UnityEngine;using Tsukimi;
public class ParCastIntToFloat : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { int n = id.X; return new Color4((float)n * 0.001f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}小数から整数への変換
Section titled “小数から整数への変換”using UnityEngine;using Tsukimi;
public class ParCastFloatToInt : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { int n = (int)(prev[id].R * 4f); return new Color4(n * 0.25f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}% で整数の剰余を計算できます。コンパイル先のシェーダコンパイラが、遅いと警告することがあります。
using UnityEngine;using Tsukimi;
public class ParModuloInt : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { int n = id.X % 4; return new Color4(n * 0.25f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}小数の折り返し
Section titled “小数の折り返し”小数の折り返しには Mathf.Repeat を使います。
using UnityEngine;using Tsukimi;
public class ParModuloFloat : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(Mathf.Repeat(prev[id].R, 0.5f), 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}2 成分の値の生成
Section titled “2 成分の値の生成”using UnityEngine;using Tsukimi;
public class ParVector2Construct : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Vector2 v = new Vector2(0.25f, 0.5f); return new Color4(v.x + v.y, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}2 成分の値の演算
Section titled “2 成分の値の演算”Vector2 どうしの足し引きのほか、magnitude などのメンバも使えます。
using UnityEngine;using Tsukimi;
public class ParVector2Ops : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Vector2 v = new Vector2(1f, 0f) + new Vector2(0f, 1f); return new Color4(v.magnitude * 0.5f, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}定数は、コンパイルのときに値へ置き換わります。
using UnityEngine;using Tsukimi;
public class ParConstField : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
private const float Gain = 0.5f;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R * Gain, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}ローカル定数
Section titled “ローカル定数”using UnityEngine;using Tsukimi;
public class ParConstLocal : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { const float gain = 0.5f; return new Color4(prev[id].R * gain, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}コンパイル先の予約語と同じ名前
Section titled “コンパイル先の予約語と同じ名前”シェーダ側の予約語と重なる名前は、コンパイルのときに改名されます。
using UnityEngine;using Tsukimi;
public class ParReservedWordName : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float sample = prev[id].R; float matrix = 0.5f; return new Color4(sample * matrix, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}関数への分割
Section titled “関数への分割”補助関数の呼び出し
Section titled “補助関数の呼び出し”カーネルから呼んだ static メソッドは、シェーダの関数として一緒に書き出されます。その補助関数に [TsukimiKernel] は要りません。
using UnityEngine;using Tsukimi;
public class ParCallHelper : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
static float Falloff(float d) { return Mathf.Clamp01(1f - d * d); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { float d = (id.X - 32) * 0.05f; return new Color4(Falloff(d), 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}引数を 2 つ取る補助関数
Section titled “引数を 2 つ取る補助関数”using UnityEngine;using Tsukimi;
public class ParHelperTwoArgs : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
static float Mix(float a, float b) { return a * 0.5f + b * 0.5f; }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(Mix(prev[id].R, prev[id].G), 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}詰め込みと端の読み出し
Section titled “詰め込みと端の読み出し”2 つの値の詰め込み
Section titled “2 つの値の詰め込み”1 セルは 4 成分・各 8 ビット(256 段階)です。詰めると、各 65536 段階まで保たれます。
using UnityEngine;using Tsukimi;
public class ParPackTwoValues : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Vector2 fine = new Vector2(prev[id].R, prev[id].G); return Gpu.Pack16x2(fine); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}詰めた値の取り出し
Section titled “詰めた値の取り出し”詰めた値は、Gpu.Unpack16x2 で元の 2 つに戻せます。
using UnityEngine;using Tsukimi;
public class ParPackRoundtrip : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { Vector2 fine = new Vector2(0.5f, 0.25f); Color4 packed = Gpu.Pack16x2(fine); Vector2 back = Gpu.Unpack16x2(packed); return new Color4(back.x, back.y, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}バッファの外の読み出し
Section titled “バッファの外の読み出し”バッファの外を指した添字は端の値に丸められるので、範囲の検査を自分で書かなくて済みます。
using UnityEngine;using Tsukimi;
public class ParEdgeRead : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[TsukimiKernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { // バッファの外を指す添字は、端の値に丸められる Color4 outside = prev[id.Offset(-1000, -1000)]; return new Color4(outside.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}