サーフェスシェーダー(試験中)
この章は試験中です。 Renderer が描く見た目を C# で記述できます。
| 書き方 | 説明 | 注意 |
|---|---|---|
[Surface] static Color4 M(SurfaceId id, ...) | ピクセルの色を決める | バッファは buf.Sample(id.UV) で位置から読み、最も近いセルの値がそのまま返ります(補間されません)。Renderer へ出すのは Gpu.Show(nameof(M), rend, buf, gain) で、値は呼ぶたびに渡します。 |
Vector3.Dot(id.Normal, toLight) | 法線の向きで陰影を付ける | |
Vector3.Dot(id.Normal, id.ViewDir) | 見ている向きを使う | |
static Color4 M(SurfaceId id, GpuBuffer2D buf, int n, bool b, Vector2 v, Vector3 w) | 値の型の引数 | 値は Gpu.Show の同じ位置に渡します。 |
[Surface] static Vector3 M(VertexId v, ...) | 頂点を動かす |
非対応(4)
Section titled “非対応(4)”| 書き方 | 説明 | エラー | 理由 | 代替 |
|---|---|---|---|---|
static Color4 M(int n) | 第 1 引数がどちらの型でもない=役割が決まらない | TUKI0001 | 設計 | 色を返すなら SurfaceId、位置を返すなら VertexId |
static float M(SurfaceId id) | 色の側がピクセルに出す値を返していない | TUKI0001 | 設計 | Color4 を返す |
static Vector3 M(VertexId v) だけ | 色を返す側が無いと何も描けない | TUKI0001 | 設計 | 同じ名前で色の側も書く |
id.Shadow | 影の受け方はほかの物の描かれ方で変わる | CS1061 | 設計 | 手で書いたシェーダーを使う |
識別子のメンバ
Section titled “識別子のメンバ”| 書き方 | 型 | 中身 |
|---|---|---|
id.UV | Vector2 | 面の上の位置(0 から 1)。メッシュに設定された値がそのまま来ます |
id.Normal | Vector3 | 面の向き(世界座標・長さ 1)。頂点を動かしても、元の向きのままです |
id.ViewDir | Vector3 | その画素から見ている人へ向かう向き(世界座標・長さ 1) |
v.Position | Vector3 | 頂点の位置(メッシュ座標)。戻り値も同じ座標で返します |
v.UV | Vector2 | 面の上の位置(0 から 1) |
SurfaceId と VertexId のメンバはこの 5 つで、ほかの名前は CS1061 になります。
ピクセルの色を決める
Section titled “ピクセルの色を決める”返した色がそのピクセルに出ます。
using UnityEngine;using Tsukimi;
public class ParSurfaceTint : TsukimiBehaviour{ public Renderer display; public float gain; private GpuBuffer2D heat;
[Kernel] static Color4 Step(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R * 0.99f, 0f, 0f, 1f); }
[Surface] static Color4 Tint(SurfaceId id, GpuBuffer2D buf, float gain) { float t = buf.Sample(id.UV).R * gain; return new Color4(t, t * t, 0f, 1f); }
void Start() { heat = Gpu.Buffer(64, 64); }
void Update() { Gpu.Show(nameof(Tint), display, heat, gain); }}法線の向きで陰影を付ける
Section titled “法線の向きで陰影を付ける”光の向きは自分で決めます(場に置かれたライトは読めません)。
using UnityEngine;using Tsukimi;
public class ParSurfaceShading : TsukimiBehaviour{ public Renderer display; private GpuBuffer2D buf;
[Surface] static Color4 Lit(SurfaceId id, GpuBuffer2D buf) { Vector3 toLight = new Vector3(0.3f, 1f, 0.2f).normalized; float lit = Mathf.Clamp01(Vector3.Dot(id.Normal, toLight) * 0.5f + 0.5f); Color4 albedo = buf.Sample(id.UV); return albedo * lit; }
void Start() { buf = Gpu.Buffer(32, 32); }
void Update() { Gpu.Show(nameof(Lit), display, buf); }}見ている向きを使う
Section titled “見ている向きを使う”浅い角度ほど強く出す、といった見せ方に使います。
using UnityEngine;using Tsukimi;
public class ParSurfaceRim : TsukimiBehaviour{ public Renderer display; public Vector4 glow; private GpuBuffer2D mist;
[Surface] static Color4 Fogged(SurfaceId id, GpuBuffer2D mist, Vector4 glow) { float m = mist.Sample(id.UV).R; float rim = 1f - Mathf.Abs(Vector3.Dot(id.Normal, id.ViewDir)); return Color4.Lerp(new Color4(m, m, m, 1f), new Color4(glow), rim); }
void Start() { mist = Gpu.Buffer(64, 64); }
void Update() { Gpu.Show(nameof(Fogged), display, mist, glow); }}値の型の引数
Section titled “値の型の引数”引数には GpuBuffer2D と float のほかに int bool Vector2 Vector3 Vector4 が使えます。
using UnityEngine;using Tsukimi;
public class ParSurfaceValueArgs : TsukimiBehaviour{ public Renderer display; public int bands; public bool invert; public Vector2 shift; public Vector3 tint; private GpuBuffer2D buf;
// 引数には GpuBuffer2D・float のほかに int・bool・Vector2・Vector3・Vector4 が使えます [Surface] static Color4 Banded(SurfaceId id, GpuBuffer2D buf, int bands, bool invert, Vector2 shift, Vector3 tint) { float v = buf.Sample(id.UV + shift).R; float stepped = Mathf.Floor(v * bands) / 8f; float t = invert ? 1f - stepped : stepped; return new Color4(t * tint.x, t * tint.y, t * tint.z, 1f); }
void Start() { buf = Gpu.Buffer(64, 64); }
void Update() { Gpu.Show(nameof(Banded), display, buf, bands, invert, shift, tint); }}頂点を動かす
Section titled “頂点を動かす”同じ名前で色の側も書くと、1 つのシェーダーになります。
using UnityEngine;using Tsukimi;
public class ParSurfaceVertex : TsukimiBehaviour{ public Renderer display; public float amplitude; private GpuBuffer2D height;
static float ToHeight(Color4 c, float amplitude) { return (c.R - 0.5f) * amplitude; }
[Kernel] static Color4 Wave(KernelId id, GpuBuffer2D prev) { return new Color4(prev[id].R, 0.5f, 0.5f, 1f); }
[Surface] static Vector3 Surf(VertexId v, GpuBuffer2D height, float amplitude) { return v.Position + new Vector3(0f, ToHeight(height.Sample(v.UV), amplitude), 0f); }
[Surface] static Color4 Surf(SurfaceId id, GpuBuffer2D height, float amplitude) { float d = 1f / height.width; float hx = ToHeight(height.Sample(id.UV + new Vector2(d, 0f)), amplitude) - ToHeight(height.Sample(id.UV - new Vector2(d, 0f)), amplitude); float hy = ToHeight(height.Sample(id.UV + new Vector2(0f, d)), amplitude) - ToHeight(height.Sample(id.UV - new Vector2(0f, d)), amplitude); Vector3 n = new Vector3(-hx, 0.2f, -hy).normalized; float lit = Mathf.Clamp01(Vector3.Dot(n, new Vector3(0.3f, 1f, 0.2f).normalized) * 0.5f + 0.5f); return new Color4(0.2f * lit, 0.5f * lit, 0.8f * lit, 1f); }
void Start() { height = Gpu.Buffer(128, 128); }
void Update() { Gpu.Show(nameof(Surf), display, height, amplitude); }}