Monday, September 17, 2012

Three.js Code Clean-Up

‹prev | My Chain | next›

I have my little Three.js / Physijs tilt-a-game at 140 lines of code (code editor). This seems good for a Gaming JavaScript entry. Still I might like to get it a little smaller, a little cleaner, and possibly add a bit more 3D "feel" to it.

I start, by trying to eliminate a fairly annoying bug. At some point in the last few days, I have introduced something that spews a lot of Three.js errors output on the JavaScript console. The error output starts with:
ERROR: 0:26: 'undefined' : syntax error 
precision highp float;
#define MAX_DIR_LIGHTS 0
#define MAX_SHADOWS 0


uniform mat4 viewMatrix;
uniform vec3 cameraPosition;
undefined Three.js:325
WebGL: INVALID_VALUE: attachShader: no object or object deleted /code-editor/ (1):1
ERROR: 0:62: 'undefined' : syntax error
Even more console errors and warnings are logged until Chrome has finally had enough:
WebGL: INVALID_OPERATION: useProgram: program not valid /code-editor/ (1):1
.WebGLRenderingContext: GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 0 /code-editor/ (1):1
WebGL: too many errors, no more errors will be reported to the console for this context. /code-editor/ (1):1
I suspect that I have added an invalid mesh or two to my scene. By process of elimination, I track all of that output down to last night's scoring mesh:
    // Scoring 
    var score = new Physijs.ConvexMesh(
      new THREE.PlaneGeometry(20, 20),
      new THREE.Material
    score.position.x = 50;
    score.position.y = -75;
    score.addEventListener('collision', function() {
Commenting those lines out (indeed, just commenting out scene.add(score)) eliminates the errors. This turns out to be caused by my use of the superclass, Three.Material. I had used that as a cheap way to get a transparent mesh. It seems the more proper way of doing so is with the opacity setting of MeshBasicMaterial:
    // Scoring 
    var score = new Physijs.ConvexMesh(
      new THREE.PlaneGeometry(20, 20),
      new THREE.MeshBasicMaterial({opacity: 0.0})
    score.position.x = 50;
    score.position.y = -75;
With those errors eliminated and a bunch of code cleaned up, I notice something else odd: I can no longer get the ball to roll when I tilt the platform. Even if I tilt the platform 90°:

This one, I cannot figure out. It seems that this was accidentally working previous because I had given the platform an initial tilt. I restore it:
    ground.__dirtyRotation = true;
    ground.rotation.x = -0.01;
Restoring this allows the tilt controls to again have an effect on the ball:

I suspect that I am doing something wrong here. It may be the use of __dirtyRotation—both here and in the subsequent tilt() function used by the game controls:
  function tilt(dir, amount) {
    ground.__dirtyRotation = true;
    ground.rotation[dir] = ground.rotation[dir] + amount;
And yes, I feel dirty for using this, but it does the trick. Mostly.

I finish up by attempting to clean up the platform generation. First off, I rename it as platform instead of ground. I am unable to clean up the beam definitions much. There is no copy()/clone() in Three.js yet, so I am stuck with defining each beam manually. I can move that into its own function, if nothing else:
  function makePlatform() {
    var beam = new Physijs.BoxMesh(
      new THREE.CubeGeometry(50, 2, 200),
      new THREE.MeshBasicMaterial({color: 0x7CFC00}),
    var beam2 = new Physijs.BoxMesh(
      new THREE.CubeGeometry(50, 2, 200),
      new THREE.MeshBasicMaterial({color: 0x7CFC00})
    beam2.position.x = 75;
I call it a night here and return to writing Gaming JavaScript. Tomorrow, I will get started on some of the more interesting Three.js scene properties that I have not used much yet (fog, illumination, particles). That should punch up the game a bit.

Day #512


  1. Just a quick note :)

    If you set the initial rotation before adding ground to the scene then you only need to set __dirtyRotation to true in the tilt function. Makes the code a little cleaner.

    1. Yup, that works and is nicer. Thanks for the tip :)