Simple Custom Mesh3D object to draw meshes

skull

Phaser’s GameObjects.Mesh object offers a very simple way of rendering 3D objects. It is designed to leverage the renderer used to draw pretty much all of the other game objects of Phaser, allowing you to use all the common tools available for the other game objects. There are some limitations, however. One is that normals information is not captured, so no shading. The other is that the object is not drawn with one webgl draw call - rather it is drawn face by face - which sometimes leads to z-depth fighting. If shading and use of depth buffers is all you need, surely it would be easy to write a custom mesh object and a shader in glsl, without having to resort to Three.js? After all, Phaser provides you with lots of useful methods for creating shaders.

First I created a custom object that recreates Phaser’s game object (ie no shading, but draw each mesh in one draw call). Phaser usefully provides you with an object called ‘Extern’ which will call your own rendering method with a clean webgl context.

What took me a long time to figure out is that the default webgl context created by Phaser does not have a depth buffer (is there a reason for this?). Hence you need to pass custom context config when booting up Phaser, like so:

// need to create a custom webgl canvas context 
const customCanvas = document.createElement('canvas');
customCanvas.id = 'customCanvas';
document.body.appendChild(customCanvas);

// customised context config
const contextCreationConfig = {
  alpha: false,
  antialias: false,
  depth: true,  // this is different from the default Phaser context config
  failIfMajorPerformanceCaveat: false,
  powerPreference: 'default',
  premultipliedAlpha: true,
  preserveDrawingBuffer: false,
  stencil: true,
};

const customContext = customCanvas.getContext('webgl', contextCreationConfig);

const config = {
  type: Phaser.WEBGL,
  width: 600,
  height: 500,
  canvas: customCanvas,
  context: customContext,
  scene: [GameScene]
}

const game = new Phaser.Game(config);

You could make the code smaller by making more use of Phaser’s build-in methods (I’ve also used gl-matrix library - you could use Phaser’s matrices).

Once you get this far, it’s very simple to make the code a bit more abstract to handle multiple shaders - very simple to ‘plug-in’ any kind of shader you want. In the below Codepen, the “skull” from the official Phaser examples page is rendered using several different shaders.

Of course, at this point no doubt you are thinking “use Three.js!” - but it’s fun seeing how far you can get with Phaser without resorting to other libraries!

1 Like