浏览代码

Merge branch 'dev' of https://github.com/mrdoob/three.js into orthographic-trackball-updates

Conflicts:
	examples/js/controls/OrthographicTrackballControls.js
Max Smolens 10 年之前
父节点
当前提交
f560c79da2
共有 100 个文件被更改,包括 3136 次插入1810 次删除
  1. 1 1
      LICENSE
  2. 1 1
      bower.json
  3. 134 751
      build/three.js
  4. 38 41
      build/three.min.js
  5. 50 17
      docs/api/core/Object3D.html
  6. 89 9
      docs/api/core/Raycaster.html
  7. 1 1
      docs/api/extras/ImageUtils.html
  8. 14 0
      docs/api/math/Euler.html
  9. 10 0
      docs/api/math/Matrix4.html
  10. 5 0
      docs/api/objects/Line.html
  11. 6 0
      docs/api/objects/Mesh.html
  12. 5 0
      docs/api/objects/PointCloud.html
  13. 2 2
      docs/api/renderers/WebGLRenderer.html
  14. 4 4
      docs/manual/introduction/Creating-a-scene.html
  15. 118 118
      docs/scenes/js/material.js
  16. 12 1
      editor/css/dark.css
  17. 12 1
      editor/css/light.css
  18. 10 1
      editor/css/main.css
  19. 172 0
      editor/examples/camera.app.json
  20. 99 0
      editor/examples/particles.app.json
  21. 137 0
      editor/examples/pong.app.json
  22. 14 12
      editor/index.html
  23. 117 4
      editor/js/Editor.js
  24. 29 4
      editor/js/Menubar.Add.js
  25. 6 2
      editor/js/Menubar.Edit.js
  26. 60 0
      editor/js/Menubar.Examples.js
  27. 16 52
      editor/js/Menubar.File.js
  28. 1 1
      editor/js/Menubar.Play.js
  29. 34 0
      editor/js/Menubar.View.js
  30. 1 0
      editor/js/Menubar.js
  31. 10 3
      editor/js/Player.js
  32. 91 0
      editor/js/Script.js
  33. 3 3
      editor/js/Sidebar.Object3D.js
  34. 1 1
      editor/js/Sidebar.Scene.js
  35. 0 46
      editor/js/Sidebar.Script.Editor.js
  36. 80 13
      editor/js/Sidebar.Script.js
  37. 27 17
      editor/js/Viewport.js
  38. 128 46
      editor/js/libs/app.js
  39. 22 14
      editor/js/libs/codemirror/codemirror.css
  40. 344 229
      editor/js/libs/codemirror/codemirror.js
  41. 8 8
      editor/js/libs/codemirror/mode/javascript.js
  42. 31 0
      editor/js/libs/codemirror/theme/monokai.css
  43. 0 75
      editor/js/libs/ui.editor.js
  44. 14 3
      editor/js/libs/ui.js
  45. 1 0
      examples/canvas_ascii_effect.html
  46. 5 4
      examples/canvas_interactive_cubes.html
  47. 5 4
      examples/canvas_interactive_cubes_tween.html
  48. 5 5
      examples/canvas_interactive_particles.html
  49. 5 5
      examples/canvas_interactive_voxelpainter.html
  50. 1 2
      examples/canvas_lines_colors.html
  51. 1 2
      examples/canvas_lines_colors_2d.html
  52. 1 1
      examples/canvas_lines_dashed.html
  53. 2 1
      examples/index.html
  54. 9 2
      examples/js/controls/OrthographicTrackballControls.js
  55. 12 12
      examples/js/crossfade/scenes.js
  56. 5 1
      examples/js/effects/StereoEffect.js
  57. 8 0
      examples/js/loaders/ColladaLoader.js
  58. 1 0
      examples/js/loaders/MTLLoader.js
  59. 2 1
      examples/js/loaders/OBJMTLLoader.js
  60. 21 1
      examples/js/loaders/STLLoader.js
  61. 7 80
      examples/js/loaders/SceneLoader.js
  62. 5 5
      examples/js/modifiers/TessellateModifier.js
  63. 1 1
      examples/js/renderers/CanvasRenderer.js
  64. 1 1
      examples/js/renderers/Projector.js
  65. 616 0
      examples/js/shaders/NormalDisplacementShader.js
  66. 1 1
      examples/misc_animation_keys.html
  67. 22 42
      examples/misc_controls_fly.html
  68. 1 1
      examples/misc_controls_orbit.html
  69. 1 1
      examples/misc_controls_trackball.html
  70. 44 40
      examples/models/molecules/aspirin.pdb
  71. 1 1
      examples/scenes/test_scene.js
  72. 1 2
      examples/webgl_animation_skinning_blending.html
  73. 1 2
      examples/webgl_animation_skinning_morph.html
  74. 1 1
      examples/webgl_buffergeometry.html
  75. 300 0
      examples/webgl_buffergeometry_drawcalls.html
  76. 1 1
      examples/webgl_buffergeometry_particles.html
  77. 1 1
      examples/webgl_buffergeometry_uint.html
  78. 1 1
      examples/webgl_custom_attributes.html
  79. 1 1
      examples/webgl_custom_attributes_lines.html
  80. 5 7
      examples/webgl_decals.html
  81. 1 1
      examples/webgl_effects_oculusrift.html
  82. 3 3
      examples/webgl_effects_vr.html
  83. 0 3
      examples/webgl_geometries2.html
  84. 1 1
      examples/webgl_geometry_colors_lookuptable.html
  85. 1 1
      examples/webgl_geometry_dynamic.html
  86. 1 1
      examples/webgl_geometry_minecraft.html
  87. 1 1
      examples/webgl_geometry_shapes.html
  88. 6 7
      examples/webgl_geometry_terrain_raycast.html
  89. 2 2
      examples/webgl_geometry_text.html
  90. 3 3
      examples/webgl_geometry_text2.html
  91. 26 27
      examples/webgl_gpgpu_birds.html
  92. 3 5
      examples/webgl_interactive_buffergeometry.html
  93. 3 3
      examples/webgl_interactive_cubes.html
  94. 1 1
      examples/webgl_interactive_cubes_gpu.html
  95. 3 4
      examples/webgl_interactive_cubes_ortho.html
  96. 2 3
      examples/webgl_interactive_draggablecubes.html
  97. 13 13
      examples/webgl_interactive_lines.html
  98. 4 6
      examples/webgl_interactive_particles.html
  99. 3 6
      examples/webgl_interactive_raycasting_pointcloud.html
  100. 6 8
      examples/webgl_interactive_voxelpainter.html

+ 1 - 1
LICENSE

@@ -1,6 +1,6 @@
 The MIT License
 
-Copyright © 2010-2014 three.js authors
+Copyright © 2010-2015 three.js authors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
 	"name": "three.js",
-	"version": "0.0.69",
+	"version": "0.0.70",
 	"homepage": "http://threejs.org/",
 	"description": "JavaScript 3D library",
 	"main": "build/three.js",

文件差异内容过多而无法显示
+ 134 - 751
build/three.js


文件差异内容过多而无法显示
+ 38 - 41
build/three.min.js


+ 50 - 17
docs/api/core/Object3D.html

@@ -25,7 +25,7 @@
 
 		<h3>[property:Integer id]</h3>
 		<div>
-		Unique number for this object instance.
+		readonly – Unique number for this object instance.
 		</div>
 
 		<h3>[property:String uuid]</h3>
@@ -59,11 +59,6 @@
 		Object's local rotation (<a href="https://en.wikipedia.org/wiki/Euler_angles" target="_blank">Euler angles</a>), in radians.
 		</div>
 
-		<h3>[property:String eulerOrder]</h3>
-		<div>
-		Order of axis for Euler angles.
-		</div>
-
 		<h3>[property:Vector3 scale]</h3>
 		<div>
 		Object's local scale.
@@ -81,48 +76,64 @@
 
 		<h3>[property:Quaternion quaternion]</h3>
 		<div>
-		Object's local rotation as [page:Quaternion Quaternion]. Only used when useQuaternion is set to true.
-		</div>
-
-		<h3>[property:Boolean useQuaternion]</h3>
-		<div>
-		Use quaternion instead of Euler angles for specifying local rotation.
+		Object's local rotation as [page:Quaternion Quaternion].
 		</div>
 
 		<h3>[property:Boolean visible]</h3>
 		<div>
 		Object gets rendered if *true*.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:Boolean castShadow]</h3>
 		<div>
 		Gets rendered into shadow map.
 		</div>
+		<div>
+		default – false
+		</div>
 
 		<h3>[property:Boolean receiveShadow]</h3>
 		<div>
 		Material gets baked in shadow receiving.
 		</div>
+		<div>
+		default – false
+		</div>
 
 		<h3>[property:Boolean frustumCulled]</h3>
 		<div>
 		When this is set, it checks every frame if the object is in the frustum of the camera. Otherwise the object gets drawn every frame even if it isn't visible.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:Boolean matrixAutoUpdate]</h3>
 		<div>
 		When this is set, it calculates the matrix of position, (rotation or quaternion) and scale every frame and also recalculates the matrixWorld property.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:Boolean matrixWorldNeedsUpdate]</h3>
 		<div>
 		When this is set, it calculates the matrixWorld in that frame and resets this property to false.
 		</div>
+		<div>
+		default – false
+		</div>
 
 		<h3>[property:Boolean rotationAutoUpdate]</h3>
 		<div>
 		When this is set, then the rotationMatrix gets calculated every frame.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:object userData]</h3>
 		<div>
@@ -195,29 +206,46 @@
 		Rotates object to face point in space.
 		</div>
 
-		<h3>[method:null add]( [page:Object3D object] )</h3>
+		<h3>[method:null add]( [page:Object3D object], ... )</h3>
 		<div>
 		object - An object.<br />
 		</div>
 		<div>
-		Adds *object* as child of this object.
+		Adds *object* as child of this object. An arbitrary number of objects may be added.
 		</div>
 
-		<h3>[method:null remove]( [page:Object3D object] )</h3>
+		<h3>[method:null remove]( [page:Object3D object], ... )</h3>
 		<div>
 		object - An object.<br />
 		</div>
 		<div>
-		Removes *object* as child of this object.
+		Removes *object* as child of this object. An arbitrary number of objects may be removed.
 		</div>
 
 		<h3>[method:null traverse]( [page:Function callback] )</h3>
 		<div>
-		callback - An Function with as first argument an object3D object.<br />
+		callback - A function with as first argument an object3D object.<br />
 		</div>
 		<div>
 		Executes the callback on this object and all descendants.
 		</div>
+		
+		<h3>[method:null traverseVisible]( [page:Function callback] )</h3>
+		<div>
+		callback - A function with as first argument an object3D object.<br />
+		</div>
+		<div>
+		Like traverse, but the callback will only be executed for visible objects.
+		Descendants of invisible objects are not traversed.
+		</div>
+		
+		<h3>[method:null traverseAncestors]( [page:Function callback] )</h3>
+		<div>
+		callback - A function with as first argument an object3D object.<br />
+		</div>
+		<div>
+		Executes the callback on this object and all ancestors.
+		</div>
 
 		<h3>[method:null updateMatrix]()</h3>
 		<div>
@@ -271,6 +299,11 @@
 		Rotate an object along an axis in object space. The axis is assumed to be normalized.
 		</div>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Abstract method to get intersections between a casted ray and this object. Subclasses such as [page:Mesh], [page:Line], and [page:PointCloud] implement this method in order to participate in raycasting.
+		</div>
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 89 - 9
docs/api/core/Raycaster.html

@@ -11,18 +11,67 @@
 
 		<div class="desc">
 		This class makes raycasting easier. Raycasting is used for picking and more.
+		</div>
+
+		<h2>Example</h2>
+		<code>
+		var raycaster = new THREE.Raycaster();
+		var mouse = new THREE.Vector2();
+
+		function onMouseMove( event ) {
+
+			// calculate mouse position in normalized device coordinates
+			// (-1 to +1) for both components
+
+			mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1
+			mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1		
+		
+		}
+
+		function render() {
+
+			// update the picking ray with the camera and mouse position	
+			raycaster.setFromCamera( mouse, camera );	
+
+			// calculate objects intersecting the picking ray
+			var intersects = raycaster.intersectObjects( scene.children );
+
+			for ( var intersect in intersects ) {
+
+				intersect.object.material.color = new THREE.Color( 0xff0000 );
 			
+			}
+			
+			renderer.render( scene, camera );
+
+		}
+
+		window.addEventListener( 'mousemove', onMouseMove, false );
+
+		window.requestAnimationFrame(render);
+
+		</code>
+		<div>Examples: [example:webgl_interactive_cubes Raycasting to a Mesh], 
+			[example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera], 
+			[example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry], 
+			[example:webgl_interactive_lines Raycasting to a Line], 
+			[example:webgl_interactive_raycasting_pointcloud Raycasting to a PointCloud], 
+			[example:webgl_geometry_terrain_raycast Terrain raycasting], 
+			[example:webgl_octree_raycasting Raycasting using an octree],
+			[example:webgl_interactive_voxelpainter Raycasting to paint voxels]</div>
+
+
+		<div>
 		</div>
 
 
 		<h2>Constructor</h2>
 
