Skip to content

Kernel statements and expressions

SyntaxDescriptionNote
float v = prev[id].RLocal variable
v = prev[id].RAssignment
v += 0.25fCompound assignment
v -= 0.1f; v *= 2f; v /= 4fOther compound assignments
n++Increment and decrement
++n; --n; n--Prefix increment and decrement
if (v > 0.5f) { ... }Branch on a condition
if (...) { } else { }Two-way branch
switch (n) { case 0: ... }Branching on a valueOnly a break at the end of an arm can be written.
case 0: case 1: ...Arm with several case labels
if (id.X == 0) { return ...; }Return partway through
for (int i = 0; i < 4; i++)Loop a fixed number of times
for (int i = 0, j = 3; i < j; i++, j--)Several declarations in for
for (i = 0; i < 4; i++)Initializing for with an assignment
while (i < 4)Conditional loop
do { ... } while (i < 4);Loop with the check after the body
breakLoop exit
continueContinue to the next iteration
{ ... }Block
if (...) { if (...) { } }Nested condition
0.5fFloat value
id.X * 2 + 1Integer arithmetic
(a - b) / 2f + a * bFloat arithmetic
a && bCombining booleans
a || bBoolean OR
!(id.X > 0)Negation
v >= 0.25f && v <= 0.75fRange comparison
n == 3, f != 0fEquality and inequality
cond ? a : bChoosing a value by condition
-vSign negation
(float)nConverting int to float
(int)(v * 4f)Float-to-int conversion
id.X % 4Integer remainderThe target shader compiler may warn that it is slow.
f % 1fFloat remainder
Mathf.Repeat(v, 0.5f)Float wraparound
id.X & 3Bitwise operationsThey do not work between booleans; use the logical operators instead.
(id.X | 1) ^ 2Bitwise OR and XOR
~id.XBitwise NOT
id.X << 2Shifting bits
id.X >> 1Right shift
id.Offset(dy: 1, dx: 0)Named argumentsThey are reordered into declaration order, not the order written.
new Vector2(x, y)Constructing a 2-component value
v + w, v.magnitudeOperating on a 2-component valueThe members are magnitude sqrMagnitude normalized, 3 in all.
v * 2f, 2f * v, v / 2f, -vScaling a 2-component value
v * w, v / wComponent-wise multiplication and division of 2-component values
v == wEquality between 2-component values
v != wInequality between 2-component values
v.x = 1fAssigning to a component of a 2-component value
v += w; v *= 2fCompound assignment to a 2-component value
new Vector3(1f, 0f, 0f)Constructing a 3-component valueComponent-wise * and / are operators that only Vector2 has.
new Vector4(1f, 0f, 0f, 1f)Constructing a 4-component value
a + b, a * 0.5f, -aOperating on a 3-component value
p + q, p * 0.5f, -pOperating on a 4-component value
a == b, a != bEquality between 3-component values
p == q, p != qEquality between 4-component values
a.z = 0.5f; p.w = 1fAssigning to a component of a 3- or 4-component value
a += b; p /= 2fCompound assignment to a 3- or 4-component value
prev[id] + Color4.BlackAdding cells
prev[id] - Color4.BlackSubtracting cells
prev[id] * 0.5fScaling a cell by a constant
prev[id] / 2fDividing a cell value
prev[id] * prev[id.Offset(1, 0)]Multiplying cells
new Color4(rgb, 1f)Constructing from 3 components and an alpha
new Color4(v)Constructing from 4 components
c += b; c *= 0.5f; c /= 2fCompound assignment to a cell value
c.R = 0.5fAssigning to a cell component
private const float Gain = 0.5f;Type constant
const float gain = 0.5f;Local constant
float sample; float matrix;Same name as a reserved word in the compile target
SyntaxDescriptionErrorReasonAlternative
v %= 2fCompound assignment with remainder (the same applies to &= |= ^= <<= >>=)TUKI0001undecidedWrite it out as v = v % 2f
+vUnary plusTUKI0001by designRemove it (the value does not change)
SyntaxDescriptionExample
new Color4(r, g, b, a)Construct from 4 floatsConstructing a cell value
new Color4(rgb, a)Construct from a Vector3 color and a float alphaConstructing from 3 components and an alpha
new Color4(v)Construct from a Vector4Constructing from 4 components
Color4.White Color4.BlackConstantConstant color
c.R c.G c.B c.AReading a componentReading a component
c.R = 0.5fAssigning to a component (local variable)Assigning to a cell component
a + bComponent-wise sumAdding cells
a - bComponent-wise differenceSubtracting cells
a * 0.5fScale each component by a constantScaling a cell by a constant
a * bComponent-wise productMultiplying cells
a / 2fDivide each component by a floatDividing a cell value
c += b c -= b c *= 0.5f c *= b c /= 2fCompound assignmentCompound assignment to a cell value
SyntaxDescriptionExample
new Vector2(x, y)Construct from 2 floatsConstructing a 2-component value
v.x v.yReading a componentScaling a 2-component value
v.x = 1fAssigning to a component (local variable)Assigning to a component of a 2-component value
v + w v - wComponent-wise sum and differenceOperating on a 2-component value
v * 2f 2f * v v / 2f -vScaling, division by a float, sign negationScaling a 2-component value
v * w v / wComponent-wise product and quotient (operators only Vector2 has)Component-wise multiplication and division of 2-component values
v == wApproximate comparisonEquality between 2-component values
v != wNegated approximate comparisonInequality between 2-component values
v += w v -= w v *= 2f v /= 2fCompound assignmentCompound assignment to a 2-component value
SyntaxDescriptionExample
new Vector3(x, y, z)Construct from 3 floatsConstructing a 3-component value
new Vector4(x, y, z, w)Construct from 4 floatsConstructing a 4-component value
a.x a.y a.z p.wReading a componentConstructing a 4-component value
a.z = 0.5f p.w = 1fAssigning to a component (local variable)Assigning to a component of a 3- or 4-component value
a + b a - b a * 2f 2f * a a / 2f -aVector3 sum, difference, scaling, division by a float, sign negationOperating on a 3-component value
p + q p - q p * 2f 2f * p p / 2f -pVector4 sum, difference, scaling, division by a float, sign negationOperating on a 4-component value
a == b a != bApproximate comparison of Vector3Equality between 3-component values
p == q p != qApproximate comparison of Vector4Equality between 4-component values
a += b a *= 2f p -= q p /= 2fCompound assignmentCompound assignment to a 3- or 4-component value
SyntaxDescriptionExample
0.5fFloat constantFloat value
a + b a - b a * b a / bArithmeticFloat arithmetic
f % 1fRemainderFloat remainder
-vSign negationSign negation
a < b a > b a <= b a >= bOrdering comparisonRange comparison
a == b a != bEquality and inequalityEquality and inequality
(float)nConversion from intConverting int to float
v += 0.25fCompound assignment with additionCompound assignment
v -= 0.1f v *= 2f v /= 4fOther compound assignmentsOther compound assignments
SyntaxDescriptionExample
id.X * 2 + 1ArithmeticInteger arithmetic
id.X % 4RemainderInteger remainder
n == 3Equality and inequalityEquality and inequality
id.X & 3Bitwise ANDBitwise operations
n | 1 n ^ 2Bitwise OR and XORBitwise OR and XOR
~nBitwise NOTBitwise NOT
id.X << 2Left shiftShifting bits
id.X >> 1Right shiftRight shift
n++Postfix incrementIncrement and decrement
++n --n n--Prefix increment and decrement, postfix decrementPrefix increment and decrement
(int)fConversion from floatFloat-to-int conversion
SyntaxDescriptionExample
a && bLogical ANDCombining booleans
a || bLogical ORBoolean OR
!aNegationNegation
cond ? a : bChoosing a value by conditionChoosing a value by condition
TypesList
Vector2Vector2(13)
Vector3Vector3(15)
Vector4Vector4(11)
Color4Color4(2)
intInteger versions of Mathf
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);
}
[Kernel]
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);
}
[Kernel]
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);
}
[Kernel]
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);
}
}

