Public
Edited
Jan 28, 2023
Importers
6 stars
Insert cell
Insert cell
width = 512
Insert cell
height = 256
Insert cell
Insert cell
{
const canvas = DOM.canvas(width, height);

// GL context
const gl = canvas.getContext("webgl");

// Only continue if WebGL is available and working
if (gl === null) {
alert(
"Unable to initialize WebGL. Your browser or machine may not support it."
);
return;
}

// set the clear color, and then redraw with that clear color
gl.clearColor(0.75, 0.25, 0.5, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

return canvas;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
initShaderProgram = (gl, vsSource, fsSource) => {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

// create shader program, attach and link shaders
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

// check if creation failed
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
console.error(
`Unable to initialize the shader program: ${gl.getProgramInfoLog(
shaderProgram
)}`
);
return null;
}

// else return program
return shaderProgram;
}
Insert cell
// type: gl.VERTEX_SHADER or gl.FRAGMENT_SHADER
// source: shader source
loadShader = (gl, type, source) => {
const shader = gl.createShader(type);

// attach shader source to shader object
gl.shaderSource(shader, source);
// compile shader program
gl.compileShader(shader);

// check for successful compilation
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(
`An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`
);
gl.deleteShader(shader);
return null;
}
// else return shader
return shader;
}
Insert cell
Insert cell
initPositionBuffer = (gl, positions) => {
// buffer for square's positions
const positionBuffer = gl.createBuffer();
// set that buffer as the one to work with
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

// tell webGL to use array of positions
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

return positionBuffer;
}
Insert cell
Insert cell
setPerspectiveUniforms = (
gl,
projectionMatrixLocation,
modelViewMatrixLocation
) => {
const { mat4 } = glMatrix;

// perspective distortion to simulation camera perspective
// set field of view to 45deg,
// only render objects between 0.1 and 100 units from camera
const fieldOfView = (45 * Math.PI) / 180; // conver to radian
const aspect = width / height;
const zNear = 0.1;
const zFar = 100.0;
const projectionMatrix = mat4.create();
mat4.perspective(
projectionMatrix, // destination to receive result
fieldOfView,
aspect,
zNear,
zFar
);

// translate drawing position
const modelViewMatrix = mat4.create();
mat4.translate(
modelViewMatrix, // destination matrix
modelViewMatrix, // matrix to translate (why same as destination?)
[-0.0, 0.0, -3.0]
);

// update shader uniforms with the newly calculated perspective & drawing position
gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);
gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix);
}
Insert cell
setPositionAttribute = (gl, position, vertexPosition) => {
const numComponents = 2; // 2 values per iteration
const type = gl.FLOAT; // data in buffer is 32bit float
const normalize = false;
const stride = 0; // how many bytes to get from one set of values to next
const offset = 0; // how many bytes inside buffer to start from

gl.enableVertexAttribArray(vertexPosition);

gl.bindBuffer(gl.ARRAY_BUFFER, position); // why bind again? just in case?
gl.vertexAttribPointer(
vertexPosition,
numComponents,
type,
normalize,
stride,
offset
);
}
Insert cell
drawPerspectiveScene = (gl, programInfo, buffers) => {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0); // Clear everything
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

const {
program,
uniformLocations: {
projectionMatrix: projectionMatrixLocation,
modelViewMatrix: modelViewMatrixLocation
},
attribLocations: { vertexPosition }
} = programInfo;

setPositionAttribute(gl, buffers.position, vertexPosition);
gl.useProgram(program);
setPerspectiveUniforms(gl, projectionMatrixLocation, modelViewMatrixLocation);

const offset = 0;
const numVertices = 4;
gl.drawArrays(gl.TRIANGLE_STRIP, offset, numVertices);
}
Insert cell
{
const canvas = DOM.canvas(width, height);
const gl = canvas.getContext("webgl");

const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
// setup info for passing into draw scene
// including where to look up attribute and uniform locations (?)
// (not sure what this location means, perhaps location in memory?)
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition")
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(
shaderProgram,
"uProjectionMatrix"
),
modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix")
}
};

// draw
const positions = [
1.0,
1.0, // right top
-1.0,
1.0, // left top
1.0,
-1.0, // right bottom
-1.0,
-1.0 // left bottom
];
const buffers = { position: initPositionBuffer(gl, positions) };
drawPerspectiveScene(gl, programInfo, buffers);

return canvas;
}
Insert cell
Insert cell
vs2Source = `
attribute vec4 aVertexPosition;
attribute vec4 aVertexColor;

varying lowp vec4 vColor;

void main(void) {
gl_Position = aVertexPosition;
vColor = aVertexColor;
}
`
Insert cell
fs2Source = `
varying lowp vec4 vColor;

void main(void) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`
Insert cell
initColorBuffer = (gl) => {
const colors = [
1.0, 1.0, 1.0, 1.0, // right top: white
1.0, 0.0, 0.0, 1.0, // left top: red
0.0, 1.0, 0.0, 1.0, // right bottom: green
]

const colorBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW)

return colorBuffer
}
Insert cell
setColorAttribute = (gl, color, vertexColor) => {
const numComponents = 4;
const type = gl.FLOAT;
gl.bindBuffer(gl.ARRAY_BUFFER, color);
gl.vertexAttribPointer(vertexColor, numComponents, type, false, 0, 0);
gl.enableVertexAttribArray(vertexColor);
}
Insert cell
drawScene = (gl, programInfo, buffers) => {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0); // Clear everything
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

const {
program,
attribLocations: { vertexPosition, vertexColor }
} = programInfo;
const { position, color } = buffers;

setPositionAttribute(gl, position, vertexPosition);
setColorAttribute(gl, color, vertexColor);
gl.useProgram(program);

const offset = 0;
const numVertices = 4;
gl.drawArrays(gl.TRIANGLE_STRIP, offset, numVertices);
}
Insert cell
{
const canvas = DOM.canvas(width, height);
const gl = canvas.getContext("webgl");

const shaderProgram = initShaderProgram(gl, vs2Source, fs2Source);
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexColor")
}
};
const buffers = {
position: initPositionBuffer(gl),
color: initColorBuffer(gl)
};
drawScene(gl, programInfo, buffers);

return canvas;
}
Insert cell
Insert cell
glMatrix = import("https://unpkg.com/gl-matrix@3.4.3/esm/index.js?module")
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