Mr.doob 9 years ago
parent
commit
f335400287
72 changed files with 8336 additions and 5678 deletions
  1. 4835 4797
      build/three.js
  2. 346 176
      build/three.min.js
  3. 57 46
      docs/api/constants/Materials.html
  4. 1 1
      docs/api/core/BufferAttribute.html
  5. 1 1
      docs/api/core/BufferGeometry.html
  6. 1 1
      docs/api/core/Raycaster.html
  7. 1 1
      docs/api/extras/geometries/ConeGeometry.html
  8. 5 0
      docs/api/materials/Material.html
  9. 7 7
      docs/api/materials/PointsMaterial.html
  10. 1 1
      docs/api/math/Color.html
  11. 1 1
      docs/api/math/Frustum.html
  12. 1 1
      docs/api/math/Line3.html
  13. 1 1
      docs/api/math/Matrix4.html
  14. 1 1
      docs/api/math/Plane.html
  15. 1 1
      docs/api/math/Quaternion.html
  16. 12 4
      docs/api/math/Ray.html
  17. 1 1
      docs/api/math/Sphere.html
  18. 1 1
      docs/api/math/Vector2.html
  19. 1 1
      docs/api/math/Vector3.html
  20. 2 2
      docs/api/objects/Points.html
  21. 1 1
      docs/manual/introduction/Creating-a-scene.html
  22. 3 0
      editor/index.html
  23. 9 3
      editor/js/Editor.js
  24. 2 0
      editor/js/Sidebar.Material.js
  25. 31 30
      editor/js/Sidebar.Scene.js
  26. 30 56
      editor/js/Viewport.js
  27. 7 2
      editor/js/libs/ui.three.js
  28. 2 2
      examples/canvas_geometry_panorama.html
  29. 2 22
      examples/canvas_geometry_panorama_fisheye.html
  30. 2 2
      examples/css3d_panorama.html
  31. 3 0
      examples/files.js
  32. 22 22
      examples/js/Cloth.js
  33. 489 0
      examples/js/ConvexObjectBreaker.js
  34. 4 1
      examples/js/ViveController.js
  35. 4 22
      examples/js/controls/EditorControls.js
  36. 4 22
      examples/js/controls/OrbitControls.js
  37. 4 23
      examples/js/controls/OrthographicTrackballControls.js
  38. 3 20
      examples/js/controls/TrackballControls.js
  39. 1 1
      examples/js/controls/TransformControls.js
  40. 6 0
      examples/js/effects/StereoEffect.js
  41. 16 15
      examples/js/effects/VREffect.js
  42. 79 41
      examples/js/loaders/MMDLoader.js
  43. 27 32
      examples/js/loaders/MTLLoader.js
  44. 2 2
      examples/js/loaders/OBJLoader.js
  45. 3 3
      examples/js/loaders/STLLoader.js
  46. 0 1
      examples/js/nodes/materials/PhongNode.js
  47. 503 0
      examples/js/postprocessing/OutlinePass.js
  48. 332 0
      examples/js/postprocessing/UnrealBloomPass.js
  49. 64 0
      examples/js/shaders/LuminosityHighPassShader.js
  50. BIN
      examples/textures/tri_pattern.jpg
  51. 1 1
      examples/webgl_animation_cloth.html
  52. 4 5
      examples/webgl_camera_logarithmicdepthbuffer.html
  53. 10 10
      examples/webgl_lights_physical.html
  54. 3 3
      examples/webgl_lights_spotlights.html
  55. 3 21
      examples/webgl_materials_cubemap_dynamic2.html
  56. 15 16
      examples/webgl_materials_transparency.html
  57. 17 24
      examples/webgl_materials_variations_basic.html
  58. 16 30
      examples/webgl_materials_variations_lambert.html
  59. 22 30
      examples/webgl_materials_variations_phong.html
  60. 12 21
      examples/webgl_materials_variations_physical.html
  61. 21 30
      examples/webgl_materials_variations_standard.html
  62. 0 32
      examples/webgl_multiple_canvases_circle.html
  63. 1 1
      examples/webgl_multiple_elements.html
  64. 2 21
      examples/webgl_panorama_dualfisheye.html
  65. 2 22
      examples/webgl_panorama_equirectangular.html
  66. 561 0
      examples/webgl_physics_convex_break.html
  67. 2 2
      examples/webgl_postprocessing_backgrounds.html
  68. 415 0
      examples/webgl_postprocessing_outline.html
  69. 275 0
      examples/webgl_postprocessing_unreal_bloom.html
  70. 19 19
      examples/webgl_tonemapping.html
  71. 2 21
      examples/webgl_video_panorama_equirectangular.html
  72. 1 1
      index.html

File diff suppressed because it is too large
+ 4835 - 4797
build/three.js


File diff suppressed because it is too large
+ 346 - 176
build/three.min.js


+ 57 - 46
docs/api/constants/Materials.html

@@ -1,47 +1,58 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
+<!DOCTYPE html>
+<html lang="en">
+	<head>
 		<meta charset="utf-8" />
-		<base href="../../" />
-		<script src="list.js"></script>
-		<script src="page.js"></script>
-		<link type="text/css" rel="stylesheet" href="page.css" />
-	</head>
-	<body>
-		<h1>Material Constants</h1>
-
-		<h2>Side</h2>
-		<div>
-		THREE.FrontSide<br />
-		THREE.BackSide<br />
-		THREE.DoubleSide
-		</div>
-
-		<h2>Shading</h2>
-		<div>
-		THREE.FlatShading<br />
-		THREE.SmoothShading
-		</div>
-
-		<h2>Colors</h2>
-		<div>
-		THREE.NoColors<br />
-		THREE.FaceColors<br />
-		THREE.VertexColors
-		</div>
-
-		<h2>Blending Mode</h2>
-		<div>
-		THREE.NoBlending<br />
-		THREE.NormalBlending<br />
-		THREE.AdditiveBlending<br />
-		THREE.SubtractiveBlending<br />
-		THREE.MultiplyBlending<br />
-		THREE.CustomBlending
-		</div>
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]
-	</body>
-</html>
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>Material Constants</h1>
+
+		<h2>Side</h2>
+		<div>
+		THREE.FrontSide<br />
+		THREE.BackSide<br />
+		THREE.DoubleSide
+		</div>
+
+		<h2>Shading</h2>
+		<div>
+		THREE.FlatShading<br />
+		THREE.SmoothShading
+		</div>
+
+		<h2>Colors</h2>
+		<div>
+		THREE.NoColors<br />
+		THREE.FaceColors<br />
+		THREE.VertexColors
+		</div>
+
+		<h2>Blending Mode</h2>
+		<div>
+		THREE.NoBlending<br />
+		THREE.NormalBlending<br />
+		THREE.AdditiveBlending<br />
+		THREE.SubtractiveBlending<br />
+		THREE.MultiplyBlending<br />
+		THREE.CustomBlending
+		</div>
+
+		<h2>Depth Mode</h2>
+		<div>
+		THREE.NeverDepth<br />
+		THREE.AlwaysDepth<br />
+		THREE.LessDepth<br />
+		THREE.LessEqualDepth<br />
+		THREE.GreaterEqualDepth<br />
+		THREE.GreaterDepth<br />
+		THREE.NotEqualDepth
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]
+	</body>
+</html>

+ 1 - 1
docs/api/core/BufferAttribute.html

@@ -34,7 +34,7 @@
 		attribute is storing a 3-component vector (such as a position, normal, or color), then itemSize should be 3.
 		</div>
 
-		<h3>[property:Integer length]</h3>
+		<h3>[property:Integer count]</h3>
 		<div>
 		Gives the total number of elements in the array.
 		</div>

+ 1 - 1
docs/api/core/BufferGeometry.html

@@ -247,7 +247,7 @@
 		You need to call this when you want the bufferGeometry removed while the application is running.
 		</div>
 
-		<h3>[method:null fromGeometry]( [page:Geometry] )</h3>
+		<h3>[method:BufferGeometry fromGeometry]( [page:Geometry] )</h3>
 		<div>
 		Populates this BufferGeometry with data from a [page:Geometry] object.
 		</div>

+ 1 - 1
docs/api/core/Raycaster.html

