3d WebGL Browser Game #6: Basic Graphics
Welcome back to Dev Log #6 🎉
In Dev Log # 3 Combat Mechanics we talked about the benefits of using basic graphics when building out the game mechanics. After nailing down a mechanic on paper, implementing it using simple 3d models can help with getting a better sense of how things feel in a 3d game world.
Lately we’ve spent most of our dev time on the game’s engine and networking code, but by now we’ve laid enough foundation to dive back into iterating on the gameplay mechanics. Since we want to have basic visuals for the mechanics that we build, now is a good time to have a static model loader at our disposal.
Last week we worked on loading static 3d models into the game.
Rendering and walking around our tree model
I searched around a bit for a small, functional wavefront .obj model loader that would allow us to draw models using our WebGL context and some model data.
After having no luck with finding an existing package I took a stab at making chinedufn/load-wavefront-obj. We’ll use it for all non-skeletal models that we create.
The loader’s unit tests are powered by the fantastic stackgl/headless-gl.
[headless-]gl lets you create a WebGL context in node.js without making a window or loading a full browser environment.
We might want to also run browser tests in the future, but stackgl/headless-gl
should do for now.
How We’re Loading Models
Our first take on the API came out like this:
// Pass in our WebGL context, the parsed JSON from our wavefront .obj file,
// and a DOM image element OR a Uint8Array of image data
var treeModel = LoadWavefrontObj(gl, treeJSON, {textureImage: treeTextureImage))
// Later we render the model using our draw function
treeModel.draw({
position: [5, 0, -5],
viewMatrix: cameraViewMatrix,
perspective: perspectiveMatrix
})
Which draws a tree in the game world:
Rendering our tree model onto the canvas
In order to draw two trees we’d do:
// We have a two different sets of [x, y, z] coordinates
var treePositions = [
[5, 0, -5],
[8, 0, -5]
]
// We call the draw function twice to draw two trees
treePositions.forEach(function (aTreePosition) {
treeModel.draw({
position: aTreePosition,
viewMatrix: cameraViewMatrix,
perspective: perspectiveMatrix
})
})
Which draws two trees in two different locations:
Rendering two tree models onto the canvas
Potential Future Issues
One potential problem is that I have near zero experience with modeling and texturing. I’m imagining that my art will come out very poorly for some time while I’ll gradually gain the skills to produce our low poly models and textures. Even so, I’m excited to gain some art experience and start tapping into a whole new way of approaching problems.
Another future issue is that the loader isn’t heavily optimized. For example, we’re always calling gl.useProgram
before drawing even if we aren’t changing shader programs. Since we’re targeting both desktop and mobile platforms we’ll likely need to tune every aspect of our render pipeline to our needs, but we’ll solve those problems as they arise.
What’s Next
For the rest of August we’ll be focusing on the combat mechanics. We’ll first define a set of constraints for the design of the combat system, and then work within those boundaries. Things such as the emotions that we want to evoke, the desired tempo and pacing, and the types of physical devices (i.e. laptop trackpad
, phones
, tablets
, game-pad
, etc) that it should feel fluid on.
Next we’ll try to implement an experience that feels great while satisfying these constraints. As we go along we’ll add in basic models and art to keep our imaginations rolling.
We’ll be aiming to have two test sessions by the end of August where we observe and take notes on people trying out the combat system.
As always, our progress gets automatically deployed to game.chinedufn.com so shoot me an email or tweet with your thoughts and feedback!
‘Til next time,
- CFN