CS 424: Computer Graphics, Fall 2015
Lab 10: More Three.js

In this lab, you will work on a three.js application that uses two of its more interesting features: raycaster input and cubemap textures. As your starting point for the lab, you should get a copy of the folder lab10-files from /classes/cs424. You will work on the file lab10.html. Currently, it shows some colored spheres bouncing inside a translucent box. In the completed program, when the user clicks on a sphere, it will be removed (and possibly be replaced by several smaller spheres), and the scene will be enclosed in a skybox that is also reflected by the spheres. Your program might not look exactly like mine, but here is a screenshot from my completed vesion:

This lab is due next Thursday, November 12. If you have not changed anything outside of lab10.html, it's sufficient to copy that file into your homework folder. If you are using a different cubemap texture, then you should submit your entire lab10 folder.

Reminder: Your Blender work is due next Monday. It should be in a folder named blender in your homework folder. If you have extra time today, consider working on and improving your Blender projects! (And if the only extra animation that you are adding to your Frosty project is falling snow, make sure that it looks and falls like snow.)

Reminder: You should let me know your definite plans for your final project tomorrow (November 6). You can send me an email or turn in something in writing in class. A paragraph or two should be sufficient, but it should include a description of what you expect the project to consist of.

Raycaster Input

You can do this part of the lab before or after the cubemap texture parts.

Objects of type THREE.Raycaster can be used to let the user use the mouse to "pick" one of the objects in the scene. You can read about raycasters and user input in Section 5.3.2, and you could also check the API documentation online.

You want to use a raycaster to respond to user mouse clicks. The raycaster's setFromCamera() and intersectObject() methods can be used to determine which sphere, if any, the user clicked. (The spheres in the program are all parented to a THREE.Object3D named ballHolder. You can use ballHolder in a call to raycaster.intersectObject() to check for intersections with the spheres. Or use ballHolder.children in a call to raycaster.intersectObjects().)

You will need an event-handler for mouse clicks, typically defined as function doMouseDown(evt). That function should be added as an event listener to the canvas in the init() function, using

canvas.addEventListener("mousedown",doMouse,false);

See Section 5.3.2 for help with writing the function. In the event-handler function, if the user clicked a sphere, you should remove that sphere from the scene. For full credit, you should also replace that sphere with something. One possibility is two or more small white spheres, moving in different directions, that the user can't remove by clicking, so that eventually, there will only be a bunch of white spheres remaining. Another possibility is to use smaller clones of the removed sphere, and to make them removable by clicking. (But you shouldn't keep dividing spheres into smaller pieces—when the user clicks one of the smaller spheres, it should just disappear.) You might come up with a better possibility.

When a sphere is removed from the scene, it should also really be removed from the array named balls. Otherwise, the program will keep updating the position of the sphere, even though it is no longer in the scene. You will have to study the program to see how to do this; balls is an array of JavaScript objects, and the Three.js object for sphere number i is actually referenced in the array as balls[i].obj. So, you will have to search for the location of the sphere in the array. Note that the way to remove element number i from the JavaScript array balls is to call

balls.splice( i, 1 ); // (The second parameter is a one.)

Skybox and Environment Map

Three.js support for cubemap textures is discussed in Section 5.3.4 and Section 5.3.5 in the textbook. For a cubemap texture, you need six images, one for each side of a cube. The folder named Coliseum in lab10-files contains the six images for a cubemap texture. I got the images from

http://www.humus.name/index.php?page=Textures

You can also use the Coliseum, or if you want something different, you could download another example from the above site. (But note that I reduced the sizes of the Coliseum images to 512-by-512 to make them more suitable for use on the Web. The original images can be quite large.)

For this lab, you want to use the cubemap texture to make a skybox that surrounds the scene, and you want to apply it as an environment map to the spheres so that it looks as though they are reflecting the skybox. Here is the sample code from Section 5.3.4 for making a cubemap texture and applying it to a skybox cube. You just have to change the file names to adapt it for your own images:

var textureURLs = [  // URLs of the six faces of the cube map 
        "cubemap-textures/park/posx.jpg",   // Note:  The order in which
        "cubemap-textures/park/negx.jpg",   //   the images are listed is
        "cubemap-textures/park/posy.jpg",   //   important!
        "cubemap-textures/park/negy.jpg",  
        "cubemap-textures/park/posz.jpg",   
        "cubemap-textures/park/negz.jpg"
   ];

var texture = THREE.ImageUtils.loadTextureCube( textureURLs );

var shader = THREE.ShaderLib[ "cube" ]; // contains the required shaders
shader.uniforms[ "tCube" ].value = texture; // data for the shaders
var material = new THREE.ShaderMaterial( {
        // A ShaderMaterial uses custom vertex and fragment shaders.
    fragmentShader: shader.fragmentShader,
    vertexShader: shader.vertexShader,
    uniforms: shader.uniforms, 
    depthWrite: false,
    side: THREE.BackSide
} );

var skybox = new THREE.Mesh( new THREE.CubeGeometry( 100, 100, 100 ), material );

You can apply the same texture as an environment map to the spheres. In fact, as explained in Section 5.3.5, it is only necessary to assign the cubemap texture to the envMap property of the material that is used on the spheres.