# The Javascript ecosystem offers exciting ways to render 3D environments. I've wanted to look into this area for some time. Here I take my first steps with WebGL, build a UI with basic controls and use them to interact with a 3D scene

My starting point is a MDN WebGL tutorial the results of which are embedded above – a spinning cube, covered with an image, rendered on an HTML Canvas using WebGL and a library called `gl-matrix`.

Having inherited this code from the tutorial I'd like to make it interactive.

## Interactive features

• Rotate the cube
• Zoom-in on the cube

### Simplest thing first

Now a checkbox toggles automatic rotation. How?

### Let's get into the code

A function called `render` runs every time a new animation frame is available...

```function render(now) {  const deltaTime = now - then;  then = now;.css-13aqjzy{display:inline-block;}
drawScene(gl, programInfo, buffers, texture, deltaTime);
requestAnimationFrame(render);}```

A measure of time-since-the-last-frame is passed into `drawScene` every time we [re]render

There is a lot going on in `drawScene`. We are interested in some state called `cubeRotation`, which is calculated based on the time delta (the more time has passed the further the cube has rotated)

See the `mat4.rotate` method from `gl-matrix` below:

`mat4.rotate(  modelViewMatrix, // destination matrix  modelViewMatrix, // matrix to rotate  cubeRotation, // amount to rotate in radians   [0, 0, 1]); // axis to rotate around (Z)mat4.rotate(  modelViewMatrix, // destination matrix  modelViewMatrix, // matrix to rotate  cubeRotation * 0.7, // amount to rotate in radians   [0, 1, 0]); // axis to rotate around (X)`

To make this a bit easier I do some clean up:

• Rotate around the more intuitive `X` and `Y` axis, rather than `X` and `Z`
• Use a separate variables for `cubeRotationX` and `cubeRotationY`no more random `* 0.7`
• Replace comments with named variables
```const xAxis = [0, 1, 0];mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotationX, xAxis);
const yAxis = [1, 0, 0];mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotationY, yAxis);```

#### Now to make rotation conditional

We simply put an `if` block around the code that updates `cubeRotationX` and `cubeRotationY`

`if (document.getElementById("autoRotation").checked) {  cubeRotationX += deltaTime / 2000;  cubeRotationY += deltaTime / 1400;}`

Our checkbox toggles automatic rotation 🎉

### Controlling X and Y rotation

We adding some more inputs to the HTML

`<div>  <label htmlFor="cubeRotationX">X</label>  <input type="number" id="cubeRotationX" name="cubeRotationX" step="0.05" /></div><div>  <label htmlFor="cubeRotationX">Y</label>  <input type="number" id="cubeRotationY" name="cubeRotationY" step="0.05" /></div>`

And use their values when not auto-rotating

`if (document.getElementById("autoRotation").checked === false) {  cubeRotationY = document.getElementById("cubeRotationY").value;  cubeRotationX = document.getElementById("cubeRotationX").value;}`

### Control the zoom

Imagining a camera is pointing at our 3D cube. There are at least three ways to achieve a "zoom" effect, relatively speaking:

1. Move the cube closer to the camera
2. Move the camera closer to the cube
3. Change the magnification of the camera
4. Increase the size of the cube

I've picked variables related to two or three of these concepts out of the code:

VaryVariableNotes
Cube position`drawingPositionZ`A starting point for drawing the cube
Camera positionn/aEverything is relative. See cube position
Camera magnification`fieldOfViewInRadians`Narrows or widens the view
Cube sizen/aNot simple to vary atm in this code

This concludes this first exploration into making some interactive WebGL.

### Take home points

1. We re-render the scene every time an animation frame is available and the browser handles it well
2. It is simple to including variables from HTML inputs in the `drawScene` function
3. In this code the easiest way to add a zoom effect was to move the scene closer to the "perspective". Although this won't work in all other scenarios it's an option that works. WebGL Fundamentals has a great page about "cameras" that has more about this topic.

Next I'll take a look at some libraries (e.g. ThreeJS, A-Frame, Clay-GL). I've found this list handy.

Spotted a typo? Edit on Github

Unless otherwise stated I am the creator of all the text, images and code.

Generally I'm happy to share but let's talk first if you want to license or commercialise any of it