Hello and welcome to this final module in which we’re going to be doing some slightly more advanced things. Particularly, we’re going to be loading in mesh geometry which is not for the standard, primitive mesh geometry that we’ve been using so far. So far we’ve used planes and spheres and cubes or boxes which can be created mathematically essentially, but to create more complex shapes and more interesting shapes, we need to download and use more interesting geometry, or you can create your own meshes in any sort of popular 3D modelling package. Blender is a common one which is free but, of course, there’s the Autodesk packages, such as Maya and 3D Studio Max and so on and so forth.
For the purposes of this course, we’ve downloaded some data from this fantastic repository at Williams College in United States, the McGuire Graphics Data. Very famous data set. And we’re particularly using the head here of Lee-Perry Smith, which is quite a famous asset to be using. And we’ve converted some of the textures to make them more suitable for web-rendering and you can download all the assets, again, from the course website. Ok, so what we need to do here is, we’ve downloaded the file in .obj format, WaveFront .obj, which is ASCII format, not the most efficient format for the web, but it will serve for our purposes.
What we need to is, we need to load that .obj file into our renderer and display it on the screen, and that’s the objective of this first lesson. So let’s go to our code. We still have the same code from the last lesson, we still have our globe which is rotating our star field, and we’re gonna really gut this now, ok?
So we’re gonna rip out the clouds, we’re gonna rip out the star fields and rip out the material, and we’re gonna keep the function “createLight” in there, but we’re gonna rip out out all these things, we’re gonna rip out the scene movement, we’re gonna keep the camera controls in because they’re quite useful, we’re gonna rip out these lights and replace them with the Spotlight that we had a while ago. So, in the “createLight” function we’re just gonna create a Spotlight. It’s very similar to what we did in the very first lesson actually, when we created a sphere, in our very first lesson to do with programming, at least, and we’re gonna create a white Spotlight.
And we’re gonna set its position
to something which I know that looks quite dramatic, and we’re gonna do the same thing with the shadow maps, so we’re gonna use a shadow map later on as well. “shadowCameraNear”.
You may ask how do I know these values. Well, I’ve just been testing them. One of the things, the frustrating things sometimes about 3D graphics that you really have to, to get things to look good you have to just trial and error, try different settings, try different values to see if you can get things to work nicely. And so if you trial and error, I’ve found these settings that look quite reasonable in the final scene. And so we’ve added the Spotlight to the scene. So now we’re creating the renderer, creating the camera, creating the lights. All these functions are the same. We’re back now, almost, to the very core code that we had right at the very first lesson.
We’re just gonna change the camera position back to something a little bit closer again as well, “15”, “16” and “23”, and so if we just play that now we’ll see a black screen, we’re not loading anything in. So, our objective now is, we need to load in a 3D mesh, so we’re gonna create a function here called “loadModel”,
and let’s just create some material in advance, we’ll explain why in a little bit, we’re just gonna create a very simple Phong material, no textures so far, just a very simple Phong material
and I’ve stored in the assets file, assets folder, sorry, an .obj which is our Lee head and just like with the images, we write a callback function, and we’re gonna pass one parameter which should be the object we’ve downloaded. Now here it’s a little bit complicated, because .obj format can’t store various meshes within a single file, so we need just to traverse all the objects stored within that object, if you would. What we also need to do then as well, once we’ve traversed, is put another callback function here, which we need to access for every child mesh in our objects file, we need to load the objects into the scene. So, let’s just go with that again.
We’ve created a loader object here, we’re loading in our .obj file, and there’s a callback, which we’re gonna call at the end of that, once we’ve finished downloading the data, we’re gonna do this callback. But the problem is that the WaveFront object file may contain several different meshes, so we’re gonna use the call to traverse things, traverse the object that’s been created, this object here, and for every single mesh that’s stored in the file, we’re going to create that mesh as a three.js mesh. In this case, there is only one, but we’ve included this code here because it’s relevant, because you may have more than one mesh stored within your .obj file. Ok, so we’re now accessing the mesh.
We just need to skip up the prototype chain because of the way the inheritance works in three.js. We need to make sure that the child we’re referencing here, in this callback function, it’s an instance of three.js, a three.js mesh object. And so we skip the prototype chain with the “instanceof” keywords, so we just skip up here “THREE.Mesh”, and that’s just basically looking at the prototype chain to assure ourselves that the child object here is a type of “THREE.Mesh”. And with that we can then set the material of this child to be the material that we created up here, ok? And what we’re gonna do is just change the position of this as well, “.y”,
we’re going to make it, just bring it down by 10 units.
And then, finally, we’re going to add the object to the scene, so we’re gonna go “scene.Add”,
and we’re adding everything now that’s in this, and “object” to the scene. So basically, we’ve loaded in our object, there’s a callback when it’s finished loading, we’re traversing every single one of the
potential meshes within our file, for every one we execute this function, which passes this parameter, which is the child of this object, it’s a new one in this case; we’re skipping out the prototype chain to make sure that that child is an instance of “THREE.Mesh”, and with that we can set the material of that mesh to be the material we created above and change its position to be down here, ok? So it’ll be down -10 units in Y. So let’s just load in this model into the scene, and with a little bit of luck it will appear.
There we go! So there is our object, which has been loaded into the scene with a very basic material. There’s quite a lot, sort of complicated code going on here, with several different functions within a function and functions, but that’s required essentially because of the asynchronous nature of WebGL and Web3D, because we have to load the object and it might take some time to download, we can’t just add it to the scene straightaway, and that’s why we require that. Ok? And I think that’s it for this lesson.