@@ -144,7 +144,7 @@
         [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
+        [page:Object3D object] – the intersected object<br />
         [page:Vector2 uv] - U,V coordinates at point of intersection
     	</p>
         <p>

+ 1 - 1
docs/api/extras/geometries/ConeGeometry.html

@@ -42,7 +42,7 @@
 
 		<h2>Constructor</h2>
 
-		<h3>[name]([page:Float radius], [page:Float height], [page:Integer radiusSegments], [page:Integer heightSegments], [page:Boolean openEnded], [page:Float thetaStart], [page:Float thetaLength])</h3>
+		<h3>[name]([page:Float radius], [page:Float height], [page:Integer radialSegments], [page:Integer heightSegments], [page:Boolean openEnded], [page:Float thetaStart], [page:Float thetaLength])</h3>
 		<div>
 		radius — Radius of the cone at the base. Default is 20.<br />
 		height — Height of the cone. Default is 100.<br />

+ 5 - 0
docs/api/materials/Material.html

@@ -80,6 +80,11 @@
 		Whether to have depth test enabled when rendering this material. Default is *true*.
 		</div>
 
+		<h3>[property:Integer depthFunc]</h3>
+		<div>
+		What depth function to use. Default is [page:Materials THREE.LessEqualDepth].
+		</div>
+
 		<h3>[property:Boolean depthWrite]</h3>
 		<div>
 		Whether rendering this material has any effect on the depth buffer. Default is *true*.

+ 7 - 7
docs/api/materials/PointsMaterial.html

@@ -12,7 +12,7 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">The default material used by [page:Points particle] systems.</div>
+		<div class="desc">The default material used by [page:Points].</div>
 
 
 		<h2>Constructor</h2>
@@ -22,9 +22,9 @@
 		<div>parameters is an object with one or more properties defining the material's appearance.</div>
 
 		<div>
-		color — Particle color in hexadecimal. Default is 0xffffff.<br />
+		color — Points color in hexadecimal. Default is 0xffffff.<br />
 		map — a [page:Texture texture].If defined, then a point has the data from texture as colors. Default is null.<br />
-		size — Define size of particles. Default is 1.0.<br />
+		size — Define size of points. Default is 1.0.<br />
 		sizeAttenuation — Enable/disable size attenuation with distance.<br />
 		vertexColors — Define whether the material uses vertex colors, or not. Default is false.<br />
 		fog — Define whether the material color is affected by global fog settings. Default is true.
@@ -35,19 +35,19 @@
 
 		<h3>[property:Number color]</h3>
 
-		<div>Sets the color of the particles. Default is 0xffffff.</div>
+		<div>Sets the color of the points. Default is 0xffffff.</div>
 
 		<h3>[property:Texture map]</h3>
 
-		<div>Sets the color of the particles using data from a texture.</div>
+		<div>Sets the color of the points using data from a texture.</div>
 
 		<h3>[property:Number size]</h3>
 
-		<div>Sets the size of the particles. Default is 1.0.</div>
+		<div>Sets the size of the points. Default is 1.0.</div>
 
 		<h3>[property:Boolean sizeAttenuation]</h3>
 
-		<div>Specify whether particles' size will get smaller with the distance. Default is true.</div>
+		<div>Specify whether points' size will get smaller with the distance. Default is true.</div>
 
 		<h3>[property:Boolean vertexColors]</h3>
 		<div>Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.</div>

+ 1 - 1
docs/api/math/Color.html

@@ -223,7 +223,7 @@
 		Linear interpolation of this colors rgb values and the rgb values of the first argument. The alpha argument can be thought of as the percent between the two colors, where 0 is this color and 1 is the first argument.
 		</div>
 
-		<h3>[method:Color equals]( [page:Color c] ) [page:Color this]</h3>
+		<h3>[method:Boolean equals]( [page:Color c] ) [page:Color this]</h3>
 		<div>
 		Compares this color and c and returns true if they are the same, false otherwise.
 		</div>

+ 1 - 1
docs/api/math/Frustum.html

@@ -52,7 +52,7 @@
 		Return a copy of this Frustum
 		</div>
 
-		<h3>[method:Boolean set]( [page:Plane p0], [page:Plane p1], [page:Plane p2], [page:Plane p3], [page:Plane p4], [page:Plane p5] )</h3>
+		<h3>[method:Frustum set]( [page:Plane p0], [page:Plane p1], [page:Plane p2], [page:Plane p3], [page:Plane p4], [page:Plane p5] )</h3>
 		<div>
 		p0 -- [page:Plane] <br />
 		p1 -- [page:Plane] <br />

+ 1 - 1
docs/api/math/Line3.html

@@ -86,7 +86,7 @@
 		Apply a matrix transform to the line segment.
 		</div>
 
-		<h3>[method:Vector at]( [page:Float t], [page:Vector3 optionalTarget] )</h3>
+		<h3>[method:Vector3 at]( [page:Float t], [page:Vector3 optionalTarget] )</h3>
 		<div>
 		t -- [page:Float] Use values 0-1 to return a result on the line segment. <br />
 		optionalTarget -- [page:Vector] Optional target to set the result.

+ 1 - 1
docs/api/math/Matrix4.html

@@ -172,7 +172,7 @@
 		Sets this matrix to the transformation composed of *translation*, *quaternion* and *scale*.
 		</div>
 
-		<h3>[method:Array decompose]( [page:Vector3 translation], [page:Quaternion quaternion], [page:Vector3 scale] ) [page:Matrix4 this]</h3>
+		<h3>[method:null decompose]( [page:Vector3 translation], [page:Quaternion quaternion], [page:Vector3 scale] ) [page:Matrix4 this]</h3>
 		<div>
 		Decomposes this matrix into the *translation*, *quaternion* and *scale* components.
 		</div>

+ 1 - 1
docs/api/math/Plane.html

@@ -95,7 +95,7 @@
 		Returns the intersection point of the passed line and the plane. Returns undefined if the line does not intersect. Returns the line's starting point if the line is coplanar with the plane.
 		</div>
 
-		<h3>[method:Vector3 setFromNormalAndCoplanarPoint]( [page:Vector3 normal], [page:Vector3 point] ) [page:Vector3 this]</h3>
+		<h3>[method:Plane setFromNormalAndCoplanarPoint]( [page:Vector3 normal], [page:Vector3 point] ) [page:Vector3 this]</h3>
 		<div>
 		normal -- [page:Vector3] <br />
 		point -- [page:Vector3]

+ 1 - 1
docs/api/math/Quaternion.html

@@ -202,7 +202,7 @@
 		THREE.Quaternion.slerp( startQuaternion, endQuaternion, mesh.quaternion, t );
 		</code>
 
-		<h3>[method:Quaternion slerpFlat]( [page:Array dst], [page:Integer dstOffset], [page:Array src0], [page:Integer srcOffset0], [page:Array src1], [page:Integer srcOffset1], [page:Float t] )</h3>
+		<h3>[method:null slerpFlat]( [page:Array dst], [page:Integer dstOffset], [page:Array src0], [page:Integer srcOffset0], [page:Array src1], [page:Integer srcOffset1], [page:Float t] )</h3>
 		<div>
 		dst -- The output array.<br />
 		dstOffset -- An offset into the output array.<br />

+ 12 - 4
docs/api/math/Ray.html

@@ -121,7 +121,7 @@
 		Return whether this and the other [page:Ray] have equal offsets and directions.
 		</div>
 
-		<h3>[method:Vector3 intersectBox]( [page:Box3 box], [page:Vector3 optionalTarget] = null ) [page:Vector3]?</h3>
+		<h3>[method:Vector3 intersectBox]( [page:Box3 box], [page:Vector3 optionalTarget] = null ) [page:Vector3]</h3>
 		<div>
 		box  -- [page:Box3] The [page:Box3] to intersect with.<br />
 		optionalTarget -- [page:Vector3] The [page:Vector3] to store the result in, or *null* to create a new [page:Vector3].
@@ -130,7 +130,7 @@
 		Intersect this [page:Ray] with a [page:Box3], returning the intersection point or *null* if there is no intersection.
 		</div>
 
-		<h3>[method:Vector3 intersectPlane]( [page:Plane plane], [page:Vector3 optionalTarget] = null ) [page:Vector3]?</h3>
+		<h3>[method:Vector3 intersectPlane]( [page:Plane plane], [page:Vector3 optionalTarget] = null ) [page:Vector3]</h3>
 		<div>
 		plane -- [page:Plane] The [page:Plane] to intersect with.<br />
 		optionalTarget -- [page:Vector3] The [page:Vector3] to store the result in, or *null* to create a new [page:Vector3].
@@ -138,9 +138,17 @@
 		<div>
 		Intersect this [page:Ray] with a [page:Plane], returning the intersection point or *null* if there is no intersection.
 		</div>
-		function ( a, b, c, backfaceCulling, optionalTarget )
 
-		<h3>[method:Vector3 intersectTriangle]( [page:Vector3 a], [page:Vector3 b], [page:Vector3 c], [page:Boolean backfaceCulling], [page:Vector3 optionalTarget] = null ) [page:Vector3]?</h3>
+		<h3>[method:Vector3 intersectSphere]( [page:Sphere sphere], [page:Vector3 optionalTarget] = null ) [page:Vector3]</h3>
+		<div>
+		sphere -- [page:Sphere] The [page:Sphere] to intersect with.<br />
+		optionalTarget -- [page:Vector3] The [page:Vector3] to store the result in, or *null* to create a new [page:Vector3].
+		</div>
+		<div>
+		Intersect this [page:Ray] with a [page:Sphere], returning the intersection point or *null* if there is no intersection.
+		</div>
+
+		<h3>[method:Vector3 intersectTriangle]( [page:Vector3 a], [page:Vector3 b], [page:Vector3 c], [page:Boolean backfaceCulling], [page:Vector3 optionalTarget] = null ) [page:Vector3]</h3>
 		<div>
 		a, b, c -- [page:Vector3] The [page:Vector3] points on the triangle.<br />
 		backfaceCulling -- [page:Boolean] Whether to use backface culling.<br />

+ 1 - 1
docs/api/math/Sphere.html

@@ -99,7 +99,7 @@
 		Returns the closest distance from the boundary of the sphere to the point. If the sphere contains the point, the distance will be negative.
 		</div>
 
-		<h3>[method:Box getBoundingBox]( [page:Box optionalTarget] )</h3>
+		<h3>[method:Box3 getBoundingBox]( [page:Box optionalTarget] )</h3>
 		<div>
 		optionalTarget -- [page:Box]
 		</div>

+ 1 - 1
docs/api/math/Vector2.html

@@ -239,7 +239,7 @@
 		Sets this vector to be the vector linearly interpolated between *v1* and *v2* with *alpha* factor.
 		</div>
 
-		<h3>[method:undefined setComponent]( [page:Integer index], [page:Float value] ) [page:Vector2 this]</h3>
+		<h3>[method:null setComponent]( [page:Integer index], [page:Float value] ) [page:Vector2 this]</h3>
 		<div>
 		index -- 0 or 1 <br />
 		value -- [page:Float]

+ 1 - 1
docs/api/math/Vector3.html

@@ -303,7 +303,7 @@
 		If this vector's x, y, or z value is less than vector v's x, y, or z value, that value is replaced by the corresponding vector v value.
 		</div>
 
-		<h3>[method:Vector3 setComponent]( [page:Integer index], [page:Float value] ) [page:Vector3 this]</h3>
+		<h3>[method:null setComponent]( [page:Integer index], [page:Float value] ) [page:Vector3 this]</h3>
 		<div>
 		index -- 0, 1, or 2 <br />
 		value -- [page:Float]

+ 2 - 2
docs/api/objects/Points.html

@@ -12,7 +12,7 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">A class for displaying particles in the form of variable size points. For example, if using the [page:WebGLRenderer], the particles are displayed using GL_POINTS.</div>
+		<div class="desc">A class for displaying points. For example, if using the [page:WebGLRenderer], the points are displayed using GL_POINTS.</div>
 
 
 		<h2>Constructor</h2>
@@ -29,7 +29,7 @@
 
 		<h3>[property:Geometry geometry]</h3>
 
-		<div>An instance of [page:Geometry], where each vertex designates the position of a particle in the system.</div>
+		<div>An instance of [page:Geometry], where each vertex designates the position the points.</div>
 
 		<h3>[property:Material material]</h3>
 

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

@@ -61,7 +61,7 @@
 
 		<div>In addition to creating the renderer instance, we also need to set the size at which we want it to render our app. It's a good idea to use the width and height of the area we want to fill with our app - in this case, the width and height of the browser window. For performance intensive apps, you can also give <strong>setSize</strong> smaller values, like <strong>window.innerWidth/2</strong> and <strong>window.innerHeight/2</strong>, which will make the app render at half size.</div>
 
-		<div>If you wish to keep the size of your app but render it at a lower resolution, you can do so by calling <strong>setSize</strong> with false as <strong>updateStyle</strong>. For example, <strong>setSize(window.innerWidth/2, window.innerHeight/2, false)</strong> will render your app at half resolution, given that your &lt;canvas&gt; has 100% width and height.</div>
+		<div>If you wish to keep the size of your app but render it at a lower resolution, you can do so by calling <strong>setSize</strong> with false as <strong>updateStyle</strong> (the third arugment). For example, <strong>setSize(window.innerWidth/2, window.innerHeight/2, false)</strong> will render your app at half resolution, given that your &lt;canvas&gt; has 100% width and height.</div>
 
 		<div>Last but not least, we add the <strong>renderer</strong> element to our HTML document. This is a &lt;canvas&gt; element the renderer uses to display the scene to us.</div>
 

+ 3 - 0
editor/index.html

@@ -143,6 +143,7 @@
 		<script src="js/Toolbar.js"></script>
 		<script src="js/Viewport.js"></script>
 		<script src="js/Viewport.Info.js"></script>
+
 		<script src="js/Command.js"></script>
 		<script src="js/commands/AddObjectCommand.js"></script>
 		<script src="js/commands/RemoveObjectCommand.js"></script>
@@ -267,6 +268,8 @@
 				signals.objectChanged.add( saveState );
 				signals.objectRemoved.add( saveState );
 				signals.materialChanged.add( saveState );
+				signals.sceneBackgroundChanged.add( saveState );
+				signals.sceneFogChanged.add( saveState );
 				signals.sceneGraphChanged.add( saveState );
 				signals.scriptChanged.add( saveState );
 				signals.historyChanged.add( saveState );

+ 9 - 3
editor/js/Editor.js

@@ -47,6 +47,8 @@ var Editor = function () {
 		spaceChanged: new Signal(),
 		rendererChanged: new Signal(),
 
+		sceneBackgroundChanged: new Signal(),
+		sceneFogChanged: new Signal(),
 		sceneGraphChanged: new Signal(),
 
 		cameraChanged: new Signal(),
@@ -69,9 +71,6 @@ var Editor = function () {
 		scriptChanged: new Signal(),
 		scriptRemoved: new Signal(),
 
-		fogTypeChanged: new Signal(),
-		fogColorChanged: new Signal(),
-		fogParametersChanged: new Signal(),
 		windowResize: new Signal(),
 
 		showGridChanged: new Signal(),
@@ -90,6 +89,7 @@ var Editor = function () {
 
 	this.scene = new THREE.Scene();
 	this.scene.name = 'Scene';
+	this.scene.background = new THREE.Color( 0xaaaaaa );
 
 	this.sceneHelpers = new THREE.Scene();
 
@@ -120,6 +120,10 @@ Editor.prototype = {
 
 		this.scene.uuid = scene.uuid;
 		this.scene.name = scene.name;
+
+		if ( scene.background !== null ) this.scene.background = scene.background.clone();
+		if ( scene.fog !== null ) this.scene.fog = scene.fog.clone();
+
 		this.scene.userData = JSON.parse( JSON.stringify( scene.userData ) );
 
 		// avoid render per object
@@ -418,6 +422,8 @@ Editor.prototype = {
 		this.storage.clear();
 
 		this.camera.copy( this.DEFAULT_CAMERA );
+		this.scene.background.setHex( 0xaaaaaa );
+		this.scene.fog = null;
 
 		var objects = this.scene.children;
 

+ 2 - 0
editor/js/Sidebar.Material.js

@@ -893,6 +893,8 @@ Sidebar.Material = function ( editor ) {
 
 			}
 
+			refreshUI();
+
 		}
 
 		if ( textureWarning ) {

+ 31 - 30
editor/js/Sidebar.Scene.js

@@ -76,34 +76,34 @@ Sidebar.Scene = function ( editor ) {
 	container.add( outliner );
 	container.add( new UI.Break() );
 
-	/*
 	// background
 
-	var backgroundRow = new UI.Row();
-	var background = new UI.Select().setOptions( {
+	function onBackgroundChanged() {
 
-		'None': 'None',
-		'Color': 'Color',
-		'Texture': 'Texture'
+		signals.sceneBackgroundChanged.dispatch( backgroundColor.getHexValue() );
 
-	} ).setWidth( '150px' );
-	background.onChange( function () {} );
+	}
+
+	var backgroundRow = new UI.Row();
+
+	var backgroundColor = new UI.Color().setValue( '#aaaaaa' ).onChange( onBackgroundChanged );
 
 	backgroundRow.add( new UI.Text( 'Background' ).setWidth( '90px' ) );
-	backgroundRow.add( background );
+	backgroundRow.add( backgroundColor );
 
 	container.add( backgroundRow );
-	*/
 
 	// fog
 
-	function updateFogParameters() {
-
-		var near = fogNear.getValue();
-		var far = fogFar.getValue();
-		var density = fogDensity.getValue();
+	function onFogChanged() {
 
-		signals.fogParametersChanged.dispatch( near, far, density );
+		signals.sceneFogChanged.dispatch(
+			fogType.getValue(),
+			fogColor.getHexValue(),
+			fogNear.getValue(),
+			fogFar.getValue(),
+			fogDensity.getValue()
+		);
 
 	}
 
@@ -117,10 +117,7 @@ Sidebar.Scene = function ( editor ) {
 	} ).setWidth( '150px' );
 	fogType.onChange( function () {
 
-		var type = fogType.getValue();
-
-		signals.fogTypeChanged.dispatch( type );
-
+		onFogChanged();
 		refreshFogUI();
 
 	} );
@@ -138,31 +135,27 @@ Sidebar.Scene = function ( editor ) {
 	container.add( fogPropertiesRow );
 
 	var fogColor = new UI.Color().setValue( '#aaaaaa' );
-	fogColor.onChange( function () {
-
-		signals.fogColorChanged.dispatch( fogColor.getHexValue() );
-
-	} );
+	fogColor.onChange( onFogChanged );
 	fogPropertiesRow.add( fogColor );
 
 	// fog near
 
-	var fogNear = new UI.Number( 0.1 ).setWidth( '40px' ).setRange( 0, Infinity ).onChange( updateFogParameters );
+	var fogNear = new UI.Number( 0.1 ).setWidth( '40px' ).setRange( 0, Infinity ).onChange( onFogChanged );
 	fogPropertiesRow.add( fogNear );
 
 	// fog far
 
-	var fogFar = new UI.Number( 100 ).setWidth( '40px' ).setRange( 0, Infinity ).onChange( updateFogParameters );
+	var fogFar = new UI.Number( 50 ).setWidth( '40px' ).setRange( 0, Infinity ).onChange( onFogChanged );
 	fogPropertiesRow.add( fogFar );
 
 	// fog density
 
-	var fogDensity = new UI.Number( 0.00025 ).setWidth( '40px' ).setRange( 0, 0.1 ).setPrecision( 5 ).onChange( updateFogParameters );
+	var fogDensity = new UI.Number( 0.05 ).setWidth( '40px' ).setRange( 0, 0.1 ).setPrecision( 3 ).onChange( onFogChanged );
 	fogPropertiesRow.add( fogDensity );
 
 	//
 
-	var refreshUI = function () {
+	function refreshUI() {
 
 		var camera = editor.camera;
 		var scene = editor.scene;
@@ -196,6 +189,12 @@ Sidebar.Scene = function ( editor ) {
 
 		}
 
+		if ( scene.background ) {
+
+			backgroundColor.setHexValue( scene.background.getHex() );
+
+		}
+
 		if ( scene.fog ) {
 
 			fogColor.setHexValue( scene.fog.color.getHex() );
@@ -221,7 +220,7 @@ Sidebar.Scene = function ( editor ) {
 
 		refreshFogUI();
 
-	};
+	}
 
 	function refreshFogUI() {
 
@@ -238,6 +237,8 @@ Sidebar.Scene = function ( editor ) {
 
 	// events
 
+	signals.editorCleared.add( refreshUI );
+
 	signals.sceneGraphChanged.add( refreshUI );
 
 	signals.objectChanged.add( function ( object ) {

+ 30 - 56
editor/js/Viewport.js

@@ -134,14 +134,6 @@ var Viewport = function ( editor ) {
 
 	sceneHelpers.add( transformControls );
 
-	// fog
-
-	var oldFogType = "None";
-	var oldFogColor = 0xaaaaaa;
-	var oldFogNear = 1;
-	var oldFogFar = 5000;
-	var oldFogDensity = 0.00025;
-
 	// object picking
 
 	var raycaster = new THREE.Raycaster();
@@ -297,8 +289,6 @@ var Viewport = function ( editor ) {
 
 	} );
 
-	var clearColor;
-
 	signals.themeChanged.add( function ( value ) {
 
 		switch ( value ) {
@@ -307,19 +297,15 @@ var Viewport = function ( editor ) {
 				sceneHelpers.remove( grid );
 				grid = new THREE.GridHelper( 30, 60, 0x444444, 0x888888 );
 				sceneHelpers.add( grid );
-				clearColor = 0xaaaaaa;
 				break;
 			case 'css/dark.css':
 				sceneHelpers.remove( grid );
 				grid = new THREE.GridHelper( 30, 60, 0xbbbbbb, 0x888888 );
 				sceneHelpers.add( grid );
-				clearColor = 0x333333;
 				break;
 
 		}
 
-		renderer.setClearColor( clearColor );
-
 		render();
 
 	} );
@@ -354,7 +340,6 @@ var Viewport = function ( editor ) {
 
 		renderer.autoClear = false;
 		renderer.autoUpdateScene = false;
-		renderer.setClearColor( clearColor );
 		renderer.setPixelRatio( window.devicePixelRatio );
 		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
 
@@ -496,53 +481,58 @@ var Viewport = function ( editor ) {
 
 	} );
 
-	signals.fogTypeChanged.add( function ( fogType ) {
+	// fog
+
+	signals.sceneBackgroundChanged.add( function ( backgroundColor ) {
+
+		scene.background.setHex( backgroundColor );
 
-		if ( fogType !== oldFogType ) {
+		render();
 
-			if ( fogType === "None" ) {
+	} );
 
-				scene.fog = null;
+	var currentFogType = null;
 
-			} else if ( fogType === "Fog" ) {
+	signals.sceneFogChanged.add( function ( fogType, fogColor, fogNear, fogFar, fogDensity ) {
 
-				scene.fog = new THREE.Fog( oldFogColor, oldFogNear, oldFogFar );
+		if ( currentFogType !== fogType ) {
 
-			} else if ( fogType === "FogExp2" ) {
+			switch ( fogType ) {
 
-				scene.fog = new THREE.FogExp2( oldFogColor, oldFogDensity );
+				case 'None':
+					scene.fog = null;
+					break;
+				case 'Fog':
+					scene.fog = new THREE.Fog();
+					break;
+				case 'FogExp2':
+					scene.fog = new THREE.FogExp2();
+					break;
 
 			}
 
-			oldFogType = fogType;
+			currentFogType = fogType;
 
 		}
 
-		render();
+		if ( scene.fog instanceof THREE.Fog ) {
 
-	} );
+			scene.fog.color.setHex( fogColor );
+			scene.fog.near = fogNear;
+			scene.fog.far = fogFar;
 
-	signals.fogColorChanged.add( function ( fogColor ) {
+		} else if ( scene.fog instanceof THREE.FogExp2 ) {
 
-		oldFogColor = fogColor;
+			scene.fog.color.setHex( fogColor );
+			scene.fog.density = fogDensity;
 
-		updateFog( scene );
+		}
 
 		render();
 
 	} );
 
-	signals.fogParametersChanged.add( function ( near, far, density ) {
-
-		oldFogNear = near;
-		oldFogFar = far;
-		oldFogDensity = density;
-
-		updateFog( scene );
-
-		render();
-
-	} );
+	//
 
 	signals.windowResize.add( function () {
 
@@ -569,20 +559,6 @@ var Viewport = function ( editor ) {
 
 	//
 
-	function updateFog( root ) {
-
-		if ( root.fog ) {
-
-			root.fog.color.setHex( oldFogColor );
-
-			if ( root.fog.near !== undefined ) root.fog.near = oldFogNear;
-			if ( root.fog.far !== undefined ) root.fog.far = oldFogFar;
-			if ( root.fog.density !== undefined ) root.fog.density = oldFogDensity;
-
-		}
-
-	}
-
 	function animate() {
 
 		requestAnimationFrame( animate );
@@ -628,14 +604,12 @@ var Viewport = function ( editor ) {
 			vrControls.update();
 
 			camera.updateMatrixWorld();
-			renderer.clear();
 
 			vrEffect.render( scene, vrCamera );
 			vrEffect.render( sceneHelpers, vrCamera );
 
 		} else {
 
-			renderer.clear();
 			renderer.render( scene, camera );
 
 			if ( renderer instanceof THREE.RaytracingRenderer === false ) {

+ 7 - 2
editor/js/libs/ui.three.js

@@ -10,6 +10,8 @@ UI.Texture = function ( mapping ) {
 
 	var dom = document.createElement( 'span' );
 
+	var form = document.createElement( 'form' );
+
 	var input = document.createElement( 'input' );
 	input.type = 'file';
 	input.addEventListener( 'change', function ( event ) {
@@ -17,6 +19,7 @@ UI.Texture = function ( mapping ) {
 		loadFile( event.target.files[ 0 ] );
 
 	} );
+	form.appendChild( input );
 
 	var canvas = document.createElement( 'canvas' );
 	canvas.width = 32;
@@ -44,7 +47,7 @@ UI.Texture = function ( mapping ) {
 	name.style.border = '1px solid #ccc';
 	dom.appendChild( name );
 
-	var loadFile = function ( file ) {
+	function loadFile( file ) {
 
 		if ( file.type.match( 'image.*' ) ) {
 
@@ -94,7 +97,9 @@ UI.Texture = function ( mapping ) {
 
 		}
 
-	};
+		form.reset();
+
+	}
 
 	this.dom = dom;
 	this.texture = null;

+ 2 - 2
examples/canvas_geometry_panorama.html

@@ -93,7 +93,7 @@
 				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
 				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
 				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
-				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
+				document.addEventListener( 'wheel', onDocumentMouseWheel, false );
 
 				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
 				document.addEventListener( 'touchmove', onDocumentTouchMove, false );
@@ -164,7 +164,7 @@
 
 			function onDocumentMouseWheel( event ) {
 
-				camera.fov -= event.wheelDeltaY * 0.05;
+				camera.fov += event.deltaY * 0.05;
 				camera.updateProjectionMatrix();
 
 			}

+ 2 - 22
examples/canvas_geometry_panorama_fisheye.html

@@ -102,8 +102,7 @@
 				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
 				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
 				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
-				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
-				document.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);
+				document.addEventListener( 'wheel', onDocumentMouseWheel, false );
 
 				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
 				document.addEventListener( 'touchmove', onDocumentTouchMove, false );
@@ -173,26 +172,7 @@
 
 			function onDocumentMouseWheel( event ) {
 
-				// WebKit
-
-				if ( event.wheelDeltaY ) {
-
-					camera.fov -= event.wheelDeltaY * 0.05;
-
-				// Opera / Explorer 9
-
-				} else if ( event.wheelDelta ) {
-
-					camera.fov -= event.wheelDelta * 0.05;
-
-				// Firefox
-
-				} else if ( event.detail ) {
-
-					camera.fov -= event.detail * 0.05;
-
-				}
-
+				camera.fov += event.deltaY * 0.05;
 				camera.updateProjectionMatrix();
 
 			}

+ 2 - 2
examples/css3d_panorama.html

@@ -110,7 +110,7 @@
 				//
 
 				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
-				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
+				document.addEventListener( 'wheel', onDocumentMouseWheel, false );
 
 				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
 				document.addEventListener( 'touchmove', onDocumentTouchMove, false );
@@ -156,7 +156,7 @@
 
 			function onDocumentMouseWheel( event ) {
 
-				camera.fov -= event.wheelDeltaY * 0.05;
+				camera.fov += event.deltaY * 0.05;
 				camera.updateProjectionMatrix();
 
 			}

+ 3 - 0
examples/files.js

@@ -184,6 +184,7 @@ var files = {
 		"webgl_physics_rope",
 		"webgl_physics_cloth",
 		"webgl_physics_volume",
+		"webgl_physics_convex_break",
 		"webgl_points_billboards",
 		"webgl_points_billboards_colors",
 		"webgl_points_dynamic",
@@ -201,10 +202,12 @@ var files = {
 		"webgl_postprocessing_msaa",
 		"webgl_postprocessing_msaa_unbiased",
 		"webgl_postprocessing_nodes",
+		"webgl_postprocessing_outline",
 		"webgl_postprocessing_procedural",
 		"webgl_postprocessing_smaa",
 		"webgl_postprocessing_ssao",
 		"webgl_postprocessing_taa",
+		"webgl_postprocessing_unreal_bloom",
 		"webgl_raycast_texture",
 		"webgl_read_float_buffer",
 		"webgl_rtt",

+ 22 - 22
examples/js/Cloth.js

@@ -1,5 +1,5 @@
 /*
- * Cloth Simulation using a relaxed constrains solver
+ * Cloth Simulation using a relaxed constraints solver
  */
 
 // Suggested Readings
@@ -82,7 +82,7 @@ Particle.prototype.addForce = function( force ) {
 };
 
 
-// Performs verlet integration
+// Performs Verlet integration
 
 Particle.prototype.integrate = function( timesq ) {
 
@@ -101,7 +101,7 @@ Particle.prototype.integrate = function( timesq ) {
 
 var diff = new THREE.Vector3();
 
-function satisifyConstrains( p1, p2, distance ) {
+function satisifyConstraints( p1, p2, distance ) {
 
 	diff.subVectors( p2.position, p1.position );
 	var currentDist = diff.length();
@@ -122,7 +122,7 @@ function Cloth( w, h ) {
 	this.h = h;
 
 	var particles = [];
-	var constrains = [];
+	var constraints = [];
 
 	var u, v;
 
@@ -145,13 +145,13 @@ function Cloth( w, h ) {
 
 		for ( u = 0; u < w; u ++ ) {
 
-			constrains.push( [
+			constraints.push( [
 				particles[ index( u, v ) ],
 				particles[ index( u, v + 1 ) ],
 				restDistance
 			] );
 
-			constrains.push( [
+			constraints.push( [
 				particles[ index( u, v ) ],
 				particles[ index( u + 1, v ) ],
 				restDistance
@@ -163,7 +163,7 @@ function Cloth( w, h ) {
 
 	for ( u = w, v = 0; v < h; v ++ ) {
 
-		constrains.push( [
+		constraints.push( [
 			particles[ index( u, v ) ],
 			particles[ index( u, v + 1 ) ],
 			restDistance
@@ -174,7 +174,7 @@ function Cloth( w, h ) {
 
 	for ( v = h, u = 0; u < w; u ++ ) {
 
-		constrains.push( [
+		constraints.push( [
 			particles[ index( u, v ) ],
 			particles[ index( u + 1, v ) ],
 			restDistance
@@ -183,8 +183,8 @@ function Cloth( w, h ) {
 	}
 
 
-	// While many system uses shear and bend springs,
-	// the relax constrains model seem to be just fine
+	// While many systems use shear and bend springs,
+	// the relaxed constraints model seems to be just fine
 	// using structural springs.
 	// Shear
 	// var diagonalDist = Math.sqrt(restDistance * restDistance * 2);
@@ -193,13 +193,13 @@ function Cloth( w, h ) {
 	// for (v=0;v<h;v++) {
 	// 	for (u=0;u<w;u++) {
 
-	// 		constrains.push([
+	// 		constraints.push([
 	// 			particles[index(u, v)],
 	// 			particles[index(u+1, v+1)],
 	// 			diagonalDist
 	// 		]);
 
-	// 		constrains.push([
+	// 		constraints.push([
 	// 			particles[index(u+1, v)],
 	// 			particles[index(u, v+1)],
 	// 			diagonalDist
@@ -210,7 +210,7 @@ function Cloth( w, h ) {
 
 
 	this.particles = particles;
-	this.constrains = constrains;
+	this.constraints = constraints;
 
 	function index( u, v ) {
 
@@ -231,7 +231,7 @@ function simulate( time ) {
 
 	}
 
-	var i, il, particles, particle, pt, constrains, constrain;
+	var i, il, particles, particle, pt, constraints, constraint;
 
 	// Aerodynamics forces
 
@@ -264,19 +264,19 @@ function simulate( time ) {
 
 	}
 
-	// Start Constrains
+	// Start Constraints
 
-	constrains = cloth.constrains;
-	il = constrains.length;
+	constraints = cloth.constraints;
+	il = constraints.length;
 
 	for ( i = 0; i < il; i ++ ) {
 
-		constrain = constrains[ i ];
-		satisifyConstrains( constrain[ 0 ], constrain[ 1 ], constrain[ 2 ] );
+		constraint = constraints[ i ];
+		satisifyConstraints( constraint[ 0 ], constraint[ 1 ], constraint[ 2 ] );
 
 	}
 
-	// Ball Constrains
+	// Ball Constraints
 
 	ballPosition.z = - Math.sin( Date.now() / 600 ) * 90 ; //+ 40;
 	ballPosition.x = Math.cos( Date.now() / 400 ) * 70;
@@ -301,7 +301,7 @@ function simulate( time ) {
 	}
 
 
-	// Floor Constains
+	// Floor Constraints
 
 	for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
 
@@ -315,7 +315,7 @@ function simulate( time ) {
 
 	}
 
-	// Pin Constrains
+	// Pin Constraints
 
 	for ( i = 0, il = pins.length; i < il; i ++ ) {
 

+ 489 - 0
examples/js/ConvexObjectBreaker.js

@@ -0,0 +1,489 @@
+/**
+ * @author yomboprime https://github.com/yomboprime
+ *
+ * @fileoverview This class can be used to subdivide a convex Geometry object into pieces.
+ *
+ * Usage:
+ *
+ * Use the function prepareBreakableObject to prepare a Mesh object to be broken.
+ *
+ * Then, call the various functions to subdivide the object (subdivideByImpact, cutByPlane)
+ *
+ * Sub-objects that are product of subdivision don't need prepareBreakableObject to be called on them.
+ *
+ * Requisites for the object:
+ *
+ *  - Mesh object must have a Geometry (not BufferGeometry) and a Material
+ *
+ *  - The Geometry must be convex (this is not tested in the library). You can create convex
+ *  Geometries with THREE.ConvexGeometry. The BoxGeometry, SphereGeometry and other convex primitives
+ *  can also be used.
+ *
+ * Note: This lib adds member variables to object's userData member and to its vertices.
+ * (see prepareBreakableObject function)
+ * Use with caution and read the code when using with other libs.
+ *
+ * @param {double} minSizeForBreak Min size a debris can have to break.
+ * @param {double} smallDelta Max distance to consider that a point belongs to a plane.
+ * 
+  */
+
+THREE.ConvexObjectBreaker = function( minSizeForBreak, smallDelta ) {
+
+	this.minSizeForBreak = minSizeForBreak || 1.4;
+	this.smallDelta = smallDelta || 0.0001;
+
+	this.tempLine1 = new THREE.Line3();
+	this.tempPlane1 = new THREE.Plane();
+	this.tempPlane2 = new THREE.Plane();
+	this.tempCM1 = new THREE.Vector3();
+	this.tempCM2 = new THREE.Vector3();
+	this.tempVector3 = new THREE.Vector3();
+	this.tempVector3_2 = new THREE.Vector3();
+	this.tempVector3_3 = new THREE.Vector3();
+	this.tempResultObjects = { object1: null, object2: null };
+
+	this.segments = [];
+	var n = 30 * 30;
+	for ( var i = 0; i < n; i++ ) {
+		this.segments[ i ] = false;
+	}
+
+};
+
+THREE.ConvexObjectBreaker.prototype = {
+
+	constructor: THREE.ConvexObjectBreaker,
+
+	prepareBreakableObject: function( object, mass, velocity, angularVelocity, breakable ) {
+
+		// object is a THREE.Object3d (normally a Mesh), must have a Geometry, and it must be convex.
+		// Its material property is propagated to its children (sub-pieces)
+		// mass must be > 0
+
+		// Create vertices mark
+		var vertices = object.geometry.vertices;
+		for ( var i = 0, il = vertices.length; i < il; i++ ) {
+			vertices[ i ].mark = 0;
+		}
+
+		var userData = object.userData;
+		userData.mass = mass;
+		userData.velocity = velocity.clone();
+		userData.angularVelocity = angularVelocity.clone();
+		userData.breakable = breakable;
+
+	},
+
+	/*
+	 * @param {int} maxRadialIterations Iterations for radial cuts.
+	 * @param {int} maxRandomIterations Max random iterations for not-radial cuts
+	 * @param {double} minSizeForRadialSubdivision Min size a debris can have to break in radial subdivision.
+	 *
+	 * Returns the array of pieces
+	 */
+	subdivideByImpact: function( object, pointOfImpact, normal, maxRadialIterations, maxRandomIterations, minSizeForRadialSubdivision ) {
+
+		var debris = [];
+
+		var tempPlane1 = this.tempPlane1;
+		var tempPlane2 = this.tempPlane2;
+
+		this.tempVector3.addVectors( pointOfImpact, normal );
+		tempPlane1.setFromCoplanarPoints( pointOfImpact, object.position, this.tempVector3 );
+
+		var maxTotalIterations = maxRandomIterations + maxRadialIterations;
+
+		var scope = this;
+
+		function subdivideRadial( subObject, startAngle, endAngle, numIterations ) {
+
+			if ( Math.random() < numIterations * 0.05 || numIterations > maxTotalIterations ) {
+
+				debris.push( subObject );
+
+				return;
+				
+			}
+			
+			var angle = Math.PI;
+
+			if ( numIterations === 0 ) {
+
+				tempPlane2.normal.copy( tempPlane1.normal );
+				tempPlane2.constant = tempPlane1.constant;
+
+			}
+			else {
+
+				if ( numIterations <= maxRadialIterations ) {
+					
+					angle = ( endAngle - startAngle ) * ( 0.2 + 0.6 * Math.random() ) + startAngle;
+
+					// Rotate tempPlane2 at impact point around normal axis and the angle
+					scope.tempVector3_2.copy( object.position ).sub( pointOfImpact ).applyAxisAngle( normal, angle ).add( pointOfImpact );
+					tempPlane2.setFromCoplanarPoints( pointOfImpact, scope.tempVector3, scope.tempVector3_2 );
+
+				}
+				else {
+
+					angle = ( ( 0.5 * ( numIterations & 1 ) ) + 0.2 * ( 2 - Math.random() ) ) * Math.PI;
+
+					// Rotate tempPlane2 at object position around normal axis and the angle
+					scope.tempVector3_2.copy( pointOfImpact ).sub( subObject.position ).applyAxisAngle( normal, angle ).add( subObject.position );
+					scope.tempVector3_3.copy( normal ).add( subObject.position );
+					tempPlane2.setFromCoplanarPoints( subObject.position, scope.tempVector3_3, scope.tempVector3_2 );
+
+				}
+
+			}
+
+			// Perform the cut
+			scope.cutByPlane( subObject, tempPlane2, scope.tempResultObjects );
+
+			var obj1 = scope.tempResultObjects.object1;
+			var obj2 = scope.tempResultObjects.object2;
+
+			if ( obj1 ) {
+
+				subdivideRadial( obj1, startAngle, angle, numIterations + 1 );
+
+			}
+
+			if ( obj2 ) {
+
+				subdivideRadial( obj2, angle, endAngle, numIterations + 1 );
+
+			}
+
+		}
+
+		subdivideRadial( object, 0, 2 * Math.PI, 0 );
+
+		return debris;
+
+	},
+
+	cutByPlane: function( object, plane, output ) {
+
+		// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
+		// object2 can be null if the plane doesn't cut the object.
+		// object1 can be null only in case of internal error
+		// Returned value is number of pieces, 0 for error.
+
+		var geometry = object.geometry;
+		var points = geometry.vertices;
+		var faces = geometry.faces;
+
+		var numPoints = points.length;
+
+		var points1 = [];
+		var points2 = [];
+
+		var delta = this.smallDelta;
+
+		// Reset vertices mark
+		for ( var i = 0; i < numPoints; i++ ) {
+			points[ i ].mark = 0;
+		}
+
+		// Reset segments mark
+		var numPointPairs = numPoints * numPoints;
+		for ( var i = 0; i < numPointPairs; i++ ) {
+			this.segments[ i ] = false;
+		}
+
+		// Iterate through the faces to mark edges shared by coplanar faces
+		for ( var i = 0, il = faces.length - 1; i < il; i++ ) {
+
+			var face1 = faces[ i ];
+
+			for ( var j = i + 1, jl = faces.length; j < jl; j++ ) {
+
+				var face2 = faces[ j ];
+
+				var coplanar = 1 - face1.normal.dot( face2.normal ) < delta;
+
+				if ( coplanar ) {
+
+					var a1 = face1.a;
+					var b1 = face1.b;
+					var c1 = face1.c;
+					var a2 = face2.a;
+					var b2 = face2.b;
+					var c2 = face2.c;
+
+
+					if ( a1 === a2 || a1 === b2 || a1 === c2 ) {
+						if ( b1 === a2 || b1 === b2 || b1 === c2 ) {
+							this.segments[ a1 * numPoints + b1 ] = true;
+							this.segments[ b1 * numPoints + a1 ] = true;
+						}
+						else {
+							this.segments[ c1 * numPoints + a1 ] = true;
+							this.segments[ a1 * numPoints + c1 ] = true;
+						}
+					}
+					else if ( b1 === a2 || b1 === b2 || b1 === c2 ) {
+						this.segments[ c1 * numPoints + b1 ] = true;
+						this.segments[ b1 * numPoints + c1 ] = true;
+					}
+
+				}
+
+			}
+
+		}
+
+		// Transform the plane to object local space
+		var localPlane = this.tempPlane1;
+		object.updateMatrix();
+		THREE.ConvexObjectBreaker.transformPlaneToLocalSpace( plane, object.matrix, localPlane );
+
+		// Iterate through the faces adding points to both pieces
+		for ( var i = 0, il = faces.length; i < il; i ++ ) {
+
+			var face = faces[ i ];
+
+			for ( var segment = 0; segment < 3; segment++ ) {
+
+				var i0 = segment === 0 ? face.a : ( segment === 1 ? face.b : face.c );
+				var i1 = segment === 0 ? face.b : ( segment === 1 ? face.c : face.a );
+
+				var segmentState = this.segments[ i0 * numPoints + i1 ];
+
+				if ( segmentState ) {
+					// The segment already has been processed in another face
+					continue;
+				}
+
+				// Mark segment as processed (also inverted segment)
+				this.segments[ i0 * numPoints + i1 ] = true;
+				this.segments[ i1 * numPoints + i0 ] = true;
+
+				var p0 = points[ i0 ];
+				var p1 = points[ i1 ];
+
+				if ( p0.mark === 0 ) {
+
+					var d = localPlane.distanceToPoint( p0 );
+
+					// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
+					if ( d > delta ) {
+						p0.mark = 2;
+						points2.push( p0 );
+					}
+					else if ( d < - delta ) {
+						p0.mark = 1;
+						points1.push( p0 );
+					}
+					else {
+						p0.mark = 3;
+						points1.push( p0 );
+						var p0_2 = p0.clone();
+						p0_2.mark = 3;
+						points2.push( p0_2 );
+					}
+
+				}
+
+				if ( p1.mark === 0 ) {
+
+					var d = localPlane.distanceToPoint( p1 );
+
+					// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
+					if ( d > delta ) {
+						p1.mark = 2;
+						points2.push( p1 );
+					}
+					else if ( d < - delta ) {
+						p1.mark = 1;
+						points1.push( p1 );
+					}
+					else {
+						p1.mark = 3;
+						points1.push( p1 );
+						var p1_2 = p1.clone();
+						p1_2.mark = 3;
+						points2.push( p1_2 );
+					}
+
+				}
+
+				var mark0 = p0.mark;
+				var mark1 = p1.mark;
+
+				if ( ( mark0 === 1 && mark1 === 2 ) || ( mark0 === 2 && mark1 === 1 ) ) {
+
+					// Intersection of segment with the plane
+
+					this.tempLine1.start.copy( p0 );
+					this.tempLine1.end.copy( p1 );
+					var intersection = localPlane.intersectLine( this.tempLine1 );
+					if ( intersection === undefined ) {
+						// Shouldn't happen
+						console.error( "Internal error: segment does not intersect plane." );
+						output.segmentedObject1 = null;
+						output.segmentedObject2 = null;
+						return 0;
+					}
+
+					intersection.mark = 1;
+					points1.push( intersection );
+					var intersection_2 = intersection.clone();
+					intersection_2.mark = 2;
+					points2.push( intersection_2 );
+
+				}
+
+			}
+
+		}
+
+		// Calculate debris mass (very fast and imprecise):
+		var newMass = object.userData.mass * 0.5;
+
+		// Calculate debris Center of Mass (again fast and imprecise)
+		this.tempCM1.set( 0, 0, 0 );
+		var radius1 = 0;
+		var numPoints1 = points1.length;
+		if ( numPoints1 > 0 ) {
+			for ( var i = 0; i < numPoints1; i++ ) {
+				this.tempCM1.add( points1[ i ] );
+			}
+			this.tempCM1.divideScalar( numPoints1 );
+			for ( var i = 0; i < numPoints1; i++ ) {
+				var p = points1[ i ];
+				p.sub( this.tempCM1 );
+				radius1 = Math.max( radius1, p.x, p.y, p.z );
+			}
+			this.tempCM1.add( object.position );
+		}
+
+		this.tempCM2.set( 0, 0, 0 );
+		var radius2 = 0;
+		var numPoints2 = points2.length;
+		if ( numPoints2 > 0 ) {
+			for ( var i = 0; i < numPoints2; i++ ) {
+				this.tempCM2.add( points2[ i ] );
+			}
+			this.tempCM2.divideScalar( numPoints2 );
+			for ( var i = 0; i < numPoints2; i++ ) {
+				var p = points2[ i ];
+				p.sub( this.tempCM2 );
+				radius2 = Math.max( radius2, p.x, p.y, p.z );
+			}
+			this.tempCM2.add( object.position );
+		}
+
+		var object1 = null;
+		var object2 = null;
+
+		var numObjects = 0;
+
+		if ( numPoints1 > 4 ) {
+
+			object1 = new THREE.Mesh( new THREE.ConvexGeometry( points1 ), object.material );
+			object1.position.copy( this.tempCM1 );
+			object1.quaternion.copy( object.quaternion );
+
+			this.prepareBreakableObject( object1, newMass, object.userData.velocity, object.userData.angularVelocity, 2 * radius1 > this.minSizeForBreak );
+
+			numObjects++;
+
+		}
+
+		if ( numPoints2 > 4 ) {
+
+			object2 = new THREE.Mesh( new THREE.ConvexGeometry( points2 ), object.material );
+			object2.position.copy( this.tempCM2 );
+			object2.quaternion.copy( object.quaternion );
+
+			this.prepareBreakableObject( object2, newMass, object.userData.velocity, object.userData.angularVelocity, 2 * radius2 > this.minSizeForBreak );
+
+			numObjects++;
+
+		}
+
+
+		output.object1 = object1;
+		output.object2 = object2;
+
+		return numObjects;
+
+	}
+
+};
+
+THREE.ConvexObjectBreaker.transformFreeVector = function( v, m ) {
+
+	// input:
+	// vector interpreted as a free vector
+	// THREE.Matrix4 orthogonal matrix (matrix without scale)
+
+	var x = v.x, y = v.y, z = v.z;
+	var e = m.elements;
+
+	v.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z;
+	v.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z;
+	v.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
+
+	return v;
+
+};
+
+THREE.ConvexObjectBreaker.transformFreeVectorInverse = function( v, m ) {
+
+	// input:
+	// vector interpreted as a free vector
+	// THREE.Matrix4 orthogonal matrix (matrix without scale)
+
+	var x = v.x, y = v.y, z = v.z;
+	var e = m.elements;
+
+	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ]  * z;
+	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ]  * z;
+	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z;
+
+	return v;
+
+};
+
+THREE.ConvexObjectBreaker.transformTiedVectorInverse = function( v, m ) {
+
+	// input:
+	// vector interpreted as a tied (ordinary) vector
+	// THREE.Matrix4 orthogonal matrix (matrix without scale)
+
+	var x = v.x, y = v.y, z = v.z;
+	var e = m.elements;
+
+	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ]  * z - e[ 12 ];
+	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ]  * z - e[ 13 ];
+	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z - e[ 14 ];
+
+	return v;
+
+};
+
+THREE.ConvexObjectBreaker.transformPlaneToLocalSpace = function() {
+
+	var v1 = new THREE.Vector3();
+	var m1 = new THREE.Matrix3();
+
+	return function transformPlaneToLocalSpace( plane, m, resultPlane ) {
+
+		resultPlane.normal.copy( plane.normal );
+		resultPlane.constant = plane.constant;
+
+		var referencePoint = THREE.ConvexObjectBreaker.transformTiedVectorInverse( plane.coplanarPoint( v1 ), m );
+
+		THREE.ConvexObjectBreaker.transformFreeVectorInverse( resultPlane.normal, m );
+
+		// recalculate constant (like in setFromNormalAndCoplanarPoint)
+		resultPlane.constant = - referencePoint.dot( resultPlane.normal );
+
+
+	};
+
+}();

+ 4 - 1
examples/js/ViveController.js

@@ -2,6 +2,9 @@ THREE.ViveController = function ( id ) {
 
 	THREE.Object3D.call( this );
 
+	var gamepad;
+
+	this.getGamepad = function () { return gamepad; };
 	this.matrixAutoUpdate = false;
 	this.standingMatrix = new THREE.Matrix4();
 
@@ -11,7 +14,7 @@ THREE.ViveController = function ( id ) {
 
 		requestAnimationFrame( update );
 
-		var gamepad = navigator.getGamepads()[ id ];
+		gamepad = navigator.getGamepads()[ id ];
 
 		if ( gamepad !== undefined && gamepad.pose !== null ) {
 

+ 4 - 22
examples/js/controls/EditorControls.js

@@ -177,23 +177,7 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		// if ( scope.enabled === false ) return;
 
-		var delta = 0;
-
-		if ( event.wheelDelta ) {
-
-			// WebKit / Opera / Explorer 9
-
-			delta = - event.wheelDelta;
-
-		} else if ( event.detail ) {
-
-			// Firefox
-
-			delta = event.detail * 10;
-
-		}
-
-		scope.zoom( new THREE.Vector3( 0, 0, delta ) );
+		scope.zoom( new THREE.Vector3( 0, 0, event.deltaY ) );
 
 	}
 
@@ -207,8 +191,7 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		domElement.removeEventListener( 'contextmenu', contextmenu, false );
 		domElement.removeEventListener( 'mousedown', onMouseDown, false );
-		domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
-		domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+		domElement.removeEventListener( 'wheel', onMouseWheel, false );
 
 		domElement.removeEventListener( 'mousemove', onMouseMove, false );
 		domElement.removeEventListener( 'mouseup', onMouseUp, false );
@@ -218,12 +201,11 @@ THREE.EditorControls = function ( object, domElement ) {
 		domElement.removeEventListener( 'touchstart', touchStart, false );
 		domElement.removeEventListener( 'touchmove', touchMove, false );
 
-	}
+	};
 
 	domElement.addEventListener( 'contextmenu', contextmenu, false );
 	domElement.addEventListener( 'mousedown', onMouseDown, false );
-	domElement.addEventListener( 'mousewheel', onMouseWheel, false );
-	domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+	domElement.addEventListener( 'wheel', onMouseWheel, false );
 
 	// touch
 

+ 4 - 22
examples/js/controls/OrbitControls.js

@@ -212,8 +212,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
 		scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
-		scope.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
-		scope.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+		scope.domElement.removeEventListener( 'wheel', onMouseWheel, false );
 
 		scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
 		scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
@@ -500,27 +499,11 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		//console.log( 'handleMouseWheel' );
 
-		var delta = 0;
-
-		if ( event.wheelDelta !== undefined ) {
-
-			// WebKit / Opera / Explorer 9
-
-			delta = event.wheelDelta;
-
-		} else if ( event.detail !== undefined ) {
-
-			// Firefox
-
-			delta = - event.detail;
-
-		}
-
-		if ( delta > 0 ) {
+		if ( event.deltaY < 0 ) {
 
 			dollyOut( getZoomScale() );
 
-		} else if ( delta < 0 ) {
+		} else if ( event.deltaY > 0 ) {
 
 			dollyIn( getZoomScale() );
 
@@ -890,8 +873,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 	scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
 
 	scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
-	scope.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
-	scope.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
+	scope.domElement.addEventListener( 'wheel', onMouseWheel, false );
 
 	scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
 	scope.domElement.addEventListener( 'touchend', onTouchEnd, false );

+ 4 - 23
examples/js/controls/OrthographicTrackballControls.js

@@ -495,23 +495,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 		event.preventDefault();
 		event.stopPropagation();
 
-		var delta = 0;
-
-		if ( event.wheelDelta ) {
-
-			// WebKit / Opera / Explorer 9
-
-			delta = event.wheelDelta / 40;
-
-		} else if ( event.detail ) {
-
-			// Firefox
-
-			delta = - event.detail / 3;
-
-		}
-
-		_zoomStart.y += delta * 0.01;
+		_zoomStart.y += event.deltaY * 0.01;
 		_this.dispatchEvent( startEvent );
 		_this.dispatchEvent( endEvent );
 
@@ -616,8 +600,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 		this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
 		this.domElement.removeEventListener( 'mousedown', mousedown, false );
-		this.domElement.removeEventListener( 'mousewheel', mousewheel, false );
-		this.domElement.removeEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
+		this.domElement.removeEventListener( 'wheel', mousewheel, false );
 
 		this.domElement.removeEventListener( 'touchstart', touchstart, false );
 		this.domElement.removeEventListener( 'touchend', touchend, false );
@@ -629,13 +612,11 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 		window.removeEventListener( 'keydown', keydown, false );
 		window.removeEventListener( 'keyup', keyup, false );
 
-	}
-
+	};
 
 	this.domElement.addEventListener( 'contextmenu', contextmenu, false );
 	this.domElement.addEventListener( 'mousedown', mousedown, false );
-	this.domElement.addEventListener( 'mousewheel', mousewheel, false );
-	this.domElement.addEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
+	this.domElement.addEventListener( 'wheel', mousewheel, false );
 
 	this.domElement.addEventListener( 'touchstart', touchstart, false );
 	this.domElement.addEventListener( 'touchend', touchend, false );

+ 3 - 20
examples/js/controls/TrackballControls.js

@@ -473,23 +473,8 @@ THREE.TrackballControls = function ( object, domElement ) {
 		event.preventDefault();
 		event.stopPropagation();
 
-		var delta = 0;
+		_zoomStart.y -= event.deltaY * 0.01;
 
-		if ( event.wheelDelta ) {
-
-			// WebKit / Opera / Explorer 9
-
-			delta = event.wheelDelta / 40;
-
-		} else if ( event.detail ) {
-
-			// Firefox
-
-			delta = - event.detail / 3;
-
-		}
-
-		_zoomStart.y += delta * 0.01;
 		_this.dispatchEvent( startEvent );
 		_this.dispatchEvent( endEvent );
 
@@ -585,8 +570,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
 		this.domElement.removeEventListener( 'mousedown', mousedown, false );
-		this.domElement.removeEventListener( 'mousewheel', mousewheel, false );
-		this.domElement.removeEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
+		this.domElement.removeEventListener( 'wheel', mousewheel, false );
 
 		this.domElement.removeEventListener( 'touchstart', touchstart, false );
 		this.domElement.removeEventListener( 'touchend', touchend, false );
@@ -602,8 +586,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 	this.domElement.addEventListener( 'contextmenu', contextmenu, false );
 	this.domElement.addEventListener( 'mousedown', mousedown, false );
-	this.domElement.addEventListener( 'mousewheel', mousewheel, false );
-	this.domElement.addEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
+	this.domElement.addEventListener( 'wheel', mousewheel, false );
 
 	this.domElement.addEventListener( 'touchstart', touchstart, false );
 	this.domElement.addEventListener( 'touchend', touchend, false );

+ 1 - 1
examples/js/controls/TransformControls.js

@@ -1113,7 +1113,7 @@
 
 			_dragging = false;
 
-			if ( event instanceof TouchEvent ) {
+			if ( 'TouchEvent' in window && event instanceof TouchEvent ) {
 
 				// Force "rollover"
 

+ 6 - 0
examples/js/effects/StereoEffect.js

@@ -10,6 +10,12 @@ THREE.StereoEffect = function ( renderer ) {
 	var _stereo = new THREE.StereoCamera();
 	_stereo.aspect = 0.5;
 
+	this.setEyeSeparation = function ( eyeSep ) {
+
+		_stereo.eyeSep = eyeSep;
+
+	};
+
 	this.setSize = function ( width, height ) {
 
 		renderer.setSize( width, height );

+ 16 - 15
examples/js/effects/VREffect.js

@@ -119,7 +119,7 @@ THREE.VREffect = function ( renderer, onError ) {
 	var leftBounds = [ 0.0, 0.0, 0.5, 1.0 ];
 	var rightBounds = [ 0.5, 0.0, 0.5, 1.0 ];
 
-	function onFullscreenChange () {
+	function onFullscreenChange() {
 
 		var wasPresenting = scope.isPresenting;
 		scope.isPresenting = vrDisplay !== undefined && ( vrDisplay.isPresenting || ( ! isWebVR1 && document[ fullscreenElement ] instanceof window.HTMLElement ) );
@@ -137,12 +137,13 @@ THREE.VREffect = function ( renderer, onError ) {
 				if ( vrDisplay.getLayers ) {
 
 					var layers = vrDisplay.getLayers();
-					if (layers.length) {
+					if ( layers.length ) {
 
 						leftBounds = layers[0].leftBounds || [ 0.0, 0.0, 0.5, 1.0 ];
 						rightBounds = layers[0].rightBounds || [ 0.5, 0.0, 0.5, 1.0 ];
 
 					}
+
 				}
 
 			} else {
@@ -271,7 +272,7 @@ THREE.VREffect = function ( renderer, onError ) {
 		}
 
 	};
-	
+
 	this.cancelAnimationFrame = function ( h ) {
 
 		if ( isWebVR1 && vrDisplay !== undefined ) {
@@ -285,7 +286,7 @@ THREE.VREffect = function ( renderer, onError ) {
 		}
 
 	};
-	
+
 	this.submitFrame = function () {
 
 		if ( isWebVR1 && vrDisplay !== undefined && scope.isPresenting ) {
@@ -361,13 +362,13 @@ THREE.VREffect = function ( renderer, onError ) {
 				height:  Math.round(size.height * rightBounds[ 3 ] )
 			};
 
-			if (renderTarget) {
-				
-				renderer.setRenderTarget(renderTarget);
+			if ( renderTarget ) {
+
+				renderer.setRenderTarget( renderTarget );
 				renderTarget.scissorTest = true;
-				
+
 			} else  {
-				
+
 				renderer.setScissorTest( true );
 			
 			}
@@ -390,8 +391,8 @@ THREE.VREffect = function ( renderer, onError ) {
 			// render left eye
 			if ( renderTarget ) {
 
-				renderTarget.viewport.set(renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height);
-				renderTarget.scissor.set(renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height);
+				renderTarget.viewport.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );
+				renderTarget.scissor.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );
 
 			} else {
 
@@ -402,10 +403,10 @@ THREE.VREffect = function ( renderer, onError ) {
 			renderer.render( scene, cameraL, renderTarget, forceClear );
 
 			// render right eye
-			if (renderTarget) {
+			if ( renderTarget ) {
 
-				renderTarget.viewport.set(renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height);
-  				renderTarget.scissor.set(renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height);
+				renderTarget.viewport.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );
+				renderTarget.scissor.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );
 
 			} else {
 
@@ -415,7 +416,7 @@ THREE.VREffect = function ( renderer, onError ) {
 			}
 			renderer.render( scene, cameraR, renderTarget, forceClear );
 
-			if (renderTarget) {
+			if ( renderTarget ) {
 
 				renderTarget.viewport.set( 0, 0, size.width, size.height );
 				renderTarget.scissor.set( 0, 0, size.width, size.height );

+ 79 - 41
examples/js/loaders/MMDLoader.js

@@ -479,10 +479,7 @@ THREE.MMDLoader.prototype.parsePmd = function ( buffer ) {
 		var parseBone = function () {
 
 			var p = {};
-			// Skinning animation doesn't work when bone name is Japanese Unicode in r73.
-			// So using charcode strings as workaround and keep original strings in .originalName.
-			p.originalName = dv.getSjisStringsAsUnicode( 20 );
-			p.name = helper.toCharcodeStrings( p.originalName );
+			p.name = dv.getSjisStringsAsUnicode( 20 );
 			p.parentIndex = dv.getInt16();
 			p.tailIndex = dv.getInt16();
 			p.type = dv.getUint8();
@@ -1085,10 +1082,7 @@ THREE.MMDLoader.prototype.parsePmx = function ( buffer ) {
 		var parseBone = function () {
 
 			var p = {};
-			// Skinning animation doesn't work when bone name is Japanese Unicode in r73.
-			// So using charcode strings as workaround and keep original strings in .originalName.
-			p.originalName = dv.getTextBuffer();
-			p.name = helper.toCharcodeStrings( p.originalName );
+			p.name = dv.getTextBuffer();
 			p.englishName = dv.getTextBuffer();
 			p.position = dv.getFloat32Array( 3 );
 			p.parentIndex = dv.getIndex( pmx.metadata.boneIndexSize );
@@ -1428,10 +1422,7 @@ THREE.MMDLoader.prototype.parseVmd = function ( buffer ) {
 		var parseMotion = function () {
 
 			var p = {};
-			// Skinning animation doesn't work when bone name is Japanese Unicode in r73.
-			// So using charcode strings as workaround and keep original strings in .originalName.
-			p.originalBoneName = dv.getSjisStringsAsUnicode( 15 );
-			p.boneName = helper.toCharcodeStrings( p.originalBoneName );
+			p.boneName = dv.getSjisStringsAsUnicode( 15 );
 			p.frameNum = dv.getUint32();
 			p.position = dv.getFloat32Array( 3 );
 			p.rotation = dv.getFloat32Array( 4 );
@@ -1649,8 +1640,7 @@ THREE.MMDLoader.prototype.parseVpd = function ( text ) {
 
 				bones.push( {
 
-					originalName: n,
-					name: helper.toCharcodeStrings( n ),
+					name: n,
 					translation: v,
 					quaternion: q
 
@@ -1808,9 +1798,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 					var link = {};
 					link.index = ik.links[ j ].index;
 
-					// Checking with .originalName, not .name.
-					// See parseBone() for the detail.
-					if ( model.bones[ link.index ].originalName.indexOf( 'ひざ' ) >= 0 ) {
+					if ( model.bones[ link.index ].name.indexOf( 'ひざ' ) >= 0 ) {
 
 						link.limitation = new THREE.Vector3( 1.0, 0.0, 0.0 );
 
@@ -2590,21 +2578,6 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 	};
 
-	function saveOriginalBoneNames ( mesh ) {
-
-		var bones = mesh.skeleton.bones;
-		var bones2 = mesh.geometry.bones;
-
-		for ( var i = 0; i < bones.length; i++ ) {
-
-			var n = model.bones[ i ].originalName;
-			bones[ i ].originalName = n;
-			bones2[ i ].originalName = n;
-
-		}
-
-	};
-
 	this.leftToRightModel( model );
 
 	initVartices();
@@ -2624,8 +2597,6 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 	var mesh = new THREE.SkinnedMesh( geometry, material );
 
-	saveOriginalBoneNames( mesh );
-
 	// console.log( mesh ); // for console debug
 
 	return mesh;
@@ -4063,6 +4034,12 @@ THREE.MMDHelper.prototype = {
 
 	add: function ( mesh ) {
 
+		if ( ! ( mesh instanceof THREE.SkinnedMesh ) ) {
+
+			throw new Error( 'THREE.MMDHelper.add() accepts only THREE.SkinnedMesh instance.' );
+
+		}
+
 		mesh.mixer = null;
 		mesh.ikSolver = null;
 		mesh.grantSolver = null;
@@ -4407,17 +4384,78 @@ THREE.MMDHelper.prototype = {
 
 	},
 
-	renderOutline: function ( scene, camera ) {
+	renderOutline: function () {
 
-		var tmpEnabled = this.renderer.shadowMap.enabled;
-		this.renderer.shadowMap.enabled = false;
+		var invisibledObjects = [];
+		var setInvisible;
+		var restoreVisible;
 
-		this.setupOutlineRendering();
-		this.callRender( scene, camera );
+		return function renderOutline( scene, camera ) {
 
-		this.renderer.shadowMap.enabled = tmpEnabled;
+			var self = this;
 
-	},
+			if ( setInvisible === undefined ) {
+
+				setInvisible = function ( object ) {
+
+					if ( ! object.visible || ! object.layers.test( camera.layers ) ) return;
+
+					// any types else to skip?
+					if ( object instanceof THREE.Scene ||
+					     object instanceof THREE.Bone ||
+					     object instanceof THREE.Light ||
+					     object instanceof THREE.Camera ||
+					     object instanceof THREE.Audio ||
+					     object instanceof THREE.AudioListener ) return;
+
+					if ( object instanceof THREE.SkinnedMesh ) {
+
+						for ( var i = 0, il = self.meshes.length; i < il; i ++ ) {
+
+							if ( self.meshes[ i ] === object ) return;
+
+						}
+
+					}
+
+					object.layers.mask &= ~ camera.layers.mask;
+					invisibledObjects.push( object );
+
+				};
+
+			}
+
+			if ( restoreVisible === undefined ) {
+
+				restoreVisible = function () {
+
+					for ( var i = 0, il = invisibledObjects.length; i < il; i ++ ) {
+
+						invisibledObjects[ i ].layers.mask |= camera.layers.mask;
+
+					}
+
+					invisibledObjects.length = 0;
+
+				};
+
+			}
+
+			scene.traverse( setInvisible );
+
+			var tmpEnabled = this.renderer.shadowMap.enabled;
+			this.renderer.shadowMap.enabled = false;
+
+			this.setupOutlineRendering();
+			this.callRender( scene, camera );
+
+			this.renderer.shadowMap.enabled = tmpEnabled;
+
+			restoreVisible();
+
+		};
+
+	}(),
 
 	callRender: function ( scene, camera ) {
 

+ 27 - 32
examples/js/loaders/MTLLoader.js

@@ -338,6 +338,7 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 		// Create material
 
+		var scope = this;
 		var mat = this.materialsInfo[ materialName ];
 		var params = {
 
@@ -358,6 +359,22 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 			return baseUrl + url;
 		};
+		
+		function setMapForType ( mapType, value ) {
+
+			if ( params[ mapType ] ) return; // Keep the first encountered texture
+
+			var texParams = scope.getTextureParams( value, params );
+			var map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) );
+			
+			map.repeat.copy( texParams.scale );
+			map.offset.copy( texParams.offset );
+
+			map.wrapS = scope.wrap;
+			map.wrapT = scope.wrap;
+			
+			params[ mapType ] = map;
+		}
 
 		for ( var prop in mat ) {
 
@@ -388,28 +405,24 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					// Diffuse texture map
 
-					if ( params.map ) break; // Keep the first encountered texture
-
-					var texParams = this.getTextureParams( value, params );
-
-					params.map = this.loadTexture( resolveURL( this.baseUrl, texParams.url ) );
-					params.map.repeat.copy( texParams.scale );
-					params.map.offset.copy( texParams.offset );
-
-					params.map.wrapS = this.wrap;
-					params.map.wrapT = this.wrap;
+					setMapForType( "map", value );
 
 					break;
 
 				case 'map_ks':
 
 					// Specular map
+					
+					setMapForType( "specularMap", value );
 
-					if ( params.specularMap ) break; // Keep the first encountered texture
+					break;
 
-					params.specularMap = this.loadTexture( resolveURL( this.baseUrl, value ) );
-					params.specularMap.wrapS = this.wrap;
-					params.specularMap.wrapT = this.wrap;
+				case 'map_bump':
+				case 'bump':
+
+					// Bump texture map				
+					
+					setMapForType( "bumpMap", value );
 
 					break;
 
@@ -444,24 +457,6 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					break;
 
-				case 'map_bump':
-				case 'bump':
-
-					// Bump texture map
-
-					if ( params.bumpMap ) break; // Keep the first encountered texture
-
-					var texParams = this.getTextureParams( value, params );					
-
-					params.bumpMap = this.loadTexture( resolveURL( this.baseUrl, texParams.url ) );
-					params.bumpMap.repeat.copy( texParams.scale );
-					params.bumpMap.offset.copy( texParams.offset );
- 
-					params.bumpMap.wrapS = this.wrap;
-					params.bumpMap.wrapT = this.wrap;
-
-					break;
-
 				default:
 					break;
 

+ 2 - 2
examples/js/loaders/OBJLoader.js

@@ -696,11 +696,11 @@ THREE.OBJLoader.prototype = {
 				}
 
 				var multiMaterial = new THREE.MultiMaterial( createdMaterials );
-				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, multiMaterial ) : new THREE.Line( buffergeometry, multiMaterial ) );
+				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, multiMaterial ) : new THREE.LineSegments( buffergeometry, multiMaterial ) );
 
 			} else {
 
-				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.Line( buffergeometry, createdMaterials[ 0 ] ) );
+				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) );
 			}
 
 			mesh.name = object.name;

+ 3 - 3
examples/js/loaders/STLLoader.js

@@ -244,13 +244,13 @@ THREE.STLLoader.prototype = {
 		if ( typeof buf !== "string" ) {
 
 			var array_buffer = new Uint8Array( buf );
-			var str = '';
+			var strArray = [];
 			for ( var i = 0; i < buf.byteLength; i ++ ) {
 
-				str += String.fromCharCode( array_buffer[ i ] ); // implicitly assumes little-endian
+				strArray.push(String.fromCharCode( array_buffer[ i ] )); // implicitly assumes little-endian
 
 			}
-			return str;
+			return strArray.join('');
 
 		} else {
 

+ 0 - 1
examples/js/nodes/materials/PhongNode.js

@@ -144,7 +144,6 @@ THREE.PhongNode.prototype.build = function( builder ) {
 			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
-			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],

+ 503 - 0
examples/js/postprocessing/OutlinePass.js

@@ -0,0 +1,503 @@
+/**
+ * @author spidersharma / http://eduperiment.com/
+ */
+
+THREE.OutlinePass = function ( resolution, scene, camera, selectedObjects ) {
+
+	this.renderScene = scene;
+	this.renderCamera = camera;
+	this.selectedObjects = selectedObjects !== undefined ? selectedObjects : [];
+	this.visibleEdgeColor = new THREE.Color(1, 1, 1);
+	this.hiddenEdgeColor = new THREE.Color(0.1, 0.04, 0.02);
+	this.edgeGlow = 0.0;
+	this.usePatternTexture = false;
+	this.edgeThickness = 1.0;
+	this.edgeStrength = 3.0;
+	this.downSampleRatio = 2;
+	this.pulsePeriod = 0;
+
+	THREE.Pass.call( this );
+
+	this.resolution = ( resolution !== undefined ) ? new THREE.Vector2(resolution.x, resolution.y) : new THREE.Vector2(256, 256);
+
+	var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
+
+	var resx = Math.round(this.resolution.x/this.downSampleRatio);
+	var resy = Math.round(this.resolution.y/this.downSampleRatio);
+
+	this.maskBufferMaterial = new THREE.MeshBasicMaterial({color:0xffffff});
+	this.maskBufferMaterial.side = THREE.DoubleSide;
+	this.renderTargetMaskBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, pars );
+	this.renderTargetMaskBuffer.texture.generateMipmaps = false;
+
+	this.depthMaterial = new THREE.MeshDepthMaterial();
+	this.depthMaterial.side = THREE.DoubleSide;
+	this.depthMaterial.depthPacking = THREE.RGBADepthPacking;
+	this.depthMaterial.blending = THREE.NoBlending;
+
+	this.prepareMaskMaterial = this.getPrepareMaskMaterial();
+	this.prepareMaskMaterial.side = THREE.DoubleSide;
+
+	this.renderTargetDepthBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, pars );
+	this.renderTargetDepthBuffer.texture.generateMipmaps = false;
+
+	this.renderTargetMaskDownSampleBuffer = new THREE.WebGLRenderTarget( resx, resy, pars );
+	this.renderTargetMaskDownSampleBuffer.texture.generateMipmaps = false;
+
+	this.renderTargetBlurBuffer1 = new THREE.WebGLRenderTarget( resx, resy, pars );
+	this.renderTargetBlurBuffer1.texture.generateMipmaps = false;
+	this.renderTargetBlurBuffer2 = new THREE.WebGLRenderTarget( Math.round(resx/2), Math.round(resy/2), pars );
+	this.renderTargetBlurBuffer2.texture.generateMipmaps = false;
+
+	this.edgeDetectionMaterial = this.getEdgeDetectionMaterial();
+	this.renderTargetEdgeBuffer1 = new THREE.WebGLRenderTarget( resx, resy, pars );
+	this.renderTargetEdgeBuffer1.texture.generateMipmaps = false;
+	this.renderTargetEdgeBuffer2 = new THREE.WebGLRenderTarget( Math.round(resx/2), Math.round(resy/2), pars );
+	this.renderTargetEdgeBuffer2.texture.generateMipmaps = false;
+
+	var MAX_EDGE_THICKNESS = 4;
+	var MAX_EDGE_GLOW = 4;
+
+	this.separableBlurMaterial1 = this.getSeperableBlurMaterial(MAX_EDGE_THICKNESS);
+	this.separableBlurMaterial1.uniforms[ "texSize" ].value = new THREE.Vector2(resx, resy);
+	this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = 1;
+	this.separableBlurMaterial2 = this.getSeperableBlurMaterial(MAX_EDGE_GLOW);
+	this.separableBlurMaterial2.uniforms[ "texSize" ].value = new THREE.Vector2(Math.round(resx/2), Math.round(resy/2));
+	this.separableBlurMaterial2.uniforms[ "kernelRadius" ].value = MAX_EDGE_GLOW;
+
+	// Overlay material
+	this.overlayMaterial = this.getOverlayMaterial();
+
+	// copy material
+	if ( THREE.CopyShader === undefined )
+		console.error( "THREE.OutlinePass relies on THREE.CopyShader" );
+
+	var copyShader = THREE.CopyShader;
+
+	this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
+	this.copyUniforms[ "opacity" ].value = 1.0;
+
+	this.materialCopy = new THREE.ShaderMaterial( {
+		uniforms: this.copyUniforms,
+		vertexShader: copyShader.vertexShader,
+		fragmentShader: copyShader.fragmentShader,
+		blending: THREE.NoBlending,
+		depthTest: false,
+		depthWrite: false,
+		transparent: true
+	} );
+
+	this.enabled = true;
+	this.needsSwap = false;
+
+	this.oldClearColor = new THREE.Color();
+	this.oldClearAlpha = 1;
+
+	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+	this.scene  = new THREE.Scene();
+
+	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
+	this.scene.add( this.quad );
+
+	this.tempPulseColor1 = new THREE.Color();
+	this.tempPulseColor2 = new THREE.Color();
+	this.textureMatrix = new THREE.Matrix4();
+};
+
+THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
+
+	constructor: THREE.OutlinePass,
+
+	dispose: function() {
+		this.renderTargetMaskBuffer.dispose();
+		this.renderTargetDepthBuffer.dispose();
+		this.renderTargetMaskDownSampleBuffer.dispose();
+		this.renderTargetBlurBuffer1.dispose();
+		this.renderTargetBlurBuffer2.dispose();
+		this.renderTargetEdgeBuffer1.dispose();
+		this.renderTargetEdgeBuffer2.dispose();
+	},
+
+	setSize: function ( width, height ) {
+
+		this.renderTargetMaskBuffer.setSize(width, height );
+
+		var resx = Math.round(width/this.downSampleRatio);
+		var resy = Math.round(height/this.downSampleRatio);
+		this.renderTargetMaskDownSampleBuffer.setSize(resx, resy );
+		this.renderTargetBlurBuffer1.setSize(resx, resy );
+		this.renderTargetEdgeBuffer1.setSize(resx, resy );
+		this.separableBlurMaterial1.uniforms[ "texSize" ].value = new THREE.Vector2(resx, resy);
+
+	  resx = Math.round(resx/2);
+	  resy = Math.round(resy/2);
+
+		this.renderTargetBlurBuffer2.setSize(resx, resy );
+		this.renderTargetEdgeBuffer2.setSize(resx, resy );
+
+		this.separableBlurMaterial2.uniforms[ "texSize" ].value = new THREE.Vector2(resx, resy);
+	},
+
+	changeVisibilityOfSelectedObjects: function( bVisible ) {
+
+		var gatherSelectedMeshesCallBack = function( object ) {
+
+			if( object instanceof THREE.Mesh ) {
+				object.visible = bVisible;
+			}
+		}
+
+		for( var i=0; i<this.selectedObjects.length; i++ ) {
+
+			var selectedObject = this.selectedObjects[i];
+
+			selectedObject.traverse( gatherSelectedMeshesCallBack );
+		}
+	},
+
+	changeVisibilityOfNonSelectedObjects: function( bVisible ) {
+
+		var selectedMeshes = [];
+
+		var gatherSelectedMeshesCallBack = function( object ) {
+
+			if( object instanceof THREE.Mesh ) {
+
+				selectedMeshes.push(object);
+
+			}
+		}
+
+		for( var i=0; i<this.selectedObjects.length; i++ ) {
+
+			var selectedObject = this.selectedObjects[i];
+
+			selectedObject.traverse( gatherSelectedMeshesCallBack );
+		}
+
+		var VisibilityChangeCallBack = function( object ) {
+
+			if( object instanceof THREE.Mesh ) {
+
+				var bFound = false;
+
+				for( var i=0; i<selectedMeshes.length; i++ ) {
+
+					var selectedObjectId = selectedMeshes[i].id;
+
+					if(selectedObjectId === object.id) {
+						bFound = true;
+						break;
+					}
+
+				}
+				if(!bFound) {
+					var visibility = object.visible;
+					if( !bVisible || object.bVisible )
+						object.visible = bVisible;
+					object.bVisible = visibility;
+				}
+			}
+		}
+		this.renderScene.traverse( VisibilityChangeCallBack );
+	},
+
+	updateTextureMatrix: function() {
+
+		this.textureMatrix.set( 0.5, 0.0, 0.0, 0.5,
+														0.0, 0.5, 0.0, 0.5,
+														0.0, 0.0, 0.5, 0.5,
+														0.0, 0.0, 0.0, 1.0 );
+		this.textureMatrix.multiply( this.renderCamera.projectionMatrix );
+		this.textureMatrix.multiply( this.renderCamera.matrixWorldInverse );
+
+	},
+
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
+
+		if(this.selectedObjects.length === 0 )
+			return;
+
+		this.oldClearColor.copy( renderer.getClearColor() );
+		this.oldClearAlpha = renderer.getClearAlpha();
+		var oldAutoClear = renderer.autoClear;
+
+		renderer.autoClear = false;
+
+		if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
+
+		renderer.setClearColor( 0xffffff, 1 );
+
+		// Make selected objects invisible
+		this.changeVisibilityOfSelectedObjects(false);
+
+		// 1. Draw Non Selected objects in the depth buffer
+		this.renderScene.overrideMaterial = this.depthMaterial;
+		renderer.render( this.renderScene, this.renderCamera, this.renderTargetDepthBuffer, true );
+
+		// Make selected objects visible
+		this.changeVisibilityOfSelectedObjects(true);
+
+		// Update Texture Matrix for Depth compare
+		this.updateTextureMatrix();
+
+		// Make non selected objects invisible, and draw only the selected objects, by comparing the depth buffer of non selected objects
+		this.changeVisibilityOfNonSelectedObjects(false);
+		this.renderScene.overrideMaterial = this.prepareMaskMaterial;
+		this.prepareMaskMaterial.uniforms[ "cameraNearFar" ].value = new THREE.Vector2(this.renderCamera.near, this.renderCamera.far);
+		this.prepareMaskMaterial.uniforms[ "depthTexture" ].value = this.renderTargetDepthBuffer.texture;
+		this.prepareMaskMaterial.uniforms[ "textureMatrix" ].value = this.textureMatrix;
+		renderer.render( this.renderScene, this.renderCamera, this.renderTargetMaskBuffer, true );
+		this.renderScene.overrideMaterial = null;
+		this.changeVisibilityOfNonSelectedObjects(true);
+
+		// 2. Downsample to Half resolution
+		this.quad.material = this.materialCopy;
+		this.copyUniforms[ "tDiffuse" ].value = this.renderTargetMaskBuffer.texture;
+		renderer.render( this.scene, this.camera, this.renderTargetMaskDownSampleBuffer, true );
+
+		this.tempPulseColor1.copy( this.visibleEdgeColor );
+		this.tempPulseColor2.copy( this.hiddenEdgeColor );
+		if( this.pulsePeriod > 0 ) {
+			var scalar = ( 1 + 0.25 ) / 2 + Math.cos( performance.now() * 0.01/ this.pulsePeriod ) * ( 1.0 - 0.25 )/2
+			this.tempPulseColor1.multiplyScalar( scalar );
+			this.tempPulseColor2.multiplyScalar( scalar );
+		}
+
+		// 3. Apply Edge Detection Pass
+		this.quad.material = this.edgeDetectionMaterial;
+		this.edgeDetectionMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskDownSampleBuffer.texture;
+		this.edgeDetectionMaterial.uniforms[ "texSize" ].value = new THREE.Vector2(this.renderTargetMaskDownSampleBuffer.width, this.renderTargetMaskDownSampleBuffer.height);
+		this.edgeDetectionMaterial.uniforms[ "visibleEdgeColor" ].value = this.tempPulseColor1;
+		this.edgeDetectionMaterial.uniforms[ "hiddenEdgeColor" ].value = this.tempPulseColor2;
+		renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer1, true );
+
+		// 4. Apply Blur on Half res
+		this.quad.material = this.separableBlurMaterial1;
+		this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture;
+		this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX;
+		this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = this.edgeThickness;
+		renderer.render( this.scene, this.camera, this.renderTargetBlurBuffer1, true );
+		this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer1.texture;
+		this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY;
+		renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer1, true );
+
+		// Apply Blur on quarter res
+		this.quad.material = this.separableBlurMaterial2;
+		this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture;
+		this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX;
+		renderer.render( this.scene, this.camera, this.renderTargetBlurBuffer2, true );
+		this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer2.texture;
+		this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY;
+		renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer2, true );
+
+		// Blend it additively over the input texture
+		this.quad.material = this.overlayMaterial;
+		this.overlayMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskBuffer.texture;
+		this.overlayMaterial.uniforms[ "edgeTexture1" ].value = this.renderTargetEdgeBuffer1.texture;
+		this.overlayMaterial.uniforms[ "edgeTexture2" ].value = this.renderTargetEdgeBuffer2.texture;
+		this.overlayMaterial.uniforms[ "patternTexture" ].value = this.patternTexture;
+		this.overlayMaterial.uniforms[ "edgeStrength" ].value = this.edgeStrength;
+		this.overlayMaterial.uniforms[ "edgeGlow" ].value = this.edgeGlow;
+		this.overlayMaterial.uniforms[ "usePatternTexture" ].value = this.usePatternTexture;
+
+
+		if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
+
+		renderer.render( this.scene, this.camera, readBuffer, false );
+
+		renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
+		renderer.autoClear = oldAutoClear;
+	},
+
+	getPrepareMaskMaterial: function() {
+
+		return new THREE.ShaderMaterial( {
+
+			uniforms: {
+				"depthTexture": { value: null },
+				"cameraNearFar": { value: new THREE.Vector2( 0.5, 0.5 ) },
+				"textureMatrix" : { value: new THREE.Matrix4() }
+			},
+
+			vertexShader:
+				"varying vec2 vUv;\
+				varying vec4 projTexCoord;\
+				varying vec4 vPosition;\
+				uniform mat4 textureMatrix;\
+				void main() {\
+					vUv = uv;\
+					vPosition = modelViewMatrix * vec4( position, 1.0 );\
+					vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\
+					projTexCoord = textureMatrix * worldPosition;\
+					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+				}",
+
+			fragmentShader:
+				"#include <packing>\
+				varying vec2 vUv;\
+				varying vec4 vPosition;\
+				varying vec4 projTexCoord;\
+				uniform sampler2D depthTexture;\
+				uniform vec2 cameraNearFar;\
+				\
+				void main() {\
+					float depth = unpackRGBAToDepth(texture2DProj( depthTexture, projTexCoord ));\
+					float viewZ = -perspectiveDepthToViewZ( depth, cameraNearFar.x, cameraNearFar.y );\
+					float depthTest = (-vPosition.z > viewZ) ? 1.0 : 0.0;\
+					gl_FragColor = vec4(0.0, depthTest, 1.0, 1.0);\
+				}"
+		} );
+	},
+
+	getEdgeDetectionMaterial: function() {
+
+		return new THREE.ShaderMaterial( {
+
+			uniforms: {
+				"maskTexture": { value: null },
+				"texSize": { value: new THREE.Vector2( 0.5, 0.5 ) },
+				"visibleEdgeColor": { value: new THREE.Vector3( 1.0, 1.0, 1.0 ) },
+				"hiddenEdgeColor":  { value: new THREE.Vector3( 1.0, 1.0, 1.0 ) },
+			},
+
+			vertexShader:
+				"varying vec2 vUv;\n\
+				void main() {\n\
+					vUv = uv;\n\
+					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+				}",
+
+			fragmentShader:
+				"varying vec2 vUv;\
+				uniform sampler2D maskTexture;\
+				uniform vec2 texSize;\
+				uniform vec3 visibleEdgeColor;\
+				uniform vec3 hiddenEdgeColor;\
+				\
+				void main() {\n\
+					vec2 invSize = 1.0 / texSize;\
+					vec4 uvOffset = vec4(1.0, 0.0, 0.0, 1.0) * vec4(invSize, invSize);\
+					vec4 c1 = texture2D( maskTexture, vUv + uvOffset.xy);\
+					vec4 c2 = texture2D( maskTexture, vUv - uvOffset.xy);\
+					vec4 c3 = texture2D( maskTexture, vUv + uvOffset.yw);\
+					vec4 c4 = texture2D( maskTexture, vUv - uvOffset.yw);\
+					float diff1 = (c1.r - c2.r)*0.5;\
+					float diff2 = (c3.r - c4.r)*0.5;\
+					float d = length( vec2(diff1, diff2) );\
+					float a1 = min(c1.g, c2.g);\
+					float a2 = min(c3.g, c4.g);\
+					float visibilityFactor = min(a1, a2);\
+					vec3 edgeColor = 1.0 - visibilityFactor > 0.001 ? visibleEdgeColor : hiddenEdgeColor;\
+					gl_FragColor = vec4(edgeColor, 1.0) * vec4(d);\
+				}"
+		} );
+	},
+
+	getSeperableBlurMaterial: function(maxRadius) {
+
+		return new THREE.ShaderMaterial( {
+
+			defines: {
+				"MAX_RADIUS" : maxRadius,
+			},
+
+			uniforms: {
+				"colorTexture": { value: null },
+				"texSize": 	{ value: new THREE.Vector2( 0.5, 0.5 ) },
+				"direction": { value: new THREE.Vector2( 0.5, 0.5 ) },
+				"kernelRadius": { value: 1.0 }
+			},
+
+			vertexShader:
+				"varying vec2 vUv;\n\
+				void main() {\n\
+					vUv = uv;\n\
+					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+				}",
+
+			fragmentShader:
+				"#include <common>\
+				varying vec2 vUv;\
+				uniform sampler2D colorTexture;\
+				uniform vec2 texSize;\
+				uniform vec2 direction;\
+				uniform float kernelRadius;\
+				\
+				float gaussianPdf(in float x, in float sigma) {\
+					return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\
+				}\
+				void main() {\
+					vec2 invSize = 1.0 / texSize;\
+					float weightSum = gaussianPdf(0.0, kernelRadius);\
+					vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
+					vec2 delta = direction * invSize * kernelRadius/float(MAX_RADIUS);\
+					vec2 uvOffset = delta;\
+					for( int i = 1; i <= MAX_RADIUS; i ++ ) {\
+						float w = gaussianPdf(uvOffset.x, kernelRadius);\
+						vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\
+						vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\
+						diffuseSum += ((sample1 + sample2) * w);\
+						weightSum += (2.0 * w);\
+						uvOffset += delta;\
+					}\
+					gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\
+				}"
+		} );
+	},
+
+	getOverlayMaterial: function() {
+
+		return new THREE.ShaderMaterial( {
+
+			uniforms: {
+				"maskTexture": { value: null },
+				"edgeTexture1": { value: null },
+				"edgeTexture2": { value: null },
+				"patternTexture": { value: null },
+				"edgeStrength" : { value: 1.0 },
+				"edgeGlow" : { value: 1.0 },
+				"usePatternTexture" : { value: 0.0 }
+			},
+
+			vertexShader:
+				"varying vec2 vUv;\n\
+				void main() {\n\
+					vUv = uv;\n\
+					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+				}",
+
+			fragmentShader:
+				"varying vec2 vUv;\
+				uniform sampler2D maskTexture;\
+				uniform sampler2D edgeTexture1;\
+				uniform sampler2D edgeTexture2;\
+				uniform sampler2D patternTexture;\
+				uniform float edgeStrength;\
+				uniform float edgeGlow;\
+				uniform bool usePatternTexture;\
+				\
+				void main() {\
+					vec4 edgeValue1 = texture2D(edgeTexture1, vUv);\
+					vec4 edgeValue2 = texture2D(edgeTexture2, vUv);\
+					vec4 maskColor = texture2D(maskTexture, vUv);\
+					vec4 patternColor = texture2D(patternTexture, 6.0 * vUv);\
+					float visibilityFactor = 1.0 - maskColor.g > 0.0 ? 1.0 : 0.5;\
+					vec4 edgeValue = edgeValue1 + edgeValue2 * edgeGlow;\
+					vec4 finalColor = edgeStrength * maskColor.r * edgeValue;\
+					if(usePatternTexture)\
+						finalColor += + visibilityFactor * (1.0 - maskColor.r) * (1.0 - patternColor.r);\
+					gl_FragColor = finalColor;\
+				}",
+
+				blending: THREE.AdditiveBlending,
+				depthTest: false,
+				depthWrite: false,
+				transparent: true
+		} );
+	}
+
+} );
+
+THREE.OutlinePass.BlurDirectionX = new THREE.Vector2( 1.0, 0.0 );
+THREE.OutlinePass.BlurDirectionY = new THREE.Vector2( 0.0, 1.0 );

+ 332 - 0
examples/js/postprocessing/UnrealBloomPass.js

@@ -0,0 +1,332 @@
+/**
+ * @author spidersharma / http://eduperiment.com/
+ Inspired from Unreal Engine::
+ https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/
+ */
+
+THREE.UnrealBloomPass = function ( resolution, strength, radius, threshold ) {
+
+	THREE.Pass.call( this );
+
+	this.strength = ( strength !== undefined ) ? strength : 1;
+	this.radius = radius;
+	this.threshold = threshold;
+	this.resolution = ( resolution !== undefined ) ? new THREE.Vector2(resolution.x, resolution.y) : new THREE.Vector2(256, 256);
+
+	// render targets
+	var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
+	this.renderTargetsHorizontal = [];
+	this.renderTargetsVertical = [];
+	this.nMips = 5;
+	var resx = Math.round(this.resolution.x/2);
+	var resy = Math.round(this.resolution.y/2);
+
+	this.renderTargetBright = new THREE.WebGLRenderTarget( resx, resy, pars );
+	this.renderTargetBright.texture.generateMipmaps = false;
+
+	for( var i=0; i<this.nMips; i++) {
+
+		var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
+
+		renderTarget.texture.generateMipmaps = false;
+
+		this.renderTargetsHorizontal.push(renderTarget);
+
+		var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
+
+		renderTarget.texture.generateMipmaps = false;
+
+		this.renderTargetsVertical.push(renderTarget);
+
+		resx = Math.round(resx/2);
+
+		resy = Math.round(resy/2);
+	}
+
+	// luminosity high pass material
+
+	if ( THREE.LuminosityHighPassShader === undefined )
+		console.error( "THREE.UnrealBloomPass relies on THREE.LuminosityHighPassShader" );
+
+	var highPassShader = THREE.LuminosityHighPassShader;
+	this.highPassUniforms = THREE.UniformsUtils.clone( highPassShader.uniforms );
+
+	this.highPassUniforms[ "luminosityThreshold" ].value = threshold;
+	this.highPassUniforms[ "smoothWidth" ].value = 0.01;
+
+	this.materialHighPassFilter = new THREE.ShaderMaterial( {
+		uniforms: this.highPassUniforms,
+		vertexShader:  highPassShader.vertexShader,
+		fragmentShader: highPassShader.fragmentShader,
+		defines: {}
+	} );
+
+	// Gaussian Blur Materials
+	this.separableBlurMaterials = [];
+	var kernelSizeArray = [3, 5, 7, 9, 11];
+	var resx = Math.round(this.resolution.x/2);
+	var resy = Math.round(this.resolution.y/2);
+
+	for( var i=0; i<this.nMips; i++) {
+
+		this.separableBlurMaterials.push(this.getSeperableBlurMaterial(kernelSizeArray[i]));
+
+		this.separableBlurMaterials[i].uniforms[ "texSize" ].value = new THREE.Vector2(resx, resy);
+
+		resx = Math.round(resx/2);
+
+		resy = Math.round(resy/2);
+	}
+
+	// Composite material
+	this.compositeMaterial = this.getCompositeMaterial(this.nMips);
+	this.compositeMaterial.uniforms["blurTexture1"].value = this.renderTargetsVertical[0].texture;
+	this.compositeMaterial.uniforms["blurTexture2"].value = this.renderTargetsVertical[1].texture;
+	this.compositeMaterial.uniforms["blurTexture3"].value = this.renderTargetsVertical[2].texture;
+	this.compositeMaterial.uniforms["blurTexture4"].value = this.renderTargetsVertical[3].texture;
+	this.compositeMaterial.uniforms["blurTexture5"].value = this.renderTargetsVertical[4].texture;
+	this.compositeMaterial.uniforms["bloomStrength"].value = strength;
+	this.compositeMaterial.uniforms["bloomRadius"].value = 0.1;
+	this.compositeMaterial.needsUpdate = true;
+
+	var bloomFactors = [1.0, 0.8, 0.6, 0.4, 0.2];
+	this.compositeMaterial.uniforms["bloomFactors"].value = bloomFactors;
+	this.bloomTintColors = [new THREE.Vector3(1,1,1), new THREE.Vector3(1,1,1), new THREE.Vector3(1,1,1)
+												,new THREE.Vector3(1,1,1), new THREE.Vector3(1,1,1)];
+	this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors;
+
+	// copy material
+	if ( THREE.CopyShader === undefined )
+		console.error( "THREE.BloomPass relies on THREE.CopyShader" );
+
+	var copyShader = THREE.CopyShader;
+
+	this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
+	this.copyUniforms[ "opacity" ].value = 1.0;
+
+	this.materialCopy = new THREE.ShaderMaterial( {
+		uniforms: this.copyUniforms,
+		vertexShader: copyShader.vertexShader,
+		fragmentShader: copyShader.fragmentShader,
+		blending: THREE.AdditiveBlending,
+		depthTest: false,
+		depthWrite: false,
+		transparent: true
+	} );
+
+	this.enabled = true;
+	this.needsSwap = false;
+
+	this.oldClearColor = new THREE.Color();
+	this.oldClearAlpha = 1;
+
+	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+	this.scene  = new THREE.Scene();
+
+	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
+	this.scene.add( this.quad );
+
+};
+
+THREE.UnrealBloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
+
+	constructor: THREE.UnrealBloomPass,
+
+	dispose: function() {
+		for( var i=0; i< this.renderTargetsHorizontal.length(); i++) {
+			this.renderTargetsHorizontal[i].dispose();
+		}
+		for( var i=0; i< this.renderTargetsVertical.length(); i++) {
+			this.renderTargetsVertical[i].dispose();
+		}
+		this.renderTargetBright.dispose();
+	},
+
+	setSize: function ( width, height ) {
+
+		var resx = Math.round(width/2);
+		var resy = Math.round(height/2);
+
+		this.renderTargetBright.setSize(resx, resy);
+
+		for( var i=0; i<this.nMips; i++) {
+
+			this.renderTargetsHorizontal[i].setSize(resx, resy);
+			this.renderTargetsVertical[i].setSize(resx, resy);
+
+			this.separableBlurMaterials[i].uniforms[ "texSize" ].value = new THREE.Vector2(resx, resy);
+
+			resx = Math.round(resx/2);
+			resy = Math.round(resy/2);
+		}
+	},
+
+	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
+
+		this.oldClearColor.copy( renderer.getClearColor() );
+		this.oldClearAlpha = renderer.getClearAlpha();
+		var oldAutoClear = renderer.autoClear;
+		renderer.autoClear = false;
+
+		renderer.setClearColor( new THREE.Color( 0, 0, 0 ), 0 );
+
+		if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
+
+		// 1. Extract Bright Areas
+		this.highPassUniforms[ "tDiffuse" ].value = readBuffer.texture;
+		this.highPassUniforms[ "luminosityThreshold" ].value = this.threshold;
+		this.quad.material = this.materialHighPassFilter;
+		renderer.render( this.scene, this.camera, this.renderTargetBright, true );
+
+		// 2. Blur All the mips progressively
+		var inputRenderTarget = this.renderTargetBright;
+
+		for(var i=0; i<this.nMips; i++) {
+
+			this.quad.material = this.separableBlurMaterials[i];
+
+			this.separableBlurMaterials[i].uniforms[ "colorTexture" ].value = inputRenderTarget.texture;
+
+			this.separableBlurMaterials[i].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionX;
+
+			renderer.render( this.scene, this.camera, this.renderTargetsHorizontal[i], true );
+
+			this.separableBlurMaterials[i].uniforms[ "colorTexture" ].value = this.renderTargetsHorizontal[i].texture;
+
+			this.separableBlurMaterials[i].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionY;
+
+			renderer.render( this.scene, this.camera, this.renderTargetsVertical[i], true );
+
+			inputRenderTarget = this.renderTargetsVertical[i];
+		}
+
+		// Composite All the mips
+		this.quad.material = this.compositeMaterial;
+		this.compositeMaterial.uniforms["bloomStrength"].value = this.strength;
+		this.compositeMaterial.uniforms["bloomRadius"].value = this.radius;
+		this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors;
+		renderer.render( this.scene, this.camera, this.renderTargetsHorizontal[0], true );
+
+		// Blend it additively over the input texture
+		this.quad.material = this.materialCopy;
+		this.copyUniforms[ "tDiffuse" ].value = this.renderTargetsHorizontal[0].texture;
+
+		if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
+
+		renderer.render( this.scene, this.camera, readBuffer, false );
+
+		renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
+		renderer.autoClear = oldAutoClear;
+	},
+
+	getSeperableBlurMaterial: function(kernelRadius) {
+
+		return new THREE.ShaderMaterial( {
+
+			defines: {
+				"KERNEL_RADIUS" : kernelRadius,
+				"SIGMA" : kernelRadius
+			},
+
+			uniforms: {
+				"colorTexture": { value: null },
+				"texSize": 				{ value: new THREE.Vector2( 0.5, 0.5 ) },
+				"direction": 				{ value: new THREE.Vector2( 0.5, 0.5 ) },
+			},
+
+			vertexShader:
+				"varying vec2 vUv;\n\
+				void main() {\n\
+					vUv = uv;\n\
+					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+				}",
+
+			fragmentShader:
+				"#include <common>\
+				varying vec2 vUv;\n\
+				uniform sampler2D colorTexture;\n\
+				uniform vec2 texSize;\
+				uniform vec2 direction;\
+				\
+				float gaussianPdf(in float x, in float sigma) {\
+					return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\
+				}\
+				void main() {\n\
+					vec2 invSize = 1.0 / texSize;\
+					float fSigma = float(SIGMA);\
+					float weightSum = gaussianPdf(0.0, fSigma);\
+					vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
+					for( int i = 1; i < KERNEL_RADIUS; i ++ ) {\
+						float x = float(i);\
+						float w = gaussianPdf(x, fSigma);\
+						vec2 uvOffset = direction * invSize * x;\
+						vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\
+						vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\
+						diffuseSum += (sample1 + sample2) * w;\
+						weightSum += 2.0 * w;\
+					}\
+					gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n\
+				}"
+		} );
+	},
+
+	getCompositeMaterial: function(nMips) {
+
+		return new THREE.ShaderMaterial( {
+
+			defines:{
+				"NUM_MIPS" : nMips
+			},
+
+			uniforms: {
+				"blurTexture1": { value: null },
+				"blurTexture2": { value: null },
+				"blurTexture3": { value: null },
+				"blurTexture4": { value: null },
+				"blurTexture5": { value: null },
+				"dirtTexture": { value: null },
+				"bloomStrength" : { value: 1.0 },
+				"bloomFactors" : { value: null },
+				"bloomTintColors" : { value: null },
+				"bloomRadius" : { value: 0.0 }
+			},
+
+			vertexShader:
+				"varying vec2 vUv;\n\
+				void main() {\n\
+					vUv = uv;\n\
+					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+				}",
+
+			fragmentShader:
+				"varying vec2 vUv;\
+				uniform sampler2D blurTexture1;\
+				uniform sampler2D blurTexture2;\
+				uniform sampler2D blurTexture3;\
+				uniform sampler2D blurTexture4;\
+				uniform sampler2D blurTexture5;\
+				uniform sampler2D dirtTexture;\
+				uniform float bloomStrength;\
+				uniform float bloomRadius;\
+				uniform float bloomFactors[NUM_MIPS];\
+				uniform vec3 bloomTintColors[NUM_MIPS];\
+				\
+				float lerpBloomFactor(const in float factor) { \
+					float mirrorFactor = 1.2 - factor;\
+					return mix(factor, mirrorFactor, bloomRadius);\
+				}\
+				\
+				void main() {\
+					gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) + \
+					 							 lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) + \
+												 lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) + \
+												 lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) + \
+												 lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );\
+				}"
+		} );
+	}
+
+} );
+
+THREE.UnrealBloomPass.BlurDirectionX = new THREE.Vector2( 1.0, 0.0 );
+THREE.UnrealBloomPass.BlurDirectionY = new THREE.Vector2( 0.0, 1.0 );

+ 64 - 0
examples/js/shaders/LuminosityHighPassShader.js

@@ -0,0 +1,64 @@
+/**
+ * @author bhouston / http://clara.io/
+ *
+ * Luminosity
+ * http://en.wikipedia.org/wiki/Luminosity
+ */
+
+THREE.LuminosityHighPassShader = {
+
+  shaderID: "luminosityHighPass",
+
+	uniforms: {
+
+		"tDiffuse": { type: "t", value: null },
+		"luminosityThreshold": { type: "f", value: 1.0 },
+		"smoothWidth": { type: "f", value: 1.0 },
+		"defaultColor": { type: "c", value: new THREE.Color( 0x000000 ) },
+		"defaultOpacity":  { type: "f", value: 0.0 },
+
+	},
+
+	vertexShader: [
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vUv = uv;",
+
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+		"}"
+
+	].join("\n"),
+
+	fragmentShader: [
+
+		"uniform sampler2D tDiffuse;",
+		"uniform vec3 defaultColor;",
+		"uniform float defaultOpacity;",
+		"uniform float luminosityThreshold;",
+		"uniform float smoothWidth;",
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vec4 texel = texture2D( tDiffuse, vUv );",
+
+			"vec3 luma = vec3( 0.299, 0.587, 0.114 );",
+
+			"float v = dot( texel.xyz, luma );",
+
+			"vec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );",
+
+			"float alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );",
+
+			"gl_FragColor = mix( outputColor, texel, alpha );",
+
+		"}"
+
+	].join("\n")
+
+};

BIN
examples/textures/tri_pattern.jpg


+ 1 - 1
examples/webgl_animation_cloth.html

@@ -30,7 +30,7 @@
 
 	<body>
 		<div id="info">Simple Cloth Simulation<br/>
-			Verlet integration with Constrains relaxation<br/>
+			Verlet integration with relaxed constraints<br/>
 			<a onclick="wind = !wind;">Wind</a> |
 			<a onclick="sphere.visible = !sphere.visible;">Ball</a> |
 			<a onclick="togglePins();">Pins</a>

+ 4 - 5
examples/webgl_camera_logarithmicdepthbuffer.html

@@ -150,12 +150,11 @@
 
 				// Resize border allows the user to easily compare effects of logarithmic depth buffer over the whole scene
 				border = document.getElementById( 'renderer_border' );
-				border.addEventListener("mousedown", onBorderMouseDown);
+				border.addEventListener( 'mousedown', onBorderMouseDown );
 
-				window.addEventListener( 'resize', onWindowResize, false );
-				window.addEventListener( 'mousewheel', onMouseWheel, false );
-				window.addEventListener( 'MozMousePixelScroll', onMouseWheel, false );
 				window.addEventListener( 'mousemove', onMouseMove, false );
+				window.addEventListener( 'resize', onWindowResize, false );
+				window.addEventListener( 'wheel', onMouseWheel, false );
 
 			}
 
@@ -340,7 +339,7 @@
 				mouse[1] = ev.clientY / window.innerHeight;
 			}
 			function onMouseWheel(ev) {
-				var amount = -ev.wheelDeltaY || ev.detail;
+				var amount = ev.deltaY;
 				if ( amount === 0 ) return;
 				var dir = amount / Math.abs(amount);
 				zoomspeed = dir/10;

+ 10 - 10
examples/webgl_lights_physical.html

@@ -41,9 +41,9 @@
 		</div>
 
 		<script src="../build/three.js"></script>
-		<script src="../examples/js/libs/stats.min.js"></script>
-		<script src="../examples/js/libs/dat.gui.min.js"></script>
-		<script src="../examples/js/controls/OrbitControls.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/Detector.js"></script>
 
 		<script>
@@ -134,7 +134,7 @@
 					bumpScale: 0.0005,
 				});
 				var textureLoader = new THREE.TextureLoader();
-				textureLoader.load( "../examples/textures/hardwood2_diffuse.jpg", function( map ) {
+				textureLoader.load( "textures/hardwood2_diffuse.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -142,7 +142,7 @@
 					floorMat.map = map;
 					floorMat.needsUpdate = true;
 				} );
-				textureLoader.load( "../examples/textures/hardwood2_bump.jpg", function( map ) {
+				textureLoader.load( "textures/hardwood2_bump.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -150,7 +150,7 @@
 					floorMat.bumpMap = map;
 					floorMat.needsUpdate = true;
 				} );
-				textureLoader.load( "../examples/textures/hardwood2_roughness.jpg", function( map ) {
+				textureLoader.load( "textures/hardwood2_roughness.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -165,7 +165,7 @@
 					bumpScale: 0.002,
 					metalness: 0.2
 				});
-				textureLoader.load( "../examples/textures/brick_diffuse.jpg", function( map ) {
+				textureLoader.load( "textures/brick_diffuse.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -173,7 +173,7 @@
 					cubeMat.map = map;
 					cubeMat.needsUpdate = true;
 				} );
-				textureLoader.load( "../examples/textures/brick_bump.jpg", function( map ) {
+				textureLoader.load( "textures/brick_bump.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -187,12 +187,12 @@
 					roughness: 0.5,
 					metalness: 1.0
 				});
-				textureLoader.load( "../examples/textures/planets/earth_atmos_2048.jpg", function( map ) {
+				textureLoader.load( "textures/planets/earth_atmos_2048.jpg", function( map ) {
 					map.anisotropy = 4;
 					ballMat.map = map;
 					ballMat.needsUpdate = true;
 				} );
-				textureLoader.load( "../examples/textures/planets/earth_specular_2048.jpg", function( map ) {
+				textureLoader.load( "textures/planets/earth_specular_2048.jpg", function( map ) {
 					map.anisotropy = 4;
 					ballMat.metalnessMap = map;
 					ballMat.needsUpdate = true;

+ 3 - 3
examples/webgl_lights_spotlights.html

@@ -40,9 +40,9 @@
 		</div>
 
 		<script src="../build/three.js"></script>
-		<script src="../examples/js/libs/dat.gui.min.js"></script>
-		<script src="../examples/js/libs/tween.min.js"></script>
-		<script src="../examples/js/controls/OrbitControls.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+		<script src="js/libs/tween.min.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/Detector.js"></script>
 
 		<script>

+ 3 - 21
examples/webgl_materials_cubemap_dynamic2.html

@@ -100,8 +100,8 @@
 				//
 
 				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
-				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
-				document.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);
+				document.addEventListener( 'wheel', onDocumentMouseWheel, false );
+
 				window.addEventListener( 'resize', onWindowResized, false );
 
 				onWindowResized( null );
@@ -145,25 +145,7 @@
 
 			function onDocumentMouseWheel( event ) {
 
-				// WebKit
-
-				if ( event.wheelDeltaY ) {
-
-					fov -= event.wheelDeltaY * 0.05;
-
-				// Opera / Explorer 9
-
-				} else if ( event.wheelDelta ) {
-
-					fov -= event.wheelDelta * 0.05;
-
-				// Firefox
-
-				} else if ( event.detail ) {
-
-					fov += event.detail * 1.0;
-
-				}
+				fov += event.deltaY * 0.05;
 
 				camera.projectionMatrix.makePerspective( fov, window.innerWidth / window.innerHeight, 1, 1100 );
 

+ 15 - 16
examples/webgl_materials_transparency.html

@@ -31,22 +31,21 @@
 		<div id="info"><a href="http://threejs.org" target="_blank">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)<br /> using RGBA8 Buffers by <a href="http://clara.io/" target="_blank">Ben Houston</a>.</div>
 
 		<script src="../build/three.js"></script>
-		<script src="../examples/js/controls/OrbitControls.js"></script>
-		<script src="../src/loaders/BinaryTextureLoader.js"></script>
-
-		<script src="../examples/js/Detector.js"></script>
-		<script src="../examples/js/libs/stats.min.js"></script>
-
-		<script src="../examples/js/libs/dat.gui.min.js"></script>
-
-		<script src="../examples/js/postprocessing/EffectComposer.js"></script>
-		<script src="../examples/js/postprocessing/RenderPass.js"></script>
-		<script src="../examples/js/postprocessing/MaskPass.js"></script>
-		<script src="../examples/js/postprocessing/ShaderPass.js"></script>
-		<script src="../examples/js/shaders/CopyShader.js"></script>
-		<script src="../examples/js/shaders/FXAAShader.js"></script>
-		<script src="../examples/js/postprocessing/BloomPass.js"></script>
-		<script src="../examples/js/shaders/ConvolutionShader.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<script src="js/postprocessing/EffectComposer.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+		<script src="js/postprocessing/MaskPass.js"></script>
+		<script src="js/postprocessing/ShaderPass.js"></script>
+		<script src="js/shaders/CopyShader.js"></script>
+		<script src="js/shaders/FXAAShader.js"></script>
+		<script src="js/postprocessing/BloomPass.js"></script>
+		<script src="js/shaders/ConvolutionShader.js"></script>
 
 		<script>
 

+ 17 - 24
examples/webgl_materials_variations_basic.html

@@ -40,7 +40,7 @@
 
 			var container, stats;
 
-			var camera, scene, renderer, controls, objects = [];
+			var camera, scene, renderer, controls;
 			var particleLight;
 
 			var loader = new THREE.FontLoader();
@@ -87,23 +87,21 @@
 
 				var geometry = new THREE.SphereBufferGeometry( sphereRadius, 32, 16 );
 
-				for( var alpha = 0; alpha <= 1.0; alpha += stepSize ) {
+				for ( var alpha = 0; alpha <= 1.0; alpha += stepSize ) {
 
-					var baseColor = new THREE.Color().setHSL( alpha, 0.5, 0.5 );
+					for ( var beta = 0; beta <= 1.0; beta += stepSize ) {
 
-					if( alpha >= 0.5 ) {
-						reflectionCube = null;
-					}
-
-					for( var beta = 0; beta <= 1.0; beta += stepSize ) {
-
-						var reflectivity = beta;
-
-						for( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
+						for ( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
 
-							var diffuseColor = baseColor.clone().multiplyScalar( gamma );
+							var diffuseColor = new THREE.Color().setHSL( alpha, 0.5, gamma * 0.5 );
 
-							var material = new THREE.MeshBasicMaterial( { map: imgTexture, color: diffuseColor, reflectivity: reflectivity, shading: THREE.SmoothShading, envMap: reflectionCube } )
+							var material = new THREE.MeshBasicMaterial( {
+								map: imgTexture,
+								color: diffuseColor,
+								reflectivity: beta,
+								shading: THREE.SmoothShading,
+								envMap: alpha < 0.5 ? reflectionCube : null
+							} );
 
 							var mesh = new THREE.Mesh( geometry, material );
 
@@ -111,14 +109,16 @@
 							mesh.position.y = beta * 400 - 200;
 							mesh.position.z = gamma * 400 - 200;
 
-							objects.push( mesh );
-
 							scene.add( mesh );
+
 						}
+
 					}
+
 				}
 
 				function addLabel( name, location ) {
+
 					var textGeo = new THREE.TextGeometry( name, {
 
 						font: font,
@@ -133,6 +133,7 @@
 					var textMesh = new THREE.Mesh( textGeo, textMaterial );
 					textMesh.position.copy( location );
 					scene.add( textMesh );
+
 				}
 
 				addLabel( "+hue", new THREE.Vector3( -350, 0, 0 ) );
@@ -213,14 +214,6 @@
 
 				camera.lookAt( scene.position );
 
-				for ( var i = 0, l = objects.length; i < l; i ++ ) {
-
-					var object = objects[ i ];
-
-					object.rotation.y += 0.005;
-
-				}
-
 				particleLight.position.x = Math.sin( timer * 7 ) * 300;
 				particleLight.position.y = Math.cos( timer * 5 ) * 400;
 				particleLight.position.z = Math.cos( timer * 3 ) * 300;

+ 16 - 30
examples/webgl_materials_variations_lambert.html

@@ -40,7 +40,7 @@
 
 			var container, stats;
 
-			var camera, scene, renderer, controls, objects = [];
+			var camera, scene, renderer, controls;
 			var particleLight;
 
 			var loader = new THREE.FontLoader();
@@ -87,29 +87,20 @@
 
 				var geometry = new THREE.SphereBufferGeometry( sphereRadius, 32, 16 );
 
-				for( var alpha = 0, alphaIndex = 0; alpha <= 1.0; alpha += stepSize, alphaIndex ++ ) {
+				for ( var alpha = 0; alpha <= 1.0; alpha += stepSize ) {
 
-					var baseColor = new THREE.Color().setHSL( alpha, 0.5, 0.5 );
+					for ( var beta = 0; beta <= 1.0; beta += stepSize ) {
 
-					if( alpha >= 0.5 ) {
-						reflectionCube = null;
-					}
-
-					for( var beta = 0, betaIndex = 0; beta <= 1.0; beta += stepSize, betaIndex ++ ) {
-
-						var reflectivity = beta;
-
-						var side = THREE.FrontSide;
-						if( ( betaIndex % 2 ) === 0 ) {
-							side = THREE.DoubleSide;
-						}
+						for ( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
 
-						for( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
+							var diffuseColor = new THREE.Color().setHSL( alpha, 0.5, gamma * 0.5 );
 
-							var diffuseColor = baseColor.clone().multiplyScalar( gamma );
-
-							var material = new THREE.MeshLambertMaterial( { map: imgTexture, color: diffuseColor,
-								 reflectivity: reflectivity, envMap: reflectionCube, side: side } )
+							var material = new THREE.MeshLambertMaterial( {
+								map: imgTexture,
+								color: diffuseColor,
+								reflectivity: beta,
+								envMap: alpha < 0.5 ? reflectionCube : null
+							} );
 
 							var mesh = new THREE.Mesh( geometry, material );
 
@@ -117,14 +108,16 @@
 							mesh.position.y = beta * 400 - 200;
 							mesh.position.z = gamma * 400 - 200;
 
-							objects.push( mesh );
-
 							scene.add( mesh );
+
 						}
+
 					}
+
 				}
 
 				function addLabel( name, location ) {
+
 					var textGeo = new THREE.TextGeometry( name, {
 
 						font: font,
@@ -139,6 +132,7 @@
 					var textMesh = new THREE.Mesh( textGeo, textMaterial );
 					textMesh.position.copy( location );
 					scene.add( textMesh );
+
 				}
 
 				addLabel( "+hue", new THREE.Vector3( -350, 0, 0 ) );
@@ -219,14 +213,6 @@
 
 				camera.lookAt( scene.position );
 
-				for ( var i = 0, l = objects.length; i < l; i ++ ) {
-
-					var object = objects[ i ];
-
-					object.rotation.y += 0.005;
-
-				}
-
 				particleLight.position.x = Math.sin( timer * 7 ) * 300;
 				particleLight.position.y = Math.cos( timer * 5 ) * 400;
 				particleLight.position.z = Math.cos( timer * 3 ) * 300;

+ 22 - 30
examples/webgl_materials_variations_phong.html

@@ -28,7 +28,6 @@
 		<div id="container"></div>
 		<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - Phong Material Variantions by <a href="http://clara.io/" target="_blank">Ben Houston</a>.</div>
 
-
 		<script src="../build/three.js"></script>
 		<script src="js/controls/OrbitControls.js"></script>
 
@@ -41,7 +40,7 @@
 
 			var container, stats;
 
-			var camera, scene, renderer, controls, objects = [];
+			var camera, scene, renderer, controls;
 			var particleLight;
 
 			var loader = new THREE.FontLoader();
@@ -88,31 +87,30 @@
 
 				var geometry = new THREE.SphereBufferGeometry( sphereRadius, 32, 16 );
 
-
-				var localReflectionCube;
-
-				for( var alpha = 0, alphaIndex = 0; alpha <= 1.0; alpha += stepSize, alphaIndex ++ ) {
-
-					if( alphaIndex % 2 === 0 ) {
-						localReflectionCube = null;
-					}
-					else {
-						localReflectionCube = reflectionCube;
-					}
+				for ( var alpha = 0, alphaIndex = 0; alpha <= 1.0; alpha += stepSize, alphaIndex ++ ) {
 
 					var specularShininess = Math.pow( 2, alpha * 10 );
 
-					for( var beta = 0; beta <= 1.0; beta += stepSize ) {
+					for ( var beta = 0; beta <= 1.0; beta += stepSize ) {
 
 						var specularColor = new THREE.Color( beta * 0.2, beta * 0.2, beta * 0.2 );
-						var reflectivity = beta;
 
-						for( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
+						for ( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
 
 							// basic monochromatic energy preservation
-							var diffuseColor = new THREE.Color( 0, 0, gamma ).multiplyScalar( 1 - beta * 0.2 );
-
-							var material = new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: diffuseColor, specular: specularColor, reflectivity: reflectivity, shininess: specularShininess, shading: THREE.SmoothShading, envMap: localReflectionCube  } )
+							var diffuseColor = new THREE.Color().setHSL( alpha, 0.5, gamma * 0.5 ).multiplyScalar( 1 - beta * 0.2 );
+
+							var material = new THREE.MeshPhongMaterial( {
+								map: imgTexture,
+								bumpMap: imgTexture,
+								bumpScale: bumpScale,
+								color: diffuseColor,
+								specular: specularColor,
+								reflectivity: beta,
+								shininess: specularShininess,
+								shading: THREE.SmoothShading,
+								envMap: alphaIndex % 2 === 0 ? null : reflectionCube
+							} );
 
 							var mesh = new THREE.Mesh( geometry, material );
 
@@ -120,15 +118,16 @@
 							mesh.position.y = beta * 400 - 200;
 							mesh.position.z = gamma * 400 - 200;
 
-							objects.push( mesh );
-
 							scene.add( mesh );
+
 						}
+
 					}
-				}
 
+				}
 
 				function addLabel( name, location ) {
+
 					var textGeo = new THREE.TextGeometry( name, {
 
 						font: font,
@@ -143,6 +142,7 @@
 					var textMesh = new THREE.Mesh( textGeo, textMaterial );
 					textMesh.position.copy( location );
 					scene.add( textMesh );
+
 				}
 
 				addLabel( "-shininess", new THREE.Vector3( -350, 0, 0 ) );
@@ -221,14 +221,6 @@
 
 				camera.lookAt( scene.position );
 
-				for ( var i = 0, l = objects.length; i < l; i ++ ) {
-
-					var object = objects[ i ];
-
-					object.rotation.y += 0.005;
-
-				}
-
 				particleLight.position.x = Math.sin( timer * 7 ) * 300;
 				particleLight.position.y = Math.cos( timer * 5 ) * 400;
 				particleLight.position.z = Math.cos( timer * 3 ) * 300;

+ 12 - 21
examples/webgl_materials_variations_physical.html

@@ -40,7 +40,7 @@
 
 			var container, stats;
 
-			var camera, scene, renderer, controls, objects = [];
+			var camera, scene, renderer, controls;
 			var particleLight;
 
 			var loader = new THREE.FontLoader();
@@ -78,25 +78,21 @@
 
 				var geometry = new THREE.SphereBufferGeometry( sphereRadius, 32, 16 );
 
-				for ( var alpha = 0, alphaIndex = 0; alpha <= 1.0; alpha += stepSize, alphaIndex ++ ) {
-
-					var clearCoat = 1.0 - alpha;
+				for ( var alpha = 0; alpha <= 1.0; alpha += stepSize ) {
 
 					for ( var beta = 0; beta <= 1.0; beta += stepSize ) {
 
-						var clearCoatRoughness = 1 - beta;
-
 						for ( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
 
-							var reflectivity = 1 - gamma;
+							var diffuseColor = new THREE.Color().setHSL( alpha, 0.5, 0.5 );
 
 							var material = new THREE.MeshPhysicalMaterial( {
-								color: 0x880000,
+								color: diffuseColor,
 								metalness: 0,
 								roughness: 0.5,
-								clearCoat: clearCoat,
-								clearCoatRoughness: clearCoatRoughness,
-								reflectivity: reflectivity,
+								clearCoat:  1.0 - alpha,
+								clearCoatRoughness: 1.0 - beta,
+								reflectivity: 1.0 - gamma,
 								envMap: reflectionCube
 							} );
 
@@ -106,14 +102,16 @@
 							mesh.position.y = beta * 400 - 200;
 							mesh.position.z = gamma * 400 - 200;
 
-							objects.push( mesh );
-
 							scene.add( mesh );
+
 						}
+
 					}
+
 				}
 
 				function addLabel( name, location ) {
+
 					var textGeo = new THREE.TextGeometry( name, {
 
 						font: font,
@@ -128,6 +126,7 @@
 					var textMesh = new THREE.Mesh( textGeo, textMaterial );
 					textMesh.position.copy( location );
 					scene.add( textMesh );
+
 				}
 
 				addLabel( "+clearCoat", new THREE.Vector3( -350, 0, 0 ) );
@@ -205,14 +204,6 @@
 
 				camera.lookAt( scene.position );
 
-				for ( var i = 0, l = objects.length; i < l; i ++ ) {
-
-					var object = objects[ i ];
-
-					object.rotation.y += 0.005;
-
-				}
-
 				particleLight.position.x = Math.sin( timer * 7 ) * 300;
 				particleLight.position.y = Math.cos( timer * 5 ) * 400;
 				particleLight.position.z = Math.cos( timer * 3 ) * 300;

+ 21 - 30
examples/webgl_materials_variations_standard.html

@@ -40,7 +40,7 @@
 
 			var container, stats;
 
-			var camera, scene, renderer, controls, objects = [];
+			var camera, scene, renderer, controls;
 			var particleLight;
 
 			var loader = new THREE.FontLoader();
@@ -87,29 +87,25 @@
 
 				var geometry = new THREE.SphereBufferGeometry( sphereRadius, 32, 16 );
 
-				var localReflectionCube;
+				for ( var alpha = 0, alphaIndex = 0; alpha <= 1.0; alpha += stepSize, alphaIndex ++ ) {
 
-				for( var alpha = 0, alphaIndex = 0; alpha <= 1.0; alpha += stepSize, alphaIndex ++ ) {
+					for ( var beta = 0; beta <= 1.0; beta += stepSize ) {
 
-					var roughness = 1.0 - alpha;
-
-					if( alphaIndex % 2 === 0 ) {
-						localReflectionCube = null;
-					}
-					else {
-						localReflectionCube = reflectionCube;
-					}
-
-					for( var beta = 0; beta <= 1.0; beta += stepSize ) {
-
-						var metalness = beta;
-
-						for( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
+						for ( var gamma = 0; gamma <= 1.0; gamma += stepSize ) {
 
 							// basic monochromatic energy preservation
-							var diffuseColor = new THREE.Color( gamma, 0, 0 ).multiplyScalar( 1 - 0.08 );
-
-							var material = new THREE.MeshStandardMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: diffuseColor, metalness: metalness, roughness: roughness, shading: THREE.SmoothShading, envMap: localReflectionCube } )
+							var diffuseColor = new THREE.Color().setHSL( alpha, 0.5, gamma * 0.5 );
+
+							var material = new THREE.MeshStandardMaterial( {
+								map: imgTexture,
+								bumpMap: imgTexture,
+								bumpScale: bumpScale,
+								color: diffuseColor,
+								metalness: beta,
+								roughness: 1.0 - alpha,
+								shading: THREE.SmoothShading,
+								envMap: alphaIndex % 2 === 0 ? null : reflectionCube
+							} )
 
 							var mesh = new THREE.Mesh( geometry, material );
 
@@ -117,14 +113,16 @@
 							mesh.position.y = beta * 400 - 200;
 							mesh.position.z = gamma * 400 - 200;
 
-							objects.push( mesh );
-
 							scene.add( mesh );
+
 						}
+
 					}
+
 				}
 
 				function addLabel( name, location ) {
+
 					var textGeo = new THREE.TextGeometry( name, {
 
 						font: font,
@@ -139,6 +137,7 @@
 					var textMesh = new THREE.Mesh( textGeo, textMaterial );
 					textMesh.position.copy( location );
 					scene.add( textMesh );
+
 				}
 
 				addLabel( "+roughness", new THREE.Vector3( -350, 0, 0 ) );
@@ -216,14 +215,6 @@
 
 				camera.lookAt( scene.position );
 
-				for ( var i = 0, l = objects.length; i < l; i ++ ) {
-
-					var object = objects[ i ];
-
-					object.rotation.y += 0.005;
-
-				}
-
 				particleLight.position.x = Math.sin( timer * 7 ) * 300;
 				particleLight.position.y = Math.cos( timer * 5 ) * 400;
 				particleLight.position.z = Math.cos( timer * 3 ) * 300;

+ 0 - 32
examples/webgl_multiple_canvases_circle.html

@@ -306,7 +306,6 @@
 					container.appendChild( renderer.domElement );
 
 					document.addEventListener( 'mousemove', onDocumentMouseMove, false );
-					document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
 
 				}
 
@@ -317,37 +316,6 @@
 
 				}
 
-				function onDocumentMouseWheel ( event ) {
-
-					var delta = 0;
-
-					if ( event.wheelDelta ) {
-
-						delta = event.wheelDelta / 120;
-						if ( window.opera ) delta = -delta;
-
-					} else if ( event.detail ) {
-
-						delta = -event.detail / 3;
-
-					}
-
-					if ( delta ) {
-
-						if ( delta < 0 ) {
-
-							cameraZ -= 200;
-
-						} else {
-
-							cameraZ += 200;
-
-						}
-
-					}
-
-				}
-
 				this.animate = function() {
 
 					render();

+ 1 - 1
examples/webgl_multiple_elements.html

@@ -74,7 +74,7 @@
 		</div>
 
 		<script src="../build/three.js"></script>
-		<script src="../examples/js/controls/OrbitControls.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
 
 		<script src="js/Detector.js"></script>
 

+ 2 - 21
examples/webgl_panorama_dualfisheye.html

@@ -110,8 +110,7 @@
 				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
 				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
 				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
-				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
-				document.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false );
+				document.addEventListener( 'wheel', onDocumentMouseWheel, false );
 
 				//
 
@@ -161,25 +160,7 @@
 
 			function onDocumentMouseWheel( event ) {
 
-				// WebKit
-
-				if ( event.wheelDeltaY ) {
-
-					distance -= event.wheelDeltaY * 0.05;
-
-				// Opera / Explorer 9
-
-				} else if ( event.wheelDelta ) {
-
-					distance -= event.wheelDelta * 0.05;
-
-				// Firefox
-
-				} else if ( event.detail ) {
-
-					distance += event.detail * 1.0;
-
-				}
+				distance += event.deltaY * 0.05;
 
 			}
 

+ 2 - 22
examples/webgl_panorama_equirectangular.html

@@ -80,8 +80,7 @@
 				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
 				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
 				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
-				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
-				document.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);
+				document.addEventListener( 'wheel', onDocumentMouseWheel, false );
 
 				//
 
@@ -169,26 +168,7 @@
 
 			function onDocumentMouseWheel( event ) {
 
-				// WebKit
-
-				if ( event.wheelDeltaY ) {
-
-					camera.fov -= event.wheelDeltaY * 0.05;
-
-				// Opera / Explorer 9
-
-				} else if ( event.wheelDelta ) {
-
-					camera.fov -= event.wheelDelta * 0.05;
-
-				// Firefox
-
-				} else if ( event.detail ) {
-
-					camera.fov += event.detail * 1.0;
-
-				}
-
+				camera.fov += event.deltaY * 0.05;
 				camera.updateProjectionMatrix();
 
 			}

+ 561 - 0
examples/webgl_physics_convex_break.html

@@ -0,0 +1,561 @@
+<html lang="en">
+    <head>
+        <title>Convex object breaking example</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: #61443e;
+                font-family:Monospace;
+                font-size:13px;
+                text-align:center;
+
+                background-color: #bfd1e5;
+                margin: 0px;
+                overflow: hidden;
+            }
+
+            #info {
+                position: absolute;
+                top: 0px; width: 100%;
+                padding: 5px;
+            }
+
+            a {
+                color: #a06851;
+            }
+
+        </style>
+    </head>
+    <body>
+	<div id="info">Physics threejs demo with convex objects breaking in real time<br />Press mouse to throw balls and move the camera.</div>
+        <div id="container"><br /><br /><br /><br /><br />Loading...</div>
+
+	<script src="../build/three.js"></script>
+	<script src="js/libs/ammo.js"></script>
+	<script src="js/controls/OrbitControls.js"></script>
+        <script src="js/Detector.js"></script>
+	<script src="js/libs/stats.min.js"></script>
+	<script src="js/ConvexObjectBreaker.js"></script>
+	<script src="js/geometries/ConvexGeometry.js"></script>
+
+        <script>
+
+		// Detects webgl
+		if ( ! Detector.webgl ) {
+		    Detector.addGetWebGLMessage();
+		    document.getElementById( 'container' ).innerHTML = "";
+		}
+
+		// - Global variables -
+
+		// Graphics variables
+		var container, stats;
+		var camera, controls, scene, renderer;
+		var textureLoader;
+		var clock = new THREE.Clock();
+
+		var mouseCoords = new THREE.Vector2();
+		var raycaster = new THREE.Raycaster();
+		var ballMaterial = new THREE.MeshPhongMaterial( { color: 0x202020 } );
+
+		// Physics variables
+		var gravityConstant = 7.8;
+		var collisionConfiguration;
+		var dispatcher;
+		var broadphase;
+		var solver;
+		var physicsWorld;
+		var margin = 0.05;
+
+		var convexBreaker = new THREE.ConvexObjectBreaker();
+
+		// Rigid bodies include all movable objects
+		var rigidBodies = [];
+
+		var pos = new THREE.Vector3();
+		var quat = new THREE.Quaternion();
+		var transformAux1 = new Ammo.btTransform();
+		var tempBtVec3_1 = new Ammo.btVector3( 0, 0, 0 );
+
+		var time = 0;
+
+		var objectsToRemove = [];
+		for ( var i = 0; i < 500; i++ ) {
+		    objectsToRemove[ i ] = null;
+		}
+		var numObjectsToRemove = 0;
+
+		var impactPoint = new THREE.Vector3();
+		var impactNormal = new THREE.Vector3();
+
+		// - Main code -
+
+		init();
+		animate();
+
+
+		// - Functions -
+
+		function init() {
+
+			initGraphics();
+
+			initPhysics();
+
+			createObjects();
+
+			initInput();
+
+		}
+
+		function initGraphics() {
+
+			container = document.getElementById( 'container' );
+
+			camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.2, 2000 );
+
+			scene = new THREE.Scene();
+
+			camera.position.x = -14;
+			camera.position.y = 8;
+			camera.position.z =  16;
+
+			controls = new THREE.OrbitControls( camera );
+			controls.target.y = 2;
+
+			renderer = new THREE.WebGLRenderer();
+			renderer.setClearColor( 0xbfd1e5 );
+			renderer.setPixelRatio( window.devicePixelRatio );
+			renderer.setSize( window.innerWidth, window.innerHeight );
+			renderer.shadowMap.enabled = true;
+
+			textureLoader = new THREE.TextureLoader();
+
+			var ambientLight = new THREE.AmbientLight( 0x707070 );
+			scene.add( ambientLight );
+
+			var light = new THREE.DirectionalLight( 0xffffff, 1 );
+			light.position.set( -10, 18, 5 );
+			light.castShadow = true;
+			var d = 14;
+			light.shadow.camera.left = -d;
+			light.shadow.camera.right = d;
+			light.shadow.camera.top = d;
+			light.shadow.camera.bottom = -d;
+
+			light.shadow.camera.near = 2;
+			light.shadow.camera.far = 50;
+
+			light.shadow.mapSize.x = 1024;
+			light.shadow.mapSize.y = 1024;
+
+			scene.add( light );
+
+
+			container.innerHTML = "";
+
+			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 initPhysics() {
+
+			// Physics configuration
+
+			collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
+			dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration );
+			broadphase = new Ammo.btDbvtBroadphase();
+			solver = new Ammo.btSequentialImpulseConstraintSolver();
+			physicsWorld = new Ammo.btDiscreteDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration );
+			physicsWorld.setGravity( new Ammo.btVector3( 0, - gravityConstant, 0 ) );
+
+		}
+
+		function createObject( mass, halfExtents, pos, quat, material ) {
+
+			var object = new THREE.Mesh( new THREE.BoxGeometry( halfExtents.x * 2, halfExtents.y * 2, halfExtents.z * 2 ), material );
+			object.position.copy( pos );
+			object.quaternion.copy( quat );
+			convexBreaker.prepareBreakableObject( object, mass, new THREE.Vector3(), new THREE.Vector3(), true );
+			createDebrisFromBreakableObject( object );
+
+		}
+
+		function createObjects() {
+
+			// Ground
+			pos.set( 0, - 0.5, 0 );
+			quat.set( 0, 0, 0, 1 );
+			var ground = createParalellepipedWithPhysics( 40, 1, 40, 0, pos, quat, new THREE.MeshPhongMaterial( { color: 0xFFFFFF } ) );
+			ground.receiveShadow = true;
+			textureLoader.load( "textures/grid.png", function( texture ) {
+				texture.wrapS = THREE.RepeatWrapping;
+				texture.wrapT = THREE.RepeatWrapping;
+				texture.repeat.set( 40, 40 );
+				ground.material.map = texture;
+				ground.material.needsUpdate = true;
+			} );
+
+			// Tower 1
+			var towerMass = 1000;
+			var towerHalfExtents = new THREE.Vector3( 2, 5, 2 );
+			pos.set( -8, 5, 0 );
+			quat.set( 0, 0, 0, 1 );
+			createObject( towerMass, towerHalfExtents, pos, quat, createMaterial( 0xF0A024 ) );
+
+			// Tower 2
+			pos.set( 8, 5, 0 );
+			quat.set( 0, 0, 0, 1 );
+			createObject( towerMass, towerHalfExtents, pos, quat, createMaterial( 0xF4A321 ) );
+
+			//Bridge
+			var bridgeMass = 100;
+			var bridgeHalfExtents = new THREE.Vector3( 7, 0.2, 1.5 );
+			pos.set( 0, 10.2, 0 );
+			quat.set( 0, 0, 0, 1 );
+			createObject( bridgeMass, bridgeHalfExtents, pos, quat, createMaterial( 0xB38835 ) );
+
+			// Stones
+			var stoneMass = 120;
+			var stoneHalfExtents = new THREE.Vector3( 1, 2, 0.15 );
+			var numStones = 8;
+			quat.set( 0, 0, 0, 1 );
+			for ( var i = 0; i < numStones; i++ ) {
+
+			    pos.set( 0, 2, 15 * ( 0.5 - i / ( numStones + 1 ) ) );
+
+			    createObject( stoneMass, stoneHalfExtents, pos, quat, createMaterial( 0xB0B0B0 ) );
+
+			}
+
+			// Mountain
+			var mountainMass = 860;
+			var mountainHalfExtents = new THREE.Vector3( 4, 5, 4 );
+			pos.set( 5, mountainHalfExtents.y * 0.5, - 7 );
+			quat.set( 0, 0, 0, 1 );
+			var mountainPoints = [];
+			mountainPoints.push( new THREE.Vector3( mountainHalfExtents.x, - mountainHalfExtents.y, mountainHalfExtents.z ) );
+			mountainPoints.push( new THREE.Vector3( - mountainHalfExtents.x, - mountainHalfExtents.y, mountainHalfExtents.z ) );
+			mountainPoints.push( new THREE.Vector3( mountainHalfExtents.x, - mountainHalfExtents.y, - mountainHalfExtents.z ) );
+			mountainPoints.push( new THREE.Vector3( - mountainHalfExtents.x, - mountainHalfExtents.y, - mountainHalfExtents.z ) );
+			mountainPoints.push( new THREE.Vector3( 0, mountainHalfExtents.y, 0 ) );
+			var mountain = new THREE.Mesh( new THREE.ConvexGeometry( mountainPoints ), createMaterial( 0xFFB443 ) );
+			mountain.position.copy( pos );
+			mountain.quaternion.copy( quat );
+			convexBreaker.prepareBreakableObject( mountain, mountainMass, new THREE.Vector3(), new THREE.Vector3(), true );
+			createDebrisFromBreakableObject( mountain );
+
+		}
+
+		function createParalellepipedWithPhysics( sx, sy, sz, mass, pos, quat, material ) {
+
+			var object = new THREE.Mesh( new THREE.BoxGeometry( sx, sy, sz, 1, 1, 1 ), material );
+			var shape = new Ammo.btBoxShape( new Ammo.btVector3( sx * 0.5, sy * 0.5, sz * 0.5 ) );
+			shape.setMargin( margin );
+
+			createRigidBody( object, shape, mass, pos, quat );
+
+			return object;
+
+		}
+
+		function createDebrisFromBreakableObject( object ) {
+
+			object.castShadow = true;
+			object.receiveShadow = true;
+
+			var shape = createConvexHullPhysicsShape( object.geometry.vertices );
+			shape.setMargin( margin );
+
+			var body = createRigidBody( object, shape, object.userData.mass, null, null, object.userData.velocity, object.userData.angularVelocity );
+
+			// Set pointer back to the three object only in the debris objects
+			var btVecUserData = new Ammo.btVector3( 0, 0, 0 );
+			btVecUserData.threeObject = object;
+			body.setUserPointer( btVecUserData );
+
+		}
+
+		function removeDebris( object ) {
+
+			scene.remove( object );
+
+			physicsWorld.removeRigidBody( object.userData.physicsBody );
+
+		}
+
+		function createConvexHullPhysicsShape( points ) {
+
+			var shape = new Ammo.btConvexHullShape();
+
+			for ( var i = 0, il = points.length; i < il; i++ ) {
+				var p = points[ i ];
+				this.tempBtVec3_1.setValue( p.x, p.y, p.z );
+				var lastOne = ( i === ( il - 1 ) );
+				shape.addPoint( this.tempBtVec3_1, lastOne );
+			}
+
+			return shape;
+
+		}
+
+		function createRigidBody( object, physicsShape, mass, pos, quat, vel, angVel ) {
+
+			if ( pos ) {
+			    object.position.copy( pos );
+			}
+			else {
+			    pos = object.position;
+			}
+			if ( quat ) {
+			    object.quaternion.copy( quat );
+			}
+			else {
+			    quat = object.quaternion;
+			}
+
+			var transform = new Ammo.btTransform();
+			transform.setIdentity();
+			transform.setOrigin( new Ammo.btVector3( pos.x, pos.y, pos.z ) );
+			transform.setRotation( new Ammo.btQuaternion( quat.x, quat.y, quat.z, quat.w ) );
+			var motionState = new Ammo.btDefaultMotionState( transform );
+
+			var localInertia = new Ammo.btVector3( 0, 0, 0 );
+			physicsShape.calculateLocalInertia( mass, localInertia );
+
+			var rbInfo = new Ammo.btRigidBodyConstructionInfo( mass, motionState, physicsShape, localInertia );
+			var body = new Ammo.btRigidBody( rbInfo );
+
+			body.setFriction( 0.5 );
+
+			if ( vel ) {
+			    body.setLinearVelocity( new Ammo.btVector3( vel.x, vel.y, vel.z ) );
+			}
+			if ( angVel ) {
+			    body.setAngularVelocity( new Ammo.btVector3( angVel.x, angVel.y, angVel.z ) );
+			}
+
+			object.userData.physicsBody = body;
+			object.userData.collided = false;
+
+			scene.add( object );
+
+			if ( mass > 0 ) {
+				rigidBodies.push( object );
+
+				// Disable deactivation
+				body.setActivationState( 4 );
+			}
+
+			physicsWorld.addRigidBody( body );
+
+			return body;
+		}
+
+		function createRandomColor() {
+			return Math.floor( Math.random() * ( 1 << 24 ) );
+		}
+
+		function createMaterial( color ) {
+			color = color || createRandomColor();
+			return new THREE.MeshPhongMaterial( { color: color } );
+		}
+
+		function initInput() {
+
+			window.addEventListener( 'mousedown', function( event ) {
+
+				mouseCoords.set(
+					( event.clientX / window.innerWidth ) * 2 - 1,
+					- ( event.clientY / window.innerHeight ) * 2 + 1
+				);
+
+				raycaster.setFromCamera( mouseCoords, camera );
+
+				// Creates a ball and throws it
+				var ballMass = 35;
+				var ballRadius = 0.4;
+
+				var ball = new THREE.Mesh( new THREE.SphereGeometry( ballRadius, 14, 10 ), ballMaterial );
+				ball.castShadow = true;
+				ball.receiveShadow = true;
+				var ballShape = new Ammo.btSphereShape( ballRadius );
+				ballShape.setMargin( margin );
+				pos.copy( raycaster.ray.direction );
+				pos.add( raycaster.ray.origin );
+				quat.set( 0, 0, 0, 1 );
+				var ballBody = createRigidBody( ball, ballShape, ballMass, pos, quat );
+
+				pos.copy( raycaster.ray.direction );
+				pos.multiplyScalar( 24 );
+				ballBody.setLinearVelocity( new Ammo.btVector3( pos.x, pos.y, pos.z ) );
+
+			}, false );
+
+		}
+
+		function onWindowResize() {
+
+			camera.aspect = window.innerWidth / window.innerHeight;
+			camera.updateProjectionMatrix();
+
+			renderer.setSize( window.innerWidth, window.innerHeight );
+
+		}
+
+		function animate() {
+
+			requestAnimationFrame( animate );
+
+			render();
+			stats.update();
+
+		}
+
+		function render() {
+
+			var deltaTime = clock.getDelta();
+
+			updatePhysics( deltaTime );
+
+			controls.update( deltaTime );
+
+			renderer.render( scene, camera );
+
+			time += deltaTime;
+
+		}
+
+		function updatePhysics( deltaTime ) {
+
+			// Step world
+			physicsWorld.stepSimulation( deltaTime, 10 );
+
+			// Update rigid bodies
+			for ( var i = 0, il = rigidBodies.length; i < il; i++ ) {
+				var objThree = rigidBodies[ i ];
+				var objPhys = objThree.userData.physicsBody;
+				var ms = objPhys.getMotionState();
+				if ( ms ) {
+
+					ms.getWorldTransform( transformAux1 );
+					var p = transformAux1.getOrigin();
+					var q = transformAux1.getRotation();
+					objThree.position.set( p.x(), p.y(), p.z() );
+					objThree.quaternion.set( q.x(), q.y(), q.z(), q.w() );
+
+					objThree.userData.collided = false;
+
+				}
+			}
+
+			for ( var i = 0, il = dispatcher.getNumManifolds(); i < il; i ++ ) {
+
+				var contactManifold = dispatcher.getManifoldByIndexInternal( i );
+				var rb0 = contactManifold.getBody0();
+				var rb1 = contactManifold.getBody1();
+
+				var threeObject0 = Ammo.castObject( rb0.getUserPointer(), Ammo.btVector3 ).threeObject;
+				var threeObject1 = Ammo.castObject( rb1.getUserPointer(), Ammo.btVector3 ).threeObject;
+
+				if ( ! threeObject0 && ! threeObject1 ) {
+					continue;
+				}
+
+				var userData0 = threeObject0 ? threeObject0.userData : null;
+				var userData1 = threeObject1 ? threeObject1.userData : null;
+
+				var breakable0 = userData0 ? userData0.breakable : false;
+				var breakable1 = userData1 ? userData1.breakable : false;
+
+				var collided0 = userData0 ? userData0.collided : false;
+				var collided1 = userData1 ? userData1.collided : false;
+
+				if ( ( ! breakable0 && ! breakable1 ) || ( collided0 && collided1 ) ) {
+					continue;
+				}
+
+				var contact = false;
+				var maxImpulse = 0;
+				for ( var j = 0, jl = contactManifold.getNumContacts(); j < jl; j ++ ) {
+					var contactPoint = contactManifold.getContactPoint( j );
+					if ( contactPoint.getDistance() < 0 ) {
+						contact = true;
+						var impulse = contactPoint.getAppliedImpulse();
+						if ( impulse > maxImpulse ) {
+							maxImpulse = impulse;
+							var pos = contactPoint.get_m_positionWorldOnB();
+							var normal = contactPoint.get_m_normalWorldOnB();
+							impactPoint.set( pos.x(), pos.y(), pos.z() );
+							impactNormal.set( normal.x(), normal.y(), normal.z() );
+						}
+						break;
+					}
+				}
+
+				// If no point has contact, abort
+				if ( ! contact ) {
+					continue;
+				}
+
+				// Subdivision
+
+				var fractureImpulse = 250;
+
+				if ( breakable0 && !collided0 && maxImpulse > fractureImpulse ) {
+
+					var debris = convexBreaker.subdivideByImpact( threeObject0, impactPoint, impactNormal , 1, 2, 1.5 );
+
+					var numObjects = debris.length;
+					for ( var j = 0; j < numObjects; j++ ) {
+
+						createDebrisFromBreakableObject( debris[ j ] );
+
+					}
+
+					objectsToRemove[ numObjectsToRemove++ ] = threeObject0;
+					userData0.collided = true;
+
+				}
+
+				if ( breakable1 && !collided1 && maxImpulse > fractureImpulse ) {
+
+					var debris = convexBreaker.subdivideByImpact( threeObject1, impactPoint, impactNormal , 1, 2, 1.5 );
+
+					var numObjects = debris.length;
+					for ( var j = 0; j < numObjects; j++ ) {
+
+						createDebrisFromBreakableObject( debris[ j ] );
+
+					}
+
+					objectsToRemove[ numObjectsToRemove++ ] = threeObject1;
+					userData1.collided = true;
+
+				}
+
+			}
+
+			for ( var i = 0; i < numObjectsToRemove; i++ ) {
+
+			    removeDebris( objectsToRemove[ i ] );
+
+			}
+			numObjectsToRemove = 0;
+
+		}
+
+        </script>
+
+    </body>
+</html>

+ 2 - 2
examples/webgl_postprocessing_backgrounds.html

@@ -190,14 +190,14 @@
 				composer.addPass( texturePass );
 
 				var textureLoader = new THREE.TextureLoader();
-				textureLoader.load( "../examples/textures/hardwood2_diffuse.jpg", function( map ) {
+				textureLoader.load( "textures/hardwood2_diffuse.jpg", function( map ) {
 					texturePass.map = map;
 				});
 
 				cubeTexturePassP = new THREE.CubeTexturePass( cameraP );
 				composer.addPass( cubeTexturePassP );
 
-				var ldrUrls = genCubeUrls( "./textures/cube/pisa/", ".png" );
+				var ldrUrls = genCubeUrls( "textures/cube/pisa/", ".png" );
 				new THREE.CubeTextureLoader().load( ldrUrls, function ( ldrCubeMap ) {
 					cubeTexturePassP.envMap = ldrCubeMap;
 					console.log( "loaded envmap");

+ 415 - 0
examples/webgl_postprocessing_outline.html

@@ -0,0 +1,415 @@
+<!DOCTYPE html>
+
+<html lang="en">
+	<head>
+		<title>three.js webgl - post processing - Scalable Ambient Occlusion (SAO)</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 {
+				background-color: #000000;
+				margin: 0px;
+				overflow: hidden;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				font-weight: bold;
+			}
+
+			a {
+				color:#00ff78;
+			}
+
+			#info {
+				color: #fff;
+				position: absolute;
+				top: 10px;
+				width: 100%;
+				text-align: center;
+				display:block;
+			}
+			.dg.ac {
+				z-index: 1 !important; /* FIX DAT.GUI */
+			}
+		</style>
+	</head>
+	<body>
+		<script src="../build/three.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/loaders/OBJLoader.js"></script>
+
+		<script src="js/Detector.js"></script>
+
+		<script src="js/shaders/CopyShader.js"></script>
+    <script src="js/postprocessing/EffectComposer.js"></script>
+    <script src="js/postprocessing/MaskPass.js"></script>
+		<script src="js/shaders/CopyShader.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+    <script src="js/postprocessing/ShaderPass.js"></script>
+		<script src="js/postprocessing/OutlinePass.js"></script>
+		<script src="js/shaders/FXAAShader.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+		<script src='js/libs/dat.gui.min.js'></script>
+
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> - Outline Pass by <a href="http://eduperiment.com" target="_blank">Prashant Sharma</a> and <a href="https://clara.io" target="_blank">Ben Houston</a><br/><br/>
+		</div>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+			var camera, scene, renderer, controls;
+			var mesh, decal;
+			var raycaster = new THREE.Raycaster();
+
+			var mouse = new THREE.Vector2();
+			var selectedObjects = [];
+
+			var composer, effectFXAA, outlinePass;
+			var obj3d = new THREE.Object3D();
+
+			var group = new THREE.Object3D();
+
+			var params = {
+				edgeStrength: 3.0,
+				edgeGlow: 0.0,
+				edgeThickness: 1.0,
+				pulsePeriod: 0,
+				rotate: false,
+				usePatternTexture: false
+			}
+
+			// Init gui
+			var gui = new dat.GUI();
+			gui.add( params, "edgeStrength", 0.01, 10 ).onChange( function(value) {
+	        outlinePass.edgeStrength = Number(value);
+	    });
+			gui.add( params, "edgeGlow", 0.0, 1 ).onChange( function(value) {
+	        outlinePass.edgeGlow = Number(value);
+	    })
+			gui.add( params, "edgeThickness", 1, 4 ).onChange( function(value) {
+	        outlinePass.edgeThickness = Number(value);
+	    })
+			gui.add( params, "pulsePeriod", 0.0, 5 ).onChange( function(value) {
+	        outlinePass.pulsePeriod = Number(value);
+	    })
+			gui.add( params, "rotate" )
+			gui.add( params, "usePatternTexture" ).onChange( function(value) {
+				outlinePass.usePatternTexture = value;
+	    })
+			var Configuration=function(){
+	            this.visibleEdgeColor = "#ffffff";
+							this.hiddenEdgeColor = "#190a05";
+	    };
+	    var conf = new Configuration();
+
+	    var controladorVisible = gui.addColor( conf, 'visibleEdgeColor');
+			var controladorHidden = gui.addColor( conf, 'hiddenEdgeColor');
+	    controladorVisible.onChange( function( colorValue  )
+	    {
+	      //the return value by the chooser is like as: #ffff
+	      colorValue=colorValue.replace( '#','' );
+	      function hexToRgb(hex) {
+	            var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+	            return result ? {
+	                r: parseInt(result[1], 16),
+	                g: parseInt(result[2], 16),
+	                b: parseInt(result[3], 16)
+	            } : null;
+	        }
+	      var rgba = hexToRgb(colorValue);
+        var color = outlinePass.visibleEdgeColor;
+        color.r = rgba.r/255;
+        color.g = rgba.g/255;
+        color.b = rgba.b/255;
+	    });
+
+			controladorHidden.onChange( function( colorValue  )
+	    {
+	      //the return value by the chooser is like as: #ffff
+	      colorValue=colorValue.replace( '#','' );
+	      function hexToRgb(hex) {
+	            var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+	            return result ? {
+	                r: parseInt(result[1], 16),
+	                g: parseInt(result[2], 16),
+	                b: parseInt(result[3], 16)
+	            } : null;
+	        }
+	      var rgba = hexToRgb(colorValue);
+        var color = outlinePass.hiddenEdgeColor;
+        color.r = rgba.r/255;
+        color.g = rgba.g/255;
+        color.b = rgba.b/255;
+	    });
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				var width = window.innerWidth || 1;
+				var height = window.innerHeight || 1;
+				var devicePixelRatio = window.devicePixelRatio || 1;
+
+				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer.shadowMap.enabled = true;
+				renderer.setClearColor( 0xa0a0a0 );
+				renderer.setPixelRatio( 1 );
+				renderer.setSize( width, height );
+				document.body.appendChild( renderer.domElement );
+
+				camera = new THREE.PerspectiveCamera( 45, width / height, 0.1, 100 );
+				camera.position.z = 8;
+				camera.position.x = 0;
+
+				scene = new THREE.Scene();
+
+				var manager = new THREE.LoadingManager();
+				manager.onProgress = function ( item, loaded, total ) {
+					console.log( item, loaded, total );
+				};
+				// model
+				var loader = new THREE.OBJLoader( manager );
+				loader.load( 'models/obj/tree.obj', function ( object ) {
+					var scale = 1.0;
+					object.traverse( function ( child ) {
+						if ( child instanceof THREE.Mesh ) {
+							child.geometry.center();
+							child.geometry.computeBoundingSphere();
+							scale = 0.2*child.geometry.boundingSphere.radius;
+							var phongMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 5 } );
+							child.material = phongMaterial;
+							child.material.side = THREE.DoubleSide;
+							child.receiveShadow = true;
+							child.castShadow = true;
+						}
+					} );
+					object.position.y = 1;
+					object.scale.x /= scale;
+					object.scale.y /= scale;
+					object.scale.z /= scale;
+					obj3d.add( object );
+				} );
+				group.add(obj3d);
+
+				controls = new THREE.OrbitControls( camera, renderer.domElement );
+				controls.enableDamping = true;
+				controls.dampingFactor = 0.25;
+
+				scene.add( group );
+
+				var light = new THREE.DirectionalLight( 0xddffdd, 0.4);
+				light.position.z = 1;
+				light.position.y = 1;
+				light.position.x = 1;
+				scene.add( light );
+				light.castShadow = true;
+
+				light.shadow.mapSize.width = 1024;
+				light.shadow.mapSize.height = 1024;
+
+				var d = 20;
+
+				light.shadow.camera.left = - d;
+				light.shadow.camera.right = d;
+				light.shadow.camera.top = d;
+				light.shadow.camera.bottom = - d;
+
+				light.shadow.camera.far = 1000;
+
+				var light2 = new THREE.DirectionalLight( 0xaadddd, 0.15 );
+				light2.position.z = 1;
+				light2.position.x = -1;
+				light2.position.y = -1;
+				scene.add( light2 );
+
+				var light3 = new THREE.DirectionalLight( 0xddddaa, 0.1 );
+				light3.position.z = 1;
+				light3.position.x = -1;
+				light3.position.y = 1;
+				scene.add( light3 );
+
+				var light3 = new THREE.AmbientLight( 0xaaaaaa, 0.2 );
+				scene.add( light3 );
+
+				var geometry = new THREE.SphereBufferGeometry( 3, 48, 24 );
+				for ( var i = 0; i < 20; i ++ ) {
+
+					var material = new THREE.MeshLambertMaterial();
+					material.roughness = 1;//0.5 * Math.random() + 0.25;
+					material.metalness = 0;
+					material.color.setHSL( Math.random(), 1.0, 0.3 );
+
+					var mesh = new THREE.Mesh( geometry, material );
+					mesh.position.x = Math.random() * 4 - 2;
+					mesh.position.y = Math.random() * 4 - 2;
+					mesh.position.z = Math.random() * 4 - 2;
+					mesh.rotation.x = Math.random();
+					mesh.rotation.y = Math.random();
+					mesh.rotation.z = Math.random();
+					mesh.receiveShadow = true;
+					mesh.castShadow = true;
+					mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 0.3 + 0.1;
+					group.add( mesh );
+				}
+
+				var floorMaterial = new THREE.MeshLambertMaterial();
+				floorMaterial.side = THREE.DoubleSide;
+				material.roughness = 0.5 * Math.random() + 0.25;
+				material.metalness = 0;
+
+				var floorGeometry = new THREE.PlaneBufferGeometry( 12, 12 );
+				var floorMesh = new THREE.Mesh( floorGeometry, floorMaterial );
+				floorMesh.rotation.x -= Math.PI * 0.5;
+				floorMesh.position.y -= 1.5;
+				group.add( floorMesh );
+				floorMesh.receiveShadow = true;
+
+				var geometry = new THREE.TorusGeometry( 1, 0.3, 16, 100 );
+				var material = new THREE.MeshPhongMaterial( { color: 0xffaaff } );
+				var torus = new THREE.Mesh( geometry, material );
+				torus.position.z = -4;
+				group.add( torus );
+				torus.receiveShadow = true;
+				torus.castShadow = true;
+
+				stats = new Stats();
+				container.appendChild( stats.dom );
+
+				// postprocessing
+				composer = new THREE.EffectComposer( renderer );
+
+				renderPass = new THREE.RenderPass( scene, camera );
+				composer.addPass( renderPass );
+
+				outlinePass = new THREE.OutlinePass( new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera);
+				composer.addPass( outlinePass );
+				var onLoad = function ( texture ) {
+					outlinePass.patternTexture = texture;
+					texture.wrapS = THREE.RepeatWrapping;
+					texture.wrapT = THREE.RepeatWrapping;
+				};
+
+				var loader = new THREE.TextureLoader();
+
+				// load a resource
+				loader.load(
+					// resource URL
+					'textures/tri_pattern.jpg',
+					// Function when resource is loaded
+					onLoad
+				);
+
+				effectFXAA = new THREE.ShaderPass(THREE.FXAAShader);
+		    effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight );
+		    effectFXAA.renderToScreen = true;
+				composer.addPass( effectFXAA );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+				var moved = false;
+
+				controls.addEventListener( 'change', function() {
+
+					moved = true;
+
+				} );
+
+				window.addEventListener( 'mousedown', function () {
+
+					moved = false;
+
+				}, false );
+
+				window.addEventListener( 'mouseup', function() {
+					if(!moved)
+						checkIntersection();
+				} );
+
+				window.addEventListener( 'mousemove', onTouchMove );
+				window.addEventListener( 'touchmove', onTouchMove );
+
+				function onTouchMove( event ) {
+
+					if ( event.changedTouches ) {
+
+						x = event.changedTouches[ 0 ].pageX;
+						y = event.changedTouches[ 0 ].pageY;
+
+					} else {
+
+						x = event.clientX;
+						y = event.clientY;
+
+					}
+
+					mouse.x = ( x / window.innerWidth ) * 2 - 1;
+					mouse.y = - ( y / window.innerHeight ) * 2 + 1;
+
+				}
+
+				function addSelectedObject(object) {
+					selectedObjects = [];
+					selectedObjects.push(object);
+				}
+
+				function checkIntersection() {
+
+					raycaster.setFromCamera( mouse, camera );
+
+					var intersects = raycaster.intersectObjects( [ scene ], true );
+
+					if ( intersects.length > 0 ) {
+						var selectedObject = intersects[ 0 ].object;
+						addSelectedObject(selectedObject);
+						outlinePass.selectedObjects = selectedObjects;
+					}
+					else {
+						// outlinePass.selectedObjects = [];
+					}
+				}
+
+			}
+
+			function onWindowResize() {
+
+				var width = window.innerWidth || 1;
+				var height = window.innerHeight || 1;
+				var devicePixelRatio = window.devicePixelRatio || 1;
+
+				camera.aspect = width / height;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( width, height );
+        composer.setSize( width, height );
+				effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight );
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				stats.begin();
+
+				var timer = performance.now();
+				if(params.rotate)
+					group.rotation.y = timer * 0.0001;
+				renderer.autoClear = true;
+				renderer.setClearColor( 0xfff0f0 );
+				renderer.setClearAlpha( 0.0 );
+
+				composer.render();
+				controls.update();
+				stats.end();
+			}
+
+
+		</script>
+	</body>
+</html>

+ 275 - 0
examples/webgl_postprocessing_unreal_bloom.html

@@ -0,0 +1,275 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>threejs webgl - materials - hdr environment mapping</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 {
+				background-color: #000000;
+				margin: 0px;
+				overflow: hidden;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				font-weight: bold;
+			}
+			a {
+				color:#00ff78;
+			}
+
+			#info {
+				color: #fff;
+				position: absolute;
+				top: 10px;
+				width: 100%;
+				text-align: center;
+				display:block;
+			}
+			.dg.ac {
+				z-index: 1 !important; /* FIX DAT.GUI */
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/three.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/loaders/RGBELoader.js"></script>
+		<script src="js/loaders/HDRCubeTextureLoader.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script src="js/Half.js"></script>
+		<script src="js/Encodings.js"></script>
+		<script src="js/pmrem/PMREMGenerator.js"></script>
+		<script src="js/pmrem/PMREMCubeUVPacker.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<script src="js/postprocessing/EffectComposer.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+		<script src="js/postprocessing/MaskPass.js"></script>
+		<script src="js/postprocessing/ShaderPass.js"></script>
+		<script src="js/shaders/CopyShader.js"></script>
+		<script src="js/shaders/FXAAShader.js"></script>
+		<script src="js/shaders/ConvolutionShader.js"></script>
+		<script src="js/shaders/LuminosityHighPassShader.js"></script>
+		<script src="js/postprocessing/UnrealBloomPass.js"></script>
+
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> - Bloom pass by <a href="http://eduperiment.com" target="_blank">Prashant Sharma</a> and <a href="https://clara.io" target="_blank">Ben Houston</a><br/><br/>
+			This Bloom Pass is inspired by the bloom pass of the Unreal Engine. It creates a mip map chain of bloom textures and blur them <br>
+			with different radii. Because of the weigted combination of mips, and since larger blurs are done on higher mips this bloom <br>
+			is better in quality and performance.<br>
+		</div>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+			var params = {
+				projection: 'normal',
+				background: false,
+				exposure: 1.0,
+				bloomStrength: 1.5,
+				bloomThreshold: 0.85,
+				bloomRadius: 0.4
+			};
+			var camera, scene, renderer, controls, objects = [];
+			var effectFXAA, bloomPass, renderScene;
+			var hdrCubeMap;
+			var composer;
+			var standardMaterial;
+			var hdrCubeRenderTarget;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
+				camera.position.set( 0.0, 35, 35 * 3.5 );
+
+				scene = new THREE.Scene();
+
+				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer.setClearColor( new THREE.Color( 0x111111 ) );
+				renderer.toneMapping = THREE.LinearToneMapping;
+
+				standardMaterial = new THREE.MeshStandardMaterial( {
+					map: null,
+					color: 0xffffff,
+					metalness: 1.0,
+					shading: THREE.SmoothShading
+				} );
+
+				var geometry = new THREE.TorusKnotGeometry( 18, 8, 150, 20 );;
+				var torusMesh1 = new THREE.Mesh( geometry, standardMaterial );
+				torusMesh1.position.x = 0.0;
+				torusMesh1.castShadow = true;
+				torusMesh1.receiveShadow = true;
+				scene.add( torusMesh1 );
+				objects.push( torusMesh1 );
+
+				var textureLoader = new THREE.TextureLoader();
+				textureLoader.load( "./textures/roughness_map.jpg", function( map ) {
+					map.wrapS = THREE.RepeatWrapping;
+					map.wrapT = THREE.RepeatWrapping;
+					map.anisotropy = 4;
+					map.repeat.set( 9, 2 );
+					standardMaterial.roughnessMap = map;
+					standardMaterial.bumpMap = map;
+					standardMaterial.needsUpdate = true;
+				} );
+
+				var genCubeUrls = function( prefix, postfix ) {
+					return [
+						prefix + 'px' + postfix, prefix + 'nx' + postfix,
+						prefix + 'py' + postfix, prefix + 'ny' + postfix,
+						prefix + 'pz' + postfix, prefix + 'nz' + postfix
+					];
+				};
+
+				var hdrUrls = genCubeUrls( "./textures/cube/pisaHDR/", ".hdr" );
+				new THREE.HDRCubeTextureLoader().load( THREE.UnsignedByteType, hdrUrls, function ( hdrCubeMap ) {
+
+					var pmremGenerator = new THREE.PMREMGenerator( hdrCubeMap );
+					pmremGenerator.update( renderer );
+
+					var pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( pmremGenerator.cubeLods );
+					pmremCubeUVPacker.update( renderer );
+
+					hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget;
+
+				} );
+				// Lights
+
+				scene.add( new THREE.AmbientLight( 0x222222 ) );
+
+				var spotLight = new THREE.SpotLight( 0xffffff );
+				spotLight.position.set( 50, 100, 50 );
+				spotLight.angle = Math.PI / 7;
+				spotLight.penumbra = 0.8
+				spotLight.castShadow = true;
+				scene.add( spotLight );
+
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.shadowMap.enabled = true;
+				container.appendChild( renderer.domElement );
+
+				renderScene = new THREE.RenderPass(scene, camera);
+
+		    // renderScene.clear = true;
+		    effectFXAA = new THREE.ShaderPass(THREE.FXAAShader);
+		    effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight );
+
+				var copyShader = new THREE.ShaderPass(THREE.CopyShader);
+				copyShader.renderToScreen = true;
+
+		    bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);//1.0, 9, 0.5, 512);
+				composer = new THREE.EffectComposer(renderer);
+		    composer.setSize(window.innerWidth, window.innerHeight);
+		    composer.addPass(renderScene);
+				composer.addPass(effectFXAA);
+		    composer.addPass(bloomPass);
+				composer.addPass(copyShader);
+				//renderer.toneMapping = THREE.ReinhardToneMapping;
+				renderer.gammaInput = true;
+				renderer.gammaOutput = true;
+
+				stats = new Stats();
+				container.appendChild( stats.dom );
+
+				controls = new THREE.OrbitControls( camera, renderer.domElement );
+				controls.target.set( 0, 0, 0 );
+				controls.update();
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+				var gui = new dat.GUI();
+
+				gui.add( params, 'exposure', 0.1, 2 );
+				gui.add( params, 'bloomThreshold', 0.0, 1.0 ).onChange( function(value) {
+		        bloomPass.threshold = Number(value);
+		    });
+				gui.add( params, 'bloomStrength', 0.0, 3.0 ).onChange( function(value) {
+		        bloomPass.strength = Number(value);
+		    });
+				gui.add( params, 'bloomRadius', 0.0, 1.0 ).onChange( function(value) {
+		        bloomPass.radius = Number(value);
+		    });
+				gui.open();
+
+			}
+
+			function onWindowResize() {
+
+				var width = window.innerWidth;
+				var height = window.innerHeight;
+
+				camera.aspect = width / height;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( width, height );
+				composer.setSize( width, height );
+				effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight );
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				stats.begin();
+				render();
+				stats.end();
+
+			}
+
+			function render() {
+
+				if ( standardMaterial !== undefined ) {
+
+					standardMaterial.roughness = 1.0;
+					standardMaterial.bumpScale = - 0.05;
+
+					var newEnvMap = standardMaterial.envMap;
+					newEnvMap = hdrCubeRenderTarget ? hdrCubeRenderTarget.texture : null;
+
+					if( newEnvMap !== standardMaterial.envMap ) {
+
+						standardMaterial.envMap = newEnvMap;
+						standardMaterial.needsUpdate = true;
+
+					}
+
+				}
+
+				renderer.toneMappingExposure = Math.pow( params.exposure, 4.0 );
+
+				var timer = Date.now() * 0.00025;
+
+				camera.lookAt( scene.position );
+
+				for ( var i = 0, l = objects.length; i < l; i ++ ) {
+
+					var object = objects[ i ];
+					object.rotation.y += 0.005;
+
+				}
+
+				// renderer.render( scene, camera );
+				composer.render();
+			}
+
+		</script>
+
+	</body>
+</html>

+ 19 - 19
examples/webgl_tonemapping.html

@@ -32,24 +32,24 @@
 		<div id="info"><a href="http://threejs.org" target="_blank">threejs</a> - Inline Tone Mapping (within a Material's fragment shader) without<br/>using a pre-processing step or float/half buffers by <a href="http://clara.io/" target="_blank">Ben Houston</a>.</div>
 
 		<script src="../build/three.js"></script>
-		<script src="../examples/js/controls/OrbitControls.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
 
-		<script src="../examples/js/Detector.js"></script>
-		<script src="../examples/js/libs/stats.min.js"></script>
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
 
-		<script src="../examples/js/libs/dat.gui.min.js"></script>
-		<script src="../examples/js/loaders/RGBELoader.js"></script>
-		<script src="../examples/js/loaders/HDRCubeTextureLoader.js"></script>
-		<script src="../examples/js/Half.js"></script>
-		<script src="../examples/js/Encodings.js"></script>
-		<script src="../examples/js/pmrem/PMREMGenerator.js"></script>
-		<script src="../examples/js/pmrem/PMREMCubeUVPacker.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+		<script src="js/loaders/RGBELoader.js"></script>
+		<script src="js/loaders/HDRCubeTextureLoader.js"></script>
+		<script src="js/Half.js"></script>
+		<script src="js/Encodings.js"></script>
+		<script src="js/pmrem/PMREMGenerator.js"></script>
+		<script src="js/pmrem/PMREMCubeUVPacker.js"></script>
 
-		<script src="../examples/js/postprocessing/EffectComposer.js"></script>
-		<script src="../examples/js/postprocessing/RenderPass.js"></script>
-		<script src="../examples/js/postprocessing/MaskPass.js"></script>
-		<script src="../examples/js/postprocessing/ShaderPass.js"></script>
-		<script src="../examples/js/shaders/CopyShader.js"></script>
+		<script src="js/postprocessing/EffectComposer.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+		<script src="js/postprocessing/MaskPass.js"></script>
+		<script src="js/postprocessing/ShaderPass.js"></script>
+		<script src="js/shaders/CopyShader.js"></script>
 
 		<script>
 
@@ -104,7 +104,7 @@
 				} );
 
 				var textureLoader = new THREE.TextureLoader();
-				textureLoader.load( "../examples/textures/brick_diffuse.jpg", function( map ) {
+				textureLoader.load( "textures/brick_diffuse.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -112,7 +112,7 @@
 					standardMaterial.map = map;
 					standardMaterial.needsUpdate = true;
 				} );
-				textureLoader.load( "../examples/textures/brick_bump.jpg", function( map ) {
+				textureLoader.load( "textures/brick_bump.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -120,7 +120,7 @@
 					standardMaterial.bumpMap = map;
 					standardMaterial.needsUpdate = true;
 				} );
-				textureLoader.load( "../examples/textures/brick_roughness.jpg", function( map ) {
+				textureLoader.load( "textures/brick_roughness.jpg", function( map ) {
 					map.wrapS = THREE.RepeatWrapping;
 					map.wrapT = THREE.RepeatWrapping;
 					map.anisotropy = 4;
@@ -155,7 +155,7 @@
 				scene.add( mesh );
 
 				// Materials
-				var hdrpath = "../examples/textures/cube/pisaHDR/";
+				var hdrpath = "textures/cube/pisaHDR/";
 				var hdrformat = '.hdr';
 				var hdrurls = [
 					hdrpath + 'px' + hdrformat, hdrpath + 'nx' + hdrformat,

+ 2 - 21
examples/webgl_video_panorama_equirectangular.html

@@ -89,8 +89,7 @@
 				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
 				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
 				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
-				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
-				document.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);
+				document.addEventListener( 'wheel', onDocumentMouseWheel, false );
 
 				//
 
@@ -140,25 +139,7 @@
 
 			function onDocumentMouseWheel( event ) {
 
-				// WebKit
-
-				if ( event.wheelDeltaY ) {
-
-					distance -= event.wheelDeltaY * 0.05;
-
-				// Opera / Explorer 9
-
-				} else if ( event.wheelDelta ) {
-
-					distance -= event.wheelDelta * 0.05;
-
-				// Firefox
-
-				} else if ( event.detail ) {
-
-					distance += event.detail * 1.0;
-
-				}
+				distance += event.deltaY * 0.05;
 
 			}
 

+ 1 - 1
index.html

@@ -218,7 +218,7 @@
 		</script>
 
 		<div id="panel" class="collapsed">
-			<h1>three.js<sup><a href="http://github.com/mrdoob/three.js/releases">r79</a></sup></h1>
+			<h1>three.js<sup><a href="http://github.com/mrdoob/three.js/releases">r80</a></sup></h1>
 			<a id="expandButton" href="#">
 				<span></span>
 				<span></span>

Some files were not shown because too many files changed in this diff