Skip to content
Rodrigo Braz Monteiro edited this page Apr 2, 2018 · 10 revisions

Overview

Materials describe how a particular draw call (including Sprites and Text Rendering) should look like. They store the following information:

  • The vertex attribute layout
  • The textures/samplers used
  • The uniforms/constants used
  • The drawing passes, and, for each of them:
    • The blend mode used
    • The vertex, geometry and pixel shaders used, for each language supported

Materials may inherit from other materials, copying their original properties and overriding them. Most materials inherit from Halley/SpriteBase, since that defines the standard vertex attribute layout, which, in turn, inherits from Halley/MaterialBase, which allows Halley to inject its MVP matrix into the shader.

A few default materials are provided by Halley, such as:

  • Halley/MaterialBase: Base material that describes the Halley constant block, used for the MVP matrix
  • Halley/SpriteBase: Base material that describes the standard vertex attribute layout used by Halley Sprites
  • Halley/Sprite: Standard alpha blended sprite
  • Halley/SpriteAdd: Standard add blended sprite
  • Halley/SpriteOpaque: Standard opaque blended sprite
  • Halley/SolidColour: Draws a solid colour, without textures
  • Halley/DistanceFieldSprite: Renders images encoded with distance fields
  • Halley/Text: Renders distance field encoded text, with outlines

Declaration

Here's an example material, Halley/Sprite, which ships with Halley:

---
name: Halley/Sprite
base: sprite_base.yaml
textures:
  - tex0: sampler2D
passes:
  - blend: AlphaPremultiplied
    shader:
      - language: glsl
        vertex: sprite.vertex.glsl
        pixel: sprite.pixel.glsl
      - language: hlsl
        vertex: sprite.vertex.hlsl
        pixel: sprite.pixel.hlsl
...

Here's an example that uses multi-texturing and uniforms:

---
name: Wargroove/PaletteSwap
base: sprite_base.yaml
textures:
  - tex0: sampler2D
  - tex1: sampler2D
uniforms:
  - MaterialBlock:
    - playerColour: float
    - skinColour: float
passes:
  - blend: AlphaPremultiplied
    shader:
      - language: glsl
        vertex: sprite.vertex.glsl
        pixel: palette_swap.pixel.glsl
      - language: hlsl
        vertex: sprite.vertex.hlsl
        pixel: palette_swap.pixel.hlsl
...

The name field specifies the name of the material. You'll need to use this name when setting up Sprites or loading the MaterialDefinition from the Resources, for example.

The base field specifies which material should be used as the base. Typically, this will be Halley/SpriteBase.

The attributes field specifies the vertex attribute layout. See below.

The textures field specifies the names and sampler type of textures. Currently only sampler2D is supported. The name of the texture should match the name of the uniform sampler2D in GLSL, but for HLSL, the ORDER of the textures is what matters - the first texture will be bound to register t0 (and sampler s0), and so on. For example, for the second example above:

// GLSL
uniform sampler2D tex0;
uniform sampler2D tex1;
// HLSL
Texture2D tex0 : register(t0);
Texture2D tex1 : register(t1);
SamplerState sampler0 : register(s0);
SamplerState sampler1 : register(s1);

The uniforms field allows you to list blocks of uniforms. See below.

The passes field allows you to list your passes. Most materials only have one pass, but they can have multiple passes. For each draw call, passes are run in order.

Pass properties

Each pass has the following properties:

blend specifies which blend type to use. The following blend modes are supported:

  • Opaque: Does not perform any blending or alpha masking (default)
  • Alpha: Performs standard alpha blending
  • AlphaPremultiplied: Performs premultiplied alpha blending (recommended for sprites)
  • Add: Performs add blend

shader allows you to list groups of shaders. Each group of shader has the following properties:

  • language: Should be hlsl or glsl
  • vertex: Specify the vertex shader file
  • geometry: Specify the geometry shader file (optional)
  • pixel: Specify the pixel/fragment shader file

All shader files should be stored under /assets_src/shader/.

Using MaterialDefinitions and Materials

todo

Using custom uniforms/constants

Using custom vertex attribute layouts

The attributes field of the material lists the attributes and their types. The order and sizes must match the data fed to the vertex buffer, typically from Halley::SpriteVertexAttrib. To this end, most Halley materials derive from Halley/SpriteBase. However, if you're feeding vertices with a different layout, you should also define your own attributes.

The base sprite material:

---
name: Halley/SpriteBase
base: material_base.yaml
attributes:
  - a_vertPos: vec4          # xy = relative position of vertex [0..1], zw = relative position of texture [0..1]
  - a_position: vec2         # position (world space)
  - a_pivot: vec2            # relative pivot [0..1]
  - a_size: vec2             # size (px), should be the size of the texture
  - a_scale: vec2            # scale (relative)
  - a_colour: vec4           # rgba
  - a_texCoord0: vec4        # xy = top-left, zw = bottom-right
  - a_rotation: float        # rotation (radians)
  - a_textureRotation: float # is the sprite rotated? (1 if 90 degrees rotated)
...

Valid attribute types are:

  • float: a single float
  • vec2: a (float, float) vector
  • vec3: a (float, float, float) vector
  • vec4: a (float, float, float, float) vector
  • mat4: a 4x4 float matrix

Note how the material definition above matches Halley::SpriteVertexAttrib:

struct SpriteVertexAttrib
{
	// This structure must match the layout of the shader
	// See shared_assets/material/sprite_base.yaml for reference
	Vector4f vertPos;
	Vector2f pos;
	Vector2f pivot;
	Vector2f size;
	Vector2f scale;
	Colour4f colour;
	Rect4f texRect;
	float rotation = 0;
	float textureRotation = 0;
	char _padding[8];
};

In GLSL, the attributes are passed to the vertex shader by name:

in vec4 a_vertPos;
in vec2 a_position;
in vec2 a_pivot;
in vec2 a_size;
in vec2 a_scale;
in vec4 a_colour;
in vec4 a_texCoord0;
in float a_rotation;
in float a_textureRotation;

However, in HLSL, the name is stripped of its prefix, converted to uppercase, and used as the name of the semantics:

struct VIn {
    float4 vertPos : VERTPOS;
    float2 position : POSITION;
    float2 pivot : PIVOT;
    float2 size : SIZE;
    float2 scale : SCALE;
    float4 colour : COLOUR;
    float4 texCoord0 : TEXCOORD0;
    float rotation : ROTATION;
    float textureRotation : TEXTUREROTATION;
};

Because of this, you always need an attribute named a_position, so HLSL gets its mandatory POSITION semantic.

Clone this wiki locally