WebGL: Drawing Sprite
Related Topics: Texture
Overview

Sprite or Billboard in 3D is commonly defined as a 2D rectangular plane with applying a texture map on it, and it is always facing to the camera. Sprite is orientation invarient for all 3 axis, but billboard is 2-axis invarient, normally Y-axis is fixed (always straight up on the ground).
To define a sprite, you need 4 vertex positions; v0, v1, v2, and v3 to constuct a quad, and texture coordinates for each vertex as well. It can be drawn by a single gl.TRIANGLE_STRIP; v0-v1-v2-v3.
The diagram shows a sprite on the XY plane (z=0) and the vertex positions by the given width and height of the sprite.
Sprite Class
With Sprite class, you can easily create a sprite in WebGL application, which is always facing to the screen. It also provides draw() function to draw the sparite with a built-in VBO. Common interfaces of Sprite class are;
Sprite | |
---|---|
Function | Description |
setSize(w,h) | Update the size of this with the given width and height |
setPosition(x,y,z) | Update the position of this |
setTexture(texId) | Update the texture map of this |
draw() | Draw this sprite |
A typical usage of Sprite class is;
// global object
gl = {};
...
// load texture
gl.tex0 = loadTexture(gl, "grid512.png");
// create sprite and configure it
gl.sprite = new Sprite(gl);
gl.sprite.setPostion(1, 2, 3); // translate
gl.sprite.setSize(5, 5); // width and height
gl.sprite.setTexture(gl.tex0); // assign texture
...
// draw sprite
gl.sprite.draw();
...
Matrix for Sprite
To make the orientation of sprites stationary, you need to override the rotation part of the view matrix. It can be done in the JavaScript in your WebGL application.
// in JavaScript
// construct model-view matrix
let matrix = gl.matrixView.clone().multiply(gl.sprite.matrix);
// then, lock the rotation part
matrix.setLeftAxis(1, 0, 0);
matrix.setUpAxis(0, 1, 0);
matrix.setForwardAxis(0, 0, 1);
// finally, construct model-view-projection matrix
matrix = gl.projectionMatrix.clone().multiply(matrix);
// pass MVP matrix to shader
gl.uniformMatrix4fv(gl.program.uniform.matrixMVP, false, matrix.m);
Or, you can reset the orientation of the view mareix in the vertex shader. For this case, you have pass the view matrix to the shader separately. Please see gles_sprite.vert for details.
// in Vertex Shader
// constants
const float ZERO = 0.0;
const float ONE = 1.0;
// vertex attributes
attribute vec3 vertexPosition;
attribute vec2 vertexTexCoord0;
// uniforms
uniform mat4 matrixModel;
uniform mat4 matrixView;
uniform mat4 matrixProjection;
// output varying variables
varying vec2 texCoord0;
void main(void)
{
mat4 matMV = matrixView * matrixModel;
// lock rotation of modelview matrix
matMV[0] = vec4(ONE, ZERO, ZERO, ZERO); // first column (left axis)
matMV[1] = vec4(ZERO, ONE, ZERO, ZERO); // second column (up axis)
matMV[2] = vec4(ZERO, ZERO, ONE, ZERO); // third column (forward axis)
mat4 matMVP = matrixProjection * matMV;
gl_Position = matMVP * vec4(vertexPosition, ONE);
// pass texture coord
texCoord0 = vertexTexCoord0;
}
Example
This example draws multiple sprites, and measures the elapased time per frame. Computing the transform matrix in GLSL shader program is slight faster than computing in JavaScript.
Fullscreen Demo: test_sprite.html
GitHub Repo: test_sprite.html