Besides +=, you can write -= *= /=.

using UnityEngine;
using Tsukimi;
public class ParCompoundAssignmentMore : 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)
{
float v = prev[id].R;
// Besides +=, you can write -= *= /=
v -= 0.1f;
v *= 2f;
v /= 4f;
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);
}
[Kernel]
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);
}
}

They can be written only as a statement or in the increment of a for.

using UnityEngine;
using Tsukimi;
public class ParIncrementPrefix : 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)
{
int n = id.X;
// Prefix ++ and --, and postfix --, can also be written as statements
++n;
--n;
n--;
return new Color4(n * 0.01f, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
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);
}
[Kernel]
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);
}
[Kernel]
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);
}
}

switch is lowered to a chain of ifs.

using UnityEngine;
using Tsukimi;
public class ParSwitch : 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)
{
float v = 0f;
switch (id.X % 3)
{
case 0: v = prev[id].R; break;
case 1: v = prev[id].G; break;
default: v = prev[id].B; break;
}
return new Color4(v, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Several case labels can be stacked on one arm.

using UnityEngine;
using Tsukimi;
public class ParSwitchMultiCase : 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)
{
int n = id.X % 4;
float v = 0f;
switch (n)
{
// Several case labels can be stacked on one arm
case 0:
case 1:
v = 0.25f;
break;
case 2:
v = 0.5f;
break;
default:
v = 1f;
break;
}
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 ParEarlyReturn : 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)
{
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);
}
}
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);
}
[Kernel]
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);
}
}

