Material Viewer

Motivation
For a while now I’ve wanted to write a simple editor/viewer to show simple, basic interaction between light and materials (based in no small part to this web page, http://www.barradeau.com/nicoptere/dump/materials.html).

I also noticed that even simple default scenes rendered very differently with Three.js, Babylon.js and PlayCanvas engine (referred to as PlayCanvas.js from hereafter). So once I started, I got the idea that it would be interesting to compare how different libraries rendered lights and materials. This would give me an opportunity to learn, compare and contrast each, as well as (hopefully) learn and apply some new ES6 features.

Use cases
 1. Investigate material properties
 2. Investigate light properties
 3. Show and compare how different renderers implement lighting

Light Properties
The following light types are supported:
 ● ambient
 ● spot
 ● point
 ● directional
 ● hemi-sphere ¹
¹ Babylon.js only

Material Properties
The following material properties are supported:
 ● ambient ²
 ● diffuse
 ● specular
 ● emissive
² Not Three.js, the ambient colour interacts directly with the diffuse material

GUI
I like dat-gui, but I’ve wanted a floating control for a long time, after several abortive attempts at writing my own (I just got bored dealing with all the fiddly bits) I finally found an old but working solution that resizes to its content. There were a couple of bugs but they were readily sorted
(e.g. dat-gui hangs over the bottom of a containing div but this was easily dealt with by adding a bottom border).

Still, I’m unhappy with both DraggableLayer and dat-gui. DraggableLayer will only work with one element, and dat-gui has limited input options (e.g. no vector entry) and colour selection can be fiddly.

Renderer Controllers
In “JavaScript: the Good Parts” Crockford eschews the use of new, using constructor functions instead. I try to follow suit with makeXXX functions. All the renderer specific code is localised to a single file, although this is rather spoiled by the matching <script> tag polluting the global space.

Each renderer has the same interface and hides any workarounds (e.g. each renderer implements ambient lighting differently). Adding a new renderer should be straightforward.

Three.js and Babylon.js were generally easy to code for, but PlayCanvas.js kept throwing up little issues and I found it’s syntax less intuitive.

PlayCanvas.js problems
PlayCanvas uses degrees rather than radians. While more an idiosyncrasy than a problem, it necessitates conversion between radians and degrees.

Despite providing a torus primitive in the editor (along with a capsule) there is no equivalent addComponent method. Using the createXXX method requires additional code to add it to the render list, etc. and maintain it. However, there was work round — generating an arbitrary mesh then replacing it with a “created” meshInstance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var mesh1 = new pc.Entity('cube');
mesh1.addComponent('model', {
  type: 'box'
});
 
var node = new pc.GraphNode();
var mesh = geometryTypes[type](app.graphicsDevice, geometryDefaults[type]);
 
var material = new pc.StandardMaterial();
var meshInstance = new pc.MeshInstance(mesh1.model.meshInstances[0].node, mesh, material);
 
mesh1.model.meshInstances = [meshInstance];
 
material.ambient.set(...materialValue.ambient);
material.diffuse.set(...materialValue.diffuse);
material.emissive.set(...materialValue.emissive);
material.specular.set(...materialValue.specular);
material.fresnelModel = pc.FRESNEL_NONE;
material.shadingModel = pc.SPECULAR_PHONG;
material.update();
mesh1.model.material = material;
 
app.root.addChild(mesh1);

To get the ambient material setting working required fiddling around with material properties. The default material is physical which needed to be switched to Phong (not a single switch but setting a couple of properties, see lines 18-19 above).

The createCylinder method had a bug and used opts.baseRadius rather than correct opts.radius. I actually raised a PR to fix this (yipee!).

I still can’t figure out how to set the rotation of the orbit camera correctly, I suspect it may be related to rounding errors when converting between degrees and radians.

GitHub
After some initial work in my mega-repo, I split it off into it’s own — always fun. It can be found here and the live version here and mirrored here.

Future work
Sort out the camera rotation bug in PlayCanvas (der).

Either find better UI libraries that support draggable elements and more input types or D-I-Y my own.

Use glTF as the interchange format rather than my own. However, there may be some unique settings that aren’t supported. Further investigation is needed.

Add more light types — directional, spot, etc.
Add light parameters — position, fall off, penumbra, etc.
Add interactive control — click ‘n’ drag
More advanced lighting/shading/materials (AO, PBM)

Pop up info/help

Add/delete models
Shadows
Import models