diff --git a/README.md b/README.md
index ec497496..5641fa3e 100644
--- a/README.md
+++ b/README.md
@@ -54,3 +54,9 @@ or to continually rebuild as you develop:
`npm run dev`
Both commands will output a bundled in `/dist/threebox.js`.
+
+## Run
+
+`node server.js`
+
+
diff --git a/dist/threebox.js b/dist/threebox.js
index a4d8e5ed..e45238f5 100644
--- a/dist/threebox.js
+++ b/dist/threebox.js
@@ -47,7 +47,7 @@ CameraSync.prototype = {
const farZ = furthestDistance * 1.01;
this.camera.projectionMatrix = utils.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ);
-
+
var cameraWorldMatrix = new THREE.Matrix4();
var cameraTranslateZ = new THREE.Matrix4().makeTranslation(0,0,cameraToCenterDistance);
@@ -59,12 +59,12 @@ CameraSync.prototype = {
cameraWorldMatrix
.premultiply(cameraTranslateZ)
.premultiply(cameraRotateX)
- .premultiply(cameraRotateZ);
+ .premultiply(cameraRotateZ);
this.camera.matrixWorld.copy(cameraWorldMatrix);
- var zoomPow = this.map.transform.scale;
+ var zoomPow = this.map.transform.scale;
// Handle scaling and translation of objects in the map in the world's matrix transform, not the camera
var scale = new THREE.Matrix4;
var translateCenter = new THREE.Matrix4;
@@ -189,6 +189,16 @@ SymbolLayer3D.prototype = {
this.source = source;
},
+ hideFeature: function(key) {
+ this.features[key].rawObject.traverse(function(object){
+ object.visible = false;
+ });
+ },
+ showFeature: function(key) {
+ this.features[key].rawObject.traverse(function(object){
+ object.visible = true;
+ });
+ },
removeFeature: function(key) {
this.parent.remove(this.features[key].rawObject);
delete this.features[key];
@@ -225,7 +235,7 @@ SymbolLayer3D.prototype = {
console.log("Loading " + remaining + " models", this.models);
const modelComplete = (m) => {
console.log("Model complete!", m);
- //if(this.models[m].loaded)
+ //if(this.models[m].loaded)
if(--remaining === 0) {
this.loaded = true;
this._addOrUpdateFeatures(this.features);
@@ -245,11 +255,11 @@ SymbolLayer3D.prototype = {
for(material in (materials.materials)) {
materials.materials[material].shininess /= 50; // Shininess exported by Blender is way too high
}
-
+
objLoader.setMaterials( materials );
}
objLoader.setPath(this.models[modelName].directory);
-
+
console.log("Loading model ", modelName);
objLoader.load(this.models[modelName].name + ".obj", obj => {
@@ -259,7 +269,7 @@ SymbolLayer3D.prototype = {
modelComplete(modelName);
}, () => (null), error => {
- console.error("Could not load SymbolLayer3D model file.");
+ console.error("Could not load SymbolLayer3D model file.");
} );
}})(m);
@@ -1660,7 +1670,7 @@ Threebox.prototype = {
-ThreeboxConstants.MERCATOR_A * coords[0] * ThreeboxConstants.DEG2RAD * ThreeboxConstants.PROJECTION_WORLD_SIZE,
-ThreeboxConstants.MERCATOR_A * Math.log(Math.tan((Math.PI*0.25) + (0.5 * coords[1] * ThreeboxConstants.DEG2RAD))) * ThreeboxConstants.PROJECTION_WORLD_SIZE
];
-
+
var pixelsPerMeter = this.projectedUnitsPerMeter(coords[1]);
//z dimension
@@ -1717,9 +1727,9 @@ Threebox.prototype = {
this._flipMaterialSides(obj);
this.world.add(geoGroup);
this.moveToCoordinate(obj, lnglat, options);
-
+
// Bestow this mesh with animation superpowers and keeps track of its movements in the global animation queue
- //this.animationManager.enroll(obj);
+ //this.animationManager.enroll(obj);
return obj;
},
@@ -1809,7 +1819,7 @@ Threebox.prototype = {
// //scene.add( lights[ 0 ] );
// this.scene.add( lights[ 1 ] );
// this.scene.add( lights[ 2 ] );
-
+
}
}
@@ -17660,7 +17670,7 @@ module.exports = exports = {
size = 2;
} else {
-
+
type = gl.UNSIGNED_BYTE;
size = 1;
}
@@ -21399,7 +21409,7 @@ module.exports = exports = {
}
scope.numPlanes = nPlanes;
-
+
return dstArray;
}
diff --git a/docs/SymbolLayer3D.md b/docs/SymbolLayer3D.md
index 363bbadc..57bd1896 100644
--- a/docs/SymbolLayer3D.md
+++ b/docs/SymbolLayer3D.md
@@ -109,3 +109,7 @@ This will update a single feature in the collection while leaving all the others
If this behavior is not desired, `updateSourceData` takes an optional second parameter, `absolute`, that if set to `true` will delete any features not included in the updated GeoJSON.
To remove a feature, use the `SymbolLayer3D.removeFeature` method and specify the `key` of the feature you want to remove.
+
+To hide a feature, use the `SymbolLayer3D.hideFeature` method and specify the `key` of the feature you want to hide.
+
+To show a previously hidden feature, use the `SymbolLayer3D.showFeature` method and specify the `key` of the feature you want to show.
diff --git a/examples/airport.html b/examples/airport.html
new file mode 100644
index 00000000..808eda53
--- /dev/null
+++ b/examples/airport.html
@@ -0,0 +1,78 @@
+
+
+ SymboLayer3D example
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/config.js b/examples/config.js
new file mode 100644
index 00000000..2669ce2d
--- /dev/null
+++ b/examples/config.js
@@ -0,0 +1,3 @@
+var config = {
+ accessToken: 'pk.eyJ1IjoiYmVpa2VoYW5iYW8yMyIsImEiOiJjamU5b2lhbjIwcW05MndtcTU2aTRyN3AwIn0.Bqh_En_g0SC879fMlBfdkg'
+};
\ No newline at end of file
diff --git a/examples/models/123.mtl b/examples/models/123.mtl
new file mode 100644
index 00000000..ec442bcf
--- /dev/null
+++ b/examples/models/123.mtl
@@ -0,0 +1,38 @@
+# 3ds Max Wavefront OBJ Exporter v0.94b - (c)2007 guruware
+# 创建的文件:26.06.2018 22:05:34
+
+newmtl 09___Default
+ Ns 10.0000
+ Ni 1.5000
+ d 1.0000
+ Tr 1.0000
+ Tf 1.0000 1.0000 1.0000
+ illum 2
+ Ka 0.0000 0.0000 0.0000
+ Kd 1.0000 0.0000 0.0000
+ Ks 0.0000 0.0000 0.0000
+ Ke 0.0000 0.0000 0.0000
+
+newmtl 02___Default
+ Ns 10.0000
+ Ni 1.5000
+ d 1.0000
+ Tr 1.0000
+ Tf 1.0000 1.0000 1.0000
+ illum 2
+ Ka 0.0000 0.0000 0.0000
+ Kd 0.5843 0.5843 0.9961
+ Ks 0.0000 0.0000 0.0000
+ Ke 0.0000 0.0000 0.0000
+
+newmtl 07___Default
+ Ns 10.0000
+ Ni 1.5000
+ d 1.0000
+ Tr 1.0000
+ Tf 1.0000 1.0000 1.0000
+ illum 2
+ Ka 0.0000 0.0000 0.0000
+ Kd 1.0000 0.9176 0.0000
+ Ks 0.0000 0.0000 0.0000
+ Ke 0.0000 0.0000 0.0000
diff --git a/examples/models/123.obj b/examples/models/123.obj
new file mode 100644
index 00000000..a6a0b73b
--- /dev/null
+++ b/examples/models/123.obj
@@ -0,0 +1,1027 @@
+# 3ds Max Wavefront OBJ Exporter v0.94b - (c)2007 guruware
+# 创建的文件:26.06.2018 22:05:34
+
+mtllib 123.mtl
+
+#
+# object Layer_________________
+#
+
+v 225140.9219 0.0000 -587937.5625
+v 228184.0313 111.6000 -583208.6875
+v 228184.0313 0.0000 -583208.6875
+v 226561.2344 111.6000 -582429.8750
+v 224775.7813 0.0000 -587762.3125
+v 226561.2344 0.0000 -582429.8750
+v 226561.4844 0.0000 -582430.0000
+v 230247.8125 0.0000 -574748.7500
+v 230247.8125 282.0000 -574748.7500
+v 226561.4844 111.6000 -582430.0000
+v 231870.6094 0.0000 -575527.5625
+v 231870.6094 282.0000 -575527.5625
+v 228184.2813 0.0000 -583208.8125
+v 228184.2813 111.6000 -583208.8125
+v 225141.1719 0.0000 -587937.6875
+v 224776.0313 0.0000 -587762.4375
+v 219344.8906 0.0000 -597468.1250
+v 219344.8906 111.6000 -597468.1250
+v 215658.6406 282.0000 -605149.3750
+v 215658.6406 0.0000 -605149.3750
+v 217281.4531 0.0000 -605928.1875
+v 217281.4531 282.0000 -605928.1875
+v 220967.7031 0.0000 -598246.9375
+v 220967.7031 111.6000 -598246.9375
+v 222387.9688 0.0000 -592739.1875
+v 222753.0938 0.0000 -592914.4375
+v 220967.4375 111.6000 -598246.8125
+v 222752.8438 0.0000 -592914.3125
+v 220967.4375 0.0000 -598246.8125
+v 222387.7031 0.0000 -592739.0625
+v 219344.6406 111.6000 -597468.0000
+v 219344.6406 0.0000 -597468.0000
+# 32 vertices
+
+vt 1.0000 0.0000 0.0000
+vt 0.0000 1.0000 1.0000
+vt 0.0000 0.0000 1.0000
+vt 1.0000 1.0000 0.0000
+vt 1.0000 0.1414 1.0000
+vt 0.1071 1.0000 0.0000
+vt 0.0000 0.9682 0.0000
+vt 0.5239 0.0000 1.0000
+vt 0.0000 0.0000 0.0000
+vt 1.0000 0.0000 1.0000
+vt 1.0000 1.0000 1.0000
+vt 0.0000 0.3957 0.0000
+vt 0.0000 1.0000 0.0000
+vt 1.0000 0.3957 0.0000
+vt 1.0000 0.0921 1.0000
+vt 0.3057 1.0000 0.0000
+vt 0.0000 0.9079 0.0000
+vt 0.6943 0.0000 1.0000
+vt 0.4762 1.0000 1.0000
+vt 0.0000 0.8586 1.0000
+vt 0.8929 0.0000 0.0000
+vt 1.0000 0.0318 0.0000
+# 22 texture coords
+
+g Layer_________________
+usemtl 09___Default
+s 1
+f 1/1 2/2 3/3
+f 4/4 5/3 6/1
+s 2
+f 2/5 1/6 5/7 4/8
+s 1
+f 7/9 8/10 9/11 10/12
+s 2
+f 11/10 12/11 9/13 8/9
+s 1
+f 13/1 14/14 12/2 11/3
+f 15/1 14/2 13/3
+f 10/4 16/3 7/1
+s 4
+f 14/5 15/6 16/7 10/8
+f 12/15 14/16 10/17 9/18
+s 1
+f 17/9 18/12 19/11 20/10
+s 2
+f 21/10 20/9 19/13 22/11
+s 1
+f 23/1 21/3 22/2 24/14
+s 4
+f 24/19 18/20 25/21 26/22
+s 1
+f 27/4 28/3 29/1
+f 30/10 31/13 32/9
+s off
+f 19/11 18/12 24/14 22/11
+f 20/10 21/10 23/1 17/9
+f 28/3 30/10 32/9 29/1
+f 16/3 15/1 13/1 7/9
+f 8/10 7/9 13/1 11/10
+# 15 polygons - 6 triangles
+
+#
+# object Layer_______________
+#
+
+v 226407.4688 27.0000 -594032.2500
+v 226591.5938 27.0000 -593691.7500
+v 226591.5938 0.0000 -593691.7500
+v 226407.4688 0.0000 -594032.2500
+v 226193.6875 27.0000 -594350.0625
+v 226193.6875 0.0000 -594350.0625
+v 225952.4375 27.0000 -594643.7500
+v 225952.4375 0.0000 -594643.7500
+v 225685.8281 27.0000 -594911.8750
+v 225685.8281 0.0000 -594911.8750
+v 225396.0000 27.0000 -595152.9375
+v 225396.0000 0.0000 -595152.9375
+v 225085.1250 27.0000 -595365.5000
+v 225085.1250 0.0000 -595365.5000
+v 224755.3125 27.0000 -595548.1250
+v 224755.3125 0.0000 -595548.1250
+v 224408.7188 27.0000 -595699.3125
+v 224408.7188 0.0000 -595699.3125
+v 224047.4844 27.0000 -595817.5625
+v 224047.4844 0.0000 -595817.5625
+v 223673.7656 27.0000 -595901.4375
+v 223673.7656 0.0000 -595901.4375
+v 223289.6719 27.0000 -595949.5000
+v 223289.6719 0.0000 -595949.5000
+v 222902.7500 27.0000 -595960.2500
+v 222902.7500 0.0000 -595960.2500
+v 222520.6250 27.0000 -595934.0625
+v 222520.6250 0.0000 -595934.0625
+v 222145.6250 27.0000 -595872.0000
+v 222145.6250 0.0000 -595872.0000
+v 221780.1250 27.0000 -595775.1250
+v 221780.1250 0.0000 -595775.1250
+v 221426.4219 27.0000 -595644.6875
+v 221426.4219 0.0000 -595644.6875
+v 221086.8906 27.0000 -595481.7500
+v 221086.8906 0.0000 -595481.7500
+v 220763.8594 27.0000 -595287.4375
+v 220763.8594 0.0000 -595287.4375
+v 220459.6563 27.0000 -595062.8125
+v 220459.6563 0.0000 -595062.8125
+v 220176.6250 27.0000 -594809.1250
+v 220176.6250 0.0000 -594809.1250
+v 219917.1250 27.0000 -594527.4375
+v 219917.1250 0.0000 -594527.4375
+v 219683.4688 27.0000 -594218.8125
+v 219683.4688 0.0000 -594218.8125
+v 219480.6719 27.0000 -593889.1250
+v 219480.6719 0.0000 -593889.1250
+v 219312.3125 27.0000 -593545.0625
+v 219312.3125 0.0000 -593545.0625
+v 219178.5781 27.0000 -593189.3125
+v 219178.5781 0.0000 -593189.3125
+v 219079.6719 27.0000 -592824.3125
+v 219079.6719 0.0000 -592824.3125
+v 219015.7969 27.0000 -592452.8125
+v 219015.7969 0.0000 -592452.8125
+v 218987.1406 27.0000 -592077.2500
+v 218987.1406 0.0000 -592077.2500
+v 218993.9219 27.0000 -591700.3750
+v 218993.9219 0.0000 -591700.3750
+v 219036.2969 27.0000 -591324.6250
+v 219036.2969 0.0000 -591324.6250
+v 219114.5156 27.0000 -590952.6250
+v 219114.5156 0.0000 -590952.6250
+v 219228.7188 27.0000 -590587.0625
+v 219228.7188 0.0000 -590587.0625
+v 219379.1563 27.0000 -590230.3750
+v 219379.1563 0.0000 -590230.3750
+v 221120.7656 27.0000 -586644.5625
+v 220936.6406 27.0000 -586985.0625
+v 220936.6563 0.0000 -586985.0625
+v 221120.7656 0.0000 -586644.5625
+v 221334.5469 27.0000 -586326.7500
+v 221334.5469 0.0000 -586326.7500
+v 221575.7969 27.0000 -586033.0625
+v 221575.7969 0.0000 -586033.0625
+v 221842.4063 27.0000 -585764.9375
+v 221842.4063 0.0000 -585764.9375
+v 222132.2344 27.0000 -585523.8750
+v 222132.2344 0.0000 -585523.8750
+v 222443.1094 27.0000 -585311.3125
+v 222443.1094 0.0000 -585311.3125
+v 222772.9219 27.0000 -585128.6875
+v 222772.9219 0.0000 -585128.6875
+v 223119.5156 27.0000 -584977.5000
+v 223119.5156 0.0000 -584977.5000
+v 223480.7500 27.0000 -584859.2500
+v 223480.7500 0.0000 -584859.2500
+v 223854.4688 27.0000 -584775.3750
+v 223854.4688 0.0000 -584775.3750
+v 224238.5625 27.0000 -584727.3125
+v 224238.5625 0.0000 -584727.3125
+v 224625.4844 27.0000 -584716.5625
+v 224625.4844 0.0000 -584716.5625
+v 225007.6094 27.0000 -584742.7500
+v 225007.6094 0.0000 -584742.7500
+v 225382.6094 27.0000 -584804.8125
+v 225382.6094 0.0000 -584804.8125
+v 225748.1094 27.0000 -584901.6875
+v 225748.1094 0.0000 -584901.6875
+v 226101.8125 27.0000 -585032.1250
+v 226101.8125 0.0000 -585032.1250
+v 226441.3438 27.0000 -585195.0625
+v 226441.3438 0.0000 -585195.0625
+v 226764.3750 27.0000 -585389.3750
+v 226764.3750 0.0000 -585389.3750
+v 227068.5781 27.0000 -585614.0000
+v 227068.5781 0.0000 -585614.0000
+v 227351.6094 27.0000 -585867.6875
+v 227351.6094 0.0000 -585867.6875
+v 227611.1094 27.0000 -586149.3750
+v 227611.1094 0.0000 -586149.3750
+v 227844.7656 27.0000 -586458.0000
+v 227844.7656 0.0000 -586458.0000
+v 228047.5625 27.0000 -586787.6875
+v 228047.5625 0.0000 -586787.6875
+v 228215.9219 27.0000 -587131.7500
+v 228215.9219 0.0000 -587131.7500
+v 228349.6563 27.0000 -587487.5000
+v 228349.6563 0.0000 -587487.5000
+v 228448.5625 27.0000 -587852.5000
+v 228448.5625 0.0000 -587852.5000
+v 228512.4375 27.0000 -588224.0000
+v 228512.4375 0.0000 -588224.0000
+v 228541.0938 27.0000 -588599.5625
+v 228541.0938 0.0000 -588599.5625
+v 228534.3125 27.0000 -588976.4375
+v 228534.3125 0.0000 -588976.4375
+v 228491.9375 27.0000 -589352.1875
+v 228491.9375 0.0000 -589352.1875
+v 228413.7188 27.0000 -589724.1875
+v 228413.7188 0.0000 -589724.1875
+v 228299.5000 27.0000 -590089.7500
+v 228299.5000 0.0000 -590089.7500
+v 228149.0781 27.0000 -590446.4375
+v 228149.0781 0.0000 -590446.4375
+v 225743.7344 0.0000 -592686.1875
+v 225614.8125 0.0000 -592924.5625
+v 225614.8125 27.0000 -592924.5625
+v 225743.7344 27.0000 -592686.1875
+v 225465.1406 0.0000 -593147.0625
+v 225465.1406 27.0000 -593147.0625
+v 225296.2344 0.0000 -593352.6875
+v 225296.2344 27.0000 -593352.6875
+v 225109.5625 0.0000 -593540.4375
+v 225109.5625 27.0000 -593540.4375
+v 224906.6563 0.0000 -593709.2500
+v 224906.6563 27.0000 -593709.2500
+v 224689.0000 0.0000 -593858.0625
+v 224689.0000 27.0000 -593858.0625
+v 224458.0781 0.0000 -593985.8750
+v 224458.0781 27.0000 -593985.8750
+v 224215.4219 0.0000 -594091.7500
+v 224215.4219 27.0000 -594091.7500
+v 223962.5156 0.0000 -594174.5000
+v 223962.5156 27.0000 -594174.5000
+v 223700.8594 0.0000 -594233.2500
+v 223700.8594 27.0000 -594233.2500
+v 223431.9375 0.0000 -594266.9375
+v 223431.9375 27.0000 -594266.9375
+v 223161.0313 0.0000 -594274.4375
+v 223161.0313 27.0000 -594274.4375
+v 222893.5000 0.0000 -594256.1250
+v 222893.5000 27.0000 -594256.1250
+v 222630.9531 0.0000 -594212.6250
+v 222630.9531 27.0000 -594212.6250
+v 222375.0469 0.0000 -594144.8125
+v 222375.0469 27.0000 -594144.8125
+v 222127.4219 0.0000 -594053.5000
+v 222127.4219 27.0000 -594053.5000
+v 221889.7031 0.0000 -593939.4375
+v 221889.7031 27.0000 -593939.4375
+v 221663.5313 0.0000 -593803.3750
+v 221663.5313 27.0000 -593803.3750
+v 221450.5469 0.0000 -593646.1250
+v 221450.5469 27.0000 -593646.1250
+v 221252.3906 0.0000 -593468.5000
+v 221252.3906 27.0000 -593468.5000
+v 221070.7031 0.0000 -593271.2500
+v 221070.7031 27.0000 -593271.2500
+v 220907.1094 0.0000 -593055.1875
+v 220907.1094 27.0000 -593055.1875
+v 220765.1250 0.0000 -592824.3750
+v 220765.1250 27.0000 -592824.3750
+v 220647.2500 0.0000 -592583.5000
+v 220647.2500 27.0000 -592583.5000
+v 220553.6250 0.0000 -592334.3750
+v 220553.6250 27.0000 -592334.3750
+v 220484.3750 0.0000 -592078.8750
+v 220484.3750 27.0000 -592078.8750
+v 220439.6563 0.0000 -591818.7500
+v 220439.6563 27.0000 -591818.7500
+v 220419.5938 0.0000 -591555.8125
+v 220419.5938 27.0000 -591555.8125
+v 220424.3281 0.0000 -591291.9375
+v 220424.3281 27.0000 -591291.9375
+v 220454.0156 0.0000 -591028.8750
+v 220454.0156 27.0000 -591028.8750
+v 220508.7656 0.0000 -590768.4375
+v 220508.7656 27.0000 -590768.4375
+v 220588.7344 0.0000 -590512.5000
+v 220588.7344 27.0000 -590512.5000
+v 220694.0469 0.0000 -590262.8125
+v 220694.0469 27.0000 -590262.7500
+v 221784.5000 0.0000 -587990.6250
+v 221913.4219 0.0000 -587752.2500
+v 221913.4219 27.0000 -587752.2500
+v 221784.5000 27.0000 -587990.6250
+v 222063.0781 0.0000 -587529.6875
+v 222063.0781 27.0000 -587529.6875
+v 222232.0000 0.0000 -587324.0625
+v 222232.0000 27.0000 -587324.0625
+v 222418.6563 0.0000 -587136.3750
+v 222418.6563 27.0000 -587136.3750
+v 222621.5781 0.0000 -586967.5625
+v 222621.5781 27.0000 -586967.5625
+v 222839.2344 0.0000 -586818.7500
+v 222839.2344 27.0000 -586818.7500
+v 223070.1406 0.0000 -586690.8750
+v 223070.1406 27.0000 -586690.8750
+v 223312.8125 0.0000 -586585.0625
+v 223312.8125 27.0000 -586585.0625
+v 223565.7188 0.0000 -586502.2500
+v 223565.7188 27.0000 -586502.2500
+v 223827.3750 0.0000 -586443.5000
+v 223827.3750 27.0000 -586443.5000
+v 224096.2969 0.0000 -586409.8750
+v 224096.2969 27.0000 -586409.8750
+v 224367.1875 0.0000 -586402.3125
+v 224367.1875 27.0000 -586402.3125
+v 224634.7344 0.0000 -586420.6875
+v 224634.7344 27.0000 -586420.6875
+v 224897.2813 0.0000 -586464.1875
+v 224897.2813 27.0000 -586464.1875
+v 225153.1875 0.0000 -586531.9375
+v 225153.1875 27.0000 -586531.9375
+v 225400.8125 0.0000 -586623.3125
+v 225400.8125 27.0000 -586623.3125
+v 225638.5313 0.0000 -586737.3750
+v 225638.5313 27.0000 -586737.3750
+v 225864.7031 0.0000 -586873.4375
+v 225864.7031 27.0000 -586873.4375
+v 226077.6875 0.0000 -587030.6875
+v 226077.6875 27.0000 -587030.6875
+v 226275.8438 0.0000 -587208.3125
+v 226275.8438 27.0000 -587208.3125
+v 226457.5313 0.0000 -587405.5625
+v 226457.5313 27.0000 -587405.5625
+v 226621.1094 0.0000 -587621.5625
+v 226621.1094 27.0000 -587621.5625
+v 226763.1094 0.0000 -587852.4375
+v 226763.1094 27.0000 -587852.4375
+v 226880.9844 0.0000 -588093.3125
+v 226880.9844 27.0000 -588093.3125
+v 226974.6094 0.0000 -588342.3750
+v 226974.6094 27.0000 -588342.3750
+v 227043.8594 0.0000 -588597.9375
+v 227043.8594 27.0000 -588597.9375
+v 227088.5781 0.0000 -588858.0625
+v 227088.5781 27.0000 -588858.0625
+v 227108.6406 0.0000 -589120.9375
+v 227108.6406 27.0000 -589120.9375
+v 227103.8906 0.0000 -589384.8750
+v 227103.8906 27.0000 -589384.8750
+v 227074.2188 0.0000 -589647.9375
+v 227074.2188 27.0000 -589647.9375
+v 227019.4688 0.0000 -589908.3750
+v 227019.4688 27.0000 -589908.3750
+v 226939.5000 0.0000 -590164.3125
+v 226939.5000 27.0000 -590164.3125
+v 226834.1719 0.0000 -590414.0625
+v 226834.1719 27.0000 -590414.0625
+# 272 vertices
+
+vt 0.0000 0.0000 0.0000
+# 1 texture coords
+
+g Layer_______________
+usemtl 02___Default
+s 1
+f 33/23 34/23 35/23 36/23
+s 3
+f 37/23 33/23 36/23 38/23
+s 2
+f 39/23 37/23 38/23 40/23
+f 41/23 39/23 40/23 42/23
+f 43/23 41/23 42/23 44/23
+f 45/23 43/23 44/23 46/23
+f 47/23 45/23 46/23 48/23
+f 49/23 47/23 48/23 50/23
+f 51/23 49/23 50/23 52/23
+f 53/23 51/23 52/23 54/23
+f 55/23 53/23 54/23 56/23
+f 57/23 55/23 56/23 58/23
+f 59/23 57/23 58/23 60/23
+f 61/23 59/23 60/23 62/23
+f 63/23 61/23 62/23 64/23
+f 65/23 63/23 64/23 66/23
+f 67/23 65/23 66/23 68/23
+f 69/23 67/23 68/23 70/23
+f 71/23 69/23 70/23 72/23
+f 73/23 71/23 72/23 74/23
+f 75/23 73/23 74/23 76/23
+f 77/23 75/23 76/23 78/23
+f 79/23 77/23 78/23 80/23
+f 81/23 79/23 80/23 82/23
+f 83/23 81/23 82/23 84/23
+f 85/23 83/23 84/23 86/23
+f 87/23 85/23 86/23 88/23
+f 89/23 87/23 88/23 90/23
+f 91/23 89/23 90/23 92/23
+f 93/23 91/23 92/23 94/23
+f 95/23 93/23 94/23 96/23
+f 97/23 95/23 96/23 98/23
+f 99/23 97/23 98/23 100/23
+s 1
+f 101/23 102/23 103/23 104/23
+s 3
+f 105/23 101/23 104/23 106/23
+s 2
+f 107/23 105/23 106/23 108/23
+f 109/23 107/23 108/23 110/23
+f 111/23 109/23 110/23 112/23
+f 113/23 111/23 112/23 114/23
+f 115/23 113/23 114/23 116/23
+f 117/23 115/23 116/23 118/23
+f 119/23 117/23 118/23 120/23
+f 121/23 119/23 120/23 122/23
+f 123/23 121/23 122/23 124/23
+f 125/23 123/23 124/23 126/23
+f 127/23 125/23 126/23 128/23
+f 129/23 127/23 128/23 130/23
+f 131/23 129/23 130/23 132/23
+f 133/23 131/23 132/23 134/23
+f 135/23 133/23 134/23 136/23
+f 137/23 135/23 136/23 138/23
+f 139/23 137/23 138/23 140/23
+f 141/23 139/23 140/23 142/23
+f 143/23 141/23 142/23 144/23
+f 145/23 143/23 144/23 146/23
+f 147/23 145/23 146/23 148/23
+f 149/23 147/23 148/23 150/23
+f 151/23 149/23 150/23 152/23
+f 153/23 151/23 152/23 154/23
+f 155/23 153/23 154/23 156/23
+f 157/23 155/23 156/23 158/23
+f 159/23 157/23 158/23 160/23
+f 161/23 159/23 160/23 162/23
+f 163/23 161/23 162/23 164/23
+f 165/23 163/23 164/23 166/23
+f 167/23 165/23 166/23 168/23
+s 1
+f 34/23 167/23 168/23 35/23
+s off
+f 100/23 103/23 102/23 99/23
+f 36/23 35/23 169/23 170/23
+f 34/23 33/23 171/23 172/23
+f 38/23 36/23 170/23 173/23
+f 33/23 37/23 174/23 171/23
+f 40/23 38/23 173/23 175/23
+f 37/23 39/23 176/23 174/23
+f 42/23 40/23 175/23 177/23
+f 39/23 41/23 178/23 176/23
+f 44/23 42/23 177/23 179/23
+f 41/23 43/23 180/23 178/23
+f 46/23 44/23 179/23 181/23
+f 43/23 45/23 182/23 180/23
+f 48/23 46/23 181/23 183/23
+f 45/23 47/23 184/23 182/23
+f 50/23 48/23 183/23 185/23
+f 47/23 49/23 186/23 184/23
+f 52/23 50/23 185/23 187/23
+f 49/23 51/23 188/23 186/23
+f 54/23 52/23 187/23 189/23
+f 51/23 53/23 190/23 188/23
+f 56/23 54/23 189/23 191/23
+f 53/23 55/23 192/23 190/23
+f 58/23 56/23 191/23 193/23
+f 55/23 57/23 194/23 192/23
+f 60/23 58/23 193/23 195/23
+f 57/23 59/23 196/23 194/23
+f 62/23 60/23 195/23 197/23
+f 59/23 61/23 198/23 196/23
+f 64/23 62/23 197/23 199/23
+f 61/23 63/23 200/23 198/23
+f 66/23 64/23 199/23 201/23
+f 63/23 65/23 202/23 200/23
+f 68/23 66/23 201/23 203/23
+f 65/23 67/23 204/23 202/23
+f 70/23 68/23 203/23 205/23
+f 67/23 69/23 206/23 204/23
+f 72/23 70/23 205/23 207/23
+f 69/23 71/23 208/23 206/23
+f 74/23 72/23 207/23 209/23
+f 71/23 73/23 210/23 208/23
+f 76/23 74/23 209/23 211/23
+f 73/23 75/23 212/23 210/23
+f 78/23 76/23 211/23 213/23
+f 75/23 77/23 214/23 212/23
+f 80/23 78/23 213/23 215/23
+f 77/23 79/23 216/23 214/23
+f 82/23 80/23 215/23 217/23
+f 79/23 81/23 218/23 216/23
+f 84/23 82/23 217/23 219/23
+f 81/23 83/23 220/23 218/23
+f 86/23 84/23 219/23 221/23
+f 83/23 85/23 222/23 220/23
+f 88/23 86/23 221/23 223/23
+f 85/23 87/23 224/23 222/23
+f 90/23 88/23 223/23 225/23
+f 87/23 89/23 226/23 224/23
+f 92/23 90/23 225/23 227/23
+f 89/23 91/23 228/23 226/23
+f 94/23 92/23 227/23 229/23
+f 91/23 93/23 230/23 228/23
+f 96/23 94/23 229/23 231/23
+f 93/23 95/23 232/23 230/23
+f 98/23 96/23 231/23 233/23
+f 95/23 97/23 234/23 232/23
+f 100/23 98/23 233/23 235/23
+f 97/23 99/23 236/23 234/23
+f 104/23 103/23 237/23 238/23
+f 102/23 101/23 239/23 240/23
+f 106/23 104/23 238/23 241/23
+f 101/23 105/23 242/23 239/23
+f 108/23 106/23 241/23 243/23
+f 105/23 107/23 244/23 242/23
+f 110/23 108/23 243/23 245/23
+f 107/23 109/23 246/23 244/23
+f 112/23 110/23 245/23 247/23
+f 109/23 111/23 248/23 246/23
+f 114/23 112/23 247/23 249/23
+f 111/23 113/23 250/23 248/23
+f 116/23 114/23 249/23 251/23
+f 113/23 115/23 252/23 250/23
+f 118/23 116/23 251/23 253/23
+f 115/23 117/23 254/23 252/23
+f 120/23 118/23 253/23 255/23
+f 117/23 119/23 256/23 254/23
+f 122/23 120/23 255/23 257/23
+f 119/23 121/23 258/23 256/23
+f 124/23 122/23 257/23 259/23
+f 121/23 123/23 260/23 258/23
+f 126/23 124/23 259/23 261/23
+f 123/23 125/23 262/23 260/23
+f 128/23 126/23 261/23 263/23
+f 125/23 127/23 264/23 262/23
+f 130/23 128/23 263/23 265/23
+f 127/23 129/23 266/23 264/23
+f 132/23 130/23 265/23 267/23
+f 129/23 131/23 268/23 266/23
+f 134/23 132/23 267/23 269/23
+f 131/23 133/23 270/23 268/23
+f 136/23 134/23 269/23 271/23
+f 133/23 135/23 272/23 270/23
+f 138/23 136/23 271/23 273/23
+f 135/23 137/23 274/23 272/23
+f 140/23 138/23 273/23 275/23
+f 137/23 139/23 276/23 274/23
+f 142/23 140/23 275/23 277/23
+f 139/23 141/23 278/23 276/23
+f 144/23 142/23 277/23 279/23
+f 141/23 143/23 280/23 278/23
+f 146/23 144/23 279/23 281/23
+f 143/23 145/23 282/23 280/23
+f 148/23 146/23 281/23 283/23
+f 145/23 147/23 284/23 282/23
+f 150/23 148/23 283/23 285/23
+f 147/23 149/23 286/23 284/23
+f 152/23 150/23 285/23 287/23
+f 149/23 151/23 288/23 286/23
+f 154/23 152/23 287/23 289/23
+f 151/23 153/23 290/23 288/23
+f 156/23 154/23 289/23 291/23
+f 153/23 155/23 292/23 290/23
+f 158/23 156/23 291/23 293/23
+f 155/23 157/23 294/23 292/23
+f 160/23 158/23 293/23 295/23
+f 157/23 159/23 296/23 294/23
+f 162/23 160/23 295/23 297/23
+f 159/23 161/23 298/23 296/23
+f 164/23 162/23 297/23 299/23
+f 161/23 163/23 300/23 298/23
+f 166/23 164/23 299/23 301/23
+f 163/23 165/23 302/23 300/23
+f 168/23 166/23 301/23 303/23
+f 165/23 167/23 304/23 302/23
+f 35/23 168/23 303/23 169/23
+f 167/23 34/23 172/23 304/23
+f 103/23 100/23 235/23 237/23
+f 99/23 102/23 240/23 236/23
+f 247/23 248/23 250/23 249/23
+s 1
+f 248/23 247/23 245/23 246/23
+f 246/23 245/23 243/23 244/23
+f 244/23 243/23 241/23 242/23
+f 242/23 241/23 238/23 239/23
+f 239/23 238/23 237/23 240/23
+f 240/23 237/23 235/23 236/23
+f 236/23 235/23 233/23 234/23
+f 234/23 233/23 231/23 232/23
+f 232/23 231/23 229/23 230/23
+f 230/23 229/23 227/23 228/23
+f 228/23 227/23 225/23 226/23
+f 226/23 225/23 223/23 224/23
+f 224/23 223/23 221/23 222/23
+f 222/23 221/23 219/23 220/23
+f 220/23 219/23 217/23 218/23
+f 218/23 217/23 215/23 216/23
+f 216/23 215/23 213/23 214/23
+f 214/23 213/23 211/23 212/23
+f 212/23 211/23 209/23 210/23
+f 210/23 209/23 207/23 208/23
+f 208/23 207/23 205/23 206/23
+f 206/23 205/23 203/23 204/23
+f 204/23 203/23 201/23 202/23
+f 202/23 201/23 199/23 200/23
+f 200/23 199/23 197/23 198/23
+f 198/23 197/23 195/23 196/23
+f 196/23 195/23 193/23 194/23
+f 194/23 193/23 191/23 192/23
+f 192/23 191/23 189/23 190/23
+f 190/23 189/23 187/23 188/23
+f 188/23 187/23 185/23 186/23
+f 186/23 185/23 183/23 184/23
+f 184/23 183/23 181/23 182/23
+f 182/23 181/23 179/23 180/23
+f 180/23 179/23 177/23 178/23
+f 178/23 177/23 175/23 176/23
+f 176/23 175/23 173/23 174/23
+f 174/23 173/23 170/23 171/23
+f 171/23 170/23 169/23 172/23
+f 172/23 169/23 303/23 304/23
+f 304/23 303/23 301/23 302/23
+f 302/23 301/23 299/23 300/23
+f 300/23 299/23 297/23 298/23
+f 298/23 297/23 295/23 296/23
+f 296/23 295/23 293/23 294/23
+f 294/23 293/23 291/23 292/23
+f 292/23 291/23 289/23 290/23
+f 290/23 289/23 287/23 288/23
+f 288/23 287/23 285/23 286/23
+f 286/23 285/23 283/23 284/23
+f 284/23 283/23 281/23 282/23
+f 282/23 281/23 279/23 280/23
+f 280/23 279/23 277/23 278/23
+f 278/23 277/23 275/23 276/23
+f 276/23 275/23 273/23 274/23
+f 274/23 273/23 271/23 272/23
+f 272/23 271/23 269/23 270/23
+f 270/23 269/23 267/23 268/23
+f 268/23 267/23 265/23 266/23
+f 266/23 265/23 263/23 264/23
+f 264/23 263/23 261/23 262/23
+f 262/23 261/23 259/23 260/23
+f 260/23 259/23 257/23 258/23
+f 258/23 257/23 255/23 256/23
+f 256/23 255/23 253/23 254/23
+f 254/23 253/23 251/23 252/23
+f 252/23 251/23 249/23 250/23
+# 272 polygons
+
+#
+# object ____002
+#
+
+v 225614.8125 -1.0000 -592924.5625
+v 225743.7344 -0.9955 -592686.1875
+v 223769.8750 -0.9818 -590295.1250
+v 226834.1719 -1.0000 -590414.0625
+v 226939.5000 -1.0000 -590164.3125
+v 227019.4688 -1.0000 -589908.3750
+v 227074.2188 -1.0000 -589647.9375
+v 227103.8906 -1.0000 -589384.8750
+v 227108.6406 -1.0000 -589120.9375
+v 227088.5781 -1.0000 -588858.0625
+v 227043.8594 -1.0000 -588597.9375
+v 226974.6094 -1.0000 -588342.3750
+v 226880.9844 -1.0000 -588093.3125
+v 226763.1094 -1.0000 -587852.4375
+v 226621.1094 -1.0000 -587621.5625
+v 226457.5313 -1.0000 -587405.5625
+v 226275.8438 -1.0000 -587208.3125
+v 226077.6875 -1.0000 -587030.6875
+v 225864.7031 -1.0000 -586873.4375
+v 225638.5313 -1.0000 -586737.3750
+v 225400.8125 -1.0000 -586623.3125
+v 225153.1875 -1.0000 -586531.9375
+v 224897.2813 -1.0000 -586464.1875
+v 224634.7344 -1.0000 -586420.6875
+v 224367.1875 -1.0000 -586402.3125
+v 224096.2969 -1.0000 -586409.8750
+v 223827.3750 -1.0000 -586443.5000
+v 223565.7188 -1.0000 -586502.2500
+v 223312.8125 -1.0000 -586585.0625
+v 223070.1406 -1.0000 -586690.8750
+v 222839.2344 -1.0000 -586818.7500
+v 222621.5781 -1.0000 -586967.5625
+v 222418.6563 -1.0000 -587136.3750
+v 222232.0000 -1.0000 -587324.0625
+v 222063.0781 -1.0000 -587529.6875
+v 221913.4219 -1.0000 -587752.2500
+v 221784.5000 -1.0000 -587990.6250
+v 220694.0469 -1.0000 -590262.8125
+v 220588.7344 -1.0000 -590512.5000
+v 220508.7656 -1.0000 -590768.4375
+v 220454.0156 -1.0000 -591028.8750
+v 220424.3281 -1.0000 -591291.9375
+v 220419.5938 -1.0000 -591555.8125
+v 220439.6563 -1.0000 -591818.7500
+v 220484.3750 -1.0000 -592078.8750
+v 220553.6250 -1.0000 -592334.3750
+v 220647.2500 -1.0000 -592583.5000
+v 220765.1250 -1.0000 -592824.3750
+v 220907.1094 -1.0000 -593055.1875
+v 221070.7031 -1.0000 -593271.2500
+v 221252.3906 -1.0000 -593468.5000
+v 221450.5469 -1.0000 -593646.1250
+v 221663.5313 -1.0000 -593803.3750
+v 221889.7031 -1.0000 -593939.4375
+v 222127.4219 -1.0000 -594053.5000
+v 222375.0469 -1.0000 -594144.8125
+v 222630.9531 -1.0000 -594212.6250
+v 222893.5000 -1.0000 -594256.1250
+v 223161.0313 -1.0000 -594274.4375
+v 223431.9375 -1.0000 -594266.9375
+v 223700.8594 -1.0000 -594233.2500
+v 223962.5156 -1.0000 -594174.5000
+v 224215.4219 -1.0000 -594091.7500
+v 224458.0781 -1.0000 -593985.8750
+v 224689.0000 -1.0000 -593858.0625
+v 224906.6563 -1.0000 -593709.2500
+v 225109.5625 -1.0000 -593540.4375
+v 225296.2344 -1.0048 -593352.7500
+v 225465.1406 -1.0000 -593147.0625
+v 223769.8750 27.3082 -590295.1250
+v 225743.7344 27.2945 -592686.1875
+v 225614.8125 27.2900 -592924.5625
+v 226939.5000 27.2900 -590164.3125
+v 226834.1719 27.2900 -590414.0625
+v 227019.4688 27.2900 -589908.3750
+v 227103.8906 27.2900 -589384.8750
+v 227074.2188 27.2900 -589647.9375
+v 227108.6406 27.2900 -589120.9375
+v 227088.5781 27.2900 -588858.0625
+v 227043.8594 27.2900 -588597.9375
+v 226974.6094 27.2900 -588342.3750
+v 226880.9844 27.2900 -588093.3125
+v 226763.1094 27.2900 -587852.4375
+v 226621.1094 27.2900 -587621.5625
+v 226457.5313 27.2900 -587405.5625
+v 226275.8438 27.2900 -587208.3125
+v 226077.6875 27.2900 -587030.6875
+v 225864.7031 27.2900 -586873.4375
+v 225638.5313 27.2900 -586737.3750
+v 225400.8125 27.2900 -586623.3125
+v 225153.1875 27.2900 -586531.9375
+v 224897.2813 27.2900 -586464.1875
+v 224634.7344 27.2900 -586420.6875
+v 224367.1875 27.2900 -586402.3125
+v 224096.2969 27.2900 -586409.8750
+v 223827.3750 27.2900 -586443.5000
+v 223565.7188 27.2900 -586502.2500
+v 223312.8125 27.2900 -586585.0625
+v 223070.1406 27.2900 -586690.8750
+v 222839.2344 27.2900 -586818.7500
+v 222621.5781 27.2900 -586967.5625
+v 222418.6563 27.2900 -587136.3750
+v 222232.0000 27.2900 -587324.0625
+v 222063.0781 27.2900 -587529.6875
+v 221913.4219 27.2900 -587752.2500
+v 221784.5000 27.2900 -587990.6250
+v 220694.0469 27.2900 -590262.8125
+v 220588.7344 27.2900 -590512.5000
+v 220508.7656 27.2900 -590768.4375
+v 220454.0156 27.2900 -591028.8750
+v 220424.3281 27.2900 -591291.9375
+v 220419.5938 27.2900 -591555.8125
+v 220439.6563 27.2900 -591818.7500
+v 220484.3750 27.2900 -592078.8750
+v 220553.6250 27.2900 -592334.3750
+v 220647.2500 27.2900 -592583.5000
+v 220765.1250 27.2900 -592824.3750
+v 220907.1094 27.2900 -593055.1875
+v 221070.7031 27.2900 -593271.2500
+v 221252.3906 27.2900 -593468.5000
+v 221450.5469 27.2900 -593646.1250
+v 221663.5313 27.2900 -593803.3750
+v 221889.7031 27.2900 -593939.4375
+v 222127.4219 27.2900 -594053.5000
+v 222375.0469 27.2900 -594144.8125
+v 222630.9531 27.2900 -594212.6250
+v 222893.5000 27.2900 -594256.1250
+v 223161.0313 27.2900 -594274.4375
+v 223431.9375 27.2900 -594266.9375
+v 223700.8594 27.2900 -594233.2500
+v 223962.5156 27.2900 -594174.5000
+v 224215.4219 27.2900 -594091.7500
+v 224458.0781 27.2900 -593985.8750
+v 224689.0000 27.2900 -593858.0625
+v 224906.6563 27.2900 -593709.2500
+v 225109.5625 27.2900 -593540.4375
+v 225296.2344 27.2852 -593352.7500
+v 225465.1406 27.2900 -593147.0625
+# 138 vertices
+
+vt 0.0000 0.0000 0.0000
+# 1 texture coords
+
+g ____002
+usemtl 07___Default
+s off
+f 305/24 306/24 307/24
+f 308/24 309/24 307/24
+f 309/24 310/24 307/24
+f 311/24 312/24 307/24
+f 312/24 313/24 307/24
+f 313/24 314/24 307/24
+f 314/24 315/24 307/24
+f 315/24 316/24 307/24
+f 316/24 317/24 307/24
+f 317/24 318/24 307/24
+f 318/24 319/24 307/24
+f 319/24 320/24 307/24
+f 320/24 321/24 307/24
+f 321/24 322/24 307/24
+f 322/24 323/24 307/24
+f 323/24 324/24 307/24
+f 324/24 325/24 307/24
+f 325/24 326/24 307/24
+f 326/24 327/24 307/24
+f 327/24 328/24 307/24
+f 328/24 329/24 307/24
+f 329/24 330/24 307/24
+f 330/24 331/24 307/24
+f 331/24 332/24 307/24
+f 332/24 333/24 307/24
+f 333/24 334/24 307/24
+f 334/24 335/24 307/24
+f 335/24 336/24 307/24
+f 336/24 337/24 307/24
+f 337/24 338/24 307/24
+f 338/24 339/24 307/24
+f 339/24 340/24 307/24
+f 340/24 341/24 307/24
+f 341/24 342/24 307/24
+f 342/24 343/24 307/24
+f 343/24 344/24 307/24
+f 344/24 345/24 307/24
+f 345/24 346/24 307/24
+f 346/24 347/24 307/24
+f 347/24 348/24 307/24
+f 348/24 349/24 307/24
+f 349/24 350/24 307/24
+f 350/24 351/24 307/24
+f 351/24 352/24 307/24
+f 352/24 353/24 307/24
+f 353/24 354/24 307/24
+f 354/24 355/24 307/24
+f 355/24 356/24 307/24
+f 356/24 357/24 307/24
+f 357/24 358/24 307/24
+f 358/24 359/24 307/24
+f 359/24 360/24 307/24
+f 360/24 361/24 307/24
+f 361/24 362/24 307/24
+f 362/24 363/24 307/24
+f 363/24 364/24 307/24
+f 364/24 365/24 307/24
+f 365/24 366/24 307/24
+f 366/24 367/24 307/24
+f 367/24 368/24 307/24
+f 368/24 369/24 307/24
+f 369/24 370/24 307/24
+f 370/24 371/24 307/24
+f 371/24 372/24 307/24
+f 373/24 305/24 307/24
+f 373/24 307/24 372/24
+f 308/24 307/24 306/24
+f 307/24 310/24 311/24
+f 374/24 375/24 376/24
+f 374/24 377/24 378/24
+f 374/24 379/24 377/24
+f 374/24 380/24 381/24
+f 374/24 382/24 380/24
+f 374/24 383/24 382/24
+f 374/24 384/24 383/24
+f 374/24 385/24 384/24
+f 374/24 386/24 385/24
+f 374/24 387/24 386/24
+f 374/24 388/24 387/24
+f 374/24 389/24 388/24
+f 374/24 390/24 389/24
+f 374/24 391/24 390/24
+f 374/24 392/24 391/24
+f 374/24 393/24 392/24
+f 374/24 394/24 393/24
+f 374/24 395/24 394/24
+f 374/24 396/24 395/24
+f 374/24 397/24 396/24
+f 374/24 398/24 397/24
+f 374/24 399/24 398/24
+f 374/24 400/24 399/24
+f 374/24 401/24 400/24
+f 374/24 402/24 401/24
+f 374/24 403/24 402/24
+f 374/24 404/24 403/24
+f 374/24 405/24 404/24
+f 374/24 406/24 405/24
+f 374/24 407/24 406/24
+f 374/24 408/24 407/24
+f 374/24 409/24 408/24
+f 374/24 410/24 409/24
+f 374/24 411/24 410/24
+f 374/24 412/24 411/24
+f 374/24 413/24 412/24
+f 374/24 414/24 413/24
+f 374/24 415/24 414/24
+f 374/24 416/24 415/24
+f 374/24 417/24 416/24
+f 374/24 418/24 417/24
+f 374/24 419/24 418/24
+f 374/24 420/24 419/24
+f 374/24 421/24 420/24
+f 374/24 422/24 421/24
+f 374/24 423/24 422/24
+f 374/24 424/24 423/24
+f 374/24 425/24 424/24
+f 374/24 426/24 425/24
+f 374/24 427/24 426/24
+f 374/24 428/24 427/24
+f 374/24 429/24 428/24
+f 374/24 430/24 429/24
+f 374/24 431/24 430/24
+f 374/24 432/24 431/24
+f 374/24 433/24 432/24
+f 374/24 434/24 433/24
+f 374/24 435/24 434/24
+f 374/24 436/24 435/24
+f 374/24 437/24 436/24
+f 374/24 438/24 437/24
+f 374/24 439/24 438/24
+f 374/24 440/24 439/24
+f 374/24 441/24 440/24
+f 374/24 376/24 442/24
+f 441/24 374/24 442/24
+f 374/24 378/24 375/24
+f 381/24 379/24 374/24
+s 1
+f 376/24 375/24 306/24 305/24
+f 378/24 377/24 309/24 308/24
+f 377/24 379/24 310/24 309/24
+f 381/24 380/24 312/24 311/24
+f 380/24 382/24 313/24 312/24
+f 382/24 383/24 314/24 313/24
+f 383/24 384/24 315/24 314/24
+f 384/24 385/24 316/24 315/24
+f 385/24 386/24 317/24 316/24
+f 386/24 387/24 318/24 317/24
+f 387/24 388/24 319/24 318/24
+f 388/24 389/24 320/24 319/24
+f 389/24 390/24 321/24 320/24
+f 390/24 391/24 322/24 321/24
+f 391/24 392/24 323/24 322/24
+f 392/24 393/24 324/24 323/24
+f 393/24 394/24 325/24 324/24
+f 394/24 395/24 326/24 325/24
+f 395/24 396/24 327/24 326/24
+f 396/24 397/24 328/24 327/24
+f 397/24 398/24 329/24 328/24
+f 398/24 399/24 330/24 329/24
+f 399/24 400/24 331/24 330/24
+f 400/24 401/24 332/24 331/24
+f 401/24 402/24 333/24 332/24
+f 402/24 403/24 334/24 333/24
+f 403/24 404/24 335/24 334/24
+f 404/24 405/24 336/24 335/24
+f 405/24 406/24 337/24 336/24
+f 406/24 407/24 338/24 337/24
+f 407/24 408/24 339/24 338/24
+f 408/24 409/24 340/24 339/24
+f 409/24 410/24 341/24 340/24
+f 410/24 411/24 342/24 341/24
+f 411/24 412/24 343/24 342/24
+f 412/24 413/24 344/24 343/24
+f 413/24 414/24 345/24 344/24
+f 414/24 415/24 346/24 345/24
+f 415/24 416/24 347/24 346/24
+f 416/24 417/24 348/24 347/24
+f 417/24 418/24 349/24 348/24
+f 418/24 419/24 350/24 349/24
+f 419/24 420/24 351/24 350/24
+f 420/24 421/24 352/24 351/24
+f 421/24 422/24 353/24 352/24
+f 422/24 423/24 354/24 353/24
+f 423/24 424/24 355/24 354/24
+f 424/24 425/24 356/24 355/24
+f 425/24 426/24 357/24 356/24
+f 426/24 427/24 358/24 357/24
+f 427/24 428/24 359/24 358/24
+f 428/24 429/24 360/24 359/24
+f 429/24 430/24 361/24 360/24
+f 430/24 431/24 362/24 361/24
+f 431/24 432/24 363/24 362/24
+f 432/24 433/24 364/24 363/24
+f 433/24 434/24 365/24 364/24
+f 434/24 435/24 366/24 365/24
+f 435/24 436/24 367/24 366/24
+f 436/24 437/24 368/24 367/24
+f 437/24 438/24 369/24 368/24
+f 438/24 439/24 370/24 369/24
+f 439/24 440/24 371/24 370/24
+f 440/24 441/24 372/24 371/24
+f 442/24 376/24 305/24 373/24
+f 441/24 442/24 373/24 372/24
+f 375/24 378/24 308/24 306/24
+f 379/24 381/24 311/24 310/24
+# 68 polygons - 136 triangles
+
diff --git a/examples/models/airport.mtl b/examples/models/airport.mtl
new file mode 100644
index 00000000..c98da996
--- /dev/null
+++ b/examples/models/airport.mtl
@@ -0,0 +1,36 @@
+# 3ds Max Wavefront OBJ Exporter v0.94b - (c)2007 guruware
+# 创建的文件:26.06.2018 08:51:08
+
+newmtl 02___Default
+ Ns 10.0000
+ Ni 1.5000
+ d 1.0000
+ Tr 1.0000
+ Tf 1.0000 1.0000 1.0000
+ illum 2
+ Ka 0.0000 0.0000 0.0000
+ Kd 0.5843 0.5843 0.9961
+ Ks 0.0000 0.0000 0.0000
+ Ke 0.0000 0.0000 0.0000
+
+newmtl 07___Default
+ Ns 10.0000
+ Ni 1.5000
+ d 1.0000
+ Tr 1.0000
+ Tf 1.0000 1.0000 1.0000
+ illum 2
+ Ka 0.0000 0.0000 0.0000
+ Kd 1.0000 0.9176 0.0000
+ Ks 0.0000 0.0000 0.0000
+ Ke 0.0000 0.0000 0.0000
+
+newmtl wire_027177088
+ Ns 32
+ d 1
+ Tr 1
+ Tf 1 1 1
+ illum 2
+ Ka 0.0000 0.0000 0.0000
+ Kd 0.1059 0.6941 0.3451
+ Ks 0.3500 0.3500 0.3500
diff --git a/examples/models/airport.obj b/examples/models/airport.obj
new file mode 100644
index 00000000..a7688938
--- /dev/null
+++ b/examples/models/airport.obj
@@ -0,0 +1,1082 @@
+# 3ds Max Wavefront OBJ Exporter v0.94b - (c)2007 guruware
+# 创建的文件:26.06.2018 08:51:08
+
+mtllib 飞机场.mtl
+
+#
+# object Cylinder01
+#
+
+v 1649455.5000 139939.0625 0.2997
+v 1646168.7500 139939.0625 -62717.0234
+v 1646168.7500 263003.5313 -62717.0195
+v 1649455.5000 263003.5313 0.2988
+v 1636344.0000 139939.0625 -124747.0313
+v 1636344.0000 263003.5313 -124747.0313
+v 1620089.3750 139939.0625 -185410.2500
+v 1620089.3750 263003.5313 -185410.2500
+v 1597582.7500 139939.0625 -244042.0469
+v 1597582.7500 263003.5313 -244042.0313
+v 1569070.7500 139939.0625 -300000.0000
+v 1569070.7500 263003.5313 -300000.0000
+v 1534865.7500 139939.0625 -352671.1250
+v 1534865.7500 263003.5313 -352671.1250
+v 1495343.1250 139939.0625 -401477.5625
+v 1495343.1250 263003.5313 -401477.5625
+v 1450933.0000 139939.0625 -445887.6875
+v 1450933.0000 263003.5313 -445887.6875
+v 1402127.6250 139939.0625 -485409.5000
+v 1402127.6250 263003.5313 -485409.5000
+v 1349454.5000 139939.0625 -519615.8750
+v 1349454.5000 263003.5313 -519615.8750
+v 1293497.5000 139939.0625 -548127.2500
+v 1293497.5000 263003.5313 -548127.2500
+v 1234865.7500 139939.0625 -570633.8750
+v 1234865.7500 263003.5313 -570633.8750
+v 1174202.5000 139939.0625 -586888.5625
+v 1174202.5000 263003.5313 -586888.5625
+v 1112172.5000 139939.0625 -596713.1875
+v 1112172.5000 263003.5313 -596713.1875
+v 1049455.5000 139939.0625 -600000.0000
+v 1049455.5000 263003.5313 -600000.0000
+v -0.0170 139939.0625 -600000.0000
+v -62717.1133 139939.0625 -596713.1250
+v -62717.1250 263003.5313 -596713.1250
+v 0.0000 263003.5313 -600000.0000
+v -124747.1172 139939.0625 -586888.5000
+v -124747.1250 263003.5313 -586888.5000
+v -185410.1719 139939.0625 -570633.8750
+v -185410.1250 263003.5313 -570633.8750
+v -244041.9688 139939.0625 -548127.3125
+v -244042.0000 263003.5313 -548127.3125
+v -300000.0625 139939.0625 -519615.1875
+v -300000.1250 263003.5313 -519615.1875
+v -352671.1563 139939.0625 -485410.1875
+v -352671.1250 263003.5313 -485410.1875
+v -401477.4375 139939.0625 -445887.6875
+v -401477.3750 263003.5313 -445887.6875
+v -445887.5000 139939.0625 -401477.6563
+v -445887.5000 263003.5313 -401477.6563
+v -485410.0313 139939.0625 -352671.3750
+v -485410.0000 263003.5313 -352671.3750
+v -519615.1250 139939.0625 -300000.2188
+v -519615.1250 263003.5313 -300000.2188
+v -548127.1250 139939.0625 -244042.3594
+v -548127.1250 263003.5313 -244042.3438
+v -570633.4375 139939.0625 -185411.7656
+v -570633.3750 263003.5313 -185411.7656
+v -586888.6875 139939.0625 -124746.3750
+v -586888.6250 263003.5313 -124746.3750
+v -596713.0625 139939.0625 -62717.6641
+v -596713.1250 263003.5313 -62717.6602
+v -600000.0000 139939.0625 -0.6661
+v -600000.0000 263003.5313 -0.6660
+v -596713.2500 139939.0625 62716.3359
+v -596713.2500 263003.5313 62716.3359
+v -586888.7500 139939.0625 124746.2500
+v -586888.7500 263003.5313 124746.2500
+v -570634.1875 139939.0625 185409.3906
+v -570634.1250 263003.5313 185409.3906
+v -548127.6875 139939.0625 244041.0938
+v -548127.6250 263003.5313 244041.0938
+v -519615.7500 139939.0625 299999.1250
+v -519615.7500 263003.5313 299999.1250
+v -485410.8125 139939.0625 352670.3125
+v -485410.8750 263003.5313 352670.3125
+v -445887.6250 139939.0625 401477.5625
+v -445887.6250 263003.5313 401477.5625
+v -401479.2813 139939.0625 445886.0625
+v -401479.2500 263003.5313 445886.0625
+v -352673.0938 139939.0625 485408.8125
+v -352673.1250 263003.5313 485408.8125
+v -300000.1250 139939.0625 519615.1250
+v -300000.1250 263003.5313 519615.1250
+v -244043.3750 139939.0625 548126.6250
+v -244043.3750 263003.5313 548126.6250
+v -185411.6406 139939.0625 570633.4375
+v -185411.6250 263003.5313 570633.4375
+v -124749.6719 139939.0625 586888.0000
+v -124749.6250 263003.5313 586888.0000
+v -62717.5859 139939.0625 596713.1250
+v -62717.6250 263003.5313 596713.1250
+v -1.6635 139939.0625 600000.0000
+v -1.6250 263003.5313 600000.0000
+v 1049453.7500 139939.0625 600000.0000
+v 1112170.8750 139939.0625 596713.3125
+v 1112170.8750 263003.5313 596713.3125
+v 1049453.7500 263003.5313 600000.0000
+v 1174199.5000 139939.0625 586889.1875
+v 1174199.5000 263003.5313 586889.1875
+v 1234865.0000 139939.0625 570634.1250
+v 1234865.0000 263003.5313 570634.1250
+v 1293495.6250 139939.0625 548128.0625
+v 1293495.6250 263003.5313 548128.0625
+v 1349453.7500 139939.0625 519616.2500
+v 1349453.7500 263003.5313 519616.2500
+v 1402125.0000 139939.0625 485411.4375
+v 1402125.0000 263003.5313 485411.4375
+v 1450931.3750 139939.0625 445889.1875
+v 1450931.3750 263003.5313 445889.1875
+v 1495341.7500 139939.0625 401479.1875
+v 1495341.7500 263003.5313 401479.1875
+v 1534864.2500 139939.0625 352673.0000
+v 1534864.2500 263003.5313 352673.0000
+v 1569069.5000 139939.0625 300002.0938
+v 1569069.5000 263003.5313 300002.0938
+v 1597581.2500 139939.0625 244045.3125
+v 1597581.2500 263003.5313 244045.3125
+v 1620089.0000 139939.0625 185411.5000
+v 1620089.0000 263003.5313 185411.5000
+v 1636343.2500 139939.0625 124750.6563
+v 1636343.2500 263003.5313 124750.6563
+v 1646168.5000 139939.0625 62718.4219
+v 1646168.5000 263003.5313 62718.4219
+v 1449455.5000 139939.0625 -0.0000
+v 1447264.2500 139939.0625 -41811.3867
+v 1440714.5000 139939.0625 -83164.6797
+v 1429878.1250 139939.0625 -123606.8047
+v 1414873.7500 139939.0625 -162694.6563
+v 1395865.6250 139939.0625 -200000.0000
+v 1373062.2500 139939.0625 -235114.0938
+v 1346713.5000 139939.0625 -267652.2500
+v 1317107.7500 139939.0625 -297257.9375
+v 1284569.6250 139939.0625 -323606.8125
+v 1249455.5000 139939.0625 -346410.1875
+v 1212150.1250 139939.0625 -365418.1875
+v 1173062.2500 139939.0625 -380422.6250
+v 1132620.2500 139939.0625 -391259.0625
+v 1091266.8750 139939.0625 -397808.7813
+v 1049455.5000 139939.0625 -400000.0000
+v -0.0175 139939.0625 -400000.0000
+v -41811.4023 139939.0625 -397808.7813
+v -83164.6953 139939.0625 -391259.0313
+v -123606.8125 139939.0625 -380422.5938
+v -162694.6875 139939.0625 -365418.1875
+v -200000.0313 139939.0625 -346410.1563
+v -235114.0781 139939.0625 -323606.8125
+v -267652.1875 139939.0625 -297257.9688
+v -297257.8438 139939.0625 -267652.3125
+v -323606.7188 139939.0625 -235114.2344
+v -346410.0625 139939.0625 -200000.1875
+v -365418.0625 139939.0625 -162694.8906
+v -380422.5313 139939.0625 -123607.0859
+v -391258.9688 139939.0625 -83165.0234
+v -397808.7188 139939.0625 -41811.7773
+v -400000.0000 139939.0625 -0.4419
+v -397808.8125 139939.0625 41810.8984
+v -391259.1563 139939.0625 83164.1563
+v -380422.7813 139939.0625 123606.2422
+v -365418.4375 139939.0625 162694.0781
+v -346410.5000 139939.0625 199999.4219
+v -323607.2188 139939.0625 235113.5313
+v -297258.4375 139939.0625 267651.6875
+v -267652.8438 139939.0625 297257.3750
+v -235114.7813 139939.0625 323606.3125
+v -200000.7813 139939.0625 346409.6875
+v -162695.5313 139939.0625 365417.7813
+v -123607.7578 139939.0625 380422.3125
+v -83165.7031 139939.0625 391258.8125
+v -41812.4727 139939.0625 397808.6563
+v -1.1396 139939.0625 400000.0000
+v 1049454.3750 139939.0625 400000.0000
+v 1091265.7500 139939.0625 397808.8750
+v 1132619.0000 139939.0625 391259.2813
+v 1173061.0000 139939.0625 380423.0000
+v 1212149.0000 139939.0625 365418.7188
+v 1249454.2500 139939.0625 346410.8438
+v 1284568.5000 139939.0625 323607.6250
+v 1317106.6250 139939.0625 297258.9063
+v 1346712.5000 139939.0625 267653.3750
+v 1373061.3750 139939.0625 235115.3594
+v 1395864.8750 139939.0625 200001.3906
+v 1414873.0000 139939.0625 162696.1719
+v 1429877.6250 139939.0625 123608.4141
+v 1440714.1250 139939.0625 83166.3828
+v 1447264.0000 139939.0625 41813.1641
+v 1447264.2500 163305.2500 -41811.3867
+v 1449455.5000 163305.2500 -0.0000
+v 1447264.0000 163305.2500 41813.1641
+v 1440714.1250 163305.2500 83166.3828
+v 1429877.6250 163305.2500 123608.4141
+v 1414873.0000 163305.2500 162696.1719
+v 1395864.8750 163305.2500 200001.3906
+v 1373061.3750 163305.2500 235115.3594
+v 1346712.5000 163305.2500 267653.3750
+v 1317106.6250 163305.2500 297258.9063
+v 1284568.5000 163305.2500 323607.6250
+v 1249454.2500 163305.2500 346410.8438
+v 1212149.0000 163305.2500 365418.7188
+v 1173061.0000 163305.2500 380423.0000
+v 1132619.0000 163305.2500 391259.2813
+v 1091265.7500 163305.2500 397808.8750
+v 1049454.3750 163305.2500 400000.0000
+v -1.1351 163305.2500 400000.0000
+v -41812.4727 163305.2500 397808.6563
+v -83165.7031 163305.2500 391258.8125
+v -123607.7578 163305.2500 380422.3125
+v -162695.5313 163305.2500 365417.7813
+v -200000.7813 163305.2500 346409.6875
+v -235114.7813 163305.2500 323606.3125
+v -267652.8438 163305.2500 297257.3750
+v -297258.4375 163305.2500 267651.6875
+v -323607.2188 163305.2500 235113.5313
+v -346410.5000 163305.2500 199999.4219
+v -365418.4375 163305.2500 162694.0781
+v -380422.7813 163305.2500 123606.2422
+v -391259.1563 163305.2500 83164.1563
+v -397808.8125 163305.2500 41810.8984
+v -400000.0000 163305.2500 -0.4419
+v -397808.7188 163305.2500 -41811.7773
+v -391258.9688 163305.2500 -83165.0234
+v -380422.5313 163305.2500 -123607.0859
+v -365418.0625 163305.2500 -162694.8906
+v -346410.0625 163305.2500 -200000.1875
+v -323606.7188 163305.2500 -235114.2344
+v -297257.8438 163305.2500 -267652.3125
+v -267652.1875 163305.2500 -297257.9688
+v -235114.0781 163305.2500 -323606.8125
+v -200000.0313 163305.2500 -346410.1563
+v -162694.6875 163305.2500 -365418.1875
+v -123606.8125 163305.2500 -380422.5938
+v -83164.6953 163305.2500 -391259.0313
+v -41811.4023 163305.2500 -397808.7813
+v -0.0166 163305.2500 -400000.0000
+v 1049455.5000 163305.2500 -400000.0000
+v 1091266.8750 163305.2500 -397808.7813
+v 1132620.2500 163305.2500 -391259.0625
+v 1173062.2500 163305.2500 -380422.6250
+v 1212150.1250 163305.2500 -365418.1875
+v 1249455.5000 163305.2500 -346410.1875
+v 1284569.6250 163305.2500 -323606.8125
+v 1317107.7500 163305.2500 -297257.9375
+v 1346713.5000 163305.2500 -267652.2500
+v 1373062.2500 163305.2500 -235114.0938
+v 1395865.6250 163305.2500 -200000.0000
+v 1414873.7500 163305.2500 -162694.6563
+v 1429878.1250 163305.2500 -123606.8047
+v 1440714.5000 163305.2500 -83164.6797
+v 1049453.7500 263003.5313 -600000.0000
+v 1049453.7500 115631.7500 -600000.0000
+v 0.0000 115631.7500 -600000.0000
+v 0.0000 263003.5313 600000.0000
+v 0.0000 115631.7500 600000.0000
+v 1049453.7500 115631.7500 600000.0000
+v -1.1250 115631.7500 400000.0000
+v 1049452.6250 115631.7500 400000.0000
+v 1049452.6250 163305.2500 400000.0000
+v 1049455.5000 115631.7500 -400000.0000
+v 1.7500 115631.7500 -400000.0000
+v 1.7500 163305.2500 -400000.0000
+v 1449455.5000 74700.2500 -0.0000
+v 1447264.2500 74700.2500 -41811.3867
+v 1440714.5000 74700.2500 -83164.6797
+v 1429878.1250 74700.2500 -123606.8047
+v 1414873.7500 74700.2500 -162694.6563
+v 1395865.5000 74700.2500 -200000.0000
+v 1395865.5000 163305.2500 -200000.0000
+v 1373062.2500 74700.2500 -235114.0938
+v 1346713.5000 74700.2500 -267652.2500
+v 1317107.7500 74700.2500 -297257.9375
+v 1284569.7500 74700.2500 -323606.8125
+v 1284569.7500 163305.2500 -323606.8125
+v 1249455.5000 74700.2500 -346410.1875
+v 1212150.1250 74700.2500 -365418.1875
+v 1173062.2500 74700.2500 -380422.6250
+v 1132620.2500 74700.2500 -391259.0625
+v 1091266.8750 74700.2500 -397808.7813
+v 1049455.5000 74700.2500 -400000.0000
+v -0.0156 74700.2500 -400000.0000
+v -41811.4063 74700.2500 -397808.7813
+v -41811.4063 163305.2500 -397808.7813
+v -83164.6953 74700.2500 -391259.0313
+v -123606.8125 74700.2500 -380422.5938
+v -162694.6875 74700.2500 -365418.1875
+v -200000.0313 74700.2500 -346410.1563
+v -235114.0781 74700.2500 -323606.8125
+v -267652.1875 74700.2500 -297257.9688
+v -297257.8438 74700.2500 -267652.3125
+v -323606.7188 74700.2500 -235114.2344
+v -346410.0625 74700.2500 -200000.1875
+v -365418.0625 74700.2500 -162694.8906
+v -380422.5313 74700.2500 -123607.0859
+v -391258.9688 74700.2500 -83165.0234
+v -397808.7188 74700.2500 -41811.7773
+v -400000.0000 74700.2500 -0.4419
+v -397808.8125 74700.2500 41810.8984
+v -391259.1563 74700.2500 83164.1563
+v -380422.7813 74700.2500 123606.2422
+v -365418.4375 74700.2500 162694.0781
+v -346410.5000 74700.2500 199999.4219
+v -323607.2188 74700.2500 235113.5313
+v -297258.4375 74700.2500 267651.6875
+v -267652.8438 74700.2500 297257.3750
+v -235114.7813 74700.2500 323606.3125
+v -200000.7813 74700.2500 346409.6875
+v -162695.5313 74700.2500 365417.7813
+v -123607.7578 74700.2500 380422.3125
+v -83165.7031 74700.2500 391258.8125
+v -41812.4688 74700.2500 397808.6563
+v -41812.4688 163305.2500 397808.6563
+v -1.1406 74700.2500 400000.0000
+v 1049454.3750 74700.2500 400000.0000
+v 1091265.7500 74700.2500 397808.8750
+v 1132619.0000 74700.2500 391259.2813
+v 1173061.0000 74700.2500 380423.0000
+v 1212149.0000 74700.2500 365418.7188
+v 1249454.2500 74700.2500 346410.8438
+v 1284568.5000 74700.2500 323607.6250
+v 1317106.5000 74700.2500 297258.9063
+v 1317106.5000 163305.2500 297258.9063
+v 1346712.5000 74700.2500 267653.3750
+v 1373061.3750 74700.2500 235115.3594
+v 1395864.8750 74700.2500 200001.3906
+v 1414873.0000 74700.2500 162696.1719
+v 1429877.7500 74700.2500 123608.4141
+v 1429877.7500 163305.2500 123608.4141
+v 1440714.0000 74700.2500 83166.3828
+v 1440714.0000 163305.2500 83166.3828
+v 1447264.0000 74700.2500 41813.1641
+v 1049455.2500 163305.2500 0.1008
+v -0.3438 163305.2500 0.1008
+v 1049455.2500 74700.2500 0.0874
+v -0.3438 74700.2500 0.0874
+# 333 vertices
+
+vt 0.7500 0.0000 1.0000
+vt 0.7667 0.0000 1.0000
+vt 0.7667 1.0000 1.0000
+vt 0.7500 1.0000 1.0000
+vt 0.7833 0.0000 1.0000
+vt 0.7833 1.0000 1.0000
+vt 0.8000 0.0000 1.0000
+vt 0.8000 1.0000 1.0000
+vt 0.8167 0.0000 1.0000
+vt 0.8167 1.0000 1.0000
+vt 0.8333 0.0000 1.0000
+vt 0.8333 1.0000 1.0000
+vt 0.8500 0.0000 1.0000
+vt 0.8500 1.0000 1.0000
+vt 0.8667 0.0000 1.0000
+vt 0.8667 1.0000 1.0000
+vt 0.8833 0.0000 1.0000
+vt 0.8833 1.0000 1.0000
+vt 0.9000 0.0000 1.0000
+vt 0.9000 1.0000 1.0000
+vt 0.9167 0.0000 1.0000
+vt 0.9167 1.0000 1.0000
+vt 0.9333 0.0000 1.0000
+vt 0.9333 1.0000 1.0000
+vt 0.9500 0.0000 1.0000
+vt 0.9500 1.0000 1.0000
+vt 0.9667 0.0000 1.0000
+vt 0.9667 1.0000 1.0000
+vt 0.9833 0.0000 1.0000
+vt 0.9833 1.0000 1.0000
+vt 1.0000 0.0000 1.0000
+vt 1.0000 1.0000 1.0000
+vt 0.0000 0.0000 1.0000
+vt 0.0167 0.0000 1.0000
+vt 0.0167 1.0000 1.0000
+vt 0.0000 1.0000 1.0000
+vt 0.0333 0.0000 1.0000
+vt 0.0333 1.0000 1.0000
+vt 0.0500 0.0000 1.0000
+vt 0.0500 1.0000 1.0000
+vt 0.0667 0.0000 1.0000
+vt 0.0667 1.0000 1.0000
+vt 0.0833 0.0000 1.0000
+vt 0.0833 1.0000 1.0000
+vt 0.1000 0.0000 1.0000
+vt 0.1000 1.0000 1.0000
+vt 0.1167 0.0000 1.0000
+vt 0.1167 1.0000 1.0000
+vt 0.1333 0.0000 1.0000
+vt 0.1333 1.0000 1.0000
+vt 0.1500 0.0000 1.0000
+vt 0.1500 1.0000 1.0000
+vt 0.1667 0.0000 1.0000
+vt 0.1667 1.0000 1.0000
+vt 0.1833 0.0000 1.0000
+vt 0.1833 1.0000 1.0000
+vt 0.2000 0.0000 1.0000
+vt 0.2000 1.0000 1.0000
+vt 0.2167 0.0000 1.0000
+vt 0.2167 1.0000 1.0000
+vt 0.2333 0.0000 1.0000
+vt 0.2333 1.0000 1.0000
+vt 0.2500 0.0000 1.0000
+vt 0.2500 1.0000 1.0000
+vt 0.2667 0.0000 1.0000
+vt 0.2667 1.0000 1.0000
+vt 0.2833 0.0000 1.0000
+vt 0.2833 1.0000 1.0000
+vt 0.3000 0.0000 1.0000
+vt 0.3000 1.0000 1.0000
+vt 0.3167 0.0000 1.0000
+vt 0.3167 1.0000 1.0000
+vt 0.3333 0.0000 1.0000
+vt 0.3333 1.0000 1.0000
+vt 0.3500 0.0000 1.0000
+vt 0.3500 1.0000 1.0000
+vt 0.3667 0.0000 1.0000
+vt 0.3667 1.0000 1.0000
+vt 0.3833 0.0000 1.0000
+vt 0.3833 1.0000 1.0000
+vt 0.4000 0.0000 1.0000
+vt 0.4000 1.0000 1.0000
+vt 0.4167 0.0000 1.0000
+vt 0.4167 1.0000 1.0000
+vt 0.4333 0.0000 1.0000
+vt 0.4333 1.0000 1.0000
+vt 0.4500 0.0000 1.0000
+vt 0.4500 1.0000 1.0000
+vt 0.4667 0.0000 1.0000
+vt 0.4667 1.0000 1.0000
+vt 0.4833 0.0000 1.0000
+vt 0.4833 1.0000 1.0000
+vt 0.5000 0.0000 1.0000
+vt 0.5000 1.0000 1.0000
+vt 0.5167 0.0000 1.0000
+vt 0.5167 1.0000 1.0000
+vt 0.5333 0.0000 1.0000
+vt 0.5333 1.0000 1.0000
+vt 0.5500 0.0000 1.0000
+vt 0.5500 1.0000 1.0000
+vt 0.5667 0.0000 1.0000
+vt 0.5667 1.0000 1.0000
+vt 0.5833 0.0000 1.0000
+vt 0.5833 1.0000 1.0000
+vt 0.6000 0.0000 1.0000
+vt 0.6000 1.0000 1.0000
+vt 0.6167 0.0000 1.0000
+vt 0.6167 1.0000 1.0000
+vt 0.6333 0.0000 1.0000
+vt 0.6333 1.0000 1.0000
+vt 0.6500 0.0000 1.0000
+vt 0.6500 1.0000 1.0000
+vt 0.6667 0.0000 1.0000
+vt 0.6667 1.0000 1.0000
+vt 0.6833 0.0000 1.0000
+vt 0.6833 1.0000 1.0000
+vt 0.7000 0.0000 1.0000
+vt 0.7000 1.0000 1.0000
+vt 0.7167 0.0000 1.0000
+vt 0.7167 1.0000 1.0000
+vt 0.7333 0.0000 1.0000
+vt 0.7333 1.0000 1.0000
+vt 0.5000 1.0000 -0.2500
+vt 0.4477 0.9973 -0.2500
+vt 0.3960 0.9891 -0.2500
+vt 0.3455 0.9755 -0.2500
+vt 0.2966 0.9568 -0.2500
+vt 0.2500 0.9330 -0.2500
+vt 0.2061 0.9045 -0.2500
+vt 0.1654 0.8716 -0.2500
+vt 0.1284 0.8346 -0.2500
+vt 0.0955 0.7939 -0.2500
+vt 0.0670 0.7500 -0.2500
+vt 0.0432 0.7034 -0.2500
+vt 0.0245 0.6545 -0.2500
+vt 0.0109 0.6040 -0.2500
+vt 0.0027 0.5523 -0.2500
+vt 0.0000 0.5000 -0.2500
+vt 0.0027 0.4477 -0.2500
+vt 0.0109 0.3960 -0.2500
+vt 0.0245 0.3455 -0.2500
+vt 0.0432 0.2966 -0.2500
+vt 0.0670 0.2500 -0.2500
+vt 0.0955 0.2061 -0.2500
+vt 0.1284 0.1654 -0.2500
+vt 0.1654 0.1284 -0.2500
+vt 0.2061 0.0955 -0.2500
+vt 0.2500 0.0670 -0.2500
+vt 0.2966 0.0432 -0.2500
+vt 0.3455 0.0245 -0.2500
+vt 0.3960 0.0109 -0.2500
+vt 0.4477 0.0027 -0.2500
+vt 0.5000 0.0000 -0.2500
+vt 0.5523 0.0027 -0.2500
+vt 0.6040 0.0109 -0.2500
+vt 0.6545 0.0245 -0.2500
+vt 0.7034 0.0432 -0.2500
+vt 0.7500 0.0670 -0.2500
+vt 0.7939 0.0955 -0.2500
+vt 0.8346 0.1284 -0.2500
+vt 0.8716 0.1654 -0.2500
+vt 0.9045 0.2061 -0.2500
+vt 0.9330 0.2500 -0.2500
+vt 0.9568 0.2966 -0.2500
+vt 0.9755 0.3455 -0.2500
+vt 0.9891 0.3960 -0.2500
+vt 0.9973 0.4477 -0.2500
+vt 1.0000 0.5000 -0.2500
+vt 0.9973 0.5523 -0.2500
+vt 0.9891 0.6040 -0.2500
+vt 0.9755 0.6545 -0.2500
+vt 0.9568 0.7034 -0.2500
+vt 0.9330 0.7500 -0.2500
+vt 0.9045 0.7939 -0.2500
+vt 0.8716 0.8346 -0.2500
+vt 0.8346 0.8716 -0.2500
+vt 0.7939 0.9045 -0.2500
+vt 0.7500 0.9330 -0.2500
+vt 0.7034 0.9568 -0.2500
+vt 0.6545 0.9755 -0.2500
+vt 0.6040 0.9891 -0.2500
+vt 0.5523 0.9973 -0.2500
+vt 0.4477 0.9973 0.2500
+vt 0.5000 1.0000 0.2500
+vt 0.5523 0.9973 0.2500
+vt 0.6040 0.9891 0.2500
+vt 0.6545 0.9755 0.2500
+vt 0.7034 0.9568 0.2500
+vt 0.7500 0.9330 0.2500
+vt 0.7939 0.9045 0.2500
+vt 0.8346 0.8716 0.2500
+vt 0.8716 0.8346 0.2500
+vt 0.9045 0.7939 0.2500
+vt 0.9330 0.7500 0.2500
+vt 0.9568 0.7034 0.2500
+vt 0.9755 0.6545 0.2500
+vt 0.9891 0.6040 0.2500
+vt 0.9973 0.5523 0.2500
+vt 1.0000 0.5000 0.2500
+vt 0.9973 0.4477 0.2500
+vt 0.9891 0.3960 0.2500
+vt 0.9755 0.3455 0.2500
+vt 0.9568 0.2966 0.2500
+vt 0.9330 0.2500 0.2500
+vt 0.9045 0.2061 0.2500
+vt 0.8716 0.1654 0.2500
+vt 0.8346 0.1284 0.2500
+vt 0.7939 0.0955 0.2500
+vt 0.7500 0.0670 0.2500
+vt 0.7034 0.0432 0.2500
+vt 0.6545 0.0245 0.2500
+vt 0.6040 0.0109 0.2500
+vt 0.5523 0.0027 0.2500
+vt 0.5000 0.0000 0.2500
+vt 0.4477 0.0027 0.2500
+vt 0.3960 0.0109 0.2500
+vt 0.3455 0.0245 0.2500
+vt 0.2966 0.0432 0.2500
+vt 0.2500 0.0670 0.2500
+vt 0.2061 0.0955 0.2500
+vt 0.1654 0.1284 0.2500
+vt 0.1284 0.1654 0.2500
+vt 0.0955 0.2061 0.2500
+vt 0.0670 0.2500 0.2500
+vt 0.0432 0.2966 0.2500
+vt 0.0245 0.3455 0.2500
+vt 0.0109 0.3960 0.2500
+vt 0.0027 0.4477 0.2500
+vt 0.0000 0.5000 0.2500
+vt 0.0027 0.5523 0.2500
+vt 0.0109 0.6040 0.2500
+vt 0.0245 0.6545 0.2500
+vt 0.0432 0.7034 0.2500
+vt 0.0670 0.7500 0.2500
+vt 0.0955 0.7939 0.2500
+vt 0.1284 0.8346 0.2500
+vt 0.1654 0.8716 0.2500
+vt 0.2061 0.9045 0.2500
+vt 0.2500 0.9330 0.2500
+vt 0.2966 0.9568 0.2500
+vt 0.3455 0.9755 0.2500
+vt 0.3960 0.9891 0.2500
+vt -524726.8750 600000.0000 0.0000
+vt 524726.8750 600000.0000 0.0000
+vt 524726.8750 600000.0000 -47673.5000
+vt -524726.8750 600000.0000 -47673.5000
+vt 524726.8750 -600000.0000 0.0000
+vt -524726.8750 -600000.0000 0.0000
+vt -524726.8750 -600000.0000 -47673.5000
+vt 524726.8750 -600000.0000 -47673.5000
+vt -524728.0000 -400000.0000 -47673.5000
+vt 524725.7500 -400000.0000 -47673.5000
+vt 524725.7500 -400000.0000 0.0000
+vt -524728.0000 -400000.0000 0.0000
+vt 524728.6250 400000.0000 -47673.5000
+vt -524725.1250 400000.0000 -47673.5000
+vt -524725.1250 400000.0000 0.0000
+vt 524728.6250 400000.0000 0.0000
+vt 0.5000 0.5000 0.2500
+vt 0.5000 0.5000 -0.2500
+# 260 texture coords
+
+g Cylinder01
+usemtl 02___Default
+s 8
+f 1/1 2/2 3/3 4/4
+f 2/2 5/5 6/6 3/3
+f 5/5 7/7 8/8 6/6
+f 7/7 9/9 10/10 8/8
+f 9/9 11/11 12/12 10/10
+f 11/11 13/13 14/14 12/12
+f 13/13 15/15 16/16 14/14
+f 15/15 17/17 18/18 16/16
+f 17/17 19/19 20/20 18/18
+f 19/19 21/21 22/22 20/20
+f 21/21 23/23 24/24 22/22
+f 23/23 25/25 26/26 24/24
+f 25/25 27/27 28/28 26/26
+f 27/27 29/29 30/30 28/28
+f 29/29 31/31 32/32 30/30
+f 33/33 34/34 35/35 36/36
+f 34/34 37/37 38/38 35/35
+f 37/37 39/39 40/40 38/38
+f 39/39 41/41 42/42 40/40
+f 41/41 43/43 44/44 42/42
+f 43/43 45/45 46/46 44/44
+f 45/45 47/47 48/48 46/46
+f 47/47 49/49 50/50 48/48
+f 49/49 51/51 52/52 50/50
+f 51/51 53/53 54/54 52/52
+f 53/53 55/55 56/56 54/54
+f 55/55 57/57 58/58 56/56
+f 57/57 59/59 60/60 58/58
+f 59/59 61/61 62/62 60/60
+f 61/61 63/63 64/64 62/62
+f 63/63 65/65 66/66 64/64
+f 65/65 67/67 68/68 66/66
+f 67/67 69/69 70/70 68/68
+f 69/69 71/71 72/72 70/70
+f 71/71 73/73 74/74 72/72
+f 73/73 75/75 76/76 74/74
+f 75/75 77/77 78/78 76/76
+f 77/77 79/79 80/80 78/78
+f 79/79 81/81 82/82 80/80
+f 81/81 83/83 84/84 82/82
+f 83/83 85/85 86/86 84/84
+f 85/85 87/87 88/88 86/86
+f 87/87 89/89 90/90 88/88
+f 89/89 91/91 92/92 90/90
+f 91/91 93/93 94/94 92/92
+f 95/93 96/95 97/96 98/94
+f 96/95 99/97 100/98 97/96
+f 99/97 101/99 102/100 100/98
+f 101/99 103/101 104/102 102/100
+f 103/101 105/103 106/104 104/102
+f 105/103 107/105 108/106 106/104
+f 107/105 109/107 110/108 108/106
+f 109/107 111/109 112/110 110/108
+f 111/109 113/111 114/112 112/110
+f 113/111 115/113 116/114 114/112
+f 115/113 117/115 118/116 116/114
+f 117/115 119/117 120/118 118/116
+f 119/117 121/119 122/120 120/118
+f 121/119 123/121 124/122 122/120
+f 123/121 1/1 4/4 124/122
+s off
+f 125/123 126/124 2/2 1/1
+f 126/124 127/125 5/5 2/2
+f 127/125 128/126 7/7 5/5
+f 128/126 129/127 9/9 7/7
+f 129/127 130/128 11/11 9/9
+f 130/128 131/129 13/13 11/11
+f 131/129 132/130 15/15 13/13
+f 132/130 133/131 17/17 15/15
+f 133/131 134/132 19/19 17/17
+f 134/132 135/133 21/21 19/19
+f 135/133 136/134 23/23 21/21
+f 136/134 137/135 25/25 23/23
+f 137/135 138/136 27/27 25/25
+f 138/136 139/137 29/29 27/27
+f 139/137 140/138 31/31 29/29
+f 141/138 142/139 34/34 33/33
+f 142/139 143/140 37/37 34/34
+f 143/140 144/141 39/39 37/37
+f 144/141 145/142 41/41 39/39
+f 145/142 146/143 43/43 41/41
+f 146/143 147/144 45/45 43/43
+f 147/144 148/145 47/47 45/45
+f 148/145 149/146 49/49 47/47
+f 149/146 150/147 51/51 49/49
+f 150/147 151/148 53/53 51/51
+f 151/148 152/149 55/55 53/53
+f 152/149 153/150 57/57 55/55
+f 153/150 154/151 59/59 57/57
+f 154/151 155/152 61/61 59/59
+f 155/152 156/153 63/63 61/61
+f 156/153 157/154 65/65 63/63
+f 157/154 158/155 67/67 65/65
+f 158/155 159/156 69/69 67/67
+f 159/156 160/157 71/71 69/69
+f 160/157 161/158 73/73 71/71
+f 161/158 162/159 75/75 73/73
+f 162/159 163/160 77/77 75/75
+f 163/160 164/161 79/79 77/77
+f 164/161 165/162 81/81 79/79
+f 165/162 166/163 83/83 81/81
+f 166/163 167/164 85/85 83/83
+f 167/164 168/165 87/87 85/85
+f 168/165 169/166 89/89 87/87
+f 169/166 170/167 91/91 89/89
+f 170/167 171/168 93/93 91/91
+f 172/168 173/169 96/95 95/93
+f 173/169 174/170 99/97 96/95
+f 174/170 175/171 101/99 99/97
+f 175/171 176/172 103/101 101/99
+f 176/172 177/173 105/103 103/101
+f 177/173 178/174 107/105 105/103
+f 178/174 179/175 109/107 107/105
+f 179/175 180/176 111/109 109/107
+f 180/176 181/177 113/111 111/109
+f 181/177 182/178 115/113 113/111
+f 182/178 183/179 117/115 115/113
+f 183/179 184/180 119/117 117/115
+f 184/180 185/181 121/119 119/117
+f 185/181 186/182 123/121 121/119
+f 186/182 125/123 1/1 123/121
+f 187/183 188/184 4/4 3/3
+f 188/184 189/185 124/122 4/4
+f 189/185 190/186 122/120 124/122
+f 190/186 191/187 120/118 122/120
+f 191/187 192/188 118/116 120/118
+f 192/188 193/189 116/114 118/116
+f 193/189 194/190 114/112 116/114
+f 194/190 195/191 112/110 114/112
+f 195/191 196/192 110/108 112/110
+f 196/192 197/193 108/106 110/108
+f 197/193 198/194 106/104 108/106
+f 198/194 199/195 104/102 106/104
+f 199/195 200/196 102/100 104/102
+f 200/196 201/197 100/98 102/100
+f 201/197 202/198 97/96 100/98
+f 202/198 203/199 98/94 97/96
+f 204/199 205/200 92/92 94/94
+f 205/200 206/201 90/90 92/92
+f 206/201 207/202 88/88 90/90
+f 207/202 208/203 86/86 88/88
+f 208/203 209/204 84/84 86/86
+f 209/204 210/205 82/82 84/84
+f 210/205 211/206 80/80 82/82
+f 211/206 212/207 78/78 80/80
+f 212/207 213/208 76/76 78/78
+f 213/208 214/209 74/74 76/76
+f 214/209 215/210 72/72 74/74
+f 215/210 216/211 70/70 72/72
+f 216/211 217/212 68/68 70/70
+f 217/212 218/213 66/66 68/68
+f 218/213 219/214 64/64 66/66
+f 219/214 220/215 62/62 64/64
+f 220/215 221/216 60/60 62/62
+f 221/216 222/217 58/58 60/60
+f 222/217 223/218 56/56 58/58
+f 223/218 224/219 54/54 56/56
+f 224/219 225/220 52/52 54/54
+f 225/220 226/221 50/50 52/52
+f 226/221 227/222 48/48 50/50
+f 227/222 228/223 46/46 48/48
+f 228/223 229/224 44/44 46/46
+f 229/224 230/225 42/42 44/44
+f 230/225 231/226 40/40 42/42
+f 231/226 232/227 38/38 40/40
+f 232/227 233/228 35/35 38/38
+f 233/228 234/229 36/36 35/35
+f 235/229 236/230 30/30 32/32
+f 236/230 237/231 28/28 30/30
+f 237/231 238/232 26/26 28/28
+f 238/232 239/233 24/24 26/26
+f 239/233 240/234 22/22 24/24
+f 240/234 241/235 20/20 22/22
+f 241/235 242/236 18/18 20/20
+f 242/236 243/237 16/16 18/18
+f 243/237 244/238 14/14 16/16
+f 244/238 245/239 12/12 14/14
+f 245/239 246/240 10/10 12/12
+f 246/240 247/241 8/8 10/10
+f 247/241 248/242 6/6 8/8
+f 248/242 187/183 3/3 6/6
+f 134/132 241/235 240/234 135/133
+s 1
+f 241/235 134/173 133/174 242/236
+f 242/236 133/174 132/175 243/237
+f 243/237 132/175 131/176 244/238
+f 244/238 131/176 130/177 245/239
+f 245/239 130/177 129/178 246/240
+f 246/240 129/178 128/179 247/241
+f 247/241 128/179 127/180 248/242
+f 248/242 127/180 126/181 187/183
+f 187/183 126/181 125/182 188/184
+f 188/184 125/182 186/123 189/185
+f 189/185 186/123 185/124 190/186
+f 190/186 185/124 184/125 191/187
+f 191/187 184/125 183/126 192/188
+f 192/188 183/126 182/127 193/189
+f 193/189 182/127 181/128 194/190
+f 194/190 181/128 180/129 195/191
+f 195/191 180/129 179/130 196/192
+f 196/192 179/130 178/131 197/193
+f 197/193 178/131 177/132 198/194
+f 198/194 177/132 176/133 199/195
+f 199/195 176/133 175/134 200/196
+f 200/196 175/134 174/135 201/197
+f 201/197 174/135 173/136 202/198
+f 202/198 173/136 172/137 203/199
+f 204/199 171/137 170/138 205/200
+f 205/200 170/138 169/139 206/201
+f 206/201 169/139 168/140 207/202
+f 207/202 168/140 167/141 208/203
+f 208/203 167/141 166/142 209/204
+f 209/204 166/142 165/143 210/205
+f 210/205 165/143 164/144 211/206
+f 211/206 164/144 163/145 212/207
+f 212/207 163/145 162/146 213/208
+f 213/208 162/146 161/147 214/209
+f 214/209 161/147 160/148 215/210
+f 215/210 160/148 159/149 216/211
+f 216/211 159/149 158/150 217/212
+f 217/212 158/150 157/151 218/213
+f 218/213 157/151 156/152 219/214
+f 219/214 156/152 155/153 220/215
+f 220/215 155/153 154/154 221/216
+f 221/216 154/154 153/155 222/217
+f 222/217 153/155 152/156 223/218
+f 223/218 152/156 151/157 224/219
+f 224/219 151/157 150/158 225/220
+f 225/220 150/158 149/159 226/221
+f 226/221 149/159 148/160 227/222
+f 227/222 148/160 147/161 228/223
+f 228/223 147/161 146/162 229/224
+f 229/224 146/162 145/163 230/225
+f 230/225 145/163 144/164 231/226
+f 231/226 144/164 143/165 232/227
+f 232/227 143/165 142/166 233/228
+f 233/228 142/166 141/167 234/229
+f 235/229 140/167 139/168 236/230
+f 236/230 139/168 138/169 237/231
+f 237/231 138/169 137/170 238/232
+f 238/232 137/170 136/171 239/233
+f 239/233 136/171 135/172 240/234
+f 36/243 249/244 250/245 251/246
+s 2
+f 98/247 252/248 253/249 254/250
+s 16
+f 255/251 256/252 254/250 253/249
+f 98/247 257/253 204/254 252/248
+f 251/246 250/245 258/255 259/256
+f 249/244 36/243 260/257 235/258
+f 259/256 258/255 256/252 255/251
+usemtl 07___Default
+f 235/258 260/257 204/254 257/253
+s 8
+f 261/1 262/2 187/3 188/4
+f 262/2 263/5 248/6 187/3
+f 263/5 264/7 247/8 248/6
+f 264/7 265/9 246/10 247/8
+f 265/9 266/11 267/12 246/10
+f 266/11 268/13 244/14 267/12
+f 268/13 269/15 243/16 244/14
+f 269/15 270/17 242/18 243/16
+f 270/17 271/19 272/20 242/18
+f 271/19 273/21 240/22 272/20
+f 273/21 274/23 239/24 240/22
+f 274/23 275/25 238/26 239/24
+f 275/25 276/27 237/28 238/26
+f 276/27 277/29 236/30 237/28
+f 277/29 278/31 235/32 236/30
+f 279/33 280/34 281/35 234/36
+f 280/34 282/37 232/38 281/35
+f 282/37 283/39 231/40 232/38
+f 283/39 284/41 230/42 231/40
+f 284/41 285/43 229/44 230/42
+f 285/43 286/45 228/46 229/44
+f 286/45 287/47 227/48 228/46
+f 287/47 288/49 226/50 227/48
+f 288/49 289/51 225/52 226/50
+f 289/51 290/53 224/54 225/52
+f 290/53 291/55 223/56 224/54
+f 291/55 292/57 222/58 223/56
+f 292/57 293/59 221/60 222/58
+f 293/59 294/61 220/62 221/60
+f 294/61 295/63 219/64 220/62
+f 295/63 296/65 218/66 219/64
+f 296/65 297/67 217/68 218/66
+f 297/67 298/69 216/70 217/68
+f 298/69 299/71 215/72 216/70
+f 299/71 300/73 214/74 215/72
+f 300/73 301/75 213/76 214/74
+f 301/75 302/77 212/78 213/76
+f 302/77 303/79 211/80 212/78
+f 303/79 304/81 210/82 211/80
+f 304/81 305/83 209/84 210/82
+f 305/83 306/85 208/86 209/84
+f 306/85 307/87 207/88 208/86
+f 307/87 308/89 206/90 207/88
+f 308/89 309/91 310/92 206/90
+f 309/91 311/93 204/94 310/92
+f 312/93 313/95 202/96 203/94
+f 313/95 314/97 201/98 202/96
+f 314/97 315/99 200/100 201/98
+f 315/99 316/101 199/102 200/100
+f 316/101 317/103 198/104 199/102
+f 317/103 318/105 197/106 198/104
+f 318/105 319/107 320/108 197/106
+f 319/107 321/109 195/110 320/108
+f 321/109 322/111 194/112 195/110
+f 322/111 323/113 193/114 194/112
+f 323/113 324/115 192/116 193/114
+f 324/115 325/117 326/118 192/116
+f 325/117 327/119 328/120 326/118
+f 327/119 329/121 189/122 328/120
+f 329/121 261/1 188/4 189/122
+s off
+f 188/4 187/3 330/259
+f 187/3 248/6 330/259
+f 248/6 247/8 330/259
+f 247/8 246/10 330/259
+f 246/10 267/12 330/259
+f 267/12 244/14 330/259
+f 244/14 243/16 330/259
+f 243/16 242/18 330/259
+f 242/18 272/20 330/259
+f 272/20 240/22 330/259
+f 240/22 239/24 330/259
+f 239/24 238/26 330/259
+f 238/26 237/28 330/259
+f 237/28 236/30 330/259
+f 236/30 235/32 330/259
+f 234/36 281/35 331/259
+f 281/35 232/38 331/259
+f 232/38 231/40 331/259
+f 231/40 230/42 331/259
+f 230/42 229/44 331/259
+f 229/44 228/46 331/259
+f 228/46 227/48 331/259
+f 227/48 226/50 331/259
+f 226/50 225/52 331/259
+f 225/52 224/54 331/259
+f 224/54 223/56 331/259
+f 223/56 222/58 331/259
+f 222/58 221/60 331/259
+f 221/60 220/62 331/259
+f 220/62 219/64 331/259
+f 219/64 218/66 331/259
+f 218/66 217/68 331/259
+f 217/68 216/70 331/259
+f 216/70 215/72 331/259
+f 215/72 214/74 331/259
+f 214/74 213/76 331/259
+f 213/76 212/78 331/259
+f 212/78 211/80 331/259
+f 211/80 210/82 331/259
+f 210/82 209/84 331/259
+f 209/84 208/86 331/259
+f 208/86 207/88 331/259
+f 207/88 206/90 331/259
+f 206/90 310/92 331/259
+f 310/92 204/94 331/259
+f 203/94 202/96 330/259
+f 202/96 201/98 330/259
+f 201/98 200/100 330/259
+f 200/100 199/102 330/259
+f 199/102 198/104 330/259
+f 198/104 197/106 330/259
+f 197/106 320/108 330/259
+f 320/108 195/110 330/259
+f 195/110 194/112 330/259
+f 194/112 193/114 330/259
+f 193/114 192/116 330/259
+f 192/116 326/118 330/259
+f 326/118 328/120 330/259
+f 328/120 189/122 330/259
+f 189/122 188/4 330/259
+f 262/2 261/1 332/260
+f 261/1 329/121 332/260
+f 329/121 327/119 332/260
+f 327/119 325/117 332/260
+f 325/117 324/115 332/260
+f 324/115 323/113 332/260
+f 323/113 322/111 332/260
+f 322/111 321/109 332/260
+f 321/109 319/107 332/260
+f 319/107 318/105 332/260
+f 318/105 317/103 332/260
+f 317/103 316/101 332/260
+f 316/101 315/99 332/260
+f 315/99 314/97 332/260
+f 314/97 313/95 332/260
+f 313/95 312/93 332/260
+f 311/93 309/91 333/260
+f 309/91 308/89 333/260
+f 308/89 307/87 333/260
+f 307/87 306/85 333/260
+f 306/85 305/83 333/260
+f 305/83 304/81 333/260
+f 304/81 303/79 333/260
+f 303/79 302/77 333/260
+f 302/77 301/75 333/260
+f 301/75 300/73 333/260
+f 300/73 299/71 333/260
+f 299/71 298/69 333/260
+f 298/69 297/67 333/260
+f 297/67 296/65 333/260
+f 296/65 295/63 333/260
+f 295/63 294/61 333/260
+f 294/61 293/59 333/260
+f 293/59 292/57 333/260
+f 292/57 291/55 333/260
+f 291/55 290/53 333/260
+f 290/53 289/51 333/260
+f 289/51 288/49 333/260
+f 288/49 287/47 333/260
+f 287/47 286/45 333/260
+f 286/45 285/43 333/260
+f 285/43 284/41 333/260
+f 284/41 283/39 333/260
+f 283/39 282/37 333/260
+f 282/37 280/34 333/260
+f 280/34 279/33 333/260
+f 278/31 277/29 332/260
+f 277/29 276/27 332/260
+f 276/27 275/25 332/260
+f 275/25 274/23 332/260
+f 274/23 273/21 332/260
+f 273/21 271/19 332/260
+f 271/19 270/17 332/260
+f 270/17 269/15 332/260
+f 269/15 268/13 332/260
+f 268/13 266/11 332/260
+f 266/11 265/9 332/260
+f 265/9 264/7 332/260
+f 264/7 263/5 332/260
+f 263/5 262/2 332/260
+# 308 polygons - 120 triangles
+
+#
+# object Box01
+#
+
+v 1040240.2500 95587.5625 63243.6406
+v 1040240.2500 95587.5625 -63243.6406
+v 2111921.5000 95587.5625 -63243.6406
+v 2111921.5000 95587.5625 63243.6406
+v 1040240.2500 129171.4219 63243.6406
+v 2111921.5000 446587.4375 63243.6406
+v 2111921.5000 446587.4375 -63243.6406
+v 1040240.2500 129171.4219 -63243.6406
+# 8 vertices
+
+vt 1.0000 0.0000 0.0000
+vt 1.0000 1.0000 0.0000
+vt 0.0000 1.0000 0.0000
+vt 0.0000 0.0000 0.0000
+# 4 texture coords
+
+g Box01
+usemtl wire_027177088
+s 2
+f 334/261 335/262 336/263 337/264
+s 4
+f 338/264 339/261 340/262 341/263
+s 8
+f 334/264 337/261 339/262 338/263
+s 16
+f 337/264 336/261 340/262 339/263
+s 32
+f 336/264 335/261 341/262 340/263
+s 64
+f 335/264 334/261 338/262 341/263
+# 6 polygons
+
diff --git a/examples/models/bantouming.mtl b/examples/models/bantouming.mtl
new file mode 100644
index 00000000..a2c4ac7b
--- /dev/null
+++ b/examples/models/bantouming.mtl
@@ -0,0 +1,14 @@
+# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
+# 创建的文件:26.06.2018 13:54:08
+
+newmtl 01___Default
+ Ns 10.0000
+ Ni 1.5000
+ d 0.3000
+ Tr 0.7000
+ Tf 0.3000 0.3000 0.3000
+ illum 2
+ Ka 0.0000 0.0000 0.0000
+ Kd 0.3922 0.2745 1.0000
+ Ks 0.0000 0.0000 0.0000
+ Ke 0.0000 0.0000 0.0000
diff --git a/examples/models/bantouming.obj b/examples/models/bantouming.obj
new file mode 100644
index 00000000..7b39495e
--- /dev/null
+++ b/examples/models/bantouming.obj
@@ -0,0 +1,49 @@
+# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
+# 创建的文件:26.06.2018 13:54:08
+
+mtllib 54.mtl
+
+#
+# object Box001
+#
+
+v -149.4397 0.0000 27.5797
+v -149.4397 0.0000 -148.2265
+v 35.0038 0.0000 -148.2265
+v 35.0038 0.0000 27.5797
+v -149.4397 89.2883 27.5797
+v 35.0038 89.2883 27.5797
+v 35.0038 89.2883 -148.2265
+v -149.4397 89.2883 -148.2265
+# 8 vertices
+
+vn 0.0000 -1.0000 -0.0000
+vn 0.0000 1.0000 -0.0000
+vn 0.0000 0.0000 1.0000
+vn 1.0000 0.0000 -0.0000
+vn 0.0000 0.0000 -1.0000
+vn -1.0000 0.0000 -0.0000
+# 6 vertex normals
+
+vt 1.0000 0.0000 0.0000
+vt 1.0000 1.0000 0.0000
+vt 0.0000 1.0000 0.0000
+vt 0.0000 0.0000 0.0000
+# 4 texture coords
+
+g Box001
+usemtl 01___Default
+s 2
+f 1/1/1 2/2/1 3/3/1 4/4/1
+s 4
+f 5/4/2 6/1/2 7/2/2 8/3/2
+s 8
+f 1/4/3 4/1/3 6/2/3 5/3/3
+s 16
+f 4/4/4 3/1/4 7/2/4 6/3/4
+s 32
+f 3/4/5 2/1/5 8/2/5 7/3/5
+s 64
+f 2/4/6 1/1/6 5/2/6 8/3/6
+# 6 polygons
+
diff --git a/examples/models/mapbox.mtl b/examples/models/mapbox.mtl
new file mode 100644
index 00000000..a5f32a91
--- /dev/null
+++ b/examples/models/mapbox.mtl
@@ -0,0 +1,20 @@
+# Blender MTL File: 'None'
+# Material Count: 2
+
+newmtl Material
+Ns 96.078431
+Ka 1.000000 1.000000 1.000000
+Kd 0.640000 0.640000 0.640000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.000000
+d 1.000000
+illum 2
+
+newmtl None
+Ns 0
+Ka 0.000000 0.000000 0.000000
+Kd 0.8 0.8 0.8
+Ks 0.8 0.8 0.8
+d 1
+illum 2
diff --git a/examples/models/mapbox.obj b/examples/models/mapbox.obj
new file mode 100644
index 00000000..7f274383
--- /dev/null
+++ b/examples/models/mapbox.obj
@@ -0,0 +1,293 @@
+# Blender v2.79 (sub 0) OBJ File: ''
+# www.blender.org
+mtllib untitled.mtl
+o BezierCurve
+v 0.941220 -2.061667 1.869847
+v 1.066758 -2.062366 1.765111
+v 1.193945 -2.062910 1.696838
+v 1.324531 -2.063323 1.659822
+v 1.460263 -2.063633 1.648860
+v 1.602890 -2.063865 1.658748
+v 1.754161 -2.064046 1.684282
+v 1.915823 -2.064202 1.720256
+v 2.089626 -2.064358 1.761468
+v 2.277318 -2.064541 1.802713
+v 2.480647 -2.064776 1.838787
+v 2.701362 -2.065090 1.864485
+v 2.941211 -2.065510 1.874604
+l 1 2
+l 2 3
+l 3 4
+l 4 5
+l 5 6
+l 6 7
+l 7 8
+l 8 9
+l 9 10
+l 10 11
+l 11 12
+l 12 13
+o Cone
+v 1.195805 -2.442688 0.544678
+v 1.390895 -2.442688 0.563892
+v 1.578488 -2.442688 0.620798
+v 1.751375 -2.442688 0.713208
+v 1.902911 -2.442688 0.837571
+v 2.027274 -2.442688 0.989108
+v 2.119684 -2.442688 1.161994
+v 2.176590 -2.442688 1.349587
+v 2.195805 -2.442688 1.544678
+v 2.176590 -2.442688 1.739768
+v 2.119684 -2.442688 1.927361
+v 2.027274 -2.442688 2.100248
+v 1.902911 -2.442688 2.251785
+v 1.751375 -2.442688 2.376147
+v 1.578488 -2.442688 2.468557
+v 1.390895 -2.442688 2.525463
+v 1.195804 -2.442688 2.544678
+v 1.000714 -2.442688 2.525463
+v 0.813121 -2.442688 2.468557
+v 0.640234 -2.442688 2.376147
+v 0.488697 -2.442688 2.251784
+v 0.364335 -2.442688 2.100247
+v 0.271925 -2.442688 1.927360
+v 1.195805 -0.442688 1.544678
+v 0.215019 -2.442688 1.739767
+v 0.195805 -2.442688 1.544677
+v 0.215020 -2.442688 1.349586
+v 0.271926 -2.442688 1.161993
+v 0.364336 -2.442688 0.989106
+v 0.488699 -2.442688 0.837570
+v 0.640235 -2.442688 0.713207
+v 0.813123 -2.442688 0.620798
+v 1.000716 -2.442688 0.563892
+vn 0.0878 0.4455 -0.8910
+vn 0.2599 0.4455 -0.8567
+vn 0.4220 0.4455 -0.7896
+vn 0.5680 0.4455 -0.6921
+vn 0.6921 0.4455 -0.5680
+vn 0.7896 0.4455 -0.4220
+vn 0.8567 0.4455 -0.2599
+vn 0.8910 0.4455 -0.0878
+vn 0.8910 0.4455 0.0878
+vn 0.8567 0.4455 0.2599
+vn 0.7896 0.4455 0.4220
+vn 0.6921 0.4455 0.5680
+vn 0.5680 0.4455 0.6921
+vn 0.4220 0.4455 0.7896
+vn 0.2599 0.4455 0.8567
+vn 0.0878 0.4455 0.8910
+vn -0.0878 0.4455 0.8910
+vn -0.2599 0.4455 0.8567
+vn -0.4220 0.4455 0.7896
+vn -0.5680 0.4455 0.6921
+vn -0.6921 0.4455 0.5680
+vn -0.7896 0.4455 0.4220
+vn -0.8567 0.4455 0.2599
+vn -0.8910 0.4455 0.0878
+vn -0.8910 0.4455 -0.0878
+vn -0.8567 0.4455 -0.2599
+vn -0.7896 0.4455 -0.4220
+vn -0.6921 0.4455 -0.5680
+vn -0.5680 0.4455 -0.6921
+vn -0.4220 0.4455 -0.7896
+vn -0.2599 0.4455 -0.8567
+vn -0.0878 0.4455 -0.8910
+vn 0.0000 -1.0000 -0.0000
+usemtl None
+s off
+f 14//1 37//1 15//1
+f 15//2 37//2 16//2
+f 16//3 37//3 17//3
+f 17//4 37//4 18//4
+f 18//5 37//5 19//5
+f 19//6 37//6 20//6
+f 20//7 37//7 21//7
+f 21//8 37//8 22//8
+f 22//9 37//9 23//9
+f 23//10 37//10 24//10
+f 24//11 37//11 25//11
+f 25//12 37//12 26//12
+f 26//13 37//13 27//13
+f 27//14 37//14 28//14
+f 28//15 37//15 29//15
+f 29//16 37//16 30//16
+f 30//17 37//17 31//17
+f 31//18 37//18 32//18
+f 32//19 37//19 33//19
+f 33//20 37//20 34//20
+f 34//21 37//21 35//21
+f 35//22 37//22 36//22
+f 36//23 37//23 38//23
+f 38//24 37//24 39//24
+f 39//25 37//25 40//25
+f 40//26 37//26 41//26
+f 41//27 37//27 42//27
+f 42//28 37//28 43//28
+f 43//29 37//29 44//29
+f 44//30 37//30 45//30
+f 45//31 37//31 46//31
+f 46//32 37//32 14//32
+f 14//33 15//33 16//33 17//33 18//33 19//33 20//33 21//33 22//33 23//33 24//33 25//33 26//33 27//33 28//33 29//33 30//33 31//33 32//33 33//33 34//33 35//33 36//33 38//33 39//33 40//33 41//33 42//33 43//33 44//33 45//33 46//33
+o Circle.001
+v 1.584141 -0.813399 1.340279
+v 1.389050 -0.813399 1.359494
+v 1.201457 -0.813399 1.416400
+v 1.028571 -0.813399 1.508810
+v 0.877034 -0.813399 1.633172
+v 0.752671 -0.813399 1.784709
+v 0.660261 -0.813399 1.957596
+v 0.603356 -0.813399 2.145189
+v 0.584141 -0.813399 2.340279
+v 0.603355 -0.813399 2.535369
+v 0.660261 -0.813399 2.722962
+v 0.752671 -0.813399 2.895849
+v 0.877034 -0.813399 3.047386
+v 1.028571 -0.813399 3.171749
+v 1.201458 -0.813399 3.264159
+v 1.389051 -0.813399 3.321064
+v 1.584141 -0.813399 3.340279
+v 1.779232 -0.813399 3.321064
+v 1.966825 -0.813399 3.264158
+v 2.139711 -0.813399 3.171748
+v 2.291248 -0.813399 3.047385
+v 2.415611 -0.813399 2.895849
+v 2.508021 -0.813399 2.722962
+v 2.564926 -0.813399 2.535368
+v 2.584141 -0.813399 2.340278
+v 2.564926 -0.813399 2.145188
+v 2.508020 -0.813399 1.957595
+v 2.415610 -0.813399 1.784708
+v 2.291247 -0.813399 1.633171
+v 2.139710 -0.813399 1.508809
+v 1.966823 -0.813399 1.416399
+v 1.779230 -0.813399 1.359493
+l 48 47
+l 49 48
+l 50 49
+l 51 50
+l 52 51
+l 53 52
+l 54 53
+l 55 54
+l 56 55
+l 57 56
+l 58 57
+l 59 58
+l 60 59
+l 61 60
+l 62 61
+l 63 62
+l 64 63
+l 65 64
+l 66 65
+l 67 66
+l 68 67
+l 69 68
+l 70 69
+l 71 70
+l 72 71
+l 73 72
+l 74 73
+l 75 74
+l 76 75
+l 77 76
+l 78 77
+l 47 78
+o Circle
+v -0.590843 -0.813399 1.340279
+v -0.785933 -0.813399 1.359494
+v -0.973527 -0.813399 1.416400
+v -1.146413 -0.813399 1.508810
+v -1.297950 -0.813399 1.633172
+v -1.422313 -0.813399 1.784709
+v -1.514723 -0.813399 1.957596
+v -1.571628 -0.813399 2.145189
+v -1.590843 -0.813399 2.340279
+v -1.571629 -0.813399 2.535369
+v -1.514723 -0.813399 2.722962
+v -1.422313 -0.813399 2.895849
+v -1.297950 -0.813399 3.047386
+v -1.146413 -0.813399 3.171749
+v -0.973526 -0.813399 3.264159
+v -0.785933 -0.813399 3.321064
+v -0.590843 -0.813399 3.340279
+v -0.395752 -0.813399 3.321064
+v -0.208159 -0.813399 3.264158
+v -0.035272 -0.813399 3.171748
+v 0.116264 -0.813399 3.047385
+v 0.240627 -0.813399 2.895849
+v 0.333037 -0.813399 2.722962
+v 0.389942 -0.813399 2.535368
+v 0.409157 -0.813399 2.340278
+v 0.389942 -0.813399 2.145188
+v 0.333036 -0.813399 1.957595
+v 0.240626 -0.813399 1.784708
+v 0.116263 -0.813399 1.633171
+v -0.035274 -0.813399 1.508809
+v -0.208161 -0.813399 1.416399
+v -0.395754 -0.813399 1.359493
+l 80 79
+l 81 80
+l 82 81
+l 83 82
+l 84 83
+l 85 84
+l 86 85
+l 87 86
+l 88 87
+l 89 88
+l 90 89
+l 91 90
+l 92 91
+l 93 92
+l 94 93
+l 95 94
+l 96 95
+l 97 96
+l 98 97
+l 99 98
+l 100 99
+l 101 100
+l 102 101
+l 103 102
+l 104 103
+l 105 104
+l 106 105
+l 107 106
+l 108 107
+l 109 108
+l 110 109
+l 79 110
+o Plane
+v -1.000000 0.000000 1.000000
+v 1.000000 0.000000 1.000000
+v -1.000000 0.000000 -1.000000
+v 1.000000 0.000000 -1.000000
+vn 0.0000 1.0000 0.0000
+usemtl None
+s off
+f 111//34 112//34 114//34 113//34
+o Cube
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 1.000000 -0.999999
+v 0.999999 1.000000 1.000001
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+vn 0.0000 -1.0000 0.0000
+vn 0.0000 1.0000 0.0000
+vn 1.0000 0.0000 0.0000
+vn -0.0000 -0.0000 1.0000
+vn -1.0000 -0.0000 -0.0000
+vn 0.0000 0.0000 -1.0000
+usemtl Material
+s off
+f 115//35 116//35 117//35 118//35
+f 119//36 122//36 121//36 120//36
+f 115//37 119//37 120//37 116//37
+f 116//38 120//38 121//38 117//38
+f 117//39 121//39 122//39 118//39
+f 119//40 115//40 118//40 122//40
diff --git a/examples/models/sanlingzhu.mtl b/examples/models/sanlingzhu.mtl
new file mode 100644
index 00000000..e422c22c
--- /dev/null
+++ b/examples/models/sanlingzhu.mtl
@@ -0,0 +1,30 @@
+# Blender MTL File: 'None'
+# Material Count: 3
+
+newmtl None
+Ns 0
+Ka 0.000000 0.000000 0.000000
+Kd 0.8 0.8 0.8
+Ks 0.8 0.8 0.8
+d 1
+illum 2
+
+newmtl 鏉愯川
+Ns 96.078431
+Ka 1.000000 1.000000 1.000000
+Kd 0.640000 0.640000 0.640000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.000000
+d 1.000000
+illum 2
+
+newmtl 鏉愯川.001
+Ns 96.078431
+Ka 1.000000 1.000000 1.000000
+Kd 0.640000 0.640000 0.640000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.000000
+d 1.000000
+illum 2
diff --git a/examples/models/sanlingzhu.obj b/examples/models/sanlingzhu.obj
new file mode 100644
index 00000000..0d1f9c95
--- /dev/null
+++ b/examples/models/sanlingzhu.obj
@@ -0,0 +1,32 @@
+# Blender v2.79 (sub 0) OBJ File: ''
+# www.blender.org
+mtllib 涓夋1鏌.mtl
+o 骞抽潰
+v -10.000000 -1.000000 10.000000
+v 10.000000 -1.000000 10.000000
+v -10.000000 -1.000000 -10.000000
+v 10.000000 -1.000000 -10.000000
+vn 0.0000 1.0000 0.0000
+usemtl None
+s off
+f 1//1 2//1 4//1 3//1
+o 绔嬫柟浣
+v -50.000000 -50.000000 50.000000
+v -50.000000 50.000000 50.000000
+v -50.000000 -50.000000 -50.000000
+v -50.000000 50.000000 -50.000000
+v 50.000000 -50.000000 50.000000
+v 50.000000 -50.000000 -50.000000
+vn -1.0000 0.0000 0.0000
+vn 0.7071 0.7071 0.0000
+vn 0.0000 -1.0000 0.0000
+vn 0.0000 0.0000 -1.0000
+vn 0.0000 0.0000 1.0000
+usemtl 鏉愯川
+s off
+f 5//2 6//2 8//2 7//2
+f 10//3 8//3 6//3 9//3
+f 7//4 10//4 9//4 5//4
+usemtl 鏉愯川.001
+f 7//5 8//5 10//5
+f 9//6 6//6 5//6
diff --git a/examples/sanlingzhu.html b/examples/sanlingzhu.html
new file mode 100644
index 00000000..75da574a
--- /dev/null
+++ b/examples/sanlingzhu.html
@@ -0,0 +1,78 @@
+
+
+ SymboLayer3D example
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/threebox-z.js b/examples/threebox-z.js
new file mode 100644
index 00000000..fd8b024d
--- /dev/null
+++ b/examples/threebox-z.js
@@ -0,0 +1,45218 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o i };
+ console.warn("Using array index for SymbolLayer3D key property.");
+ }
+
+ this.parent = parent;
+
+ this.id = options.id;
+ this.keyGen = ValueGenerator(options.key);
+ if (typeof options.source === "string")
+ this.sourcePath = options.source;
+ else
+ this.source = options.source;
+
+ this.modelDirectoryGen = ValueGenerator(options.modelDirectory);
+ this.modelNameGen = ValueGenerator(options.modelName);
+ this.rotationGen = ValueGenerator(options.rotation);
+ this.scaleGen = ValueGenerator(options.scale);
+ this.models = Object.create(null);
+ this.features = Object.create(null);
+ this.scaleWithMapProjection = options.scaleWithMapProjection;
+
+ this.loaded = false;
+
+ if(this.sourcePath) {
+ // Load source and models
+ const sourceLoader = new THREE.FileLoader();
+
+ sourceLoader.load(this.sourcePath, data => {
+
+ this.source = JSON.parse(data);
+ // TODO: Handle invalid GeoJSON
+
+ this._initialize();
+
+ }, () => (null), error => {
+ return console.error("Could not load SymbolLayer3D source file.")
+ });
+ }
+ else {
+ this._initialize();
+ }
+}
+
+SymbolLayer3D.prototype = {
+ updateSourceData: function(source, absolute) {
+ var oldFeatures = {}
+
+ if (!source.features) return console.error("updateSourceData expects a GeoJSON FeatureCollection with a 'features' property");
+ source.features.forEach((feature, i) => {
+ const key = this.keyGen(feature,i); // TODO: error handling
+ if (key in this.features) {
+ // Update
+ this.features[key].geojson = feature;
+ oldFeatures[key] = feature;
+ }
+ else {
+ // Create
+ const modelDirectory = this.modelDirectoryGen(feature,i);
+ const modelName = this.modelNameGen(feature,i);
+
+ // TODO: Handle loading of new models
+ this.features[key] = {
+ geojson: feature,
+ model: modelDirectory + modelName
+ }
+ }
+ });
+
+ this._addOrUpdateFeatures(this.features)
+
+ if(absolute) {
+ // Check for any features that are not have not been updated and remove them from the scene
+ for(key in this.features) {
+ if(!key in oldFeatures) {
+ this.removeFeature(key);
+ }
+ }
+ }
+
+ this.source = source;
+
+ },
+ removeFeature: function(key) {
+ this.parent.remove(this.features[key].rawObject);
+ delete this.features[key];
+ },
+ _initialize: function() {
+ var modelNames = [];
+
+ // Determine how to load the models
+ if(!this.modelNameGen)
+ return console.error("Invalid model name definition provided to SymbolLayer3D");
+ if(!this.modelDirectoryGen)
+ return console.error("Invalid model directory definition provided to SymbolLayer3D");
+
+ // Add features to a map
+ this.source.features.forEach((f,i) => {
+ const key = this.keyGen(f,i); // TODO: error handling
+ if(this.features[key] !== undefined) console.warn("Features with duplicate key: " + key);
+
+ const modelDirectory = this.modelDirectoryGen(f,i);
+ const modelName = this.modelNameGen(f,i);
+ this.features[key] = {
+ geojson: f,
+ model: modelDirectory + modelName
+ }
+
+ modelNames.push({directory: modelDirectory, name: modelName});
+ });
+
+ // Filter out only unique models
+ modelNames.forEach(m => this.models[(m.directory + m.name)] = { directory: m.directory, name: m.name, loaded: false });
+
+ // And load models asynchronously
+ var remaining = Object.keys(this.models).length;
+ console.log("Loading " + remaining + " models", this.models);
+ const modelComplete = (m) => {
+ console.log("Model complete!", m);
+ //if(this.models[m].loaded)
+ if(--remaining === 0) {
+ this.loaded = true;
+ this._addOrUpdateFeatures(this.features);
+ }
+ }
+
+ for (m in this.models) {
+ // TODO: Support formats other than OBJ/MTL
+ const objLoader = new OBJLoader();
+ const materialLoader = new MTLLoader();
+
+ var loadObject = ((modelName) => { return (materials) => {
+ // Closure madness!
+ if(materials) {
+ materials.preload();
+
+ for(material in (materials.materials)) {
+ materials.materials[material].shininess /= 50; // Shininess exported by Blender is way too high
+ }
+
+ objLoader.setMaterials( materials );
+ }
+ objLoader.setPath(this.models[modelName].directory);
+
+ console.log("Loading model ", modelName);
+
+ objLoader.load(this.models[modelName].name + ".obj", obj => {
+ this.models[modelName].obj = obj;
+ this.models[modelName].isMesh = obj.isMesh;
+ this.models[modelName].loaded = true;
+
+ modelComplete(modelName);
+ }, () => (null), error => {
+ console.error("Could not load SymbolLayer3D model file.");
+ } );
+
+ }})(m);
+
+ materialLoader.setPath(this.models[m].directory);
+ materialLoader.load(this.models[m].name + ".mtl", loadObject, () => (null), error => {
+ console.warn("No material file found for SymbolLayer3D model " + m);
+ loadObject();
+ });
+ }
+ },
+ _addOrUpdateFeatures: function(features) {
+ for (key in features) {
+ const f = features[key];
+ const position = f.geojson.geometry.coordinates;
+ const scale = this.scaleGen(f.geojson);
+
+ const rotation = this.rotationGen(f.geojson);
+
+ var obj;
+ if (!f.rawObject) {
+ // Need to create a scene graph object and add it to the scene
+ if(f.model && this.models[f.model] && this.models[f.model].obj && this.models[f.model].loaded)
+ obj = this.models[f.model].obj.clone();
+ else {
+ console.warn("Model not loaded: " + f.model);
+ obj = new THREE.Group(); // Temporary placeholder if the model doesn't exist and/or will be loaded later
+ }
+
+ f.rawObject = obj;
+
+ this.parent.addAtCoordinate(obj, position, {scaleToLatitude: this.scaleWithMapProjection, preScale: scale});
+ //this.features[key] = f;
+ }
+ else {
+ obj = f.rawObject;
+ this.parent.moveToCoordinate(obj, position, {scaleToLatitude: this.scaleWithMapProjection, preScale: scale});
+ }
+
+ obj.rotation.copy(rotation);
+ }
+ }
+}
+
+module.exports = exports = SymbolLayer3D;
+},{"../Loaders/MTLLoader.js":4,"../Loaders/OBJLoader.js":5,"../Utils/Utils.js":7,"../Utils/ValueGenerator.js":8,"../constants.js":9,"../three64.js":10}],4:[function(require,module,exports){
+/**
+ * Loads a Wavefront .mtl file specifying materials
+ *
+ * @author angelxuanchang
+ */
+
+const THREE = require('../three64.js');
+
+const MTLLoader = function ( manager ) {
+
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+};
+
+MTLLoader.prototype = {
+
+ constructor: MTLLoader,
+
+ /**
+ * Loads and parses a MTL asset from a URL.
+ *
+ * @param {String} url - URL to the MTL file.
+ * @param {Function} [onLoad] - Callback invoked with the loaded object.
+ * @param {Function} [onProgress] - Callback for download progress.
+ * @param {Function} [onError] - Callback for download errors.
+ *
+ * @see setPath setTexturePath
+ *
+ * @note In order for relative texture references to resolve correctly
+ * you must call setPath and/or setTexturePath explicitly prior to load.
+ */
+ load: function ( url, onLoad, onProgress, onError ) {
+
+ var scope = this;
+
+ var loader = new THREE.FileLoader( this.manager );
+ loader.setPath( this.path );
+ loader.load( url, function ( text ) {
+
+ onLoad( scope.parse( text ) );
+
+ }, onProgress, onError );
+
+ },
+
+ /**
+ * Set base path for resolving references.
+ * If set this path will be prepended to each loaded and found reference.
+ *
+ * @see setTexturePath
+ * @param {String} path
+ *
+ * @example
+ * mtlLoader.setPath( 'assets/obj/' );
+ * mtlLoader.load( 'my.mtl', ... );
+ */
+ setPath: function ( path ) {
+
+ this.path = path;
+
+ },
+
+ /**
+ * Set base path for resolving texture references.
+ * If set this path will be prepended found texture reference.
+ * If not set and setPath is, it will be used as texture base path.
+ *
+ * @see setPath
+ * @param {String} path
+ *
+ * @example
+ * mtlLoader.setPath( 'assets/obj/' );
+ * mtlLoader.setTexturePath( 'assets/textures/' );
+ * mtlLoader.load( 'my.mtl', ... );
+ */
+ setTexturePath: function ( path ) {
+
+ this.texturePath = path;
+
+ },
+
+ setBaseUrl: function ( path ) {
+
+ console.warn( 'THREE.MTLLoader: .setBaseUrl() is deprecated. Use .setTexturePath( path ) for texture path or .setPath( path ) for general base path instead.' );
+
+ this.setTexturePath( path );
+
+ },
+
+ setCrossOrigin: function ( value ) {
+
+ this.crossOrigin = value;
+
+ },
+
+ setMaterialOptions: function ( value ) {
+
+ this.materialOptions = value;
+
+ },
+
+ /**
+ * Parses a MTL file.
+ *
+ * @param {String} text - Content of MTL file
+ * @return {THREE.MTLLoader.MaterialCreator}
+ *
+ * @see setPath setTexturePath
+ *
+ * @note In order for relative texture references to resolve correctly
+ * you must call setPath and/or setTexturePath explicitly prior to parse.
+ */
+ parse: function ( text ) {
+
+ var lines = text.split( '\n' );
+ var info = {};
+ var delimiter_pattern = /\s+/;
+ var materialsInfo = {};
+
+ for ( var i = 0; i < lines.length; i ++ ) {
+
+ var line = lines[ i ];
+ line = line.trim();
+
+ if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
+
+ // Blank line or comment ignore
+ continue;
+
+ }
+
+ var pos = line.indexOf( ' ' );
+
+ var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
+ key = key.toLowerCase();
+
+ var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : '';
+ value = value.trim();
+
+ if ( key === 'newmtl' ) {
+
+ // New material
+
+ info = { name: value };
+ materialsInfo[ value ] = info;
+
+ } else if ( info ) {
+
+ if ( key === 'ka' || key === 'kd' || key === 'ks' ) {
+
+ var ss = value.split( delimiter_pattern, 3 );
+ info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];
+
+ } else {
+
+ info[ key ] = value;
+
+ }
+
+ }
+
+ }
+
+ var materialCreator = new MTLLoader.MaterialCreator( this.texturePath || this.path, this.materialOptions );
+ materialCreator.setCrossOrigin( this.crossOrigin );
+ materialCreator.setManager( this.manager );
+ materialCreator.setMaterials( materialsInfo );
+ return materialCreator;
+
+ }
+
+};
+
+/**
+ * Create a new THREE-MTLLoader.MaterialCreator
+ * @param baseUrl - Url relative to which textures are loaded
+ * @param options - Set of options on how to construct the materials
+ * side: Which side to apply the material
+ * THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide
+ * wrap: What type of wrapping to apply for textures
+ * THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
+ * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
+ * Default: false, assumed to be already normalized
+ * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
+ * Default: false
+ * @constructor
+ */
+
+MTLLoader.MaterialCreator = function ( baseUrl, options ) {
+
+ this.baseUrl = baseUrl || '';
+ this.options = options;
+ this.materialsInfo = {};
+ this.materials = {};
+ this.materialsArray = [];
+ this.nameLookup = {};
+
+ this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;
+ this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;
+
+};
+
+MTLLoader.MaterialCreator.prototype = {
+
+ constructor: MTLLoader.MaterialCreator,
+
+ setCrossOrigin: function ( value ) {
+
+ this.crossOrigin = value;
+
+ },
+
+ setManager: function ( value ) {
+
+ this.manager = value;
+
+ },
+
+ setMaterials: function ( materialsInfo ) {
+
+ this.materialsInfo = this.convert( materialsInfo );
+ this.materials = {};
+ this.materialsArray = [];
+ this.nameLookup = {};
+
+ },
+
+ convert: function ( materialsInfo ) {
+
+ if ( ! this.options ) return materialsInfo;
+
+ var converted = {};
+
+ for ( var mn in materialsInfo ) {
+
+ // Convert materials info into normalized form based on options
+
+ var mat = materialsInfo[ mn ];
+
+ var covmat = {};
+
+ converted[ mn ] = covmat;
+
+ for ( var prop in mat ) {
+
+ var save = true;
+ var value = mat[ prop ];
+ var lprop = prop.toLowerCase();
+
+ switch ( lprop ) {
+
+ case 'kd':
+ case 'ka':
+ case 'ks':
+
+ // Diffuse color (color under white light) using RGB values
+
+ if ( this.options && this.options.normalizeRGB ) {
+
+ value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
+
+ }
+
+ if ( this.options && this.options.ignoreZeroRGBs ) {
+
+ if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) {
+
+ // ignore
+
+ save = false;
+
+ }
+
+ }
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+ if ( save ) {
+
+ covmat[ lprop ] = value;
+
+ }
+
+ }
+
+ }
+
+ return converted;
+
+ },
+
+ preload: function () {
+
+ for ( var mn in this.materialsInfo ) {
+
+ this.create( mn );
+
+ }
+
+ },
+
+ getIndex: function ( materialName ) {
+
+ return this.nameLookup[ materialName ];
+
+ },
+
+ getAsArray: function () {
+
+ var index = 0;
+
+ for ( var mn in this.materialsInfo ) {
+
+ this.materialsArray[ index ] = this.create( mn );
+ this.nameLookup[ mn ] = index;
+ index ++;
+
+ }
+
+ return this.materialsArray;
+
+ },
+
+ create: function ( materialName ) {
+
+ if ( this.materials[ materialName ] === undefined ) {
+
+ this.createMaterial_( materialName );
+
+ }
+
+ return this.materials[ materialName ];
+
+ },
+
+ createMaterial_: function ( materialName ) {
+
+ // Create material
+
+ var scope = this;
+ var mat = this.materialsInfo[ materialName ];
+ var params = {
+
+ name: materialName,
+ side: this.side
+
+ };
+
+ function resolveURL( baseUrl, url ) {
+
+ if ( typeof url !== 'string' || url === '' )
+ return '';
+
+ // Absolute URL
+ if ( /^https?:\/\//i.test( url ) ) return url;
+
+ 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 ) {
+
+ var value = mat[ prop ];
+
+ if ( value === '' ) continue;
+
+ switch ( prop.toLowerCase() ) {
+
+ // Ns is material specular exponent
+
+ case 'kd':
+
+ // Diffuse color (color under white light) using RGB values
+
+ params.color = new THREE.Color().fromArray( value );
+
+ break;
+
+ case 'ks':
+
+ // Specular color (color when light is reflected from shiny surface) using RGB values
+ params.specular = new THREE.Color().fromArray( value );
+
+ break;
+
+ case 'map_kd':
+
+ // Diffuse texture map
+
+ setMapForType( "map", value );
+
+ break;
+
+ case 'map_ks':
+
+ // Specular map
+
+ setMapForType( "specularMap", value );
+
+ break;
+
+ case 'map_bump':
+ case 'bump':
+
+ // Bump texture map
+
+ setMapForType( "bumpMap", value );
+
+ break;
+
+ case 'ns':
+
+ // The specular exponent (defines the focus of the specular highlight)
+ // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
+ params.shininess = parseFloat( value );
+
+ break;
+
+ case 'd':
+
+ if ( value < 1 ) {
+
+ params.opacity = value;
+ params.transparent = true;
+
+ }
+
+ break;
+
+ case 'Tr':
+
+ if ( value > 0 ) {
+
+ params.opacity = 1 - value;
+ params.transparent = true;
+
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
+ return this.materials[ materialName ];
+
+ },
+
+ getTextureParams: function ( value, matParams ) {
+
+ var texParams = {
+
+ scale: new THREE.Vector2( 1, 1 ),
+ offset: new THREE.Vector2( 0, 0 )
+
+ };
+
+ var items = value.split( /\s+/ );
+ var pos;
+
+ pos = items.indexOf( '-bm' );
+
+ if ( pos >= 0 ) {
+
+ matParams.bumpScale = parseFloat( items[ pos + 1 ] );
+ items.splice( pos, 2 );
+
+ }
+
+ pos = items.indexOf( '-s' );
+
+ if ( pos >= 0 ) {
+
+ texParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
+ items.splice( pos, 4 ); // we expect 3 parameters here!
+
+ }
+
+ pos = items.indexOf( '-o' );
+
+ if ( pos >= 0 ) {
+
+ texParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
+ items.splice( pos, 4 ); // we expect 3 parameters here!
+
+ }
+
+ texParams.url = items.join( ' ' ).trim();
+ return texParams;
+
+ },
+
+ loadTexture: function ( url, mapping, onLoad, onProgress, onError ) {
+
+ var texture;
+ var loader = THREE.Loader.Handlers.get( url );
+ var manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager;
+
+ if ( loader === null ) {
+
+ loader = new THREE.TextureLoader( manager );
+
+ }
+
+ if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin );
+ texture = loader.load( url, onLoad, onProgress, onError );
+
+ if ( mapping !== undefined ) texture.mapping = mapping;
+
+ return texture;
+
+ }
+
+};
+
+module.exports = exports = MTLLoader;
+},{"../three64.js":10}],5:[function(require,module,exports){
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+const THREE = require('../three64.js');
+
+const OBJLoader = function ( manager ) {
+
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+ this.materials = null;
+
+ this.regexp = {
+ // v float float float
+ vertex_pattern : /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
+ // vn float float float
+ normal_pattern : /^vn\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
+ // vt float float
+ uv_pattern : /^vt\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
+ // f vertex vertex vertex
+ face_vertex : /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/,
+ // f vertex/uv vertex/uv vertex/uv
+ face_vertex_uv : /^f\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+))?/,
+ // f vertex/uv/normal vertex/uv/normal vertex/uv/normal
+ face_vertex_uv_normal : /^f\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+)\/(-?\d+))?/,
+ // f vertex//normal vertex//normal vertex//normal
+ face_vertex_normal : /^f\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)(?:\s+(-?\d+)\/\/(-?\d+))?/,
+ // o object_name | g group_name
+ object_pattern : /^[og]\s*(.+)?/,
+ // s boolean
+ smoothing_pattern : /^s\s+(\d+|on|off)/,
+ // mtllib file_reference
+ material_library_pattern : /^mtllib /,
+ // usemtl material_name
+ material_use_pattern : /^usemtl /
+ };
+
+};
+
+OBJLoader.prototype = {
+
+ constructor: OBJLoader,
+
+ load: function ( url, onLoad, onProgress, onError ) {
+
+ var scope = this;
+
+ var loader = new THREE.FileLoader( scope.manager );
+ loader.setPath( this.path );
+ loader.load( url, function ( text ) {
+
+ onLoad( scope.parse( text ) );
+
+ }, onProgress, onError );
+
+ },
+
+ setPath: function ( value ) {
+
+ this.path = value;
+
+ },
+
+ setMaterials: function ( materials ) {
+
+ this.materials = materials;
+
+ },
+
+ _createParserState : function () {
+
+ var state = {
+ objects : [],
+ object : {},
+
+ vertices : [],
+ normals : [],
+ uvs : [],
+
+ materialLibraries : [],
+
+ startObject: function ( name, fromDeclaration ) {
+
+ // If the current object (initial from reset) is not from a g/o declaration in the parsed
+ // file. We need to use it for the first parsed g/o to keep things in sync.
+ if ( this.object && this.object.fromDeclaration === false ) {
+
+ this.object.name = name;
+ this.object.fromDeclaration = ( fromDeclaration !== false );
+ return;
+
+ }
+
+ var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
+
+ if ( this.object && typeof this.object._finalize === 'function' ) {
+
+ this.object._finalize( true );
+
+ }
+
+ this.object = {
+ name : name || '',
+ fromDeclaration : ( fromDeclaration !== false ),
+
+ geometry : {
+ vertices : [],
+ normals : [],
+ uvs : []
+ },
+ materials : [],
+ smooth : true,
+
+ startMaterial : function( name, libraries ) {
+
+ var previous = this._finalize( false );
+
+ // New usemtl declaration overwrites an inherited material, except if faces were declared
+ // after the material, then it must be preserved for proper MultiMaterial continuation.
+ if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
+
+ this.materials.splice( previous.index, 1 );
+
+ }
+
+ var material = {
+ index : this.materials.length,
+ name : name || '',
+ mtllib : ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
+ smooth : ( previous !== undefined ? previous.smooth : this.smooth ),
+ groupStart : ( previous !== undefined ? previous.groupEnd : 0 ),
+ groupEnd : -1,
+ groupCount : -1,
+ inherited : false,
+
+ clone : function( index ) {
+ var cloned = {
+ index : ( typeof index === 'number' ? index : this.index ),
+ name : this.name,
+ mtllib : this.mtllib,
+ smooth : this.smooth,
+ groupStart : 0,
+ groupEnd : -1,
+ groupCount : -1,
+ inherited : false
+ };
+ cloned.clone = this.clone.bind(cloned);
+ return cloned;
+ }
+ };
+
+ this.materials.push( material );
+
+ return material;
+
+ },
+
+ currentMaterial : function() {
+
+ if ( this.materials.length > 0 ) {
+ return this.materials[ this.materials.length - 1 ];
+ }
+
+ return undefined;
+
+ },
+
+ _finalize : function( end ) {
+
+ var lastMultiMaterial = this.currentMaterial();
+ if ( lastMultiMaterial && lastMultiMaterial.groupEnd === -1 ) {
+
+ lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
+ lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
+ lastMultiMaterial.inherited = false;
+
+ }
+
+ // Ignore objects tail materials if no face declarations followed them before a new o/g started.
+ if ( end && this.materials.length > 1 ) {
+
+ for ( var mi = this.materials.length - 1; mi >= 0; mi-- ) {
+ if ( this.materials[mi].groupCount <= 0 ) {
+ this.materials.splice( mi, 1 );
+ }
+ }
+
+ }
+
+ // Guarantee at least one empty material, this makes the creation later more straight forward.
+ if ( end && this.materials.length === 0 ) {
+
+ this.materials.push({
+ name : '',
+ smooth : this.smooth
+ });
+
+ }
+
+ return lastMultiMaterial;
+
+ }
+ };
+
+ // Inherit previous objects material.
+ // Spec tells us that a declared material must be set to all objects until a new material is declared.
+ // If a usemtl declaration is encountered while this new object is being parsed, it will
+ // overwrite the inherited material. Exception being that there was already face declarations
+ // to the inherited material, then it will be preserved for proper MultiMaterial continuation.
+
+ if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === "function" ) {
+
+ var declared = previousMaterial.clone( 0 );
+ declared.inherited = true;
+ this.object.materials.push( declared );
+
+ }
+
+ this.objects.push( this.object );
+
+ },
+
+ finalize : function() {
+
+ if ( this.object && typeof this.object._finalize === 'function' ) {
+
+ this.object._finalize( true );
+
+ }
+
+ },
+
+ parseVertexIndex: function ( value, len ) {
+
+ var index = parseInt( value, 10 );
+ return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
+
+ },
+
+ parseNormalIndex: function ( value, len ) {
+
+ var index = parseInt( value, 10 );
+ return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
+
+ },
+
+ parseUVIndex: function ( value, len ) {
+
+ var index = parseInt( value, 10 );
+ return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
+
+ },
+
+ addVertex: function ( a, b, c ) {
+
+ var src = this.vertices;
+ var dst = this.object.geometry.vertices;
+
+ dst.push( src[ a + 0 ] );
+ dst.push( src[ a + 1 ] );
+ dst.push( src[ a + 2 ] );
+ dst.push( src[ b + 0 ] );
+ dst.push( src[ b + 1 ] );
+ dst.push( src[ b + 2 ] );
+ dst.push( src[ c + 0 ] );
+ dst.push( src[ c + 1 ] );
+ dst.push( src[ c + 2 ] );
+
+ },
+
+ addVertexLine: function ( a ) {
+
+ var src = this.vertices;
+ var dst = this.object.geometry.vertices;
+
+ dst.push( src[ a + 0 ] );
+ dst.push( src[ a + 1 ] );
+ dst.push( src[ a + 2 ] );
+
+ },
+
+ addNormal : function ( a, b, c ) {
+
+ var src = this.normals;
+ var dst = this.object.geometry.normals;
+
+ dst.push( src[ a + 0 ] );
+ dst.push( src[ a + 1 ] );
+ dst.push( src[ a + 2 ] );
+ dst.push( src[ b + 0 ] );
+ dst.push( src[ b + 1 ] );
+ dst.push( src[ b + 2 ] );
+ dst.push( src[ c + 0 ] );
+ dst.push( src[ c + 1 ] );
+ dst.push( src[ c + 2 ] );
+
+ },
+
+ addUV: function ( a, b, c ) {
+
+ var src = this.uvs;
+ var dst = this.object.geometry.uvs;
+
+ dst.push( src[ a + 0 ] );
+ dst.push( src[ a + 1 ] );
+ dst.push( src[ b + 0 ] );
+ dst.push( src[ b + 1 ] );
+ dst.push( src[ c + 0 ] );
+ dst.push( src[ c + 1 ] );
+
+ },
+
+ addUVLine: function ( a ) {
+
+ var src = this.uvs;
+ var dst = this.object.geometry.uvs;
+
+ dst.push( src[ a + 0 ] );
+ dst.push( src[ a + 1 ] );
+
+ },
+
+ addFace: function ( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {
+
+ var vLen = this.vertices.length;
+
+ var ia = this.parseVertexIndex( a, vLen );
+ var ib = this.parseVertexIndex( b, vLen );
+ var ic = this.parseVertexIndex( c, vLen );
+ var id;
+
+ if ( d === undefined ) {
+
+ this.addVertex( ia, ib, ic );
+
+ } else {
+
+ id = this.parseVertexIndex( d, vLen );
+
+ this.addVertex( ia, ib, id );
+ this.addVertex( ib, ic, id );
+
+ }
+
+ if ( ua !== undefined ) {
+
+ var uvLen = this.uvs.length;
+
+ ia = this.parseUVIndex( ua, uvLen );
+ ib = this.parseUVIndex( ub, uvLen );
+ ic = this.parseUVIndex( uc, uvLen );
+
+ if ( d === undefined ) {
+
+ this.addUV( ia, ib, ic );
+
+ } else {
+
+ id = this.parseUVIndex( ud, uvLen );
+
+ this.addUV( ia, ib, id );
+ this.addUV( ib, ic, id );
+
+ }
+
+ }
+
+ if ( na !== undefined ) {
+
+ // Normals are many times the same. If so, skip function call and parseInt.
+ var nLen = this.normals.length;
+ ia = this.parseNormalIndex( na, nLen );
+
+ ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
+ ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );
+
+ if ( d === undefined ) {
+
+ this.addNormal( ia, ib, ic );
+
+ } else {
+
+ id = this.parseNormalIndex( nd, nLen );
+
+ this.addNormal( ia, ib, id );
+ this.addNormal( ib, ic, id );
+
+ }
+
+ }
+
+ },
+
+ addLineGeometry: function ( vertices, uvs ) {
+
+ this.object.geometry.type = 'Line';
+
+ var vLen = this.vertices.length;
+ var uvLen = this.uvs.length;
+
+ for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
+
+ this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
+
+ }
+
+ for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
+
+ this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
+
+ }
+
+ }
+
+ };
+
+ state.startObject( '', false );
+
+ return state;
+
+ },
+
+ parse: function ( text ) {
+
+ //console.time( 'OBJLoader' );
+
+ var state = this._createParserState();
+
+ if ( text.indexOf( '\r\n' ) !== - 1 ) {
+
+ // This is faster than String.split with regex that splits on both
+ text = text.replace( /\r\n/g, '\n' );
+
+ }
+
+ if ( text.indexOf( '\\\n' ) !== - 1) {
+
+ // join lines separated by a line continuation character (\)
+ text = text.replace( /\\\n/g, '' );
+
+ }
+
+ var lines = text.split( '\n' );
+ var line = '', lineFirstChar = '', lineSecondChar = '';
+ var lineLength = 0;
+ var result = [];
+
+ // Faster to just trim left side of the line. Use if available.
+ var trimLeft = ( typeof ''.trimLeft === 'function' );
+
+ for ( var i = 0, l = lines.length; i < l; i ++ ) {
+
+ line = lines[ i ];
+
+ line = trimLeft ? line.trimLeft() : line.trim();
+
+ lineLength = line.length;
+
+ if ( lineLength === 0 ) continue;
+
+ lineFirstChar = line.charAt( 0 );
+
+ // @todo invoke passed in handler if any
+ if ( lineFirstChar === '#' ) continue;
+
+ if ( lineFirstChar === 'v' ) {
+
+ lineSecondChar = line.charAt( 1 );
+
+ if ( lineSecondChar === ' ' && ( result = this.regexp.vertex_pattern.exec( line ) ) !== null ) {
+
+ // 0 1 2 3
+ // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+
+ state.vertices.push(
+ parseFloat( result[ 1 ] ),
+ parseFloat( result[ 2 ] ),
+ parseFloat( result[ 3 ] )
+ );
+
+ } else if ( lineSecondChar === 'n' && ( result = this.regexp.normal_pattern.exec( line ) ) !== null ) {
+
+ // 0 1 2 3
+ // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+
+ state.normals.push(
+ parseFloat( result[ 1 ] ),
+ parseFloat( result[ 2 ] ),
+ parseFloat( result[ 3 ] )
+ );
+
+ } else if ( lineSecondChar === 't' && ( result = this.regexp.uv_pattern.exec( line ) ) !== null ) {
+
+ // 0 1 2
+ // ["vt 0.1 0.2", "0.1", "0.2"]
+
+ state.uvs.push(
+ parseFloat( result[ 1 ] ),
+ parseFloat( result[ 2 ] )
+ );
+
+ } else {
+
+ throw new Error( "Unexpected vertex/normal/uv line: '" + line + "'" );
+
+ }
+
+ } else if ( lineFirstChar === "f" ) {
+
+ if ( ( result = this.regexp.face_vertex_uv_normal.exec( line ) ) !== null ) {
+
+ // f vertex/uv/normal vertex/uv/normal vertex/uv/normal
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12
+ // ["f 1/1/1 2/2/2 3/3/3", "1", "1", "1", "2", "2", "2", "3", "3", "3", undefined, undefined, undefined]
+
+ state.addFace(
+ result[ 1 ], result[ 4 ], result[ 7 ], result[ 10 ],
+ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
+ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
+ );
+
+ } else if ( ( result = this.regexp.face_vertex_uv.exec( line ) ) !== null ) {
+
+ // f vertex/uv vertex/uv vertex/uv
+ // 0 1 2 3 4 5 6 7 8
+ // ["f 1/1 2/2 3/3", "1", "1", "2", "2", "3", "3", undefined, undefined]
+
+ state.addFace(
+ result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
+ result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
+ );
+
+ } else if ( ( result = this.regexp.face_vertex_normal.exec( line ) ) !== null ) {
+
+ // f vertex//normal vertex//normal vertex//normal
+ // 0 1 2 3 4 5 6 7 8
+ // ["f 1//1 2//2 3//3", "1", "1", "2", "2", "3", "3", undefined, undefined]
+
+ state.addFace(
+ result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
+ undefined, undefined, undefined, undefined,
+ result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
+ );
+
+ } else if ( ( result = this.regexp.face_vertex.exec( line ) ) !== null ) {
+
+ // f vertex vertex vertex
+ // 0 1 2 3 4
+ // ["f 1 2 3", "1", "2", "3", undefined]
+
+ state.addFace(
+ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
+ );
+
+ } else {
+
+ throw new Error( "Unexpected face line: '" + line + "'" );
+
+ }
+
+ } else if ( lineFirstChar === "l" ) {
+
+ var lineParts = line.substring( 1 ).trim().split( " " );
+ var lineVertices = [], lineUVs = [];
+
+ if ( line.indexOf( "/" ) === - 1 ) {
+
+ lineVertices = lineParts;
+
+ } else {
+
+ for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
+
+ var parts = lineParts[ li ].split( "/" );
+
+ if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
+ if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
+
+ }
+
+ }
+ state.addLineGeometry( lineVertices, lineUVs );
+
+ } else if ( ( result = this.regexp.object_pattern.exec( line ) ) !== null ) {
+
+ // o object_name
+ // or
+ // g group_name
+
+ // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
+ // var name = result[ 0 ].substr( 1 ).trim();
+ var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
+
+ state.startObject( name );
+
+ } else if ( this.regexp.material_use_pattern.test( line ) ) {
+
+ // material
+
+ state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
+
+ } else if ( this.regexp.material_library_pattern.test( line ) ) {
+
+ // mtl file
+
+ state.materialLibraries.push( line.substring( 7 ).trim() );
+
+ } else if ( ( result = this.regexp.smoothing_pattern.exec( line ) ) !== null ) {
+
+ // smooth shading
+
+ // @todo Handle files that have varying smooth values for a set of faces inside one geometry,
+ // but does not define a usemtl for each face set.
+ // This should be detected and a dummy material created (later MultiMaterial and geometry groups).
+ // This requires some care to not create extra material on each smooth value for "normal" obj files.
+ // where explicit usemtl defines geometry groups.
+ // Example asset: examples/models/obj/cerberus/Cerberus.obj
+
+ var value = result[ 1 ].trim().toLowerCase();
+ state.object.smooth = ( value === '1' || value === 'on' );
+
+ var material = state.object.currentMaterial();
+ if ( material ) {
+
+ material.smooth = state.object.smooth;
+
+ }
+
+ } else {
+
+ // Handle null terminated files without exception
+ if ( line === '\0' ) continue;
+
+ throw new Error( "Unexpected line: '" + line + "'" );
+
+ }
+
+ }
+
+ state.finalize();
+
+ var container = new THREE.Group();
+ container.materialLibraries = [].concat( state.materialLibraries );
+
+ for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
+
+ var object = state.objects[ i ];
+ var geometry = object.geometry;
+ var materials = object.materials;
+ var isLine = ( geometry.type === 'Line' );
+
+ // Skip o/g line declarations that did not follow with any faces
+ if ( geometry.vertices.length === 0 ) continue;
+
+ var buffergeometry = new THREE.BufferGeometry();
+
+ buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );
+
+ if ( geometry.normals.length > 0 ) {
+
+ buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
+
+ } else {
+
+ buffergeometry.computeVertexNormals();
+
+ }
+
+ if ( geometry.uvs.length > 0 ) {
+
+ buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
+
+ }
+
+ // Create materials
+
+ var createdMaterials = [];
+
+ for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {
+
+ var sourceMaterial = materials[mi];
+ var material = undefined;
+
+ if ( this.materials !== null ) {
+
+ material = this.materials.create( sourceMaterial.name );
+
+ // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
+ if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
+
+ var materialLine = new THREE.LineBasicMaterial();
+ materialLine.copy( material );
+ materialLine.lights = false;
+ material = materialLine;
+
+ }
+
+ }
+
+ if ( ! material ) {
+
+ material = ( ! isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() );
+ material.name = sourceMaterial.name;
+
+ }
+
+ material.shading = sourceMaterial.smooth ? THREE.SmoothShading : THREE.FlatShading;
+
+ createdMaterials.push(material);
+
+ }
+
+ // Create mesh
+
+ var mesh;
+
+ if ( createdMaterials.length > 1 ) {
+
+ for ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {
+
+ var sourceMaterial = materials[mi];
+ buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
+
+ }
+
+ var multiMaterial = new THREE.MultiMaterial( createdMaterials );
+ mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, multiMaterial ) : new THREE.LineSegments( buffergeometry, multiMaterial ) );
+
+ } else {
+
+ mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) );
+ }
+
+ mesh.name = object.name;
+
+ container.add( mesh );
+
+ }
+
+ //console.timeEnd( 'OBJLoader' );
+
+ return container;
+
+ }
+
+};
+
+module.exports = exports = OBJLoader;
+},{"../three64.js":10}],6:[function(require,module,exports){
+var THREE = require("./three64.js"); // Modified version to use 64-bit double precision floats for matrix math
+var ThreeboxConstants = require("./constants.js");
+var CameraSync = require("./Camera/CameraSync.js");
+var utils = require("./Utils/Utils.js");
+//var AnimationManager = require("./Animation/AnimationManager.js");
+var SymbolLayer3D = require("./Layers/SymbolLayer3D.js");
+
+function Threebox(map){
+ this.map = map;
+
+ // Set up a THREE.js scene
+ this.renderer = new THREE.WebGLRenderer( { alpha: true, antialias:true} );
+ this.renderer.setSize( this.map.transform.width, this.map.transform.height );
+ this.renderer.shadowMap.enabled = true;
+
+ this.map._container.appendChild( this.renderer.domElement );
+ this.renderer.domElement.style["position"] = "relative";
+ this.renderer.domElement.style["pointer-events"] = "none";
+ this.renderer.domElement.style["z-index"] = 1000;
+ //this.renderer.domElement.style["transform"] = "scale(1,-1)";
+
+ var _this = this;
+ this.map.on("resize", function() { _this.renderer.setSize(_this.map.transform.width, _this.map.transform.height); } );
+
+
+ this.scene = new THREE.Scene();
+ this.camera = new THREE.PerspectiveCamera( 28, window.innerWidth / window.innerHeight, 0.000001, 5000000000);
+ this.layers = [];
+
+ // The CameraSync object will keep the Mapbox and THREE.js camera movements in sync.
+ // It requires a world group to scale as we zoom in. Rotation is handled in the camera's
+ // projection matrix itself (as is field of view and near/far clipping)
+ // It automatically registers to listen for move events on the map so we don't need to do that here
+ this.world = new THREE.Group();
+ this.scene.add(this.world);
+ this.cameraSynchronizer = new CameraSync(this.map, this.camera, this.world);
+
+ //this.animationManager = new AnimationManager();
+ this.update();
+}
+
+Threebox.prototype = {
+ SymbolLayer3D: SymbolLayer3D,
+
+ update: function(timestamp) {
+ // Update any animations
+ //this.animationManager.update(timestamp);
+
+ // Render the scene
+ this.renderer.render( this.scene, this.camera );
+
+ // Run this again next frame
+ var thisthis = this;
+ requestAnimationFrame(function(timestamp) { thisthis.update(timestamp); } );
+ },
+
+ projectToWorld: function (coords){
+ // Spherical mercator forward projection, re-scaling to WORLD_SIZE
+ var projected = [
+ -ThreeboxConstants.MERCATOR_A * coords[0] * ThreeboxConstants.DEG2RAD * ThreeboxConstants.PROJECTION_WORLD_SIZE,
+ -ThreeboxConstants.MERCATOR_A * Math.log(Math.tan((Math.PI*0.25) + (0.5 * coords[1] * ThreeboxConstants.DEG2RAD))) * ThreeboxConstants.PROJECTION_WORLD_SIZE
+ ];
+
+ var pixelsPerMeter = this.projectedUnitsPerMeter(coords[1]);
+
+ //z dimension
+ var height = coords[2] || 0;
+ projected.push( height * pixelsPerMeter );
+
+ var result = new THREE.Vector3(projected[0], projected[1], projected[2]);
+
+ return result;
+ },
+ projectedUnitsPerMeter: function(latitude) {
+ return Math.abs(ThreeboxConstants.WORLD_SIZE * (1 / Math.cos(latitude*Math.PI/180))/ThreeboxConstants.EARTH_CIRCUMFERENCE);
+ },
+ _scaleVerticesToMeters: function(centerLatLng, vertices) {
+ var pixelsPerMeter = this.projectedUnitsPerMeter(centerLatLng[1]);
+ var centerProjected = this.projectToWorld(centerLatLng);
+
+ for (var i = 0; i < vertices.length; i++) {
+ vertices[i].multiplyScalar(pixelsPerMeter);
+ }
+
+ return vertices;
+ },
+ projectToScreen: function(coords) {
+ console.log("WARNING: Projecting to screen coordinates is not yet implemented");
+ },
+ unprojectFromScreen: function (pixel) {
+ console.log("WARNING: unproject is not yet implemented");
+ },
+ unprojectFromWorld: function (pixel) {
+
+ var unprojected = [
+ -pixel.x / (ThreeboxConstants.MERCATOR_A * ThreeboxConstants.DEG2RAD * ThreeboxConstants.PROJECTION_WORLD_SIZE),
+ 2*(Math.atan(Math.exp(pixel.y/(ThreeboxConstants.PROJECTION_WORLD_SIZE*(-ThreeboxConstants.MERCATOR_A))))-Math.PI/4)/ThreeboxConstants.DEG2RAD
+ ];
+
+ var pixelsPerMeter = this.projectedUnitsPerMeter(unprojected[1]);
+
+ //z dimension
+ var height = pixel.z || 0;
+ unprojected.push( height / pixelsPerMeter );
+
+ return unprojected;
+ },
+
+ _flipMaterialSides: function(obj) {
+
+ },
+
+ addAtCoordinate: function(obj, lnglat, options) {
+ var geoGroup = new THREE.Group();
+ geoGroup.userData.isGeoGroup = true;
+ geoGroup.add(obj);
+ this._flipMaterialSides(obj);
+ this.world.add(geoGroup);
+ this.moveToCoordinate(obj, lnglat, options);
+
+ // Bestow this mesh with animation superpowers and keeps track of its movements in the global animation queue
+ //this.animationManager.enroll(obj);
+
+ return obj;
+ },
+ moveToCoordinate: function(obj, lnglat, options) {
+ /** Place the given object on the map, centered around the provided longitude and latitude
+ The object's internal coordinates are assumed to be in meter-offset format, meaning
+ 1 unit represents 1 meter distance away from the provided coordinate.
+ */
+
+ if (options === undefined) options = {};
+ if(options.preScale === undefined) options.preScale = 1.0;
+
+ options.preScale = 0.001;
+ if(options.scaleToLatitude === undefined || obj.userData.scaleToLatitude) options.scaleToLatitude = true;
+
+ obj.userData.scaleToLatitude = options.scaleToLatitude;
+
+ if (typeof options.preScale === 'number') options.preScale = new THREE.Vector3(options.preScale, options.preScale, options.preScale);
+ else if(options.preScale.constructor === Array && options.preScale.length === 3) options.preScale = new THREE.Vector3(options.preScale[0], options.preScale[1], options.preScale[2]);
+ else if(options.preScale.constructor !== THREE.Vector3) {
+ console.warn("Invalid preScale value: number, Array with length 3, or THREE.Vector3 expected. Defaulting to [1,1,1]");
+ options.preScale = new THREE.Vector3(1,1,1);
+ }
+
+ var scale = options.preScale;
+
+ // Figure out if this object is a geoGroup and should be positioned and scaled directly, or if its parent
+ var geoGroup;
+ if (obj.userData.isGeoGroup) geoGroup = obj;
+ else if (obj.parent && obj.parent.userData.isGeoGroup) geoGroup = obj.parent;
+ else return console.error("Cannot set geographic coordinates of object that does not have an associated GeoGroup. Object must be added to scene with 'addAtCoordinate()'.")
+
+ if(options.scaleToLatitude) {
+ // Scale the model so that its units are interpreted as meters at the given latitude
+ var pixelsPerMeter = this.projectedUnitsPerMeter(lnglat[1]);
+ scale.multiplyScalar(pixelsPerMeter);
+ }
+
+ geoGroup.scale.copy(scale);
+
+ geoGroup.position.copy(this.projectToWorld(lnglat));
+ obj.coordinates = lnglat;
+
+ return obj;
+ },
+
+ addGeoreferencedMesh: function(mesh, options) {
+ /* Place the mesh on the map, assuming its internal (x,y) coordinates are already in (longitude, latitude) format
+ TODO: write this
+ */
+
+ },
+
+ addSymbolLayer: function(options) {
+ const layer = new SymbolLayer3D(this, options);
+ this.layers.push(layer);
+
+ return layer;
+ },
+
+ getDataLayer: function(id) {
+ for(var i = 0; i < this.layers.length; i++) {
+ if (this.layer.id === id) return layer;
+ }
+ },
+
+ remove: function(obj) {
+ this.world.remove(obj);
+ },
+
+ setupDefaultLights: function() {
+ this.scene.add( new THREE.AmbientLight( 0xCCCCCC ) );
+
+ var sunlight = new THREE.DirectionalLight(0xffffff, 0.5);
+ sunlight.position.set(0,800,1000);
+ sunlight.matrixWorldNeedsUpdate = true;
+ this.world.add(sunlight);
+ //this.world.add(sunlight.target);
+
+ // var lights = [];
+ // lights[ 0 ] = new THREE.PointLight( 0x999999, 1, 0 );
+ // lights[ 1 ] = new THREE.PointLight( 0x999999, 1, 0 );
+ // lights[ 2 ] = new THREE.PointLight( 0x999999, 0.2, 0 );
+
+ // lights[ 0 ].position.set( 0, 200, 1000 );
+ // lights[ 1 ].position.set( 100, 200, 1000 );
+ // lights[ 2 ].position.set( -100, -200, 0 );
+
+ // //scene.add( lights[ 0 ] );
+ // this.scene.add( lights[ 1 ] );
+ // this.scene.add( lights[ 2 ] );
+
+ }
+}
+
+module.exports = exports = Threebox;
+
+
+},{"./Camera/CameraSync.js":2,"./Layers/SymbolLayer3D.js":3,"./Utils/Utils.js":7,"./constants.js":9,"./three64.js":10}],7:[function(require,module,exports){
+var THREE = require("../three64.js"); // Modified version to use 64-bit double precision floats for matrix math
+
+function prettyPrintMatrix(uglymatrix){
+ for (var s=0;s<4;s++){
+ var quartet=[uglymatrix[s],
+ uglymatrix[s+4],
+ uglymatrix[s+8],
+ uglymatrix[s+12]];
+ console.log(quartet.map(function(num){return num.toFixed(4)}))
+ }
+}
+
+function makePerspectiveMatrix(fovy, aspect, near, far) {
+ var out = new THREE.Matrix4();
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out.elements[0] = f / aspect;
+ out.elements[1] = 0;
+ out.elements[2] = 0;
+ out.elements[3] = 0;
+ out.elements[4] = 0;
+ out.elements[5] = f;
+ out.elements[6] = 0;
+ out.elements[7] = 0;
+ out.elements[8] = 0;
+ out.elements[9] = 0;
+ out.elements[10] = (far + near) * nf;
+ out.elements[11] = -1;
+ out.elements[12] = 0;
+ out.elements[13] = 0;
+ out.elements[14] = (2 * far * near) * nf;
+ out.elements[15] = 0;
+ return out;
+}
+
+//gimme radians
+function radify(deg){
+
+ if (typeof deg === 'object'){
+ return deg.map(function(degree){
+ return Math.PI*2*degree/360
+ })
+ }
+
+ else return Math.PI*2*deg/360
+}
+
+//gimme degrees
+function degreeify(rad){
+ return 360*rad/(Math.PI*2)
+}
+
+module.exports.prettyPrintMatrix = prettyPrintMatrix;
+module.exports.makePerspectiveMatrix = makePerspectiveMatrix;
+module.exports.radify = radify;
+module.exports.degreeify = degreeify;
+},{"../three64.js":10}],8:[function(require,module,exports){
+const ValueGenerator = function(input) {
+ if(typeof input === 'object' && input.property !== undefined) // Value name comes from a property in each item
+ return (f => f.properties[input.property]);
+ else if(typeof input === 'object' && input.generator !== undefined) // Value name generated by a function run on each item
+ return input.generator;
+ else return (() => input);
+
+ return undefined;
+}
+
+module.exports = exports = ValueGenerator;
+},{}],9:[function(require,module,exports){
+const WORLD_SIZE = 512;
+const MERCATOR_A = 6378137.0;
+
+module.exports = exports = {
+ WORLD_SIZE: WORLD_SIZE,
+ PROJECTION_WORLD_SIZE: WORLD_SIZE / (MERCATOR_A * Math.PI) / 2,
+ MERCATOR_A: MERCATOR_A, // 900913 projection property
+ DEG2RAD: Math.PI / 180,
+ RAD2DEG: 180 / Math.PI,
+ EARTH_CIRCUMFERENCE: 40075000, // In meters
+
+}
+},{}],10:[function(require,module,exports){
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
+ (factory((global.THREE = global.THREE || {})));
+}(this, (function (exports) { 'use strict';
+
+ // Polyfills
+
+ if ( Number.EPSILON === undefined ) {
+
+ Number.EPSILON = Math.pow( 2, - 52 );
+
+ }
+
+ //
+
+ if ( Math.sign === undefined ) {
+
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
+
+ Math.sign = function ( x ) {
+
+ return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;
+
+ };
+
+ }
+
+ if ( Function.prototype.name === undefined ) {
+
+ // Missing in IE9-11.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
+
+ Object.defineProperty( Function.prototype, 'name', {
+
+ get: function () {
+
+ return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ];
+
+ }
+
+ } );
+
+ }
+
+ if ( Object.assign === undefined ) {
+
+ // Missing in IE.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
+
+ ( function () {
+
+ Object.assign = function ( target ) {
+
+ 'use strict';
+
+ if ( target === undefined || target === null ) {
+
+ throw new TypeError( 'Cannot convert undefined or null to object' );
+
+ }
+
+ var output = Object( target );
+
+ for ( var index = 1; index < arguments.length; index ++ ) {
+
+ var source = arguments[ index ];
+
+ if ( source !== undefined && source !== null ) {
+
+ for ( var nextKey in source ) {
+
+ if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {
+
+ output[ nextKey ] = source[ nextKey ];
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return output;
+
+ };
+
+ } )();
+
+ }
+
+ /**
+ * https://github.com/mrdoob/eventdispatcher.js/
+ */
+
+ function EventDispatcher() {}
+
+ EventDispatcher.prototype = {
+
+ addEventListener: function ( type, listener ) {
+
+ if ( this._listeners === undefined ) this._listeners = {};
+
+ var listeners = this._listeners;
+
+ if ( listeners[ type ] === undefined ) {
+
+ listeners[ type ] = [];
+
+ }
+
+ if ( listeners[ type ].indexOf( listener ) === - 1 ) {
+
+ listeners[ type ].push( listener );
+
+ }
+
+ },
+
+ hasEventListener: function ( type, listener ) {
+
+ if ( this._listeners === undefined ) return false;
+
+ var listeners = this._listeners;
+
+ return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
+
+ },
+
+ removeEventListener: function ( type, listener ) {
+
+ if ( this._listeners === undefined ) return;
+
+ var listeners = this._listeners;
+ var listenerArray = listeners[ type ];
+
+ if ( listenerArray !== undefined ) {
+
+ var index = listenerArray.indexOf( listener );
+
+ if ( index !== - 1 ) {
+
+ listenerArray.splice( index, 1 );
+
+ }
+
+ }
+
+ },
+
+ dispatchEvent: function ( event ) {
+
+ if ( this._listeners === undefined ) return;
+
+ var listeners = this._listeners;
+ var listenerArray = listeners[ event.type ];
+
+ if ( listenerArray !== undefined ) {
+
+ event.target = this;
+
+ var array = [], i = 0;
+ var length = listenerArray.length;
+
+ for ( i = 0; i < length; i ++ ) {
+
+ array[ i ] = listenerArray[ i ];
+
+ }
+
+ for ( i = 0; i < length; i ++ ) {
+
+ array[ i ].call( this, event );
+
+ }
+
+ }
+
+ }
+
+ };
+
+ var REVISION = '84dev';
+ var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
+ var CullFaceNone = 0;
+ var CullFaceBack = 1;
+ var CullFaceFront = 2;
+ var CullFaceFrontBack = 3;
+ var FrontFaceDirectionCW = 0;
+ var FrontFaceDirectionCCW = 1;
+ var BasicShadowMap = 0;
+ var PCFShadowMap = 1;
+ var PCFSoftShadowMap = 2;
+ var FrontSide = 0;
+ var BackSide = 1;
+ var DoubleSide = 2;
+ var FlatShading = 1;
+ var SmoothShading = 2;
+ var NoColors = 0;
+ var FaceColors = 1;
+ var VertexColors = 2;
+ var NoBlending = 0;
+ var NormalBlending = 1;
+ var AdditiveBlending = 2;
+ var SubtractiveBlending = 3;
+ var MultiplyBlending = 4;
+ var CustomBlending = 5;
+ var AddEquation = 100;
+ var SubtractEquation = 101;
+ var ReverseSubtractEquation = 102;
+ var MinEquation = 103;
+ var MaxEquation = 104;
+ var ZeroFactor = 200;
+ var OneFactor = 201;
+ var SrcColorFactor = 202;
+ var OneMinusSrcColorFactor = 203;
+ var SrcAlphaFactor = 204;
+ var OneMinusSrcAlphaFactor = 205;
+ var DstAlphaFactor = 206;
+ var OneMinusDstAlphaFactor = 207;
+ var DstColorFactor = 208;
+ var OneMinusDstColorFactor = 209;
+ var SrcAlphaSaturateFactor = 210;
+ var NeverDepth = 0;
+ var AlwaysDepth = 1;
+ var LessDepth = 2;
+ var LessEqualDepth = 3;
+ var EqualDepth = 4;
+ var GreaterEqualDepth = 5;
+ var GreaterDepth = 6;
+ var NotEqualDepth = 7;
+ var MultiplyOperation = 0;
+ var MixOperation = 1;
+ var AddOperation = 2;
+ var NoToneMapping = 0;
+ var LinearToneMapping = 1;
+ var ReinhardToneMapping = 2;
+ var Uncharted2ToneMapping = 3;
+ var CineonToneMapping = 4;
+ var UVMapping = 300;
+ var CubeReflectionMapping = 301;
+ var CubeRefractionMapping = 302;
+ var EquirectangularReflectionMapping = 303;
+ var EquirectangularRefractionMapping = 304;
+ var SphericalReflectionMapping = 305;
+ var CubeUVReflectionMapping = 306;
+ var CubeUVRefractionMapping = 307;
+ var RepeatWrapping = 1000;
+ var ClampToEdgeWrapping = 1001;
+ var MirroredRepeatWrapping = 1002;
+ var NearestFilter = 1003;
+ var NearestMipMapNearestFilter = 1004;
+ var NearestMipMapLinearFilter = 1005;
+ var LinearFilter = 1006;
+ var LinearMipMapNearestFilter = 1007;
+ var LinearMipMapLinearFilter = 1008;
+ var UnsignedByteType = 1009;
+ var ByteType = 1010;
+ var ShortType = 1011;
+ var UnsignedShortType = 1012;
+ var IntType = 1013;
+ var UnsignedIntType = 1014;
+ var FloatType = 1015;
+ var HalfFloatType = 1016;
+ var UnsignedShort4444Type = 1017;
+ var UnsignedShort5551Type = 1018;
+ var UnsignedShort565Type = 1019;
+ var UnsignedInt248Type = 1020;
+ var AlphaFormat = 1021;
+ var RGBFormat = 1022;
+ var RGBAFormat = 1023;
+ var LuminanceFormat = 1024;
+ var LuminanceAlphaFormat = 1025;
+ var RGBEFormat = RGBAFormat;
+ var DepthFormat = 1026;
+ var DepthStencilFormat = 1027;
+ var RGB_S3TC_DXT1_Format = 2001;
+ var RGBA_S3TC_DXT1_Format = 2002;
+ var RGBA_S3TC_DXT3_Format = 2003;
+ var RGBA_S3TC_DXT5_Format = 2004;
+ var RGB_PVRTC_4BPPV1_Format = 2100;
+ var RGB_PVRTC_2BPPV1_Format = 2101;
+ var RGBA_PVRTC_4BPPV1_Format = 2102;
+ var RGBA_PVRTC_2BPPV1_Format = 2103;
+ var RGB_ETC1_Format = 2151;
+ var LoopOnce = 2200;
+ var LoopRepeat = 2201;
+ var LoopPingPong = 2202;
+ var InterpolateDiscrete = 2300;
+ var InterpolateLinear = 2301;
+ var InterpolateSmooth = 2302;
+ var ZeroCurvatureEnding = 2400;
+ var ZeroSlopeEnding = 2401;
+ var WrapAroundEnding = 2402;
+ var TrianglesDrawMode = 0;
+ var TriangleStripDrawMode = 1;
+ var TriangleFanDrawMode = 2;
+ var LinearEncoding = 3000;
+ var sRGBEncoding = 3001;
+ var GammaEncoding = 3007;
+ var RGBEEncoding = 3002;
+ var LogLuvEncoding = 3003;
+ var RGBM7Encoding = 3004;
+ var RGBM16Encoding = 3005;
+ var RGBDEncoding = 3006;
+ var BasicDepthPacking = 3200;
+ var RGBADepthPacking = 3201;
+
+ /**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+ var _Math = {
+
+ DEG2RAD: Math.PI / 180,
+ RAD2DEG: 180 / Math.PI,
+
+ generateUUID: function () {
+
+ // http://www.broofa.com/Tools/Math.uuid.htm
+
+ var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
+ var uuid = new Array( 36 );
+ var rnd = 0, r;
+
+ return function generateUUID() {
+
+ for ( var i = 0; i < 36; i ++ ) {
+
+ if ( i === 8 || i === 13 || i === 18 || i === 23 ) {
+
+ uuid[ i ] = '-';
+
+ } else if ( i === 14 ) {
+
+ uuid[ i ] = '4';
+
+ } else {
+
+ if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
+ r = rnd & 0xf;
+ rnd = rnd >> 4;
+ uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
+
+ }
+
+ }
+
+ return uuid.join( '' );
+
+ };
+
+ }(),
+
+ clamp: function ( value, min, max ) {
+
+ return Math.max( min, Math.min( max, value ) );
+
+ },
+
+ // compute euclidian modulo of m % n
+ // https://en.wikipedia.org/wiki/Modulo_operation
+
+ euclideanModulo: function ( n, m ) {
+
+ return ( ( n % m ) + m ) % m;
+
+ },
+
+ // Linear mapping from range to range
+
+ mapLinear: function ( x, a1, a2, b1, b2 ) {
+
+ return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
+
+ },
+
+ // https://en.wikipedia.org/wiki/Linear_interpolation
+
+ lerp: function ( x, y, t ) {
+
+ return ( 1 - t ) * x + t * y;
+
+ },
+
+ // http://en.wikipedia.org/wiki/Smoothstep
+
+ smoothstep: function ( x, min, max ) {
+
+ if ( x <= min ) return 0;
+ if ( x >= max ) return 1;
+
+ x = ( x - min ) / ( max - min );
+
+ return x * x * ( 3 - 2 * x );
+
+ },
+
+ smootherstep: function ( x, min, max ) {
+
+ if ( x <= min ) return 0;
+ if ( x >= max ) return 1;
+
+ x = ( x - min ) / ( max - min );
+
+ return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
+
+ },
+
+ // Random integer from interval
+
+ randInt: function ( low, high ) {
+
+ return low + Math.floor( Math.random() * ( high - low + 1 ) );
+
+ },
+
+ // Random float from interval
+
+ randFloat: function ( low, high ) {
+
+ return low + Math.random() * ( high - low );
+
+ },
+
+ // Random float from <-range/2, range/2> interval
+
+ randFloatSpread: function ( range ) {
+
+ return range * ( 0.5 - Math.random() );
+
+ },
+
+ degToRad: function ( degrees ) {
+
+ return degrees * _Math.DEG2RAD;
+
+ },
+
+ radToDeg: function ( radians ) {
+
+ return radians * _Math.RAD2DEG;
+
+ },
+
+ isPowerOfTwo: function ( value ) {
+
+ return ( value & ( value - 1 ) ) === 0 && value !== 0;
+
+ },
+
+ nearestPowerOfTwo: function ( value ) {
+
+ return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );
+
+ },
+
+ nextPowerOfTwo: function ( value ) {
+
+ value --;
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ value ++;
+
+ return value;
+
+ }
+
+ };
+
+ /**
+ * @author mrdoob / http://mrdoob.com/
+ * @author philogb / http://blog.thejit.org/
+ * @author egraether / http://egraether.com/
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ */
+
+ function Vector2( x, y ) {
+
+ this.x = x || 0;
+ this.y = y || 0;
+
+ }
+
+ Vector2.prototype = {
+
+ constructor: Vector2,
+
+ isVector2: true,
+
+ get width() {
+
+ return this.x;
+
+ },
+
+ set width( value ) {
+
+ this.x = value;
+
+ },
+
+ get height() {
+
+ return this.y;
+
+ },
+
+ set height( value ) {
+
+ this.y = value;
+
+ },
+
+ //
+
+ set: function ( x, y ) {
+
+ this.x = x;
+ this.y = y;
+
+ return this;
+
+ },
+
+ setScalar: function ( scalar ) {
+
+ this.x = scalar;
+ this.y = scalar;
+
+ return this;
+
+ },
+
+ setX: function ( x ) {
+
+ this.x = x;
+
+ return this;
+
+ },
+
+ setY: function ( y ) {
+
+ this.y = y;
+
+ return this;
+
+ },
+
+ setComponent: function ( index, value ) {
+
+ switch ( index ) {
+
+ case 0: this.x = value; break;
+ case 1: this.y = value; break;
+ default: throw new Error( 'index is out of range: ' + index );
+
+ }
+
+ return this;
+
+ },
+
+ getComponent: function ( index ) {
+
+ switch ( index ) {
+
+ case 0: return this.x;
+ case 1: return this.y;
+ default: throw new Error( 'index is out of range: ' + index );
+
+ }
+
+ },
+
+ clone: function () {
+
+ return new this.constructor( this.x, this.y );
+
+ },
+
+ copy: function ( v ) {
+
+ this.x = v.x;
+ this.y = v.y;
+
+ return this;
+
+ },
+
+ add: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
+ return this.addVectors( v, w );
+
+ }
+
+ this.x += v.x;
+ this.y += v.y;
+
+ return this;
+
+ },
+
+ addScalar: function ( s ) {
+
+ this.x += s;
+ this.y += s;
+
+ return this;
+
+ },
+
+ addVectors: function ( a, b ) {
+
+ this.x = a.x + b.x;
+ this.y = a.y + b.y;
+
+ return this;
+
+ },
+
+ addScaledVector: function ( v, s ) {
+
+ this.x += v.x * s;
+ this.y += v.y * s;
+
+ return this;
+
+ },
+
+ sub: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
+ return this.subVectors( v, w );
+
+ }
+
+ this.x -= v.x;
+ this.y -= v.y;
+
+ return this;
+
+ },
+
+ subScalar: function ( s ) {
+
+ this.x -= s;
+ this.y -= s;
+
+ return this;
+
+ },
+
+ subVectors: function ( a, b ) {
+
+ this.x = a.x - b.x;
+ this.y = a.y - b.y;
+
+ return this;
+
+ },
+
+ multiply: function ( v ) {
+
+ this.x *= v.x;
+ this.y *= v.y;
+
+ return this;
+
+ },
+
+ multiplyScalar: function ( scalar ) {
+
+ if ( isFinite( scalar ) ) {
+
+ this.x *= scalar;
+ this.y *= scalar;
+
+ } else {
+
+ this.x = 0;
+ this.y = 0;
+
+ }
+
+ return this;
+
+ },
+
+ divide: function ( v ) {
+
+ this.x /= v.x;
+ this.y /= v.y;
+
+ return this;
+
+ },
+
+ divideScalar: function ( scalar ) {
+
+ return this.multiplyScalar( 1 / scalar );
+
+ },
+
+ min: function ( v ) {
+
+ this.x = Math.min( this.x, v.x );
+ this.y = Math.min( this.y, v.y );
+
+ return this;
+
+ },
+
+ max: function ( v ) {
+
+ this.x = Math.max( this.x, v.x );
+ this.y = Math.max( this.y, v.y );
+
+ return this;
+
+ },
+
+ clamp: function ( min, max ) {
+
+ // This function assumes min < max, if this assumption isn't true it will not operate correctly
+
+ this.x = Math.max( min.x, Math.min( max.x, this.x ) );
+ this.y = Math.max( min.y, Math.min( max.y, this.y ) );
+
+ return this;
+
+ },
+
+ clampScalar: function () {
+
+ var min, max;
+
+ return function clampScalar( minVal, maxVal ) {
+
+ if ( min === undefined ) {
+
+ min = new Vector2();
+ max = new Vector2();
+
+ }
+
+ min.set( minVal, minVal );
+ max.set( maxVal, maxVal );
+
+ return this.clamp( min, max );
+
+ };
+
+ }(),
+
+ clampLength: function ( min, max ) {
+
+ var length = this.length();
+
+ return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
+
+ },
+
+ floor: function () {
+
+ this.x = Math.floor( this.x );
+ this.y = Math.floor( this.y );
+
+ return this;
+
+ },
+
+ ceil: function () {
+
+ this.x = Math.ceil( this.x );
+ this.y = Math.ceil( this.y );
+
+ return this;
+
+ },
+
+ round: function () {
+
+ this.x = Math.round( this.x );
+ this.y = Math.round( this.y );
+
+ return this;
+
+ },
+
+ roundToZero: function () {
+
+ this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
+ this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
+
+ return this;
+
+ },
+
+ negate: function () {
+
+ this.x = - this.x;
+ this.y = - this.y;
+
+ return this;
+
+ },
+
+ dot: function ( v ) {
+
+ return this.x * v.x + this.y * v.y;
+
+ },
+
+ lengthSq: function () {
+
+ return this.x * this.x + this.y * this.y;
+
+ },
+
+ length: function () {
+
+ return Math.sqrt( this.x * this.x + this.y * this.y );
+
+ },
+
+ lengthManhattan: function() {
+
+ return Math.abs( this.x ) + Math.abs( this.y );
+
+ },
+
+ normalize: function () {
+
+ return this.divideScalar( this.length() );
+
+ },
+
+ angle: function () {
+
+ // computes the angle in radians with respect to the positive x-axis
+
+ var angle = Math.atan2( this.y, this.x );
+
+ if ( angle < 0 ) angle += 2 * Math.PI;
+
+ return angle;
+
+ },
+
+ distanceTo: function ( v ) {
+
+ return Math.sqrt( this.distanceToSquared( v ) );
+
+ },
+
+ distanceToSquared: function ( v ) {
+
+ var dx = this.x - v.x, dy = this.y - v.y;
+ return dx * dx + dy * dy;
+
+ },
+
+ distanceToManhattan: function ( v ) {
+
+ return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
+
+ },
+
+ setLength: function ( length ) {
+
+ return this.multiplyScalar( length / this.length() );
+
+ },
+
+ lerp: function ( v, alpha ) {
+
+ this.x += ( v.x - this.x ) * alpha;
+ this.y += ( v.y - this.y ) * alpha;
+
+ return this;
+
+ },
+
+ lerpVectors: function ( v1, v2, alpha ) {
+
+ return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
+
+ },
+
+ equals: function ( v ) {
+
+ return ( ( v.x === this.x ) && ( v.y === this.y ) );
+
+ },
+
+ fromArray: function ( array, offset ) {
+
+ if ( offset === undefined ) offset = 0;
+
+ this.x = array[ offset ];
+ this.y = array[ offset + 1 ];
+
+ return this;
+
+ },
+
+ toArray: function ( array, offset ) {
+
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this.x;
+ array[ offset + 1 ] = this.y;
+
+ return array;
+
+ },
+
+ fromAttribute: function ( attribute, index, offset ) {
+
+ if ( offset !== undefined ) {
+
+ console.warn( 'THREE.Vector2: offset has been removed from .fromAttribute().' );
+
+ }
+
+ this.x = attribute.getX( index );
+ this.y = attribute.getY( index );
+
+ return this;
+
+ },
+
+ rotateAround: function ( center, angle ) {
+
+ var c = Math.cos( angle ), s = Math.sin( angle );
+
+ var x = this.x - center.x;
+ var y = this.y - center.y;
+
+ this.x = x * c - y * s + center.x;
+ this.y = x * s + y * c + center.y;
+
+ return this;
+
+ }
+
+ };
+
+ /**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ * @author szimek / https://github.com/szimek/
+ */
+
+ var textureId = 0;
+
+ function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
+
+ Object.defineProperty( this, 'id', { value: textureId ++ } );
+
+ this.uuid = _Math.generateUUID();
+
+ this.name = '';
+
+ this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
+ this.mipmaps = [];
+
+ this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
+
+ this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
+ this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
+
+ this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
+ this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
+
+ this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
+
+ this.format = format !== undefined ? format : RGBAFormat;
+ this.type = type !== undefined ? type : UnsignedByteType;
+
+ this.offset = new Vector2( 0, 0 );
+ this.repeat = new Vector2( 1, 1 );
+
+ this.generateMipmaps = true;
+ this.premultiplyAlpha = false;
+ this.flipY = true;
+ this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
+
+
+ // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
+ //
+ // Also changing the encoding after already used by a Material will not automatically make the Material
+ // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
+ this.encoding = encoding !== undefined ? encoding : LinearEncoding;
+
+ this.version = 0;
+ this.onUpdate = null;
+
+ }
+
+ Texture.DEFAULT_IMAGE = undefined;
+ Texture.DEFAULT_MAPPING = UVMapping;
+
+ Texture.prototype = {
+
+ constructor: Texture,
+
+ isTexture: true,
+
+ set needsUpdate( value ) {
+
+ if ( value === true ) this.version ++;
+
+ },
+
+ clone: function () {
+
+ return new this.constructor().copy( this );
+
+ },
+
+ copy: function ( source ) {
+
+ this.image = source.image;
+ this.mipmaps = source.mipmaps.slice( 0 );
+
+ this.mapping = source.mapping;
+
+ this.wrapS = source.wrapS;
+ this.wrapT = source.wrapT;
+
+ this.magFilter = source.magFilter;
+ this.minFilter = source.minFilter;
+
+ this.anisotropy = source.anisotropy;
+
+ this.format = source.format;
+ this.type = source.type;
+
+ this.offset.copy( source.offset );
+ this.repeat.copy( source.repeat );
+
+ this.generateMipmaps = source.generateMipmaps;
+ this.premultiplyAlpha = source.premultiplyAlpha;
+ this.flipY = source.flipY;
+ this.unpackAlignment = source.unpackAlignment;
+ this.encoding = source.encoding;
+
+ return this;
+
+ },
+
+ toJSON: function ( meta ) {
+
+ if ( meta.textures[ this.uuid ] !== undefined ) {
+
+ return meta.textures[ this.uuid ];
+
+ }
+
+ function getDataURL( image ) {
+
+ var canvas;
+
+ if ( image.toDataURL !== undefined ) {
+
+ canvas = image;
+
+ } else {
+
+ canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
+ canvas.width = image.width;
+ canvas.height = image.height;
+
+ canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height );
+
+ }
+
+ if ( canvas.width > 2048 || canvas.height > 2048 ) {
+
+ return canvas.toDataURL( 'image/jpeg', 0.6 );
+
+ } else {
+
+ return canvas.toDataURL( 'image/png' );
+
+ }
+
+ }
+
+ var output = {
+ metadata: {
+ version: 4.4,
+ type: 'Texture',
+ generator: 'Texture.toJSON'
+ },
+
+ uuid: this.uuid,
+ name: this.name,
+
+ mapping: this.mapping,
+
+ repeat: [ this.repeat.x, this.repeat.y ],
+ offset: [ this.offset.x, this.offset.y ],
+ wrap: [ this.wrapS, this.wrapT ],
+
+ minFilter: this.minFilter,
+ magFilter: this.magFilter,
+ anisotropy: this.anisotropy,
+
+ flipY: this.flipY
+ };
+
+ if ( this.image !== undefined ) {
+
+ // TODO: Move to THREE.Image
+
+ var image = this.image;
+
+ if ( image.uuid === undefined ) {
+
+ image.uuid = _Math.generateUUID(); // UGH
+
+ }
+
+ if ( meta.images[ image.uuid ] === undefined ) {
+
+ meta.images[ image.uuid ] = {
+ uuid: image.uuid,
+ url: getDataURL( image )
+ };
+
+ }
+
+ output.image = image.uuid;
+
+ }
+
+ meta.textures[ this.uuid ] = output;
+
+ return output;
+
+ },
+
+ dispose: function () {
+
+ this.dispatchEvent( { type: 'dispose' } );
+
+ },
+
+ transformUv: function ( uv ) {
+
+ if ( this.mapping !== UVMapping ) return;
+
+ uv.multiply( this.repeat );
+ uv.add( this.offset );
+
+ if ( uv.x < 0 || uv.x > 1 ) {
+
+ switch ( this.wrapS ) {
+
+ case RepeatWrapping:
+
+ uv.x = uv.x - Math.floor( uv.x );
+ break;
+
+ case ClampToEdgeWrapping:
+
+ uv.x = uv.x < 0 ? 0 : 1;
+ break;
+
+ case MirroredRepeatWrapping:
+
+ if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
+
+ uv.x = Math.ceil( uv.x ) - uv.x;
+
+ } else {
+
+ uv.x = uv.x - Math.floor( uv.x );
+
+ }
+ break;
+
+ }
+
+ }
+
+ if ( uv.y < 0 || uv.y > 1 ) {
+
+ switch ( this.wrapT ) {
+
+ case RepeatWrapping:
+
+ uv.y = uv.y - Math.floor( uv.y );
+ break;
+
+ case ClampToEdgeWrapping:
+
+ uv.y = uv.y < 0 ? 0 : 1;
+ break;
+
+ case MirroredRepeatWrapping:
+
+ if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
+
+ uv.y = Math.ceil( uv.y ) - uv.y;
+
+ } else {
+
+ uv.y = uv.y - Math.floor( uv.y );
+
+ }
+ break;
+
+ }
+
+ }
+
+ if ( this.flipY ) {
+
+ uv.y = 1 - uv.y;
+
+ }
+
+ }
+
+ };
+
+ Object.assign( Texture.prototype, EventDispatcher.prototype );
+
+ /**
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ * @author philogb / http://blog.thejit.org/
+ * @author mikael emtinger / http://gomo.se/
+ * @author egraether / http://egraether.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
+ function Vector4( x, y, z, w ) {
+
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+ this.w = ( w !== undefined ) ? w : 1;
+
+ }
+
+ Vector4.prototype = {
+
+ constructor: Vector4,
+
+ isVector4: true,
+
+ set: function ( x, y, z, w ) {
+
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+
+ return this;
+
+ },
+
+ setScalar: function ( scalar ) {
+
+ this.x = scalar;
+ this.y = scalar;
+ this.z = scalar;
+ this.w = scalar;
+
+ return this;
+
+ },
+
+ setX: function ( x ) {
+
+ this.x = x;
+
+ return this;
+
+ },
+
+ setY: function ( y ) {
+
+ this.y = y;
+
+ return this;
+
+ },
+
+ setZ: function ( z ) {
+
+ this.z = z;
+
+ return this;
+
+ },
+
+ setW: function ( w ) {
+
+ this.w = w;
+
+ return this;
+
+ },
+
+ setComponent: function ( index, value ) {
+
+ switch ( index ) {
+
+ case 0: this.x = value; break;
+ case 1: this.y = value; break;
+ case 2: this.z = value; break;
+ case 3: this.w = value; break;
+ default: throw new Error( 'index is out of range: ' + index );
+
+ }
+
+ return this;
+
+ },
+
+ getComponent: function ( index ) {
+
+ switch ( index ) {
+
+ case 0: return this.x;
+ case 1: return this.y;
+ case 2: return this.z;
+ case 3: return this.w;
+ default: throw new Error( 'index is out of range: ' + index );
+
+ }
+
+ },
+
+ clone: function () {
+
+ return new this.constructor( this.x, this.y, this.z, this.w );
+
+ },
+
+ copy: function ( v ) {
+
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+ this.w = ( v.w !== undefined ) ? v.w : 1;
+
+ return this;
+
+ },
+
+ add: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
+ return this.addVectors( v, w );
+
+ }
+
+ this.x += v.x;
+ this.y += v.y;
+ this.z += v.z;
+ this.w += v.w;
+
+ return this;
+
+ },
+
+ addScalar: function ( s ) {
+
+ this.x += s;
+ this.y += s;
+ this.z += s;
+ this.w += s;
+
+ return this;
+
+ },
+
+ addVectors: function ( a, b ) {
+
+ this.x = a.x + b.x;
+ this.y = a.y + b.y;
+ this.z = a.z + b.z;
+ this.w = a.w + b.w;
+
+ return this;
+
+ },
+
+ addScaledVector: function ( v, s ) {
+
+ this.x += v.x * s;
+ this.y += v.y * s;
+ this.z += v.z * s;
+ this.w += v.w * s;
+
+ return this;
+
+ },
+
+ sub: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
+ return this.subVectors( v, w );
+
+ }
+
+ this.x -= v.x;
+ this.y -= v.y;
+ this.z -= v.z;
+ this.w -= v.w;
+
+ return this;
+
+ },
+
+ subScalar: function ( s ) {
+
+ this.x -= s;
+ this.y -= s;
+ this.z -= s;
+ this.w -= s;
+
+ return this;
+
+ },
+
+ subVectors: function ( a, b ) {
+
+ this.x = a.x - b.x;
+ this.y = a.y - b.y;
+ this.z = a.z - b.z;
+ this.w = a.w - b.w;
+
+ return this;
+
+ },
+
+ multiplyScalar: function ( scalar ) {
+
+ if ( isFinite( scalar ) ) {
+
+ this.x *= scalar;
+ this.y *= scalar;
+ this.z *= scalar;
+ this.w *= scalar;
+
+ } else {
+
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 0;
+
+ }
+
+ return this;
+
+ },
+
+ applyMatrix4: function ( m ) {
+
+ var x = this.x, y = this.y, z = this.z, w = this.w;
+ var e = m.elements;
+
+ this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
+ this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
+ this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
+ this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
+
+ return this;
+
+ },
+
+ divideScalar: function ( scalar ) {
+
+ return this.multiplyScalar( 1 / scalar );
+
+ },
+
+ setAxisAngleFromQuaternion: function ( q ) {
+
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
+
+ // q is assumed to be normalized
+
+ this.w = 2 * Math.acos( q.w );
+
+ var s = Math.sqrt( 1 - q.w * q.w );
+
+ if ( s < 0.0001 ) {
+
+ this.x = 1;
+ this.y = 0;
+ this.z = 0;
+
+ } else {
+
+ this.x = q.x / s;
+ this.y = q.y / s;
+ this.z = q.z / s;
+
+ }
+
+ return this;
+
+ },
+
+ setAxisAngleFromRotationMatrix: function ( m ) {
+
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
+
+ // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+
+ var angle, x, y, z, // variables for result
+ epsilon = 0.01, // margin to allow for rounding errors
+ epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
+
+ te = m.elements,
+
+ m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
+ m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
+ m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
+
+ if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
+ ( Math.abs( m13 - m31 ) < epsilon ) &&
+ ( Math.abs( m23 - m32 ) < epsilon ) ) {
+
+ // singularity found
+ // first check for identity matrix which must have +1 for all terms
+ // in leading diagonal and zero in other terms
+
+ if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
+ ( Math.abs( m13 + m31 ) < epsilon2 ) &&
+ ( Math.abs( m23 + m32 ) < epsilon2 ) &&
+ ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
+
+ // this singularity is identity matrix so angle = 0
+
+ this.set( 1, 0, 0, 0 );
+
+ return this; // zero angle, arbitrary axis
+
+ }
+
+ // otherwise this singularity is angle = 180
+
+ angle = Math.PI;
+
+ var xx = ( m11 + 1 ) / 2;
+ var yy = ( m22 + 1 ) / 2;
+ var zz = ( m33 + 1 ) / 2;
+ var xy = ( m12 + m21 ) / 4;
+ var xz = ( m13 + m31 ) / 4;
+ var yz = ( m23 + m32 ) / 4;
+
+ if ( ( xx > yy ) && ( xx > zz ) ) {
+
+ // m11 is the largest diagonal term
+
+ if ( xx < epsilon ) {
+
+ x = 0;
+ y = 0.707106781;
+ z = 0.707106781;
+
+ } else {
+
+ x = Math.sqrt( xx );
+ y = xy / x;
+ z = xz / x;
+
+ }
+
+ } else if ( yy > zz ) {
+
+ // m22 is the largest diagonal term
+
+ if ( yy < epsilon ) {
+
+ x = 0.707106781;
+ y = 0;
+ z = 0.707106781;
+
+ } else {
+
+ y = Math.sqrt( yy );
+ x = xy / y;
+ z = yz / y;
+
+ }
+
+ } else {
+
+ // m33 is the largest diagonal term so base result on this
+
+ if ( zz < epsilon ) {
+
+ x = 0.707106781;
+ y = 0.707106781;
+ z = 0;
+
+ } else {
+
+ z = Math.sqrt( zz );
+ x = xz / z;
+ y = yz / z;
+
+ }
+
+ }
+
+ this.set( x, y, z, angle );
+
+ return this; // return 180 deg rotation
+
+ }
+
+ // as we have reached here there are no singularities so we can handle normally
+
+ var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
+ ( m13 - m31 ) * ( m13 - m31 ) +
+ ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
+
+ if ( Math.abs( s ) < 0.001 ) s = 1;
+
+ // prevent divide by zero, should not happen if matrix is orthogonal and should be
+ // caught by singularity test above, but I've left it in just in case
+
+ this.x = ( m32 - m23 ) / s;
+ this.y = ( m13 - m31 ) / s;
+ this.z = ( m21 - m12 ) / s;
+ this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
+
+ return this;
+
+ },
+
+ min: function ( v ) {
+
+ this.x = Math.min( this.x, v.x );
+ this.y = Math.min( this.y, v.y );
+ this.z = Math.min( this.z, v.z );
+ this.w = Math.min( this.w, v.w );
+
+ return this;
+
+ },
+
+ max: function ( v ) {
+
+ this.x = Math.max( this.x, v.x );
+ this.y = Math.max( this.y, v.y );
+ this.z = Math.max( this.z, v.z );
+ this.w = Math.max( this.w, v.w );
+
+ return this;
+
+ },
+
+ clamp: function ( min, max ) {
+
+ // This function assumes min < max, if this assumption isn't true it will not operate correctly
+
+ this.x = Math.max( min.x, Math.min( max.x, this.x ) );
+ this.y = Math.max( min.y, Math.min( max.y, this.y ) );
+ this.z = Math.max( min.z, Math.min( max.z, this.z ) );
+ this.w = Math.max( min.w, Math.min( max.w, this.w ) );
+
+ return this;
+
+ },
+
+ clampScalar: function () {
+
+ var min, max;
+
+ return function clampScalar( minVal, maxVal ) {
+
+ if ( min === undefined ) {
+
+ min = new Vector4();
+ max = new Vector4();
+
+ }
+
+ min.set( minVal, minVal, minVal, minVal );
+ max.set( maxVal, maxVal, maxVal, maxVal );
+
+ return this.clamp( min, max );
+
+ };
+
+ }(),
+
+ floor: function () {
+
+ this.x = Math.floor( this.x );
+ this.y = Math.floor( this.y );
+ this.z = Math.floor( this.z );
+ this.w = Math.floor( this.w );
+
+ return this;
+
+ },
+
+ ceil: function () {
+
+ this.x = Math.ceil( this.x );
+ this.y = Math.ceil( this.y );
+ this.z = Math.ceil( this.z );
+ this.w = Math.ceil( this.w );
+
+ return this;
+
+ },
+
+ round: function () {
+
+ this.x = Math.round( this.x );
+ this.y = Math.round( this.y );
+ this.z = Math.round( this.z );
+ this.w = Math.round( this.w );
+
+ return this;
+
+ },
+
+ roundToZero: function () {
+
+ this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
+ this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
+ this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
+ this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
+
+ return this;
+
+ },
+
+ negate: function () {
+
+ this.x = - this.x;
+ this.y = - this.y;
+ this.z = - this.z;
+ this.w = - this.w;
+
+ return this;
+
+ },
+
+ dot: function ( v ) {
+
+ return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
+
+ },
+
+ lengthSq: function () {
+
+ return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
+
+ },
+
+ length: function () {
+
+ return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
+
+ },
+
+ lengthManhattan: function () {
+
+ return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
+
+ },
+
+ normalize: function () {
+
+ return this.divideScalar( this.length() );
+
+ },
+
+ setLength: function ( length ) {
+
+ return this.multiplyScalar( length / this.length() );
+
+ },
+
+ lerp: function ( v, alpha ) {
+
+ this.x += ( v.x - this.x ) * alpha;
+ this.y += ( v.y - this.y ) * alpha;
+ this.z += ( v.z - this.z ) * alpha;
+ this.w += ( v.w - this.w ) * alpha;
+
+ return this;
+
+ },
+
+ lerpVectors: function ( v1, v2, alpha ) {
+
+ return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
+
+ },
+
+ equals: function ( v ) {
+
+ return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
+
+ },
+
+ fromArray: function ( array, offset ) {
+
+ if ( offset === undefined ) offset = 0;
+
+ this.x = array[ offset ];
+ this.y = array[ offset + 1 ];
+ this.z = array[ offset + 2 ];
+ this.w = array[ offset + 3 ];
+
+ return this;
+
+ },
+
+ toArray: function ( array, offset ) {
+
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this.x;
+ array[ offset + 1 ] = this.y;
+ array[ offset + 2 ] = this.z;
+ array[ offset + 3 ] = this.w;
+
+ return array;
+
+ },
+
+ fromAttribute: function ( attribute, index, offset ) {
+
+ if ( offset !== undefined ) {
+
+ console.warn( 'THREE.Vector4: offset has been removed from .fromAttribute().' );
+
+ }
+
+ this.x = attribute.getX( index );
+ this.y = attribute.getY( index );
+ this.z = attribute.getZ( index );
+ this.w = attribute.getW( index );
+
+ return this;
+
+ }
+
+ };
+
+ /**
+ * @author szimek / https://github.com/szimek/
+ * @author alteredq / http://alteredqualia.com/
+ * @author Marius Kintel / https://github.com/kintel
+ */
+
+ /*
+ In options, we can specify:
+ * Texture parameters for an auto-generated target texture
+ * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
+ */
+ function WebGLRenderTarget( width, height, options ) {
+
+ this.uuid = _Math.generateUUID();
+
+ this.width = width;
+ this.height = height;
+
+ this.scissor = new Vector4( 0, 0, width, height );
+ this.scissorTest = false;
+
+ this.viewport = new Vector4( 0, 0, width, height );
+
+ options = options || {};
+
+ if ( options.minFilter === undefined ) options.minFilter = LinearFilter;
+
+ this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
+
+ this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
+ this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
+ this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
+
+ }
+
+ WebGLRenderTarget.prototype = {
+
+ constructor: WebGLRenderTarget,
+
+ isWebGLRenderTarget: true,
+
+ setSize: function ( width, height ) {
+
+ if ( this.width !== width || this.height !== height ) {
+
+ this.width = width;
+ this.height = height;
+
+ this.dispose();
+
+ }
+
+ this.viewport.set( 0, 0, width, height );
+ this.scissor.set( 0, 0, width, height );
+
+ },
+
+ clone: function () {
+
+ return new this.constructor().copy( this );
+
+ },
+
+ copy: function ( source ) {
+
+ this.width = source.width;
+ this.height = source.height;
+
+ this.viewport.copy( source.viewport );
+
+ this.texture = source.texture.clone();
+
+ this.depthBuffer = source.depthBuffer;
+ this.stencilBuffer = source.stencilBuffer;
+ this.depthTexture = source.depthTexture;
+
+ return this;
+
+ },
+
+ dispose: function () {
+
+ this.dispatchEvent( { type: 'dispose' } );
+
+ }
+
+ };
+
+ Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype );
+
+ /**
+ * @author alteredq / http://alteredqualia.com
+ */
+
+ function WebGLRenderTargetCube( width, height, options ) {
+
+ WebGLRenderTarget.call( this, width, height, options );
+
+ this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
+ this.activeMipMapLevel = 0;
+
+ }
+
+ WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );
+ WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;
+
+ WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;
+
+ /**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ * @author WestLangley / http://github.com/WestLangley
+ * @author bhouston / http://clara.io
+ */
+
+ function Quaternion( x, y, z, w ) {
+
+ this._x = x || 0;
+ this._y = y || 0;
+ this._z = z || 0;
+ this._w = ( w !== undefined ) ? w : 1;
+
+ }
+
+ Quaternion.prototype = {
+
+ constructor: Quaternion,
+
+ get x () {
+
+ return this._x;
+
+ },
+
+ set x ( value ) {
+
+ this._x = value;
+ this.onChangeCallback();
+
+ },
+
+ get y () {
+
+ return this._y;
+
+ },
+
+ set y ( value ) {
+
+ this._y = value;
+ this.onChangeCallback();
+
+ },
+
+ get z () {
+
+ return this._z;
+
+ },
+
+ set z ( value ) {
+
+ this._z = value;
+ this.onChangeCallback();
+
+ },
+
+ get w () {
+
+ return this._w;
+
+ },
+
+ set w ( value ) {
+
+ this._w = value;
+ this.onChangeCallback();
+
+ },
+
+ set: function ( x, y, z, w ) {
+
+ this._x = x;
+ this._y = y;
+ this._z = z;
+ this._w = w;
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ clone: function () {
+
+ return new this.constructor( this._x, this._y, this._z, this._w );
+
+ },
+
+ copy: function ( quaternion ) {
+
+ this._x = quaternion.x;
+ this._y = quaternion.y;
+ this._z = quaternion.z;
+ this._w = quaternion.w;
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ setFromEuler: function ( euler, update ) {
+
+ if ( (euler && euler.isEuler) === false ) {
+
+ throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
+
+ }
+
+ // http://www.mathworks.com/matlabcentral/fileexchange/
+ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
+ // content/SpinCalc.m
+
+ var c1 = Math.cos( euler._x / 2 );
+ var c2 = Math.cos( euler._y / 2 );
+ var c3 = Math.cos( euler._z / 2 );
+ var s1 = Math.sin( euler._x / 2 );
+ var s2 = Math.sin( euler._y / 2 );
+ var s3 = Math.sin( euler._z / 2 );
+
+ var order = euler.order;
+
+ if ( order === 'XYZ' ) {
+
+ this._x = s1 * c2 * c3 + c1 * s2 * s3;
+ this._y = c1 * s2 * c3 - s1 * c2 * s3;
+ this._z = c1 * c2 * s3 + s1 * s2 * c3;
+ this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+ } else if ( order === 'YXZ' ) {
+
+ this._x = s1 * c2 * c3 + c1 * s2 * s3;
+ this._y = c1 * s2 * c3 - s1 * c2 * s3;
+ this._z = c1 * c2 * s3 - s1 * s2 * c3;
+ this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+ } else if ( order === 'ZXY' ) {
+
+ this._x = s1 * c2 * c3 - c1 * s2 * s3;
+ this._y = c1 * s2 * c3 + s1 * c2 * s3;
+ this._z = c1 * c2 * s3 + s1 * s2 * c3;
+ this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+ } else if ( order === 'ZYX' ) {
+
+ this._x = s1 * c2 * c3 - c1 * s2 * s3;
+ this._y = c1 * s2 * c3 + s1 * c2 * s3;
+ this._z = c1 * c2 * s3 - s1 * s2 * c3;
+ this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+ } else if ( order === 'YZX' ) {
+
+ this._x = s1 * c2 * c3 + c1 * s2 * s3;
+ this._y = c1 * s2 * c3 + s1 * c2 * s3;
+ this._z = c1 * c2 * s3 - s1 * s2 * c3;
+ this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+ } else if ( order === 'XZY' ) {
+
+ this._x = s1 * c2 * c3 - c1 * s2 * s3;
+ this._y = c1 * s2 * c3 - s1 * c2 * s3;
+ this._z = c1 * c2 * s3 + s1 * s2 * c3;
+ this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+ }
+
+ if ( update !== false ) this.onChangeCallback();
+
+ return this;
+
+ },
+
+ setFromAxisAngle: function ( axis, angle ) {
+
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
+
+ // assumes axis is normalized
+
+ var halfAngle = angle / 2, s = Math.sin( halfAngle );
+
+ this._x = axis.x * s;
+ this._y = axis.y * s;
+ this._z = axis.z * s;
+ this._w = Math.cos( halfAngle );
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ setFromRotationMatrix: function ( m ) {
+
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+
+ // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+
+ var te = m.elements,
+
+ m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
+ m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
+ m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
+
+ trace = m11 + m22 + m33,
+ s;
+
+ if ( trace > 0 ) {
+
+ s = 0.5 / Math.sqrt( trace + 1.0 );
+
+ this._w = 0.25 / s;
+ this._x = ( m32 - m23 ) * s;
+ this._y = ( m13 - m31 ) * s;
+ this._z = ( m21 - m12 ) * s;
+
+ } else if ( m11 > m22 && m11 > m33 ) {
+
+ s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
+
+ this._w = ( m32 - m23 ) / s;
+ this._x = 0.25 * s;
+ this._y = ( m12 + m21 ) / s;
+ this._z = ( m13 + m31 ) / s;
+
+ } else if ( m22 > m33 ) {
+
+ s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
+
+ this._w = ( m13 - m31 ) / s;
+ this._x = ( m12 + m21 ) / s;
+ this._y = 0.25 * s;
+ this._z = ( m23 + m32 ) / s;
+
+ } else {
+
+ s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
+
+ this._w = ( m21 - m12 ) / s;
+ this._x = ( m13 + m31 ) / s;
+ this._y = ( m23 + m32 ) / s;
+ this._z = 0.25 * s;
+
+ }
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ setFromUnitVectors: function () {
+
+ // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
+
+ // assumes direction vectors vFrom and vTo are normalized
+
+ var v1, r;
+
+ var EPS = 0.000001;
+
+ return function setFromUnitVectors( vFrom, vTo ) {
+
+ if ( v1 === undefined ) v1 = new Vector3();
+
+ r = vFrom.dot( vTo ) + 1;
+
+ if ( r < EPS ) {
+
+ r = 0;
+
+ if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
+
+ v1.set( - vFrom.y, vFrom.x, 0 );
+
+ } else {
+
+ v1.set( 0, - vFrom.z, vFrom.y );
+
+ }
+
+ } else {
+
+ v1.crossVectors( vFrom, vTo );
+
+ }
+
+ this._x = v1.x;
+ this._y = v1.y;
+ this._z = v1.z;
+ this._w = r;
+
+ return this.normalize();
+
+ };
+
+ }(),
+
+ inverse: function () {
+
+ return this.conjugate().normalize();
+
+ },
+
+ conjugate: function () {
+
+ this._x *= - 1;
+ this._y *= - 1;
+ this._z *= - 1;
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ dot: function ( v ) {
+
+ return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
+
+ },
+
+ lengthSq: function () {
+
+ return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
+
+ },
+
+ length: function () {
+
+ return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
+
+ },
+
+ normalize: function () {
+
+ var l = this.length();
+
+ if ( l === 0 ) {
+
+ this._x = 0;
+ this._y = 0;
+ this._z = 0;
+ this._w = 1;
+
+ } else {
+
+ l = 1 / l;
+
+ this._x = this._x * l;
+ this._y = this._y * l;
+ this._z = this._z * l;
+ this._w = this._w * l;
+
+ }
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ multiply: function ( q, p ) {
+
+ if ( p !== undefined ) {
+
+ console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
+ return this.multiplyQuaternions( q, p );
+
+ }
+
+ return this.multiplyQuaternions( this, q );
+
+ },
+
+ premultiply: function ( q ) {
+
+ return this.multiplyQuaternions( q, this );
+
+ },
+
+ multiplyQuaternions: function ( a, b ) {
+
+ // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
+
+ var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
+ var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
+
+ this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
+ this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
+ this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
+ this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ slerp: function ( qb, t ) {
+
+ if ( t === 0 ) return this;
+ if ( t === 1 ) return this.copy( qb );
+
+ var x = this._x, y = this._y, z = this._z, w = this._w;
+
+ // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
+
+ var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
+
+ if ( cosHalfTheta < 0 ) {
+
+ this._w = - qb._w;
+ this._x = - qb._x;
+ this._y = - qb._y;
+ this._z = - qb._z;
+
+ cosHalfTheta = - cosHalfTheta;
+
+ } else {
+
+ this.copy( qb );
+
+ }
+
+ if ( cosHalfTheta >= 1.0 ) {
+
+ this._w = w;
+ this._x = x;
+ this._y = y;
+ this._z = z;
+
+ return this;
+
+ }
+
+ var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
+
+ if ( Math.abs( sinHalfTheta ) < 0.001 ) {
+
+ this._w = 0.5 * ( w + this._w );
+ this._x = 0.5 * ( x + this._x );
+ this._y = 0.5 * ( y + this._y );
+ this._z = 0.5 * ( z + this._z );
+
+ return this;
+
+ }
+
+ var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
+ var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
+ ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
+
+ this._w = ( w * ratioA + this._w * ratioB );
+ this._x = ( x * ratioA + this._x * ratioB );
+ this._y = ( y * ratioA + this._y * ratioB );
+ this._z = ( z * ratioA + this._z * ratioB );
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ equals: function ( quaternion ) {
+
+ return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
+
+ },
+
+ fromArray: function ( array, offset ) {
+
+ if ( offset === undefined ) offset = 0;
+
+ this._x = array[ offset ];
+ this._y = array[ offset + 1 ];
+ this._z = array[ offset + 2 ];
+ this._w = array[ offset + 3 ];
+
+ this.onChangeCallback();
+
+ return this;
+
+ },
+
+ toArray: function ( array, offset ) {
+
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this._x;
+ array[ offset + 1 ] = this._y;
+ array[ offset + 2 ] = this._z;
+ array[ offset + 3 ] = this._w;
+
+ return array;
+
+ },
+
+ onChange: function ( callback ) {
+
+ this.onChangeCallback = callback;
+
+ return this;
+
+ },
+
+ onChangeCallback: function () {}
+
+ };
+
+ Object.assign( Quaternion, {
+
+ slerp: function( qa, qb, qm, t ) {
+
+ return qm.copy( qa ).slerp( qb, t );
+
+ },
+
+ slerpFlat: function(
+ dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
+
+ // fuzz-free, array-based Quaternion SLERP operation
+
+ var x0 = src0[ srcOffset0 + 0 ],
+ y0 = src0[ srcOffset0 + 1 ],
+ z0 = src0[ srcOffset0 + 2 ],
+ w0 = src0[ srcOffset0 + 3 ],
+
+ x1 = src1[ srcOffset1 + 0 ],
+ y1 = src1[ srcOffset1 + 1 ],
+ z1 = src1[ srcOffset1 + 2 ],
+ w1 = src1[ srcOffset1 + 3 ];
+
+ if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
+
+ var s = 1 - t,
+
+ cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
+
+ dir = ( cos >= 0 ? 1 : - 1 ),
+ sqrSin = 1 - cos * cos;
+
+ // Skip the Slerp for tiny steps to avoid numeric problems:
+ if ( sqrSin > Number.EPSILON ) {
+
+ var sin = Math.sqrt( sqrSin ),
+ len = Math.atan2( sin, cos * dir );
+
+ s = Math.sin( s * len ) / sin;
+ t = Math.sin( t * len ) / sin;
+
+ }
+
+ var tDir = t * dir;
+
+ x0 = x0 * s + x1 * tDir;
+ y0 = y0 * s + y1 * tDir;
+ z0 = z0 * s + z1 * tDir;
+ w0 = w0 * s + w1 * tDir;
+
+ // Normalize in case we just did a lerp:
+ if ( s === 1 - t ) {
+
+ var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
+
+ x0 *= f;
+ y0 *= f;
+ z0 *= f;
+ w0 *= f;
+
+ }
+
+ }
+
+ dst[ dstOffset ] = x0;
+ dst[ dstOffset + 1 ] = y0;
+ dst[ dstOffset + 2 ] = z0;
+ dst[ dstOffset + 3 ] = w0;
+
+ }
+
+ } );
+
+ /**
+ * @author mrdoob / http://mrdoob.com/
+ * @author *kile / http://kile.stravaganza.org/
+ * @author philogb / http://blog.thejit.org/
+ * @author mikael emtinger / http://gomo.se/
+ * @author egraether / http://egraether.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
+ function Vector3( x, y, z ) {
+
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+
+ }
+
+ Vector3.prototype = {
+
+ constructor: Vector3,
+
+ isVector3: true,
+
+ set: function ( x, y, z ) {
+
+ this.x = x;
+ this.y = y;
+ this.z = z;
+
+ return this;
+
+ },
+
+ setScalar: function ( scalar ) {
+
+ this.x = scalar;
+ this.y = scalar;
+ this.z = scalar;
+
+ return this;
+
+ },
+
+ setX: function ( x ) {
+
+ this.x = x;
+
+ return this;
+
+ },
+
+ setY: function ( y ) {
+
+ this.y = y;
+
+ return this;
+
+ },
+
+ setZ: function ( z ) {
+
+ this.z = z;
+
+ return this;
+
+ },
+
+ setComponent: function ( index, value ) {
+
+ switch ( index ) {
+
+ case 0: this.x = value; break;
+ case 1: this.y = value; break;
+ case 2: this.z = value; break;
+ default: throw new Error( 'index is out of range: ' + index );
+
+ }
+
+ return this;
+
+ },
+
+ getComponent: function ( index ) {
+
+ switch ( index ) {
+
+ case 0: return this.x;
+ case 1: return this.y;
+ case 2: return this.z;
+ default: throw new Error( 'index is out of range: ' + index );
+
+ }
+
+ },
+
+ clone: function () {
+
+ return new this.constructor( this.x, this.y, this.z );
+
+ },
+
+ copy: function ( v ) {
+
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+
+ return this;
+
+ },
+
+ add: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
+ return this.addVectors( v, w );
+
+ }
+
+ this.x += v.x;
+ this.y += v.y;
+ this.z += v.z;
+
+ return this;
+
+ },
+
+ addScalar: function ( s ) {
+
+ this.x += s;
+ this.y += s;
+ this.z += s;
+
+ return this;
+
+ },
+
+ addVectors: function ( a, b ) {
+
+ this.x = a.x + b.x;
+ this.y = a.y + b.y;
+ this.z = a.z + b.z;
+
+ return this;
+
+ },
+
+ addScaledVector: function ( v, s ) {
+
+ this.x += v.x * s;
+ this.y += v.y * s;
+ this.z += v.z * s;
+
+ return this;
+
+ },
+
+ sub: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
+ return this.subVectors( v, w );
+
+ }
+
+ this.x -= v.x;
+ this.y -= v.y;
+ this.z -= v.z;
+
+ return this;
+
+ },
+
+ subScalar: function ( s ) {
+
+ this.x -= s;
+ this.y -= s;
+ this.z -= s;
+
+ return this;
+
+ },
+
+ subVectors: function ( a, b ) {
+
+ this.x = a.x - b.x;
+ this.y = a.y - b.y;
+ this.z = a.z - b.z;
+
+ return this;
+
+ },
+
+ multiply: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
+ return this.multiplyVectors( v, w );
+
+ }
+
+ this.x *= v.x;
+ this.y *= v.y;
+ this.z *= v.z;
+
+ return this;
+
+ },
+
+ multiplyScalar: function ( scalar ) {
+
+ if ( isFinite( scalar ) ) {
+
+ this.x *= scalar;
+ this.y *= scalar;
+ this.z *= scalar;
+
+ } else {
+
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+
+ }
+
+ return this;
+
+ },
+
+ multiplyVectors: function ( a, b ) {
+
+ this.x = a.x * b.x;
+ this.y = a.y * b.y;
+ this.z = a.z * b.z;
+
+ return this;
+
+ },
+
+ applyEuler: function () {
+
+ var quaternion;
+
+ return function applyEuler( euler ) {
+
+ if ( (euler && euler.isEuler) === false ) {
+
+ console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
+
+ }
+
+ if ( quaternion === undefined ) quaternion = new Quaternion();
+
+ return this.applyQuaternion( quaternion.setFromEuler( euler ) );
+
+ };
+
+ }(),
+
+ applyAxisAngle: function () {
+
+ var quaternion;
+
+ return function applyAxisAngle( axis, angle ) {
+
+ if ( quaternion === undefined ) quaternion = new Quaternion();
+
+ return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
+
+ };
+
+ }(),
+
+ applyMatrix3: function ( m ) {
+
+ var x = this.x, y = this.y, z = this.z;
+ var e = m.elements;
+
+ this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
+ this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
+ this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
+
+ return this;
+
+ },
+
+ applyMatrix4: function ( m ) {
+
+ // input: THREE.Matrix4 affine matrix
+
+ var x = this.x, y = this.y, z = this.z;
+ var e = m.elements;
+
+ this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ];
+ this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ];
+ this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];
+
+ return this;
+
+ },
+
+ applyProjection: function ( m ) {
+
+ // input: THREE.Matrix4 projection matrix
+
+ var x = this.x, y = this.y, z = this.z;
+ var e = m.elements;
+ var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide
+
+ this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * d;
+ this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * d;
+ this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d;
+
+ return this;
+
+ },
+
+ applyQuaternion: function ( q ) {
+
+ var x = this.x, y = this.y, z = this.z;
+ var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
+
+ // calculate quat * vector
+
+ var ix = qw * x + qy * z - qz * y;
+ var iy = qw * y + qz * x - qx * z;
+ var iz = qw * z + qx * y - qy * x;
+ var iw = - qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+
+ this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
+ this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
+ this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
+
+ return this;
+
+ },
+
+ project: function () {
+
+ var matrix;
+
+ return function project( camera ) {
+
+ if ( matrix === undefined ) matrix = new Matrix4();
+
+ matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
+ return this.applyProjection( matrix );
+
+ };
+
+ }(),
+
+ unproject: function () {
+
+ var matrix;
+
+ return function unproject( camera ) {
+
+ if ( matrix === undefined ) matrix = new Matrix4();
+
+ matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
+ return this.applyProjection( matrix );
+
+ };
+
+ }(),
+
+ transformDirection: function ( m ) {
+
+ // input: THREE.Matrix4 affine matrix
+ // vector interpreted as a direction
+
+ var x = this.x, y = this.y, z = this.z;
+ var e = m.elements;
+
+ this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
+ this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
+ this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
+
+ return this.normalize();
+
+ },
+
+ divide: function ( v ) {
+
+ this.x /= v.x;
+ this.y /= v.y;
+ this.z /= v.z;
+
+ return this;
+
+ },
+
+ divideScalar: function ( scalar ) {
+
+ return this.multiplyScalar( 1 / scalar );
+
+ },
+
+ min: function ( v ) {
+
+ this.x = Math.min( this.x, v.x );
+ this.y = Math.min( this.y, v.y );
+ this.z = Math.min( this.z, v.z );
+
+ return this;
+
+ },
+
+ max: function ( v ) {
+
+ this.x = Math.max( this.x, v.x );
+ this.y = Math.max( this.y, v.y );
+ this.z = Math.max( this.z, v.z );
+
+ return this;
+
+ },
+
+ clamp: function ( min, max ) {
+
+ // This function assumes min < max, if this assumption isn't true it will not operate correctly
+
+ this.x = Math.max( min.x, Math.min( max.x, this.x ) );
+ this.y = Math.max( min.y, Math.min( max.y, this.y ) );
+ this.z = Math.max( min.z, Math.min( max.z, this.z ) );
+
+ return this;
+
+ },
+
+ clampScalar: function () {
+
+ var min, max;
+
+ return function clampScalar( minVal, maxVal ) {
+
+ if ( min === undefined ) {
+
+ min = new Vector3();
+ max = new Vector3();
+
+ }
+
+ min.set( minVal, minVal, minVal );
+ max.set( maxVal, maxVal, maxVal );
+
+ return this.clamp( min, max );
+
+ };
+
+ }(),
+
+ clampLength: function ( min, max ) {
+
+ var length = this.length();
+
+ return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
+
+ },
+
+ floor: function () {
+
+ this.x = Math.floor( this.x );
+ this.y = Math.floor( this.y );
+ this.z = Math.floor( this.z );
+
+ return this;
+
+ },
+
+ ceil: function () {
+
+ this.x = Math.ceil( this.x );
+ this.y = Math.ceil( this.y );
+ this.z = Math.ceil( this.z );
+
+ return this;
+
+ },
+
+ round: function () {
+
+ this.x = Math.round( this.x );
+ this.y = Math.round( this.y );
+ this.z = Math.round( this.z );
+
+ return this;
+
+ },
+
+ roundToZero: function () {
+
+ this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
+ this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
+ this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
+
+ return this;
+
+ },
+
+ negate: function () {
+
+ this.x = - this.x;
+ this.y = - this.y;
+ this.z = - this.z;
+
+ return this;
+
+ },
+
+ dot: function ( v ) {
+
+ return this.x * v.x + this.y * v.y + this.z * v.z;
+
+ },
+
+ lengthSq: function () {
+
+ return this.x * this.x + this.y * this.y + this.z * this.z;
+
+ },
+
+ length: function () {
+
+ return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
+
+ },
+
+ lengthManhattan: function () {
+
+ return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
+
+ },
+
+ normalize: function () {
+
+ return this.divideScalar( this.length() );
+
+ },
+
+ setLength: function ( length ) {
+
+ return this.multiplyScalar( length / this.length() );
+
+ },
+
+ lerp: function ( v, alpha ) {
+
+ this.x += ( v.x - this.x ) * alpha;
+ this.y += ( v.y - this.y ) * alpha;
+ this.z += ( v.z - this.z ) * alpha;
+
+ return this;
+
+ },
+
+ lerpVectors: function ( v1, v2, alpha ) {
+
+ return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
+
+ },
+
+ cross: function ( v, w ) {
+
+ if ( w !== undefined ) {
+
+ console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
+ return this.crossVectors( v, w );
+
+ }
+
+ var x = this.x, y = this.y, z = this.z;
+
+ this.x = y * v.z - z * v.y;
+ this.y = z * v.x - x * v.z;
+ this.z = x * v.y - y * v.x;
+
+ return this;
+
+ },
+
+ crossVectors: function ( a, b ) {
+
+ var ax = a.x, ay = a.y, az = a.z;
+ var bx = b.x, by = b.y, bz = b.z;
+
+ this.x = ay * bz - az * by;
+ this.y = az * bx - ax * bz;
+ this.z = ax * by - ay * bx;
+
+ return this;
+
+ },
+
+ projectOnVector: function ( vector ) {
+
+ var scalar = vector.dot( this ) / vector.lengthSq();
+
+ return this.copy( vector ).multiplyScalar( scalar );
+
+ },
+
+ projectOnPlane: function () {
+
+ var v1;
+
+ return function projectOnPlane( planeNormal ) {
+
+ if ( v1 === undefined ) v1 = new Vector3();
+
+ v1.copy( this ).projectOnVector( planeNormal );
+
+ return this.sub( v1 );
+
+ };
+
+ }(),
+
+ reflect: function () {
+
+ // reflect incident vector off plane orthogonal to normal
+ // normal is assumed to have unit length
+
+ var v1;
+
+ return function reflect( normal ) {
+
+ if ( v1 === undefined ) v1 = new Vector3();
+
+ return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
+
+ };
+
+ }(),
+
+ angleTo: function ( v ) {
+
+ var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );
+
+ // clamp, to handle numerical problems
+
+ return Math.acos( _Math.clamp( theta, - 1, 1 ) );
+
+ },
+
+ distanceTo: function ( v ) {
+
+ return Math.sqrt( this.distanceToSquared( v ) );
+
+ },
+
+ distanceToSquared: function ( v ) {
+
+ var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
+
+ return dx * dx + dy * dy + dz * dz;
+
+ },
+
+ distanceToManhattan: function ( v ) {
+
+ return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
+
+ },
+
+ setFromSpherical: function( s ) {
+
+ var sinPhiRadius = Math.sin( s.phi ) * s.radius;
+
+ this.x = sinPhiRadius * Math.sin( s.theta );
+ this.y = Math.cos( s.phi ) * s.radius;
+ this.z = sinPhiRadius * Math.cos( s.theta );
+
+ return this;
+
+ },
+
+ setFromCylindrical: function( c ) {
+
+ this.x = c.radius * Math.sin( c.theta );
+ this.y = c.y;
+ this.z = c.radius * Math.cos( c.theta );
+
+ return this;
+
+ },
+
+ setFromMatrixPosition: function ( m ) {
+
+ return this.setFromMatrixColumn( m, 3 );
+
+ },
+
+ setFromMatrixScale: function ( m ) {
+
+ var sx = this.setFromMatrixColumn( m, 0 ).length();
+ var sy = this.setFromMatrixColumn( m, 1 ).length();
+ var sz = this.setFromMatrixColumn( m, 2 ).length();
+
+ this.x = sx;
+ this.y = sy;
+ this.z = sz;
+
+ return this;
+
+ },
+
+ setFromMatrixColumn: function ( m, index ) {
+
+ if ( typeof m === 'number' ) {
+
+ console.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' );
+ var temp = m;
+ m = index;
+ index = temp;
+
+ }
+
+ return this.fromArray( m.elements, index * 4 );
+
+ },
+
+ equals: function ( v ) {
+
+ return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
+
+ },
+
+ fromArray: function ( array, offset ) {
+
+ if ( offset === undefined ) offset = 0;
+
+ this.x = array[ offset ];
+ this.y = array[ offset + 1 ];
+ this.z = array[ offset + 2 ];
+
+ return this;
+
+ },
+
+ toArray: function ( array, offset ) {
+
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this.x;
+ array[ offset + 1 ] = this.y;
+ array[ offset + 2 ] = this.z;
+
+ return array;
+
+ },
+
+ fromAttribute: function ( attribute, index, offset ) {
+
+ if ( offset !== undefined ) {
+
+ console.warn( 'THREE.Vector3: offset has been removed from .fromAttribute().' );
+
+ }
+
+ this.x = attribute.getX( index );
+ this.y = attribute.getY( index );
+ this.z = attribute.getZ( index );
+
+ return this;
+
+ }
+
+ };
+
+ /**
+ * @author mrdoob / http://mrdoob.com/
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ * @author philogb / http://blog.thejit.org/
+ * @author jordi_ros / http://plattsoft.com
+ * @author D1plo1d / http://github.com/D1plo1d
+ * @author alteredq / http://alteredqualia.com/
+ * @author mikael emtinger / http://gomo.se/
+ * @author timknip / http://www.floorplanner.com/
+ * @author bhouston / http://clara.io
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
+ function Matrix4() {
+
+ this.elements = new Float64Array( [
+
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+
+ ] );
+
+ if ( arguments.length > 0 ) {
+
+ console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
+
+ }
+
+ }
+
+ Matrix4.prototype = {
+
+ constructor: Matrix4,
+
+ isMatrix4: true,
+
+ set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
+
+ var te = this.elements;
+
+ te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
+ te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
+ te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
+ te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
+
+ return this;
+
+ },
+
+ identity: function () {
+
+ this.set(
+
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ clone: function () {
+
+ return new Matrix4().fromArray( this.elements );
+
+ },
+
+ copy: function ( m ) {
+
+ this.elements.set( m.elements );
+
+ return this;
+
+ },
+
+ copyPosition: function ( m ) {
+
+ var te = this.elements;
+ var me = m.elements;
+
+ te[ 12 ] = me[ 12 ];
+ te[ 13 ] = me[ 13 ];
+ te[ 14 ] = me[ 14 ];
+
+ return this;
+
+ },
+
+ extractBasis: function ( xAxis, yAxis, zAxis ) {
+
+ xAxis.setFromMatrixColumn( this, 0 );
+ yAxis.setFromMatrixColumn( this, 1 );
+ zAxis.setFromMatrixColumn( this, 2 );
+
+ return this;
+
+ },
+
+ makeBasis: function ( xAxis, yAxis, zAxis ) {
+
+ this.set(
+ xAxis.x, yAxis.x, zAxis.x, 0,
+ xAxis.y, yAxis.y, zAxis.y, 0,
+ xAxis.z, yAxis.z, zAxis.z, 0,
+ 0, 0, 0, 1
+ );
+
+ return this;
+
+ },
+
+ extractRotation: function () {
+
+ var v1;
+
+ return function extractRotation( m ) {
+
+ if ( v1 === undefined ) v1 = new Vector3();
+
+ var te = this.elements;
+ var me = m.elements;
+
+ var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
+ var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
+ var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
+
+ te[ 0 ] = me[ 0 ] * scaleX;
+ te[ 1 ] = me[ 1 ] * scaleX;
+ te[ 2 ] = me[ 2 ] * scaleX;
+
+ te[ 4 ] = me[ 4 ] * scaleY;
+ te[ 5 ] = me[ 5 ] * scaleY;
+ te[ 6 ] = me[ 6 ] * scaleY;
+
+ te[ 8 ] = me[ 8 ] * scaleZ;
+ te[ 9 ] = me[ 9 ] * scaleZ;
+ te[ 10 ] = me[ 10 ] * scaleZ;
+
+ return this;
+
+ };
+
+ }(),
+
+ makeRotationFromEuler: function ( euler ) {
+
+ if ( (euler && euler.isEuler) === false ) {
+
+ console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
+
+ }
+
+ var te = this.elements;
+
+ var x = euler.x, y = euler.y, z = euler.z;
+ var a = Math.cos( x ), b = Math.sin( x );
+ var c = Math.cos( y ), d = Math.sin( y );
+ var e = Math.cos( z ), f = Math.sin( z );
+
+ if ( euler.order === 'XYZ' ) {
+
+ var ae = a * e, af = a * f, be = b * e, bf = b * f;
+
+ te[ 0 ] = c * e;
+ te[ 4 ] = - c * f;
+ te[ 8 ] = d;
+
+ te[ 1 ] = af + be * d;
+ te[ 5 ] = ae - bf * d;
+ te[ 9 ] = - b * c;
+
+ te[ 2 ] = bf - ae * d;
+ te[ 6 ] = be + af * d;
+ te[ 10 ] = a * c;
+
+ } else if ( euler.order === 'YXZ' ) {
+
+ var ce = c * e, cf = c * f, de = d * e, df = d * f;
+
+ te[ 0 ] = ce + df * b;
+ te[ 4 ] = de * b - cf;
+ te[ 8 ] = a * d;
+
+ te[ 1 ] = a * f;
+ te[ 5 ] = a * e;
+ te[ 9 ] = - b;
+
+ te[ 2 ] = cf * b - de;
+ te[ 6 ] = df + ce * b;
+ te[ 10 ] = a * c;
+
+ } else if ( euler.order === 'ZXY' ) {
+
+ var ce = c * e, cf = c * f, de = d * e, df = d * f;
+
+ te[ 0 ] = ce - df * b;
+ te[ 4 ] = - a * f;
+ te[ 8 ] = de + cf * b;
+
+ te[ 1 ] = cf + de * b;
+ te[ 5 ] = a * e;
+ te[ 9 ] = df - ce * b;
+
+ te[ 2 ] = - a * d;
+ te[ 6 ] = b;
+ te[ 10 ] = a * c;
+
+ } else if ( euler.order === 'ZYX' ) {
+
+ var ae = a * e, af = a * f, be = b * e, bf = b * f;
+
+ te[ 0 ] = c * e;
+ te[ 4 ] = be * d - af;
+ te[ 8 ] = ae * d + bf;
+
+ te[ 1 ] = c * f;
+ te[ 5 ] = bf * d + ae;
+ te[ 9 ] = af * d - be;
+
+ te[ 2 ] = - d;
+ te[ 6 ] = b * c;
+ te[ 10 ] = a * c;
+
+ } else if ( euler.order === 'YZX' ) {
+
+ var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
+
+ te[ 0 ] = c * e;
+ te[ 4 ] = bd - ac * f;
+ te[ 8 ] = bc * f + ad;
+
+ te[ 1 ] = f;
+ te[ 5 ] = a * e;
+ te[ 9 ] = - b * e;
+
+ te[ 2 ] = - d * e;
+ te[ 6 ] = ad * f + bc;
+ te[ 10 ] = ac - bd * f;
+
+ } else if ( euler.order === 'XZY' ) {
+
+ var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
+
+ te[ 0 ] = c * e;
+ te[ 4 ] = - f;
+ te[ 8 ] = d * e;
+
+ te[ 1 ] = ac * f + bd;
+ te[ 5 ] = a * e;
+ te[ 9 ] = ad * f - bc;
+
+ te[ 2 ] = bc * f - ad;
+ te[ 6 ] = b * e;
+ te[ 10 ] = bd * f + ac;
+
+ }
+
+ // last column
+ te[ 3 ] = 0;
+ te[ 7 ] = 0;
+ te[ 11 ] = 0;
+
+ // bottom row
+ te[ 12 ] = 0;
+ te[ 13 ] = 0;
+ te[ 14 ] = 0;
+ te[ 15 ] = 1;
+
+ return this;
+
+ },
+
+ makeRotationFromQuaternion: function ( q ) {
+
+ var te = this.elements;
+
+ var x = q.x, y = q.y, z = q.z, w = q.w;
+ var x2 = x + x, y2 = y + y, z2 = z + z;
+ var xx = x * x2, xy = x * y2, xz = x * z2;
+ var yy = y * y2, yz = y * z2, zz = z * z2;
+ var wx = w * x2, wy = w * y2, wz = w * z2;
+
+ te[ 0 ] = 1 - ( yy + zz );
+ te[ 4 ] = xy - wz;
+ te[ 8 ] = xz + wy;
+
+ te[ 1 ] = xy + wz;
+ te[ 5 ] = 1 - ( xx + zz );
+ te[ 9 ] = yz - wx;
+
+ te[ 2 ] = xz - wy;
+ te[ 6 ] = yz + wx;
+ te[ 10 ] = 1 - ( xx + yy );
+
+ // last column
+ te[ 3 ] = 0;
+ te[ 7 ] = 0;
+ te[ 11 ] = 0;
+
+ // bottom row
+ te[ 12 ] = 0;
+ te[ 13 ] = 0;
+ te[ 14 ] = 0;
+ te[ 15 ] = 1;
+
+ return this;
+
+ },
+
+ lookAt: function () {
+
+ var x, y, z;
+
+ return function lookAt( eye, target, up ) {
+
+ if ( x === undefined ) {
+
+ x = new Vector3();
+ y = new Vector3();
+ z = new Vector3();
+
+ }
+
+ var te = this.elements;
+
+ z.subVectors( eye, target ).normalize();
+
+ if ( z.lengthSq() === 0 ) {
+
+ z.z = 1;
+
+ }
+
+ x.crossVectors( up, z ).normalize();
+
+ if ( x.lengthSq() === 0 ) {
+
+ z.z += 0.0001;
+ x.crossVectors( up, z ).normalize();
+
+ }
+
+ y.crossVectors( z, x );
+
+
+ te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
+ te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
+ te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
+
+ return this;
+
+ };
+
+ }(),
+
+ multiply: function ( m, n ) {
+
+ if ( n !== undefined ) {
+
+ console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
+ return this.multiplyMatrices( m, n );
+
+ }
+
+ return this.multiplyMatrices( this, m );
+
+ },
+
+ premultiply: function ( m ) {
+
+ return this.multiplyMatrices( m, this );
+
+ },
+
+ multiplyMatrices: function ( a, b ) {
+
+ var ae = a.elements;
+ var be = b.elements;
+ var te = this.elements;
+
+ var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
+ var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
+ var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
+ var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
+
+ var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
+ var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
+ var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
+ var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
+
+ te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
+ te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
+ te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
+ te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
+
+ te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
+ te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
+ te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
+ te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
+
+ te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
+ te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
+ te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
+ te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
+
+ te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
+ te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
+ te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
+ te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
+
+ return this;
+
+ },
+
+ multiplyToArray: function ( a, b, r ) {
+
+ var te = this.elements;
+
+ this.multiplyMatrices( a, b );
+
+ r[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ];
+ r[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ];
+ r[ 8 ] = te[ 8 ]; r[ 9 ] = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ];
+ r[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ];
+
+ return this;
+
+ },
+
+ multiplyScalar: function ( s ) {
+
+ var te = this.elements;
+
+ te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
+ te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
+ te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
+ te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
+
+ return this;
+
+ },
+
+ applyToBufferAttribute: function () {
+
+ var v1;
+
+ return function applyToBufferAttribute( attribute ) {
+
+ if ( v1 === undefined ) v1 = new Vector3();
+
+ for ( var i = 0, l = attribute.count; i < l; i ++ ) {
+
+ v1.x = attribute.getX( i );
+ v1.y = attribute.getY( i );
+ v1.z = attribute.getZ( i );
+
+ v1.applyMatrix4( this );
+
+ attribute.setXYZ( i, v1.x, v1.y, v1.z );
+
+ }
+
+ return attribute;
+
+ };
+
+ }(),
+
+ determinant: function () {
+
+ var te = this.elements;
+
+ var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
+ var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
+ var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
+ var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
+
+ //TODO: make this more efficient
+ //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
+
+ return (
+ n41 * (
+ + n14 * n23 * n32
+ - n13 * n24 * n32
+ - n14 * n22 * n33
+ + n12 * n24 * n33
+ + n13 * n22 * n34
+ - n12 * n23 * n34
+ ) +
+ n42 * (
+ + n11 * n23 * n34
+ - n11 * n24 * n33
+ + n14 * n21 * n33
+ - n13 * n21 * n34
+ + n13 * n24 * n31
+ - n14 * n23 * n31
+ ) +
+ n43 * (
+ + n11 * n24 * n32
+ - n11 * n22 * n34
+ - n14 * n21 * n32
+ + n12 * n21 * n34
+ + n14 * n22 * n31
+ - n12 * n24 * n31
+ ) +
+ n44 * (
+ - n13 * n22 * n31
+ - n11 * n23 * n32
+ + n11 * n22 * n33
+ + n13 * n21 * n32
+ - n12 * n21 * n33
+ + n12 * n23 * n31
+ )
+
+ );
+
+ },
+
+ transpose: function () {
+
+ var te = this.elements;
+ var tmp;
+
+ tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
+ tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
+ tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
+
+ tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
+ tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
+ tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
+
+ return this;
+
+ },
+
+ setPosition: function ( v ) {
+
+ var te = this.elements;
+
+ te[ 12 ] = v.x;
+ te[ 13 ] = v.y;
+ te[ 14 ] = v.z;
+
+ return this;
+
+ },
+
+ getInverse: function ( m, throwOnDegenerate ) {
+
+ // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
+ var te = this.elements,
+ me = m.elements,
+
+ n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
+ n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
+ n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
+ n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],
+
+ t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
+ t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
+ t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
+ t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
+
+ var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
+
+ if ( det === 0 ) {
+
+ var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0";
+
+ if ( throwOnDegenerate === true ) {
+
+ throw new Error( msg );
+
+ } else {
+
+ console.warn( msg );
+
+ }
+
+ return this.identity();
+
+ }
+
+ var detInv = 1 / det;
+
+ te[ 0 ] = t11 * detInv;
+ te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
+ te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
+ te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
+
+ te[ 4 ] = t12 * detInv;
+ te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
+ te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
+ te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
+
+ te[ 8 ] = t13 * detInv;
+ te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
+ te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
+ te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
+
+ te[ 12 ] = t14 * detInv;
+ te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
+ te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
+ te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
+
+ return this;
+
+ },
+
+ scale: function ( v ) {
+
+ var te = this.elements;
+ var x = v.x, y = v.y, z = v.z;
+
+ te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
+ te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
+ te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
+ te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
+
+ return this;
+
+ },
+
+ getMaxScaleOnAxis: function () {
+
+ var te = this.elements;
+
+ var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
+ var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
+ var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
+
+ return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
+
+ },
+
+ makeTranslation: function ( x, y, z ) {
+
+ this.set(
+
+ 1, 0, 0, x,
+ 0, 1, 0, y,
+ 0, 0, 1, z,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ makeRotationX: function ( theta ) {
+
+ var c = Math.cos( theta ), s = Math.sin( theta );
+
+ this.set(
+
+ 1, 0, 0, 0,
+ 0, c, - s, 0,
+ 0, s, c, 0,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ makeRotationY: function ( theta ) {
+
+ var c = Math.cos( theta ), s = Math.sin( theta );
+
+ this.set(
+
+ c, 0, s, 0,
+ 0, 1, 0, 0,
+ - s, 0, c, 0,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ makeRotationZ: function ( theta ) {
+
+ var c = Math.cos( theta ), s = Math.sin( theta );
+
+ this.set(
+
+ c, - s, 0, 0,
+ s, c, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ makeRotationAxis: function ( axis, angle ) {
+
+ // Based on http://www.gamedev.net/reference/articles/article1199.asp
+
+ var c = Math.cos( angle );
+ var s = Math.sin( angle );
+ var t = 1 - c;
+ var x = axis.x, y = axis.y, z = axis.z;
+ var tx = t * x, ty = t * y;
+
+ this.set(
+
+ tx * x + c, tx * y - s * z, tx * z + s * y, 0,
+ tx * y + s * z, ty * y + c, ty * z - s * x, 0,
+ tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ makeScale: function ( x, y, z ) {
+
+ this.set(
+
+ x, 0, 0, 0,
+ 0, y, 0, 0,
+ 0, 0, z, 0,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ makeShear: function ( x, y, z ) {
+
+ this.set(
+
+ 1, y, z, 0,
+ x, 1, z, 0,
+ x, y, 1, 0,
+ 0, 0, 0, 1
+
+ );
+
+ return this;
+
+ },
+
+ compose: function ( position, quaternion, scale ) {
+
+ this.makeRotationFromQuaternion( quaternion );
+ this.scale( scale );
+ this.setPosition( position );
+
+ return this;
+
+ },
+
+ decompose: function () {
+
+ var vector, matrix;
+
+ return function decompose( position, quaternion, scale ) {
+
+ if ( vector === undefined ) {
+
+ vector = new Vector3();
+ matrix = new Matrix4();
+
+ }
+
+ var te = this.elements;
+
+ var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
+ var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
+ var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
+
+ // if determine is negative, we need to invert one scale
+ var det = this.determinant();
+ if ( det < 0 ) {
+
+ sx = - sx;
+
+ }
+
+ position.x = te[ 12 ];
+ position.y = te[ 13 ];
+ position.z = te[ 14 ];
+
+ // scale the rotation part
+
+ matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()
+
+ var invSX = 1 / sx;
+ var invSY = 1 / sy;
+ var invSZ = 1 / sz;
+
+ matrix.elements[ 0 ] *= invSX;
+ matrix.elements[ 1 ] *= invSX;
+ matrix.elements[ 2 ] *= invSX;
+
+ matrix.elements[ 4 ] *= invSY;
+ matrix.elements[ 5 ] *= invSY;
+ matrix.elements[ 6 ] *= invSY;
+
+ matrix.elements[ 8 ] *= invSZ;
+ matrix.elements[ 9 ] *= invSZ;
+ matrix.elements[ 10 ] *= invSZ;
+
+ quaternion.setFromRotationMatrix( matrix );
+
+ scale.x = sx;
+ scale.y = sy;
+ scale.z = sz;
+
+ return this;
+
+ };
+
+ }(),
+
+ makePerspective: function ( left, right, top, bottom, near, far ) {
+
+ if ( far === undefined ) {
+
+ console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
+
+ }
+
+ var te = this.elements;
+ var x = 2 * near / ( right - left );
+ var y = 2 * near / ( top - bottom );
+
+ var a = ( right + left ) / ( right - left );
+ var b = ( top + bottom ) / ( top - bottom );
+ var c = - ( far + near ) / ( far - near );
+ var d = - 2 * far * near / ( far - near );
+
+ te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
+ te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
+ te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
+ te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
+
+ return this;
+
+ },
+
+ makeOrthographic: function ( left, right, top, bottom, near, far ) {
+
+ var te = this.elements;
+ var w = 1.0 / ( right - left );
+ var h = 1.0 / ( top - bottom );
+ var p = 1.0 / ( far - near );
+
+ var x = ( right + left ) * w;
+ var y = ( top + bottom ) * h;
+ var z = ( far + near ) * p;
+
+ te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
+ te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
+ te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
+ te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
+
+ return this;
+
+ },
+
+ equals: function ( matrix ) {
+
+ var te = this.elements;
+ var me = matrix.elements;
+
+ for ( var i = 0; i < 16; i ++ ) {
+
+ if ( te[ i ] !== me[ i ] ) return false;
+
+ }
+
+ return true;
+
+ },
+
+ fromArray: function ( array, offset ) {
+
+ if ( offset === undefined ) offset = 0;
+
+ for( var i = 0; i < 16; i ++ ) {
+
+ this.elements[ i ] = array[ i + offset ];
+
+ }
+
+ return this;
+
+ },
+
+ toArray: function ( array, offset ) {
+
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ var te = this.elements;
+
+ array[ offset ] = te[ 0 ];
+ array[ offset + 1 ] = te[ 1 ];
+ array[ offset + 2 ] = te[ 2 ];
+ array[ offset + 3 ] = te[ 3 ];
+
+ array[ offset + 4 ] = te[ 4 ];
+ array[ offset + 5 ] = te[ 5 ];
+ array[ offset + 6 ] = te[ 6 ];
+ array[ offset + 7 ] = te[ 7 ];
+
+ array[ offset + 8 ] = te[ 8 ];
+ array[ offset + 9 ] = te[ 9 ];
+ array[ offset + 10 ] = te[ 10 ];
+ array[ offset + 11 ] = te[ 11 ];
+
+ array[ offset + 12 ] = te[ 12 ];
+ array[ offset + 13 ] = te[ 13 ];
+ array[ offset + 14 ] = te[ 14 ];
+ array[ offset + 15 ] = te[ 15 ];
+
+ return array;
+
+ }
+
+ };
+
+ /**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+ function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
+
+ images = images !== undefined ? images : [];
+ mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
+
+ Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
+
+ this.flipY = false;
+
+ }
+
+ CubeTexture.prototype = Object.create( Texture.prototype );
+ CubeTexture.prototype.constructor = CubeTexture;
+
+ CubeTexture.prototype.isCubeTexture = true;
+
+ Object.defineProperty( CubeTexture.prototype, 'images', {
+
+ get: function () {
+
+ return this.image;
+
+ },
+
+ set: function ( value ) {
+
+ this.image = value;
+
+ }
+
+ } );
+
+ /**
+ * @author tschw
+ *
+ * Uniforms of a program.
+ * Those form a tree structure with a special top-level container for the root,
+ * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
+ *
+ *
+ * Properties of inner nodes including the top-level container:
+ *
+ * .seq - array of nested uniforms
+ * .map - nested uniforms by name
+ *
+ *
+ * Methods of all nodes except the top-level container:
+ *
+ * .setValue( gl, value, [renderer] )
+ *
+ * uploads a uniform value(s)
+ * the 'renderer' parameter is needed for sampler uniforms
+ *
+ *
+ * Static methods of the top-level container (renderer factorizations):
+ *
+ * .upload( gl, seq, values, renderer )
+ *
+ * sets uniforms in 'seq' to 'values[id].value'
+ *
+ * .seqWithValue( seq, values ) : filteredSeq
+ *
+ * filters 'seq' entries with corresponding entry in values
+ *
+ *
+ * Methods of the top-level container (renderer factorizations):
+ *
+ * .setValue( gl, name, value )
+ *
+ * sets uniform with name 'name' to 'value'
+ *
+ * .set( gl, obj, prop )
+ *
+ * sets uniform from object and property with same name than uniform
+ *
+ * .setOptional( gl, obj, prop )
+ *
+ * like .set for an optional property of the object
+ *
+ */
+
+ var emptyTexture = new Texture();
+ var emptyCubeTexture = new CubeTexture();
+
+ // --- Base for inner nodes (including the root) ---
+
+ function UniformContainer() {
+
+ this.seq = [];
+ this.map = {};
+
+ }
+
+ // --- Utilities ---
+
+ // Array Caches (provide typed arrays for temporary by size)
+
+ var arrayCacheF32 = [];
+ var arrayCacheI32 = [];
+
+ // Flattening for arrays of vectors and matrices
+
+ function flatten( array, nBlocks, blockSize ) {
+
+ var firstElem = array[ 0 ];
+
+ if ( firstElem <= 0 || firstElem > 0 ) return array;
+ // unoptimized: ! isNaN( firstElem )
+ // see http://jacksondunstan.com/articles/983
+
+ var n = nBlocks * blockSize,
+ r = arrayCacheF32[ n ];
+
+ if ( r === undefined ) {
+
+ r = new Float32Array( n );
+ arrayCacheF32[ n ] = r;
+
+ }
+
+ if ( nBlocks !== 0 ) {
+
+ firstElem.toArray( r, 0 );
+
+ for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {
+
+ offset += blockSize;
+ array[ i ].toArray( r, offset );
+
+ }
+
+ }
+
+ return r;
+
+ }
+
+ // Texture unit allocation
+
+ function allocTexUnits( renderer, n ) {
+
+ var r = arrayCacheI32[ n ];
+
+ if ( r === undefined ) {
+
+ r = new Int32Array( n );
+ arrayCacheI32[ n ] = r;
+
+ }
+
+ for ( var i = 0; i !== n; ++ i )
+ r[ i ] = renderer.allocTextureUnit();
+
+ return r;
+
+ }
+
+ // --- Setters ---
+
+ // Note: Defining these methods externally, because they come in a bunch
+ // and this way their names minify.
+
+ // Single scalar
+
+ function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); }
+ function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); }
+
+ // Single float vector (from flat array or THREE.VectorN)
+
+ function setValue2fv( gl, v ) {
+
+ if ( v.x === undefined ) gl.uniform2fv( this.addr, v );
+ else gl.uniform2f( this.addr, v.x, v.y );
+
+ }
+
+ function setValue3fv( gl, v ) {
+
+ if ( v.x !== undefined )
+ gl.uniform3f( this.addr, v.x, v.y, v.z );
+ else if ( v.r !== undefined )
+ gl.uniform3f( this.addr, v.r, v.g, v.b );
+ else
+ gl.uniform3fv( this.addr, v );
+
+ }
+
+ function setValue4fv( gl, v ) {
+
+ if ( v.x === undefined ) gl.uniform4fv( this.addr, v );
+ else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
+
+ }
+
+ // Single matrix (from flat array or MatrixN)
+
+ function setValue2fm( gl, v ) {
+
+ gl.uniformMatrix2fv( this.addr, false, v.elements || v );
+
+ }
+
+ function setValue3fm( gl, v ) {
+
+ gl.uniformMatrix3fv( this.addr, false, v.elements || v );
+
+ }
+
+ function setValue4fm( gl, v ) {
+
+ gl.uniformMatrix4fv( this.addr, false, new Float32Array(v.elements) || new Float32Array(v) );
+
+ }
+
+ // Single texture (2D / Cube)
+
+ function setValueT1( gl, v, renderer ) {
+
+ var unit = renderer.allocTextureUnit();
+ gl.uniform1i( this.addr, unit );
+ renderer.setTexture2D( v || emptyTexture, unit );
+
+ }
+
+ function setValueT6( gl, v, renderer ) {
+
+ var unit = renderer.allocTextureUnit();
+ gl.uniform1i( this.addr, unit );
+ renderer.setTextureCube( v || emptyCubeTexture, unit );
+
+ }
+
+ // Integer / Boolean vectors or arrays thereof (always flat arrays)
+
+ function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); }
+ function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); }
+ function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); }
+
+ // Helper to pick the right setter for the singular case
+
+ function getSingularSetter( type ) {
+
+ switch ( type ) {
+
+ case 0x1406: return setValue1f; // FLOAT
+ case 0x8b50: return setValue2fv; // _VEC2
+ case 0x8b51: return setValue3fv; // _VEC3
+ case 0x8b52: return setValue4fv; // _VEC4
+
+ case 0x8b5a: return setValue2fm; // _MAT2
+ case 0x8b5b: return setValue3fm; // _MAT3
+ case 0x8b5c: return setValue4fm; // _MAT4
+
+ case 0x8b5e: return setValueT1; // SAMPLER_2D
+ case 0x8b60: return setValueT6; // SAMPLER_CUBE
+
+ case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
+ case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
+ case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
+ case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
+
+ }
+
+ }
+
+ // Array of scalars
+
+ function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); }
+ function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); }
+
+ // Array of vectors (flat or from THREE classes)
+
+ function setValueV2a( gl, v ) {
+
+ gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );
+
+ }
+
+ function setValueV3a( gl, v ) {
+
+ gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );
+
+ }
+
+ function setValueV4a( gl, v ) {
+
+ gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );
+
+ }
+
+ // Array of matrices (flat or from THREE clases)
+
+ function setValueM2a( gl, v ) {
+
+ gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );
+
+ }
+
+ function setValueM3a( gl, v ) {
+
+ gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );
+
+ }
+
+ function setValueM4a( gl, v ) {
+
+ gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );
+
+ }
+
+ // Array of textures (2D / Cube)
+
+ function setValueT1a( gl, v, renderer ) {
+
+ var n = v.length,
+ units = allocTexUnits( renderer, n );
+
+ gl.uniform1iv( this.addr, units );
+
+ for ( var i = 0; i !== n; ++ i ) {
+
+ renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
+
+ }
+
+ }
+
+ function setValueT6a( gl, v, renderer ) {
+
+ var n = v.length,
+ units = allocTexUnits( renderer, n );
+
+ gl.uniform1iv( this.addr, units );
+
+ for ( var i = 0; i !== n; ++ i ) {
+
+ renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
+
+ }
+
+ }
+
+ // Helper to pick the right setter for a pure (bottom-level) array
+
+ function getPureArraySetter( type ) {
+
+ switch ( type ) {
+
+ case 0x1406: return setValue1fv; // FLOAT
+ case 0x8b50: return setValueV2a; // _VEC2
+ case 0x8b51: return setValueV3a; // _VEC3
+ case 0x8b52: return setValueV4a; // _VEC4
+
+ case 0x8b5a: return setValueM2a; // _MAT2
+ case 0x8b5b: return setValueM3a; // _MAT3
+ case 0x8b5c: return setValueM4a; // _MAT4
+
+ case 0x8b5e: return setValueT1a; // SAMPLER_2D
+ case 0x8b60: return setValueT6a; // SAMPLER_CUBE
+
+ case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
+ case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
+ case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
+ case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
+
+ }
+
+ }
+
+ // --- Uniform Classes ---
+
+ function SingleUniform( id, activeInfo, addr ) {
+
+ this.id = id;
+ this.addr = addr;
+ this.setValue = getSingularSetter( activeInfo.type );
+
+ // this.path = activeInfo.name; // DEBUG
+
+ }
+
+ function PureArrayUniform( id, activeInfo, addr ) {
+
+ this.id = id;
+ this.addr = addr;
+ this.size = activeInfo.size;
+ this.setValue = getPureArraySetter( activeInfo.type );
+
+ // this.path = activeInfo.name; // DEBUG
+
+ }
+
+ function StructuredUniform( id ) {
+
+ this.id = id;
+
+ UniformContainer.call( this ); // mix-in
+
+ }
+
+ StructuredUniform.prototype.setValue = function( gl, value ) {
+
+ // Note: Don't need an extra 'renderer' parameter, since samplers
+ // are not allowed in structured uniforms.
+
+ var seq = this.seq;
+
+ for ( var i = 0, n = seq.length; i !== n; ++ i ) {
+
+ var u = seq[ i ];
+ u.setValue( gl, value[ u.id ] );
+
+ }
+
+ };
+
+ // --- Top-level ---
+
+ // Parser - builds up the property tree from the path strings
+
+ var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
+
+ // extracts
+ // - the identifier (member name or array index)
+ // - followed by an optional right bracket (found when array index)
+ // - followed by an optional left bracket or dot (type of subscript)
+ //
+ // Note: These portions can be read in a non-overlapping fashion and
+ // allow straightforward parsing of the hierarchy that WebGL encodes
+ // in the uniform names.
+
+ function addUniform( container, uniformObject ) {
+
+ container.seq.push( uniformObject );
+ container.map[ uniformObject.id ] = uniformObject;
+
+ }
+
+ function parseUniform( activeInfo, addr, container ) {
+
+ var path = activeInfo.name,
+ pathLength = path.length;
+
+ // reset RegExp object, because of the early exit of a previous run
+ RePathPart.lastIndex = 0;
+
+ for (; ;) {
+
+ var match = RePathPart.exec( path ),
+ matchEnd = RePathPart.lastIndex,
+
+ id = match[ 1 ],
+ idIsIndex = match[ 2 ] === ']',
+ subscript = match[ 3 ];
+
+ if ( idIsIndex ) id = id | 0; // convert to integer
+
+ if ( subscript === undefined ||
+ subscript === '[' && matchEnd + 2 === pathLength ) {
+ // bare name or "pure" bottom-level array "[0]" suffix
+
+ addUniform( container, subscript === undefined ?
+ new SingleUniform( id, activeInfo, addr ) :
+ new PureArrayUniform( id, activeInfo, addr ) );
+
+ break;
+
+ } else {
+ // step into inner node / create it in case it doesn't exist
+
+ var map = container.map,
+ next = map[ id ];
+
+ if ( next === undefined ) {
+
+ next = new StructuredUniform( id );
+ addUniform( container, next );
+
+ }
+
+ container = next;
+
+ }
+
+ }
+
+ }
+
+ // Root Container
+
+ function WebGLUniforms( gl, program, renderer ) {
+
+ UniformContainer.call( this );
+
+ this.renderer = renderer;
+
+ var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
+
+ for ( var i = 0; i !== n; ++ i ) {
+
+ var info = gl.getActiveUniform( program, i ),
+ path = info.name,
+ addr = gl.getUniformLocation( program, path );
+
+ parseUniform( info, addr, this );
+
+ }
+
+ }
+
+ WebGLUniforms.prototype.setValue = function( gl, name, value ) {
+
+ var u = this.map[ name ];
+
+ if ( u !== undefined ) u.setValue( gl, value, this.renderer );
+
+ };
+
+ WebGLUniforms.prototype.set = function( gl, object, name ) {
+
+ var u = this.map[ name ];
+
+ if ( u !== undefined ) u.setValue( gl, object[ name ], this.renderer );
+
+ };
+
+ WebGLUniforms.prototype.setOptional = function( gl, object, name ) {
+
+ var v = object[ name ];
+
+ if ( v !== undefined ) this.setValue( gl, name, v );
+
+ };
+
+
+ // Static interface
+
+ WebGLUniforms.upload = function( gl, seq, values, renderer ) {
+
+ for ( var i = 0, n = seq.length; i !== n; ++ i ) {
+
+ var u = seq[ i ],
+ v = values[ u.id ];
+
+ if ( v.needsUpdate !== false ) {
+ // note: always updating when .needsUpdate is undefined
+
+ u.setValue( gl, v.value, renderer );
+
+ }
+
+ }
+
+ };
+
+ WebGLUniforms.seqWithValue = function( seq, values ) {
+
+ var r = [];
+
+ for ( var i = 0, n = seq.length; i !== n; ++ i ) {
+
+ var u = seq[ i ];
+ if ( u.id in values ) r.push( u );
+
+ }
+
+ return r;
+
+ };
+
+ /**
+ * Uniform Utilities
+ */
+
+ var UniformsUtils = {
+
+ merge: function ( uniforms ) {
+
+ var merged = {};
+
+ for ( var u = 0; u < uniforms.length; u ++ ) {
+
+ var tmp = this.clone( uniforms[ u ] );
+
+ for ( var p in tmp ) {
+
+ merged[ p ] = tmp[ p ];
+
+ }
+
+ }
+
+ return merged;
+
+ },
+
+ clone: function ( uniforms_src ) {
+
+ var uniforms_dst = {};
+
+ for ( var u in uniforms_src ) {
+
+ uniforms_dst[ u ] = {};
+
+ for ( var p in uniforms_src[ u ] ) {
+
+ var parameter_src = uniforms_src[ u ][ p ];
+
+ if ( parameter_src && ( parameter_src.isColor ||
+ parameter_src.isMatrix3 || parameter_src.isMatrix4 ||
+ parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||
+ parameter_src.isTexture ) ) {
+
+ uniforms_dst[ u ][ p ] = parameter_src.clone();
+
+ } else if ( Array.isArray( parameter_src ) ) {
+
+ uniforms_dst[ u ][ p ] = parameter_src.slice();
+
+ } else {
+
+ uniforms_dst[ u ][ p ] = parameter_src;
+
+ }
+
+ }
+
+ }
+
+ return uniforms_dst;
+
+ }
+
+ };
+
+ var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";
+
+ var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";
+
+ var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";
+
+ var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n";
+
+ var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
+
+ var begin_vertex = "\nvec3 transformed = vec3( position );\n";
+
+ var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";
+
+ var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t\t}\n\t\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 ltcTextureCoords( const in GeometricContext geometry, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = (LUT_SIZE - 1.0)/LUT_SIZE;\n\tconst float LUT_BIAS = 0.5/LUT_SIZE;\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nvoid clipQuadToHorizon( inout vec3 L[5], out int n ) {\n\tint config = 0;\n\tif ( L[0].z > 0.0 ) config += 1;\n\tif ( L[1].z > 0.0 ) config += 2;\n\tif ( L[2].z > 0.0 ) config += 4;\n\tif ( L[3].z > 0.0 ) config += 8;\n\tn = 0;\n\tif ( config == 0 ) {\n\t} else if ( config == 1 ) {\n\t\tn = 3;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 2 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 3 ) {\n\t\tn = 4;\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t\tL[3] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 4 ) {\n\t\tn = 3;\n\t\tL[0] = -L[3].z * L[2] + L[2].z * L[3];\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t} else if ( config == 5 ) {\n\t\tn = 0;\n\t} else if ( config == 6 ) {\n\t\tn = 4;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 7 ) {\n\t\tn = 5;\n\t\tL[4] = -L[3].z * L[0] + L[0].z * L[3];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 8 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[1] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = L[3];\n\t} else if ( config == 9 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[2].z * L[3] + L[3].z * L[2];\n\t} else if ( config == 10 ) {\n\t\tn = 0;\n\t} else if ( config == 11 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 12 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t} else if ( config == 13 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = L[2];\n\t\tL[2] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t} else if ( config == 14 ) {\n\t\tn = 5;\n\t\tL[4] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t} else if ( config == 15 ) {\n\t\tn = 4;\n\t}\n\tif ( n == 3 )\n\t\tL[3] = L[0];\n\tif ( n == 4 )\n\t\tL[4] = L[0];\n}\nfloat integrateLtcBrdfOverRectEdge( vec3 v1, vec3 v2 ) {\n\tfloat cosTheta = dot( v1, v2 );\n\tfloat theta = acos( cosTheta );\n\tfloat res = cross( v1, v2 ).z * ( ( theta > 0.001 ) ? theta / sin( theta ) : 1.0 );\n\treturn res;\n}\nvoid initRectPoints( const in vec3 pos, const in vec3 halfWidth, const in vec3 halfHeight, out vec3 rectPoints[4] ) {\n\trectPoints[0] = pos - halfWidth - halfHeight;\n\trectPoints[1] = pos + halfWidth - halfHeight;\n\trectPoints[2] = pos + halfWidth + halfHeight;\n\trectPoints[3] = pos - halfWidth + halfHeight;\n}\nvec3 integrateLtcBrdfOverRect( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tvec3 T1, T2;\n\tT1 = normalize(V - N * dot( V, N ));\n\tT2 = - cross( N, T1 );\n\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\n\tvec3 clippedRect[5];\n\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\n\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\n\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\n\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\n\tint n;\n\tclipQuadToHorizon(clippedRect, n);\n\tif ( n == 0 )\n\t\treturn vec3( 0, 0, 0 );\n\tclippedRect[0] = normalize( clippedRect[0] );\n\tclippedRect[1] = normalize( clippedRect[1] );\n\tclippedRect[2] = normalize( clippedRect[2] );\n\tclippedRect[3] = normalize( clippedRect[3] );\n\tclippedRect[4] = normalize( clippedRect[4] );\n\tfloat sum = 0.0;\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[0], clippedRect[1] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[1], clippedRect[2] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[2], clippedRect[3] );\n\tif (n >= 4)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[3], clippedRect[4] );\n\tif (n == 5)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[4], clippedRect[0] );\n\tsum = max( 0.0, sum );\n\tvec3 Lo_i = vec3( sum, sum, sum );\n\treturn Lo_i;\n}\nvec3 Rect_Area_Light_Specular_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight,\n\t\tconst in float roughness,\n\t\tconst in sampler2D ltcMat, const in sampler2D ltcMag ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tvec2 uv = ltcTextureCoords( geometry, roughness );\n\tvec4 brdfLtcApproxParams, t;\n\tbrdfLtcApproxParams = texture2D( ltcMat, uv );\n\tt = texture2D( ltcMat, uv );\n\tfloat brdfLtcScalar = texture2D( ltcMag, uv ).a;\n\tmat3 brdfLtcApproxMat = mat3(\n\t\tvec3( 1, 0, t.y ),\n\t\tvec3( 0, t.z, 0 ),\n\t\tvec3( t.w, 0, t.x )\n\t);\n\tvec3 specularReflectance = integrateLtcBrdfOverRect( geometry, brdfLtcApproxMat, rectPoints );\n\tspecularReflectance *= brdfLtcScalar;\n\treturn specularReflectance;\n}\nvec3 Rect_Area_Light_Diffuse_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tmat3 diffuseBrdfMat = mat3(1);\n\tvec3 diffuseReflectance = integrateLtcBrdfOverRect( geometry, diffuseBrdfMat, rectPoints );\n\treturn diffuseReflectance;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n";
+
+ var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";
+
+ var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n";
+
+ var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n";
+
+ var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";
+
+ var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";
+
+ var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
+
+ var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";
+
+ var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
+
+ var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";
+
+ var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n";
+
+ var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n";
+
+ var defaultnormal_vertex = "#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n";
+
+ var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";
+
+ var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";
+
+ var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n";
+
+ var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";
+
+ var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n";
+
+ var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n return value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n float maxComponent = max( max( value.r, value.g ), value.b );\n float fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n return vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n return vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n float maxRGB = max( value.x, max( value.g, value.b ) );\n float M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n M = ceil( M * 255.0 ) / 255.0;\n return vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n float maxRGB = max( value.x, max( value.g, value.b ) );\n float D = max( maxRange / maxRGB, 1.0 );\n D = min( floor( D ) / 255.0, 1.0 );\n return vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n vec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n Xp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n vec4 vResult;\n vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n vResult.w = fract(Le);\n vResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n return vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n float Le = value.z * 255.0 + value.w;\n vec3 Xp_Y_XYZp;\n Xp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n vec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n return vec4( max(vRGB, 0.0), 1.0 );\n}\n";
+
+ var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n";
+
+ var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";
+
+ var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n";
+
+ var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n";
+
+ var fog_fragment = "#ifdef USE_FOG\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\t#else\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\t#endif\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n";
+
+ var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif";
+
+ var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n";
+
+ var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";
+
+ var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
+
+ var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n";
+
+ var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n";
+
+ var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";
+
+ var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\n#if NUM_RECT_AREA_LIGHTS > 0\n void RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n vec3 matDiffColor = material.diffuseColor;\n vec3 matSpecColor = material.specularColor;\n vec3 lightColor = rectAreaLight.color;\n float roughness = BlinnExponentToGGXRoughness( material.specularShininess );\n vec3 spec = Rect_Area_Light_Specular_Reflectance(\n geometry,\n rectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n roughness,\n ltcMat, ltcMag );\n vec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n geometry,\n rectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n reflectedLight.directSpecular += lightColor * matSpecColor * spec / PI2;\n reflectedLight.directDiffuse += lightColor * matDiffColor * diff / PI2;\n }\n#endif\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n";
+
+ var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n";
+
+ var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n vec3 matDiffColor = material.diffuseColor;\n vec3 matSpecColor = material.specularColor;\n vec3 lightColor = rectAreaLight.color;\n float roughness = material.specularRoughness;\n vec3 spec = Rect_Area_Light_Specular_Reflectance(\n geometry,\n rectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n roughness,\n ltcMat, ltcMag );\n vec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n geometry,\n rectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n reflectedLight.directSpecular += lightColor * matSpecColor * spec;\n reflectedLight.directDiffuse += lightColor * matDiffColor * diff;\n }\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n";
+
+ var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t \tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\t\t\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";
+
+ var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif";
+
+ var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n";
+
+ var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif";
+
+ var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n";
+
+ var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";
+
+ var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";
+
+ var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n";
+
+ var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n";
+
+ var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.r;\n#endif\n";
+
+ var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
+
+ var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n";
+
+ var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
+
+ var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n";
+
+ var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n";
+
+ var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal ) * flipNormal;\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";
+
+ var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";
+
+ var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n return normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n return 1.0 - 2.0 * rgb.xyz;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n return ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n return linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n return (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n return ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n";
+
+ var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";
+
+ var project_vertex = "#ifdef USE_SKINNING\n\tvec4 mvPosition = modelViewMatrix * skinned;\n#else\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;\n";
+
+ var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.r;\n#endif\n";
+
+ var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
+
+ var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n #if NUM_RECT_AREA_LIGHTS > 0\n #endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn 1.0;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n";
+
+ var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n #if NUM_RECT_AREA_LIGHTS > 0\n #endif\n#endif\n";
+
+ var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n #if NUM_RECT_AREA_LIGHTS > 0\n #endif\n#endif\n";
+
+ var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_RECT_AREA_LIGHTS > 0\n\t#endif\n\t#endif\n\treturn shadow;\n}\n";
+
+ var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
+
+ var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n";
+
+ var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n#endif\n";
+
+ var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n";
+
+ var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
+
+ var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
+
+ var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";
+
+ var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n return toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n color *= toneMappingExposure;\n return saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n color *= toneMappingExposure;\n return saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n color *= toneMappingExposure;\n color = max( vec3( 0.0 ), color - 0.004 );\n return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n";
+
+ var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif";
+
+ var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n";
+
+ var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif";
+
+ var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
+
+ var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";
+
+ var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";
+
+ var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\t#ifdef USE_SKINNING\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\t#else\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\t#endif\n#endif\n";
+
+ var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n";
+
+ var cube_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n";
+
+ var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";
+
+ var depth_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
+
+ var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include \n#include \n#include \nvoid main () {\n\t#include \n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n";
+
+ var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition;\n}\n";
+
+ var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n";
+
+ var equirect_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n";
+
+ var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
+
+ var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n}\n";
+
+ var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
+
+ var meshbasic_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
+
+ var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
+
+ var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
+
+ var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n";
+
+ var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include