# Ben Scott

Loading 3D models in and putting them right on this webpage here right now via Three.js. It’s pretty limited in what it can do presently, but hopefully I can add some stuff to allow for better customization.

### Ben Scott # 2015-10-26 # Viewer ###

'use strict' # just like JavaScript

### Constants & Aliases ###
{abs,floor,random,sqrt} = Math # destructuring fun
T = THREE

### DOM ###
dir = "/js/assets/" # directory
divID = "CoffeeCode" # id of parent
container = null # parent in the HTML document

### WebGL ###
renderers = [] # list of objects to render


### Main

This is the program entrypoint, and it initializes all of the Three.js objects.

• @scene: An object representing everything in the environment, including cameras, 3D models, etc.
• @camera: The main rendering viewpoint, typically uses perspective rather than orthogonal rendering.
• @renderer: … I’ll… get back to you about exactly what it is that this one does!
class Main
constructor: (filename) ->
@scene = new T.Scene()
@scene.fog = new T.Fog(0x00,2**12,2**16)
@camera = new T.PerspectiveCamera(
75,768/512,1,65536)
@renderer = new T.WebGLRenderer {
antialias: true, alpha: true }
@renderer.setSize(768,512)
@renderer.setClearColor(0x0,0)
@ambient = new T.AmbientLight(0x404040)
@light = new T.DirectionalLight(0xEFEFED,1)
@light.position.set(512,512,512)
@import3D(filename)

init: (distance = 1024) ->
@initDOM()
@initControls()
@camera.position.z = distance
@render()

initDOM: ->
container = document.getElementById(divID)
container.appendChild(@renderer.domElement)

initControls: ->
@controls = new T.OrbitControls(
@camera,@renderer.domElement)
@controls.userZoom = false

update: ->
@controls.update()


### Main.render

This needs to be a bound function, and is the callback used by requestAnimationFrame, which does a bunch of stuff, e.g., calling render at the proper framerate.

    render: =>
requestAnimationFrame(@render)
@update()
rend.render() for rend in renderers
@renderer.render(@scene,@camera)


### Main.import3D

This needs to be a bound function, and is the callback used by the JSONLoader to initialize geometry from the provided filename.

    import3D: (filename) =>
"/js/3D/#{filename}.js"
(geo) =>
mat = new T.MeshPhongMaterial {
color: 0xAEAEAE
specular: 0x282828 }
mesh = new T.Mesh(geo, mat)
mesh.scale.set(50,50,50)


### @initViewer

This is a global function, callable from other scripts, and will be used with another script on the page to load an arbitrary 3D model into a basic scene.

@initViewer = (filename, distance=1024) =>
main = new Main(filename)
main.init(distance)


Finally, the page needs to start the program and provide a filename for the 3D model (from which other data like textures will be inferred).

<script language="javascript">
initViewer("purple-root",2)
</script>


In this case, the argument to initViewer is a template variable, defined in the post’s Jekyll Frontmatter. I require a filename, but the camera render distance is optional. In the future, I hope to have more parameters / a better way to pass more complicated data to the function.