Rendering a 3D textured cube with hwoa-rang-gl

Demo | Source Code

I recently open sourced my WebGL framework that I have been working on for the last couple of months. I’ve been using three.js to make 3D for a long time, but as a very high level library with large footprint, many things are hidden to the developer. If one wants more control over the rendering pipeline or implementing specific effects, it can be very cumbersome and tricky to manage, especially while keeping the performance high.

On the other hand, writing raw WebGL can be a real pain with its state machine and verbose API. Hence I decided to try to bridge the gap with hwoa-rang-gl. It aims to be compact and provide the minimum set of classes and methods to be productive and get your idea off the ground.

Parts of it can easily be mixed or replaced with raw WebGL code. For example, you don’t have to use it’s Framebuffer class, you can create one yourself using gl.createFramebuffer and mix it with the rest of the code . Same applies for other WebGL objects like Texture, Program, etc. You can see the full docs here.

This tutorial aims to serve as introduction to core concepts of the library by rendering a simple 3D scene with a spinning shaded cube. You can find the finished demo here.

1. App Skeleton

Again, hwoa-rang-gl tries to keep things simple and does not introduce opinionated rules when it comes to structuring your program. Let’s kick it off by creating a HTMLCanvasElement and corresponding WebGLRenderingContext, sizing our canvas and viewport and starting an animation loop, very much like we would if we were to write a plain WebGL program:

With this code we will get an empty scene with grayish background color repainted on each frame.

2. Perspective Camera

Let’s introduce the library by installing it withnpm i hwoa-rang-gl and importing it at the top of our file:

Let’s create our perspective camera:

2. The 3D cube

We will place a cube in the center of our 3D world. It will be 1 unit in width, height and depth. Let’s start by constructing its needed geometry by calling HwoaRangGL.GeometryUtils.createBox() and supplying the result vertices, uvs, normals and indices to the base Geometry class:

We can use the generated geometry and supply it to a Mesh class, which will be responsible for painting it on the screen. We need to provide the geometry along with our vertex & fragment shaders. This part of the API was heavily inspired by theShaderMaterial class in three.js. Just like there, hwoa-rang-gl also provides the projectionMatrix viewMatrix and modelMatrix uniforms by default to every Mesh vertex shader, so you don’t have to manage them yourself.

Finally we need to augment our renderFrame method to actually draw our cube:

With this new code, upon reloading our browser we are greeted with a spinning cube using its UV coordinates as colors:

Our rotated 3D red cube painted on the device screen

3. Texturing our cube

I am going to use the WebGL logo as a texture to our cube. I resized it to power-of-two 512x512 box in Photoshop so we can benefit from mipmapping and exported it as a .png file.

Here is the needed code to load the image and use it as a texture:

Let’s augment our Mesh and its corresponding fragment shader to account for the texture object:

Finally, we need to bind our texture to gl.ACTIVE_TEXTURE0 before rendering the mesh like so:

With this code we get this result on the device screen:

Our textured 3D cube spinning on the screen

4. Basic shading

As a last step, let’s add some shading via directional lighting. The principles of directional lighting are out of the scope of this tutorial, but you can find a good article here.

Let’s add a new lightDirection vec3 uniform and update our shaders to consume the normal buffer from our geometry:

And here is the result:

Our shaded textured cube

Conclusion

While already being able to render complex scenes, this library is still an ongoing project. I have developed it for my needs and will continue iterating over it where new needs might arise from new projects.

I hope I managed to give you a glimpse into what is possible when using the library and you will give it a try yourself :)

Frontend Developer with interest in realtime graphics https://archive.georgi-nikolov.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store