One for can declare 2 variables, and can have 2 incrementors.

using UnityEngine;
using Tsukimi;
public class ParForMultiDeclaration : 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)
{
float v = 0f;
// One for can declare 2 variables and have 2 incrementors
for (int i = 0, j = 3; i < j; i++, j--)
{
v += prev[id.Offset(i, j)].R;
}
return new Color4(v * 0.5f, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

The initializer can also be an assignment to a variable declared earlier.

using UnityEngine;
using Tsukimi;
public class ParForAssignInit : 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)
{
int i;
float v = 0f;
// The initializer need not be a declaration; assigning to a variable declared earlier works
for (i = 0; i < 4; i++)
{
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);
}
}
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);
}
[Kernel]
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 ParDoWhile : 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)
{
float v = 0f;
int i = 0;
do { v = v + prev[id.Offset(i, 0)].R; i++; } while (i < 4);
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 ParBreak : 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)
{
float v = 0f;
for (int i = 0; i < 8; i++)
{
if (prev[id.Offset(i, 0)].R > 0.5f) { break; }
v = v + 0.125f;
}
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 ParContinue : 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)
{
float v = 0f;
for (int i = 0; i < 4; i++)
{
if (i == 2) { continue; }
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);
}
}
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);
}
[Kernel]
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);
}
}
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);
}
[Kernel]
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);
}
}

Write a float constant by appending 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);
}
[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);
}
}
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);
}
[Kernel]
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);
}
}
using UnityEngine;
using Tsukimi;
public class ParFloatArith : 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)
{
float a = prev[id].R;
float b = prev[id].G;
// Arithmetic between floats
float v = (a - b) / 2f + a * b;
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 ParBoolLogic : 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)
{
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 ParBoolOr : 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)
{
bool a = id.X > 8;
bool b = id.Y > 8;
// Logical OR of booleans
return new Color4(a || 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);
}
[Kernel]
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);
}
[Kernel]
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);
}
}

== and != can be written between integers and between floats.

using UnityEngine;
using Tsukimi;
public class ParEquality : 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)
{
int n = id.X % 4;
float f = prev[id].R;
// == and != work between integers and between floats
bool a = n == 3;
bool b = f != 0f;
return new Color4(a ? 1f : 0f, b ? 1f : 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
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);
}
[Kernel]
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);
}
[Kernel]
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);
}
}
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);
}
[Kernel]
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);
}
}
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);
}
[Kernel]
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);
}
}

% computes an integer remainder.

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);
}
[Kernel]
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);
}
}

% can also be written between floats.

using UnityEngine;
using Tsukimi;
public class ParModuloFloatOperator : 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)
{
float f = prev[id].R * 4f;
// % also works between floats
float v = f % 1f;
return new Color4(v, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Use Mathf.Repeat to wrap into the range from 0 to the length.

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);
}
[Kernel]
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);
}
}

Bitwise operations between integers can be written.

