It's a very fun time every time I start a new WebGL project. I keep forgetting about the basic setup, so I always end up looking up on Google for tutorials on drawing a basic triangle.
Well no! It's not fun at all!
Lately, I started to be a bit smarter about it and create a template I can reuse, so I don't have to relearn everything from scratch every time.
For those who also need to start a new WebGL project and are looking for a Hello World, here's a neat template that sets up the WebGL basic.
https://github.com/jacklehamster/opengl-template
Along the way, let's go through the step for setting up a simple WebGL hello world. We're also here to learn!
- Define the WebGL Canvas, and get a ref from it.
<canvas ref={canvasRef}
width={width}
height={height}
style={{
...props?.style,
width: "100%",
height: "100%",
}}>
</canvas>;
- Set the WebGL2RenderingContext context, passing some WebGL attributes if needed.
const [gl, setGL] = useState<WebGL2RenderingContext | undefined>();
React.useLayoutEffect(() => {
const canvas = canvasRef.current;
setGL(canvas?.getContext?.("webgl2", {
...DEFAULT_ATTRIBUTES,
...webglAttributes,
}) ?? undefined);
}, []);
- Attach the vertex and fragment shaders. Make sure to do proper cleanup.
const vertexShader = createShader(vertex, gl.VERTEX_SHADER)!;
const fragmentShader = createShader(fragment, gl.FRAGMENT_SHADER)!;
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.detachShader(program, vertexShader);
gl.detachShader(program, fragmentShader);
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
The template does all of the above, provided that you pass the shader codes. You can then write custom code to render cool stuff in WebGL. For now let's just render a triangle.
- Setup the Vertex and Fragment shaders. In the vertex shader, we just grab the position and color and pass it further. In fragment, we just grab the color and process it.
Vertex:
#version 300 es
precision highp float;
layout (location=0) in vec4 position;
layout (location=1) in vec3 color;
out vec3 vColor;
void main() {
vColor = color;
gl_Position = position;
}
Fragment:
#version 300 es
precision highp float;
in vec3 vColor;
out vec4 fragColor;
void main() {
fragColor = vec4(vColor, 1.0);
}
const triangleArray = gl.createVertexArray();
gl.bindVertexArray(triangleArray);
const positionLocation = controller.getAttributeLocation("position");
const positions = positionLocation >= 0 ? new Float32Array([
0.0, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
]) : undefined;
const positionBuffer = positionLocation >= 0 ? gl.createBuffer() : undefined;
if (positionLocation >= 0) {
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLocation);
}
const colorLocation = controller.getAttributeLocation("color");
const colors = colorLocation >= 0 ? new Float32Array([
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
]) : undefined;
const colorBuffer = colorLocation >= 0 ? gl.createBuffer() : undefined;
if (colorLocation >= 0) {
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);SubtleCrypto
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.vertexAttribPointer(colorLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(colorLocation);
}
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
I hope this was helpful.
You can go into details by checking out the repo and the demo page.
I'll be doing a few more post with some neat WebGL tricks for beginners, such as animating within the Vertex shader so you don't have to interact with the GPU every frame.
Top comments (0)