GPU カーネル
[Kernel] は以前 [TsukimiKernel] という綴りでした。古い綴りもそのまま動きます。
対応(18)
Section titled “対応(18)”| 書き方 | 説明 | 注意 |
|---|---|---|
return new Color4(...) | 戻り値のあるメソッド | 書き込む手段はこれだけです。 |
static Color4 Step(...) => prev[id] * 0.5f | 式だけのカーネル | |
int bands | 整数の引数 | |
bool invert | 真偽値の引数 | |
Vector2 shift | 2 成分の引数 | |
Vector3 tint | 3 成分の引数 | |
Vector4 weights | 4 成分の引数 | |
prev[id] | 自分のセルの読み出し | prev[id] はそのセルの値を読みます。 |
c.R c.G c.B c.A | 成分の読み出し | |
new Color4(r, g, b, a) | セルの値の生成 | |
Color4.White | 定数の色 | |
Color4.Black | 定数の色の返却 | |
id.X id.Y | 担当セルの座標 | |
prev[id.Offset(1, -1)] | 相対位置のセルの読み出し | バッファの外を指した添字は、端の値に丸められます(下の「数の性質」)。 |
new KernelId(1, 2) | 座標の生成 | |
prev[id.Offset(-1000, -1000)] | バッファの外の読み出し | |
prev.Wrap(id.Offset(1, 0)) | 反対側へ回した読み出し | 端の値に丸める添字と違って、小さな板を敷き詰めるときに使えます。幅 64 のバッファで -1 を指すと 63 のセルが返ります。 |
prev.Smooth(position) | まわりと混ぜた読み出し | 拡大しても境目が出ません。4 つのセルを読むので、1 つを読むより費用がかかります。 |
非対応(18)
Section titled “非対応(18)”| 書き方 | 説明 | エラー | 理由 | カーネルの外 |
|---|---|---|---|---|
foreach | 並びの走査 | TUKI0001 | 設計 | 対応 |
float v = (i++) + 1f | 値として使う位置の増減 | TUKI0001 | 設計 | 対応 |
float w = (v = 1f) + 1f | 値として使う位置の代入 | TUKI0001 | 設計 | 対応 |
double d | 倍精度の小数 | TUKI0001 | 未定 | 対応 |
string s | 文字列 | TUKI0001 | 設計 | 対応 |
float[] xs | 配列 | TUKI0001 | 設計 | 対応 |
struct Pair { } | 自分で作った値型 | TUKI0001 | 未定 | 対応 |
Debug.Log(x) | Unity の API を呼ぶ | TUKI0001 | 設計 | 対応 |
Random.value | 乱数 | TUKI0001 | 設計 | 対応 |
Time.time | 時刻 | TUKI0001 | 設計 | 対応 |
0f / 0f | NaN になる定数 | TUKI0001 | 設計 | 対応 |
1f / 0f | 無限大になる定数 | TUKI0001 | 設計 | 対応 |
out 引数 | 引数で値を返す | TUKI0001 | 設計 | 対応 |
goto | 任意の位置への移動 | TUKI0001 | 設計 | 非対応 |
try / catch | 例外を捕まえる | TUKI0001 | 環境 | 非対応 |
自分を呼ぶ関数 | 再帰 | TUKI0001 | 設計 | 非対応 |
Peek(GpuBuffer2D b, ...) | 補助関数にバッファを渡す | TUKI0001 | 設計 | — |
prev[id.Offset(1, 0)] = c | 他のセルに書く | CS0200, TUKI0001 | 設計 | — |
| 型 | 中身 | 例 |
|---|---|---|
GpuBuffer2D | セルの並び。カーネルの引数として受け取り、添字で読みます | 自分のセルの読み出し |
KernelId | 担当するセルの座標。X と Y は int です | 担当セルの座標 |
Color4 | 1 セルの値。R G B A は 0 から 1 の float です | 成分の読み出し |
float int bool | スカラー。引数・ローカル変数・補助関数の引数と戻り値に使えます | 整数の引数 |
Vector2 Vector3 Vector4 | 2 から 4 成分の値。演算子は型ごとの演算子にあります | 2 成分の引数 |
Vector4[] | 表。[Capacity(N)] を付けた引数としてだけ受け取れます | 表を渡した実行 |
文・式・関数のページ
Section titled “文・式・関数のページ”| ページ | 中身 |
|---|---|
| カーネルの文と式 | 制御構文・演算子・型ごとの演算の一覧 |
| カーネルから呼べる関数 | 組み込みの表と補助関数 |
カーネルの内と外の差
Section titled “カーネルの内と外の差”| 書ける範囲 | この言語のうちの狭い一部です。上の表の「カーネルの外」の列がその差で、13 種類の構文は通常のメソッドでは書けるのに、カーネルの中では書けません |
| エラーの文言 | どちらの理由でも同じです(TUKI0001「Udon に落とせない C# 構文です」)。上の 13 形は Udon では現に書けるので、文言どおりに読むと原因を取り違えます |
| 判別方法 | エラーになった構文が通常のメソッドでは対応しているなら、原因はその構文ではなく、カーネルの中に書いたことです |
書き込み先の制限
Section titled “書き込み先の制限”書き込む手段はカーネルの戻り値だけで、その値が自分のセルに書かれます。他のセルへ代入すると、
TUKI 番号ではなく CS0200(読み取り専用への代入)のエラーになります。バッファの添字が
読み出し専用なので、この言語の検査に到達する前に、C# コンパイラの規則でエラーになります。
- 1 セルは 4 成分で、成分は既定では 8 ビット(256 段階)です。0..1 の内側で細かい値が必要なら
Gpu.Pack16x2で 2 つ詰めます(各 65536 段階・1 セルに 2 値)。0..1 の外の値が必要なら、バッファをGpuFormat.Halfで作ります - バッファの外を指す添字は端の値に丸められるので、範囲の検査を自分で書かなくて済みます
- 辺の長さは 16 の倍数にしておくと、対応する環境が広くなります
Gpu.Pack16x2はカーネルの中でしか使えません(外から詰めて渡すことはできません)
既定のバッファでは色は 8 ビットに丸まります。1 つの色に複数の値を詰めると、その段階数だけ精度が落ちます。
カーネルの形
Section titled “カーネルの形”戻り値のあるメソッド
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); }
[Kernel] 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 “式だけのカーネル”本体が 1 つの式なら => で書けます。
using UnityEngine;using Tsukimi;
public class ParExpressionBody : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
// 本体が 1 つの式なら、=> で書けます [Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev) => prev[id] * 0.5f;
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}Gpu.Run の同じ位置に、同じ型の値を渡します。
using UnityEngine;using Tsukimi;
public class ParArgInt : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; public int bands;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev, int bands) { // 整数の引数は、Gpu.Run の同じ位置に int を渡します float v = prev[id].R * bands; return new Color4(v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current, bands); Gpu.Swap(ref current, ref next); }}真偽値の引数
Section titled “真偽値の引数”using UnityEngine;using Tsukimi;
public class ParArgBool : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; public bool invert;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev, bool invert) { float v = prev[id].R; // 真偽値の引数は、そのまま条件に使えます return new Color4(invert ? 1f - v : v, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current, invert); Gpu.Swap(ref current, ref next); }}2 成分の引数
Section titled “2 成分の引数”using UnityEngine;using Tsukimi;
public class ParArgVector2 : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; public Vector2 shift;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev, Vector2 shift) { // 2 成分の引数。ここでは読むセルをずらす量に使っています return prev[id.Offset((int)shift.x, (int)shift.y)]; }
void Update() { Gpu.Run(nameof(Step), next, current, shift); Gpu.Swap(ref current, ref next); }}3 成分の引数
Section titled “3 成分の引数”using UnityEngine;using Tsukimi;
public class ParArgVector3 : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; public Vector3 tint;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev, Vector3 tint) { Color4 c = prev[id]; // 3 成分の引数。ここでは色の係数に使っています return new Color4(c.R * tint.x, c.G * tint.y, c.B * tint.z, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current, tint); Gpu.Swap(ref current, ref next); }}4 成分の引数
Section titled “4 成分の引数”using UnityEngine;using Tsukimi;
public class ParArgVector4 : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next; public Vector4 weights;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev, Vector4 weights) { Color4 c = prev[id]; // 4 成分の引数。ここでは成分ごとの重みに使っています float v = c.R * weights.x + c.G * weights.y + c.B * weights.z + c.A * weights.w; return new Color4(v, v, v, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current, weights); Gpu.Swap(ref current, ref next); }}自分のセルの読み出し
Section titled “自分のセルの読み出し”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); }
[Kernel] 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); }
[Kernel] 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); }
[Kernel] 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); }
[Kernel] 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); }
[Kernel] 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 ParIdXy : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[Kernel] 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); }
[Kernel] 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); }
[Kernel] 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); }}バッファの外の読み出し
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); }
[Kernel] 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); }}反対側へ回した読み出し
Section titled “反対側へ回した読み出し”Wrap は、バッファの外を指した添字を反対側へ回します。
using UnityEngine;using Tsukimi;
public class ParCellWrap : TsukimiBehaviour{ private GpuBuffer2D current; private GpuBuffer2D next;
void Start() { current = Gpu.Buffer(64, 64); next = Gpu.Buffer(64, 64); }
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { // バッファの外を指す添字は、反対側へ回る Color4 far = prev.Wrap(id.Offset(-1, 0)); return new Color4(far.R, 0f, 0f, 1f); }
void Update() { Gpu.Run(nameof(Step), next, current); Gpu.Swap(ref current, ref next); }}まわりと混ぜた読み出し
Section titled “まわりと混ぜた読み出し”Smooth は、位置(0 から 1)で指した値を、まわりのセルと混ぜて返します。
using UnityEngine;using Tsukimi;
public class ParCellSmooth : TsukimiBehaviour{ private GpuBuffer2D small; private GpuBuffer2D big;
void Start() { small = Gpu.Buffer(16, 16); big = Gpu.Buffer(256, 256); }
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D board) { // 位置(0 から 1)で指して、まわりのセルと混ぜて読む Vector2 position = new Vector2(id.X * 0.00390625f, id.Y * 0.00390625f); return board.Smooth(position); }
void Update() { Gpu.Run(nameof(Step), big, small); }}