using UnityEngine;
using Tsukimi;
public class ParBitwiseAnd : 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)
{
int n = id.X & 3;
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 ParBitwiseOrXor : 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)
{
// | and ^ also work between integers
int n = (id.X | 1) ^ 2;
return new Color4((n & 3) * 0.25f, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

It can be written only for integers.

using UnityEngine;
using Tsukimi;
public class ParBitwiseNot : 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)
{
// ~ is bitwise NOT (integers only)
int n = ~id.X & 3;
return new Color4(n * 0.25f, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Left and right shifts between integers can be written.

using UnityEngine;
using Tsukimi;
public class ParShift : 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)
{
int n = id.X << 1;
return new Color4(n * 0.001f, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
using UnityEngine;
using Tsukimi;
public class ParShiftRight : 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)
{
int n = (id.X >> 1) & 3;
return new Color4(n * 0.25f, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Arguments can be passed by name.

using UnityEngine;
using Tsukimi;
public class ParNamedArguments : 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)
{
// Arguments can be passed by name. They are reordered into declaration order, not the order written
Color4 c = prev[id.Offset(dy: 1, dx: 0)];
float t = Mathf.Lerp(t: 0.5f, a: 0f, b: c.R);
return new Color4(a: 1f, r: t, g: 0f, b: 0f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
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);
}
[Kernel]
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);
}
}

Addition and subtraction between Vector2 values can be written.

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);
}
[Kernel]
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 ParVector2Scale : 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)
{
Vector2 v = new Vector2(prev[id].R, prev[id].G);
// Multiplication and division by a float, and sign negation
Vector2 a = v * 0.5f;
Vector2 b = 0.5f * v;
Vector2 c = v / 2f;
Vector2 d = -v;
return new Color4(a.x, b.y, c.x, d.y + 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Component-wise multiplication and division of 2-component values

Section titled “Component-wise multiplication and division of 2-component values”

* and / between Vector2 values are the component-wise product and quotient.

using UnityEngine;
using Tsukimi;
public class ParVector2Componentwise : 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)
{
Vector2 v = new Vector2(prev[id].R, prev[id].G);
Vector2 w = new Vector2(0.5f, 2f);
// * and / between Vector2 values are the component-wise product and quotient
Vector2 p = v * w;
Vector2 q = v / w;
return new Color4(p.x, p.y, q.x, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

== between Vector2 values is the same approximate comparison Unity uses.

using UnityEngine;
using Tsukimi;
public class ParVector2Equality : 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)
{
Vector2 v = new Vector2(prev[id].R, prev[id].G);
bool same = v == new Vector2(0f, 0f);
return new Color4(same ? 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 ParVector2Inequality : 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)
{
Vector2 v = new Vector2(prev[id].R, prev[id].G);
Vector2 w = new Vector2(0.5f, 0.5f);
// != is the same approximate comparison as ==
bool differs = v != w;
return new Color4(differs ? 1f : 0f, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Assigning to a component of a 2-component value

Section titled “Assigning to a component of a 2-component value”

You can assign to a component of a local variable.

using UnityEngine;
using Tsukimi;
public class ParVector2ComponentWrite : 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)
{
Vector2 v = new Vector2(0f, 0f);
// You can assign to a component of a local variable
v.x = prev[id].R;
v.y = 1f;
return new Color4(v.x, v.y, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Compound assignment to a 2-component value

Section titled “Compound assignment to a 2-component value”
using UnityEngine;
using Tsukimi;
public class ParVector2CompoundAssignment : 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)
{
Vector2 v = new Vector2(prev[id].R, prev[id].G);
Vector2 w = new Vector2(0.25f, 0.25f);
// Compound assignment also works on Vector2
v += w;
v -= w;
v *= 2f;
v /= 2f;
return new Color4(v.x, v.y, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Vector3 and Vector4 support construction, reading components, addition and subtraction, and multiplication and division by a float.

using UnityEngine;
using Tsukimi;
public class ParVector3Value : 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)
{
Vector3 v = new Vector3(1f, 0f, 0f);
return new Color4(v.x, 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
using UnityEngine;
using Tsukimi;
public class ParVector4Value : 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)
{
// Construct a 4-component value and read its components
Vector4 p = new Vector4(prev[id].R, 0f, 0f, 1f);
return new Color4(p.x, p.y, p.z, p.w);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
using UnityEngine;
using Tsukimi;
public class ParVector3Ops : 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)
{
Vector3 a = new Vector3(prev[id].R, 0f, 0f);
Vector3 b = new Vector3(0f, 1f, 0f);
// Addition, subtraction, multiplication and division by a float, and sign negation (component-wise * and / are Vector2 only)
Vector3 s = a + b;
Vector3 d = a - b;
Vector3 m = a * 0.5f;
Vector3 n = 0.5f * a;
Vector3 q = a / 2f;
Vector3 neg = -a;
return new Color4(s.x, d.y + 1f, m.x + n.x + q.x, neg.x + 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
using UnityEngine;
using Tsukimi;
public class ParVector4Ops : 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)
{
Vector4 p = new Vector4(prev[id].R, 0f, 0f, 1f);
Vector4 q = new Vector4(0f, 1f, 0f, 0f);
// The same operators as Vector3
Vector4 s = p + q;
Vector4 d = p - q;
Vector4 m = p * 0.5f;
Vector4 n = 0.5f * p;
Vector4 h = p / 2f;
Vector4 neg = -p;
return new Color4(s.x, d.y + 1f, m.x + n.x + h.x, neg.w + 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

== and != between Vector3 values are the same approximate comparison as for Vector2.

using UnityEngine;
using Tsukimi;
public class ParVector3Equality : 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)
{
Vector3 a = new Vector3(prev[id].R, 0f, 0f);
Vector3 b = new Vector3(0.5f, 0f, 0f);
// == and != between Vector3 values are the same approximate comparison as for Vector2
bool same = a == b;
bool differs = a != b;
return new Color4(same ? 1f : 0f, differs ? 1f : 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
using UnityEngine;
using Tsukimi;
public class ParVector4Equality : 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)
{
Vector4 p = new Vector4(prev[id].R, 0f, 0f, 1f);
Vector4 q = new Vector4(0.5f, 0f, 0f, 1f);
// == and != between Vector4 values are approximate comparisons too
bool same = p == q;
bool differs = p != q;
return new Color4(same ? 1f : 0f, differs ? 1f : 0f, 0f, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Assigning to a component of a 3- or 4-component value

Section titled “Assigning to a component of a 3- or 4-component value”
using UnityEngine;
using Tsukimi;
public class ParVectorComponentWrite : 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)
{
Vector3 a = new Vector3(0f, 0f, 0f);
Vector4 p = new Vector4(0f, 0f, 0f, 0f);
// You can also assign to components of Vector3 and Vector4
a.z = prev[id].R;
p.w = 1f;
return new Color4(a.z, 0f, 0f, p.w);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Compound assignment to a 3- or 4-component value

Section titled “Compound assignment to a 3- or 4-component value”
using UnityEngine;
using Tsukimi;
public class ParVectorCompoundAssignment : 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)
{
Vector3 a = new Vector3(prev[id].R, 0f, 0f);
Vector4 p = new Vector4(0f, 0f, 0f, 1f);
// Compound assignment also works on Vector3 and Vector4
a += new Vector3(0f, 0.5f, 0f);
a *= 0.5f;
p -= new Vector4(0f, 0f, 0f, 0.5f);
p /= 2f;
return new Color4(a.x, a.y, 0f, p.w + 0.75f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
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);
}
[Kernel]
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);
}
}
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);
}
[Kernel]
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);
}
}
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);
}
[Kernel]
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);
}
}