-
 		<h3>[name]( [page:Vector3 origin], [page:Vector3 direction], [page:Float near], [page:Float far] ) {</h3>
 		<div>
 		[page:Vector3 origin] — The origin vector where the ray casts from.<br />
 		[page:Vector3 direction] — The direction vector that  gives direction to the ray.<br />
-		[page:Float near] — All results returned are further away then near. Near can't be negative. Default value is 0.<br />
+		[page:Float near] — All results returned are further away than near. Near can't be negative. Default value is 0.<br />
 		[page:Float far] — All results returned are closer then far. Far can't be lower then near . Default value is Infinity.
 		</div>
 		<div>
@@ -51,7 +100,12 @@
 
 		<h3>[property:float precision]</h3>
 		<div>
-		The precision factor of the raycaster. 
+		The precision factor of the raycaster when intersecting [page:Mesh] objects. 
+		</div>
+
+		<h3>.[page:float linePrecision]</h3>
+		<div>
+		The precision factor of the raycaster when intersecting [page:Line] objects. 
 		</div>
 
 		<h2>Methods</h2>
@@ -65,16 +119,45 @@
 		Updates the ray with a new origin and direction.
 		</div>
 
+		<h3>[method:null setFromCamera]( [page:Vector2 coords], [page:Camera camera] )</h3>
+		<div>
+		[page:Vector2 coords] — 2D coordinates of the mouse, in normalized device coordinates (NDC)---X and Y components should be between -1 and 1.<br />
+		[page:Camera camera] — camera from which the ray should originate
+		</div>
+		<div>
+		Updates the ray with a new origin and direction.
+		</div>
+
+
 		<h3>[method:Array intersectObject]( [page:Object3D object], [page:Boolean recursive] )</h3>
 		<div>
+		<p>
 		[page:Object3D object] — The object to check for intersection with the ray.<br />
 		[page:Boolean recursive] — If set, it also checks all descendants. Otherwise it only checks intersecton with the object.
+		</p>
 		</div>
 		<div>
-		checks all intersection between the ray and the object with or without the descendants. Intersections are returned sorted by distance, closest first.
+		Checks all intersection between the ray and the object with or without the descendants. Intersections are returned sorted by distance, closest first. An array of intersections is returned...
         <code>
-            [ { distance, point, face, faceIndex, object }, ... ]
+            [ { distance, point, face, faceIndex, indices, object }, ... ]
         </code>
+        <p>
+        [page:Float distance] – distance between the origin of the ray and the intersection<br />
+        [page:Vector3 point] – point of intersection, in world coordinates<br />
+        [page:Face3 face] – intersected face<br />
+        [page:Integer faceIndex] – index of the intersected face<br />
+        [page:Array indices] – indices of vertices comprising the intersected face<br />
+        [page:Object3D object] – the intersected object
+    	</p>
+        <p>
+        When intersecting a [page:Mesh] with a [page:BufferGeometry], the *faceIndex* will be *undefined*, and *indices* will be set; when intersecting a [page:Mesh] with a [page:Geometry], *indices* will be *undefined*. 
+        </p>
+		<p>
+		*Raycaster* delegates to the [page:Object3D.raycast raycast] method of the passed object, when evaluating whether the ray intersects the object or not. This allows [page:Mesh meshes] to respond differently to ray casting than [page:Line lines] and [page:PointCloud pointclouds].
+		</p>
+		<p>
+		*Note* that for meshes, faces must be pointed towards the origin of the [page:.ray ray] in order to be detected; intersections of the ray passing through the back of a face will not be detected. To raycast against both faces of an object, you'll want to set the [page:Mesh.material material]'s [page:Material.side side] property to *THREE.DoubleSide*.  
+		</p>
 		</div>
 
 		<h3>[method:Array intersectObjects]( [page:Array objects], [page:Boolean recursive] )</h3>
@@ -83,10 +166,7 @@
 		[page:Boolean recursive] — If set, it also checks all descendants of the objects. Otherwise it only checks intersecton with the objects.
 		</div>
 		<div>
-		checks all intersection between the ray and the objects with or without the descendants. Intersections are returned sorted by distance, closest first.
-        <code>
-            [ { distance, point, face, faceIndex, object }, ... ]
-        </code>
+		Checks all intersection between the ray and the objects with or without the descendants. Intersections are returned sorted by distance, closest first. Intersections are of the same form as those returned by [page:.intersectObject].
 		</div>
 
 

+ 1 - 1
docs/api/extras/ImageUtils.html

@@ -58,7 +58,7 @@
 		<h3>[method:todo loadTexture]([page:String url], [page:UVMapping mapping], [page:Function onLoad], [page:Function onError])</h3>
 		<div>
 		url -- the url of the texture<br />
-		mapping -- Can be an instance of [page:UVMapping THREE.UVMapping], [page:CubeReflectionMapping THREE.CubeReflectionMapping] or [page:SphericalReflectionMapping THREE.SphericalReflectionMapping]. Describes how the image is applied to the object.<br />Use undefined instead of null as a default value. See mapping property of [page:Texture texture] for more details.
+		mapping -- Can be an instance of [page:UVMapping THREE.UVMapping], [page:CubeReflectionMapping THREE.CubeReflectionMapping] or [page:SphericalReflectionMapping THREE.SphericalReflectionMapping]. Describes how the image is applied to the object.<br />Use undefined instead of null as a default value. See mapping property of [page:Texture texture] for more details. <br/>
 		onLoad -- callback function<br />
 		onError -- callback function
 		</div>

+ 14 - 0
docs/api/math/Euler.html

@@ -91,6 +91,20 @@
     WARNING: this discards revolution information.
     </div>
 
+    <h3>[method:Euler setFromVector3]([page:Vector3 vector], [page:String order]) [page:Euler this]</h3>
+    <div>
+    vector -- [page:Vector3].
+    order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
+    </div>
+    <div>
+    Optionally Vector3 to the XYZ parameters of Euler, and order to the Euler's order property.
+    </div>
+
+    <h3>[method:Vector3 toVector3]()</h3>
+    <div>
+    Returns the Euler's XYZ properties as a Vector3.
+    </div>
+
     <h3>[method:Euler fromArray]([page:Array array]) [page:Euler this]</h3>
     <div>
     array -- [page:Array] of length 3 or 4. array[3] is an optional order argument.

+ 10 - 0
docs/api/math/Matrix4.html

@@ -71,6 +71,16 @@
 		Copies the translation component of the supplied matrix *m* into this matrix translation component.
 		</div>
 
+		<h3>[method:Matrix4 makeBasis]( [page:Vector3 xAxis], [page:Vector3 zAxis], [page:Vector3 zAxis] ) [page:Matrix4 this]</h3>
+		<div>
+		Creates the basis matrix consisting of the three provided axis vectors.  Returns the current matrix.
+		</div>
+
+		<h3>[method:Matrix4 extractBasis]( [page:Vector3 xAxis], [page:Vector3 zAxis], [page:Vector3 zAxis] ) [page:Matrix4 this]</h3>
+		<div>
+		Extracts basis of into the three axis vectors provided.  Returns the current matrix.
+		</div>
+
 		<h3>[method:Matrix4 extractRotation]( [page:Matrix4 m] ) [page:Matrix4 this]</h3>
 		<div>
 		Extracts the rotation of the supplied matrix *m* into this matrix rotation component.

+ 5 - 0
docs/api/objects/Line.html

@@ -70,6 +70,11 @@
 
 		<h2>Methods</h2>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Get intersections between a casted ray and this Line. [page:Raycaster.intersectObject] will call this method.
+		</div>
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 6 - 0
docs/api/objects/Mesh.html

@@ -60,6 +60,12 @@
 		Updates the morphtargets to have no influence on the object.
 		</div>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Get intersections between a casted ray and this mesh. [page:Raycaster.intersectObject] will call this method.
+		</div>
+
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 5 - 0
docs/api/objects/PointCloud.html

@@ -42,6 +42,11 @@
 		This creates a clone of the particle system.
 		</div>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Get intersections between a casted ray and this PointCloud. [page:Raycaster.intersectObject] will call this method.
+		</div>
+
 
 		<h2>Source</h2>
 

+ 2 - 2
docs/api/renderers/WebGLRenderer.html

@@ -184,8 +184,8 @@
 
 		<code>// Creates a renderer with red background
 		var renderer = new THREE.WebGLRenderer();
-		renderer.setSize(200, 100);
-		renderer.setClearColor(0xff0000, 1);
+		renderer.setSize( 200, 100 );
+		renderer.setClearColor( 0xff0000 );
 		</code>
 
 		<h3>[method:Color getClearColor]()</h3>

+ 4 - 4
docs/manual/introduction/Creating-a-scene.html

@@ -9,13 +9,13 @@
 	<body>
 		<h1>[name]</h1>
 
-		<div>The goal of this section is to give a brief introduction to Three.js. We will start by setting up a scene, with a spinning cube. A working example is provided at the bottom of the page, if you get stuck, and need help.</div>
+		<div>The goal of this section is to give a brief introduction to Three.js. We will start by setting up a scene, with a spinning cube. A working example is provided at the bottom of the page in case you get stuck and need help.</div>
 
 		<h2>What is Three.js?</h2>
 
-		<div>If you're reading this, you probably have some understanding of what Three.js is, and what it helps you with, but let's try to describe it briefly anyway.</div>
+		<div>Let's try to describe it briefly:</div>
 
-		<div>Three.js is a library that makes WebGL - 3D in the browser - very easy. While a simple cube in raw WebGL would turn out hundreds of lines of Javascript and shader code, a Three.js equivalent is only a fraction of that.</div>
+		<div>Three.js is a library that makes WebGL - 3D in the browser - easy to use. While a simple cube in raw WebGL would turn out hundreds of lines of Javascript and shader code, a Three.js equivalent is only a fraction of that.</div>
 
 		<h2>Before we start</h2>
 		<div>Before you can use Three.js, you need somewhere to display it. Save the following HTML to a file on your computer, along with a copy of <a href="http://threejs.org/build/three.min.js">three.min.js</a> in the js/ directory, and open it in your browser.</div>
@@ -53,7 +53,7 @@
 		document.body.appendChild( renderer.domElement );
 		</code>
 
-		<div>Let's take a moment to explain what's going on here. We have now set up the scene, our camera and the renderer. There are a few different cameras in Three.js, but we'll go more into that later. For now, let's use a PerspectiveCamera. The first attribute is the <strong>field of view</strong>.</div>
+		<div>Let's take a moment to explain what's going on here. We have now set up the scene, our camera and the renderer. There are a few different cameras in Three.js. For now, let's use a PerspectiveCamera. The first attribute is the <strong>field of view</strong>.</div>
 
 		<div>The second one is the <strong>aspect ratio</strong>. You almost always want to use the width of the element divided by the height, or you'll get the same result as when you play old movies on a widescreen TV - the image looks squished.</div>
 

+ 118 - 118
docs/scenes/js/material.js

@@ -3,60 +3,60 @@
  */
 
 var constants = {
-	
+
 	combine: {
-		
+
 		"THREE.MultiplyOperation" : THREE.MultiplyOperation,
 		"THREE.MixOperation" : THREE.MixOperation,
 		"THREE.AddOperation" : THREE.AddOperation
-		
+
 	},
-	
+
 	side : {
-		
+
 		"THREE.FrontSide" : THREE.FrontSide,
 		"THREE.BackSide" : THREE.BackSide,
 		"THREE.DoubleSide" : THREE.DoubleSide
-		
+
 	},
-	
+
 	shading : {
-		
+
 		"THREE.NoShading" : THREE.NoShading,
 		"THREE.FlatShading" : THREE.FlatShading,
 		"THREE.SmoothShading" : THREE.SmoothShading
-		
+
 	},
 
 	colors : {
-		
+
 		"THREE.NoColors" : THREE.NoColors,
 		"THREE.FaceColors" : THREE.FaceColors,
 		"THREE.VertexColors" : THREE.VertexColors
-		
+
 	},
-	
+
 	blendingMode : {
-		
+
 		"THREE.NoBlending" : THREE.NoBlending,
 		"THREE.NormalBlending" : THREE.NormalBlending,
 		"THREE.AdditiveBlending" : THREE.AdditiveBlending,
 		"THREE.SubtractiveBlending" : THREE.SubtractiveBlending,
 		"THREE.MultiplyBlending" : THREE.MultiplyBlending,
 		"THREE.CustomBlending" : THREE.CustomBlending
-		
+
 	},
-	
+
 	equations : {
-		
+
 		"THREE.AddEquation" : THREE.AddEquation,
 		"THREE.SubtractEquation" : THREE.SubtractEquation,
 		"THREE.ReverseSubtractEquation" : THREE.ReverseSubtractEquation
-		
+
 	},
-	
+
 	destinationFactors : {
-		
+
 		"THREE.ZeroFactor" : THREE.ZeroFactor,
 		"THREE.OneFactor" : THREE.OneFactor,
 		"THREE.SrcColorFactor" : THREE.SrcColorFactor,
@@ -65,38 +65,38 @@ var constants = {
 		"THREE.OneMinusSrcAlphaFactor" : THREE.OneMinusSrcAlphaFactor,
 		"THREE.DstAlphaFactor" : THREE.DstAlphaFactor,
 		"THREE.OneMinusDstAlphaFactor" : THREE.OneMinusDstAlphaFactor
-		
+
 	},
-	
+
 	sourceFactors : {
-		
+
 		"THREE.DstColorFactor" : THREE.DstColorFactor,
 		"THREE.OneMinusDstColorFactor" : THREE.OneMinusDstColorFactor,
 		"THREE.SrcAlphaSaturateFactor" : THREE.SrcAlphaSaturateFactor
-		
+
 	}
-	
+
 }
 
 function getObjectsKeys( obj ) {
-	
+
 	var keys = [];
-	
+
 	for ( var key in obj ) {
-		
+
 		if ( obj.hasOwnProperty( key ) ) {
-			
+
 			keys.push( key );
-			
+
 		}
-		
+
 	}
-	
+
 	return keys;
 }
 
 var envMaps = (function () {
-	
+
 	var path = "../../examples/textures/cube/SwedishRoyalCastle/";
 	var format = '.jpg';
 	var urls = [
@@ -111,32 +111,32 @@ var envMaps = (function () {
 
 	var refractionCube = new THREE.Texture( reflectionCube.image, THREE.CubeRefractionMapping );
 	reflectionCube.format = THREE.RGBFormat;
-	
+
 	return {
 		none : null,
 		reflection : reflectionCube,
 		refraction : refractionCube
 	};
-	
+
 })();
 
 var envMapKeys = getObjectsKeys( envMaps );
 
 var textureMaps = (function () {
-	
+
 	return {
 		none : null,
 		grass : THREE.ImageUtils.loadTexture( "../../examples/textures/terrain/grasslight-thin.jpg" )
 	};
-	
+
 })();
 
 var textureMapKeys = getObjectsKeys( textureMaps );
 
 function generateVertexColors ( geometry ) {
-	
+
 	for ( var i=0, il = geometry.faces.length; i < il; i++ ) {
-				
+
 		geometry.faces[i].vertexColors.push( new THREE.Color().setHSL(
 			i / il * Math.random(),
 			0.5,
@@ -152,15 +152,15 @@ function generateVertexColors ( geometry ) {
 			0.5,
 			0.5
 		) );
-		
+
 		geometry.faces[i].color = new THREE.Color().setHSL(
 			i / il * Math.random(),
 			0.5,
 			0.5
 		);
-		
+
 	}
-	
+
 }
 
 function generateMorphTargets ( mesh, geometry ) {
@@ -172,7 +172,7 @@ function generateMorphTargets ( mesh, geometry ) {
 		vertices.push( geometry.vertices[ i ].clone() );
 
 		scale = 1 + Math.random() * 0.3;
-		
+
 		vertices[ vertices.length - 1 ].x *= scale;
 		vertices[ vertices.length - 1 ].y *= scale;
 		vertices[ vertices.length - 1 ].z *= scale;
@@ -180,31 +180,31 @@ function generateMorphTargets ( mesh, geometry ) {
 	}
 
 	geometry.morphTargets.push( { name: "target1", vertices: vertices } );
-	
+
 	geometry.update
 
 }
 
 function handleColorChange ( color ) {
-	
+
 	return function ( value ){
-		
+
 		if (typeof value === "string") {
-			
+
 			value = value.replace('#', '0x');
-			
+
 		}
-		
+
 		color.setHex( value );
-		
+
     };
-	
+
 }
 
 function needsUpdate ( material, geometry ) {
-	
+
 	return function () {
-		
+
 		material.shading = +material.shading; //Ensure number
 		material.vertexColors = +material.vertexColors; //Ensure number
 		material.side = +material.side; //Ensure number
@@ -212,63 +212,63 @@ function needsUpdate ( material, geometry ) {
 		geometry.verticesNeedUpdate = true;
 		geometry.normalsNeedUpdate = true;
 		geometry.colorsNeedUpdate = true;
-		
+
 	};
-	
+
 };
 
 function updateMorphs ( torus, material ) {
 
 	return function () {
-		
+
 		torus.updateMorphTargets();
 		material.needsUpdate = true;
-		
+
 	};
-	
+
 }
 
 function updateTexture ( material, materialKey, textures ) {
 
 	return function ( key ) {
-		
+
 		material[materialKey] = textures[key];
 		material.needsUpdate = true;
-		
+
 	};
-	
+
 }
 
 function guiScene ( gui, scene ) {
-	
+
 	var folder = gui.addFolder('Scene');
-	
+
 	var data = {
 		background : "#000000",
 		"ambient light" : ambientLight.color.getHex()
 	}
-	
+
 	var color = new THREE.Color();
 	var colorConvert = handleColorChange( color );
-	
+
 	folder.addColor( data, "background" ).onChange( function ( value ) {
-		
+
 		colorConvert( value );
-		
-		renderer.setClearColor(color.getHex(), 1);
-		
+
+		renderer.setClearColor( color.getHex() );
+
 	} );
-	
+
 	folder.addColor( data, "ambient light" ).onChange( handleColorChange( ambientLight.color ) )
-	
+
 	guiSceneFog( folder, scene );
-	
+
 }
 
 function guiSceneFog ( folder, scene ) {
-	
+
 	var fogFolder = folder.addFolder('scene.fog');
-	
+
 	var fog = new THREE.Fog( 0x3f7b9d, 0, 60 );
 
 	var data = {
@@ -277,29 +277,29 @@ function guiSceneFog ( folder, scene ) {
 			"scene.fog.color" : fog.color.getHex()
 		}
 	};
-	
+
 	fogFolder.add( data.fog, 'THREE.Fog()' ).onChange( function ( useFog ) {
-		
+
 		if ( useFog ) {
-			
+
 			scene.fog = fog;
-			
+
 		} else {
-			
+
 			scene.fog = null;
-			
+
 		}
-		
+
 	} );
-	
+
 	fogFolder.addColor( data.fog, 'scene.fog.color').onChange( handleColorChange( fog.color ) );
-	
+
 }
 
 function guiMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var folder = gui.addFolder('THREE.Material');
-	
+
 	folder.add( material, 'transparent' );
 	folder.add( material, 'opacity', 0, 1 );
 	// folder.add( material, 'blending', constants.blendingMode );
@@ -315,11 +315,11 @@ function guiMaterial ( gui, mesh, material, geometry ) {
 	// folder.add( material, 'overdraw', 0, 5 );
 	folder.add( material, 'visible' );
 	folder.add( material, 'side', constants.side ).onChange( needsUpdate( material, geometry ) );
-	
+
 }
 
 function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex(),
 		envMaps : envMapKeys,
@@ -328,7 +328,7 @@ function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
 		specularMap : textureMapKeys,
 		alphaMap : textureMapKeys
 	};
-		
+
 	var folder = gui.addFolder('THREE.MeshBasicMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
@@ -337,7 +337,7 @@ function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'shading', constants.shading);
 	folder.add( material, 'vertexColors', constants.colors).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'fog' );
-	
+
 	folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) );
 	folder.add( data, 'map', textureMapKeys ).onChange( updateTexture( material, 'map', textureMaps ) );
 	folder.add( data, 'lightMap', textureMapKeys ).onChange( updateTexture( material, 'lightMap', textureMaps ) );
@@ -348,36 +348,36 @@ function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'reflectivity', 0, 1 );
 	folder.add( material, 'refractionRatio', 0, 1 );
 	//folder.add( material, 'skinning' );
-	
+
 }
 
 function guiMeshDepthMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var folder = gui.addFolder('THREE.MeshDepthMaterial');
-		
+
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );
 	folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) );
-	
+
 }
 
 function guiMeshNormalMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var folder = gui.addFolder('THREE.MeshNormalMaterial');
-	
+
 	folder.add( material, 'shading', constants.shading).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );
 	folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) );
-	
+
 }
 
 function guiLineBasicMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex()
 	};
-		
+
 	var folder = gui.addFolder('THREE.LineBasicMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
@@ -386,11 +386,11 @@ function guiLineBasicMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'linejoin', ["round", "bevel", "miter"] );
 	folder.add( material, 'vertexColors', constants.colors).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'fog' );
-	
+
 }
 
 function guiMeshLambertMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex(),
 		ambient : material.ambient.getHex(),
@@ -401,15 +401,15 @@ function guiMeshLambertMaterial ( gui, mesh, material, geometry ) {
 		specularMap : textureMapKeys,
 		alphaMap : textureMapKeys
 	};
-	
+
 	var envObj = {};
-			
+
 	var folder = gui.addFolder('THREE.MeshLambertMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
 	folder.addColor( data, 'ambient' ).onChange( handleColorChange( material.ambient ) );
 	folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
-	
+
 	folder.add( material, 'shading', constants.shading ).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );
@@ -426,11 +426,11 @@ function guiMeshLambertMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'reflectivity', 0, 1 );
 	folder.add( material, 'refractionRatio', 0, 1 );
 	//folder.add( material, 'skinning' );
-	
+
 }
 
 function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex(),
 		ambient : material.ambient.getHex(),
@@ -442,7 +442,7 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
 		specularMap : textureMapKeys,
 		alphaMap : textureMapKeys
 	};
-		
+
 	var folder = gui.addFolder('THREE.MeshPhongMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
@@ -461,16 +461,16 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
 	folder.add( data, 'lightMap', textureMapKeys ).onChange( updateTexture( material, 'lightMap', textureMaps ) );
 	folder.add( data, 'specularMap', textureMapKeys ).onChange( updateTexture( material, 'specularMap', textureMaps ) );
 	folder.add( data, 'alphaMap', textureMapKeys ).onChange( updateTexture( material, 'alphaMap', textureMaps ) );
-	
+
 }
 
 function chooseFromHash ( gui, mesh, geometry ) {
 
 	var selectedMaterial = window.location.hash.substring(1) || "MeshBasicMaterial";
 	var material;
-	
+
 	switch (selectedMaterial) {
-		
+
 	case "MeshBasicMaterial" :
 
 		material = new THREE.MeshBasicMaterial({color: 0x2194CE});
@@ -480,7 +480,7 @@ function chooseFromHash ( gui, mesh, geometry ) {
 		return material;
 
 		break;
-	
+
 	case "MeshLambertMaterial" :
 
 		material = new THREE.MeshLambertMaterial({color: 0x2194CE});
@@ -490,7 +490,7 @@ function chooseFromHash ( gui, mesh, geometry ) {
 		return material;
 
 		break;
-	
+
 	case "MeshPhongMaterial" :
 
 		material = new THREE.MeshPhongMaterial({color: 0x2194CE});
@@ -500,27 +500,27 @@ function chooseFromHash ( gui, mesh, geometry ) {
 		return material;
 
 		break;
-	
+
 	case "MeshDepthMaterial" :
-		
+
 		material = new THREE.MeshDepthMaterial({color: 0x2194CE});
 		guiMaterial( gui, mesh, material, geometry );
 		guiMeshDepthMaterial( gui, mesh, material, geometry );
 
 		return material;
-		
+
 		break;
-	
+
 	case "MeshNormalMaterial" :
-		
+
 		material = new THREE.MeshNormalMaterial();
 		guiMaterial( gui, mesh, material, geometry );
 		guiMeshNormalMaterial( gui, mesh, material, geometry );
 
 		return material;
-		
+
 		break;
-		
+
 	case "LineBasicMaterial" :
 
 		material = new THREE.LineBasicMaterial({color: 0x2194CE});
@@ -531,5 +531,5 @@ function chooseFromHash ( gui, mesh, geometry ) {
 
 		break;
 	}
-	
+
 }

+ 12 - 1
editor/css/dark.css

@@ -37,6 +37,15 @@ input.Number {
 		text-shadow: 1px 1px 0px rgba(0,0,0,0.25);
 	}
 
+#script {
+	position: absolute;
+	top: 32px;
+	left: 0px;
+	right: 300px;
+	bottom: 32px;
+	opacity: 0.9;
+}
+
 #player {
 	position: absolute;
 	top: 32px;
@@ -52,6 +61,8 @@ input.Number {
 	background: #111;
 	padding: 0px;
 	margin: 0px;
+	right: 0px;
+	top: 0px;
 }
 
 	#menubar .menu {
@@ -78,7 +89,7 @@ input.Number {
 			display: none;
 			padding: 5px 0px;
 			background: #111;
-			width: 140px;
+			width: 150px;
 		}
 
 		#menubar .menu:hover .options {

+ 12 - 1
editor/css/light.css

@@ -38,6 +38,15 @@ input.Number {
 		text-shadow: 1px 1px 0px rgba(0,0,0,0.25);
 	}
 
+#script {
+	position: absolute;
+	top: 32px;
+	left: 0px;
+	right: 300px;
+	bottom: 32px;
+	opacity: 0.9;
+}
+
 #player {
 	position: absolute;
 	top: 32px;
@@ -53,6 +62,8 @@ input.Number {
 	background: #eee;
 	padding: 0px;
 	margin: 0px;
+	right: 0px;
+	top: 0px;
 }
 
 	#menubar .menu {
@@ -79,7 +90,7 @@ input.Number {
 			display: none;
 			padding: 5px 0px;
 			background: #eee;
-			width: 140px;
+			width: 150px;
 		}
 
 		#menubar .menu:hover .options {

+ 10 - 1
editor/css/main.css

@@ -19,6 +19,7 @@ button {
 }
 
 textarea {
+	tab-size: 4;
 	white-space: pre;
 	word-wrap: normal;
 }
@@ -70,6 +71,14 @@ textarea, input { outline: none; } /* osx */
 		display: none;
 	}
 
+.CodeMirror {
+
+	position: absolute !important;
+	top: 37px;
+	width: 100% !important;
+	height: calc(100% - 37px) !important;
+
+}
 /* scene types */
 
 .type {
@@ -121,4 +130,4 @@ textarea, input { outline: none; } /* osx */
 
 .MeshPhongMaterial {
 	color: #ffaa88;
-}
+}

+ 172 - 0
editor/examples/camera.app.json

@@ -0,0 +1,172 @@
+{
+	"camera": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"object": {
+			"uuid": "F0D8434F-4603-415B-8024-792FE97B9600",
+			"type": "PerspectiveCamera",
+			"name": "Camera",
+			"fov": 50,
+			"aspect": 1.2252042007001167,
+			"near": 0.1,
+			"far": 100000,
+			"matrix": [0.9700406789779663,-5.500052080442686e-10,-0.24294254183769226,0,-0.04822639003396034,0.9800989627838135,-0.19256223738193512,0,0.23810774087905884,0.19850945472717285,0.950735867023468,0,159.0158233642578,132.5708465576172,634.9312744140625,1]
+		}
+	},
+	"scene": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"geometries": [
+			{
+				"uuid": "D8E200D3-27BC-49F8-A5C5-7384206E70FE",
+				"type": "BoxGeometry",
+				"width": 100,
+				"height": 100,
+				"depth": 100,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			},
+			{
+				"uuid": "25BA32DB-8B02-4ABA-A77C-69868C464A1A",
+				"type": "CylinderGeometry",
+				"radiusTop": 0,
+				"radiusBottom": 40,
+				"height": 75,
+				"radialSegments": 4,
+				"heightSegments": 1,
+				"openEnded": false
+			},
+			{
+				"uuid": "51BB3E54-D2DF-4576-9953-FB8E940588B5",
+				"type": "PlaneGeometry",
+				"width": 1000,
+				"height": 1000,
+				"widthSegments": 1,
+				"heightSegments": 1
+			},
+			{
+				"uuid": "4DECFAB5-6FD1-4D84-9A29-565807B074EA",
+				"type": "IcosahedronGeometry",
+				"radius": 40,
+				"detail": 2
+			}],
+		"materials": [
+			{
+				"uuid": "B5943856-E404-45D9-A427-4774202C2CD0",
+				"type": "MeshPhongMaterial",
+				"color": 37119,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "3F872310-2067-4BE4-9250-5B3F4E43797E",
+				"type": "MeshPhongMaterial",
+				"color": 15859456,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "4AE8130E-B6A8-47BC-ACCF-060973C74044",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "E1826901-7922-4584-A25D-6D487E2C9BBD",
+				"type": "MeshPhongMaterial",
+				"color": 16711680,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			}],
+		"object": {
+			"uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
+			"type": "Scene",
+			"name": "Scene",
+			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+			"children": [
+				{
+					"uuid": "60B69C58-4201-43FD-815E-AD2EDFBBD0CE",
+					"type": "PerspectiveCamera",
+					"name": "PerspectiveCamera 1",
+					"fov": 50,
+					"aspect": 1,
+					"near": 100,
+					"far": 10000,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,100,400,1]
+				},
+				{
+					"uuid": "26DAAD69-725D-43B7-AF9D-990A99DEF8C5",
+					"type": "Mesh",
+					"name": "Box 1",
+					"geometry": "D8E200D3-27BC-49F8-A5C5-7384206E70FE",
+					"material": "B5943856-E404-45D9-A427-4774202C2CD0",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+				},
+				{
+					"uuid": "AAAFF2D6-4725-4AFC-A9FE-26419B11011F",
+					"type": "Mesh",
+					"name": "Cylinder 3",
+					"geometry": "25BA32DB-8B02-4ABA-A77C-69868C464A1A",
+					"material": "3F872310-2067-4BE4-9250-5B3F4E43797E",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-130,-15,0,1]
+				},
+				{
+					"uuid": "A460C230-DC88-4A8F-A3FB-AA0FE735F3ED",
+					"type": "Mesh",
+					"name": "Plane 4",
+					"geometry": "51BB3E54-D2DF-4576-9953-FB8E940588B5",
+					"material": "4AE8130E-B6A8-47BC-ACCF-060973C74044",
+					"matrix": [1,0,0,0,0,0.040785059332847595,-0.9991679191589355,0,0,0.9991679191589355,0.040785059332847595,0,0,-50,0,1]
+				},
+				{
+					"uuid": "3412781E-27CC-43C3-A5DB-54C0C8E42ED6",
+					"type": "PointLight",
+					"name": "PointLight 2",
+					"color": 12773063,
+					"intensity": 1,
+					"distance": 0,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,88.12999725341797,8.3100004196167,125.44999694824219,1]
+				},
+				{
+					"uuid": "E2939A7B-5E40-438A-8C1B-32126FBC6892",
+					"type": "PointLight",
+					"name": "PointLight 1",
+					"color": 9474221,
+					"intensity": 0.75,
+					"distance": 0,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-93.86000061035156,127.12999725341797,-114.30000305175781,1]
+				},
+				{
+					"uuid": "B855E267-A266-4098-ACD6-6A1FDE7B88BA",
+					"type": "Mesh",
+					"name": "Icosahedron 1",
+					"geometry": "4DECFAB5-6FD1-4D84-9A29-565807B074EA",
+					"material": "E1826901-7922-4584-A25D-6D487E2C9BBD",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,130,-10,0,1]
+				}]
+		}
+	},
+	"scripts": {
+		"60B69C58-4201-43FD-815E-AD2EDFBBD0CE": [
+			{
+				"name": "Camera Orbit",
+				"source": "player.setCamera( this );\n\nfunction update( event ) {\n\n\tvar time = event.time * 0.001;\n\n\tthis.position.x = Math.sin( time ) * 400;\n\tthis.position.z = Math.cos( time ) * 400;\n\tthis.lookAt( scene.position );\n\n}"
+			}]
+	}
+}

