Resources are referenced from the following links:
- webgl is a state machine and a graphic pipeline. It holds an internal state and allow user update them.
- When ready to render, there are a handful of methods webgl provides to 'clear' the viewport, with the current internal state defined.
- We are always drawing 3D object in canvas using webgl.
- Nearly all webgl APIs are for setting up the webgl state. After that, you will need to call pairs of functions (or programs) with vertex shader and fragment shader to execute the draw methods.
- WebGL only cares about 2 things: clipspace coordinates and colors. Your job as a programmer using WebGL is to provide WebGL with those 2 things. You provide your 2 "shaders" to do this. A Vertex shader which provides the clipspace coordinates and a fragment shader that provides the color. ref
- There are essentially two steps for webgl to draw anything:
- Init phase (prepare buffers). You need to prepare model buffers and bind model data in them. You need to also init shaders to generate program.
- Draw phase (read buffers). You need to take shader program and matrices (model matrix, projection matrix, model view matrix) from buffers as your input, to call one of the webgl draw methods to draw all the pixels
- Common procedure of using webgl is as following:
- Detect webgl in executing environment (feature detection)
- Set webgl viewport dimension so that webgl knows how to convert the clipspace to pixels
- Mutate webgl internal states
- clear or other method triggers rendering
- Detecting webgl can be done with
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
and checkgl
. The difference betweenwebgl
context andexperimental-webgl
context can be found here. Basicallyexperimental-webgl
will be deprecated. - Setting canvas dimension (width and height) will automatically set the webgl drawing buffer dimensions in init phase. However after that you need to update the size and viewport if you change the canvas dimension. See this great article for details.
- You should always use CSS to set the display size for canvas, and use
clientWidth
andclientHeight
to set the actual pixel size in JS. This is the most flexible way to control dimensions. - For high-definition DPI display or Retina display, use
window.devicePixelRatio
to make sure the actual pixel dimensions are the same to display dimensions set by CSS. - It's a common optimization in games to actually render less pixels than are displayed and let the GPU scale them up. ref
- Unlike browser window or canvas, the vertical position in webgl is measured from bottom to top.
- Colors in webgl go from 0 to 1.
- There are two shader functions/programs runs when drawing webgl content:
vertex shader
andfragment shader
. On a high level,vertex shader
defines the geometry of the 3D object (by rasterizing the states), andfragment shader
defines the colors, lights, textures on the 3D object (by applying them on each pixel). - In shader functions, we have the following data types
attribute
andbuffer
: Similar to data view and array buffer in JSuniform
: Similar to global variables in JStexture
: Similar to array variable in JS to hold data you can randomly access. For exampleimageData
varying
: An adaptor from vertex shader to fragment shader
- One typical workflow for shader program is ref
- Initialization phase
- create webgl context from canvas
- create vertex shader and fragment shader programs (most likely in string format)
- create buffer and bind it to webgl
- bind data to buffer
- Render phase
- resize canvas to display size
- resize the viewport so that clipspace can convert to pixel space
- clear canvas to prepare for rendering
- tell webgl to use the program
- get the attribute location and enable it
- bind vertex attribute pointer and tell webgl how to set value from buffer
- tell webgl how to draw and execute the draw function
- Initialization phase
gl.COLOR_BUFFER_BIT
ref: webgl constant indicates the buffers currently enabled for color writing.gl.SCISSOR_TEST
ref: Scissoring operation. Aftergl.enable(gl.SCISSOR_TEST)
, you can callgl.scissor(x, y, width, height)
to define the scissoring area, which will be actually affected by following clear commands.
gl.clear(mask)
ref: Clear the drawing buffer to the preset values that are indicated by mask.gl.clearColor(r, g, b, a)
ref: Clear the drawing buffer with given color.gl.colorMask(r, g, b, a)
ref: Set the color mask with booleans on red, green, blue and alpha channels. When a channel mask is off, the color in that channel won't be rendered even it's set in internal state.gl.scissor(x, y, width, height)
ref: Define scissoring area for further rendering. Note thaty
is from bottom up.gl.createShader(type)
: Create a vertex or fragment shader.gl.shaderSource(shader, source)
: Set the source for a given shader.gl.compileShader(shader)
: Compile the source code for given shader.gl.getShaderParameter(shader, parameterName)
: Get the shader's parameter by given parameter name.gl.getShaderInfoLog(shader)
: Get the shader's log for debugging.gl.deleteShader(shader)
: Dispose the shader from webgl context.gl.createProgram()
: Create a program.gl.attachShader(program, shader)
: Attach a shader into program. A program is composited by a vertex shader and a fragment shader.gl.linkProgram(program)
: Linking program which will generate executable internally.gl.getProgramParameter(program, parameterName)
: Get the program's parameter by given parameter name.gl.getProgramInfoLog(program)
: Get the program's log for debugging.gl.deleteProgram(program)
: Dispose the program from webgl context.gl.getAttribLocation(program, attributeName)
: Get the program's attribute name.gl.createBuffer()
: Create a buffer for webgl. webgl uses buffer to store binary data.gl.bindBuffer(bufferType, buffer)
: Bind a buffer to the bind point for webgl, so that consumer can pass data into webgl program.gl.bufferData(bufferType, stronglyTypedData, hintEnumOnHowToUseData)
: Pass the data into the buffer that of thebufferType
type.