// Define geometry
var vertexPositionData = [
0.0, 0.0, 0.0, // vertex 0 position
1.0, 0.0, 0.0, // vertex 1 position
// ...
];
var vertexTexCoordData = [
0.0, 0.0, // vertex 0 tex coord
1.0, 0.0, // vertex 1 tex coord
// ...
];
var indexData = [
0, 1, 2, // indices of triangle 0
0, 3, 2, // indices of triangle 1
// ...
];
// Send data to the GPU
var vertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositionData), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var vertexTexCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexTexCoordData), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
// Draw the geometry
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
var positionLocation = gl.getAttribLocation(program, "position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 4 * 3, 0); // 12 bytes per vertex, no offset
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
var texCoordLocation = gl.getAttribLocation(program, "texCoord");
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 4 * 2, 0); // 8 bytes per vertex, no offset
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.drawElements(gl.TRIANGLES, indexData.length, gl.UNSIGNED_SHORT, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
// Define geometry
var vertexData = [
0.0, 0.0, 0.0, // vertex 0 position
0.0, 0.0, // vertex 0 tex coord
1.0, 0.0, 0.0, // vertex 1 position
1.0, 0.0, // vertex 1 tex coord
// ...
];
var indexData = [
0, 1, 2, // indices of triangle 0
0, 3, 2, // indices of triangle 1
// ...
];
// Send data to the GPU
var vertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
// Draw the geometry
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
var positionLocation = gl.getAttribLocation(program, "position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 4 * 5, 0); // 20 bytes per vertex, no offset
var texCoordLocation = gl.getAttribLocation(program, "texCoord");
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 4 * 5, 4 * 3); // 20 bytes per vertex, offset of 12 bytes
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.drawElements(gl.TRIANGLES, indexData.length, gl.UNSIGNED_SHORT, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
attribute mat3 basis;
, but you still send the data in columns:
var basisLocation = gl.getAttributeLocation(program, "basis");
gl.enableVertexAttribArray(basisLocation);
gl.vertexAttribPointer(basisLocation, 3, gl.FLOAT, false, 4 * 3 * 3, 0);
gl.enableVertexAttribArray(basisLocation+1);
gl.vertexAttribPointer(basisLocation+1, 3, gl.FLOAT, false, 4 * 3 * 3, 4 * 3);
gl.enableVertexAttribArray(basisLocation+2);
gl.vertexAttribPointer(basisLocation+2, 3, gl.FLOAT, false, 4 * 3 * 3, 4 * 3 * 2);
gl.vertexAttrib[1234]f[v]()
(documentation here) and omitting the gl.enableVertexAttribArray()
call (or calling gl.disableVertexAttribArray()
if it has already been enabled). However, unless you plan on enabling the vertex attribute array at some point in your program, it would be better to use a uniform variable instead.glMatrix
glMatrix
is a JavaScript library for vectors and matrices. It is available here.gl.uniform[234]fv()
expects a JavaScript typed array (Float32Array
) as an argument. If we give it a JavaScript array of numbers, these will be converted to floats before being sent to the GPU.glMatrix
objects store data as floats internally, and can be passed directly to gl.uniform[234]fv()
calls without any casting.Operation | GLSL | glMatrix |
---|---|---|
Declaration | vec3 a; | var a = vec3.create(); |
Creating From Values | vec3 a = vec3(1.0, 2.0, 3.0); | var a = vec3.fromValues(1.0, 2.0, 3.0); |
Cloning | vec3 a = b; | var a = vec3.clone(b); |
Copying | a = b; | vec3.copy(a, b); |
Addition | a = b + c; | vec3.add(a, b, c); |
Scaled Addition | a = b + s * c; | vec3.scaleAndAdd(a, b, c, s); |
Scaling | a = s * b; | vec3.scale(a, b, s); |
Component-wise Multiplication | a = b * c; | vec3.multiply(a, b, c); // or vec3.mul() |
Dot Product | float s = dot(a, b); | var s = vec3.dot(a, b); |
Cross Product | a = cross(b, c); | vec3.cross(a, b, c); |
Normalization | a = normalize(b); | vec3.normalize(a, b); |
Euclidean Length | float s = length(a); | vec3.length(a) // or vec3.len() |
Matrix-Vector Multiplication | a = m * b; | vec3.transformMat3(a, b, m); |
Homogeneous Matrix-Vector Multiplication | vec4 c = m * vec4(b, 1.0); a = c.xyz / c.w; | vec3.transformMat4(a, b, m); |
Matrix-Matrix Multiplication | a = b * c; | mat4.multiply(a, b, c); // or mat4.mul() |
Matrix Inversion | Not available in WebGL 1 | mat4.invert(a, b); |
Float32Array
s, or glMatrix
objects of the correct size.glMatrix
also has several utility functions for creating special kinds of matrices, such mat4.fromTranslation()
, mat4.fromRotation()
, mat4.fromScaling()
, mat4.lookAt()
(for camera matrices), mat4.ortho()
, and mat4.perspective()
.uniform mat4 viewProj;
gl.uniform()
variants.gl.uniformMartrix[234]fv(location, transpose, value)
location
is the uniform location returned by gl.getUniformLocation()
.transpose
is a boolean; true
if the matrix should be transposed as it is sent to the GPU. For WebGL, this should be false
.value
is a Float32Array
or a glMatrix
matrix of the appropriate size.gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.depthFunc(func)
.func
is gl.LESS
(meaning the fragment will overwrite the color value if its depth is less than the current value in the depth buffer).gl.GREATER
, gl.EQUAL
, gl.LEQUAL
, gl.GEQUAL
, gl.NOTEQUAL
, gl.ALWAYS
, and gl.NEVER
. These are rarely used.