+ 99 - 0
editor/examples/particles.app.json

@@ -0,0 +1,99 @@
+{
+	"camera": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"object": {
+			"uuid": "D722B468-8D40-4CAB-82D6-944D2D5A8D35",
+			"type": "PerspectiveCamera",
+			"name": "Camera",
+			"fov": 50,
+			"aspect": 1.2237762237762237,
+			"near": 0.1,
+			"far": 100000,
+			"matrix": [0.7071067690849304,-2.468905080377226e-9,-0.7071068286895752,0,-0.2357022613286972,0.9428090453147888,-0.235702246427536,0,0.6666666865348816,0.3333333134651184,0.6666666269302368,0,500,250,500,1]
+		}
+	},
+	"scene": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"geometries": [
+			{
+				"uuid": "5009F17C-E9D3-4D0E-82A6-2E23159128FB",
+				"type": "PlaneGeometry",
+				"width": 600,
+				"height": 600,
+				"widthSegments": 1,
+				"heightSegments": 1
+			},
+			{
+				"uuid": "8693E7B2-0009-4C4C-94C5-8E031557AEC2",
+				"type": "BoxGeometry",
+				"width": 4,
+				"height": 4,
+				"depth": 4,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			}],
+		"materials": [
+			{
+				"uuid": "6EDB0369-7E11-4B0F-BF98-4BD761846D65",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "D586E672-03FC-4C82-9D6E-CCCF899DDDB1",
+				"type": "MeshBasicMaterial",
+				"color": 16777215
+			}],
+		"object": {
+			"uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
+			"type": "Scene",
+			"name": "Scene",
+			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+			"children": [
+				{
+					"uuid": "05B57416-1BE5-4A96-BB05-9D9CD112D52B",
+					"type": "Mesh",
+					"name": "Ground",
+					"geometry": "5009F17C-E9D3-4D0E-82A6-2E23159128FB",
+					"material": "6EDB0369-7E11-4B0F-BF98-4BD761846D65",
+					"matrix": [1,0,0,0,0,0.0007962886593304574,-0.9999997019767761,0,0,0.9999997019767761,0.0007962886593304574,0,0,-2,0,1]
+				},
+				{
+					"uuid": "9DFA44C6-C85A-4F2F-9252-E9564C2785C5",
+					"type": "Mesh",
+					"name": "Particle",
+					"geometry": "8693E7B2-0009-4C4C-94C5-8E031557AEC2",
+					"material": "D586E672-03FC-4C82-9D6E-CCCF899DDDB1",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+				},
+				{
+					"uuid": "40E5CDA4-0E39-4265-9293-3E9EC3207F61",
+					"type": "PointLight",
+					"name": "PointLight",
+					"color": 16777215,
+					"intensity": 10,
+					"distance": 0,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+				}]
+		}
+	},
+	"scripts": {
+		"3741222A-BD8F-401C-A5D2-5A907E891896": [
+			{
+				"name": "Particle Fountain",
+				"source": "var original = this.getObjectByName( 'Particle' );\n\nvar particles = [];\n\nfunction update( event ) {\n\n\tif ( particles.length < 200 ) {\n\n\t\tvar velocity = new THREE.Vector3();\n\t\tvelocity.x = Math.random() * 10 - 5;\n\t\tvelocity.y = Math.random() * 10 + 10;\n\t\tvelocity.z = Math.random() * 10 - 5;\n\n\t\tvar particle = original.clone();\n\t\tparticle.userData.velocity = velocity;\n\t\tparticles.push( particle );\n\n\t\tthis.add( particle );\n\n\t}\n\n\tfor ( var i = 0; i < particles.length; i ++ ) {\n\n\t\tvar particle = particles[ i ];\n\n\t\tvar velocity = particle.userData.velocity;\n\n\t\tvelocity.y -= 0.98;\n\n\t\tparticle.position.add( velocity );\n\n\t\tif ( particle.position.y < 0 ) {\n\n\t\t\tparticle.position.y = 0;\n\n\t\t\tvelocity.y = - velocity.y;\n\t\t\tvelocity.multiplyScalar( 0.6 );\n\n\t\t}\n\n\t}\n\n}"
+			}]
+	}
+}

+ 137 - 0
editor/examples/pong.app.json

@@ -0,0 +1,137 @@
+{
+	"camera": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"object": {
+			"uuid": "E5C76691-3D55-4E26-862E-24BADC21F4D7",
+			"type": "PerspectiveCamera",
+			"name": "Camera",
+			"fov": 50,
+			"aspect": 1.3291139240506329,
+			"near": 0.1,
+			"far": 100000,
+			"matrix": [0.9522120356559753,4.209433246415983e-9,-0.3054378032684326,0,-0.17742955684661865,0.8139731884002686,-0.553142249584198,0,0.24861818552017212,0.5809023976325989,0.7750750780105591,0,186.46363830566406,435.67681884765625,581.3063354492188,1]
+		}
+	},
+	"scene": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"geometries": [
+			{
+				"uuid": "77B20ED1-2871-4B14-A652-8F823B2A817E",
+				"type": "PlaneGeometry",
+				"width": 600,
+				"height": 400,
+				"widthSegments": 1,
+				"heightSegments": 1
+			},
+			{
+				"uuid": "7ADE0D01-A56A-4D33-869A-6C360E096EF7",
+				"type": "BoxGeometry",
+				"width": 10,
+				"height": 10,
+				"depth": 10,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			},
+			{
+				"uuid": "E8C064B6-3454-4739-9E02-3B07B8E70B4C",
+				"type": "BoxGeometry",
+				"width": 20,
+				"height": 20,
+				"depth": 100,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			}],
+		"materials": [
+			{
+				"uuid": "7EDF7C08-6325-418A-BBAB-89341C694730",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 16777215,
+				"shininess": 30
+			},
+			{
+				"uuid": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC",
+				"type": "MeshPhongMaterial",
+				"color": 16711680,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "FBDBE66D-B613-4741-802D-5AE1DE07DE46",
+				"type": "MeshPhongMaterial",
+				"color": 2752767,
+				"ambient": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			}],
+		"object": {
+			"uuid": "31517222-A9A7-4EAF-B5F6-60751C0BABA3",
+			"type": "Scene",
+			"name": "Scene",
+			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+			"children": [
+				{
+					"uuid": "B47D0BFC-D63A-4CBB-985E-9C4DBDF086E4",
+					"type": "Mesh",
+					"name": "Ground",
+					"geometry": "77B20ED1-2871-4B14-A652-8F823B2A817E",
+					"material": "7EDF7C08-6325-418A-BBAB-89341C694730",
+					"matrix": [1,0,0,0,0,0.0007961748051457107,-0.9999997019767761,0,0,0.9999997019767761,0.0007961748051457107,0,0,-10,0,1]
+				},
+				{
+					"uuid": "CE13E58A-4E8B-4F72-9E2E-7DE57C58F989",
+					"type": "Mesh",
+					"name": "Ball",
+					"geometry": "7ADE0D01-A56A-4D33-869A-6C360E096EF7",
+					"material": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+				},
+				{
+					"uuid": "2AAEA3AA-EC45-492B-B450-10473D1EC6C5",
+					"type": "Mesh",
+					"name": "Pad 1",
+					"geometry": "E8C064B6-3454-4739-9E02-3B07B8E70B4C",
+					"material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-240,0,0,1]
+				},
+				{
+					"uuid": "F1DD46A7-6584-4A37-BC76-852C3911077E",
+					"type": "Mesh",
+					"name": "Pad 2",
+					"geometry": "E8C064B6-3454-4739-9E02-3B07B8E70B4C",
+					"material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,240,0,0,1]
+				},
+				{
+					"uuid": "C62AAE9F-9E51-46A5-BD2B-71BA804FC0B3",
+					"type": "DirectionalLight",
+					"name": "DirectionalLight 3",
+					"color": 16777215,
+					"intensity": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,100,200,150,1]
+				}]
+		}
+	},
+	"scripts": {
+		"31517222-A9A7-4EAF-B5F6-60751C0BABA3": [
+			{
+				"name": "Game logic",
+				"source": "var ball = this.getObjectByName( 'Ball' );\n\nvar position = ball.position;\n\nvar velocity = new THREE.Vector3();\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = Math.random() - 0.5;\ndirection.normalize();\n\nvar pad1 = this.getObjectByName( 'Pad 1' );\nvar pad2 = this.getObjectByName( 'Pad 2' );\n\nvar raycaster = new THREE.Raycaster();\nvar objects = [ pad1, pad2 ];\n\n//\n\nfunction mousemove( event ) {\n\n\tpad1.position.z = ( event.clientX / player.width ) * 300 - 150;\n\tpad2.position.z = - pad1.position.z;\n\n}\n\nfunction update( event ) {\n\n\tif ( position.x < -300 || position.x > 300 ) {\n\t\t\n\t\tdirection.x = - direction.x;\n\t\t\n\t}\n\n\tif ( position.z < -200 || position.z > 200 ) {\n\t\t\n\t\tdirection.z = - direction.z;\n\t\t\n\t}\n\t\n\traycaster.set( position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( objects );\n\t\n\tif ( intersections.length > 0 ) {\n\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 10 ) {\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n\tposition.add( velocity.copy( direction ).multiplyScalar( 8 ) );\n\n}"
+			}]
+	}
+}

+ 14 - 12
editor/index.html

@@ -36,14 +36,19 @@
 		<script src="../examples/js/renderers/SoftwareRenderer.js"></script>
 		<script src="../examples/js/renderers/SVGRenderer.js"></script>
 
+		<link rel="stylesheet" href="js/libs/codemirror/codemirror.css">
+		<link rel="stylesheet" href="js/libs/codemirror/theme/monokai.css">
+		<script src="js/libs/codemirror/codemirror.js"></script>
+		<script src="js/libs/codemirror/mode/javascript.js"></script>
+
 		<script src="js/libs/jszip.min.js"></script>
 		<script src="js/libs/signals.min.js"></script>
 		<script src="js/libs/ui.js"></script>
-		<script src="js/libs/ui.editor.js"></script>
 		<script src="js/libs/ui.three.js"></script>
 
 		<script src="js/libs/app.js"></script>
 		<script src="js/Player.js"></script>
+		<script src="js/Script.js"></script>
 
 		<script src="js/Storage.js"></script>
 
@@ -56,6 +61,7 @@
 		<script src="js/Menubar.Add.js"></script>
 		<script src="js/Menubar.Play.js"></script>
 		<script src="js/Menubar.View.js"></script>
+		<script src="js/Menubar.Examples.js"></script>
 		<script src="js/Menubar.Help.js"></script>
 		<script src="js/Menubar.Status.js"></script>
 		<script src="js/Sidebar.js"></script>
@@ -77,7 +83,6 @@
 		<script src="js/Sidebar.Geometry.TorusKnotGeometry.js"></script>
 		<script src="js/Sidebar.Material.js"></script>
 		<script src="js/Sidebar.Script.js"></script>
-		<script src="js/Sidebar.Script.Editor.js"></script>
 		<script src="js/Toolbar.js"></script>
 		<script src="js/Viewport.js"></script>
 		<script src="js/Viewport.Info.js"></script>
@@ -98,6 +103,9 @@
 			var viewport = new Viewport( editor );
 			document.body.appendChild( viewport.dom );
 
+			var script = new Script( editor );
+			document.body.appendChild( script.dom );
+
 			var player = new Player( editor );
 			document.body.appendChild( player.dom );
 
@@ -123,10 +131,7 @@
 
 					if ( state !== undefined ) {
 
-						var loader = new THREE.ObjectLoader();
-						var scene = loader.parse( state );
-
-						editor.setScene( scene );
+						editor.fromJSON( state );
 
 					}
 
