Sketch 3 — loading and manipulating models

The following code loads a glTF file into the scene:

// clears everything (this is optional
// but handier than pressing 'file' / 'new')
clearAll()

// this maps a directory from your computer into
// the webspace of the browser
// this means that http://your.ip.address:8090/myfiles/somefile
// points to the file 'somefile' on my Desktop
mapDirectory("/Users/marc/Desktop/", "/myfiles")

// finally, this loads a .gltf file (and any attendant .bin file)
loadGLTF("/myfiles/first.gltf", "myfile")

The result of loading this scene is two-fold. Firstly, you’ll be able to see your seen in the browser — as usual it might be behind you, it might be too big, you might be inside it, it might be pitch black (no lights?) etc. Secondly, Field will create a new variable (as in var) called myfile which contains information and access to the things that you’ve loaded. Feel free to pass in any legal name for this argument

Please note, loadGLTF will return before the model and before myfile is set. Wait until the model has been loaded before proceeding. ** See this note in the reference for a way around this in alpha15.c and beyond

The contents of the myfile vary a little depending on the loader that you are using, but it will contain at the very least:

// play the animation from where you are
myfile.play()

// stop playing the animation
myfile.stop()

// move to 0.5 seconds into the animation and stop
myfile.apply(0.5)

To find out the current contents of myfile simply print(myfile). We’ll probably broaden

In addition to loadGLTF you’ll find loadFBX (for .fbx files, popular in AutoDesk apps) and loadJSONScene (for scenes that have been exported from our editor with ‘export scene’). These have the same arguments. If popular demand requires we can also do .obj (no animations) and .dae.

known glTF exporters

For Blender — https://github.com/KhronosGroup/glTF-Blender-Exporter. Blender is available for free https://www.blender.org/. It has a almost completely inscrutable interface that bucks all convention offset, in part, by a solid set of tutorials.

For Maya https://kashika.co.jp/product/gltfexporter/ — but note that Maya’s FBX exporter is fairly solid.

Accessing parts of the scene by name

Take care to name things before you export them — you can check that the names have come in correctly in the top right hand corner of our editor. Once named you can search over the scene-graph by name in Field:

var cube = findByName("Cube")

Finds the first Three.js object in the Scene called ‘name’. Case sensitive, ‘Scene’ is not the same as an object called ‘sceNE’.

var something = findBySearchingFor("ube")

Finds the first Three.js object in the Scene with a name containing ‘pattern’. E.g findBySearchingFor('ear) matches an object called Pear

This will work for geometry (like cubes and the skins of characters) and other things (like lights and groups of objects that have no specific geometry themselves). Once you have part of your scene you need to figure out what you can do to it.

var c = findByName("Cube001")

c.position.x=5 // move the model around
c.rotation.z=5 // rotate this group
c.visible=false // make it invisible
c.material.opacity=0.3 // change aspects of its material

The best way to do this is to write c. (our variable containing the thing that we want to inspect) and then press ctrl-period to bring up autocompletion, and then start typing to search. This integrates the documentation and some live introspection and lets us see what kinds of things we can type.

A more sophisticated example

Here’s some more example code (that uses the new syntax for deferred execution and a Duck model curtesy of Pamela:

// clear everything
clearAll()

// we need to name successive ducks differently
var number = 0

// hold onto the most recently fired animation
// so we can stop it again
var mostRecent

// when the mouse/finger is pressed
mouseDown.ball = (event) =>
{
    // come up with a 'unique' name
    number ++
    var name = "bounce"+number
    // name is now a 'unique' name
    // so we can 'findByName' on it correctly

    // load a model and call it's root `name`
    loadFBX("/myfiles/ducky.fbx", name, (x) => {
        var c = findByName(name)
        c.scale.x = 0.01
        c.scale.y = 0.01
        c.scale.z = 0.01

        x.play(false) // play without looping

        // hold onto the object that controls playback		
        mostRecent = x
    })
}

// when the finger is released
mouseUp.ball = (event) =>
{
	// pause it (stopping it will reset to the non-animated position which will look odd)
	mostRecent.pause()
}

That’s two levels of indirection (when the mouse is pressed, load -> when the loading is finished -> scale and play). When studying this code think about how you would have come to write it. In particular how you would test those pieces of code that are deferred in more direct ways.