Scalar types
| Type | Size | Use it for |
|---|---|---|
float |
32-bit floating-point | Most values: positions, UVs, colors, time. |
half |
16-bit floating-point | Colors and normalized directions, where lower precision is enough. Faster on many mobile GPUs. |
int |
32-bit signed integer | Counters, indices, bit operations. |
uint |
32-bit unsigned integer | Bit operations and hashing. |
bool |
true or false | Conditions. |
Other C# numeric types, such as long, short, byte, char or decimal, aren't supported.
Note
double isn't supported, and there are no double vectors or matrices. Most GPUs don't support double precision at all: Metal, mobile GPUs and WebGL have none, and on desktop GPUs it's an optional feature that runs much slower than float. Using double in shader code is an error (SSG3001). Numbers without the f suffix, such as 0.5, and const double values still work: they're computed at compile time and reach the shader as float.
Literals
Literals are written as in C#: 1.5f is a float, 2 is an int, 2u is a uint. Hexadecimal (0xFF), digit separators (1_000) and exponents (1e-3f) work too. There's no half literal: write (half)0.5f.
Conversions
Conversions follow the C# rules:
intanduintconvert tofloatimplicitly:float f = i;.floatconverts tointonly with a cast, which drops the fractional part:(int)1.7fis 1,(int)-1.7fis -1.floatandhalfconvert both ways implicitly, as in HLSL. An operation that mixeshalfandfloatgives afloat.
Warning
Integer division drops the remainder, in C# as on the GPU: 7 / 2 is 3, even when you assign it to a float. Write 7f / 2 for 3.5.
half precision
A half keeps about 3 significant digits and holds values up to 65504. That's enough for colors and for normalized directions, but not for positions, large UVs or time. On GPUs without half-precision support, half is computed as float, so the code works everywhere; it's only faster where half precision exists.
LitFragmentOutput.albedo and UnlitFragmentOutput.albedo are half3, so a float3 color needs a cast: OUT.albedo = (half3)color.rgb;.