@@ -160,7 +165,7 @@
 
 						timeout = setTimeout( function () {
 
-							editor.storage.set( editor.scene.toJSON() );
+							editor.storage.set( editor.toJSON() );
 
 							editor.signals.savingFinished.dispatch();
 
@@ -172,12 +177,14 @@
 
 				var signals = editor.signals;
 
+				signals.editorCleared.add( saveState );
 				signals.geometryChanged.add( saveState );
 				signals.objectAdded.add( saveState );
 				signals.objectChanged.add( saveState );
 				signals.objectRemoved.add( saveState );
 				signals.materialChanged.add( saveState );
 				signals.sceneGraphChanged.add( saveState );
+				signals.scriptChanged.add( saveState );
 
 				var showDialog = function ( content ) {
 
@@ -215,11 +222,6 @@
 					case 8: // prevent browser back
 						event.preventDefault();
 						break;
-					case 46: // delete
-						var parent = editor.selected.parent;
-						editor.removeObject( editor.selected );
-						editor.select( parent );
-						break;
 
 				}
 

+ 117 - 4
editor/js/Editor.js

@@ -8,6 +8,10 @@ var Editor = function () {
 
 	this.signals = {
 
+		// script
+
+		editScript: new SIGNALS.Signal(),
+
 		// player
 
 		startPlayer: new SIGNALS.Signal(),
@@ -22,6 +26,8 @@ var Editor = function () {
 
 		// notifications
 
+		editorCleared: new SIGNALS.Signal(),
+
 		savingStarted: new SIGNALS.Signal(),
 		savingFinished: new SIGNALS.Signal(),
 
@@ -49,6 +55,11 @@ var Editor = function () {
 		helperRemoved: new SIGNALS.Signal(),
 
 		materialChanged: new SIGNALS.Signal(),
+
+		scriptAdded: new SIGNALS.Signal(),
+		scriptChanged: new SIGNALS.Signal(),
+		scriptRemoved: new SIGNALS.Signal(),
+
 		fogTypeChanged: new SIGNALS.Signal(),
 		fogColorChanged: new SIGNALS.Signal(),
 		fogParametersChanged: new SIGNALS.Signal(),
@@ -62,7 +73,7 @@ var Editor = function () {
 	this.storage = new Storage();
 	this.loader = new Loader( this );
 
-	this.camera = new THREE.PerspectiveCamera( 50, 1, 0.1, 100000 );
+	this.camera = new THREE.PerspectiveCamera( 50, 1, 1, 100000 );
 	this.camera.name = 'Camera';
 
 	this.scene = new THREE.Scene();
@@ -74,7 +85,7 @@ var Editor = function () {
 	this.geometries = {};
 	this.materials = {};
 	this.textures = {};
-	// this.scripts = {};
+	this.scripts = {};
 
 	this.selected = null;
 	this.helpers = {};
@@ -91,16 +102,19 @@ Editor.prototype = {
 
 	},
 
+	/*
 	showDialog: function ( value ) {
 
 		this.signals.showDialog.dispatch( value );
 
 	},
+	*/
 
 	//
 
 	setScene: function ( scene ) {
 
+		this.scene.uuid = scene.uuid;
 		this.scene.name = scene.name;
 		this.scene.userData = JSON.parse( JSON.stringify( scene.userData ) );
 
@@ -152,8 +166,6 @@ Editor.prototype = {
 
 		if ( object.parent === undefined ) return; // avoid deleting the camera or scene
 
-		if ( confirm( 'Delete ' + object.name + '?' ) === false ) return;
-
 		var scope = this;
 
 		object.traverse( function ( child ) {
@@ -275,6 +287,38 @@ Editor.prototype = {
 
 	//
 
+	addScript: function ( object, script ) {
+
+		if ( this.scripts[ object.uuid ] === undefined ) {
+
+			this.scripts[ object.uuid ] = [];
+
+		}
+
+		this.scripts[ object.uuid ].push( script );
+
+		this.signals.scriptAdded.dispatch( script );
+
+	},
+
+	removeScript: function ( object, script ) {
+
+		if ( this.scripts[ object.uuid ] === undefined ) return;
+
+		var index = this.scripts[ object.uuid ].indexOf( script );
+
+		if ( index !== - 1 ) {
+
+			this.scripts[ object.uuid ].splice( index, 1 );
+
+		}
+
+		this.signals.scriptRemoved.dispatch( script );
+
+	},
+
+	//
+
 	parent: function ( object, parent ) {
 
 		if ( parent === undefined ) {
@@ -355,6 +399,75 @@ Editor.prototype = {
 
 		this.focus( this.scene.getObjectById( id, true ) );
 
+	},
+
+	clear: function () {
+
+		this.camera.position.set( 500, 250, 500 );
+		this.camera.lookAt( new THREE.Vector3() );
+
+		var objects = this.scene.children;
+
+		while ( objects.length > 0 ) {
+
+			this.removeObject( objects[ 0 ] );
+
+		}
+
+		this.geometries = {};
+		this.materials = {};
+		this.textures = {};
+		this.scripts = {};
+
+		this.deselect();
+
+		this.signals.editorCleared.dispatch();
+
+	},
+
+	//
+
+	fromJSON: function ( json ) {
+
+		var loader = new THREE.ObjectLoader();
+
+		// backwards
+
+		if ( json.scene === undefined ) {
+
+			var scene = loader.parse( json );
+
+			this.setScene( scene );
+
+			return;
+
+		}
+
+		// TODO: Clean this up somehow
+
+		var camera = loader.parse( json.camera );
+
+		this.camera.position.copy( camera.position );
+		this.camera.rotation.copy( camera.rotation );
+		this.camera.aspect = camera.aspect;
+		this.camera.near = camera.near;
+		this.camera.far = camera.far;
+
+		this.setScene( loader.parse( json.scene ) );
+		this.scripts = json.scripts;
+
+	},
+
+	toJSON: function () {
+
+		return {
+
+			camera: this.camera.toJSON(),
+			scene: this.scene.toJSON(),
+			scripts: this.scripts
+
+		};
+
 	}
 
 }

+ 29 - 4
editor/js/Menubar.Add.js

@@ -20,6 +20,15 @@ Menubar.Add = function ( editor ) {
 
 	var meshCount = 0;
 	var lightCount = 0;
+	var cameraCount = 0;
+
+	editor.signals.editorCleared.add( function () {
+
+		meshCount = 0;
+		lightCount = 0;
+		cameraCount = 0;
+
+	} );
 
 	// Group
 
@@ -227,10 +236,6 @@ Menubar.Add = function ( editor ) {
 	} );
 	options.add( option );
 
-	//
-
-	options.add( new UI.HorizontalRule() );
-
 	// Sprite
 
 	var option = new UI.Panel();
@@ -358,6 +363,26 @@ Menubar.Add = function ( editor ) {
 	} );
 	options.add( option );
 
+	//
+
+	options.add( new UI.HorizontalRule() );
+
+	// PerspectiveCamera
+
+	var option = new UI.Panel();
+	option.setClass( 'option' );
+	option.setTextContent( 'PerspectiveCamera' );
+	option.onClick( function() {
+
+		var camera = new THREE.PerspectiveCamera( 50, 1, 1, 10000 );
+		camera.name = 'PerspectiveCamera ' + ( ++ cameraCount );
+
+		editor.addObject( camera );
+		editor.select( camera );
+
+	} );
+	options.add( option );
+
 	return container;
 
 }

+ 6 - 2
editor/js/Menubar.Edit.js

@@ -41,9 +41,13 @@ Menubar.Edit = function ( editor ) {
 	option.setClass( 'option' );
 	option.setTextContent( 'Delete' );
 	option.onClick( function () {
+	
+		var object = editor.selected;
+
+		if ( confirm( 'Delete ' + object.name + '?' ) === false ) return;
 
-		var parent = editor.selected.parent;
-		editor.removeObject( editor.selected );
+		var parent = object.parent;
+		editor.removeObject( object );
 		editor.select( parent );
 
 	} );

+ 60 - 0
editor/js/Menubar.Examples.js

@@ -0,0 +1,60 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+Menubar.Examples = function ( editor ) {
+
+	var container = new UI.Panel();
+	container.setClass( 'menu' );
+
+	var title = new UI.Panel();
+	title.setClass( 'title' );
+	title.setTextContent( 'Examples' );
+	container.add( title );
+
+	var options = new UI.Panel();
+	options.setClass( 'options' );
+	container.add( options );
+
+	// Examples
+
+	var items = [
+		{ title: 'Camera', file: 'camera.app.json' },
+		{ title: 'Particles', file: 'particles.app.json' },
+		{ title: 'Pong', file: 'pong.app.json' }
+	];
+
+	var loader = new THREE.XHRLoader();
+
+	for ( var i = 0; i < items.length; i ++ ) {
+
+		( function ( i ) {
+
+			var item = items[ i ];
+
+			var option = new UI.Panel();
+			option.setClass( 'option' );
+			option.setTextContent( item.title );
+			option.onClick( function () {
+
+				if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
+
+					loader.load( 'examples/' + item.file, function ( text ) {
+
+						editor.clear();
+						editor.fromJSON( JSON.parse( text ) );
+
+					} );
+
+				}
+
+			} );
+			options.add( option );
+
+		} )( i )
+
+	}
+
+	return container;
+
+};

+ 16 - 52
editor/js/Menubar.File.js

@@ -23,18 +23,9 @@ Menubar.File = function ( editor ) {
 	option.setTextContent( 'New' );
 	option.onClick( function () {
 
-		if ( confirm( 'Are you sure?' ) ) {
+		if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
 
-			editor.config.setKey(
-				'camera/position', [ 500, 250, 500 ],
-				'camera/target', [ 0, 0, 0 ]
-			);
-
-			editor.storage.clear( function () {
-
-				location.href = location.pathname;
-
-			} );
+			editor.clear();
 
 		}
 
@@ -213,48 +204,21 @@ Menubar.File = function ( editor ) {
 			'	</head>',
 			'	<body ontouchstart="">',
 			'		<script src="js/three.min.js"></script>',
-			'		<script src="js/OrbitControls.js"></script>',
+			'		<script src="js/app.js"></script>',
 			'		<script>',
 			'',
-			'			var camera, controls, scene, renderer;',
-			'',
-			'			var loader = new THREE.ObjectLoader();',
-			'			loader.load( \'scene.json\', function ( object ) {',
-			'',
-			'				scene = object;',
+			'			var loader = new THREE.XHRLoader();',
+			'			loader.load( \'app.json\', function ( text ) {',
 			'',
-			'				camera = new THREE.PerspectiveCamera( ' + camera.fov + ', 1, ' + camera.near + ', ' + camera.far + ' );',
-			'				camera.position.set( ' + camera.position.x + ', ' + camera.position.y + ', ' + camera.position.z + ' );',
-			'				camera.rotation.set( ' + camera.rotation.x + ', ' + camera.rotation.y + ', ' + camera.rotation.z + ' );',
+			'				var player = new APP.Player();',
+			'				player.load( JSON.parse( text ) );',
+			'				player.setSize( window.innerWidth, window.innerHeight );',
+			'				player.play();',
 			'',
-			'				controls = new THREE.OrbitControls( camera );',
-			'				controls.addEventListener( \'change\', render );',
-			'',
-			'				renderer = new THREE.WebGLRenderer();',
-			'				renderer.setSize( window.innerWidth, window.innerHeight );',
-			'				document.body.appendChild( renderer.domElement );',
-			'',
-			'				camera.aspect = window.innerWidth / window.innerHeight;',
-			'				camera.updateProjectionMatrix();',
-			'',
-			'				animate();',
-			'				render();',
+			'				document.body.appendChild( player.dom );',
 			'',
 			'			} );',
 			'',
-			'			var render = function () {',
-			'',
-			'				renderer.render( scene, camera );',
-			'',
-			'			};',
-			'',
-			'			var animate = function () {',
-			'',
-			'				requestAnimationFrame( animate );',
-			'				controls.update();',
-			'',
-			'			};',
-			'',
 			'		</script>',
 			'	</body>',
 			'</html>'
@@ -263,11 +227,11 @@ Menubar.File = function ( editor ) {
 
 		//
 
-		var output = editor.scene.toJSON();
+		var output = editor.toJSON();
 		output = JSON.stringify( output, null, '\t' );
 		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
-		zip.file( 'scene.json', output );
+		zip.file( 'app.json', output );
 
 		//
 
@@ -278,14 +242,14 @@ Menubar.File = function ( editor ) {
 		} );
 
 		var loader = new THREE.XHRLoader( manager );
-		loader.load( '../build/three.min.js', function ( content ) {
+		loader.load( 'js/libs/app.js', function ( content ) {
 
-			zip.file( 'js/three.min.js', content );
+			zip.file( 'js/app.js', content );
 
 		} );
-		loader.load( '../examples/js/controls/OrbitControls.js', function ( content ) {
+		loader.load( '../build/three.min.js', function ( content ) {
 
-			zip.file( 'js/OrbitControls.js', content );
+			zip.file( 'js/three.min.js', content );
 
 		} );
 

+ 1 - 1
editor/js/Menubar.Play.js

@@ -20,7 +20,7 @@ Menubar.Play = function ( editor ) {
 
 			isPlaying = true;
 			title.setTextContent( 'Stop' );
-			signals.startPlayer.dispatch( editor.scene.toJSON() );
+			signals.startPlayer.dispatch();
 
 		} else {
 

+ 34 - 0
editor/js/Menubar.View.js

@@ -42,6 +42,40 @@ Menubar.View = function ( editor ) {
 	} );
 	options.add( option );
 
+	//
+
+	options.add( new UI.HorizontalRule() );
+
+	// fullscreen
+
+	var option = new UI.Panel();
+	option.setClass( 'option' );
+	option.setTextContent( 'Fullscreen' );
+	option.onClick( function () {
+
+		var element = document.body;
+
+		if ( element.requestFullscreen ) {
+
+			element.requestFullscreen();
+
+		} else if ( element.mozRequestFullScreen ) {
+
+			element.mozRequestFullScreen();
+
+		} else if ( element.webkitRequestFullscreen ) {
+
+			element.webkitRequestFullscreen();
+
+		} else if ( element.msRequestFullscreen ) {
+
+			element.msRequestFullscreen();
+
+		}
+
+	} );
+	options.add( option );
+
 	return container;
 
 };

+ 1 - 0
editor/js/Menubar.js

@@ -11,6 +11,7 @@ var Menubar = function ( editor ) {
 	container.add( new Menubar.Edit( editor ) );
 	container.add( new Menubar.Add( editor ) );
 	container.add( new Menubar.Play( editor ) );
+	container.add( new Menubar.Examples( editor ) );
 	container.add( new Menubar.View( editor ) );
 	container.add( new Menubar.Help( editor ) );
 

+ 10 - 3
editor/js/Player.js

@@ -15,12 +15,19 @@ var Player = function ( editor ) {
 
 	var player = new APP.Player();
 
-	signals.startPlayer.add( function ( json ) {
+	window.addEventListener( 'resize', function () {
+
+		if ( player.dom === undefined ) return;
+
+		player.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
+
+	} );
+
+	signals.startPlayer.add( function () {
 
 		container.setDisplay( '' );
 
-		player.load( json );
-		player.setCamera( editor.camera );
+		player.load( editor.toJSON() );
 		player.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
 		player.play();
 

+ 91 - 0
editor/js/Script.js

@@ -0,0 +1,91 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+var Script = function ( editor ) {
+
+	var signals = editor.signals;
+
+	var container = new UI.Panel();
+	container.setId( 'script' );
+	container.setPosition( 'absolute' );
+	container.setBackgroundColor( '#272822' );
+	container.setDisplay( 'none' );
+
+	var header = new UI.Panel();
+	header.setPadding( '10px' );
+	container.add( header );
+	
+	var title = new UI.Text().setColor( '#fff' );
+	header.add( title );
+
+	var buttonSVG = ( function () {
+		var svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
+		svg.setAttribute( 'width', 32 );
+		svg.setAttribute( 'height', 32 );
+		var path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
+		path.setAttribute( 'd', 'M 12,12 L 22,22 M 22,12 12,22' );
+		path.setAttribute( 'stroke', '#fff' );
+		svg.appendChild( path );
+		return svg;
+	} )();
+
+	var close = new UI.Element( buttonSVG );
+	close.setPosition( 'absolute' );
+	close.setTop( '3px' );
+	close.setRight( '1px' );
+	close.setCursor( 'pointer' );
+	close.onClick( function () {
+
+		container.setDisplay( 'none' );
+
+	} );
+	header.add( close );
+
+	var delay;
+	var currentScript;
+
+	var codemirror = CodeMirror( container.dom, {
+		value: '',
+		lineNumbers: true,
+		matchBrackets: true,
+		indentWithTabs: true,
+		tabSize: 4,
+		indentUnit: 4
+	} );
+	codemirror.setOption( 'theme', 'monokai' );
+	codemirror.on( 'change', function () {
+
+		clearTimeout( delay );
+		delay = setTimeout( function () {
+
+			currentScript.source = codemirror.getValue();
+
+			signals.scriptChanged.dispatch( currentScript );
+
+		}, 300 );
+
+	});
+
+	//
+	
+	signals.editorCleared.add( function () {
+
+		container.setDisplay( 'none' );
+
+	} );
+
+	signals.editScript.add( function ( object, script ) {
+
+		container.setDisplay( '' );
+
+		currentScript = script;
+
+		title.setValue( object.name + ' / ' + script.name );
+		codemirror.setValue( script.source );
+
+	} );
+
+	return container;
+
+};

+ 3 - 3
editor/js/Sidebar.Object3D.js

@@ -40,7 +40,7 @@ Sidebar.Object3D = function ( editor ) {
 	// name
 
 	var objectNameRow = new UI.Panel();
-	var objectName = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( function () {
+	var objectName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () {
 
 			editor.setObjectName( editor.selected, objectName.getValue() );
 
@@ -54,7 +54,7 @@ Sidebar.Object3D = function ( editor ) {
 	// parent
 
 	var objectParentRow = new UI.Panel();
-	var objectParent = new UI.Select().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	var objectParent = new UI.Select().setWidth( '150px' ).setFontSize( '12px' ).onChange( update );
 
 	objectParentRow.add( new UI.Text( 'Parent' ).setWidth( '90px' ) );
 	objectParentRow.add( objectParent );
@@ -200,7 +200,7 @@ Sidebar.Object3D = function ( editor ) {
 	container.add( objectVisibleRow );
 
 	// user data
-	
+
 	var timeout;
 
 	var objectUserDataRow = new UI.Panel();

+ 1 - 1
editor/js/Sidebar.Scene.js

@@ -133,7 +133,7 @@ Sidebar.Scene = function ( editor ) {
 
 		var options = [];
 
-		options.push( { value: camera.id, html: '<span class="type ' + camera.type + '"></span> ' + camera.name } );
+		// options.push( { value: camera.id, html: '<span class="type ' + camera.type + '"></span> ' + camera.name } );
 		options.push( { value: scene.id, html: '<span class="type ' + scene.type + '"></span> ' + scene.name } );
 
 		( function addObjects( objects, pad ) {

+ 0 - 46
editor/js/Sidebar.Script.Editor.js

@@ -1,46 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-Sidebar.Script.Editor = function ( editor ) {
-
-	var timeout;
-
-	var scriptSource = new UI.TextArea( 'javascript' ).setWidth( '240px' ).setHeight( '180px' ).setFontSize( '12px' );
-	scriptSource.onKeyUp( function () {
-
-		clearTimeout( timeout );
-
-		timeout = setTimeout( function () {
-
-			var object = editor.selected;
-			var source = scriptSource.getValue();
-
-			try {
-
-				var script = new Function( 'scene', 'time', source ).bind( object.clone() );
-				script( new THREE.Scene(), 0 );
-
-				scriptSource.dom.classList.add( 'success' );
-				scriptSource.dom.classList.remove( 'fail' );
-
-			} catch ( error ) {
-
-				scriptSource.dom.classList.remove( 'success' );
-				scriptSource.dom.classList.add( 'fail' );
-
-				return;
-
-			}
-
-			editor.scripts[ object.uuid ] = [ source ];
-
-			editor.signals.objectChanged.dispatch( object );
-
-		}, 500 );
-
-	} );
-
-	return scriptSource;
-
-}

+ 80 - 13
editor/js/Sidebar.Script.js

@@ -18,28 +18,92 @@ Sidebar.Script = function ( editor ) {
 	container.addStatic( new UI.Text( 'Script' ).setTextTransform( 'uppercase' ) );
 	container.add( new UI.Break() );
 
-	var source = new Sidebar.Script.Editor( editor );
-	container.add( source );
+	//
 
-	signals.objectSelected.add( function ( object ) {
+	var scriptsContainer = new UI.Panel();
+	container.add( scriptsContainer );
 
-		if ( object !== null ) {
+	var newScript = new UI.Button( 'New' );
+	newScript.onClick( function () {
 
-			container.setDisplay( 'block' );
+		var script = { name: '', source: 'function update( event ) {}' };
+		editor.addScript( editor.selected, script );
+
+	} );
+	container.add( newScript );
+
+	/*
+	var loadScript = new UI.Button( 'Load' );
+	loadScript.setMarginLeft( '4px' );
+	container.add( loadScript );
+	*/
+
+	//
+
+	function update() {
+
+		scriptsContainer.clear();
+
+		var object = editor.selected;
+		var scripts = editor.scripts[ object.uuid ];
+
+		if ( scripts !== undefined ) {
+
+			for ( var i = 0; i < scripts.length; i ++ ) {
+
+				( function ( object, script ) {
+
+					var name = new UI.Input( script.name ).setWidth( '130px' ).setFontSize( '12px' );
+					name.onChange( function () {
+
+						script.name = this.getValue();
+
+						signals.scriptChanged.dispatch();
+
+					} );
+					scriptsContainer.add( name );
 
-			/*
-			var scripts = editor.scripts[ object.uuid ];
+					var edit = new UI.Button( 'Edit' );
+					edit.setMarginLeft( '4px' );
+					edit.onClick( function () {
 
-			if ( scripts !== undefined ) {
+						signals.editScript.dispatch( object, script );
 
-				scriptSource.setValue( scripts[ 0 ] );
+					} );
+					scriptsContainer.add( edit );
 
-			} else {
+					var remove = new UI.Button( 'Remove' );
+					remove.setMarginLeft( '4px' );
+					remove.onClick( function () {
 
-				scriptSource.setValue( '' );
+						if ( confirm( 'Are you sure?' ) ) {
+
+							editor.removeScript( editor.selected, script );
+
+						}
+
+					} );
+					scriptsContainer.add( remove );
+					
+					scriptsContainer.add( new UI.Break() );
+
+				} )( object, scripts[ i ] )
 
 			}
-			*/
+
+		}
+
+	}
+
+	// signals
+
+	signals.objectSelected.add( function ( object ) {
+
+		if ( object !== null ) {
+
+			container.setDisplay( 'block' );
+
+			update();
 
 		} else {
 
@@ -49,6 +113,9 @@ Sidebar.Script = function ( editor ) {
 
 	} );
 
+	signals.scriptAdded.add( update );
+	signals.scriptRemoved.add( update );
+
 	return container;
 
-}
+};

+ 27 - 17
editor/js/Viewport.js

@@ -79,16 +79,15 @@ var Viewport = function ( editor ) {
 	// object picking
 
 	var raycaster = new THREE.Raycaster();
+	var mouse = new THREE.Vector2();
 
 	// events
 
 	var getIntersects = function ( point, object ) {
 
-		var vector = new THREE.Vector3();
-		vector.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1, 0.5 );
-		vector.unproject( camera );
+		mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );
 
-		raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
+		raycaster.setFromCamera( mouse, camera );
 
 		if ( object instanceof Array ) {
 
@@ -226,6 +225,12 @@ var Viewport = function ( editor ) {
 
 	// signals
 
+	signals.editorCleared.add( function () {
+
+		render();
+
+	} );
+
 	signals.themeChanged.add( function ( value ) {
 
 		switch ( value ) {
@@ -271,6 +276,7 @@ var Viewport = function ( editor ) {
 
 		renderer = createRenderer( type, antialias );
 		renderer.setClearColor( clearColor );
+		renderer.setPixelRatio( window.devicePixelRatio );
 		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
 
 		container.dom.appendChild( renderer.domElement );
@@ -323,11 +329,7 @@ var Viewport = function ( editor ) {
 
 			}
 
-			if ( object instanceof THREE.PerspectiveCamera === false ) {
-
-				transformControls.attach( object );
-
-			}
+			transformControls.attach( object );
 
 		}
 
@@ -341,7 +343,13 @@ var Viewport = function ( editor ) {
 
 	} );
 
-	signals.geometryChanged.add( render );
+	signals.geometryChanged.add( function ( geometry ) {
+
+		selectionBox.update( editor.selected );
+
+		render();
+
+	} );
 
 	signals.objectAdded.add( function ( object ) {
 
@@ -363,19 +371,21 @@ var Viewport = function ( editor ) {
 
 		transformControls.update();
 
-		if ( object !== camera ) {
+		if ( object.geometry !== undefined ) {
 
-			if ( object.geometry !== undefined ) {
+			selectionBox.update( object );
 
-				selectionBox.update( object );
+		}
 
-			}
+		if ( object instanceof THREE.PerspectiveCamera ) {
 
-			if ( editor.helpers[ object.id ] !== undefined ) {
+			object.updateProjectionMatrix();
 
-				editor.helpers[ object.id ].update();
+		}
 
-			}
+		if ( editor.helpers[ object.id ] !== undefined ) {
+
+			editor.helpers[ object.id ].update();
 
 		}
 

+ 128 - 46
editor/js/libs/app.js

@@ -2,88 +2,170 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-var APP = {};
+var APP = {
 
-APP.Player = function () {
+	Player: function () {
 
-	var loader = new THREE.ObjectLoader();
-	var camera, scene, renderer;
-	var scripts;
-	
-	this.dom = undefined;
+		var loader = new THREE.ObjectLoader();
+		var camera, scene, renderer;
 
-	this.load = function ( json ) {
+		var scripts = {};
 
-		renderer = new THREE.WebGLRenderer( { antialias: true } );
+		this.dom = undefined;
 
-		scene = loader.parse( json );
+		this.width = 500;
+		this.height = 500;
 
-		/*
-		scripts = [];
+		this.load = function ( json ) {
 
-		scene.traverse( function ( child ) {
+			renderer = new THREE.WebGLRenderer( { antialias: true } );
+			renderer.setPixelRatio( window.devicePixelRatio );
 
-			if ( child.script !== undefined ) {
+			camera = loader.parse( json.camera );
+			scene = loader.parse( json.scene );
 
-				var script = new Function( 'scene', 'time', child.script.source ).bind( child );
-				scripts.push( script );
+			scripts = {
+				keydown: [],
+				keyup: [],
+				mousedown: [],
+				mouseup: [],
+				mousemove: [],
+				update: []
+			};
+
+			for ( var uuid in json.scripts ) {
+
+				var object = scene.getObjectByProperty( 'uuid', uuid, true );
+
+				var sources = json.scripts[ uuid ];
+
+				for ( var i = 0; i < sources.length; i ++ ) {
+
+					var script = sources[ i ];
+
+					var events = ( new Function( 'player', 'scene', 'keydown', 'keyup', 'mousedown', 'mouseup', 'mousemove', 'update', script.source + '\nreturn { keydown: keydown, keyup: keyup, mousedown: mousedown, mouseup: mouseup, mousemove: mousemove, update: update };' ).bind( object ) )( this, scene );
+
+					for ( var name in events ) {
+
+						if ( events[ name ] === undefined ) continue;
+
+						if ( scripts[ name ] === undefined ) {
+
+							console.warn( 'APP.Player: event type not supported (', name, ')' );
+							continue;
+
+						}
+
+						scripts[ name ].push( events[ name ].bind( object ) );
+
+					}
+
+				}
 
 			}
 
-		} );
-		*/
+			this.dom = renderer.domElement;
 
-		this.dom = renderer.domElement;
+		};
 
-	};
+		this.setCamera = function ( value ) {
 
-	this.setCamera = function ( master ) {
+			camera = value;
+			camera.aspect = this.width / this.height;
+			camera.updateProjectionMatrix();
 
-		camera = master.clone();
+		};
 
-	};
+		this.setSize = function ( width, height ) {
 
-	this.setSize = function ( width, height ) {
+			this.width = width;
+			this.height = height;
 
-		renderer.setSize( width, height );
+			camera.aspect = this.width / this.height;
+			camera.updateProjectionMatrix();
 
-	};
+			renderer.setSize( width, height );
 
-	var request;
+		};
 
-	var animate = function ( time ) {
+		var dispatch = function ( array, event ) {
 
-		request = requestAnimationFrame( animate );
+			for ( var i = 0, l = array.length; i < l; i ++ ) {
 
-		/*
-		for ( var i = 0; i < scripts.length; i ++ ) {
+				array[ i ]( event );
 
-			scripts[ i ]( scene, time );
+			}
 
-		}
-		*/
+		};
 
-		renderer.render( scene, camera );
+		var request;
 
-	};
+		var animate = function ( time ) {
 
-	this.play = function () {
+			request = requestAnimationFrame( animate );
 
-		request = requestAnimationFrame( animate );
+			dispatch( scripts.update, { time: time } );
 
-	};
+			renderer.render( scene, camera );
 
-	this.stop = function () {
+		};
 
-		cancelAnimationFrame( request );
+		this.play = function () {
 
-	};
+			document.addEventListener( 'keydown', onDocumentKeyDown );
+			document.addEventListener( 'keyup', onDocumentKeyUp );
+			document.addEventListener( 'mousedown', onDocumentMouseDown );
+			document.addEventListener( 'mouseup', onDocumentMouseUp );
+			document.addEventListener( 'mousemove', onDocumentMouseMove );
 
-};
+			request = requestAnimationFrame( animate );
+
+		};
+
+		this.stop = function () {
+
+			document.removeEventListener( 'keydown', onDocumentKeyDown );
+			document.removeEventListener( 'keyup', onDocumentKeyUp );
+			document.removeEventListener( 'mousedown', onDocumentMouseDown );
+			document.removeEventListener( 'mouseup', onDocumentMouseUp );
+			document.removeEventListener( 'mousemove', onDocumentMouseMove );
+
+			cancelAnimationFrame( request );
+
+		};
+
+		//
+
+		var onDocumentKeyDown = function ( event ) {
+
+			dispatch( scripts.keydown, event );
+
+		};
+
+		var onDocumentKeyUp = function ( event ) {
+
+			dispatch( scripts.keyup, event );
+
+		};
+
+		var onDocumentMouseDown = function ( event ) {
+
+			dispatch( scripts.mousedown, event );
+
+		};
+
+		var onDocumentMouseUp = function ( event ) {
+
+			dispatch( scripts.mouseup, event );
+
+		};
+
+		var onDocumentMouseMove = function ( event ) {
+
+			dispatch( scripts.mousemove, event );
 
-APP.Script = function ( source ) {
+		};
 
-	this.uuid = THREE.Math.generateUUID();
-	this.source = source;
+	}
 
 };

+ 22 - 14
editor/js/libs/codemirror/codemirror.css

@@ -5,10 +5,6 @@
   font-family: monospace;
   height: 300px;
 }
-.CodeMirror-scroll {
-  /* Set scrolling behaviour here */
-  overflow: auto;
-}
 
 /* PADDING */
 
@@ -52,11 +48,15 @@
 .CodeMirror div.CodeMirror-secondarycursor {
   border-left: 1px solid silver;
 }
-.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
   width: auto;
   border: 0;
   background: #7e7;
 }
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
 .cm-animate-fat-cursor {
   width: auto;
   border: 0;
@@ -83,7 +83,7 @@
 /* Can style cursor different in overwrite (non-insert) mode */
 div.CodeMirror-overwrite div.CodeMirror-cursor {}
 
-.cm-tab { display: inline-block; }
+.cm-tab { display: inline-block; text-decoration: inherit; }
 
 .CodeMirror-ruler {
   border-left: 1px solid #ccc;
@@ -121,6 +121,7 @@ div.CodeMirror-overwrite div.CodeMirror-cursor {}
 .cm-header, .cm-strong {font-weight: bold;}
 .cm-em {font-style: italic;}
 .cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
 
 .cm-s-default .cm-error {color: #f00;}
 .cm-invalidchar {color: #f00;}
@@ -146,6 +147,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 }
 
 .CodeMirror-scroll {
+  overflow: scroll !important; /* Things will break if this is overridden */
   /* 30px is the magic margin used to hide the element's real scrollbars */
   /* See overflow: hidden in .CodeMirror */
   margin-bottom: -30px; margin-right: -30px;
@@ -190,7 +192,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 
 .CodeMirror-gutters {
   position: absolute; left: 0; top: 0;
-  padding-bottom: 30px;
   z-index: 3;
 }
 .CodeMirror-gutter {
@@ -198,13 +199,17 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
   height: 100%;
   -moz-box-sizing: content-box;
   box-sizing: content-box;
-  padding-bottom: 30px;
-  margin-bottom: -32px;
   display: inline-block;
+  margin-bottom: -30px;
   /* Hack to make IE7 behave */
   *zoom:1;
   *display:inline;
 }
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  height: 100%;
+}
 .CodeMirror-gutter-elt {
   position: absolute;
   cursor: default;
@@ -213,6 +218,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 
 .CodeMirror-lines {
   cursor: text;
+  min-height: 1px; /* prevents collapsing before first draw */
 }
 .CodeMirror pre {
   /* Reset some styles that the rest of the page might have set */
@@ -250,10 +256,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 
 .CodeMirror-widget {}
 
-.CodeMirror-wrap .CodeMirror-scroll {
-  overflow-x: hidden;
-}
-
 .CodeMirror-measure {
   position: absolute;
   width: 100%;
@@ -272,7 +274,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 div.CodeMirror-cursors {
   visibility: hidden;
   position: relative;
-  z-index: 1;
+  z-index: 3;
 }
 .CodeMirror-focused div.CodeMirror-cursors {
   visibility: visible;
@@ -299,3 +301,9 @@ div.CodeMirror-cursors {
     visibility: hidden;
   }
 }
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }

文件差异内容过多而无法显示
+ 344 - 229
editor/js/libs/codemirror/codemirror.js


+ 8 - 8
editor/js/libs/codemirror/modes/javascript.js → editor/js/libs/codemirror/mode/javascript.js

@@ -19,7 +19,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   var jsonldMode = parserConfig.jsonld;
   var jsonMode = parserConfig.json || jsonldMode;
   var isTS = parserConfig.typescript;
-  var wordRE = parserConfig.wordCharacters || /[\w$]/;
+  var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
 
   // Tokenizer
 
@@ -205,6 +205,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
         ++depth;
       } else if (wordRE.test(ch)) {
         sawSomething = true;
+      } else if (/["'\/]/.test(ch)) {
+        return;
       } else if (sawSomething && !depth) {
         ++pos;
         break;
@@ -391,7 +393,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   function maybeoperatorNoComma(type, value, noComma) {
     var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
     var expr = noComma == false ? expression : expressionNoComma;
-    if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
+    if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
     if (type == "operator") {
       if (/\+\+|--/.test(value)) return cont(me);
       if (value == "?") return cont(expression, expect(":"), expr);
@@ -417,13 +419,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   }
   function arrowBody(type) {
     findFatArrow(cx.stream, cx.state);
-    if (type == "{") return pass(statement);
-    return pass(expression);
+    return pass(type == "{" ? statement : expression);
   }
   function arrowBodyNoComma(type) {
     findFatArrow(cx.stream, cx.state);
-    if (type == "{") return pass(statement);
-    return pass(expressionNoComma);
+    return pass(type == "{" ? statement : expressionNoComma);
   }
   function maybelabel(type) {
     if (type == ":") return cont(poplex, statement);
@@ -592,7 +592,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   }
   function maybeArrayComprehension(type) {
     if (type == "for") return pass(comprehension, expect("]"));
-    if (type == ",") return cont(commasep(expressionNoComma, "]"));
+    if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
     return pass(commasep(expressionNoComma, "]"));
   }
   function comprehension(type) {
@@ -658,7 +658,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
       else return lexical.indented + (closing ? 0 : indentUnit);
     },
 
-    electricChars: ":{}",
+    electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
     blockCommentStart: jsonMode ? null : "/*",
     blockCommentEnd: jsonMode ? null : "*/",
     lineComment: jsonMode ? null : "//",

+ 31 - 0
editor/js/libs/codemirror/theme/monokai.css

@@ -0,0 +1,31 @@
+/* Based on Sublime Text's Monokai theme */
+
+.cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2;}
+.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}
+.cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;}
+.cm-s-monokai .CodeMirror-guttermarker { color: white; }
+.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-monokai .CodeMirror-linenumber {color: #d0d0d0;}
+.cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;}
+
+.cm-s-monokai span.cm-comment {color: #75715e;}
+.cm-s-monokai span.cm-atom {color: #ae81ff;}
+.cm-s-monokai span.cm-number {color: #ae81ff;}
+
+.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;}
+.cm-s-monokai span.cm-keyword {color: #f92672;}
+.cm-s-monokai span.cm-string {color: #e6db74;}
+
+.cm-s-monokai span.cm-variable {color: #a6e22e;}
+.cm-s-monokai span.cm-variable-2 {color: #9effff;}
+.cm-s-monokai span.cm-def {color: #fd971f;}
+.cm-s-monokai span.cm-bracket {color: #f8f8f2;}
+.cm-s-monokai span.cm-tag {color: #f92672;}
+.cm-s-monokai span.cm-link {color: #ae81ff;}
+.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
+
+.cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;}
+.cm-s-monokai .CodeMirror-matchingbracket {
+  text-decoration: underline;
+  color: white !important;
+}

+ 0 - 75
editor/js/libs/ui.editor.js

@@ -1,75 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-UI.CodeEditor = function ( mode ) {
-
-	UI.Element.call( this );
-
-	var scope = this;
-
-	var dom = document.createElement( 'div' );
-	dom.className = 'CodeEditor';
-
-	var editor = CodeMirror( dom, { mode: mode, indentWithTabs: true, lineWrapping: true, matchBrackets: true } );
-	editor.onKeyUp( 'keyup', function () {
-
-		if ( scope.onKeyUpCallback !== undefined ) {
-
-			scope.onKeyUpCallback();
-
-		}
-
-	});
-
-	this.dom = dom;
-	this.editor = editor;
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype = Object.create( UI.Element.prototype );
-UI.CodeEditor.prototype.constructor = UI.CodeEditor;
-
-UI.CodeEditor.prototype.setWidth = function ( value ) {
-
-	UI.Element.prototype.setWidth.call( this, value );
-
-	this.editor.setSize( this.dom.style.width, this.dom.style.height );
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype.setHeight = function ( value ) {
-
-	UI.Element.prototype.setHeight.call( this, value );
-
-	this.editor.setSize( this.dom.style.width, this.dom.style.height );
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype.getValue = function () {
-
-	return this.editor.getValue();
-
-};
-
-UI.CodeEditor.prototype.setValue = function ( value ) {
-
-	this.editor.setValue( value );
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype.onKeyUp = function ( callback ) {
-
-	this.onKeyUpCallback = callback;
-
-	return this;
-
-};

+ 14 - 3
editor/js/libs/ui.js

@@ -4,7 +4,11 @@
 
 var UI = {};
 
-UI.Element = function () {};
+UI.Element = function ( dom ) {
+
+	this.dom = dom;
+
+};
 
 UI.Element.prototype = {
 
@@ -56,7 +60,7 @@ UI.Element.prototype = {
 
 var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft',
 'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
-'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor' ];
+'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ];
 
 properties.forEach( function ( property ) {
 
@@ -307,6 +311,12 @@ UI.Text = function ( text ) {
 UI.Text.prototype = Object.create( UI.Element.prototype );
 UI.Text.prototype.constructor = UI.Text;
 
+UI.Text.prototype.getValue = function () {
+
+	return this.dom.textContent;
+
+};
+
 UI.Text.prototype.setValue = function ( value ) {
 
 	if ( value !== undefined ) {
@@ -322,7 +332,7 @@ UI.Text.prototype.setValue = function ( value ) {
 
 // Input
 
-UI.Input = function () {
+UI.Input = function ( text ) {
 
 	UI.Element.call( this );
 
@@ -340,6 +350,7 @@ UI.Input = function () {
 	}, false );
 
 	this.dom = dom;
+	this.setValue( text );
 
 	return this;
 

+ 1 - 0
examples/canvas_ascii_effect.html

@@ -82,6 +82,7 @@
 				scene.add( plane );
 
 				renderer = new THREE.CanvasRenderer();
+				renderer.setClearColor( 0xf0f0f0 );
 				renderer.setSize( width, height );
 				// container.appendChild( renderer.domElement );
 

+ 5 - 4
examples/canvas_interactive_cubes.html

@@ -29,6 +29,7 @@
 			var particleMaterial;
 
 			var raycaster;
+			var mouse;
 
 			var objects = [];
 
@@ -93,6 +94,7 @@
 				//
 				
 				raycaster = new THREE.Raycaster();
+				mouse = new THREE.Vector2();
 
 				renderer = new THREE.CanvasRenderer();
 				renderer.setClearColor( 0xf0f0f0 );
@@ -137,11 +139,10 @@
 
 				event.preventDefault();
 
-				var vector = new THREE.Vector3();
-				vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
-				vector.unproject( camera );
+				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
 
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( objects );
 

+ 5 - 4
examples/canvas_interactive_cubes_tween.html

@@ -29,6 +29,7 @@
 			var camera, scene, renderer;
 			
 			var raycaster;
+			var mouse;
 
 			init();
 			animate();
@@ -73,6 +74,7 @@
 				//
 				
 				raycaster = new THREE.Raycaster();
+				mouse = new THREE.Vector2();
 
 				renderer = new THREE.CanvasRenderer();
 				renderer.setClearColor( 0xf0f0f0 );
@@ -117,11 +119,10 @@
 
 				event.preventDefault();
 
-				var vector = new THREE.Vector3();
-				vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
-				vector.unproject( camera );
+				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
 
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( scene.children );
 

+ 5 - 5
examples/canvas_interactive_particles.html

@@ -28,6 +28,7 @@
 			var camera, scene, renderer;
 
 			var raycaster;
+			var mouse;
 
 			var PI2 = Math.PI * 2;
 
@@ -48,7 +49,7 @@
 
 			}
 
-			var mouse = { x: 0, y: 0 }, INTERSECTED;
+			var INTERSECTED;
 
 			init();
 			animate();
@@ -85,6 +86,7 @@
 				//
 				
 				raycaster = new THREE.Raycaster();
+				mouse = new THREE.Vector2();
 
 				renderer = new THREE.CanvasRenderer();
 				renderer.setClearColor( 0xf0f0f0 );
@@ -148,13 +150,11 @@
 				camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
 				camera.lookAt( scene.position );
 
-				// find intersections
-
 				camera.updateMatrixWorld();
 
-				var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 ).unproject( camera );
+				// find intersections
 
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( scene.children );
 

+ 5 - 5
examples/canvas_interactive_voxelpainter.html

@@ -26,7 +26,7 @@
 			var camera, scene, renderer;
 			var plane;
 
-			var vector, raycaster, isShiftDown = false;
+			var mouse, raycaster, isShiftDown = false;
 
 			var cubeGeometry = new THREE.BoxGeometry( 50, 50, 50 );
 			var cubeMaterial = new THREE.MeshLambertMaterial( { color: 0x00ff80, overdraw: 0.5 } );
@@ -78,8 +78,8 @@
 
 				//
 
-				vector = new THREE.Vector3();
 				raycaster = new THREE.Raycaster();
+				mouse = new THREE.Vector2();
 
 				var geometry = new THREE.PlaneBufferGeometry( 1000, 1000 );
 				geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
@@ -142,10 +142,10 @@
 
 				event.preventDefault();
 
-				vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
-				vector.unproject( camera );
+				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
 
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( objects );
 

+ 1 - 2
examples/canvas_lines_colors.html

@@ -80,8 +80,7 @@
 
 				scene = new THREE.Scene();
 
-				renderer = new THREE.CanvasRenderer( { antialias: false } );
-				renderer.setClearColor( 0x000000, 1 );
+				renderer = new THREE.CanvasRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 1 - 2
examples/canvas_lines_colors_2d.html

@@ -80,8 +80,7 @@
 
 				scene = new THREE.Scene();
 
-				renderer = new THREE.CanvasRenderer( { antialias: false } );
-				renderer.setClearColor( 0x000000, 1 );
+				renderer = new THREE.CanvasRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/canvas_lines_dashed.html

@@ -99,7 +99,7 @@
 				scene.add( object );
 
 				renderer = new THREE.CanvasRenderer();
-				renderer.setClearColor( 0x111111, 1 );
+				renderer.setClearColor( 0x111111 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( WIDTH, HEIGHT );
 

+ 2 - 1
examples/index.html

@@ -197,6 +197,7 @@
 				"webgl_buffergeometry_lines",
 				"webgl_buffergeometry_lines_indexed",
 				"webgl_buffergeometry_particles",
+				"webgl_buffergeometry_drawcalls",
 				"webgl_buffergeometry_rawshader",
 				"webgl_buffergeometry_uint",
 				"webgl_camera",
@@ -301,7 +302,7 @@
 				"webgl_materials_grass",
 				"webgl_materials_lightmap",
 				"webgl_materials_normalmap",
-				"webgl_materials_normalmap2",
+				"webgl_materials_normaldisplacementmap",
 				"webgl_materials_parallaxmap",
 				"webgl_materials_shaders_fresnel",
 				"webgl_materials_skin",

+ 9 - 2
examples/js/controls/OrthographicTrackballControls.js

@@ -1,5 +1,6 @@
 /**
  * @author Eberhard Graether / http://egraether.com/
+ * @author Mark Lundin 	/ http://mark-lundin.com
  * @author Patrick Fuller / http://patrick-fuller.com
  */
 
@@ -74,6 +75,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 	var startEvent = { type: 'start'};
 	var endEvent = { type: 'end'};
 
+
 	// methods
 
 	this.handleResize = function () {
@@ -99,6 +101,11 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 		this.radius = 0.5 * Math.min( this.screen.width, this.screen.height );
 
+		this.left0 = this.object.left;
+		this.right0 = this.object.right;
+		this.top0 = this.object.top;
+		this.bottom0 = this.object.bottom;
+
 	};
 
 	this.handleEvent = function ( event ) {
@@ -174,8 +181,8 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 			return vector;
 
- 		};
- 
+		};
+
 	}() );
 
 	this.rotateCamera = (function(){

+ 12 - 12
examples/js/crossfade/scenes.js

@@ -1,7 +1,7 @@
 function generateGeometry(objectType, numObjects) {
 
 	var geometry = new THREE.Geometry();
-	
+
 	function applyVertexColors( g, c ) {
 
 		g.faces.forEach( function( f ) {
@@ -19,7 +19,7 @@ function generateGeometry(objectType, numObjects) {
 	}
 
 	for ( var i = 0; i < numObjects; i ++ ) {
-	
+
 		var position = new THREE.Vector3();
 
 		position.x = Math.random() * 10000 - 5000;
@@ -51,7 +51,7 @@ function generateGeometry(objectType, numObjects) {
 			scale.y = scale.z = scale.x;
 			color.setRGB( Math.random()+0.1, 0, 0 );
 		}
-		
+
 		// give the geom's vertices a random color, to be displayed
 		applyVertexColors( geom, color );
 
@@ -70,12 +70,12 @@ function generateGeometry(objectType, numObjects) {
 }
 
 function Scene ( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
-	
+
 	this.clearColor = clearColor;
-	
+
 	this.camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 10000 );
 	this.camera.position.z = cameraZ;
-	
+
 	// Setup scene
 	this.scene = new THREE.Scene();
 	this.scene.add( new THREE.AmbientLight( 0x555555 ) );
@@ -91,19 +91,19 @@ function Scene ( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
 
 	renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
 	this.fbo = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters );
-	
+
 	this.render = function( delta, rtt ) {
-		
+
 		this.mesh.rotation.x += delta*this.rotationSpeed.x;
 		this.mesh.rotation.y += delta*this.rotationSpeed.y;
 		this.mesh.rotation.z += delta*this.rotationSpeed.z;
-		
-		renderer.setClearColor( this.clearColor, 1 );
-		
+
+		renderer.setClearColor( this.clearColor );
+
 		if (rtt)
 			renderer.render( this.scene, this.camera, this.fbo, true );
 		else
 			renderer.render( this.scene, this.camera );
-		
+
 	};
 }

+ 5 - 1
examples/js/effects/StereoEffect.js

@@ -122,15 +122,19 @@ THREE.StereoEffect = function ( renderer ) {
 
 		//
 
-		renderer.setViewport( 0, 0, _width * 2, _height );
 		renderer.clear();
+		renderer.enableScissorTest( true );
 
+		renderer.setScissor( 0, 0, _width, _height );
 		renderer.setViewport( 0, 0, _width, _height );
 		renderer.render( scene, _cameraL );
 
+		renderer.setScissor( _width, 0, _width, _height );
 		renderer.setViewport( _width, 0, _width, _height );
 		renderer.render( scene, _cameraR );
 
+		renderer.enableScissorTest( false );
+
 	};
 
 };

+ 8 - 0
examples/js/loaders/ColladaLoader.js

@@ -2805,6 +2805,14 @@ THREE.ColladaLoader = function () {
 
 		this.geometry3js = new THREE.Geometry();
 
+		if ( this.vertices === null ) {
+
+			// TODO (mrdoob): Study case when this is null (carrier.dae)
+
+			return this;
+
+		}
+
 		var vertexData = sources[ this.vertices.input['POSITION'].source ].data;
 
 		for ( var i = 0; i < vertexData.length; i += 3 ) {

+ 1 - 0
examples/js/loaders/MTLLoader.js

@@ -87,6 +87,7 @@ THREE.MTLLoader.prototype = {
 		}
 
 		var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options );
+		materialCreator.crossOrigin = this.crossOrigin
 		materialCreator.setMaterials( materialsInfo );
 		return materialCreator;
 

+ 2 - 1
examples/js/loaders/OBJMTLLoader.js

@@ -20,13 +20,14 @@ THREE.OBJMTLLoader.prototype = {
 		var scope = this;
 
 		var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) );
+		mtlLoader.crossOrigin = scope.crossOrigin;
 		mtlLoader.load( mtlurl, function ( materials ) {
 
 			var materialsCreator = materials;
 			materialsCreator.preload();
 
 			var loader = new THREE.XHRLoader( scope.manager );
-			loader.setCrossOrigin( this.crossOrigin );
+			loader.setCrossOrigin( scope.crossOrigin );
 			loader.load( url, function ( text ) {
 
 				var object = scope.parse( text );

+ 21 - 1
examples/js/loaders/STLLoader.js

@@ -61,7 +61,27 @@ THREE.STLLoader.prototype = {
 			face_size = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8);
 			n_faces = reader.getUint32(80,true);
 			expect = 80 + (32 / 8) + (n_faces * face_size);
-			return expect === reader.byteLength;
+			
+			if ( expect === reader.byteLength ) {
+				
+				return true;
+				
+			}
+
+			// some binary files will have different size from expected,
+			// checking characters higher than ASCII to confirm is binary
+			var fileLength = reader.byteLength;
+			for ( var index = 0; index < fileLength; index ++ ) {
+
+				if ( reader.getUint8(index, false) > 127 ) {
+					
+					return true;
+					
+				}
+
+			}
+
+			return false;
 
 		};
 

+ 7 - 80
examples/js/loaders/SceneLoader.js

@@ -1036,7 +1036,7 @@ THREE.SceneLoader.prototype = {
 
 			for ( parID in matJSON.parameters ) {
 
-				if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" || parID === "alphaMap" ) {
+				if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" || parID === "normalMap" || parID === "alphaMap" ) {
 
 					matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ];
 
@@ -1087,6 +1087,11 @@ THREE.SceneLoader.prototype = {
 					var v3 = matJSON.parameters[ parID ];
 					matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] );
 
+				} else if ( parID === "normalScale" ) {
+
+					var v2 = matJSON.parameters[ parID ];
+					matJSON.parameters[ parID ] = new THREE.Vector2( v2[ 0 ], v2[ 1 ] );
+
 				}
 
 			}
@@ -1097,85 +1102,7 @@ THREE.SceneLoader.prototype = {
 
 			}
 
-			if ( matJSON.parameters.normalMap ) {
-
-				var shader = THREE.ShaderLib[ "normalmap" ];
-				var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-				var diffuse = matJSON.parameters.color;
-				var specular = matJSON.parameters.specular;
-				var ambient = matJSON.parameters.ambient;
-				var shininess = matJSON.parameters.shininess;
-
-				uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ];
-
-				if ( matJSON.parameters.normalScale ) {
-
-					uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] );
-
-				}
-
-				if ( matJSON.parameters.map ) {
-
-					uniforms[ "tDiffuse" ].value = matJSON.parameters.map;
-					uniforms[ "enableDiffuse" ].value = true;
-
-				}
-
-				if ( matJSON.parameters.envMap ) {
-
-					uniforms[ "tCube" ].value = matJSON.parameters.envMap;
-					uniforms[ "enableReflection" ].value = true;
-					uniforms[ "reflectivity" ].value = matJSON.parameters.reflectivity;
-
-				}
-
-				if ( matJSON.parameters.lightMap ) {
-
-					uniforms[ "tAO" ].value = matJSON.parameters.lightMap;
-					uniforms[ "enableAO" ].value = true;
-
-				}
-
-				if ( matJSON.parameters.specularMap ) {
-
-					uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ];
-					uniforms[ "enableSpecular" ].value = true;
-
-				}
-
-				if ( matJSON.parameters.displacementMap ) {
-
-					uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ];
-					uniforms[ "enableDisplacement" ].value = true;
-
-					uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias;
-					uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale;
-
-				}
-
-				uniforms[ "diffuse" ].value.setHex( diffuse );
-				uniforms[ "specular" ].value.setHex( specular );
-				uniforms[ "ambient" ].value.setHex( ambient );
-
-				uniforms[ "shininess" ].value = shininess;
-
-				if ( matJSON.parameters.opacity ) {
-
-					uniforms[ "opacity" ].value = matJSON.parameters.opacity;
-
-				}
-
-				var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
-
-				material = new THREE.ShaderMaterial( parameters );
-
-			} else {
-
-				material = new THREE[ matJSON.type ]( matJSON.parameters );
-
-			}
-
+			material = new THREE[ matJSON.type ]( matJSON.parameters );
 			material.name = matID;
 
 			result.materials[ matID ] = material;

+ 5 - 5
examples/js/modifiers/TessellateModifier.js

@@ -17,7 +17,7 @@ THREE.TessellateModifier.prototype.modify = function ( geometry ) {
 
 	var faces = [];
 	var faceVertexUvs = [];
-	var maxEdgeLength = this.maxEdgeLength;
+	var maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
 
 	for ( var i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) {
 
@@ -39,11 +39,11 @@ THREE.TessellateModifier.prototype.modify = function ( geometry ) {
 			var vb = geometry.vertices[ b ];
 			var vc = geometry.vertices[ c ];
 
-			var dab = va.distanceTo( vb );
-			var dbc = vb.distanceTo( vc );
-			var dac = va.distanceTo( vc );
+			var dab = va.distanceToSquared( vb );
+			var dbc = vb.distanceToSquared( vc );
+			var dac = va.distanceToSquared( vc );
 
-			if ( dab > maxEdgeLength || dbc > maxEdgeLength || dac > maxEdgeLength ) {
+			if ( dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared ) {
 
 				var m = geometry.vertices.length;
 

+ 1 - 1
examples/js/renderers/CanvasRenderer.js

@@ -66,7 +66,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 	} ),
 
 	_clearColor = new THREE.Color( 0x000000 ),
-	_clearAlpha = 0,
+	_clearAlpha = parameters.alpha === true ? 0 : 1,
 
 	_contextGlobalAlpha = 1,
 	_contextGlobalCompositeOperation = 0,

+ 1 - 1
examples/js/renderers/Projector.js

@@ -145,7 +145,7 @@ THREE.Projector = function () {
 
 	this.pickingRay = function ( vector, camera ) {
 
-		console.error( 'THREE.Projector: .pickingRay() has been removed.' );
+		console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
 
 	};
 

+ 616 - 0
examples/js/shaders/NormalDisplacementShader.js

@@ -0,0 +1,616 @@
+/* 
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * Normal map shader
+ *  - Blinn-Phong
+ *  - normal + diffuse + specular + AO + displacement + reflection + shadow maps
+ *  - point and directional lights (use with "lights: true" material option)
+ */
+
+THREE.NormalDisplacementShader = {
+
+	uniforms: THREE.UniformsUtils.merge( [
+
+		THREE.UniformsLib[ "fog" ],
+		THREE.UniformsLib[ "lights" ],
+		THREE.UniformsLib[ "shadowmap" ],
+
+		{
+
+		"enableAO"          : { type: "i", value: 0 },
+		"enableDiffuse"     : { type: "i", value: 0 },
+		"enableSpecular"    : { type: "i", value: 0 },
+		"enableReflection"  : { type: "i", value: 0 },
+		"enableDisplacement": { type: "i", value: 0 },
+
+		"tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture
+		"tDiffuse"     : { type: "t", value: null },
+		"tCube"        : { type: "t", value: null },
+		"tNormal"      : { type: "t", value: null },
+		"tSpecular"    : { type: "t", value: null },
+		"tAO"          : { type: "t", value: null },
+
+		"uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) },
+
+		"uDisplacementBias": { type: "f", value: 0.0 },
+		"uDisplacementScale": { type: "f", value: 1.0 },
+
+		"diffuse": { type: "c", value: new THREE.Color( 0xffffff ) },
+		"specular": { type: "c", value: new THREE.Color( 0x111111 ) },
+		"ambient": { type: "c", value: new THREE.Color( 0xffffff ) },
+		"shininess": { type: "f", value: 30 },
+		"opacity": { type: "f", value: 1 },
+
+		"refractionRatio": { type: "f", value: 0.98 },
+		"reflectivity": { type: "f", value: 0.5 },
+
+		"uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) },
+		"uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) },
+
+		"wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
+
+		}
+
+	] ),
+
+	fragmentShader: [
+
+		"uniform vec3 ambient;",
+		"uniform vec3 diffuse;",
+		"uniform vec3 specular;",
+		"uniform float shininess;",
+		"uniform float opacity;",
+
+		"uniform bool enableDiffuse;",
+		"uniform bool enableSpecular;",
+		"uniform bool enableAO;",
+		"uniform bool enableReflection;",
+
+		"uniform sampler2D tDiffuse;",
+		"uniform sampler2D tNormal;",
+		"uniform sampler2D tSpecular;",
+		"uniform sampler2D tAO;",
+
+		"uniform samplerCube tCube;",
+
+		"uniform vec2 uNormalScale;",
+
+		"uniform float refractionRatio;",
+		"uniform float reflectivity;",
+
+		"varying vec3 vTangent;",
+		"varying vec3 vBinormal;",
+		"varying vec3 vNormal;",
+		"varying vec2 vUv;",
+
+		"uniform vec3 ambientLightColor;",
+
+		"#if MAX_DIR_LIGHTS > 0",
+
+		"	uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
+		"	uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
+
+		"#endif",
+
+		"#if MAX_HEMI_LIGHTS > 0",
+
+		"	uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
+		"	uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
+		"	uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
+
+		"#endif",
+
+		"#if MAX_POINT_LIGHTS > 0",
+
+		"	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
+		"	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
+		"	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+
+		"#endif",
+
+		"#if MAX_SPOT_LIGHTS > 0",
+
+		"	uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
+		"	uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
+		"	uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
+		"	uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
+		"	uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
+		"	uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
+
+		"#endif",
+
+		"#ifdef WRAP_AROUND",
+
+		"	uniform vec3 wrapRGB;",
+
+		"#endif",
+
+		"varying vec3 vWorldPosition;",
+		"varying vec3 vViewPosition;",
+
+		THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
+		THREE.ShaderChunk[ "fog_pars_fragment" ],
+		THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],
+
+		"void main() {",
+			THREE.ShaderChunk[ "logdepthbuf_fragment" ],
+
+		"	gl_FragColor = vec4( vec3( 1.0 ), opacity );",
+
+		"	vec3 specularTex = vec3( 1.0 );",
+
+		"	vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
+		"	normalTex.xy *= uNormalScale;",
+		"	normalTex = normalize( normalTex );",
+
+		"	if( enableDiffuse ) {",
+
+		"		#ifdef GAMMA_INPUT",
+
+		"			vec4 texelColor = texture2D( tDiffuse, vUv );",
+		"			texelColor.xyz *= texelColor.xyz;",
+
+		"			gl_FragColor = gl_FragColor * texelColor;",
+
+		"		#else",
+
+		"			gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );",
+
+		"		#endif",
+
+		"	}",
+
+		"	if( enableAO ) {",
+
+		"		#ifdef GAMMA_INPUT",
+
+		"			vec4 aoColor = texture2D( tAO, vUv );",
+		"			aoColor.xyz *= aoColor.xyz;",
+
+		"			gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;",
+
+		"		#else",
+
+		"			gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;",
+
+		"		#endif",
+
+		"	}",
+		
+		THREE.ShaderChunk[ "alphatest_fragment" ],
+
+		"	if( enableSpecular )",
+		"		specularTex = texture2D( tSpecular, vUv ).xyz;",
+
+		"	mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );",
+		"	vec3 finalNormal = tsb * normalTex;",
+
+		"	#ifdef FLIP_SIDED",
+
+		"		finalNormal = -finalNormal;",
+
+		"	#endif",
+
+		"	vec3 normal = normalize( finalNormal );",
+		"	vec3 viewPosition = normalize( vViewPosition );",
+
+			// point lights
+
+		"	#if MAX_POINT_LIGHTS > 0",
+
+		"		vec3 pointDiffuse = vec3( 0.0 );",
+		"		vec3 pointSpecular = vec3( 0.0 );",
+
+		"		for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
+
+		"			vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
+		"			vec3 pointVector = lPosition.xyz + vViewPosition.xyz;",
+
+		"			float pointDistance = 1.0;",
+		"			if ( pointLightDistance[ i ] > 0.0 )",
+		"				pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );",
+
+		"			pointVector = normalize( pointVector );",
+
+					// diffuse
+
+		"			#ifdef WRAP_AROUND",
+
+		"				float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );",
+		"				float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );",
+
+		"				vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
+
+		"			#else",
+
+		"				float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
+
+		"			#endif",
+
+		"			pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;",
+
+					// specular
+
+		"			vec3 pointHalfVector = normalize( pointVector + viewPosition );",
+		"			float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
+		"			float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );",
+
+		"			float specularNormalization = ( shininess + 2.0 ) / 8.0;",
+
+		"			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( pointVector, pointHalfVector ), 0.0 ), 5.0 );",
+		"			pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",
+
+		"		}",
+
+		"	#endif",
+
+			// spot lights
+
+		"	#if MAX_SPOT_LIGHTS > 0",
+
+		"		vec3 spotDiffuse = vec3( 0.0 );",
+		"		vec3 spotSpecular = vec3( 0.0 );",
+
+		"		for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
+
+		"			vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
+		"			vec3 spotVector = lPosition.xyz + vViewPosition.xyz;",
+
+		"			float spotDistance = 1.0;",
+		"			if ( spotLightDistance[ i ] > 0.0 )",
+		"				spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );",
+
+		"			spotVector = normalize( spotVector );",
+
+		"			float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",
+
+		"			if ( spotEffect > spotLightAngleCos[ i ] ) {",
+
+		"				spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );",
+
+						// diffuse
+
+		"				#ifdef WRAP_AROUND",
+
+		"					float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );",
+		"					float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );",
+
+		"					vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",
+
+		"				#else",
+
+		"					float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );",
+
+		"				#endif",
+
+		"				spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;",
+
+						// specular
+
+		"				vec3 spotHalfVector = normalize( spotVector + viewPosition );",
+		"				float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
+		"				float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );",
+
+		"				float specularNormalization = ( shininess + 2.0 ) / 8.0;",
+
+		"				vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( spotVector, spotHalfVector ), 0.0 ), 5.0 );",
+		"				spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;",
+
+		"			}",
+
+		"		}",
+
+		"	#endif",
+
+			// directional lights
+
+		"	#if MAX_DIR_LIGHTS > 0",
+
+		"		vec3 dirDiffuse = vec3( 0.0 );",
+		"		vec3 dirSpecular = vec3( 0.0 );",
+
+		"		for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
+
+		"			vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
+		"			vec3 dirVector = normalize( lDirection.xyz );",
+
+					// diffuse
+
+		"			#ifdef WRAP_AROUND",
+
+		"				float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );",
+		"				float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
+
+		"				vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );",
+
+		"			#else",
+
+		"				float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
+
+		"			#endif",
+
+		"			dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;",
+
+					// specular
+
+		"			vec3 dirHalfVector = normalize( dirVector + viewPosition );",
+		"			float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
+		"			float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );",
+
+		"			float specularNormalization = ( shininess + 2.0 ) / 8.0;",
+
+		"			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );",
+		"			dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
+
+		"		}",
+
+		"	#endif",
+
+			// hemisphere lights
+
+		"	#if MAX_HEMI_LIGHTS > 0",
+
+		"		vec3 hemiDiffuse = vec3( 0.0 );",
+		"		vec3 hemiSpecular = vec3( 0.0 );" ,
+
+		"		for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
+
+		"			vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
+		"			vec3 lVector = normalize( lDirection.xyz );",
+
+					// diffuse
+
+		"			float dotProduct = dot( normal, lVector );",
+		"			float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
+
+		"			vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
+
+		"			hemiDiffuse += diffuse * hemiColor;",
+
+					// specular (sky light)
+
+
+		"			vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
+		"			float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
+		"			float hemiSpecularWeightSky = specularTex.r * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );",
+
+					// specular (ground light)
+
+		"			vec3 lVectorGround = -lVector;",
+
+		"			vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
+		"			float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
+		"			float hemiSpecularWeightGround = specularTex.r * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );",
+
+		"			float dotProductGround = dot( normal, lVectorGround );",
+
+		"			float specularNormalization = ( shininess + 2.0 ) / 8.0;",
+
+		"			vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );",
+		"			vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );",
+		"			hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
+
+		"		}",
+
+		"	#endif",
+
+			// all lights contribution summation
+
+		"	vec3 totalDiffuse = vec3( 0.0 );",
+		"	vec3 totalSpecular = vec3( 0.0 );",
+
+		"	#if MAX_DIR_LIGHTS > 0",
+
+		"		totalDiffuse += dirDiffuse;",
+		"		totalSpecular += dirSpecular;",
+
+		"	#endif",
+
+		"	#if MAX_HEMI_LIGHTS > 0",
+
+		"		totalDiffuse += hemiDiffuse;",
+		"		totalSpecular += hemiSpecular;",
+
+		"	#endif",
+
+		"	#if MAX_POINT_LIGHTS > 0",
+
+		"		totalDiffuse += pointDiffuse;",
+		"		totalSpecular += pointSpecular;",
+
+		"	#endif",
+
+		"	#if MAX_SPOT_LIGHTS > 0",
+
+		"		totalDiffuse += spotDiffuse;",
+		"		totalSpecular += spotSpecular;",
+
+		"	#endif",
+
+		"	#ifdef METAL",
+
+		"		gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );",
+
+		"	#else",
+
+		"		gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;",
+
+		"	#endif",
+
+		"	if ( enableReflection ) {",
+
+		"		vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",
+
+		"		#ifdef ENVMAP_MODE_REFLECTION",
+
+		"			vec3 vReflect = reflect( cameraToVertex, normal );",
+
+		"		#else",
+
+		"			vec3 vReflect = refract( cameraToVertex, normal, refractionRatio );",
+
+		"		#endif",
+
+		"		vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );",
+
+		"		#ifdef GAMMA_INPUT",
+
+		"			cubeColor.xyz *= cubeColor.xyz;",
+
+		"		#endif",
+
+		"		gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );",
+
+		"	}",
+
+			THREE.ShaderChunk[ "shadowmap_fragment" ],
+			THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
+			THREE.ShaderChunk[ "fog_fragment" ],
+
+		"}"
+
+	].join("\n"),
+
+	vertexShader: [
+
+		"attribute vec4 tangent;",
+
+		"uniform vec2 uOffset;",
+		"uniform vec2 uRepeat;",
+
+		"uniform bool enableDisplacement;",
+
+		"#ifdef VERTEX_TEXTURES",
+
+		"	uniform sampler2D tDisplacement;",
+		"	uniform float uDisplacementScale;",
+		"	uniform float uDisplacementBias;",
+
+		"#endif",
+
+		"varying vec3 vTangent;",
+		"varying vec3 vBinormal;",
+		"varying vec3 vNormal;",
+		"varying vec2 vUv;",
+
+		"varying vec3 vWorldPosition;",
+		"varying vec3 vViewPosition;",
+
+		THREE.ShaderChunk[ "skinning_pars_vertex" ],
+		THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
+		THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],
+
+		"void main() {",
+
+			THREE.ShaderChunk[ "skinbase_vertex" ],
+			THREE.ShaderChunk[ "skinnormal_vertex" ],
+
+			// normal, tangent and binormal vectors
+
+		"	#ifdef USE_SKINNING",
+
+		"		vNormal = normalize( normalMatrix * skinnedNormal.xyz );",
+
+		"		vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );",
+		"		vTangent = normalize( normalMatrix * skinnedTangent.xyz );",
+
+		"	#else",
+
+		"		vNormal = normalize( normalMatrix * normal );",
+		"		vTangent = normalize( normalMatrix * tangent.xyz );",
+
+		"	#endif",
+
+		"	vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );",
+
+		"	vUv = uv * uRepeat + uOffset;",
+
+			// displacement mapping
+
+		"	vec3 displacedPosition;",
+
+		"	#ifdef VERTEX_TEXTURES",
+
+		"		if ( enableDisplacement ) {",
+
+		"			vec3 dv = texture2D( tDisplacement, uv ).xyz;",
+		"			float df = uDisplacementScale * dv.x + uDisplacementBias;",
+		"			displacedPosition = position + normalize( normal ) * df;",
+
+		"		} else {",
+
+		"			#ifdef USE_SKINNING",
+
+		"				vec4 skinVertex = bindMatrix * vec4( position, 1.0 );",
+
+		"				vec4 skinned = vec4( 0.0 );",
+		"				skinned += boneMatX * skinVertex * skinWeight.x;",
+		"				skinned += boneMatY * skinVertex * skinWeight.y;",
+		"				skinned += boneMatZ * skinVertex * skinWeight.z;",
+		"				skinned += boneMatW * skinVertex * skinWeight.w;",
+		"				skinned  = bindMatrixInverse * skinned;",
+
+		"				displacedPosition = skinned.xyz;",
+
+		"			#else",
+
+		"				displacedPosition = position;",
+
+		"			#endif",
+
+		"		}",
+
+		"	#else",
+
+		"		#ifdef USE_SKINNING",
+
+		"			vec4 skinVertex = bindMatrix * vec4( position, 1.0 );",
+
+		"			vec4 skinned = vec4( 0.0 );",
+		"			skinned += boneMatX * skinVertex * skinWeight.x;",
+		"			skinned += boneMatY * skinVertex * skinWeight.y;",
+		"			skinned += boneMatZ * skinVertex * skinWeight.z;",
+		"			skinned += boneMatW * skinVertex * skinWeight.w;",
+		"			skinned  = bindMatrixInverse * skinned;",
+
+		"			displacedPosition = skinned.xyz;",
+
+		"		#else",
+
+		"			displacedPosition = position;",
+
+		"		#endif",
+
+		"	#endif",
+
+			//
+
+		"	vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );",
+		"	vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );",
+
+		"	gl_Position = projectionMatrix * mvPosition;",
+
+			THREE.ShaderChunk[ "logdepthbuf_vertex" ],
+
+			//
+
+		"	vWorldPosition = worldPosition.xyz;",
+		"	vViewPosition = -mvPosition.xyz;",
+
+			// shadows
+
+		"	#ifdef USE_SHADOWMAP",
+
+		"		for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
+
+		"			vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;",
+
+		"		}",
+
+		"	#endif",
+
+		"}"
+
+	].join("\n")
+
+};

+ 1 - 1
examples/misc_animation_keys.html

@@ -59,7 +59,7 @@
 				camera.lookAt(new THREE.Vector3( 0, 0, 0 ));
 
 				renderer = new THREE.WebGLRenderer();
-				renderer.setClearColor( 0x555555, 1 );
+				renderer.setClearColor( 0x555555 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 22 - 42
examples/misc_controls_fly.html

@@ -107,46 +107,17 @@
 				dirLight.position.set( -1, 0, 1 ).normalize();
 				scene.add( dirLight );
 
-				ambientLight = new THREE.AmbientLight( 0x000000 );
-				scene.add( ambientLight );
-
-				var planetTexture   = THREE.ImageUtils.loadTexture( "textures/planets/earth_atmos_2048.jpg" );
-				var cloudsTexture   = THREE.ImageUtils.loadTexture( "textures/planets/earth_clouds_1024.png" );
-				var normalTexture   = THREE.ImageUtils.loadTexture( "textures/planets/earth_normal_2048.jpg" );
-				var specularTexture = THREE.ImageUtils.loadTexture( "textures/planets/earth_specular_2048.jpg" );
-
-				var moonTexture = THREE.ImageUtils.loadTexture( "textures/planets/moon_1024.jpg" );
-
-				var shader = THREE.ShaderLib[ "normalmap" ];
-				var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
-				uniforms[ "tNormal" ].value = normalTexture;
-				uniforms[ "uNormalScale" ].value.set( 0.85, 0.85 );
-
-				uniforms[ "tDiffuse" ].value = planetTexture;
-				uniforms[ "tSpecular" ].value = specularTexture;
-
-				uniforms[ "enableAO" ].value = false;
-				uniforms[ "enableDiffuse" ].value = true;
-				uniforms[ "enableSpecular" ].value = true;
-
-				uniforms[ "diffuse" ].value.setHex( 0xffffff );
-				uniforms[ "specular" ].value.setHex( 0x333333 );
-				uniforms[ "ambient" ].value.setHex( 0x000000 );
-
-				uniforms[ "shininess" ].value = 15;
-
-				var parameters = {
-
-					fragmentShader: shader.fragmentShader,
-					vertexShader: shader.vertexShader,
-					uniforms: uniforms,
-					lights: true,
-					fog: true
-
-				};
-
-				var materialNormalMap = new THREE.ShaderMaterial( parameters );
+				var materialNormalMap = new THREE.MeshPhongMaterial( {
+				
+					ambient: 0x000000,
+					specular: 0x333333,
+					shininess: 15,
+					map: THREE.ImageUtils.loadTexture( "textures/planets/earth_atmos_2048.jpg" ),
+					specularMap: THREE.ImageUtils.loadTexture( "textures/planets/earth_specular_2048.jpg" ),
+					normalMap: THREE.ImageUtils.loadTexture( "textures/planets/earth_normal_2048.jpg" ),
+					normalScale: new THREE.Vector2( 0.85, 0.85 )
+				
+				} );
 
 				// planet
 
@@ -160,7 +131,12 @@
 
 				// clouds
 
-				var materialClouds = new THREE.MeshLambertMaterial( { color: 0xffffff, map: cloudsTexture, transparent: true } );
+				var materialClouds = new THREE.MeshLambertMaterial( {
+				
+					map: THREE.ImageUtils.loadTexture( "textures/planets/earth_clouds_1024.png" ),
+					transparent: true
+				
+				} );
 
 				meshClouds = new THREE.Mesh( geometry, materialClouds );
 				meshClouds.scale.set( cloudsScale, cloudsScale, cloudsScale );
@@ -169,7 +145,11 @@
 
 				// moon
 
-				var materialMoon = new THREE.MeshPhongMaterial( { color: 0xffffff, map: moonTexture } );
+				var materialMoon = new THREE.MeshPhongMaterial( {
+				
+					map: THREE.ImageUtils.loadTexture( "textures/planets/moon_1024.jpg" )
+				
+				} );
 
 				meshMoon = new THREE.Mesh( geometry, materialMoon );
 				meshMoon.position.set( radius * 5, 0, 0 );

+ 1 - 1
examples/misc_controls_orbit.html

@@ -109,7 +109,7 @@
 				// renderer
 
 				renderer = new THREE.WebGLRenderer( { antialias: false } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 1 - 1
examples/misc_controls_trackball.html

@@ -117,7 +117,7 @@
 				// renderer
 
 				renderer = new THREE.WebGLRenderer( { antialias: false } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 44 - 40
examples/models/molecules/aspirin.pdb

@@ -1,40 +1,44 @@
-HEADER    NONAME 22-Apr-10                                              NONE   1
-TITLE                                                                   NONE   2
-AUTHOR    Chemical Structure Services at http://cactus.nci.nih.gov      NONE   3
-REVDAT   1  22-Apr-10     0                                             NONE   4
-ATOM      1  C           0       2.154   1.017  -0.012  0.00  0.00           C+0
-ATOM      2  C           0      -0.545   1.675   0.087  0.00  0.00           C+0
-ATOM      3  C           0       1.761   2.338   0.015  0.00  0.00           C+0
-ATOM      4  C           0       0.416   2.666   0.064  0.00  0.00           C+0
-ATOM      5  C           0      -3.466  -1.377   0.133  0.00  0.00           C+0
-ATOM      6  C           0       1.192   0.004   0.010  0.00  0.00           C+0
-ATOM      7  C           0      -0.168   0.341   0.060  0.00  0.00           C+0
-ATOM      8  O           0       0.765  -2.290  -0.001  0.00  0.00           O+0
-ATOM      9  O           0      -2.733   0.825  -0.277  0.00  0.00           O+0
-ATOM     10  O           0       2.912  -1.731  -0.067  0.00  0.00           O+0
-ATOM     11  C           0       1.604  -1.411  -0.019  0.00  0.00           C+0
-ATOM     12  C           0      -2.411  -0.315  -0.036  0.00  0.00           C+0
-ATOM     13  O           0      -1.112  -0.634   0.081  0.00  0.00           O+0
-ATOM     14  H           0       3.183  -2.659  -0.086  0.00  0.00           H+0
-ATOM     15  H           0       3.203   0.765  -0.054  0.00  0.00           H+0
-ATOM     16  H           0      -1.591   1.939   0.125  0.00  0.00           H+0
-ATOM     17  H           0       2.506   3.120  -0.002  0.00  0.00           H+0
-ATOM     18  H           0       0.118   3.704   0.085  0.00  0.00           H+0
-ATOM     19  H           0      -3.762  -1.431   1.181  0.00  0.00           H+0
-ATOM     20  H           0      -4.334  -1.127  -0.477  0.00  0.00           H+0
-ATOM     21  H           0      -3.066  -2.340  -0.182  0.00  0.00           H+0
-CONECT    1    6    3   15    0                                         NONE  26
-CONECT    2    7    4   16    0                                         NONE  27
-CONECT    3    1    4   17    0                                         NONE  28
-CONECT    4    2    3   18    0                                         NONE  29
-CONECT    5   12   19   20   21                                         NONE  30
-CONECT    6    7    1   11    0                                         NONE  31
-CONECT    7    6    2   13    0                                         NONE  32
-CONECT    8   11    0    0    0                                         NONE  33
-CONECT    9   12    0    0    0                                         NONE  34
-CONECT   10   11   14    0    0                                         NONE  35
-CONECT   11    6   10    8    0                                         NONE  36
-CONECT   12   13    5    9    0                                         NONE  37
-CONECT   13    7   12    0    0                                         NONE  38
-END                                                                     NONE  39
-
+HEADER
+HETATM    1  C   UNK  0001      -0.778  -3.342  -0.910
+HETATM    2  O   UNK  0001      -1.251  -3.633  -1.994
+HETATM    3  O   UNK  0001      -0.469  -4.239   0.048
+HETATM    4  C   UNK  0001      -0.569  -1.952  -0.480
+HETATM    5  C   UNK  0001      -1.706  -1.156  -0.297
+HETATM    6  C   UNK  0001      -1.565   0.180   0.087
+HETATM    7  C   UNK  0001      -0.294   0.725   0.273
+HETATM    8  C   UNK  0001       0.843  -0.060   0.075
+HETATM    9  C   UNK  0001       0.703  -1.401  -0.291
+HETATM   10  O   UNK  0001       1.883  -2.113  -0.531
+HETATM   11  C   UNK  0001       2.213  -2.986   0.497
+HETATM   12  C   UNK  0001       3.539  -3.621   0.208
+HETATM   13  O   UNK  0001       1.510  -3.239   1.470
+HETATM   14  H   UNK  0001      -0.081  -3.852   0.870
+HETATM   15  H   UNK  0001      -2.698  -1.572  -0.462
+HETATM   16  H   UNK  0001      -2.449   0.799   0.229
+HETATM   17  H   UNK  0001      -0.189   1.769   0.561
+HETATM   18  H   UNK  0001       1.830   0.376   0.201
+HETATM   19  H   UNK  0001       4.294  -2.847   0.047
+HETATM   20  H   UNK  0001       3.844  -4.225   1.067
+HETATM   21  H   UNK  0001       3.456  -4.267  -0.669
+CONECT    1    2    3    4
+CONECT    2    1
+CONECT    3    1   14
+CONECT    4    1    5    9
+CONECT    5    4    6   15
+CONECT    6    5    7   16
+CONECT    7    6    8   17
+CONECT    8    7    9   18
+CONECT    9    4    8   10
+CONECT   10    9   11
+CONECT   11   10   12   13
+CONECT   12   11   19   20   21
+CONECT   13   11
+CONECT   14    3
+CONECT   15    5
+CONECT   16    6
+CONECT   17    7
+CONECT   18    8
+CONECT   19   12
+CONECT   20   12
+CONECT   21   12
+END

+ 1 - 1
examples/scenes/test_scene.js

@@ -592,7 +592,7 @@
 
 		"phong_normal": {
 			"type": "MeshPhongMaterial",
-			"parameters": { "color": 0, "specular": 16777215, "shininess": 25, "envMap": "cube_reflection", "reflectivity": 0.1, "lightMap": "texture_ao", "normalMap": "texture_normal", "normalScale": [ 1, -1 ], "displacementMap": "texture_displacement", "displacementScale": 2.436143, "displacementBias": -0.428408 }
+			"parameters": { "color": 0, "specular": 16777215, "shininess": 25, "envMap": "cube_reflection", "reflectivity": 0.1, "lightMap": "texture_ao", "normalMap": "texture_normal", "normalScale": [ 1, -1 ] }
 		},
 
 		"phong_morph": {

+ 1 - 2
examples/webgl_animation_skinning_blending.html

@@ -68,7 +68,7 @@
 				scene.add( light );
 
 				renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false } );
-				renderer.setClearColor( '#777777', 1 );
+				renderer.setClearColor( 0x777777 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.autoClear = true;
@@ -263,4 +263,3 @@
 
 	</body>
 </html>
-

+ 1 - 2
examples/webgl_animation_skinning_morph.html

@@ -134,12 +134,11 @@
 				// RENDERER
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 				renderer.domElement.style.position = "relative";
 
-				renderer.setClearColor( scene.fog.color, 1 );
-
 				container.appendChild( renderer.domElement );
 
 				renderer.gammaInput = true;

+ 1 - 1
examples/webgl_buffergeometry.html

@@ -227,7 +227,7 @@
 				//
 
 				renderer = new THREE.WebGLRenderer( { antialias: false } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 300 - 0
examples/webgl_buffergeometry_drawcalls.html

@@ -0,0 +1,300 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - buffergeometry - lines drawcalls</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				color: #cccccc;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+
+				background-color: #000000;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+			}
+
+			a {
+
+				color: #0080ff;
+			}
+
+		</style>
+	</head>
+	<body>
+
+		<div id="container"></div>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> webgl - buffergeometry drawcalls - by <a href="https://twitter.com/fernandojsg">fernandojsg</a>
+		</div>
+
+		<script src="js/libs/dat.gui.min.js"></script>
+		<script src="../build/three.min.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script>
+
+			var group;
+			var container, stats;
+			var particlesData = [];
+			var camera, scene, renderer;
+			var positions,colors;
+			var pointCloud;
+			var particlePositions;
+			var linesMesh;
+
+			var maxParticleCount = 1000;
+			var particleCount = 500;
+			var r = 800;
+			var rHalf = r / 2;
+
+			var effectController = {
+				showDots: true,
+				showLines: true,
+				minDistance: 150,
+				limitConnections: false,
+				maxConnections: 20,
+				particleCount: 500
+			}
+
+			init();
+			animate();
+
+			function initGUI() {
+
+				var gui = new dat.GUI();
+
+				gui.add( effectController, "showDots" ).onChange( function( value ) { pointCloud.visible = value; } );
+				gui.add( effectController, "showLines" ).onChange( function( value ) { linesMesh.visible = value; } );
+				gui.add( effectController, "minDistance", 10, 300 );
+				gui.add( effectController, "limitConnections" );
+				gui.add( effectController, "maxConnections", 0, 30, 1 );
+				gui.add( effectController, "particleCount", 0, maxParticleCount, 1 ).onChange( function( value ) {
+
+					particleCount = parseInt( value );
+					particles.drawcalls[ 0 ].count = particleCount;
+
+				});
+
+			}
+
+			function init() {
+
+				initGUI();
+
+				container = document.getElementById( 'container' );
+
+				//
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 4000 );
+				camera.position.z = 1750;
+
+				controls = new THREE.OrbitControls( camera, container );
+
+				scene = new THREE.Scene();
+
+				geometry = new THREE.BufferGeometry();
+				var material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors });
+
+				var segments = maxParticleCount * maxParticleCount;
+
+				positions = new Float32Array( segments * 3 );
+				colors = new Float32Array( segments * 3 );
+
+				var pMaterial = new THREE.PointCloudMaterial({
+					color: 0xFFFFFF,
+					size: 3,
+					blending: THREE.AdditiveBlending,
+					transparent: true,
+					sizeAttenuation: false
+				});
+
+				particles = new THREE.BufferGeometry();
+				particlePositions = new Float32Array( maxParticleCount * 3 );
+
+				for ( var i = 0; i < maxParticleCount; i++ ) {
+
+					var x = Math.random() * r - r / 2;
+					var y = Math.random() * r - r / 2;
+					var z = Math.random() * r - r / 2;
+
+					particlePositions[ i * 3     ] = x;
+					particlePositions[ i * 3 + 1 ] = y;
+					particlePositions[ i * 3 + 2 ] = z;
+
+					// add it to the geometry
+					particlesData.push({
+						velocity: new THREE.Vector3( -1 + Math.random() * 2, -1 + Math.random() * 2,  -1 + Math.random() * 2 ),
+						numConnections: 0
+					});
+
+				}
+
+				particles.drawcalls.push( {
+					start: 0,
+					count: particleCount,
+					index: 0
+				} );
+
+				particles.addAttribute( 'position', new THREE.BufferAttribute( particlePositions, 3 ) );
+
+				// create the particle system
+				pointCloud = new THREE.PointCloud( particles, pMaterial );
+
+				group = new THREE.Object3D();
+
+				// add it to the scene
+				group.add( pointCloud );
+
+				geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+				geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
+
+				geometry.computeBoundingSphere();
+
+				geometry.drawcalls.push( {
+					start: 0,
+					count: 0,
+					index: 0
+				} );
+
+				linesMesh = new THREE.Line( geometry, material, THREE.LinePieces );
+				group.add( linesMesh );
+
+				scene.add( group );
+
+				//
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio )
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				renderer.gammaInput = true;
+				renderer.gammaOutput = true;
+
+				container.appendChild( renderer.domElement );
+
+				//
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				var vertexpos = 0;
+				var colorpos = 0;
+				var numConnected = 0;
+
+				for ( var i = 0; i < particleCount; i++ )
+					particlesData[ i ].numConnections = 0;
+
+				for ( var i = 0; i < particleCount; i++ ) {
+
+					// get the particle
+					var particleData = particlesData[i];
+
+					particlePositions[ i * 3     ] += particleData.velocity.x;
+					particlePositions[ i * 3 + 1 ] += particleData.velocity.y;
+					particlePositions[ i * 3 + 2 ] += particleData.velocity.z;
+
+					if ( particlePositions[ i * 3 + 1 ] < -rHalf || particlePositions[ i * 3 + 1 ] > rHalf )
+						particleData.velocity.y = -particleData.velocity.y;
+
+					if ( particlePositions[ i * 3 ] < -rHalf || particlePositions[ i * 3 ] > rHalf )
+						particleData.velocity.x = -particleData.velocity.x;
+
+					if ( particlePositions[ i * 3 + 2 ] < -rHalf || particlePositions[ i * 3 + 2 ] > rHalf )
+						particleData.velocity.z = -particleData.velocity.z;
+
+					if ( effectController.limitConnections && particleData.numConnections >= effectController.maxConnections )
+						continue;
+
+					// Check collision
+					for ( var j = i + 1; j < particleCount; j++ ) {
+
+						var particleDataB = particlesData[ j ];
+						if ( effectController.limitConnections && particleDataB.numConnections >= effectController.maxConnections )
+							continue;
+
+						var dx = particlePositions[ i * 3     ] - particlePositions[ j * 3     ];
+						var dy = particlePositions[ i * 3 + 1 ] - particlePositions[ j * 3 + 1 ];
+						var dz = particlePositions[ i * 3 + 2 ] - particlePositions[ j * 3 + 2 ];
+						var dist = Math.sqrt( dx * dx + dy * dy + dz * dz );
+
+						if ( dist < effectController.minDistance ) {
+
+							particleData.numConnections++;
+							particleDataB.numConnections++;
+
+							var alpha = 1.0 - dist / effectController.minDistance + 0.2;
+
+							positions[ vertexpos++ ] = particlePositions[ i * 3     ];
+							positions[ vertexpos++ ] = particlePositions[ i * 3 + 1 ];
+							positions[ vertexpos++ ] = particlePositions[ i * 3 + 2 ];
+
+							positions[ vertexpos++ ] = particlePositions[ j * 3     ];
+							positions[ vertexpos++ ] = particlePositions[ j * 3 + 1 ];
+							positions[ vertexpos++ ] = particlePositions[ j * 3 + 2 ];
+
+							colors[ colorpos++ ] = alpha;
+							colors[ colorpos++ ] = alpha;
+							colors[ colorpos++ ] = alpha;
+
+							colors[ colorpos++ ] = alpha;
+							colors[ colorpos++ ] = alpha;
+							colors[ colorpos++ ] = alpha;
+
+							numConnected++;
+						}
+					}
+				}
+
+
+				linesMesh.geometry.drawcalls[ 0 ].count = numConnected * 2;
+				linesMesh.geometry.attributes.position.needsUpdate = true;
+				linesMesh.geometry.attributes.color.needsUpdate = true;
+
+				pointCloud.geometry.attributes.position.needsUpdate = true;
+
+				requestAnimationFrame( animate );
+
+				stats.update();
+				render();
+
+			}
+
+			function render() {
+
+				var time = Date.now() * 0.001;
+
+				group.rotation.y = time * 0.1;
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>

+ 1 - 1
examples/webgl_buffergeometry_particles.html

@@ -117,7 +117,7 @@
 				//
 
 				renderer = new THREE.WebGLRenderer( { antialias: false } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 1 - 1
examples/webgl_buffergeometry_uint.html

@@ -208,7 +208,7 @@
 				//
 
 				renderer = new THREE.WebGLRenderer( { antialias: false } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 1 - 1
examples/webgl_custom_attributes.html

@@ -150,7 +150,7 @@
 			scene.add( sphere );
 
 			renderer = new THREE.WebGLRenderer();
-			renderer.setClearColor( 0x050505, 1 );
+			renderer.setClearColor( 0x050505 );
 			renderer.setPixelRatio( window.devicePixelRatio );
 			renderer.setSize( WIDTH, HEIGHT );
 

+ 1 - 1
examples/webgl_custom_attributes_lines.html

@@ -186,7 +186,7 @@
 			scene.add( object );
 
 			renderer = new THREE.WebGLRenderer( { antialias: true } );
-			renderer.setClearColor( 0x050505, 1 );
+			renderer.setClearColor( 0x050505 );
 			renderer.setPixelRatio( window.devicePixelRatio );
 			renderer.setSize( WIDTH, HEIGHT );
 

+ 5 - 7
examples/webgl_decals.html

@@ -44,7 +44,6 @@
 			normal: new THREE.Vector3()
 		};
 		var controls;
-		var mouseVector = new THREE.Vector3();
 		var mouse = new THREE.Vector2();
 
 		var decalDiffuse = THREE.ImageUtils.loadTexture( 'textures/decal/decal-diffuse.png' );
@@ -103,9 +102,10 @@
 			camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 );
 			camera.position.z = 100;
 			camera.target = new THREE.Vector3();
-			controls = new THREE.OrbitControls( camera, renderer.domElement );
 
-			scene.add( camera );
+			controls = new THREE.OrbitControls( camera, renderer.domElement );
+			controls.minDistance = 50;
+			controls.maxDistance = 200;
 
 			var light = new THREE.HemisphereLight( 0xffddcc, 0x111122 );
 			light.position.set( 1, 0.75, 0.5 );
@@ -121,8 +121,8 @@
 			raycaster = new THREE.Raycaster();
 
 			mouseHelper = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 10 ), new THREE.MeshNormalMaterial() );
-			scene.add( mouseHelper );
 			mouseHelper.visible = false;
+			scene.add( mouseHelper );
 
 			window.addEventListener( 'resize', onWindowResize, false );
 
@@ -171,9 +171,7 @@
 
 				if( !mesh ) return;
 
-				mouseVector.set( mouse.x, mouse.y, 1 ).unproject( camera );
-
-				raycaster.set( camera.position, mouseVector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( [ mesh ] );
 

+ 1 - 1
examples/webgl_effects_oculusrift.html

@@ -194,7 +194,7 @@
 				scene.add( directionalLight );
 
 				renderer = new THREE.WebGLRenderer();
-				renderer.setClearColor( 0xbfd1e5, 1 );
+				renderer.setClearColor( 0xbfd1e5 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 3 - 3
examples/webgl_effects_vr.html

@@ -204,11 +204,11 @@
 				camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
 				camera.lookAt( scene.position );
 
-				// find intersections
+				camera.updateMatrixWorld();
 
-				var vector = new THREE.Vector3( mouse.x, mouse.y, 1 ).unproject( camera );
+				// find intersections
 
-				raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( scene.children );
 

+ 0 - 3
examples/webgl_geometries2.html

@@ -22,7 +22,6 @@
 
 		<script src="js/CurveExtras.js"></script>
 		<script src="js/ParametricGeometries.js"></script>
-		<script src="js/utils/UVsUtils.js"></script>
 
 		<script>
 
@@ -110,7 +109,6 @@
 				scene.add( object );
 
 				var geo = new THREE.ParametricGeometry( THREE.ParametricGeometries.plane( 200, 200 ), 10, 20 );
-				// document.body.appendChild( THREE.UVsDebug( geo ));
 				object = THREE.SceneUtils.createMultiMaterialObject( geo, materials );
 				object.position.set( 0, 0, 0 );
 				scene.add( object );
@@ -131,7 +129,6 @@
 				//  scene.add( object );
 
 				object = THREE.SceneUtils.createMultiMaterialObject( sphere2, materials );
-				// document.body.appendChild( THREE.UVsDebug( sphere2 ));
 				object.position.set( 200, 0, 0 );
 				scene.add( object );
 

+ 1 - 1
examples/webgl_geometry_colors_lookuptable.html

@@ -105,7 +105,7 @@
 				scene.add( directionalLight );
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setClearColor(0xffffff, 1);
+				renderer.setClearColor( 0xffffff );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize(  window.innerWidth,  window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_geometry_dynamic.html

@@ -112,7 +112,7 @@
 				scene.add( mesh );
 
 				renderer = new THREE.WebGLRenderer();
-				renderer.setClearColor( 0xaaccff, 1 );
+				renderer.setClearColor( 0xaaccff );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 1 - 1
examples/webgl_geometry_minecraft.html

@@ -193,7 +193,7 @@
 				scene.add( directionalLight );
 
 				renderer = new THREE.WebGLRenderer();
-				renderer.setClearColor( 0xbfd1e5, 1 );
+				renderer.setClearColor( 0xbfd1e5 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 

+ 1 - 1
examples/webgl_geometry_shapes.html

@@ -331,7 +331,7 @@
 				//
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setClearColor( 0xf0f0f0, 1 );
+				renderer.setClearColor( 0xf0f0f0 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 6 - 7
examples/webgl_geometry_terrain_raycast.html

@@ -64,6 +64,9 @@
 
 			var helper;
 
+			var raycaster = new THREE.Raycaster();
+			var mouse = new THREE.Vector2();
+
 			init();
 			animate();
 
@@ -248,14 +251,10 @@
 
 			function onMouseMove( event ) {
 
-				var mouseX = ( event.clientX / window.innerWidth ) * 2 - 1;
-				var mouseY = -( event.clientY / window.innerHeight ) * 2 + 1;
-
-				var vector = new THREE.Vector3( mouseX, mouseY, camera.near );
-				// Convert the [-1, 1] screen coordinate into a world coordinate on the near plane
-				vector.unproject( camera );
+				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
 
-				var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				// See if the ray from the camera into the world hits one of our meshes
 				var intersects = raycaster.intersectObject( mesh );

+ 2 - 2
examples/webgl_geometry_text.html

@@ -223,7 +223,7 @@
 
 				}
 
-				material = new THREE.MeshFaceMaterial( [ 
+				material = new THREE.MeshFaceMaterial( [
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ), // front
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
 				] );
@@ -246,7 +246,7 @@
 				// RENDERER
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 3 - 3
examples/webgl_geometry_text2.html

@@ -84,7 +84,7 @@
 				};
 			} )();
 		</script>
-		
+
 
 		<script>
 
@@ -238,7 +238,7 @@
 
 				}
 
-				material = new THREE.MeshFaceMaterial( [ 
+				material = new THREE.MeshFaceMaterial( [
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ), // front
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
 				] );
@@ -261,7 +261,7 @@
 				// RENDERER
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 26 - 27
examples/webgl_gpgpu_birds.html

@@ -207,54 +207,53 @@
 				vec3 central = vec3( 0., 0., 0. );
 				dir = selfPosition - central;
 				dist = length( dir );
+
 				dir.y *= 2.5;
 				velocity -= normalize( dir ) * delta * 5.;
 
 				for (float y=0.0;y<height;y++) {
 					for (float x=0.0;x<width;x++) {
 
-						if (
-							x == gl_FragCoord.x && y == gl_FragCoord.y) continue;
-
-						birdPosition = texture2D( texturePosition,
-							vec2( x / resolution.x,  y / resolution.y ) ).xyz;
+						vec2 ref = vec2( x + 0.5, y + 0.5 ) / resolution.xy;
+						birdPosition = texture2D( texturePosition, ref ).xyz;
 
 						dir = birdPosition - selfPosition;
 						dist = length(dir);
-						distSquared = dist * dist;
 
-						if ( dist > 0.0 && distSquared < zoneRadiusSquared ) {
+						if (dist < 0.0001) continue;
+
+						distSquared = dist * dist;
 
-							percent = distSquared / zoneRadiusSquared;
+						if (distSquared > zoneRadiusSquared ) continue;
 
-							if ( percent < separationThresh ) { // low
+						percent = distSquared / zoneRadiusSquared;
 
-								// Separation - Move apart for comfort
-								f = (separationThresh / percent - 1.0) * delta;
-								velocity -= normalize(dir) * f;
+						if ( percent < separationThresh ) { // low
 
-							} else if ( percent < alignmentThresh ) { // high
+							// Separation - Move apart for comfort
+							f = (separationThresh / percent - 1.0) * delta;
+							velocity -= normalize(dir) * f;
 
-								// Alignment - fly the same direction
-								float threshDelta = alignmentThresh - separationThresh;
-								float adjustedPercent = ( percent - separationThresh ) / threshDelta;
+						} else if ( percent < alignmentThresh ) { // high
 
-								birdVelocity = texture2D( textureVelocity, vec2(x/resolution.x, y/resolution.y) ).xyz;
+							// Alignment - fly the same direction
+							float threshDelta = alignmentThresh - separationThresh;
+							float adjustedPercent = ( percent - separationThresh ) / threshDelta;
 
-								f = ( 0.5 - cos( adjustedPercent * PI_2 ) * 0.5 + 0.5 ) * delta;
-								velocity += normalize(birdVelocity) * f;
+							birdVelocity = texture2D( textureVelocity, ref ).xyz;
 
-							} else {
+							f = ( 0.5 - cos( adjustedPercent * PI_2 ) * 0.5 + 0.5 ) * delta;
+							velocity += normalize(birdVelocity) * f;
 
-								// Attraction / Cohesion - move closer
-								float threshDelta = 1.0 - alignmentThresh;
-								float adjustedPercent = ( percent - alignmentThresh ) / threshDelta;
+						} else {
 
-								 f = ( 0.5 - ( cos( adjustedPercent * PI_2 ) * -0.5 + 0.5 ) ) * delta;
+							// Attraction / Cohesion - move closer
+							float threshDelta = 1.0 - alignmentThresh;
+							float adjustedPercent = ( percent - alignmentThresh ) / threshDelta;
 
-								 velocity += normalize(dir) * f;
+							f = ( 0.5 - ( cos( adjustedPercent * PI_2 ) * -0.5 + 0.5 ) ) * delta;
 
-							}
+							velocity += normalize(dir) * f;
 
 						}
 
@@ -505,7 +504,7 @@
 				scene.fog = new THREE.Fog( 0xffffff, 100, 1000 );
 
 				renderer = new THREE.WebGLRenderer();
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 3 - 5
examples/webgl_interactive_buffergeometry.html

@@ -213,7 +213,7 @@
 				//
 
 				renderer = new THREE.WebGLRenderer( { antialias: false } );
-				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setClearColor( scene.fog.color );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
@@ -268,9 +268,7 @@
 				mesh.rotation.x = time * 0.15;
 				mesh.rotation.y = time * 0.25;
 
-				var vector = new THREE.Vector3( mouse.x, mouse.y, 1 ).unproject( camera );
-
-				raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObject( mesh );
 
@@ -288,7 +286,7 @@
 					linePosition.copyAt( 3, meshPosition, face.a );
 
 					mesh.updateMatrix();
-					
+
 					line.geometry.applyMatrix( mesh.matrix );
 
 					line.visible = true;

+ 3 - 3
examples/webgl_interactive_cubes.html

@@ -133,11 +133,11 @@
 				camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
 				camera.lookAt( scene.position );
 
-				// find intersections
+				camera.updateMatrixWorld();
 
-				var vector = new THREE.Vector3( mouse.x, mouse.y, 1 ).unproject( camera );
+				// find intersections
 
-				raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( scene.children );
 

+ 1 - 1
examples/webgl_interactive_cubes_gpu.html

@@ -164,7 +164,7 @@
 				scene.add( highlightBox );
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setClearColor( 0xffffff, 1 );
+				renderer.setClearColor( 0xffffff );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.sortObjects = false;

+ 3 - 4
examples/webgl_interactive_cubes_ortho.html

@@ -137,12 +137,11 @@
 				camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
 				camera.lookAt( scene.position );
 
-				// find intersections
+				camera.updateMatrixWorld();
 
-				var vector = new THREE.Vector3( mouse.x, mouse.y, - 1 ).unproject( camera );
-				var direction = new THREE.Vector3( 0, 0, -1 ).transformDirection( camera.matrixWorld );
+				// find intersections
 
-				raycaster.set( vector, direction );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( scene.children );
 

+ 2 - 3
examples/webgl_interactive_draggablecubes.html

@@ -27,6 +27,7 @@
 			var camera, controls, scene, renderer;
 			var objects = [], plane;
 
+			var raycaster = new THREE.Raycaster();
 			var mouse = new THREE.Vector2(),
 			offset = new THREE.Vector3(),
 			INTERSECTED, SELECTED;
@@ -159,9 +160,7 @@
 
 				//
 
-				var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 ).unproject( camera );
-
-				var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				if ( SELECTED ) {
 

+ 13 - 13
examples/webgl_interactive_lines.html

@@ -42,7 +42,7 @@
 				info.style.top = '10px';
 				info.style.width = '100%';
 				info.style.textAlign = 'center';
-				info.innerHTML = '<a href="http://threejs.org" target="_blank">three.js</a> canvas - interactive lines';
+				info.innerHTML = '<a href="http://threejs.org" target="_blank">three.js</a> webgl - interactive lines';
 				container.appendChild( info );
 
 				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
@@ -52,21 +52,21 @@
 				var geometry = new THREE.SphereGeometry( 5 );
 				var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
 
-				sphereInter = new THREE.Mesh( geometry, material );
-				sphereInter.visible = false;
-				scene.add( sphereInter );
+				//sphereInter = new THREE.Mesh( geometry, material );
+				//sphereInter.visible = false;
+				//scene.add( sphereInter );
 
 				var geometry = new THREE.Geometry();
 
 				var point = new THREE.Vector3();
 				var direction = new THREE.Vector3();
 
-				for ( var i = 0; i < 100; i ++ ) {
+				for ( var i = 0; i < 50; i ++ ) {
 
 					direction.x += Math.random() - 0.5;
 					direction.y += Math.random() - 0.5;
 					direction.z += Math.random() - 0.5;
-					direction.normalize().multiplyScalar( 5 );
+					direction.normalize().multiplyScalar( 10 );
 
 					point.add( direction );
 
@@ -111,7 +111,7 @@
 				scene.add( parentTransform );
 
 				raycaster = new THREE.Raycaster();
-				raycaster.linePrecision = 3;
+				raycaster.linePrecision = 1;
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setClearColor( 0xf0f0f0 );
@@ -170,11 +170,11 @@
 				camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
 				camera.lookAt( scene.position );
 
-				// find intersections
+				camera.updateMatrixWorld();
 
-				var vector = new THREE.Vector3( mouse.x, mouse.y, 1 ).unproject( camera );
+				// find intersections
 
-				raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( parentTransform.children, true);
 
@@ -189,8 +189,8 @@
 					currentIntersected = intersects[ 0 ].object;
 					currentIntersected.material.linewidth = 5;
 
-					sphereInter.visible = true;
-					sphereInter.position.copy( intersects[ 0 ].point );
+					//sphereInter.visible = true;
+					//sphereInter.position.copy( intersects[ 0 ].point );
 
 				} else {
 
@@ -202,7 +202,7 @@
 
 					currentIntersected = undefined;
 
-					sphereInter.visible = false;
+					//sphereInter.visible = false;
 
 				}
 

+ 4 - 6
examples/webgl_interactive_particles.html

@@ -88,8 +88,7 @@
 			var PARTICLE_SIZE = 20;
 
 			var raycaster, intersects;
-			var mouse = { x: 1, y: 1 }, INTERSECTED;
-			var vector = new THREE.Vector3();
+			var mouse, INTERSECTED;
 
 			init();
 			animate();
@@ -159,6 +158,7 @@
 				//
 
 				raycaster = new THREE.Raycaster();
+				mouse = new THREE.Vector2()
 
 				//
 
@@ -201,14 +201,12 @@
 
 			}
 
-			function render() { ref: http://dl.dropboxusercontent.com/u/4253186/three/examples/webgl_interactive_particles.html
+			function render() {
 
 				particles.rotation.x += 0.0005;
 				particles.rotation.y += 0.001;
 
-				vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 ).unproject( camera );
-
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				intersects = raycaster.intersectObject( particles );
 

+ 3 - 6
examples/webgl_interactive_raycasting_pointcloud.html

@@ -43,8 +43,7 @@
 			var renderer, scene, camera, stats;
 			var pointclouds;
 			var raycaster, intersects;
-			var mouse = { x: 1, y: 1 };
-			var vector = new THREE.Vector3();
+			var mouse = new THREE.Vector2();
 			var intersection = null;
 			var spheres = [];
 			var spheresIndex = 0;
@@ -323,11 +322,9 @@
 			function render() {
 
 				camera.applyMatrix( rotateY );
-				camera.updateMatrixWorld( true );
+				camera.updateMatrixWorld();
 
-				vector.set( mouse.x, mouse.y, 0.1 ).unproject( camera );
-
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersections = raycaster.intersectObjects( pointclouds );
 				intersection = ( intersections.length ) > 0 ? intersections[ 0 ] : null;

+ 6 - 8
examples/webgl_interactive_voxelpainter.html

@@ -28,7 +28,7 @@
 			var container;
 			var camera, scene, renderer;
 			var plane, cube;
-			var vector, raycaster, isShiftDown = false;
+			var mouse, raycaster, isShiftDown = false;
 
 			var rollOverMesh, rollOverMaterial;
 			var cubeGeo, cubeMaterial;
@@ -93,8 +93,8 @@
 
 				//
 
-				vector = new THREE.Vector3();
 				raycaster = new THREE.Raycaster();
+				mouse = new THREE.Vector2();
 
 				var geometry = new THREE.PlaneBufferGeometry( 1000, 1000 );
 				geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
@@ -144,10 +144,9 @@
 
 				event.preventDefault();
 
-				vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
-				vector.unproject( camera );
+				mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );
 
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( objects );
 
@@ -168,10 +167,9 @@
 
 				event.preventDefault();
 
-				vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
-				vector.unproject( camera );
+				mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );
 
-				raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
+				raycaster.setFromCamera( mouse, camera );
 
 				var intersects = raycaster.intersectObjects( objects );
 

部分文件因为文件数量过多而无法显示