- Set up context with canvas element
const canvas = document.querySelector('canvas')
const gl = canvas.getContext('webgl')
- Create Program
const program = gl.createProgram()
- Create, compile and attach shaders to program
const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
const vShaderSource = `
attribute vec2 position;
void main() {
gl_PointSize = 20.0;
gl_Position = vec4(position / 2.0, 0, 1);
}
`
const fShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
`
function compileShader(shader, source) {
gl.shaderSource(shader, source)
gl.compileShader(shader)
const log = gl.getShaderInfoLog(shader)
if (log) throw new Error(log)
}
compileShader(vertexShader, vShaderSource)
compileShader(fragmentShader, fShaderSource)
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
- Link and use program
gl.linkProgram(program)
gl.useProgram(program)
-
For each attribute passed from Javascript
- Get attrib location/pointer from shader
const positionPointer = gl.getAttribLocation(program, 'position')
- Create data (ex. Float32)
const positionData = new Float32Array([ -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0 ])
- Create buffer
const positionBuffer = gl.createBuffer(gl.ARRAY_BUFFER)
- Bind buffer
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
- Buffer data
gl.bufferData(gl.ARRAY_BUFFER, positionData, gl.STATIC_DRAW)
- Enable vertex attrib array
gl.enableVertexAttribArray(positionPointer)
- Vertex attrib pointer
const attributeSize = 2 const type = gl.FLOAT const normalized = false const stride = 0 const offset = 0 gl.vertexAttribPointer(positionPointer, attributeSize, type, normalized, stride, offset)
-
For each uniform passed from Javascript
- Get uniform location/pointer from shader
const resolutionUniformLocation = gl.getUniformLocation(program, 'resolution')
- Set value of pointer
gl.uniform2fv(resolutionUniformLocation, [canvas.width, canvas.height])
-
For each index buffer passed from Javascript
- Create data
const indexData = new Uint8Array([ 0, 1, 2, 1, 2, 3 ])
- Create buffer
const indexBuffer = gl.createBuffer(gl.ARRAY_BUFFER)
- Bind buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
- Buffer data
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexData, gl.STATIC_DRAW)
-
For each texture passed from Javascript
- Use a vertex shader like this
attribute vec2 position; void main() { gl_Position = vec4(position, 0, 1); }
- Use a fragment shader like this
precision mediump float; uniform sampler2D texture; uniform vec2 resolution; void main() { vec2 texCoord = gl_FragCoord.xy / resolution; gl_FragColor = texture2D(texture, texCoord); }
- Draw a rectangle
const vertexPositionData = new Float32Array([ -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, ]) const vertexPositionBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer) gl.bufferData(gl.ARRAY_BUFFER, vertexPosition, gl.STATIC_DRAW) const attributeLocations = { position: gl.getAttribLocation(program, 'position'), } const uniformLocations = { texture: gl.getUniformLocation(program, 'texture'), resolution: gl.getUniformLocation(program, 'resolution') } gl.enableVertexAttribArray(attributeLocations.position) gl.vertexAttribPointer(attributeLocations.position, 2, gl.FLOAT, false, 0, 0) gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexPositionData.length / 2)
- Load image
export async function loadImage(src) { const img = new Image() let _resolve const p = new Promise((resolve) => _resolve = resolve) img.onload = () => { _resolve(img) } img.src = src return p } import textureImageSrc from '../assets/images/texture.jpg' loadImage(textureImageSrc).then((textureImg) => { const texture = gl.createTexture() gl.bindTexture(gl.TEXTURE_2D, texture) gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1) gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImg ) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.activeTexture(gl.TEXTURE0) gl.uniform1i(uniformLocations.texture, 0) gl.uniform2fv(uniformLocations.resolution, [canvas.width, canvas.height]) gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0) })
-
Draw to context
- If using index buffer
gl.drawElements(gl.TRIANGLES, indexData.length, gl.UNSIGNED_BYTE, 0)
- Else
gl.drawArrays(gl.TRIANGLES, 0, positionData.length / 2)