Each of the 4 components is divided.

using UnityEngine;
using Tsukimi;
public class ParCellDivide : 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)
{
// Dividing by a float divides each of the 4 components
Color4 c = prev[id] / 2f;
return new Color4(c.R, c.G, c.B, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

It is the component-wise product.

using UnityEngine;
using Tsukimi;
public class ParCellMultiply : 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)
{
// * between Color4 values is the component-wise product
Color4 c = prev[id] * prev[id.Offset(1, 0)];
return new Color4(c.R, c.G, c.B, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

Constructing from 3 components and an alpha

Section titled “Constructing from 3 components and an alpha”

It can be built from a Vector3 color and a float alpha.

using UnityEngine;
using Tsukimi;
public class ParCellFromVector3 : 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)
{
Vector3 rgb = new Vector3(prev[id].R, 0f, 0f);
// Built from a 3-component color and an alpha
return new Color4(rgb, 1f);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

A Vector4 value can be used directly as a color.

using UnityEngine;
using Tsukimi;
public class ParCellFromVector4 : 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)
{
Vector4 v = new Vector4(prev[id].R, 0f, 0f, 1f);
// A 4-component value can be used directly as a color
return new Color4(v);
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}
using UnityEngine;
using Tsukimi;
public class ParCellCompoundAssignment : 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];
// Compound assignment also works on Color4 (+= -= take a Color4, *= a float or a Color4, /= a float)
c += Color4.Black;
c -= Color4.Black;
c *= 0.5f;
c *= prev[id];
c /= 2f;
return c;
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

You can assign to a component of a local variable.

using UnityEngine;
using Tsukimi;
public class ParCellComponentWrite : 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];
// You can assign to a component of a local variable
c.R = 0.5f;
c.A = 1f;
return c;
}
void Update()
{
Gpu.Run(nameof(Step), next, current);
Gpu.Swap(ref current, ref next);
}
}

A constant is replaced with its value at compile time.

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);
}
[Kernel]
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);
}
}
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);
}
[Kernel]
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);
}
}

Same name as a reserved word in the compile target

Section titled “Same name as a reserved word in the compile target”

A name that collides with a reserved word on the shader side is renamed at compile time.

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);
}
[Kernel]
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);
}
}