Skip to content
Jérôme Leclercq edited this page Apr 15, 2025 · 4 revisions

Introduction

NZSL is a strong typed shading language, inspired by C++ and Rust, with a syntax aimed at being easy to use yet very clear about what it does.

Here's a short example of a fragment/vertex shader which outputs vertex color, first in GLSL then the equivalent NZSL code.

GLSL vertex shader:

#version 450

layout(std140, binding = 0) uniform Matrices
{
	mat4 projection;
	mat4 view;
	mat4 model;
} matrices;

layout(location = 0) in vec3 vertPos;
layout(location = 1) in vec3 vertColor;
layout(location = 0) out vec3 fragColor;

void main()
{
	vec4 worldPos = matrices.model * vec4(vertPos, 1.0);
 
	gl_Position = matrices.projection * matrices.view * worldPos;
	fragColor = vertColor;
}

GLSL fragment shader:

#version 450

layout(location = 0) in vec3 vertColor;
layout(location = 0) out vec3 outputColor;

void main()
{
	outputColor = vertColor;
}

And here's the equivalent NZSL shader:

[nzsl_version("1.0")]
module;

[layout(std140)]
struct Matrices
{
	projection: mat4[f32],
	view: mat4[f32],
	model: mat4[f32]
}

external
{
	[binding(0)] matrices: uniform[Matrices]
}

struct VertIn
{
	[location(0)] pos: vec3[f32],
	[location(1)] color: vec4[f32]
}

struct VertOut
{
	[location(0)] color: vec4[f32],
	[builtin(position)] pos: vec4[f32]
}

[entry(vert)]
fn main(input: VertIn) -> VertOut
{
	let worldPos = matrices.model * vec4[f32](input.pos, 1.0);

	let output: VertOut;
	output.pos = matrices.projection * matrices.view * worldPos;
	output.color = input.color;
	return output;
}

struct FragOut
{
	[location(0)] color: vec4[f32]
}

[entry(frag)]
fn main(input: VertOut) -> FragOut
{
	let output: FragOut;
	output.color = input.color;
	return output;
}

So if you're familiar with HLSL or GLSL, it should feel familiar yet a bit different.

First of all, it's a bit more verbose than GLSL by choice (vec3[f32] instead of vec3 for example), but it also has type inference and allows you to define multiple shaders stages inside of the same file (it also has modules which are described on their own page).

Basic Types

Primitive types

  • bool: boolean value taking true or false
  • f32: 32bits floating-point value (commonly called float)
  • f64: 64bits floating-point value (commonly called double) - requires the float64 feature (see module declaration)
  • i32: Signed 32bits integer
  • u32: Unsigned 32bits integer
  • (): No type, rarely used

Vector types

Vector types are made of primitive types, using [] as a type specifier, giving vecN[type] syntax (with N between 2 and 4), for example:

  • vec3[f32] is a three components vector made of 32bits floating-point values
  • vec2[bool] is a two components vector made of bool values.

Matrix types

Matrix types are declared using:

  1. matNxM[type]: A matrix with n columns and m rows (examples: mat2x2, mat4x3).
  2. matn[type]: Common shorthand for matNxN[type] which is a square matrix with n columns and n rows.

Attributes

NZSL allows one to tag statements and expressions with attributes with the following form: [attr] statement or [attr(value)] statement.

This is used to give important parameters to the compiler, for example to declare the entry point of a shader you would write:

[entry(frag)] //< attribute entry with frag as a parameter
fn main()
{
    // ...
}

The module statement

Modules are the basic compilation unit of NZSL, each module is compiled separately.

The very first statement of a NZSL file should be the module statement, for example:

// You can have comments here
[nzsl_version("1.0")]
module;

This declares an anonymous module.

Module can also be named in the following way:

[nzsl_version("1.0")]
module MyEngine.MyModule; //< a module name can take multiple identifiers separated (or not) by a dot

Naming a module may be useful to import it in another module.

The module statement requires a nzsl_version attribute, taking a string parameter which much follow the versionning schema of NZSL x.y(.z), for now only the 1.0 version is valid. This indicates the NZSL version used to write this module, allowing the language to break retrocompatibility in future update if required without breaking existing shader files (as explained here).

The module statement can also take the following attributes:

  • author: takes a string, indicates the module author (can only appear once), has no semantic meaning.
  • desc: takes a string, gives the module a description (can only appear once), has no semantic meaning.
  • license: takes a string, indicates the module license (can only appear once), has no semantic meaning.
  • feature: takes a ModuleFeature, enables the usage of an additional feature for this module.

A complete example is:

[nzsl_version("1.0")]
[author("Lynix")]
[desc("A simple example module")]
[license("Public domain")]
[feature(float64), feature(texture1D)]
module Examples.Name;

Struct declaration

Function declaration

Variable declaration

Aliases

Clone this wiki locally