08 August 2020

Using Hiero Font Tool to create a distance field font to use with shaders

This article is about text rendering with a 3D graphics library, like OpenGL. A regular font atlas texture doesn't scale well. To render text that looks sharp at any size, you need a distance field texture atlas. Hiero is a tool that can create such a font. It requires Java.

  • Pick a font (system or file) and the characters you want (sample text).
  • Set Rendering to Java, so the effects are listed.
  • Remove the Color effect and add a Distance field effect.
  • Set it's Scale to 15 and Spread to 10. This high scale will make the sample slow to regenerate, so maybe do this last.
  • At the right-bottom, set X and Y to 0 and the four Padding values to 8.
  • Increase or decrease the Size of the glyphs, so they all fit on one page.

Now you can save the font. Hiero will create a png image of the glyphs and a fnt file describing their positions and sizes. With these, you can generate textured quads for your text. A specific fragment shader will use the distance fields in the texture to render sharp text.

21 July 2020

Math - Calculate a look-at matrix for OpenGL (II)

This is a simplification of the method to create a look-at or camera matrix from 2017. Based on DirectX documentation, it creates the matrix in one step, without multiplication. The matrix is created transposed for OpenGL. This method takes in a Vector3 Position and Direction.

This matrix doesn't work when looking straight up or down, because in that case the x-axis cross product fails. To solve this, manually set the x-axis in that case.

bool isVertical = direction.X == 0 && direction.Z == 0;
var up = new Vector3(0, 1, 0);
var zAxis = direction.Normalized();
var xAxis = isVertical ? new Vector3(1, 0, 0) : Vector3.CrossProduct(up, zAxis).Normalized();
var yAxis = Vector3.CrossProduct(zAxis, xAxis);

return new Matrix(
    xAxis.X, xAxis.Y, xAxis.Z, -Vector3.DotProduct(xAxis, position),
    yAxis.X, yAxis.Y, yAxis.Z, -Vector3.DotProduct(yAxis, position),
    zAxis.X, zAxis.Y, zAxis.Z, -Vector3.DotProduct(zAxis, position),
    0, 0, 0, 1
);

19 April 2020

OpenGL - Billboarding in the vertex shader

All of the particles of a particle system are typically billboarded to always face the camera. At first, you do this by calculating a model matrix for each particle and send it to the instance buffer. You could also just send the particle's position and calculate the model matrix in the vertex shader:

mat4 model = mat4(1); //Identity matrix
model = translate(model, position);

This requires a function to translate a matrix, which GLSL doesn't have, so you provide one.

mat4 translate(mat4 m, vec3 p)
{
    m[3][0] = m[0][0] * p.x + m[1][0] * p.y + m[2][0] * p.z + m[3][0];
    m[3][1] = m[0][1] * p.x + m[1][1] * p.y + m[2][1] * p.z + m[3][1];
    m[3][2] = m[0][2] * p.x + m[1][2] * p.y + m[2][2] * p.z + m[3][2];
    m[3][3] = m[0][3] * p.x + m[1][3] * p.y + m[2][3] * p.z + m[3][3];
    return m;
}

You then multiply this model matrix with the camera (view) matrix. It is the resulting modelView matrix that you want to billboard by removing the rotation from it:

mat4 billboard(mat4 m)
{
    m[0][0] = 1;
    m[0][1] = 0;
    m[0][2] = 0;

    m[1][0] = 0;
    m[1][1] = 1;
    m[1][2] = 0;

    m[2][0] = 0;
    m[2][1] = 0;
    m[2][2] = 1;

    return m;
}