gl.
functionsThe following are presented in order of frequency of use in roughly 200 student’s submissions of 4 WebGL2 assignments.
gl.getUniformLocation
uniform
variable in one or both of those shaders.
Uniforms are generally data sent from the CPU to the GPU once and accessed by all the vertices and/or fragments in the scene. They are commonly used for matrices, textures, and some scene-wide constants like light locations.
Each uniform is given a specific location, a small integer usually between 0 and 15. The shader linker picks these location per program, and may pick different locations each compilation.
gl.bindVertexArray
gl.createVertexArray
, a Vertex Array Object (VAO).
Two related effects.
First, the VAO will record all subsequent calls of
and a few related but uncommon functions.
Second, at the moment of binding, anything recorded by the previously-bound VAO (which may be a default VAO managed by WebGL2 if none was ever bound) will be disabled and anything previously recorded by this VAO will be re-enabled.
gl.vertexAttribPointer
are manually specified, not generated by the compiler.
gl.useProgram
gl.clear
gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT
gl.uniformMatrix4fv
gl.getUniformLocation
, which is a shader program-specific integerfalse
(no other value permitted)Float32Array
containing 16 numbersuniform mat4
in the GPU.
WebGL2 assumes arrays are given in column-major order; that is,
.uniformMatrix4fv(loc, false,
gl1, 2, 3, 4
[ , 5, 6, 7, 8
, 9, 10, 11, 12
,13, 14, 15, 16
])
will create the matrix which is not the order that most programmers expect.
gl.bindBuffer
gl.ARRAY_BUFFER
(for attributes) or gl.ELEMENT_ARRAY_BUFFER
(for indices)gl.createBuffer
, an opaque pointer to an array in GPU memorygl.bindBuffer
might accidentally work if the correct buffer was the last one bound, but then stop working if you later change setup code or the like. To avoid this problem, it is recommended that any JavaScript function that interacts with a buffer calls gl.bindBuffer
before doing so.
gl.bufferData
gl.bindBuffer
)Float32Array
for attributes or Uint16Array
for indicesgl.STATIC_DRAW
for data that will be supplied just once or gl.DYNAMIC_DRAW
for data that will be re-supplied every frameIn more flexible standards like Vulkan, step 4 is not guaranteed as an array might be referenced by multiple buffers, but that can’t happen in WebGL2. Because step 4 is guaranteed in WebGL2, it can be moved to happen earlier in this sequence, often re-using memory from the old array for the new one.
gl.bufferSubData
may be faster as it does not rely on optimizations to avoid allocating more memory.
gl.drawElements
gl.TRIANGLES
gl.bindBuffer
and generally re-enabled via gl.bindVertexArray
gl.UNSIGNED_SHORT
gl.vertexAttribPointer
, primitive connectivity set by the current gl.ELEMENT_ARRAY_BUFFER
, and the shader program set by gl.useProgram
.
The count is a count of indices, not primitives: if you have 10 triangles then the count needs to be 30, not 10.
The offset is in bytes, not indices or primitives: if you want to skip the first 10 triangles and have gl.UNSIGNED_SHORT
indices then the offset is (2 bytes per index) × (3 indices per triangle) × (10 triangles) = 60.
gl.createBuffer
The thing returned by this function does not have a precise parallel in the CPU-only code that you’d used in other classes. It serves primarily as a way of managing GPU memory.
Actions on buffers all requiring using gl.bindBuffer
to link them to one of a fixed set of bind points. The buffer returned by gl.createBuffer
is not used otherwise directly used in your code.
Arrays allocated in GPU memory by gl.bufferData
are attached to the buffer currently bound to the bind point. If a different array is attached to the same buffer or when the buffer is garbage collected by JavaScript, the array is freed.
gl.createBuffer
controls GPU memory management and should be called only as needed. If you want to change data, use gl.bufferData
without re-calling gl.createBuffer
; calling gl.createBuffer
every frame is likely to cause a GPU memory leak.
gl.createBuffer
does not bind its return value; you’ll generally want to follow it with gl.bindBuffer
.
Buffers only store bytes. The data types represented by those bytes is handled by the combination of the data supply functions gl.bufferData
/gl.bufferSubData
and the data use functions gl.vertexAttribPointer
/gl.drawElements
. Mixing and matching types in those calls is very unlikely to work.
gl.attachShader
gl.createProgram
gl.createShader
, after calling gl.shaderSource
and gl.compileShader
on itYou may attach the same shader to as many shader programs as you wish.
Exactly one vertex shader and one fragment shader must be attached to a shader program prior to linking.
Once attached to a shader program, the shader variable is no longer needed.
gl.createShader
gl.VERTEX_SHADER
or gl.FRAGMENT_SHADER
gl.shaderSource
, gl.compileShader
, and gl.attachShader
.
gl.shaderSource
gl.createShader
gl.compileShader
. gl.shaderSource
performs no error checking or any kind; all that is done by gl.compileShader
.
#version 300 es
. Without that, the shader defaults to WebGL1’s shader language which had various differences in syntax and semantics and might cause errors either at compile or run time.
gl.compileShader
gl.createShader
, after calling gl.shaderSource
on it
gl.COMPILE_STATUS
using gl.getShaderParameter
after running this function; without that you can’t tell if the compilation succeeded or not.
gl.getShaderParameter
gl.createShader
gl.getShaderParameter
gl.getShaderParameter
, either true
for success or false
for any compiler error.
Always check the gl.COMPILE_STATUS
after running gl.compileShader
; without that you can’t tell if the compilation succeeded or not.
If the status is false
, use gl.getShaderInfoLog
to learn why the compilation failed.
gl.getShaderInfoLog
gl.createShader
gl.getShaderInfoLog
does not remove the need for gl.getShaderParameter
: the info log might be non-empty even if the compilation succeeds.
gl.uniform1f
gl.getUniformLocation
, which is a shader program-specific integeruniform float
in the GPU.
gl.uniform1f
to set a vec4
, but doing so tends to cause confusion and errors and should be avoided.
gl.clearColor
gl.clear
will replace the entire canvas with, assuming gl.COLOR_BUFFER_BIT
is included in the gl.clear
call.
gl.enableVertexAttribArray
layout(location=...)
in the vertex shader
gl.enableVertexAttribArray
must be called on an attribute location before it is used in any other functions.
gl.vertexAttribPointer
index
: the location of an attribute, as given by layout(location=...)
in the vertex shadersize
: an integer between 1 and 4 (inclusive), indicating how many numbers are in the array per attribute (e.g. for 2D Cartesian vectors this would be 2)type
: a type code, describing how to parse the bytes in the array; typically gl.FLOAT
normalized
: whether to try to convert integers to floats or not; typically false
, ignored if the previous argument was gl.FLOAT
stride
: how many bytes to skip between the end of one attribute value and the start of the next; typically 0
offset
: the index of the first byte of the first value to reach; typically 0
in
variables). Note that this is connected to the attribute, not the buffer, to support cases where multiple attributes are stored in different parts of the same buffer.
The size
argument should be the number of elements per value in the buffer, not in the vertex shader. For example, if you have a vec3
in GLSL being supplied with 2-vectors in the buffer you’d use 2
, not 3
; the GPU will automatically fill in any missing parts of the GLSL declaration with the corresponding coordinate of the homogeneous zero point .
The type
and normalized
arguments are primarily for memory-constrained systems with very large geometries; they should be gl.FLOAT
and false
, respectively, unless you spend time learning the various other formats and how they are mapped to floats.
The stride
and offset
arguments can be used to store several attributes in a single buffer.
If I had a Float32Array
storing position and normal interleaved as
I’d send it to the GPU using gl.bufferData
and tell the GPU to parse it as
let posiLoc = /* the value from layout(location=...) in the vertex shader */
let normLoc = /* the value from layout(location=...) in the vertex shader */
.vertexAttribPointer(posiLoc, 3, gl.FLOAT, 0, 3*4, 0*4)
gl.vertexAttribPointer(normLoc, 3, gl.FLOAT, 0, 3*4, 3*4) gl
where the *4
is is handling the bytes per value in a Float32Array
.
size
is the size of one attribute value, not the entire array.
size
uses the unit of numbers
, while stride
and offset
use the unit of bytes
.
type
must match the format of the typed array passed to gl.bufferData
; for example, Float32Array
must be paired with gl.FLOAT
.
gl.enableVertexAttribArray
must be called on an attribute location before it is used in any other functions, including gl.vertexAttribPointer
.
gl.createProgram
gl.linkProgram
gl.getProgramParameter
gl.getProgramInfoLog
gl.createVertexArray
gl.drawArrays
gl.uniform4fv
gl.uniform1i
gl.enable
gl.viewport
gl.uniform3fv
gl.blendFunc
gl.uniform4f
gl.uniform2fv
gl.uniform2f
gl.texParameteri
gl.activeTexture
gl.disable
gl.uniform1fv
gl.bindTexture
gl.texImage2D
gl.uniformMatrix3fv
gl.uniform4iv
gl.uniform3iv
gl.uniform2iv
gl.getUniform
gl.generateMipmap
gl.detachShader
gl.createTexture
gl.bufferSubData
gl.vertexAttrib3f
gl.validateProgram
gl.uniformMatrix2fv
gl.pixelStorei
gl.getVertexAttrib
gl.getExtension
gl.getActiveUniform
gl.depthFunc
gl.deleteProgram
gl.blendEquation