WebGL Development Update 2 – First Steps

After Bootcamping my iMac with Windows 7 and downloading/installing 3D Studio Max, Brackets, Photoshop & Illustrator, I set to work on collecting a bunch of reference materials and inspiration sources for the first step of my plan:

I selected a house…

A “Cornell” style of house on the David Wilson Homes development in North Hykeham

I located high resolution floor plans…

Floor plans obtained from the internet
The ground floor plan


Gathered together a selection of reference shots of the exterior…


Then I started digitising the floor plan to ensure that I was modelling to the correct scale and proportions. The output is essentially an architectural rendering so there’s no room to be sloppy.

For this I imported the floorplans into Illustrator and tracked them with the pen tool to create a path of the exterior. When I start working in 3D I can simply import the Illustrator file and extrude the path which will get treated as a spline.

Plans traced in Illustrator ready for import into 3D Studio Max

Once inside 3DS Max, the extruded spline becomes a mesh which I started adding detail to. The first details were to cut out the window/door holes and create the roof. Then I modelled the windows, door, door frame, guttering, window lintels and sills and added them to the model.

The house with the front detail modelled and temporary lighting

Then came the fun part… creating the materials for the following models:

  • Walls – Red brick and mortar
  • Roof – Grey slate tiles
  • Windows Upstairs – White plastic with glass
  • Windows Downstairs – As above only larger
  • Front Door Frame – wood with small windows that sit above the door hole
  • Front Door – mixture of wood, plastic, metal and glass
  • Guttering – black plastic
  • Guttering Holders – white plastic things that sit just under the roof where it touches the walls

Collecting the textures is easy. I headed to CGTextures.com to gather my textures for the materials. Textures are just 2D images that represent the colour data of an surface. When created for use on a 3D model they are referred to as “texture maps“. I tried where possible to get textures which were already set up to tile. However, the brick I wanted wasn’t set up for tiling so I had to heavily modify the texture:

(left) original texture from cgtextures.com and (right) my edited original which allowed the texture to be tilable and removed any obvious areas of repetition (such as the “lines” of lighter bricks and the odd dark brick)

Textures such as the windows and front door had to be created from scratch using a combination of photos, textured surfaces and my own drawing skills in Photoshop:

A bespoke texture for the front door model

I created a material for each of the surfaces and added each corresponding texture to the material which I then applied to the correct mesh (model of each of the elements listed above):

With no lighting (so just the diffuse in effect), the materials have started to bring the house model to life, but the scene needs lighting to appreciate the detail in the materials

Although now the house is visually starting to look like a house, it isn’t exactly looking very realistic. For this we need lighting. I started by adding a directional light to portray the sun, then I added a few omni lights to highlight detail:

Lighting really starts to add depth to the scene, pushing it towards the realistic look I require.

Better, however all the surfaces are responding the same to the light sources. It’s time to start describing each material in terms of its reactions to light. This is the key conceptual difference between a texture and a material:

  • A Texture is the colours of the material in 2D, and is usually an image of that material free of any light influence
  • A Material on the other-hand is a combination of the texture and other information either in the form of other types of image or values of the shader properties such as shininess, reflectivity and self illumination

I started with the roof. I wanted to make the roof tiles slightly shiny and give the impression they are individual tiles without having to complicate the mesh. For this I used a combination of a normal map and specular map:

(left) a close up of the roof with just a light hitting it whereas (right) you can see the effect of the specular and normal maps on the roof as they allow the lighting to identity and “raise” the edges of individual tiles and better scatter the light across the surface

There are different methods of creating a normal map, each with its own tradeoff between time/effort and the quality of the output. The easiest method is to take the texture map itself and use a special texture tools in Photoshop available from the Nvidia website (for free). With some tweaking you can create a normal map from just this tool and by making the texture greyscale. However the output is poor.

Normal maps created in this way roughly use pixel data to decide whether the surface at that location is higher or lower that the average colour value found throughout the texture. White being highest, black lowest and various shades of grey os everything in-between.

The reason the results are poor is that colours in the texture map (also referred to as diffuse map) do not actually represent the height of the surface. Read more about the issues with creating normal maps this way here. There are however certain ways to improve the results if your texture map is of a single surface type (i.e. rock, sand, wood, etc.). Read more about these methods of improving a texture created normal map here.

The best method is to create a really highly detailed 3D model of the surface and render out a normal map from it. Then, you create a simpler model; a model with a much lower polygon count  (essential for real-time 3D games and applications), and then apply the normal to the material as either a normal or bump surface descriptor as shown below:

Image obtained from Wikipedia demonstrating how a high polygon model is used to create lighting detail in a low polygon representation of the same model

The example above is a good candidate for this approach as the model is fully three dimensional with a great deal of detail. However, if, like my tiles mentioned above, the model is along a simple plane and you just wish to give the material some height definition, then there is a quicker way.

I simply created a new layer in Photoshop over my diffuse map and manually drew in the black lines to represent the edges of the tiles, and then used a simple greyscale gradient (with some noise applied) to create the suggestion of a sloped surface to the lighting in 3D Studio Max. I went to this trouble because WebGL also supports Normal Mapping so I can use them to make my house look realistic when it is running in a Web Browser.

Specular mapping uses an image to display how surfaces throughout the material reflect light. Lighter areas reflect more light (indicating a shiny surface) whereas dark or black areas are treated at matt. Colour is also plays a part as the specular can reflect hints of colour.

I created my specular map by starting off with a dull background and working out which areas should reflect light, such as glass, metal shiny plastics. I didn’t spend too much time on these as I’m still not sure how effective they will be in WebGL.

I applied this approach to all the models in my scene and this was the final render:

Render from 3D Studio Max of the development materials (including diffuse, normal and specular mapping) applied to the house model

I decided to model just the front detail as that would provide me with enough content to evaluate if the model would still look realistic when it has been imported and run in WebGL. At this point I still had no idea how it was going to look or even if Three.js can provide me with enough access to WebGL shaders in order for me to recreate the complex materials I had applied to my model in 3D Studio Max.

The final model (scene) for export contains 2600 polygons, 3000 vertices, 1 directional light, 2 omni lights and 9 materials.

I will report how the import and WebGL process went in a follow-up post soon.