Tuesday, September 18, 2012

Pretty, Shiny Materials for Three.js Games

‹prev | My Chain | next›

I have not done a fantastic job of keeping the code in my tilt-a-board game small. I cleaned it up and generally tried to make it shorter yesterday and it went from 140 to 150 lines of code. I still might eke out some lines of code savings another time. For today, I am going to see what I can do about making this Three.js / Physijs game a little slicker.

I think this would likely end up being a separate chapter in Gaming JavaScript—cool things to make a working game more visually appealing. Since it's for kids, I'll probably call it "make your games look awesome" or something like that. Let's see if I can actually do that.

I think I'll try to avoid things like bump maps and the like. It is certainly possible to create visually stunning scenes with them, but I am unsure if the amount of effort is worth the payoff. That's something to consider another day. For now, I will try to get enough bang from the map-less buck.

I start by simply making the background color black:
    renderer = initRenderer(0x000000);
// ...

  function initRenderer(bgColor) {
   var renderer = renderingStrategy();

   renderer.setSize(window.innerWidth, window.innerHeight);

   return renderer;

  function renderingStrategy() {
    if (Detector.webgl) return new THREE.WebGLRenderer({antialias: true});
   if (Detector.canvas) return new THREE.CanvasRenderer();
   return undefined;
I will add some stars later, but first want to improve the material used for both the ball an the game board. Both are as basic as Three.js allows:

I start by adding some lighting to the scene. Without lighting, Three.js just assumes an ambient white light everywhere. I tone down the ambient light with a grey, then add a point light behind the board and a spot light to the side:
    // Lighting
    scene.add(new THREE.AmbientLight(0x999999));

    var back_light = new THREE.PointLight(0xffffff, 0.9);
    back_light.position.set(100, 100, -200);
    var spotLight = new THREE.SpotLight( 0xffffff ); 
    spotLight.position.set( -250, 250, 250 );  
    spotLight.castShadow = true;  
    spotLight.shadowMapWidth = 1024; 
    spotLight.shadowMapHeight = 1024;  
    spotLight.shadowCameraNear = 500; 
    spotLight.shadowCameraFar = 4000; 
    spotLight.shadowCameraFov = 30; 
    scene.add( spotLight );
The lighting itself is not as important as the various color options in the materials. For instance, I set the ball as follows:
    ball = new Physijs.SphereMesh(
      new THREE.SphereGeometry(10),
      new THREE.MeshPhongMaterial({
        color: 0x000000,
        shininess: 100.0,
        ambient: 0xff0000,
        emissive: 0x111111,
        specular: 0xbbbbbb
The color in a Phong material is not the intrinsic color as we normally think of it—that is what the ambient color does. The color in the Three.js Phong material describes how diffuse the lighting will be (0xffffff would be low contrast). I want things to be as shiny as possible, so I disable the diffuse color entirely. Then I crank up the shininess factor. I want my game ball's intrinsic color to be red, so I set the ambient color to red. I do not want the ball to emit light. Lastly, I want the reflections from the shine to be really bright, so I crank up the specular color.

After doing similar for the game board, the result is a shiny looking ball and game board:

I can live with that. I still need to add some stars to simulate space and maybe some fog and a spotlight from below. But I will play with those tomorrow.

[the code so far]

Day #513

No comments:

Post a Comment