4. TODAY
1. (v1) Angular & Three.js 3D Model Viewer
2. (v2) “Controller as” &
prototypal Angular components
3. Grunt & Closure compilation approaches
4. (v3*) Scoped scene graph
5. WHY?
Great pattern(s) with low barrier of entry
& high productivity
All web devs can easily be 3D web devs
Isolate THREE code from Angular UI/UX code!
6. THREE WHAT?
threejs.org three features
● Renderers
● Scene Graph
● Cameras
● Animation
● Lights
● Materials
● Shaders
● Objects
● Geometry
● Loaders
● Utilities
● Export/Import
● Support
● Examples
● WebVR
● DIYVR
Started by Mr. Doob on April 23, 2010
9. CONTROLLER
AppController
CONTROLLER
FileLoaderController
UI Elements and Controllers
DIRECTIVE INCLUDE
file-loader.html
DIRECTIVE INCLUDE
about.html
DIRECTIVE INCLUDE
chrome.html
DIRECTIVE INCLUDE
toolbar.html
10. CONTROLLER
FileLoaderController
Dependency Injections Across Angular Components
CONTROLLER
AppController
DIRECTIVE
select
SERVICE
StorageService
SERVICE
MessageBus
FACTORY
Viewer
11. Viewer.factory('ViewerFactory', … ) {
init()
home = new Viewer.Scene()
animate ()
render ()
makeSelection ()
loadOBJMTL ()
loadGLTF ()
loadOBJ ()
loadJSON ()
scale ()
rotate ()
/** Translate the model along an axis
* @param {number} x
* @param {number} y
* @param {number} z */
translate (x,y,z)
home.wrangler.currentModel.position.set(x, y, z);
CONTROLLER
AppController
● init ()
● rotate ()
● scale ()
● translate ()
SERVICE
MessageBus
DIRECTIVE
select
● makeSelection ()
CONTROLLER
FileLoaderController
● loadOBJMTL ()
● loadGLTF ()
● loadOBJ ()
● loadJSON ()
Viewer Factory Interface
12. Viewer Factory Architecture
Viewer Factory Singleton
function init(params) {
home = new Viewer.Scene(params);
animate();
}
Viewer.Scene()
this.scene
THREE.Scene()
this.renderer
THREE.WebGLRenderer()
this.wrangler
Viewer.Wrangler()
function animate () {
requestAnimationFrame(animate);
render();
}
this.setup
Viewer.Setup()
this.cameras
Viewer.Cameras()
this.controls
THREE.OrbitControls()
this.raycaster
THREE.Raycaster()
13. USE CASE - User Click, Intersect 3D Model, Return Model Information
Angular Directive, <canvas select>
elem.on(tap, function(e)
x = e.gesture.center.x;
y = e.gesture.center.y;
// creating NDC coordinates for ray intersection.
mouseDown.x = (x / width) * 2 - 1;
mouseDown.y = -(y / height) * 2 + 1;
ViewerFactory.makeSelection(mouseDown);
Viewer Factory, makeSelection
makeSelection(mouse):
Angular Controller/Factory
$scope.$on(‘objectSelected’, function () {
// Do Something.
});
var vector = new THREE.Vector3( mouse.x, mouse.y, 1).unproject(home.cameras.liveCam);
home.raycaster.set(home.cameras.liveCam.position, vector.sub(home.cameras.liveCam.position).normalize());
var intersected = home.raycaster.intersectObjects(home.wrangler.currentModel, true);
MessageBus.trigger('objectSelected', intersected[0])
19. Service, !Factory
Viewer.ViewerService
.prototype
init
listeners
animate
render
makeSelection
loadOBJMTL
loadOBJ
loadGLTF
loadJSON
rotate
translate
scale
● No More Factories
○ closure pattern
● Instead, prototypal Service
○ ‘new’ and this
○ .bind() for callbacks
● Saves Memory, Time, Searches (sorry)
● Single Pattern For Everything!
● IMHO, the best way to code JS
21. CAonnntorotallteior nass
/** Service which initiates the THREE.js scene and
* provides methods to interact with that scene
*
* @param {angular.$timeout} $timeout
* @param {!Viewer.MessageBus} MessageBus
* @constructor
* @ngInject
*/
Viewer.ViewerService = function($timeout, MessageBus){
this.timeout = $timeout;
this.MessageBus = MessageBus;
};
/**
* Translate the model along an axis
* @param {number} x
* @param {number} y
* @param {number} z
*/
Viewer.ViewerService.prototype.translate = function(x, y, z){
this.home.wrangler.currentModel.position.set(x, y, z)
};
/**
* @param {number} s
*/
Viewer.ViewerService.prototype.scale = function(s) {
this.home.wrangler.currentModel.scale.set(s, s, s);
};
The Closure Compiler can use data type
information about JavaScript variables to provide
enhanced optimization and warnings.