Published
Edited
Aug 18, 2021
Insert cell
md`# WebGL Triangle #2: VAO`
Insert cell
canvas = DOM.canvas(width, height);
Insert cell
{
drawWithVAO()
// drawWithoutVAO()
}
Insert cell
vao1 = {
const vao = gl.createVertexArray()
gl.bindVertexArray(vao)
{
// connect buffers and attributes
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers1.position);
gl.vertexAttribPointer(
attributeLocations1.position,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations1.position);
}
return vao
}
Insert cell
vao2 = {
const vao = gl.createVertexArray()
gl.bindVertexArray(vao)
{
// connect buffers and attributes
{
// positions
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers2.position);
gl.vertexAttribPointer(
attributeLocations2.position,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations2.position);
}
{
// colors
const numComponents = 4;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers2.color);
gl.vertexAttribPointer(
attributeLocations2.color,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations2.color);
}
}
return vao
}
Insert cell
function drawWithVAO() {
// clear
gl.clearColor(1., 1., 1., 1.);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// triangle1

// use program
gl.useProgram(program1);

// bind VAO
gl.bindVertexArray(vao1)

{
// connect uniforms
gl.uniform2f(uniformLocations1.resolution, width, height);
gl.uniform4fv(uniformLocations1.color, new Float32Array(data1.color));
gl.uniformMatrix4fv(uniformLocations1.transform, false, new Float32Array(transform));
}

// draw
{
const offset = 0;
const vertexCount = 3;
gl.drawArrays(gl.TRIANGLES, 0, 3)
}



// triangle2
// use program
gl.useProgram(program2);

// bind VAO
gl.bindVertexArray(vao2)

{
// connect uniforms
gl.uniform2f(uniformLocations2.resolution, width, height);
gl.uniformMatrix4fv(uniformLocations2.transform, false, new Float32Array(transform));
}

// draw
{
const offset = 0;
const vertexCount = 3;
gl.drawArrays(gl.TRIANGLES, 0, 3)
}
}
Insert cell
function drawWithoutVAO() {
// clear
gl.clearColor(1., 1., 1., 1.);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// triangle1

// use program
gl.useProgram(program1);

{
// connect buffers and attributes
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers1.position);
gl.vertexAttribPointer(
attributeLocations1.position,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations1.position);
}

{
// connect uniforms
gl.uniform2f(uniformLocations1.resolution, width, height);
gl.uniform4fv(uniformLocations1.color, new Float32Array(data1.color));
gl.uniformMatrix4fv(uniformLocations1.transform, false, new Float32Array(transform));

}

// draw
{
const offset = 0;
const vertexCount = 3;
gl.drawArrays(gl.TRIANGLES, 0, 3)
}



// triangle2
// use program
gl.useProgram(program2);

{
// connect buffers and attributes
{
// positions
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers2.position);
gl.vertexAttribPointer(
attributeLocations2.position,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations2.position);
}
{
// colors
const numComponents = 4;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers2.color);
gl.vertexAttribPointer(
attributeLocations2.color,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations2.color);
}
}

{
// connect uniforms
gl.uniform2f(uniformLocations2.resolution, width, height);
gl.uniformMatrix4fv(uniformLocations2.transform, false, new Float32Array(transform));
}

// draw
{
const offset = 0;
const vertexCount = 3;
gl.drawArrays(gl.TRIANGLES, 0, 3)
}
}
Insert cell
Insert cell
data2 = ({
positions: [
400, 300,
800, 300,
600, 600
],
colors: [
1., 0., 0., 1.,
0., 1., 0., 1.,
0., 0., 1., 1.,
]
})
Insert cell
Insert cell
buffers1 = {
return {
position: createBuffer(gl, data1.positions)
}
}
Insert cell
buffers2 = {
return {
position: createBuffer(gl, data2.positions),
color: createBuffer(gl, data2.colors)
}
}
Insert cell
attributeLocations1 = {
return {
position: gl.getAttribLocation(program1, "in_position"),
}
}
Insert cell
attributeLocations2 = {
return {
position: gl.getAttribLocation(program2, "in_position"),
color: gl.getAttribLocation(program2, "in_color"),
}
}
Insert cell
uniformLocations1 = {
return {
resolution: gl.getUniformLocation(program1, "u_resolution"),
transform: gl.getUniformLocation(program1, "u_transform"),
color: gl.getUniformLocation(program1, "u_color")
}
}
Insert cell
uniformLocations2 = {
return {
resolution: gl.getUniformLocation(program2, "u_resolution"),
transform: gl.getUniformLocation(program2, "u_transform"),
}
}
Insert cell
program1 = createProgram(gl, vertexShaderSource1, fragmentShaderSource1)
Insert cell
// for test
program2 = createProgram(gl, vertexShaderSource2, fragmentShaderSource2)
Insert cell
gl = canvas.getContext('webgl2')
Insert cell
height = width * 0.75
Insert cell
Insert cell
vertexShaderSource2 = `#version 300 es

in vec4 in_color;
in vec2 in_position;

uniform vec2 u_resolution;
uniform mat4 u_transform;

out vec4 color;

void main() {
color = in_color;
vec4 pos = u_transform * vec4(in_position, 0., 1.);

// convert the position from pixels to 0.0 to 1.0
vec2 zeroToOne = pos.xy / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;

gl_Position = vec4(clipSpace, 0, 1);
}
`
Insert cell
Insert cell
fragmentShaderSource2 = `#version 300 es

precision highp float;

in vec4 color;

out vec4 fragColor;

void main() {
fragColor = color;
}
`
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more