コンテンツにスキップ

サーフェスシェーダー(試験中)

この章は試験中です。 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, ...)頂点を動かす
書き方説明エラー理由代替
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設計手で書いたシェーダーを使う
書き方型中身
id.UVVector2面の上の位置(0 から 1)。メッシュに設定された値がそのまま来ます
id.NormalVector3面の向き(世界座標・長さ 1)。頂点を動かしても、元の向きのままです
id.ViewDirVector3その画素から見ている人へ向かう向き(世界座標・長さ 1)
v.PositionVector3頂点の位置(メッシュ座標)。戻り値も同じ座標で返します
v.UVVector2面の上の位置(0 から 1)

SurfaceId と VertexId のメンバはこの 5 つで、ほかの名前は CS1061 になります。

返した色がそのピクセルに出ます。

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);
}
}

光の向きは自分で決めます(場に置かれたライトは読めません)。

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);
}
}

浅い角度ほど強く出す、といった見せ方に使います。

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);
}
}

引数には 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);
}
}

同じ名前で色の側も書くと、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);
}
}