DEV Community

Cover image for WebGL canvas in React
Jack Le Hamster
Jack Le Hamster

Posted on

WebGL canvas in React

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!

<canvas ref={canvasRef}
            width={width}
            height={height}
            style={{
                ...props?.style,
                width: "100%",
                height: "100%",
            }}>
</canvas>;
Enter fullscreen mode Exit fullscreen mode
const [gl, setGL] = useState<WebGL2RenderingContext | undefined>();

React.useLayoutEffect(() => {
   const canvas = canvasRef.current;
   setGL(canvas?.getContext?.("webgl2", {
      ...DEFAULT_ATTRIBUTES,
      ...webglAttributes,
   }) ?? undefined);
}, []);
Enter fullscreen mode Exit fullscreen mode
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);
Enter fullscreen mode Exit fullscreen mode

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.

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;
}
Enter fullscreen mode Exit fullscreen mode

Fragment:

#version 300 es

precision highp float;
in vec3 vColor;
out vec4 fragColor;

void main() {
   fragColor = vec4(vColor, 1.0);
}
Enter fullscreen mode Exit fullscreen mode
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);
}
Enter fullscreen mode Exit fullscreen mode
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
Enter fullscreen mode Exit fullscreen mode

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.

Oldest comments (0)