diff --git a/build.js b/build.js index 76ac634..0133545 100644 --- a/build.js +++ b/build.js @@ -1,16 +1,29 @@ +// # Build script using Node.js +// +// Single script build,used as a lightweight alternative +// when a build platform (grunt/gulp wtc.) feels like overkill +// +// - Dependencies: NPM/Node.js +// - Conventions: +// * code is in a lib/ folder with a main.js as the main context (closure) +// * a package.json on the root contains all the info about the lib: name, description, author, license +// * compiled files are saved in a build folder + // settings var FILE_ENCODING = 'utf-8', EOL = '\n'; // Dependencies -var _cli = require('commander'), - _uglify = require("uglify-js"), - _jshint = require('jshint'), - _handlebars = require('hbs'), - _fs = require('fs'); - -// will generate a CSV if package.json contains multiple licenses -_handlebars.registerHelper('license', function(items){ +var cli = require('commander'), + uglify = require("uglify-js"), + jshint = require('jshint'), + handlebars = require('hbs'), + fs = require('fs'), + zlib = require('zlib'); + + +// will generate a CSV if package info contains multiple licenses +handlebars.registerHelper('license', function(items){ items = items.map(function(val){ return val.type; }); @@ -18,37 +31,44 @@ _handlebars.registerHelper('license', function(items){ }); - // Logic - // - concatinate all files +// Logic +// - read module name from package file +var package = JSON.parse( fs.readFileSync('package.json', FILE_ENCODING) ); // condition the existance of package.json or component.json... +var name = package.name; +// - list files in the lib folder +//var src = libFiles(); +// - concatinate all files +var src = [ + 'lib/core.js', + 'lib/attributes.js', + 'lib/css.js', + 'lib/animations.js', + 'lib/effects.js', + 'lib/events.js', + 'lib/manipulation.js', + 'lib/markup.js', + 'lib/selectors.js', + 'lib/terrain.js', + 'lib/webgl.js', + 'lib/utils.js' +]; + +// - concatinate all files concat({ - src : [ - 'lib/_start.js', - 'lib/core.js', - 'lib/attributes.js', - 'lib/css.js', - 'lib/effects.js', - 'lib/events.js', - 'lib/manipulation.js', - 'lib/markup.js', - 'lib/selectors.js', - 'lib/webgl.js', - 'lib/utils.js', - 'lib/_end.js' - ], - dest : 'build/jquery.three.js' + src: src, + dest: 'build/'+ name +'.js' }); // - Validate js -lint('build/jquery.three.js', function(){ +lint('build/'+ name +'.js', function(){ // - Create / save minified file - uglify('build/jquery.three.js', 'build/jquery.three-min.js'); + minify('build/'+ name +'.js', 'build/'+ name +'-min.js'); }); - // // Methods function concat(opts) { @@ -56,56 +76,71 @@ function concat(opts) { var distPath = opts.dest; var lib = fileList.map(function(filePath){ - return _fs.readFileSync(filePath, FILE_ENCODING); + return fs.readFileSync(filePath, FILE_ENCODING); }); - var template = _handlebars.compile( lib.join(EOL) ); + var wrapper = fs.readFileSync('lib/main.js', FILE_ENCODING); + + var template = handlebars.compile( wrapper ); //reuse package.json data and add build date - var data = JSON.parse( _fs.readFileSync('package.json', FILE_ENCODING) ); + var data = package; + data.lib = lib.join(EOL); data.build_date = (new Date()).toUTCString(); // Save uncompressed file - _fs.writeFileSync(distPath, template(data), FILE_ENCODING); + fs.writeFileSync(distPath, template(data), FILE_ENCODING); console.log(' '+ distPath +' built.'); } -function uglify(srcPath, distPath) { +function minify(srcPath, distPath) { /* var jsp = uglyfyJS.parser, pro = uglyfyJS.uglify, - ast = jsp.parse( _fs.readFileSync(srcPath, FILE_ENCODING) ); + ast = jsp.parse( fs.readFileSync(srcPath, FILE_ENCODING) ); ast = pro.ast_mangle(ast); ast = pro.ast_squeeze(ast); */ - var result = _uglify.minify(srcPath, { compressor: { - comments : true - } }); + var result = uglify.minify(srcPath, { + mangle: true, + output: { + comments : /@name|@author|@cc_on|@url|@license/ + } + }); - _fs.writeFileSync(distPath, result.code, FILE_ENCODING); + fs.writeFileSync(distPath, result.code, FILE_ENCODING); console.log(' '+ distPath +' built.'); + return; + + // gzip + zlib.gzip(result.code, function (error, bytes) { + if (error) throw error; + fs.writeFileSync(distPath, bytes, FILE_ENCODING); + console.log(' '+ distPath +' built.'); + }); + } function lint(path, callback) { - var buf = _fs.readFileSync(path, 'utf-8'); + var buf = fs.readFileSync(path, 'utf-8'); // remove Byte Order Mark buf = buf.replace(/^\uFEFF/, ''); - _jshint.JSHINT(buf); + jshint.JSHINT(buf); - var nErrors = _jshint.JSHINT.errors.length; + var nErrors = jshint.JSHINT.errors.length; if (nErrors) { // ruff output of errors (for now) - console.log(_jshint.JSHINT.errors); + console.log(jshint.JSHINT.errors); console.log(' Found %j lint errors on %s, do you want to continue?', nErrors, path); - _cli.choose(['no', 'yes'], function(i){ + cli.choose(['no', 'yes'], function(i){ if (i) { process.stdin.destroy(); if(callback) callback(); @@ -117,3 +152,16 @@ function lint(path, callback) { callback(); } } + +function libFiles(){ + var src = []; + var files = fs.readdirSync( "lib/" ); + // folter only javascript files + for( var i in files ){ + var file = files[i]; + // exclude certain files and main.js + if( file.substr(0, 1) == "." || file.substr(-3) !== ".js" || file == "main.js" ) continue; + src.push( "lib/"+ file ); + } + return src; +} diff --git a/build/jquery.three-min.js b/build/jquery.three-min.js index 022b4ef..13e8df7 100644 --- a/build/jquery.three-min.js +++ b/build/jquery.three-min.js @@ -1 +1,14 @@ -window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1e3/60)}}(),function(e,t){"use strict";var r=r||!1,a=e.$||e.jQuery||e.ender;r&&"function"==typeof r&&r.amd?r(["jquery"],t):t(a)}(this,function(e){var t,r={self:function(){return this}},a={watch:!1,deps:{THREE:"https://raw.github.com/mrdoob/three.js/master/build/three.min.js"},paused:!1};Three=function(t,r,i){var n=this;this.el=this.setEl(t),this.options=e.extend(!0,{},a,r),this.objects={},this.scenes={},this.cameras={},this.materials={},this.groups={camera:"cameras",scene:"scenes",mesh:"objects",plane:"objects",cube:"objects",sphere:"objects",cylinder:"objects",material:"materials"},this.frame={current:0,rate:0,date:new Date},this.last=!1,this.parent=!1,this.dependencies(function(){n.init(),i instanceof Function&&i(n)})},Three.prototype={init:function(){var t=this;this.active={scene:!1,camera:!1,skybox:!1},this.properties=this.setProperties(),this.renderer=new THREE.WebGLRenderer,this.renderer.setSize(this.properties.width,this.properties.height),this.renderer.autoClear=!1,e(this.el).find(".fallback").remove();var r=e(this.el).html();e(this.el).html(""),this.parent=e(this.el).find("shadow-root"),this.target=this.parent,this.html(r),e(this.renderer.domElement).appendTo(this.el),window.addEventListener("resize",function(){t.resize()},!1),this.options.watch&&this.watch(this.parent),this.tick()},destroy:function(){return this.each(function(){var t=e(this);t.data("three"),t.removeData("three")})},self:function(t,r){var a=[];return this.each(function(){var i=e(this),n=i.data("three");n||(n=new Three(this,t,r),e(this).data("three",n)),a.push(n)}),1==a.length?a[0]:e(a)},tick:function(){var e=this;this.options.paused||this.render();var t=new Date;this.frame.date.getSeconds()===t.getSeconds()?this.frame.current++:(this.frame.rate=this.frame.current,this.frame.current=1,this.frame.date=t),requestAnimFrame(function(){e.tick()})},render:function(){e(this.el).trigger({type:"update",target:this}),this.active.scene&&this.active.camera&&(this.active.skybox&&(this.active.skybox.camera&&this.active.skybox.camera.rotation.copy(this.active.camera.rotation),this.renderer.render(this.active.skybox.scene,this.active.skybox.camera)),this.renderer.render(this.active.scene,this.active.camera))},show:function(){},hide:function(){},update:function(){},detect:function(){return{canvas:!!window.CanvasRenderingContext2D,webgl:function(){try{return!!window.WebGLRenderingContext&&!!document.createElement("canvas").getContext("experimental-webgl")}catch(e){return!1}}(),workers:!!window.Worker,fileapi:window.File&&window.FileReader&&window.FileList&&window.Blob,all:function(){return this.webgl&&this.canvas&&this.workers&&this.fileapi}}},resize:function(){this.properties=this.setProperties();for(var e in this.cameras)this.cameras[e].aspect=this.properties.aspect,this.cameras[e].updateProjectionMatrix();this.active.skybox&&(this.active.skybox.camera.aspect=this.properties.aspect,this.active.skybox.camera.updateProjectionMatrix()),this.renderer.setSize(this.properties.width,this.properties.height)},dependencies:function(t){var r=e.map(this.options.deps,function(e,t){return window[t]||window.THREE&&window.THREE[t]?void 0:e});r.length?this.loadScripts(r,t):t()},loadScripts:function(t,r){var a=this;e.when(e.getScript(t.shift())).done(function(){t.length>0?a.loadScripts(t,r):r()})},setEl:function(t){var r=e(this).attr("id");return("undefined"==typeof r||r===!1)&&e(t).addClass("3d-"+n.unid()),t}},e.fn.three=function(e,t){return e||(e=!1),t||(t=function(e){return e}),Three.prototype.self.apply(this,arguments,e,t)},Three.prototype.getAttributes=function(t){var r={};return e(t).each(function(){var e=this.attributes;for(var t in e)if(e[t].name&&0===e[t].name.search("data-")){var a=e[t].name.replace("data-","");a=n.camelCase(a);var i=e[t].value;r[a]=parseInt(i,10)||"0"===i?parseInt(i,10):i}else if(e[t].name&&0===e[t].name.search("class")){var s=e[t].value.split(" ");r["class"]=s}else e[t].name&&0===e[t].name.search("src")?r.src=e[t].value:e[t].name&&0===e[t].name.search("style")&&(r.style=e[t].value)}),r},Three.prototype.addClass=function(t){var r=this.last,a=e(this.el).find("[data-id='"+r.id+"']");a.addClass(t);var i=this.fn.css.styles.call(this,a);return this.fn.css.set.call(this,r,i),this},t=function(e){return this.fn.css.set.call(this,this.last,e),this},r.css={styles:function(t){var r=document.styleSheets,a={};for(var n in r){var s=r[n].rules||r[n].cssRules;for(var o in s)if(!(s[o].selectorText&&s[o].selectorText.search(":hover")>-1))try{t.is(s[o].selectorText)&&(a=e.extend(a,i(s[o].style)))}catch(c){console.log(c)}}return a=e.extend(a,i(t.attr("style")))},set:function(e,t){if(e&&e.id)for(var r in t){var a=r.replace("-webkit-","").replace("-moz-","");switch(a){case"width":e.scale.x=parseInt(t[r],10);break;case"height":e.scale.y=parseInt(t[r],10);break;case"top":e.position.y=parseInt(t[r],10);break;case"left":e.position.x=parseInt(t[r],10);break;case"color":var i=this.colorToHex(t[r]);e instanceof THREE.Scene?this.webglLight({color:i}):e.material.color.setHex(i);break;case"transform":var n;t[r].search("translate3d")>-1&&(n=this.fn.css.translate.call(this,t[r]),e instanceof THREE.Mesh&&"terrain"!=e.type?e.parent.position.set(n.x,n.y,n.z):e.position.set(n.x,n.y,n.z)),t[r].search("rotate3d")>-1&&(n=this.fn.css.rotate.call(this,t[r]),e instanceof THREE.Mesh&&"terrain"!=e.type?e.parent.rotation.set(n.x,n.y,n.z):e.rotation.set(n.x,n.y,n.z)),t[r].search("scale3d")>-1&&(n=this.fn.css.scale.call(this,t[r]),e instanceof THREE.Mesh&&"terrain"!=e.type?e.parent.scale.set(n.x,n.y,n.z):e.scale.set(n.x,n.y,n.z));break;case"animation-duration":console.log(a,t[r]);break;case"animation-timing":console.log(a,t[r]);break;case"animation-delay":console.log(a,t[r]);break;case"animation-iteration-count":console.log(a,t[r]);break;case"animation-direction":console.log(a,t[r]);break;case"animation-fill-mode":console.log(a,t[r]);break;case"animation-name":console.log(a,t[r]);break;case"display":break;case"background-image":if(e instanceof THREE.Scene)this.fn.css.skybox.call(this,t[r]);else if("terrain"==e.type)this.fn.css.terrain.call(this,t[r]);else if(e instanceof THREE.Mesh)this.fn.css.texture.call(this,e,t[r]);else if(e instanceof THREE.Object3D&&e.children.length)try{var s=e.children[0];this.fn.css.texture.call(this,s,t[r])}catch(o){console.log(o)}}}},rotate:function(e){var t,r={};return e.search("rotate3d")>-1&&(t=e.match(/rotate3d\(([\s\S]*?)\)/gi),t=t[0].replace(/rotate3d\(|deg|\)| /gi,"").split(","),r={x:parseFloat(t[0],10)*parseFloat(t[3],10)*(Math.PI/180),y:parseFloat(t[1],10)*parseFloat(t[3],10)*(Math.PI/180),z:parseFloat(t[2],10)*parseFloat(t[3],10)*(Math.PI/180)}),r},translate:function(e){var t={};if(e.search("translate3d")>-1){var r=e.match(/translate3d\(([\s\S]*?)\)/gi);r=r[0].replace(/translate3d\(|px|\)| /gi,"").split(","),t={x:parseFloat(r[0],10)||0,y:parseFloat(r[1],10)||0,z:parseFloat(r[2],10)||0}}return t},scale:function(e){var t={};if(e.search("scale3d")>-1){var r=e.match(/scale3d\(([\s\S]*?)\)/gi);r=r[0].replace(/scale3d\(|\)| /gi,"").split(","),t={x:parseFloat(r[0],10)||0,y:parseFloat(r[1],10)||0,z:parseFloat(r[2],10)||0}}return t},texture:function(e,t){var r=t.replace(/\s|url\(|\)/g,""),a=this.webglMaterial({map:r});e.material=a},terrain:function(e){var t=this.last,r=e.replace(/\s|url\(|\)/g,"").split(",");if(r instanceof Array)for(var a in r){if(r[a].search("heightmap")>-1){var i=THREE.ImageUtils.loadTexture(r[a]);t.material.uniforms.tDisplacement.value=i,t.material.uniforms.uDisplacementScale.value=375;var n=i;n.wrapS=n.wrapT=THREE.RepeatWrapping,t.material.uniforms.tDiffuse2.value=n,t.material.uniforms.enableDiffuse2.value=!0}if(r[a].search("diffuse")>-1){var s=THREE.ImageUtils.loadTexture(r[a]);s.wrapS=s.wrapT=THREE.RepeatWrapping,t.material.uniforms.tDiffuse1.value=s,t.material.uniforms.enableDiffuse1.value=!0}if(r[a].search("specular")>-1){var o=THREE.ImageUtils.loadTexture(r[a]);o.wrapS=o.wrapT=THREE.RepeatWrapping,t.material.uniforms.tSpecular.value=o,t.material.uniforms.enableSpecular.value=!0}}},skybox:function(e){var t=e.replace(/\s|url\(|\)/g,"").split(",");t instanceof Array&&this.addSkybox(t)}};var i=function(e){var t={};if(!e)return t;if(e instanceof CSSStyleDeclaration)for(var r in e)e[r].toLowerCase&&(t[e[r].toLowerCase()]=e[e[r]]);else if("string"==typeof e){e=e.split("; ");for(var a in e){var i=e[a].split(": ");t[i[0].toLowerCase()]=i[1]}}return t};Three.prototype.animate=function(){},Three.prototype.watch=function(t){var r=this,a=e(this.el).toSelector()+" "+e(t).selector;e("body").on("DOMSubtreeModified",a,function(e){r.eventSubtree(e)}),t.onpropertychange?e("body").on("propertychange",a,function(e){r.eventAttribute(e)}):e("body").on("DOMAttrModified",a,function(e){r.eventAttribute(e)})},Three.prototype.eventSubtree=function(t){t.stopPropagation();var r=e(e(this.el).toSelector()+" shadow-root").get(0),a=e(t.target).get(0);if(this.parent=r==a?e(t.target):e(t.target).parent(),this.target=e(t.target),t.target.innerHTML.length>0){var i=e(t.target).html();this.append(i,{silent:!0,target:this.target,traverse:!1,watch:!0})}},Three.prototype.eventAttribute=function(e){e.stopPropagation(),console.log("attribute",e.target)},Three.prototype.add=function(e,t){var r=this;return t=t||{},"undefined"==typeof e||"undefined"==typeof e.type?this:(this.webgl(e,function(a){if(!a||"undefined"==typeof a)return this;var i;r.last=a;var n=r.groups[e.type]||!1;"objects"==n&&a instanceof THREE.Mesh?(i=new THREE.Object3D,i.add(a),i.name=a.name):i=a,r.active[e.type]=i,n&&(r[n][i.id]=i),"scene"==e.type?r.active.scene=i:r.active.scene&&r.active.scene.add(i),e["data-id"]=i.id||!1;var s;t.silent&&e.el?(s=e.el,s.attr("data-id",e["data-id"])):(s=r.createHTML(e),r.target=s);var o=r.fn.css.styles.call(r,s);r.fn.css.set.call(r,a,o)}),this)},Three.prototype.addScene=function(e){var t=e||{};return t.type="scene",this.add(t),this},Three.prototype.addCamera=function(e){var t=e||{};return t.type="camera",this.add(t),this},Three.prototype.addMesh=function(e){var t=e||{};return t.type="mesh",this.add(t),this},Three.prototype.addPlane=function(e){var t=e||{};return t.type="plane",this.add(t),this},Three.prototype.addSphere=function(e){var t=e||{};return t.type="sphere",this.add(t),this},Three.prototype.addCube=function(e){var t=e||{};return t.type="cube",this.add(t),this},Three.prototype.addCylinder=function(e){var t=e||{};return t.type="cylinder",this.add(t),this},Three.prototype.addAsset=function(e){var t=e||{};return t.type="asset",this.add(t),this},Three.prototype.addSkybox=function(t){var r=new THREE.PerspectiveCamera(50,e(this.el).width()/e(this.el).height(),1,100),a=new THREE.Scene,i=THREE.ImageUtils.loadTextureCube(t);i.format=THREE.RGBFormat;var n=THREE.ShaderLib.cube,s=THREE.UniformsUtils.clone(n.uniforms);s.tCube.value=i;var o=new THREE.ShaderMaterial({fragmentShader:n.fragmentShader,vertexShader:n.vertexShader,uniforms:s,depthWrite:!1,side:THREE.BackSide}),c=new THREE.Mesh(new THREE.CubeGeometry(100,100,100),o);a.add(c),this.active.skybox={scene:a,camera:r}},Three.prototype.addTerrain=function(e){var t=e||{};return t.type="terrain",this.add(t),this},Three.prototype.html=function(t,r){var a=this;return r=r||{},r.target=r.target||this.target,"undefined"==typeof r.traverse&&(r.traverse=!0),e(t).filter("*").each(function(t,i){var n="undefined"==typeof i?!1:e(i);if(n&&"undefined"==typeof n.attr("data-id")){var s={};s.type=i.nodeName.toLowerCase(),s.id=n.attr("id");var o=a.getAttributes(i);s=e.extend(s,o),s.el=r.target.children(":eq("+t+")"),(!r.watch||s.el.length)&&(a.add(s,r),""!==n.html()&&r.traverse&&a.html(n.html(),r))}}),this},Three.prototype.createHTML=function(t){var r=e("<"+t.type+">");if(t.id&&r.attr("id",t.id),t["data-id"]&&r.attr("data-id",t["data-id"]),t["class"]&&t["class"].length){var a=t["class"].join(" ");r.attr("class",a)}return t.style&&r.attr("style",t.style),r.appendTo(this.parent),("scene"==t.type||"asset"==t.type||"player"==t.type)&&(this.parent=r),r},Three.prototype.append=function(e,t){return t=t||{},this.html(e,t),this},Three.prototype.get=function(e){var t=this.objects[e]||this.cameras[e]||this.scenes[e]||null;return t},find=function(e){var t=this.fn.find.el.call(this,e);return this.last=t,this},r.find={el:function(t){var r=e(this.el).find("shadow-root "+t).attr("data-id"),a=this.objects[r]||this.cameras[r]||this.scenes[r]||null;return a}},r.three=function(e,t){var r=this.last;try{r[e](t)}catch(a){console.log("Method not supported:",a)}return this},Three.prototype.webgl=function(e,t){var r;switch(e.type){case"scene":r=this.webglScene(e);break;case"camera":r=this.webglCamera(e);break;case"mesh":r=this.webglMesh(e);break;case"material":r=this.webglMaterial(e);break;case"light":r=this.webglLight(e);break;case"plane":r=this.webglPlane(e);break;case"sphere":r=this.webglSphere(e);break;case"cube":r=this.webglCube(e);break;case"cylinder":r=this.webglCylinder(e);break;case"terrain":r=this.webglTerrain(e);break;default:"undefined"!=typeof this.fn.webgl[e.type]&&this.fn.webgl[e.type].apply(this,[e,t])}return t(r)},r.webgl={},Three.prototype.webglScene=function(t){var r={id:!1};e.extend(r,t);var a=new THREE.Scene;return this.scenes[a.id]=a,a},Three.prototype.webglCamera=function(t){var r,a={fov:50,aspect:this.properties.aspect,near:1,far:1e3,scene:this.active.scene},i=e.extend(a,t);return i.orthographic||(r=new THREE.PerspectiveCamera(i.fov,i.aspect,i.near,i.far)),r},Three.prototype.webglMesh=function(t){var r,a={id:!1,wireframe:!1,scene:this.active.scene};return e.extend(a,t),r},Three.prototype.webglMaterial=function(t){var r,a,i={id:!1,color:0,wireframe:!1,map:!1,scene:this.active.scene},n=e.extend(i,t),s=window.Shaders||{};if(n.id&&s[n.id]){a={};var o=Shaders[n.id];o.uniforms&&(a.uniforms=THREE.UniformsUtils.clone(o.uniforms)),o.vertexShader&&(a.vertexShader=o.vertexShader),o.fragmentShader&&(a.fragmentShader=o.fragmentShader),n.map&&o.uniforms&&(a.uniforms.texture.texture=THREE.ImageUtils.loadTexture(n.map)),r=new THREE.ShaderMaterial(a)}else a={},n.map&&(a.map=THREE.ImageUtils.loadTexture(n.map)),n.color&&!n.map&&(a.color=n.color),n.wireframe&&(a.wireframe=n.wireframe),r=new THREE.MeshBasicMaterial(a);return r},Three.prototype.webglTexture=function(e){var t=new THREE.Texture,r=new THREE.ImageLoader;return r.addEventListener("load",function(e){t.image=e.content,t.needsUpdate=!0}),r.load(e),t},Three.prototype.webglLight=function(e){this.active.scene.add(new THREE.AmbientLight(parseInt(e.color,16)))},Three.prototype.webglPlane=function(t){var r={width:1,height:1,color:0,wireframe:!1,scene:this.active.scene},a=e.extend(r,t),i=new THREE.PlaneGeometry(a.width,a.height);i.dynamic=!0;var n=new THREE.MeshBasicMaterial({color:a.color,wireframe:a.wireframe}),s=new THREE.Mesh(i,n);return a.id&&(s.name=a.id),s},Three.prototype.webglSphere=function(t){var r={id:!1,radius:1,segments:16,rings:16,color:0,wireframe:!1,map:!1,scene:this.active.scene},a=e.extend(r,t),i=new THREE.SphereGeometry(a.radius,a.segments,a.rings);i.dynamic=!0;var n=this.webglMaterial(a),s=new THREE.Mesh(i,n);return s.matrixAutoUpdate=!1,a.id&&(s.name=a.id),s},Three.prototype.webglCube=function(t){var r={id:!1,width:1,height:1,depth:1,color:0,wireframe:!1,scene:this.active.scene},a=e.extend(r,t),i=new THREE.CubeGeometry(a.width,a.height,a.depth);i.dynamic=!0;var n=new THREE.MeshBasicMaterial({color:a.color,wireframe:a.wireframe}),s=new THREE.Mesh(i,n);return a.id&&(s.name=a.id),s},Three.prototype.webglCylinder=function(t){var r={id:!1,radiusTop:1,radiusBottom:1,segmentsRadius:4,segmentsHeight:16,openEnded:!1,color:0,wireframe:!1,scene:this.active.scene},a=e.extend(r,t),i=new THREE.CylinderGeometry(a.radiusTop,a.radiusBottom,a.segmentsRadius,a.segmentsHeight,a.openEnded,!1);i.dynamic=!0;var n=new THREE.MeshBasicMaterial({color:a.color,wireframe:a.wireframe}),s=new THREE.Mesh(i,n);return a.id&&(s.name=a.id),s},Three.prototype.webglTerrain=function(){var e;this.active.scene.add(new THREE.AmbientLight(1118481)),directionalLight=new THREE.DirectionalLight(16777215,1.15),directionalLight.position.set(500,2e3,0),this.active.scene.add(directionalLight);var t=new THREE.PlaneGeometry(6e3,6e3,256,256);t.computeFaceNormals(),t.computeVertexNormals(),t.computeTangents();var r=THREE.ShaderTerrain.terrain;uniformsTerrain=THREE.UniformsUtils.clone(r.uniforms),uniformsTerrain.uDiffuseColor.value.setHex(16777215),uniformsTerrain.uSpecularColor.value.setHex(16777215),uniformsTerrain.uAmbientColor.value.setHex(1118481),uniformsTerrain.uRepeatOverlay.value.set(6,6);var a=new THREE.ShaderMaterial({uniforms:uniformsTerrain,vertexShader:r.vertexShader,fragmentShader:r.fragmentShader,lights:!0,fog:!1});return e=new THREE.Mesh(t,a),e.type="terrain",this.active.scene.add(e),e},Three.prototype.colorToHex=function(e){if("#"===e.substr(0,1))return e.replace("#","0x");var t=/(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(e),r=parseInt(t[2],10).toString(16),a=parseInt(t[3],10).toString(16),i=parseInt(t[4],10).toString(16);return 1==r.length&&(r="0"+r),1==a.length&&(a="0"+a),1==i.length&&(i="0"+i),"0x"+r+a+i},Three.prototype.setProperties=function(){return{width:e(this.el).width(),height:e(this.el).height(),aspect:e(this.el).width()/e(this.el).height()}};var n={camelCase:function(e){return e.replace(/-([a-z])/g,function(e){return e[1].toUpperCase()})},unid:function(){return Math.round(Math.random()*(new Date).getTime())}};!function(e){e.fn.toSelector=function(){var t=e(this).get(0),r=t.tagName.toLowerCase(),a=e(this).attr("id"),i=t.className.split(/\s+/),n=r;return"undefined"!=typeof a&&(n+="#"+a),"undefined"!=typeof i&&(n+="."+i.join(".")),n}}(jQuery),Three.prototype.css=t,Three.prototype.find=find,Three.prototype.fn=r,Three.prototype.lookAt=function(){return this.fn.three.call(this,"lookAt",arguments)}}); \ No newline at end of file +/** + * @name jquery.three + * jQuery Three() - jQuery extension with 3D methods (using Three.js) + * Version: 0.9.8 (Sun, 11 Dec 2016 13:05:25 GMT) + * + * @author makesites + * Created by: Makis Tracend (@tracend) + * + * Homepage: http://github.com/makesites/jquery-three + * @license MIT License + */ +window.requestAnimFrame=function(e){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1e3/60)}}(),function(e,t){var a=e.$||e.jQuery||e.ender;"function"==typeof define&&define.amd?define(["jquery"],t):t(a)}(this,function(e){function t(e,t){if(e=e||{},e.material)if(e.material.materials)for(var a in e.material.materials)e.material.materials[a].color.setHex(t);else e.material.color.setHex(t)}function a(){for(var e in this._animations){var t=this._animations[e],a=t.keyframes;t.start=t.start||u.now(),t.end=t.end||t.start+t.duration,t.offset=t.offset||r(this),t.count=t.count||0;var i=u.now(),n=(i-t.start)/t.duration*100,s=!1,o=!1;for(var c in a)n>=c&&(s=a[c]),c>n&&!o&&(o=a[c]);s||(s=a[0]),o||(o=a[100]);var h={x:"undefined"!=typeof s.rotation.x&&"undefined"!=typeof o.rotation.x?(o.rotation.x-s.rotation.x)*(n/100):0,y:"undefined"!=typeof s.rotation.y&&"undefined"!=typeof o.rotation.y?(o.rotation.y-s.rotation.y)*(n/100):0,z:"undefined"!=typeof s.rotation.z&&"undefined"!=typeof o.rotation.z?(o.rotation.z-s.rotation.z)*(n/100):0};if(this.rotation.set(t.offset.rotation.x+h.x,t.offset.rotation.y+h.y,t.offset.rotation.z+h.z),this instanceof THREE.Sprite){var l={x:this.material.map.offset.x,y:this.material.map.offset.y},d=t.easing,p=100/d,f=parseInt(n,10)%p===0?parseInt(n,10)/100:0;f&&(f-=1/d,"undefined"!=typeof t.keyframes[0]["background-position"].x&&(l.x=(d-1)/d-f),"undefined"!=typeof t.keyframes[0]["background-position"].y&&(l.y=(d-1)/d-f),this.material.map.offset.set(l.x,l.y))}n>=100&&(delete t.start,delete t.end,delete t.offset,t.count++),t.count==t.repeat?delete this._animations[e]:this._animations[e]=t}}function r(e){return{position:{x:e.position.x,y:e.position.y,z:e.position.z},rotation:{x:e.rotation.x,y:e.rotation.y,z:e.rotation.z},scale:{x:e.scale.x,y:e.scale.y,z:e.scale.z}}}function i(e){for(var t=document.styleSheets,a=0;a"),this.parent=e(this.el).find("shadow-root"),this.target=this.parent,this.html(a),e(this.renderer.domElement).appendTo(this.el),window.addEventListener("resize",function(){t.resize()},!1),this.options.watch&&this.watch(this.parent),this.tick()},destroy:function(){return this.each(function(){var t=e(this);t.data("three");t.removeData("three")})},self:function(t,a){var r=[];return this.each(function(){var i=e(this),n=i.data("three");n||(n=new Three(this,t,a),e(this).data("three",n)),r.push(n)}),1==r.length?r[0]:e(r)},tick:function(){var e=this;this.options.paused||this.render();var t=new Date;this.frame.date.getSeconds()===t.getSeconds()?this.frame.current++:(this.frame.rate=this.frame.current,this.frame.current=1,this.frame.date=t),requestAnimFrame(function(){e.tick()})},render:function(){if(this.active.scene&&this.active.camera){if(this.active.skybox){var t=this.active.camera.far,a=this.active.skybox.scale;a.x!==t&&(a.x=a.y=a.z=t);var r=this.active.camera.position;this.active.skybox.position.set(r.x,r.y,r.z)}this.renderer.render(this.active.scene,this.active.camera)}this.fn.animate.update(),e(this.el).trigger({type:"update",target:this})},show:function(){},hide:function(){},update:function(e){},detect:function(){return{canvas:!!window.CanvasRenderingContext2D,webgl:function(){try{return!!window.WebGLRenderingContext&&!!document.createElement("canvas").getContext("experimental-webgl")}catch(e){return!1}}(),workers:!!window.Worker,fileapi:window.File&&window.FileReader&&window.FileList&&window.Blob,all:function(){return this.webgl&&this.canvas&&this.workers&&this.fileapi}}},resize:function(){this.properties=this.setProperties();for(var e in this.cameras)this.cameras[e].aspect=this.properties.aspect,this.cameras[e].updateProjectionMatrix();this.renderer.setSize(this.properties.width,this.properties.height)},dependencies:function(t){var a=e.map(this.options.deps,function(e,t){return window[t]||window.THREE&&window.THREE[t]?void 0:e});a.length?this.loadScripts(a,t):t()},loadScripts:function(t,a){var r=this;e.when(e.getScript(t.shift())).done(function(){t.length>0?r.loadScripts(t,a):a()})},setEl:function(t){var a=e(this).attr("id");return"undefined"!=typeof a&&a!==!1||e(t).addClass("3d-"+u.unid()),t}},e.fn.three=function(e,t){e||(e=!1),t||(t=function(e){return e});return Three.prototype.self.apply(this,arguments,e,t)},Three.prototype.getAttributes=function(t){var a={};return e(t).each(function(){var e=this.attributes;for(var t in e)if(e[t].name&&0===e[t].name.search("data-")){var r=e[t].name.replace("data-","");r=u.camelCase(r);var i=e[t].value;a[r]=parseInt(i,10)||"0"===i?parseInt(i,10):i,"false"!==a[r]&&"true"!==a[r]||(a[r]=JSON.parse(a[r]))}else if(e[t].name&&0===e[t].name.search("class")){var n=e[t].value.split(" ");a["class"]=n}else e[t].name&&0===e[t].name.search("src")?a.src=e[t].value:e[t].name&&0===e[t].name.search("style")&&(a.style=e[t].value)}),a},Three.prototype.addClass=function(t){var a=this.last,r=e(this.el).find("[data-id='"+a.id+"']");r.addClass(t);var i=this.fn.css.styles.call(this,r);return this.fn.css.set.call(this,a,i),this},n=function(e){return this.fn.css.set.call(this,this.last,e),this},c.css={styles:function(t){var a=document.styleSheets,r={};for(var i in a){var n=a[i],s=n.href&&0!==n.href.indexOf("/")&&0!==n.href.indexOf(o);if(!s&&null!==n.cssRules){var c=n.cssRules||n.rules;for(var h in c)if(!(c[h].selectorText&&c[h].selectorText.search(":hover")>-1||c[h].selectorText&&c[h].selectorText.search("::before")>-1||c[h].selectorText&&c[h].selectorText.search("::after")>-1))try{t.is(c[h].selectorText)&&(r=e.extend(r,l(c[h].style)))}catch(d){console.log(d)}}}return r=e.extend(r,l(t.attr("style")))},set:function(e,a){if(e&&e.id)for(var r in a){var i=r.replace("-webkit-","").replace("-moz-","");e._style=e._style||{},e._shaders=e._shaders||{};var n=!e._style[i]||e._style[i]!=a[r];if(e._style[i]=a[r],n)switch(i){case"width":e.scale.x=parseInt(a[r],10);break;case"height":e.scale.y=parseInt(a[r],10);break;case"top":e.position.y=parseInt(a[r],10);break;case"left":e.position.x=parseInt(a[r],10);break;case"color":var s=this.colorToHex(a[r]);e instanceof THREE.Scene?this.webglLight({color:s}):t(e,s);break;case"transform":var o;a[r].search("translate3d")>-1&&(o=this.fn.css.translate.call(this,a[r]),e instanceof THREE.Mesh&&"terrain"!=e.type?e.parent.position.set(o.x,o.y,o.z):e.position.set(o.x,o.y,o.z)),a[r].search("rotate3d")>-1&&(o=this.fn.css.rotate.call(this,a[r]),e instanceof THREE.Mesh&&"terrain"!=e.type?e.parent.rotation.set(o.x,o.y,o.z):e.rotation.set(o.x,o.y,o.z)),a[r].search("scale3d")>-1&&(o=this.fn.css.scale.call(this,a[r]),e instanceof THREE.Mesh&&"terrain"!=e.type?e.parent.scale.set(o.x,o.y,o.z):e.scale.set(o.x,o.y,o.z));break;case"animation-duration":this.fn.css.animation.duration=1e3*parseInt(a[r],10);break;case"animation-timing":this.fn.css.animation.easing=a[r];break;case"animation-delay":this.fn.css.animation.delay=a[r];break;case"animation-iteration-count":this.fn.css.animation.repeat=a[r];break;case"animation-direction":this.fn.css.animation.direction=a[r];break;case"animation-fill-mode":this.fn.css.animation.fill=a[r];break;case"animation-name":this.fn.css.animation.name=a[r],this.animate(this.fn.css.animation,e),this.fn.css.animation={};break;case"animation-timing-function":var c=a[r].match(/steps\((\d)/);this.fn.css.animation.easing=c?parseInt(c[1],10):a[r];break;case"animation-play-state":this.fn.css.animation.state=a[r];break;case"display":break;case"background-image":if(e instanceof THREE.Scene)this.fn.css.skybox.call(this,a[r]);else if("terrain"==e.type)this.fn.css.terrain.call(this,a[r]);else if(e instanceof THREE.Mesh)this.fn.css.texture.call(this,e,a[r]);else if(e instanceof THREE.Object3D&&e.children.length)try{var h=e.children[0];this.fn.css.texture.call(this,h,a[r])}catch(l){console.log(l)}else if(e instanceof THREE.Sprite){var d=a[r].replace(/\s|url\(|"|'|\)/g,"");e.material.map=u.textureLoader(d)}break;case"background-size":e instanceof THREE.Sprite&&this.fn.css.sprite.call(this,e,a[r]);break;case"background-position-x":e instanceof THREE.Sprite&&this.fn.css.sprite.call(this,e);break;case"background-position-y":e instanceof THREE.Sprite&&this.fn.css.sprite.call(this,e);break;case"filter":var p,f;e instanceof THREE.Mesh&&e.parent instanceof THREE.Object3D?(p=e.parent,f=e.parent.$el):(p=e,f=e.$el);var m=a[r].replace(/url\(|"|'|\)/g,"").split("|");if(!m.length)break;p._shaders=p._shaders||{};for(var g in m){var v=m[g].substring(m[g].lastIndexOf("/")+1);p._shaders[v]=u.getFile(m[g])}p.getShader=function(e){return this._shaders[e]||null},f.trigger("css-filter")}}},animation:{},rotate:function(e){var t,a={};return e.search("rotate3d")>-1?(t=e.match(/rotate3d\(([\s\S]*?)\)/gi),t=t[0].replace(/rotate3d\(|deg|\)| /gi,"").split(","),a={x:parseFloat(t[0],10)*parseFloat(t[3],10)*(Math.PI/180),y:parseFloat(t[1],10)*parseFloat(t[3],10)*(Math.PI/180),z:parseFloat(t[2],10)*parseFloat(t[3],10)*(Math.PI/180)}):e.search("rotateX")>-1?(t=e.match(/rotateX\(([\s\S]*?)\)/gi),t=t[0].replace(/rotateX\(|deg|\)| /gi,"").rot={x:parseFloat(t,10)*(Math.PI/180)}):e.search("rotateY")>-1?(t=e.match(/rotateY\(([\s\S]*?)\)/gi),t=t[0].replace(/rotateY\(|deg|\)| /gi,""),a={y:parseFloat(t,10)*(Math.PI/180)}):e.search("rotateZ")>-1?(t=e.match(/rotateZ\(([\s\S]*?)\)/gi),t=t[0].replace(/rotateZ\(|deg|\)| /gi,""),a={z:parseFloat(t,10)*(Math.PI/180)}):e.search("rotate")>-1&&(t=e.match(/rotate\(([\s\S]*?)\)/gi),t=t[0].replace(/rotate\(|deg|\)| /gi,""),a={z:parseFloat(t,10)*(Math.PI/180)}),a},translate:function(e){var t={};if(e.search("translate3d")>-1){var a=e.match(/translate3d\(([\s\S]*?)\)/gi);a=a[0].replace(/translate3d\(|px|\)| /gi,"").split(","),t={x:parseFloat(a[0],10)||0,y:parseFloat(a[1],10)||0,z:parseFloat(a[2],10)||0}}return t},scale:function(e){var t={};if(e.search("scale3d")>-1){var a=e.match(/scale3d\(([\s\S]*?)\)/gi);a=a[0].replace(/scale3d\(|\)| /gi,"").split(","),t={x:parseFloat(a[0],10)||0,y:parseFloat(a[1],10)||0,z:parseFloat(a[2],10)||0}}return t},texture:function(e,t){var a,r=t.replace(/\s|url\(|"|'|\)/g,"").split(",");if(r.length>1){var i={},n={},s=(new THREE.CubeTextureLoader).load(r);if(s.format=THREE.RGBFormat,i.tCube={type:"t",value:s},e._shaders)for(var o in e._shaders){var c=e._shaders[o];o.indexOf(".fs")>-1&&(n.fragmentShader=c),o.indexOf(".vs")>-1&&(n.vertexShader=c)}n.uniforms=i,n.needsUpdate=!0,a=new THREE.ShaderMaterial(n)}else a=this.webglMaterial({map:r[0]});e.material=a},terrain:function(e){var t=this.last,a=e.match(/url\(\s*[\'"]?(([^\\\\\'" \(\)]*(\\\\.)?)+)[\'"]?\s*\)/gim);if(a instanceof Array){var r,i,n;for(var s in a)a[s]=a[s].replace(/\s|url\(|"|'|\)/g,""),a[s].search("heightmap")>-1&&(r=t.updateTexture("heightmap",a[s])),a[s].search("diffuse")>-1&&(i=t.updateTexture("diffuse",a[s])),a[s].search("specular")>-1&&(n=t.updateTexture("specular",a[s]));!r&&a[0]&&t.updateTexture("heightmap",a[0]),!i&&a[1]&&t.updateTexture("diffuse",a[1]),!n&&a[2]&&t.updateTexture("specular",a[2])}else t.updateTexture("heightmap",a),t.updateTexture("diffuse",a)},skybox:function(e){var t=e.replace(/\s|url\(|"|'|\)/g,"").split(",");t instanceof Array&&this.addSkybox(t)},sprite:function(e,t){var a=setInterval(function(){if(e.material.map.image&&e.material.map.image.width){t=t||e._style["background-size"]||"0 0";var r=t.split(" "),i=parseFloat(r[0],10),n=parseFloat(r[1],10),s=parseFloat(e._style["background-position-x"]||0),o=parseFloat(e._style["background-position-y"]||0);if(i&&n){var c=e.material.map.image.width,h=e.material.map.image.height;e.material.map.offset.set((c-i-s)/c,(h-n-o)/h),e.material.map.repeat.set(i/c,n/h),clearInterval(a)}}},200)}};var l=function(e){var t={};if(!e)return t;if(e instanceof CSSStyleDeclaration)for(var a in e)e[a].toLowerCase&&(t[e[a].toLowerCase()]=e[e[a]]);else if("string"==typeof e){e=e.split("; ");for(var r in e){var i=e[r].split(": ");t[i[0].toLowerCase()]=i[1]}}return t};Three.prototype.animate=function(e,t){if(e=e||{},t=t||this.last||!1,t instanceof THREE.Mesh&&t.parent instanceof THREE.Object3D&&(t=t.parent),t&&e.name&&(t._animations=t._animations||{},t._update=t._update||a.bind(t),e.keyframes=this.fn.animate.getKeyframes.call(this,e.name),e.keyframes)){t._animations[e.name]=e;var r="undefined"!=typeof this.fn.animate.queue[t.uuid];r||(this.fn.animate.queue[t.uuid]=t._update)}},c.animate={queue:{},getKeyframes:function(e){var t={},a=i(e);if(a){for(var r in a.cssRules){var n=a.cssRules[r],s={};if(n.keyText){var o,c=parseInt(n.keyText,10);s.rotation=this.fn.css.rotate(n.cssText),s.translation=this.fn.css.translate(n.cssText),s.scale=this.fn.css.scale(n.cssText),n.cssText.search("background-position-x")>-1&&(s["background-position"]=s["background-position"]||{},o=n.cssText.match(/:[\d|\s|\w]+\;/),o&&(s["background-position"].x=parseFloat(o[0].substr(1),10))),n.cssText.search("background-position-y")>-1&&(s["background-position"]=s["background-position"]||{},o=n.cssText.match(/:[\d|\s|\w]+\;/),o&&(s["background-position"].y=parseFloat(o[0].substr(1),10))),t[c]=s}}return t}},update:function(e){for(var t in this.queue)this.queue[t]()}},Three.prototype.fx=function(){},Three.prototype.watch=function(t){function a(e){var t=e.target,a=e.attributeName,i=e.target.getAttribute(a);e.oldValue;if("style"==a){var n=r.objects[t.getAttribute("data-id")]||r.active.terrain,s=n.children[0]||n,o=l(i);r.last=s,r.fn.css.set.call(r,s,o)}}var r=this,i=e(t).selector||"shadow-root",n=(e(this.el).toSelector()+" "+i,document.getElementById("main").querySelector("shadow-root")),s=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,o={childList:!0,attributes:!0,subtree:!0,attributeOldValue:!0,attributeFilter:["class","style"]},c=new s(function(t){e.each(t,function(e,t){var a=t;"childList"===t.type?t.addedNodes.length>0?r.eventSubtree(a):t.removedNodes.length>0:"attributes"===t.type&&"class"===t.attributeName&&r.eventAttribute(a)})});c.observe(n,o);var h=new s(function(e){e.forEach(a)});h.observe(n,{childList:!1,attributes:!0,subtree:!0,attributeFilter:["class","style"]})},Three.prototype.eventSubtree=function(t){var a=e(e(this.el).toSelector()+" shadow-root").get(0),r=e(t.target).get(0);if(this.parent=a==r?e(t.target):e(t.target).parent(),this.target=e(t.target),0!==t.target.innerHTML.length){var i=e(t.target).html();this.append(i,{silent:!0,target:this.target,traverse:!1,watch:!0})}},Three.prototype.eventAttribute=function(e){console.log("attribute",e.target)},Three.prototype.add=function(e,t){var a=this;return t=t||{},"undefined"==typeof e||"undefined"==typeof e.type?this:(this.webgl(e,function(r){if(!r||"undefined"==typeof r)return this;var i;a.last=r;var n=a.groups[e.type]||!1;if("objects"==n&&r instanceof THREE.Mesh?(i=new THREE.Object3D,i.add(r),i.name=r.name):i=r,a.active[e.type]=i,e["data-id"]=i.id||!1,!e.el.data("id")){var s;t.silent&&e.el?(s=e.el,s.attr("data-id",e["data-id"])):(s=a.createHTML(e),a.target=s),i.$el=s;var o=a.fn.css.styles.call(a,s);a.fn.css.set.call(a,r,o),n&&(a[n][i.id]=i),"scene"==e.type?a.active.scene=i:a.active.scene&&a.active.scene.add(i)}}),this)},Three.prototype.addScene=function(e){var t=e||{};return t.type="scene",this.add(t),this},Three.prototype.addCamera=function(e){var t=e||{};return t.type="camera",this.add(t),this},Three.prototype.addMesh=function(e){var t=e||{};return t.type="mesh",this.add(t),this},Three.prototype.addPlane=function(e){var t=e||{};return t.type="plane",this.add(t),this},Three.prototype.addSphere=function(e){var t=e||{};return t.type="sphere",this.add(t),this},Three.prototype.addCube=function(e){var t=e||{};return t.type="cube",this.add(t),this},Three.prototype.addCylinder=function(e){var t=e||{};return t.type="cylinder",this.add(t),this},Three.prototype.addAsset=function(e){var t=e||{};return t.type="asset",this.add(t),this},Three.prototype.addSkybox=function(e){var t,a;if(1==e.length)t=new THREE.SphereGeometry(1,60,40),t.applyMatrix((new THREE.Matrix4).makeScale(-1,1,1)),a=new THREE.MeshBasicMaterial({map:u.textureLoader(e[0])});else{var r;if(THREE.REVISION<70)r=THREE.ImageUtils.loadTextureCube(e);else{var i=new THREE.CubeTextureLoader;r=i.load(e)}r.format=THREE.RGBFormat;var n=THREE.ShaderLib.cube,s=THREE.UniformsUtils.clone(n.uniforms);s.tCube.value=r,a=new THREE.ShaderMaterial({fragmentShader:n.fragmentShader,vertexShader:n.vertexShader,uniforms:s,depthWrite:!1,side:THREE.BackSide}),t=new THREE.BoxGeometry(1,1,1)}var o=new THREE.Mesh(t,a);this.active.scene.add(o),this.active.skybox=o},Three.prototype.addTerrain=function(e){var t=e||{};return t.type="terrain",this.add(t),this},Three.prototype.html=function(t,a){var r=this;return a=a||{},a.target=a.target||this.target,"undefined"==typeof a.traverse&&(a.traverse=!0),e(t).filter("*").each(function(t,i){var n="undefined"==typeof i?!1:e(i);if(n&&"undefined"==typeof n.attr("data-id")){var s={};s.type=i.nodeName.toLowerCase(),s.id=n.attr("id");var o=r.getAttributes(i);s=e.extend(s,o),s.el=a.target.children(":eq("+t+")"),a.watch&&!s.el.length||(r.add(s,a),""!==n.html()&&a.traverse&&r.html(n.html(),a))}}),this},Three.prototype.createHTML=function(t){var a=e("<"+t.type+">");if(t.id&&a.attr("id",t.id),t["data-id"]&&a.attr("data-id",t["data-id"]),t["class"]&&t["class"].length){var r=t["class"].join(" ");a.attr("class",r)}return t.style&&a.attr("style",t.style),a.appendTo(this.parent),"scene"!=t.type&&"asset"!=t.type&&"player"!=t.type||(this.parent=a),a},Three.prototype.append=function(e,t){return t=t||{},this.html(e,t),this},Three.prototype.get=function(e){var t=this.objects[e]||this.cameras[e]||this.scenes[e]||this.terrains[e]||null;return t},find=function(e){var t=this.fn.find.el.call(this,e);return this.last=t,this},c.find={el:function(t){var a=e(this.el).find("shadow-root "+t).attr("data-id"),r=this.objects[a]||this.cameras[a]||this.scenes[a]||this.terrains[a]||null;return r}},c.three=function(e,t){var a=this.last;try{a[e](t)}catch(r){console.log("Method not supported:",r)}return this};var d=function(e){this.options=e;var t=e.resolution,a=e.resolution,r=new THREE.PlaneBufferGeometry(e.width,e.height,t,a);r.computeFaceNormals(),r.computeVertexNormals(),u.computeTangents(r);var i=e.shader?this.shaderMaterial():this.basicMaterial(),n=new THREE.Mesh(r,i);return n.type="terrain",n._attributes=e,e.shader?n.updateTexture=this.shaderTexture.bind(n):(n.computeElevation=this.computeElevation.bind(n),n.updateTexture=this.basicTexture.bind(n)),this.terrain=n,this};d.prototype.shaderMaterial=function(){if(!THREE.ShaderTerrain)return console.log("THREE.ShaderTerrain not loaded. Use data-shader='false' to generate a poly terrain");var e=this.options,t=THREE.ShaderTerrain.terrain,a=THREE.UniformsUtils.clone(t.uniforms);THREE.REVISION<70?(a.uDiffuseColor.value.setHex(16777215),a.uSpecularColor.value.setHex(16777215),a.uAmbientColor.value.setHex(1118481)):(a.diffuse.value.setHex(16777215),a.specular.value.setHex(16777215)),a.uRepeatOverlay.value.set(e.repeat,e.repeat);var r=new THREE.ShaderMaterial({uniforms:a,vertexShader:t.vertexShader,fragmentShader:t.fragmentShader,lights:e.lights,fog:e.fog,needsUpdate:!0});return r},d.prototype.basicMaterial=function(){var e=new THREE.MeshBasicMaterial({map:u.pixel(),overdraw:.5});return e},d.prototype.computeElevation=function(e){if(!this._attributes.shader){var t=this,a=document.createElement("canvas"),r=a.getContext("2d"),i=e.image,n=t.geometry.parameters.widthSegments+1,s=t.geometry.parameters.heightSegments+1,o=t._attributes.scale,c=-t._attributes.scale/2,h=(t.geometry.parameters.width,t.geometry.attributes.position),l=[];a.width=n,a.height=s,r.drawImage(i,0,0,i.width,i.height,0,0,n,s);var d=r.getImageData(0,0,n,s).data;for(var u in d)if(!(u%4)){var p=d[u]/255*o+c;l.push(p),h.setZ(u/4,p)}t.geometry.attributes.position.needsUpdate=!0}},d.prototype.shaderTexture=function(e,t){var a=u.textureLoader(t);if("heightmap"==e){var r=this._attributes.scale;this.material.uniforms.tDisplacement.value=a,this.material.uniforms.uDisplacementScale.value=r,this.material.uniforms.uDisplacementBias.value=-r/2}return"diffuse"==e&&(a.wrapS=a.wrapT=THREE.RepeatWrapping,this.material.uniforms.tDiffuse1.value=a,this.material.uniforms.enableDiffuse1.value=!0),"specular"==e&&(this.material.uniforms.tSpecular.value=a,this.material.uniforms.enableSpecular.value=!0),a},d.prototype.basicTexture=function(e,t){var a;if("heightmap"==e){a=u.textureLoader(t,"heightmap-loaded");var r=this,i=function(e){r.computeElevation(a),r.$el.trigger("heightmap-updated")};document.removeEventListener("heightmap-loaded",i),document.addEventListener("heightmap-loaded",i,!1)}if("diffuse"==e){a=u.textureLoader(t);var n=this._attributes.repeat;a.wrapT=THREE.RepeatWrapping,a.wrapS=THREE.RepeatWrapping,a.repeat.set(n,n),a.needsUpdate=!0,this.material.map=a}return a},Three.prototype.webgl=function(e,t){var a;switch(e.type){case"scene":a=this.webglScene(e);break;case"camera":a=this.webglCamera(e);break;case"mesh":a=this.webglMesh(e);break;case"material":a=this.webglMaterial(e);break;case"light":a=this.webglLight(e);break;case"plane":a=this.webglPlane(e);break;case"sphere":a=this.webglSphere(e);break;case"cube":a=this.webglCube(e);break;case"cylinder":a=this.webglCylinder(e);break;case"sprite":a=this.webglSprite(e);break;case"terrain":a=this.webglTerrain(e);break;default:"undefined"!=typeof this.fn.webgl[e.type]&&this.fn.webgl[e.type].apply(this,[e,t])}return t(a)},c.webgl={},Three.prototype.webglScene=function(t){var a={id:!1},r=e.extend(a,t),i=new THREE.Scene;return this.scenes[i.id]=i,i._attributes=r,i},Three.prototype.webglCamera=function(t){var a,r={fov:50,aspect:this.properties.aspect,near:1,far:1e3,scene:this.active.scene},i=e.extend(r,t);return i.orthographic||(a=new THREE.PerspectiveCamera(i.fov,i.aspect,i.near,i.far)),a._attributes=i,a},Three.prototype.webglMesh=function(t){var a,r={id:!1,wireframe:!1,scene:this.active.scene};e.extend(r,t);return a},Three.prototype.webglMaterial=function(t){var a,r,i={id:!1,color:0,wireframe:!1,map:!1,scene:this.active.scene},n=e.extend(i,t),s=window.Shaders||{};if(n.id&&s[n.id]){r={};var o=Shaders[n.id];o.uniforms&&(r.uniforms=THREE.UniformsUtils.clone(o.uniforms)),o.vertexShader&&(r.vertexShader=o.vertexShader),o.fragmentShader&&(r.fragmentShader=o.fragmentShader),n.map&&o.uniforms&&(r.uniforms.texture.texture=u.textureLoader(n.map)),a=new THREE.ShaderMaterial(r)}else r={},n.map&&(r.map=u.textureLoader(n.map)),n.color&&!n.map&&(r.color=n.color),n.wireframe&&(r.wireframe=n.wireframe),a=new THREE.MeshBasicMaterial(r);return a},Three.prototype.webglTexture=function(e){var t=new THREE.Texture,a=new THREE.ImageLoader;return a.addEventListener("load",function(e){t.image=e.content,t.needsUpdate=!0}),a.load(e),t},Three.prototype.webglLight=function(e){this.active.scene.add(new THREE.AmbientLight(parseInt(e.color,16)))},Three.prototype.webglPlane=function(t){var a={width:1,height:1,color:0,wireframe:!1,scene:this.active.scene},r=e.extend(a,t),i=r.buffer?THREE.PlaneBufferGeometry:THREE.PlaneGeometry,n=new i(r.width,r.height);n.dynamic=!0;var s=new THREE.MeshBasicMaterial({color:r.color,wireframe:r.wireframe}),o=new THREE.Mesh(n,s);return r.id&&(o.name=r.id),o._attributes=r,o},Three.prototype.webglSphere=function(t){var a={id:!1,radius:1,segments:16,rings:16,color:0,wireframe:!1,map:!1,scene:this.active.scene},r=e.extend(a,t),i=new THREE.SphereGeometry(r.radius,r.segments,r.rings);i.dynamic=!0;var n=this.webglMaterial(r),s=new THREE.Mesh(i,n);return s.matrixAutoUpdate=!1,r.id&&(s.name=r.id),s._attributes=r,s},Three.prototype.webglCube=function(t){var a={id:!1,width:1,height:1,depth:1,color:0,wireframe:!1,scene:this.active.scene},r=e.extend(a,t),i=new THREE.BoxGeometry(r.width,r.height,r.depth);i.dynamic=!0;var n=new THREE.MeshBasicMaterial({color:r.color,wireframe:r.wireframe}),s=new THREE.Mesh(i,n);return r.id&&(s.name=r.id),s._attributes=r,s},Three.prototype.webglCylinder=function(t){var a={id:!1,radiusTop:1,radiusBottom:1,segmentsRadius:4,segmentsHeight:16,openEnded:!1,color:0,wireframe:!1,scene:this.active.scene},r=e.extend(a,t),i=new THREE.CylinderGeometry(r.radiusTop,r.radiusBottom,r.segmentsRadius,r.segmentsHeight,r.openEnded,!1);i.dynamic=!0;var n=new THREE.MeshBasicMaterial({color:r.color,wireframe:r.wireframe}),s=new THREE.Mesh(i,n);return r.id&&(s.name=r.id),s._attributes=r,s},Three.prototype.webglSprite=function(t){t=t||{};var a={map:!1,color:16777215,fog:!1,transparent:!0,opacity:1},r=e.extend(a,t);t.map?r.map=u.textureLoader(t.map):r.map=u.pixel();var i=r.id;delete r.id,delete r["class"],delete r.el,delete r.style;var n=new THREE.SpriteMaterial(r);n.scaleByViewport=!0,n.blending=THREE.AdditiveBlending;var s=new THREE.Sprite(n);return s.name=i,s._attributes=r,s},Three.prototype.webglTerrain=function(t){t=t||{};var a={lights:!0,fog:!0,scale:256,width:6e3,height:6e3,resolution:256,shader:!0,repeat:1},r=e.extend(a,t),i=new d(r).terrain;return this.active.scene.add(i),i},Three.prototype.colorToHex=function(e){if("#"===e.substr(0,1))return e.replace("#","0x");var t=/(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(e),a=parseInt(t[2],10).toString(16),r=parseInt(t[3],10).toString(16),i=parseInt(t[4],10).toString(16);return 1==a.length&&(a="0"+a),1==r.length&&(r="0"+r),1==i.length&&(i="0"+i),"0x"+a+r+i},Three.prototype.setProperties=function(){return{width:e(this.el).width(),height:e(this.el).height(),aspect:e(this.el).width()/e(this.el).height()}};var u={camelCase:function(e){return e.replace(/-([a-z])/g,function(e){return e[1].toUpperCase()})},delay:function(e,t){t=t||0;var a=Array.prototype.slice.call(arguments,2);return setTimeout(function(){return e.apply(null,a)},t)},unid:function(){return Math.round(Math.random()*(new Date).getTime())},now:function(){return performance&&performance.now?Math.floor(performance.now()):(new Date).getTime()},pixel:function(){var e=document.createElement("img"),t=new THREE.Texture(e);return e.addEventListener("load",function(e){t.needsUpdate=!0}),e.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",t},textureLoader:function(e,t){var a=this.pixel();return THREE.REVISION<70?(e.search(";base64,")>-1&&(e=e.replace(/data:image\/(png|jpg|jpeg);base64,/,"")),a=THREE.ImageUtils.loadTexture(e)):(new THREE.TextureLoader).load(e,function(e){if(a.image=e.image,a.needsUpdate=!0,t){var r=new Event(t);document.dispatchEvent(r)}}),a},getHeightData:function(e){var t=document.createElement("canvas");t.width=128,t.height=128;var a=t.getContext("2d"),r=16384,i=new Float32Array(r);a.drawImage(e,0,0);for(var n=0;r>n;n++)i[n]=0;for(var s=a.getImageData(0,0,128,128),o=s.data,c=0,h=0,l=o.length;l>h;h+=4){var d=o[h]+o[h+1]+o[h+2];i[c++]=d/30}return i},getFile:function(t){return s[t]?s[t]:(s[t]=e.ajax({type:"GET",url:t,dataType:"string",async:!1,success:function(e){s[t]=e}}).responseText,s[t])}, +// @author mrdoob / http://mrdoob.com/ +computeTangents:function(e){function t(e,t,a){v.fromArray(s,3*e),y.fromArray(s,3*t),w.fromArray(s,3*a),E.fromArray(c,2*e),T.fromArray(c,2*t),b.fromArray(c,2*a);var r=y.x-v.x,i=w.x-v.x,n=y.y-v.y,o=w.y-v.y,h=y.z-v.z,l=w.z-v.z,p=T.x-E.x,f=b.x-E.x,m=T.y-E.y,g=b.y-E.y,H=1/(p*g-f*m);x.set((g*r-m*i)*H,(g*n-m*o)*H,(g*h-m*l)*H),R.set((p*i-f*r)*H,(p*o-f*n)*H,(p*l-f*h)*H),d[e].add(x),d[t].add(x),d[a].add(x),u[e].add(R),u[t].add(R),u[a].add(R)}function a(e){C.fromArray(o,3*e),L.copy(C),z=d[e],I.copy(z),I.sub(C.multiplyScalar(C.dot(z))).normalize(),_.crossVectors(L,z),F=_.dot(u[e]),M=0>F?-1:1,l[4*e]=I.x,l[4*e+1]=I.y,l[4*e+2]=I.z,l[4*e+3]=M}var r=e.index,i=e.attributes;if(null===r||void 0===i.position||void 0===i.normal||void 0===i.uv)return void console.warn("THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");var n=r.array,s=i.position.array,o=i.normal.array,c=i.uv.array,h=s.length/3;void 0===i.tangent&&e.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*h),4));for(var l=i.tangent.array,d=[],u=[],p=0;h>p;p++)d[p]=new THREE.Vector3,u[p]=new THREE.Vector3;var f,m,g,v=new THREE.Vector3,y=new THREE.Vector3,w=new THREE.Vector3,E=new THREE.Vector2,T=new THREE.Vector2,b=new THREE.Vector2,x=new THREE.Vector3,R=new THREE.Vector3,H=e.groups;0===H.length&&(H=[{start:0,count:n.length}]);for(var S=0;Sk;k+=3)t(n[k+0],n[k+1],n[k+2])}for(var M,z,F,I=new THREE.Vector3,_=new THREE.Vector3,C=new THREE.Vector3,L=new THREE.Vector3,B=0;Bj;j+=3)a(n[j+0]),a(n[j+1]),a(n[j+2])}}};!function(e){e.fn.toSelector=function(){var t=e(this).get(0),a=t.tagName.toLowerCase(),r=e(this).attr("id"),i=t.className.split(/\s+/),n=a;return"undefined"!=typeof r&&(n+="#"+r),"undefined"!=typeof i&&(n+="."+i.join(".")),n}}(jQuery),Three.prototype.css=n,Three.prototype.find=find,Three.prototype.fn=c,Three.prototype.lookAt=function(){return this.fn.three.call(this,"lookAt",arguments)}}); \ No newline at end of file diff --git a/build/jquery.three.js b/build/jquery.three.js index 5714871..4481811 100644 --- a/build/jquery.three.js +++ b/build/jquery.three.js @@ -1,7 +1,7 @@ /** * @name jquery.three * jQuery Three() - jQuery extension with 3D methods (using Three.js) - * Version: 0.8.0 (Sat, 30 Nov 2013 10:20:34 GMT) + * Version: 0.9.8 (Sun, 11 Dec 2016 13:05:25 GMT) * * @author makesites * Created by: Makis Tracend (@tracend) @@ -25,12 +25,12 @@ window.requestAnimFrame = ( function( callback ) { (function (root, factory) { - "use strict"; + //"use strict"; - var define = define || false; + //var define = define || false; var jquery = root.$ || root.jQuery || root.ender; - if (define && typeof define === 'function' && define.amd) { + if (typeof define === 'function' && define.amd){ // AMD. Register as an anonymous module. define(['jquery'], factory); } else { @@ -42,17 +42,22 @@ window.requestAnimFrame = ( function( callback ) { // Local variables var css, _css; +var files = {}; +var origin = location.origin || location.protocol + "//" + location.hostname + (location.port ? ":" + location.port: ""); // Create a fn container for internal methods var fn = { - self : function(){ return this; } - }; + self : function(){ return this; } +}; + var defaults = { - watch : false, + alpha: true, + clock: true, + watch: false, //deps : { "THREE" : "http://cdnjs.cloudflare.com/ajax/libs/three.js/r54/three.min.js" } - deps : { + deps: { "THREE" : "https://raw.github.com/mrdoob/three.js/master/build/three.min.js" //"FresnelShader" : "" }, @@ -68,12 +73,16 @@ var fn = { this.objects = {}; this.scenes = {}; this.cameras = {}; + this.terrains = {}; this.materials = {}; // defining types (extandable) this.groups = { - "camera" : "cameras", "scene" : "scenes", "mesh" : "objects", "plane" : "objects", "cube" : "objects", "sphere" : "objects", "cylinder" : "objects", "material" : "materials" + "camera" : "cameras", "scene" : "scenes", "terrain" : "terrains", "mesh" : "objects", "plane" : "objects", "cube" : "objects", "sphere" : "objects", "cylinder" : "objects", "material" : "materials" }; - // #43 - calculating 'actual' framerate + + // init clock + if( this.options.clock ) this.clock = new THREE.Clock(); + // #43 - calculating 'actual' framerate (use clock?) this.frame = { current: 0, rate: 0, @@ -107,7 +116,7 @@ Three.prototype = { this.properties = this.setProperties(); // init renderer - this.renderer = new THREE.WebGLRenderer(); + this.renderer = new THREE.WebGLRenderer({ alpha: this.options.alpha }); this.renderer.setSize( this.properties.width, this.properties.height); // condition this! this.renderer.autoClear = false; @@ -194,7 +203,7 @@ Three.prototype = { } else { // new frame, new count this.frame.rate = this.frame.current; - this.frame.current = 1; //start fron 1 to include running frame ;) + this.frame.current = 1; //start from 1 to include running frame ;) this.frame.date = now; } // loop on the next click @@ -202,22 +211,31 @@ Three.prototype = { }, render : function() { - // apply transformations - $(this.el).trigger({ - type: "update", - target: this - }); - // - + // init render if( this.active.scene && this.active.camera ){ - // render the skybox as a first pass + // resize skybox to the limits of the active camera (far attribute) if( this.active.skybox ){ - if( this.active.skybox.camera ) this.active.skybox.camera.rotation.copy( this.active.camera.rotation ); - this.renderer.render( this.active.skybox.scene, this.active.skybox.camera ); + //if( this.active.skybox.camera ) this.active.skybox.camera.rotation.copy( this.active.camera.rotation ); + //this.renderer.render( this.active.skybox.scene, this.active.skybox.camera ); + var horizon = this.active.camera.far; + var scale = this.active.skybox.scale; + if( scale.x !== horizon ) + scale.x = scale.y = scale.z = horizon; + // always center around camera... + var position = this.active.camera.position; + this.active.skybox.position.set( position.x, position.y, position.z ); } + this.renderer.render( this.active.scene, this.active.camera ); } + // update internal animation queue + this.fn.animate.update(); + // trigger update event regardlesss + $(this.el).trigger({ + type: "update", + target: this + }); }, show : function( ) { }, @@ -252,10 +270,10 @@ Three.prototype = { this.cameras[i].updateProjectionMatrix(); } // better way of targeting skybox??? - if( this.active.skybox ){ - this.active.skybox.camera.aspect = this.properties.aspect; - this.active.skybox.camera.updateProjectionMatrix(); - } + //if( this.active.skybox ){ + // this.active.skybox.camera.aspect = this.properties.aspect; + // this.active.skybox.camera.updateProjectionMatrix(); + //} this.renderer.setSize( this.properties.width, this.properties.height ); }, @@ -347,6 +365,8 @@ Three.prototype.getAttributes = function( html ){ var val = attr[i].value; // check if it's a number... data[key] = ( parseInt(val, 10) || val === "0" ) ? parseInt(val, 10) : val; + // convert boolean + if( data[key] === "false" || data[key] === "true" ) data[key] = JSON.parse( data[key] ); } else if( attr[i].name && attr[i].name.search("class") === 0 ){ // add classes var classes = attr[i].value.split(" "); @@ -390,17 +410,25 @@ css = function ( styles ){ return this; }; - // Internal functions fn.css = { styles: function (a){ var sheets = document.styleSheets, o = {}; + // loop through stylesheets - for(var i in sheets) { - var rules = sheets[i].rules || sheets[i].cssRules; + for( var i in sheets ){ + var sheet = sheets[i]; + var isOutsideOfDomain = sheet.href && sheet.href.indexOf("/") !== 0 && sheet.href.indexOf(origin) !== 0; + // ignore sheets out-of-domain or without CSS rules + if(isOutsideOfDomain || sheet.cssRules === null) continue; + // + var rules = sheet.cssRules || sheet.rules; for(var r in rules) { // #21 - excluding :hover styles from parsing if( rules[r].selectorText && rules[r].selectorText.search(":hover") > -1) continue; + // excluding other pseudo elements + if( rules[r].selectorText && rules[r].selectorText.search("::before") > -1) continue; + if( rules[r].selectorText && rules[r].selectorText.search("::after") > -1) continue; try{ if(a.is(rules[r].selectorText)) { o = $.extend(o, css2json(rules[r].style)); @@ -422,6 +450,13 @@ fn.css = { for( var attr in css ){ // remove prefixes var key = attr.replace('-webkit-','').replace('-moz-',''); + // save attribute reference in the object + object._style = object._style || {}; + object._shaders = object._shaders || {}; + var changed = ( object._style[key] && object._style[key] == css[attr] ) ? false : true; // save old value? + object._style[key] = css[attr]; + // parse only changed atrributes + if( !changed ) continue; // supported attributes switch(key){ // - width @@ -453,7 +488,7 @@ fn.css = { //this.fn.css.skybox.call(this, css[attr]); this.webglLight({color : color}); } else { - object.material.color.setHex(color); + setColor( object, color ); } break; // - transforms @@ -489,25 +524,38 @@ fn.css = { break; // - animation case "animation-duration": - console.log( key, css[attr]); + this.fn.css.animation.duration = parseInt( css[attr], 10) * 1000; // convert seconds to milliseconds break; case "animation-timing": - console.log( key, css[attr]); + this.fn.css.animation.easing = css[attr]; break; case "animation-delay": - console.log( key, css[attr]); + this.fn.css.animation.delay = css[attr]; break; case "animation-iteration-count": - console.log( key, css[attr]); + this.fn.css.animation.repeat = css[attr]; break; case "animation-direction": - console.log( key, css[attr]); + this.fn.css.animation.direction = css[attr]; break; case "animation-fill-mode": - console.log( key, css[attr]); + this.fn.css.animation.fill = css[attr]; break; case "animation-name": - console.log( key, css[attr]); + //console.log( key, css[attr]); + // assumption: name is the last animation attribute processed + this.fn.css.animation.name = css[attr]; + this.animate( this.fn.css.animation, object ); + this.fn.css.animation = {}; + break; + case "animation-timing-function": + // duplicate of animation-timing? + // if counting steps, save the number + var steps = css[attr].match(/steps\((\d)/); // not closed.. + this.fn.css.animation.easing = ( steps ) ? parseInt(steps[1], 10) : css[attr]; + break; + case "animation-play-state": + this.fn.css.animation.state = css[attr]; break; case "display": // set it as the active one... @@ -517,6 +565,8 @@ fn.css = { if( object instanceof THREE.Scene){ this.fn.css.skybox.call(this, css[attr]); } else if( object.type == "terrain" ){ + // make sure this get's processed on the next tick + //utils.delay( this.fn.css.terrain.bind(this), 100, css[attr] ); this.fn.css.terrain.call(this, css[attr]); } else if ( object instanceof THREE.Mesh ) { this.fn.css.texture.call(this, object, css[attr]); @@ -529,19 +579,73 @@ fn.css = { } catch( e ){ console.log(e); } + } else if( object instanceof THREE.Sprite ){ + var src = css[attr].replace(/\s|url\(|"|'|\)/g, ""); + object.material.map = utils.textureLoader( src ); + } + break; + case "background-size": + if( object instanceof THREE.Sprite ){ + // + this.fn.css.sprite.call(this, object, css[attr]); + } + break; + // "background-position" arrives split in axis + case "background-position-x": + if( object instanceof THREE.Sprite ){ + // update sprite + this.fn.css.sprite.call(this, object); + } + break; + case "background-position-y": + if( object instanceof THREE.Sprite ){ + // update sprite + this.fn.css.sprite.call(this, object); } break; + case "filter": + // variables + // - find element + var el, $el; + if( object instanceof THREE.Mesh && object.parent instanceof THREE.Object3D ){ + // parent is always an object...? + el = object.parent; + $el = object.parent.$el; + } else { + el = object; + $el = object.$el; + } + // get URLs + var urls = css[attr].replace(/url\(|"|'|\)/g, "").split('|'); // all shaders in one url? + // prerequisite + if( !urls.length ) break; + // get shaders + el._shaders = el._shaders || {}; + for( var i in urls ){ + var name = urls[i].substring(urls[i].lastIndexOf('/')+1); + el._shaders[name] = utils.getFile( urls[i] ); + } + // add helper method + el.getShader = function( name ){ + return this._shaders[name] || null; + }; + // trigger event + $el.trigger('css-filter'); + break; } } }, + // temporary container for parsed (animation) attributes... + animation: {}, + rotate: function( attr ){ var rot = {}; var val; - // only supporting rotate3d for now... + // if( attr.search("rotate3d") > -1 ){ // replace all the bits we don't need val = attr.match(/rotate3d\(([\s\S]*?)\)/gi); @@ -554,6 +658,32 @@ fn.css = { z: parseFloat( val[2], 10 ) * parseFloat( val[3], 10 ) * (Math.PI/180) }; + } else if( attr.search("rotateX") > -1 ){ + // axis based rotation + val = attr.match(/rotateX\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotateX\(|deg|\)| /gi, ""). + rot = { + x: parseFloat( val, 10 ) * (Math.PI/180) + }; + } else if( attr.search("rotateY") > -1 ){ + val = attr.match(/rotateY\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotateY\(|deg|\)| /gi, ""); + rot = { + y: parseFloat( val, 10 ) * (Math.PI/180) + }; + } else if( attr.search("rotateZ") > -1 ){ + val = attr.match(/rotateZ\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotateZ\(|deg|\)| /gi, ""); + rot = { + z: parseFloat( val, 10 ) * (Math.PI/180) + }; + } else if( attr.search("rotate") > -1 ){ + val = attr.match(/rotate\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotate\(|deg|\)| /gi, ""); + // if no axis is set assume Z? + rot = { + z: parseFloat( val, 10 ) * (Math.PI/180) + }; } return rot; @@ -585,7 +715,7 @@ fn.css = { scale: function( attr ){ var size = {}; - // only supporting rotate3d for now... + // only supporting scale3d for now... if( attr.search("scale3d") > -1 ){ // replace all the bits we don't need var val = attr.match(/scale3d\(([\s\S]*?)\)/gi); @@ -605,71 +735,75 @@ fn.css = { }, texture: function( el, attr ){ - var map = attr.replace(/\s|url\(|\)/g, ""); - var material = this.webglMaterial({ map : map }); + var material; + var img = attr.replace(/\s|url\(|"|'|\)/g, "").split(','); + if( img.length > 1 ){ + // shader material + // add available shaders + var uniforms = {}; + var params = {}; + var textureCube = new THREE.CubeTextureLoader().load( img ); + //var textureCube = app.layout.views.get('back').$3d.active.skybox.material.uniforms.tCube.value ); + textureCube.format = THREE.RGBFormat; + + uniforms.tCube = { + type: "t", + value: textureCube + }; + // add shaders if available + if(el._shaders){ + for( var i in el._shaders ){ + var shader = el._shaders[i]; + if( i.indexOf('.fs') > -1 ){ + params.fragmentShader = shader; + } + if( i.indexOf('.vs') > -1 ){ + params.vertexShader = shader; + } + } + } + + params.uniforms = uniforms; + params.needsUpdate = true; + + material = new THREE.ShaderMaterial( params ); + + } else { + // basic map material + material = this.webglMaterial({ map : img[0] }); + } el.material = material; }, terrain: function( attr ){ - var object = this.last; - - var img = attr.replace(/\s|url\(|\)/g, "").split(','); + var terrain = this.last; + //var img = attr.replace(/\s|url\(|"|'|\)/g, "").split(','); + var img = attr.match(/url\(\s*[\'"]?(([^\\\\\'" \(\)]*(\\\\.)?)+)[\'"]?\s*\)/img); + // if(img instanceof Array){ + var heightmap, diffuse, specular; for( var i in img ){ + // clean url(...) content + img[i] = img[i].replace(/\s|url\(|"|'|\)/g, ""); - if( img[i].search("heightmap") > -1 ){ - - var heightmapTexture = THREE.ImageUtils.loadTexture( img[i] ); - //var heightmapTexture = this.webglTexture( img[i] ); - object.material.uniforms.tDisplacement.value = heightmapTexture; - object.material.uniforms.uDisplacementScale.value = 375; - // heightmap also the second diffuse map? - var diffuseTexture2 = heightmapTexture; - diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; - - object.material.uniforms.tDiffuse2.value = diffuseTexture2; - object.material.uniforms.enableDiffuse2.value = true; - - } - if( img[i].search("diffuse") > -1 ){ - - var diffuseTexture1 = THREE.ImageUtils.loadTexture( img[i] ); - //var diffuseTexture1 = this.webglTexture( img[i] ); - diffuseTexture1.wrapS = diffuseTexture1.wrapT = THREE.RepeatWrapping; - - object.material.uniforms.tDiffuse1.value = diffuseTexture1; - object.material.uniforms.enableDiffuse1.value = true; + if( img[i].search("heightmap") > -1 ) heightmap = terrain.updateTexture('heightmap', img[i]); - } - if( img[i].search("specular") > -1 ){ - - var specularMap = THREE.ImageUtils.loadTexture( img[i] ); - //var specularMap = this.webglTexture( img[i] ); - specularMap.wrapS = specularMap.wrapT = THREE.RepeatWrapping; + if( img[i].search("diffuse") > -1 ) diffuse = terrain.updateTexture('diffuse', img[i]); - object.material.uniforms.tSpecular.value = specularMap; - object.material.uniforms.enableSpecular.value = true; + if( img[i].search("specular") > -1 ) specular = terrain.updateTexture('specular', img[i]); - } } + // fallbacks + if(!heightmap && img[0]) terrain.updateTexture('heightmap', img[0]); + if(!diffuse && img[1]) terrain.updateTexture('diffuse', img[1]); + if(!specular && img[2]) terrain.updateTexture('specular', img[2]); + } else { - // one image... which texture is it?... + // one image... assume it's both heightmap and texture + terrain.updateTexture('heightmap', img); + terrain.updateTexture('diffuse', img); } - /* - - leftovers ( normal and detail textures) - - //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; - - //uniformsTerrain[ "tNormal" ].value = heightmapTexture; - //uniformsTerrain[ "uNormalScale" ].value = 1; - - //uniformsTerrain[ "tDetail" ].value = detailTexture; - - //uniformsTerrain[ "uShininess" ].value = 30; - - */ }, @@ -677,7 +811,7 @@ fn.css = { // remove any whitespace, the url(..) and // attempt to break it into an array - var img = attr.replace(/\s|url\(|\)/g, "").split(','); + var img = attr.replace(/\s|url\(|"|'|\)/g, "").split(','); if(img instanceof Array){ // expect a six-pack of images this.addSkybox( img ); @@ -686,6 +820,39 @@ fn.css = { // this is one image... not implemented yet } + }, + + sprite: function( el, attr ){ + // wait for the image to load + var loaded = setInterval(function(){ + // assume map is available... + if( !el.material.map.image || !el.material.map.image.width ) return; + // fallbacks + attr = attr || el._style["background-size"] || "0 0"; + var size = attr.split(" "); + var width = parseFloat(size[0], 10); + var height = parseFloat(size[1], 10); + // get position from style + var x = parseFloat( el._style["background-position-x"] || 0 ); + var y = parseFloat( el._style["background-position-y"] || 0 ); + + if( !width || !height ) return; + + // image dimensions + var imgWidth = el.material.map.image.width; + var imgHeight = el.material.map.image.height; + // + //el.material.uvOffset.set(1 / 5, 0); + //el.material.uvScale.set(1 / 5, 1); + el.material.map.offset.set( (imgWidth - width - x) / imgWidth, (imgHeight - height - y) / imgHeight ); // start from top left... + el.material.map.repeat.set(width / imgWidth, height / imgHeight); + //el.scale.set( width, height, 1 ); + //console.log("sprite loaded"); + // stop loop + clearInterval(loaded); + }, 200); + + } }; @@ -728,19 +895,308 @@ var css2json = function (css){ return s; }; +function setColor( object, color ){ + object = object || {}; + // prerequisite + if( !object.material ) return; // create material instead? + // in case we have more than one materials + if( object.material.materials ){ + // check it it's an array first? + for(var i in object.material.materials ){ + object.material.materials[i].color.setHex(color); + } + } else { + object.material.color.setHex(color); + } +} + +Three.prototype.animate = function( options, el ){ + //this.mesh.rotation.z = Date.now() / 1000; -Three.prototype.animate = function(){ + // fallbacks + options = options || {}; + el = el || this.last || false; // last processed object + // FIX: we are checking the type of the element to attach to Object3D? + if( el instanceof THREE.Mesh && el.parent instanceof THREE.Object3D ){ + el = el.parent; + } + // prerequisites + if( !el || !options.name ) return; + // create the necessary object containers + // should we be checking the type of the element to attach to Object3D? + el._animations = el._animations || {}; + el._update = el._update || updateAnimations.bind( el ); + + // pickup animation keyframes + options.keyframes = this.fn.animate.getKeyframes.call( this, options.name ); + // exit now... + if( !options.keyframes ) return; + // set the new animation + el._animations[ options.name ] = options; + // add to animate queue (once...) + var inQueue = ( typeof this.fn.animate.queue[el.uuid] !== "undefined" ); + if( !inQueue){ + this.fn.animate.queue[el.uuid] = el._update; // using uuid to be able to remove from queue later + } +}; + +// Internal + +fn.animate = { + // container for all methods to be updated + queue: {}, + + getKeyframes: function( name ){ + var keyframes = {}; + // first find the rules + var animation = findKeyframesRule( name ); + + if(!animation) return; + // parse each one of them + for(var i in animation.cssRules){ + var rule = animation.cssRules[i]; + var frame = {}; + // FIX: only rules parsed + if( !rule.keyText ) continue; + // convert percent to 1-100 number + var key = parseInt( rule.keyText, 10 ), val; + // find rotation values + frame.rotation = this.fn.css.rotate( rule.cssText ); + // find translate values + frame.translation = this.fn.css.translate( rule.cssText ); + // find scale values + frame.scale = this.fn.css.scale( rule.cssText ); + // other attributes + if( rule.cssText.search("background-position-x") > -1 ){ + frame["background-position"] = frame["background-position"] || {}; + val = rule.cssText.match(/:[\d|\s|\w]+\;/); // capture everything between : ; + if( val ) frame["background-position"].x = parseFloat(val[0].substr(1), 10); + } + if( rule.cssText.search("background-position-y") > -1 ){ + frame["background-position"] = frame["background-position"] || {}; + val = rule.cssText.match(/:[\d|\s|\w]+\;/); // capture everything between : ; + if( val ) frame["background-position"].y = parseFloat(val[0].substr(1), 10); + } + // add to the keyframes + keyframes[ key ] = frame; + } + return keyframes; + }, + + // loop through the object's animations and update the object's properties + update: function( el ){ + //console.log( this.queue ); + // loop through the queue + for( var i in this.queue ){ + // execute + this.queue[i](); + } + } + +}; + +// Helpers + +function updateAnimations(){ + // context is the individual object + //console.log( this ); + // loop through animations + for( var i in this._animations){ + var animation = this._animations[i]; + var keyframes = animation.keyframes; + // get current params + animation.start = animation.start || utils.now(); + animation.end = animation.end || ( animation.start + animation.duration ); + animation.offset = animation.offset || registerState( this ); + animation.count = animation.count || 0; + // find the right stage in the animation + var now = utils.now(); + var percent = ( ( now - animation.start) / animation.duration ) * 100; + var start = false, + end = false; + for( var key in keyframes ){ + if( key <= percent ){ + start = keyframes[ key ]; + } + if( key > percent && !end ){ + end = keyframes[ key ]; + } + } + // fallbacks + if( !start ) start = keyframes[ 0 ]; + if( !end ) end = keyframes[ 100 ]; + // apply updates + // NOTE: only linear supported for now... + // - rotate + var rot = { + x: ( typeof start.rotation.x != "undefined" && typeof end.rotation.x != "undefined" ) ? (end.rotation.x - start.rotation.x )*(percent/100) : 0, + y: ( typeof start.rotation.y != "undefined" && typeof end.rotation.y != "undefined" ) ? (end.rotation.y - start.rotation.y )*(percent/100) : 0, + z: ( typeof start.rotation.z != "undefined" && typeof end.rotation.z != "undefined" ) ? (end.rotation.z - start.rotation.z )*(percent/100) : 0 + }; + this.rotation.set( animation.offset.rotation.x+rot.x, animation.offset.rotation.y+rot.y, animation.offset.rotation.z+ rot.z); + // TBA... + // - translate + + // - scale + + // - sprites + if( this instanceof THREE.Sprite ){ + // get current sprite index + var offset = { + x: this.material.map.offset.x, + y: this.material.map.offset.y + }; + // increment + var steps = animation.easing; + var step = 100/steps; + var nextStep = ( (parseInt( percent, 10) % step) === 0 ) ? parseInt( percent, 10) / 100 : 0; // every time we return to zero we have a new step + if( nextStep ){ + // FIX: start index of steps from zero + nextStep -= 1/steps; + // find the right axis + if( typeof animation.keyframes[0]["background-position"].x !== "undefined" ){ + // - numbers go in reverse order (steps-1 to 0) + offset.x = ((steps-1)/steps)-nextStep; + } + if( typeof animation.keyframes[0]["background-position"].y !== "undefined" ){ + // - numbers go in reverse order (steps-1 to 0) + offset.y = ((steps-1)/steps)-nextStep; + } + // update sprite + this.material.map.offset.set( offset.x, offset.y ); + } + + } + // reset if reached completion + if( percent >= 100 ){ + delete animation.start; + delete animation.end; + delete animation.offset; + animation.count++; + } + // + if( animation.count == animation.repeat ){ + delete this._animations[i]; + } else { + // save animation updates + this._animations[i] = animation; + } + } +} + +// register element state +function registerState( el ){ + return { + position: { + x: el.position.x, + y: el.position.y, + z: el.position.z + }, + rotation: { + x: el.rotation.x, + y: el.rotation.y, + z: el.rotation.z + }, + scale: { + x: el.scale.x, + y: el.scale.y, + z: el.scale.z + } + }; +} + +/* + * Access and modify CSS animations @keyFrames with Javascript + * Based on : http://jsfiddle.net/russelluresti/RHhBz/2/ + * Issue : http://stackoverflow.com/questions/10342494/set-webkit-keyframes-values-using-javascript-variable + */ + + // search the CSSOM for a specific -webkit-keyframe rule +function findKeyframesRule(rule){ + // gather all stylesheets into an array + var ss = document.styleSheets; + + // loop through the stylesheets + for (var i = 0; i < ss.length; ++i) { + + // loop through all the rules + for (var j = 0; j < ss[i].cssRules.length; ++j) { + + // find the -webkit-keyframe rule whose name matches our passed over parameter and return that rule + if (ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && ss[i].cssRules[j].name == rule) + return ss[i].cssRules[j]; + } + } + + // rule not found + return null; +} + +// remove old keyframes and add new ones +function changeAnimationKeyframes(anim){ + // find our -webkit-keyframe rule + var keyframes = findKeyframesRule(anim); + + // remove the existing 0% and 100% rules + keyframes.deleteRule("0%"); + keyframes.deleteRule("100%"); + + // create new 0% and 100% rules with random numbers + keyframes.insertRule("0% { -webkit-transform: rotate("+randomFromTo(-360,360)+"deg); }"); + keyframes.insertRule("100% { -webkit-transform: rotate("+randomFromTo(-360,360)+"deg); }"); + + // assign the animation to our element (which will cause the animation to run) + document.getElementById('box').style.webkitAnimationName = anim; +} + +Three.prototype.fx = function(){ //this.mesh.rotation.z = Date.now() / 1000; - + }; // watch an element for changes Three.prototype.watch = function( el ) { var self = this; - var element = $(this.el).toSelector() +" "+ $( el ).selector; + var selector = $( el ).selector || "shadow-root"; // fallback to main root + var element = $(this.el).toSelector() +" "+ selector; + + var node = document.getElementById("main").querySelector("shadow-root"), //$(this.el)[0], //$(element)[0], + bubbles = false; + + // shim + var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; + + var whatToObserve = { childList: true, attributes: true, subtree: true, attributeOldValue: true, attributeFilter: ['class', 'style']}; + //var whatToObserve = { childList: true, attributes: false, subtree: true }; + var attrObserver = new MutationObserver(function(mutationRecords) { + $.each(mutationRecords, function(index, mutationRecord) { + var e = mutationRecord; + if (mutationRecord.type === 'childList') { + if (mutationRecord.addedNodes.length > 0) { + //DOM node added, do something + //console.log("execute", mutationRecord ); + //console.log('DOMSubtreeModified', e.target.innerHTML.length, e.target ); + self.eventSubtree(e); + } else if (mutationRecord.removedNodes.length > 0) { + //DOM node removed, do something + } + } + else if (mutationRecord.type === 'attributes') { + if (mutationRecord.attributeName === 'class') { + //class changed, do something + self.eventAttribute(e); + } + } + }); + }); + + attrObserver.observe(node, whatToObserve); + // monitor new elements + /* $('body').on('DOMSubtreeModified', element, function(e){ + console.log(e); self.eventSubtree(e); }); // monitor attribute changes @@ -754,13 +1210,39 @@ Three.prototype.watch = function( el ) { self.eventAttribute(e); }); } + */ + + var observeStyles = new MutationObserver(function (mutations) { + mutations.forEach(stylesModified); + }); + observeStyles.observe(node, { childList: false, attributes: true, subtree: true, attributeFilter: ['class', 'style'] }); + + // monitor css style changes + function stylesModified(mutation) { + var el = mutation.target, + name = mutation.attributeName, + newValue = mutation.target.getAttribute(name), + oldValue = mutation.oldValue; + // skip all id, data-id updates (not editable from the user) + //if( name == 'id' || name == 'data-id' ) return; + // styling updates + if( name == 'style' ){ + var object = self.objects[ el.getAttribute('data-id') ] || self.active.terrain; + var webgl = object.children[0] || object; + var css = css2json(newValue); // validate? + // HACK: why is terrain using this.last? + self.last = webgl; + self.fn.css.set.call(self, webgl, css ); + } + //console.log(name, newValue, oldValue); + } }; // - new element Three.prototype.eventSubtree = function(e) { - e.stopPropagation(); + //e.stopPropagation(); // mutation event doesn't propagate? // variables var $root = $( $(this.el).toSelector() +" shadow-root" ).get(0); @@ -770,21 +1252,29 @@ Three.prototype.eventSubtree = function(e) { this.parent = ( $root == $target ) ? $(e.target) : $(e.target).parent(); this.target = $(e.target); - if (e.target.innerHTML.length > 0) { - // Handle new content - //var html = e.target.innerHTML; - var html = $(e.target).html(); - //this.newEl = $(e.target).children().last(); - // #46 parsing one tag at a time - //html = $(html).html("").get(0); - //this.newEl = $(html).last(); - this.append( html, { silent : true, target: this.target, traverse: false, watch: true }); - } + // exclude shadow-root + //if( $root == $target ) return; + // exclude empty targets + if(e.target.innerHTML.length === 0) return; + // Handle new content + //var html = e.target.innerHTML; + var html = $(e.target).html(); + //var wrapper = $(html).eq(0)[0]; + // FIX: exclude empty div tags (dead-ends) + //if( wrapper.tagName == "DIV" && + //if( wrapper.toString().substr(0, 5).toLowerCase() == "
" ) return; + // html = wrapper.childNodes[0].toString().trim(); + //this.newEl = $(e.target).children().last(); + // #46 parsing one tag at a time + //html = $(html).html("").get(0); + //this.newEl = $(html).last(); + this.append( html, { silent : true, target: this.target, traverse: false, watch: true }); + }; // - updated attribute Three.prototype.eventAttribute = function(e) { - e.stopPropagation(); + //e.stopPropagation(); console.log("attribute", e.target ); @@ -793,7 +1283,6 @@ Three.prototype.eventAttribute = function(e) { // - updated style(s) - // generic method to add an element Three.prototype.add = function( attributes, options ){ var self = this; @@ -833,21 +1322,16 @@ Three.prototype.add = function( attributes, options ){ object = webgl; } //this[ attributes.type+"s" ][0] = webgl; + // condition which elements have an active flag? self.active[ attributes.type ] = object; - // - if( container ){ - // save in the objects bucket - self[container][object.id] = object; - } - // add to scene - if( attributes.type == "scene"){ - self.active.scene = object; - } else if( self.active.scene ){ - self.active.scene.add( object ); - } + // keep a reference of the object id attributes["data-id"] = object.id || false; + + // FIX: stop now if duplicate id was generated (why?) + if( attributes.el.data('id') ) return; + // create the tag in the shadow dom var $html; if( options.silent && attributes.el){ @@ -860,10 +1344,26 @@ Three.prototype.add = function( attributes, options ){ $html = self.createHTML( attributes ); self.target = $html; } + + // save reference of html tag in object + object.$el = $html; + // apply css var css = self.fn.css.styles.call(self, $html ); self.fn.css.set.call(self, webgl, css ); + // save in the objects bucket + if( container ){ + self[container][object.id] = object; + } + + // add to scene + if( attributes.type == "scene"){ + self.active.scene = object; + } else if( self.active.scene ){ + self.active.scene.add( object ); + } + }); return this; @@ -974,38 +1474,69 @@ Three.prototype.addAsset = function( obj ){ Three.prototype.addSkybox = function( img ){ - // does this camera have set values?? - var camera = new THREE.PerspectiveCamera( 50, $(this.el).width() / $(this.el).height(), 1, 100 ); + //var scene = new THREE.Scene(); + var camera, geometry, material; - var scene = new THREE.Scene(); + if( img.length == 1){ - var reflectionCube = THREE.ImageUtils.loadTextureCube( img ); - reflectionCube.format = THREE.RGBFormat; + //camera = new THREE.PerspectiveCamera( 50, $(this.el).width() / $(this.el).height(), 1, 1100 ); + //camera.target = new THREE.Vector3( 0, 0, 0 ); - //var shader = THREE.ShaderUtils.lib.cube; - var shader = THREE.ShaderLib.cube; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - uniforms.tCube.value = reflectionCube; + // skysphere + geometry = new THREE.SphereGeometry( 1, 60, 40 ); + geometry.applyMatrix( new THREE.Matrix4().makeScale( -1, 1, 1 ) ); + material = new THREE.MeshBasicMaterial({ + map: utils.textureLoader( img[0] ) + }); - var material = new THREE.ShaderMaterial( { + } else { + // + var reflectionCube; + // skybox (with legacy support) + if(THREE.REVISION < 70){ + reflectionCube = THREE.ImageUtils.loadTextureCube( img ); + } else { + var cubeTextureLoader = new THREE.CubeTextureLoader(); + reflectionCube = cubeTextureLoader.load( img ); + } + reflectionCube.format = THREE.RGBFormat; - fragmentShader: shader.fragmentShader, - vertexShader: shader.vertexShader, - uniforms: uniforms, - depthWrite: false, - side: THREE.BackSide + // does this camera have set values?? + //camera = new THREE.PerspectiveCamera( 50, $(this.el).width() / $(this.el).height(), 1, 100 ); - }); + //var shader = THREE.ShaderUtils.lib.cube; + var shader = THREE.ShaderLib.cube; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + uniforms.tCube.value = reflectionCube; - var mesh = new THREE.Mesh( new THREE.CubeGeometry( 100, 100, 100 ), material ); + material = new THREE.ShaderMaterial( { - scene.add( mesh ); + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader, + uniforms: uniforms, + depthWrite: false, + side: THREE.BackSide + + }); + // the dimensions of the skybox will be resized to the limits of the active camera (far) + geometry = new THREE.BoxGeometry( 1, 1, 1 ); + } + + var mesh = new THREE.Mesh( geometry, material ); + /* + var object = new THREE.Object3D(); + object.add( mesh ); + // #40 copy name from mesh + object.name = mesh.name = "skybox"; + */ + this.active.scene.add( mesh ); // save as active - this.active.skybox = { - scene : scene, - camera : camera - }; + this.active.skybox = mesh; + //this.active.skybox = { + // scene : scene, + // camera : camera + //}; }; Three.prototype.addTerrain = function( obj ){ @@ -1136,7 +1667,7 @@ Three.prototype.append = function(html, options){ Three.prototype.get = function( id ){ // find the element in the containers - var el = this.objects[id] || this.cameras[id] || this.scenes[id] || null; + var el = this.objects[id] || this.cameras[id] || this.scenes[id] || this.terrains[id] || null; return el; @@ -1162,7 +1693,7 @@ fn.find = { var id = $(this.el).find("shadow-root "+ query).attr("data-id"); // find the element in the containers - var el = this.objects[id] || this.cameras[id] || this.scenes[id] || null; + var el = this.objects[id] || this.cameras[id] || this.scenes[id] || this.terrains[id] || null; return el; } @@ -1181,6 +1712,277 @@ fn.three = function(fn, query ){ }; +// internal constructor for Terrain +var Terrain = function( options ){ + // prerequisites? + + // reference to the options + this.options = options; + + // binding resolution across axis + var resX = options.resolution, + resY = options.resolution; + + // in both cases the geometry is Buffer + var plane = new THREE.PlaneBufferGeometry( options.width, options.height, resX, resY ); + + // update normals after images are loaded? + plane.computeFaceNormals(); + plane.computeVertexNormals(); + //plane.computeTangents( plane ); + //THREE.BufferGeometryUtils.computeTangents( plane ); + utils.computeTangents( plane ); + + // look if we're rendering using a shader + var material = ( options.shader ) ? this.shaderMaterial() : this.basicMaterial(); + + // exit now id we didn't generate a material? + + // generate mesh + var terrain = new THREE.Mesh( plane, material ); + // needsUpdate as attribute + //terrain.geometry.attributes.normal.needsUpdate = true; + + // save type as part of the mesh + terrain.type = "terrain"; + + // save attributes + terrain._attributes = options; + + // helper methods + if( options.shader ){ + terrain.updateTexture = this.shaderTexture.bind(terrain); + } else { + terrain.computeElevation = this.computeElevation.bind(terrain); + terrain.updateTexture = this.basicTexture.bind(terrain); + } + + // save reference + this.terrain = terrain; + + return this; +}; + + +Terrain.prototype.shaderMaterial = function(){ + // prerequisites + if( !THREE.ShaderTerrain ) + return console.log("THREE.ShaderTerrain not loaded. Use data-shader='false' to generate a poly terrain"); + + var options = this.options; + var terrainShader = THREE.ShaderTerrain.terrain; + + var uniformsTerrain = THREE.UniformsUtils.clone( terrainShader.uniforms ); + + /* these are all moved to the css styling... + var heightmapTexture = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); + var diffuseTexture1 = THREE.ImageUtils.loadTexture( "assets/img/terrain/diffuse.jpg" ); + var diffuseTexture2 = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); + var specularMap = THREE.ImageUtils.loadTexture( "assets/img/terrain/specular.png"); + + diffuseTexture1.wrapS = diffuseTexture1.wrapT = THREE.RepeatWrapping; + diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; + //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; + specularMap.wrapS = specularMap.wrapT = THREE.RepeatWrapping; + + //uniformsTerrain[ "tNormal" ].value = heightmapTexture; + //uniformsTerrain[ "uNormalScale" ].value = 1; + + uniformsTerrain[ "tDisplacement" ].value = heightmapTexture; + uniformsTerrain[ "uDisplacementScale" ].value = 375; + + uniformsTerrain[ "tDiffuse1" ].value = diffuseTexture1; + uniformsTerrain[ "tDiffuse2" ].value = diffuseTexture2; + uniformsTerrain[ "tSpecular" ].value = specularMap; + //uniformsTerrain[ "tDetail" ].value = diffuseTexture1; + + uniformsTerrain[ "enableDiffuse1" ].value = true; + uniformsTerrain[ "enableDiffuse2" ].value = true; + uniformsTerrain[ "enableSpecular" ].value = true; + + uniformsTerrain[ "uDiffuseColor" ].value.setHex( 0xffffff ); + uniformsTerrain[ "uSpecularColor" ].value.setHex( 0xffffff ); + uniformsTerrain[ "uAmbientColor" ].value.setHex( 0x111111 ); + + //uniformsTerrain[ "uShininess" ].value = 30; + */ + + // allow the terrain to emit ambient light from the scene + if( THREE.REVISION < 70 ){ + uniformsTerrain.uDiffuseColor.value.setHex( 0xffffff ); + uniformsTerrain.uSpecularColor.value.setHex( 0xffffff ); + uniformsTerrain.uAmbientColor.value.setHex( 0x111111 ); + } else { + uniformsTerrain.diffuse.value.setHex( 0xffffff ); + uniformsTerrain.specular.value.setHex( 0xffffff ); + //uniformsTerrain.ambient.value.setHex( 0x111111 ); + } + + // this should also be accessible by a background-size value (with percentage conversion) + uniformsTerrain.uRepeatOverlay.value.set( options.repeat, options.repeat ); + // + + var material = new THREE.ShaderMaterial( { + uniforms : uniformsTerrain, + vertexShader : terrainShader.vertexShader, + fragmentShader : terrainShader.fragmentShader, + lights : options.lights, + fog : options.fog, + needsUpdate: true + }); + + return material; + +}; + +Terrain.prototype.basicMaterial = function(){ + + var material = new THREE.MeshBasicMaterial( { map: utils.pixel(), overdraw: 0.5 } ); + // + return material; +}; + +// Helpers + +// Terrain helper to compute elevation from heightmap +Terrain.prototype.computeElevation = function( texture ){ + // prerequisite + if( this._attributes.shader ) return; + var terrain = this; // method binded to terrain object + + // canvas for image processing + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext("2d"); + var img = texture.image; + // canvas takes the polygon dimensions | vertices = faces +1 for every side + var width = terrain.geometry.parameters.widthSegments + 1; + var height = terrain.geometry.parameters.heightSegments + 1; + var terrainScale = terrain._attributes.scale; //terrain.material.uniforms.uDisplacementScale.value; + var terrainBias = - terrain._attributes.scale/2; //terrain.material.uniforms.uDisplacementBias.value; + var size = terrain.geometry.parameters.width; // option? + //var scale = size / width; + // - main data + var vertices = terrain.geometry.attributes.position; + var d = []; + + canvas.width = width; + canvas.height = height; + + ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height); + // scale image to polygons + //ctx.scale(width/img.width, height/img.height); // already resized from drawImage + // loop through image data + var data = ctx.getImageData(0,0, width, height).data; + + for( var i in data ){ + if ( i % 4 ) continue; // pick only every forth - item size 4: RGBA + // OLD method: calculating the whole vector + //var z = ( Math.floor(i/width) ) - (size/2); + //var x = (i - ( Math.floor(i/width)*width)) - (size/2); + //var y = (data[i]/255 * terrainScale) + terrainBias; // normalize height to a fraction + //vertices.push( new THREE.Vector3(x, y, z) ); + //vertices.push( (data[i]/255 * terrainScale) + terrainBias ); + + // updating the z axis of the vertices directly + var z = ( (data[i]/255 * terrainScale) + terrainBias ); // terrain has z axis up... + // instead combine all colors? + //var decimal = (data[i]+data[i+1]+data[i+2])/(3*255); + d.push( z ); + vertices.setZ( i/4, z ); + } + + // update the vertices in the terrain object + terrain.geometry.attributes.position.needsUpdate = true; +}; + +Terrain.prototype.shaderTexture = function(type, img){ + + var texture = utils.textureLoader( img ); //this.webglTexture( img ); + + if( type == 'heightmap' ){ + var terrainScale = this._attributes.scale; // modified through an option + + this.material.uniforms.tDisplacement.value = texture; + this.material.uniforms.uDisplacementScale.value = terrainScale; + this.material.uniforms.uDisplacementBias.value = - terrainScale/2; + // heightmap also the second diffuse map? + //var diffuseTexture2 = texture; + //diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; + //this.material.uniforms.tDiffuse2.value = diffuseTexture2; + //this.material.uniforms.enableDiffuse2.value = true; + } + if( type == 'diffuse' ){ + + texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + + this.material.uniforms.tDiffuse1.value = texture; + this.material.uniforms.enableDiffuse1.value = true; + + } + if( type == 'specular' ){ + //var texture = this.webglTexture( img ); + //texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + + this.material.uniforms.tSpecular.value = texture; + this.material.uniforms.enableSpecular.value = true; + + } + // always update vertices... + // why don't these work with ShaderTerrain? + //this.geometry.attributes.position.needsUpdate = true; + //this.geometry.verticesNeedUpdate = true; + + /* + leftovers ( normal and detail textures) + + //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; + //uniformsTerrain[ "tNormal" ].value = heightmapTexture; + //uniformsTerrain[ "uNormalScale" ].value = 1; + //uniformsTerrain[ "tDetail" ].value = detailTexture; + //uniformsTerrain[ "uShininess" ].value = 30; + */ + + return texture; +}; + + +Terrain.prototype.basicTexture = function(type, img){ + var texture; + + if( type == 'heightmap' ){ + texture = utils.textureLoader( img, 'heightmap-loaded' ); + // texture isn't loaded in material, just used in computeElevation + // monitoring event + var self = this; + // remove pre-existing event... + var cb = function(e){ + self.computeElevation( texture ); + // trigger element event + self.$el.trigger('heightmap-updated'); + }; + document.removeEventListener('heightmap-loaded', cb); + document.addEventListener('heightmap-loaded', cb, false); + } + if( type == 'diffuse' ){ + texture = utils.textureLoader( img ); + var repeat = this._attributes.repeat; + // dirty re-write + texture.wrapT = THREE.RepeatWrapping; + texture.wrapS = THREE.RepeatWrapping; + texture.repeat.set( repeat, repeat ); + //texture.offset.set( 1, 1 ); + texture.needsUpdate = true; + + this.material.map = texture; + } + if( type == 'specular' ){ + // not supported? + } + + return texture; +}; + + // generic method to create an element Three.prototype.webgl = function( options, callback ){ // get the type from the tag name @@ -1215,6 +2017,9 @@ Three.prototype.webgl = function( options, callback ){ case "cylinder": el = this.webglCylinder( options ); break; + case "sprite": + el = this.webglSprite( options ); + break; case "terrain": el = this.webglTerrain( options ); break; @@ -1233,19 +2038,22 @@ fn.webgl = { }; -Three.prototype.webglScene = function( options ){ +Three.prototype.webglScene = function( attributes ){ var defaults = { id : false }; - var settings = $.extend(defaults, options); + var options = $.extend(defaults, attributes); var scene = new THREE.Scene(); // save in the objects bucket this.scenes[scene.id] = scene; + // save attributes + scene._attributes = options; + return scene; }; @@ -1271,6 +2079,9 @@ Three.prototype.webglCamera = function( attributes ){ camera = new THREE.PerspectiveCamera( options.fov, options.aspect, options.near, options.far ); } + // save attributes + camera._attributes = options; + return camera; }; @@ -1315,13 +2126,13 @@ Three.prototype.webglMaterial = function( attributes ){ if( shader.uniforms ) settings.uniforms = THREE.UniformsUtils.clone(shader.uniforms); if( shader.vertexShader ) settings.vertexShader = shader.vertexShader; if( shader.fragmentShader ) settings.fragmentShader = shader.fragmentShader; - if( options.map && shader.uniforms) settings.uniforms.texture.texture= THREE.ImageUtils.loadTexture( options.map ); + if( options.map && shader.uniforms) settings.uniforms.texture.texture= utils.textureLoader( options.map ); material = new THREE.ShaderMaterial( settings ); } else { // create a basic material settings = {}; - if( options.map ) settings.map = THREE.ImageUtils.loadTexture( options.map ); + if( options.map ) settings.map = utils.textureLoader( options.map ); if( options.color && !options.map ) settings.color = options.color; if( options.wireframe ) settings.wireframe = options.wireframe; material = new THREE.MeshBasicMaterial( settings ); @@ -1372,7 +2183,9 @@ Three.prototype.webglPlane = function( attributes ){ var options = $.extend(defaults, attributes); - var geometry = new THREE.PlaneGeometry( options.width, options.height ); + var Constructor = ( options.buffer ) ? THREE.PlaneBufferGeometry : THREE.PlaneGeometry; + + var geometry = new Constructor( options.width, options.height ); // make this optional? geometry.dynamic = true; var material = new THREE.MeshBasicMaterial( { color: options.color, wireframe: options.wireframe } ); @@ -1381,6 +2194,9 @@ Three.prototype.webglPlane = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; @@ -1410,6 +2226,9 @@ Three.prototype.webglSphere = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; @@ -1427,7 +2246,7 @@ Three.prototype.webglCube = function( attributes ){ var options = $.extend(defaults, attributes); - var geometry = new THREE.CubeGeometry( options.width, options.height, options.depth); + var geometry = new THREE.BoxGeometry( options.width, options.height, options.depth); // make this optional? geometry.dynamic = true; var material = new THREE.MeshBasicMaterial( { color: options.color, wireframe: options.wireframe } ); @@ -1436,6 +2255,9 @@ Three.prototype.webglCube = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; @@ -1465,92 +2287,81 @@ Three.prototype.webglCylinder = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; -Three.prototype.webglTerrain = function( attributes ){ - // assuming that terrain is generated from a heightmap - support class="mesh" in the future? - var terrain; - - var defaults = { - - }; +Three.prototype.webglSprite = function( attributes ){ + // sprite - this.active.scene.add( new THREE.AmbientLight( 0x111111 ) ); + attributes = attributes || {}; - directionalLight = new THREE.DirectionalLight( 0xffffff, 1.15 ); - directionalLight.position.set( 500, 2000, 0 ); - this.active.scene.add( directionalLight ); - - - var plane = new THREE.PlaneGeometry( 6000, 6000, 256, 256 ); - - plane.computeFaceNormals(); - plane.computeVertexNormals(); - plane.computeTangents(); - - // - - var terrainShader = THREE.ShaderTerrain.terrain; - - uniformsTerrain = THREE.UniformsUtils.clone( terrainShader.uniforms ); - /* - var heightmapTexture = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); - var diffuseTexture1 = THREE.ImageUtils.loadTexture( "assets/img/terrain/diffuse.jpg" ); - var diffuseTexture2 = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); - var specularMap = THREE.ImageUtils.loadTexture( "assets/img/terrain/specular.png"); - - diffuseTexture1.wrapS = diffuseTexture1.wrapT = THREE.RepeatWrapping; - diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; - //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; - specularMap.wrapS = specularMap.wrapT = THREE.RepeatWrapping; - - //uniformsTerrain[ "tNormal" ].value = heightmapTexture; - //uniformsTerrain[ "uNormalScale" ].value = 1; - - uniformsTerrain[ "tDisplacement" ].value = heightmapTexture; - uniformsTerrain[ "uDisplacementScale" ].value = 375; + var defaults = { + map : false, + color: 0xffffff, + fog: false, + transparent: true, + opacity: 1 + //alignment: THREE.SpriteAlignment.topLeft + //useScreenCoordinates: true + //scene: this.active.scene + }; - uniformsTerrain[ "tDiffuse1" ].value = diffuseTexture1; - uniformsTerrain[ "tDiffuse2" ].value = diffuseTexture2; - uniformsTerrain[ "tSpecular" ].value = specularMap; - //uniformsTerrain[ "tDetail" ].value = diffuseTexture1; + var options = $.extend(defaults, attributes); + // FIX map + if ( attributes.map ) { + options.map = utils.textureLoader( attributes.map ); + } else { + //placeholder pixel + options.map = utils.pixel(); + } + // save id (name) for later + var name = options.id; + // FIX: delete unsupported options (why not define the options supported?) + delete options.id; + delete options['class']; + delete options.el; + delete options.style; - uniformsTerrain[ "enableDiffuse1" ].value = true; - uniformsTerrain[ "enableDiffuse2" ].value = true; - uniformsTerrain[ "enableSpecular" ].value = true; + var material = new THREE.SpriteMaterial( options ); + material.scaleByViewport = true; + material.blending = THREE.AdditiveBlending; - uniformsTerrain[ "uDiffuseColor" ].value.setHex( 0xffffff ); - uniformsTerrain[ "uSpecularColor" ].value.setHex( 0xffffff ); - uniformsTerrain[ "uAmbientColor" ].value.setHex( 0x111111 ); + var sprite = new THREE.Sprite( material ); + // save name (id) back to the object + sprite.name = name; - //uniformsTerrain[ "uShininess" ].value = 30; + // save attributes + sprite._attributes = options; - uniformsTerrain[ "uRepeatOverlay" ].value.set( 6, 6 ); - */ + return sprite; - uniformsTerrain.uDiffuseColor.value.setHex( 0xffffff ); - uniformsTerrain.uSpecularColor.value.setHex( 0xffffff ); - uniformsTerrain.uAmbientColor.value.setHex( 0x111111 ); + }; - uniformsTerrain.uRepeatOverlay.value.set( 6, 6 ); - // +Three.prototype.webglTerrain = function( attributes ){ + // fallbacks + attributes = attributes || {}; - // fog is expensive - disable for now... - var material = new THREE.ShaderMaterial( { - uniforms : uniformsTerrain, - vertexShader : terrainShader.vertexShader, - fragmentShader : terrainShader.fragmentShader, - lights : true, - fog : false - }); + var defaults = { + lights: true, + fog: true, + scale: 256, + width: 6000, + height: 6000, + resolution: 256, + shader: true, + repeat: 1 // diffuse map repeat + }; - terrain = new THREE.Mesh( plane, material ); + var options = $.extend(defaults, attributes); - // save type as part of the mesh - terrain.type = "terrain"; + // logic contained + // assuming that terrain is generated from a heightmap - support class="mesh" in the future? + var terrain = (new Terrain( options )).terrain; //terrain.visible=false; this.active.scene.add( terrain ); @@ -1586,6 +2397,7 @@ Three.prototype.setProperties = function() { }; }; + // internal object of utilities var utils = { // Convert Dashed to CamelCase @@ -1594,12 +2406,287 @@ var utils = { return string.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); }, + // Based on undercore _.delay + delay: function (fn, timeout) { + timeout = timeout || 0; + var args = Array.prototype.slice.call(arguments, 2); + return setTimeout(function () { return fn.apply(null, args); }, timeout); + }, + // unique (but not universal) id generator unid: function(){ return Math.round( Math.random() * (new Date()).getTime() ); + }, + + now: function(){ + if( !performance || !performance.now ) return new Date().getTime(); + return Math.floor( performance.now() ); // are the fractions of a millisecond significant? + }, + // returns a 1x1 invisible texture + // used when we have no texture data + pixel: function(){ + var image = document.createElement( 'img' ); + var texture = new THREE.Texture( image ); + // not neeeded? + image.addEventListener( 'load', function ( event ) { + texture.needsUpdate = true; + } ); + image.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; + return texture; + }, + // texture loader (support legacy) + textureLoader: function( image, eventName ){ + var map = this.pixel(); + + if( THREE.REVISION < 70 ){ + // FIX: support base64 images + if( image.search(";base64,") > -1 ) image = image.replace(/data:image\/(png|jpg|jpeg);base64,/, ""); + map = THREE.ImageUtils.loadTexture( image ); + } else { + (new THREE.TextureLoader()).load(image, function( texture ){ + // update image source on the original map + map.image = texture.image; + map.needsUpdate = true; + // trigger event + if( eventName ){ + var event = new Event(eventName); + document.dispatchEvent( event ); + } + }); + } + // return immediantely (update asychronously) + return map; + }, + + // Convert the color information of an image to height data + // source: http://oos.moxiecode.com/js_webgl/terrain/index.html + getHeightData: function(img) { + var canvas = document.createElement( 'canvas' ); + canvas.width = 128; + canvas.height = 128; + var context = canvas.getContext( '2d' ); + + var size = 128 * 128, data = new Float32Array( size ); + + context.drawImage(img,0,0); + + for ( var i = 0; i < size; i ++ ) { + data[i] = 0; + } + + var imgd = context.getImageData(0, 0, 128, 128); + var pix = imgd.data; + + var j=0; + for (var k = 0, n = pix.length; k < n; k += (4)) { + var all = pix[k]+pix[k+1]+pix[k+2]; + data[j++] = all/30; + } + + return data; + }, + + getFile: function (url) { + // if already downloaded return the same content + if( files[url] ) return files[url]; + files[url] = $.ajax({ + type : "GET", + url : url, + dataType : "string", + async : false, + success : function(data) { + files[url] = data; + } + }).responseText; + return files[url]; + }, + + //THREE.BufferGeometryUtils + // @author mrdoob / http://mrdoob.com/ + computeTangents: function ( geometry ) { + + var index = geometry.index; + var attributes = geometry.attributes; + + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) + + if ( index === null || + attributes.position === undefined || + attributes.normal === undefined || + attributes.uv === undefined ) { + + console.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' ); + return; + + } + + var indices = index.array; + var positions = attributes.position.array; + var normals = attributes.normal.array; + var uvs = attributes.uv.array; + + var nVertices = positions.length / 3; + + if ( attributes.tangent === undefined ) { + + geometry.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); + + } + + var tangents = attributes.tangent.array; + + var tan1 = [], tan2 = []; + + for ( var k = 0; k < nVertices; k ++ ) { + + tan1[ k ] = new THREE.Vector3(); + tan2[ k ] = new THREE.Vector3(); + + } + + var vA = new THREE.Vector3(), + vB = new THREE.Vector3(), + vC = new THREE.Vector3(), + + uvA = new THREE.Vector2(), + uvB = new THREE.Vector2(), + uvC = new THREE.Vector2(), + + sdir = new THREE.Vector3(), + tdir = new THREE.Vector3(); + + function handleTriangle( a, b, c ) { + + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); + + uvA.fromArray( uvs, a * 2 ); + uvB.fromArray( uvs, b * 2 ); + uvC.fromArray( uvs, c * 2 ); + + var x1 = vB.x - vA.x; + var x2 = vC.x - vA.x; + + var y1 = vB.y - vA.y; + var y2 = vC.y - vA.y; + + var z1 = vB.z - vA.z; + var z2 = vC.z - vA.z; + + var s1 = uvB.x - uvA.x; + var s2 = uvC.x - uvA.x; + + var t1 = uvB.y - uvA.y; + var t2 = uvC.y - uvA.y; + + var r = 1.0 / ( s1 * t2 - s2 * t1 ); + + sdir.set( + ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r + ); + + tdir.set( + ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r + ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + var groups = geometry.groups; + var group, start, count; + + if ( groups.length === 0 ) { + + groups = [ { + start: 0, + count: indices.length + } ]; + + } + + for ( var j = 0; j < groups.length; ++ j ) { + + group = groups[ j ]; + + start = group.start; + count = group.count; + + for ( var g = start, gl = start + count; g < gl; g += 3 ) { + + handleTriangle( + indices[ g + 0 ], + indices[ g + 1 ], + indices[ g + 2 ] + ); + + } + + } + + var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); + var n = new THREE.Vector3(), n2 = new THREE.Vector3(); + var w, t, test; + + function handleVertex( v ) { + + n.fromArray( normals, v * 3 ); + n2.copy( n ); + + t = tan1[ v ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( n2, t ); + test = tmp2.dot( tan2[ v ] ); + w = ( test < 0.0 ) ? - 1.0 : 1.0; + + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; + + } + + for ( var l = 0; l < groups.length; ++ l ) { + + group = groups[ l ]; + + start = group.start; + count = group.count; + + for ( var i = start, il = start + count; i < il; i += 3 ) { + + handleVertex( indices[ i + 0 ] ); + handleVertex( indices[ i + 1 ] ); + handleVertex( indices[ i + 2 ] ); + + } + + } + } + }; + /** * jQuery.toSelector - get the selector text of a jQuery object * https://gist.github.com/tracend/6402299 @@ -1631,6 +2718,7 @@ var utils = { }( jQuery )); + // Prototype Three.prototype.css = css; Three.prototype.find = find; @@ -1644,4 +2732,4 @@ Three.prototype.lookAt = function(){ return this.fn.three.call(this, "lookAt", arguments); }; -})); \ No newline at end of file +})); diff --git a/component.json b/component.json index a1e3cdf..1bc1532 100644 --- a/component.json +++ b/component.json @@ -1,6 +1,6 @@ { "name": "jquery-three", - "version": "0.8.0", + "version": "0.9.8", "main": ["./build/jquery.three-min.js"], "dependencies": { "jquery": "~2.0.3" diff --git a/examples/assets/3d/palm/maps/palm_bark.jpg b/examples/assets/3d/palm/maps/palm_bark.jpg new file mode 100755 index 0000000..eb862aa Binary files /dev/null and b/examples/assets/3d/palm/maps/palm_bark.jpg differ diff --git a/examples/assets/3d/palm/maps/palm_bark_norm.jpg b/examples/assets/3d/palm/maps/palm_bark_norm.jpg new file mode 100755 index 0000000..b325503 Binary files /dev/null and b/examples/assets/3d/palm/maps/palm_bark_norm.jpg differ diff --git a/examples/assets/3d/palm/maps/palm_bark_spec.jpg b/examples/assets/3d/palm/maps/palm_bark_spec.jpg new file mode 100755 index 0000000..087ef5c Binary files /dev/null and b/examples/assets/3d/palm/maps/palm_bark_spec.jpg differ diff --git a/examples/assets/3d/palm/palm_leafs.png b/examples/assets/3d/palm/maps/palm_leafs.png old mode 100644 new mode 100755 similarity index 77% rename from examples/assets/3d/palm/palm_leafs.png rename to examples/assets/3d/palm/maps/palm_leafs.png index ade885d..cf9931e Binary files a/examples/assets/3d/palm/palm_leafs.png and b/examples/assets/3d/palm/maps/palm_leafs.png differ diff --git a/examples/assets/3d/palm/maps/palm_leafs_spec.jpg b/examples/assets/3d/palm/maps/palm_leafs_spec.jpg new file mode 100755 index 0000000..cf6f4a4 Binary files /dev/null and b/examples/assets/3d/palm/maps/palm_leafs_spec.jpg differ diff --git a/examples/assets/3d/palm/mesh.bin b/examples/assets/3d/palm/mesh.bin new file mode 100644 index 0000000..c7c5d5e Binary files /dev/null and b/examples/assets/3d/palm/mesh.bin differ diff --git a/examples/assets/3d/palm/mesh.js b/examples/assets/3d/palm/mesh.js new file mode 100644 index 0000000..b86ab07 --- /dev/null +++ b/examples/assets/3d/palm/mesh.js @@ -0,0 +1,51 @@ +{ + "metadata": { + "formatVersion": 0.6, + "sourceFile": "palm.obj", + "generatedBy": "three-obj", + "vertices": 537, + "faces": 399, + "normals": 490, + "colors": 0, + "uvs": 150, + "materials": 3 + }, + + "materials": [{ + "DbgName": "coconuts", + "DbgIndex": 0, + "DbgColor": 15597568, + "colorDiffuse": [1, 1, 1], + "colorSpecular": [1, 1, 1], + "illumination": 2, + "specularCoef": 8, + "mapDiffuse": "maps/palm_leafs.png", + "mapSpecular": "maps/palm_leafs_spec.jpg", + "transparent" : false + }, { + "DbgName": "trunk", + "DbgIndex": 1, + "DbgColor": 15658734, + "colorDiffuse": [1, 1, 1], + "colorSpecular": [1, 1, 1], + "illumination": 2, + "specularCoef": 8, + "mapDiffuse": "maps/palm_bark.jpg", + "mapBump": "maps/palm_bark_norm.jpg", + "mapSpecular": "maps/palm_bark_spec.jpg", + "transparent" : false + }, { + "DbgName": "branches", + "DbgIndex": 2, + "DbgColor": 60928, + "colorDiffuse": [1, 1, 1], + "colorSpecular": [1, 1, 1], + "illumination": 2, + "specularCoef": 8, + "mapDiffuse": "maps/palm_leafs.png", + "mapSpecular": "maps/palm_leafs_spec.jpg", + "opacity" : 1.0, + "transparent" : true + }], + "buffers": "mesh.bin" +} diff --git a/examples/assets/3d/palm/palm.bin b/examples/assets/3d/palm/palm.bin deleted file mode 100644 index e5dbf7e..0000000 Binary files a/examples/assets/3d/palm/palm.bin and /dev/null differ diff --git a/examples/assets/3d/palm/palm.js b/examples/assets/3d/palm/palm.js deleted file mode 100644 index 2be891e..0000000 --- a/examples/assets/3d/palm/palm.js +++ /dev/null @@ -1,45 +0,0 @@ -{ - - "metadata" : - { - "formatVersion" : 3.1, - "sourceFile" : "palm.obj", - "generatedBy" : "OBJConverter", - "vertices" : 534, - "faces" : 398, - "normals" : 490, - "uvs" : 147, - "materials" : 2 - }, - - "materials": [{ - "DbgColor" : 15658734, - "DbgIndex" : 0, - "DbgName" : "trunk", - "colorAmbient" : [0.8, 0.8, 0.8], - "colorDiffuse" : [1.0, 1.0, 1.0], - "colorSpecular" : [1.0, 1.0, 1.0], - "illumination" : 2, - "mapBump" : "palm_bark_norm.png", - "mapDiffuse" : "palm_bark.png", - "specularCoef" : 8.0, - "transparent" : false - }, - - { - "DbgColor" : 15597568, - "DbgIndex" : 1, - "DbgName" : "branches", - "colorAmbient" : [0.8, 0.8, 0.8], - "colorDiffuse" : [1.0, 1.0, 1.0], - "colorSpecular" : [1.0, 1.0, 1.0], - "illumination" : 2, - "mapDiffuse" : "palm_leafs.png", - "specularCoef" : 8.0, - "transparency" : 1.0, - "transparent" : true - }], - - "buffers": "palm.bin" - -} diff --git a/examples/assets/3d/palm/palm_bark.png b/examples/assets/3d/palm/palm_bark.png deleted file mode 100644 index 5807ac6..0000000 Binary files a/examples/assets/3d/palm/palm_bark.png and /dev/null differ diff --git a/examples/assets/3d/palm/palm_bark_norm.png b/examples/assets/3d/palm/palm_bark_norm.png deleted file mode 100644 index d4189e6..0000000 Binary files a/examples/assets/3d/palm/palm_bark_norm.png and /dev/null differ diff --git a/examples/assets/3d/palm/palm_bark_spec.png b/examples/assets/3d/palm/palm_bark_spec.png deleted file mode 100644 index 08d5432..0000000 Binary files a/examples/assets/3d/palm/palm_bark_spec.png and /dev/null differ diff --git a/examples/assets/3d/palm/palm_leafs_spec.png b/examples/assets/3d/palm/palm_leafs_spec.png deleted file mode 100644 index f500de0..0000000 Binary files a/examples/assets/3d/palm/palm_leafs_spec.png and /dev/null differ diff --git a/examples/assets/css/styles.css b/examples/assets/css/styles.css new file mode 100644 index 0000000..3c8a25e --- /dev/null +++ b/examples/assets/css/styles.css @@ -0,0 +1,23 @@ +/* reset */ +html, body { + margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; +} + +#main { + width: 100%; + height: 100%; +} + +header { + position: fixed; + width: 100%; + padding: 24px; + background: rgba( 0, 0, 0, 0.5 ); + color: #fff; + font-size: 1.5em; + z-index: 9999; +} + +header a { + color: #fff; +} diff --git a/examples/assets/img/deviantart-hero_walk_cycle_spritesheet_by_mrnoobtastic-d3defej.png b/examples/assets/img/deviantart-hero_walk_cycle_spritesheet_by_mrnoobtastic-d3defej.png new file mode 100644 index 0000000..4286393 Binary files /dev/null and b/examples/assets/img/deviantart-hero_walk_cycle_spritesheet_by_mrnoobtastic-d3defej.png differ diff --git a/examples/assets/img/skysphere.jpg b/examples/assets/img/skysphere.jpg new file mode 100644 index 0000000..fd63641 Binary files /dev/null and b/examples/assets/img/skysphere.jpg differ diff --git a/examples/assets/img/sprite_king.png b/examples/assets/img/sprite_king.png new file mode 100755 index 0000000..80e934f Binary files /dev/null and b/examples/assets/img/sprite_king.png differ diff --git a/examples/assets/img/terrain/heightmap.png b/examples/assets/img/terrain/heightmap.png index 3ec8c35..fb037ec 100644 Binary files a/examples/assets/img/terrain/heightmap.png and b/examples/assets/img/terrain/heightmap.png differ diff --git a/examples/assets/img/waternormals.jpg b/examples/assets/img/waternormals.jpg new file mode 100644 index 0000000..9dfe03c Binary files /dev/null and b/examples/assets/img/waternormals.jpg differ diff --git a/examples/assets/js/ShaderTerrain.js b/examples/assets/js/ShaderTerrain.js deleted file mode 100644 index 23514ae..0000000 --- a/examples/assets/js/ShaderTerrain.js +++ /dev/null @@ -1,377 +0,0 @@ -/** - * @author alteredq / http://alteredqualia.com/ - * - */ - -THREE.ShaderTerrain = { - - /* ------------------------------------------------------------------------- - // Dynamic terrain shader - // - Blinn-Phong - // - height + normal + diffuse1 + diffuse2 + specular + detail maps - // - point, directional and hemisphere lights (use with "lights: true" material option) - // - shadow maps receiving - ------------------------------------------------------------------------- */ - - 'terrain' : { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], - - { - - "enableDiffuse1" : { type: "i", value: 0 }, - "enableDiffuse2" : { type: "i", value: 0 }, - "enableSpecular" : { type: "i", value: 0 }, - "enableReflection": { type: "i", value: 0 }, - - "tDiffuse1" : { type: "t", value: null }, - "tDiffuse2" : { type: "t", value: null }, - "tDetail" : { type: "t", value: null }, - "tNormal" : { type: "t", value: null }, - "tSpecular" : { type: "t", value: null }, - "tDisplacement": { type: "t", value: null }, - - "uNormalScale": { type: "f", value: 1.0 }, - - "uDisplacementBias": { type: "f", value: 0.0 }, - "uDisplacementScale": { type: "f", value: 1.0 }, - - "uDiffuseColor": { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) }, - "uAmbientColor": { type: "c", value: new THREE.Color( 0x050505 ) }, - "uShininess": { type: "f", value: 30 }, - "uOpacity": { type: "f", value: 1 }, - - "uRepeatBase" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, - "uRepeatOverlay" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, - - "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) } - - } - - ] ), - - fragmentShader: [ - - "uniform vec3 uAmbientColor;", - "uniform vec3 uDiffuseColor;", - "uniform vec3 uSpecularColor;", - "uniform float uShininess;", - "uniform float uOpacity;", - - "uniform bool enableDiffuse1;", - "uniform bool enableDiffuse2;", - "uniform bool enableSpecular;", - - "uniform sampler2D tDiffuse1;", - "uniform sampler2D tDiffuse2;", - "uniform sampler2D tDetail;", - "uniform sampler2D tNormal;", - "uniform sampler2D tSpecular;", - "uniform sampler2D tDisplacement;", - - "uniform float uNormalScale;", - - "uniform vec2 uRepeatOverlay;", - "uniform vec2 uRepeatBase;", - - "uniform vec2 uOffset;", - - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", - - "uniform vec3 ambientLightColor;", - - "#if MAX_DIR_LIGHTS > 0", - - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightPosition[ MAX_HEMI_LIGHTS ];", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", - - "#endif", - - "varying vec3 vViewPosition;", - - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - - "void main() {", - - "gl_FragColor = vec4( vec3( 1.0 ), uOpacity );", - - "vec3 specularTex = vec3( 1.0 );", - - "vec2 uvOverlay = uRepeatOverlay * vUv + uOffset;", - "vec2 uvBase = uRepeatBase * vUv;", - - "vec3 normalTex = texture2D( tDetail, uvOverlay ).xyz * 2.0 - 1.0;", - "normalTex.xy *= uNormalScale;", - "normalTex = normalize( normalTex );", - - "if( enableDiffuse1 && enableDiffuse2 ) {", - - "vec4 colDiffuse1 = texture2D( tDiffuse1, uvOverlay );", - "vec4 colDiffuse2 = texture2D( tDiffuse2, uvOverlay );", - - "#ifdef GAMMA_INPUT", - - "colDiffuse1.xyz *= colDiffuse1.xyz;", - "colDiffuse2.xyz *= colDiffuse2.xyz;", - - "#endif", - - "gl_FragColor = gl_FragColor * mix ( colDiffuse1, colDiffuse2, 1.0 - texture2D( tDisplacement, uvBase ) );", - - " } else if( enableDiffuse1 ) {", - - "gl_FragColor = gl_FragColor * texture2D( tDiffuse1, uvOverlay );", - - "} else if( enableDiffuse2 ) {", - - "gl_FragColor = gl_FragColor * texture2D( tDiffuse2, uvOverlay );", - - "}", - - "if( enableSpecular )", - "specularTex = texture2D( tSpecular, uvOverlay ).xyz;", - - "mat3 tsb = mat3( vTangent, vBinormal, vNormal );", - "vec3 finalNormal = tsb * normalTex;", - - "vec3 normal = normalize( finalNormal );", - "vec3 viewPosition = normalize( vViewPosition );", - - // point lights - - "#if MAX_POINT_LIGHTS > 0", - - "vec3 pointDiffuse = vec3( 0.0 );", - "vec3 pointSpecular = vec3( 0.0 );", - - "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - - "float lDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", - - "lVector = normalize( lVector );", - - "vec3 pointHalfVector = normalize( lVector + viewPosition );", - "float pointDistance = lDistance;", - - "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - "float pointDiffuseWeight = max( dot( normal, lVector ), 0.0 );", - - "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );", - - "pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;", - "pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;", - - "}", - - "#endif", - - // directional lights - - "#if MAX_DIR_LIGHTS > 0", - - "vec3 dirDiffuse = vec3( 0.0 );", - "vec3 dirSpecular = vec3( 0.0 );", - - "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", - - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - - "vec3 dirVector = normalize( lDirection.xyz );", - "vec3 dirHalfVector = normalize( dirVector + viewPosition );", - - "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", - - "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );", - - "dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;", - "dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;", - - "}", - - "#endif", - - // hemisphere lights - - "#if MAX_HEMI_LIGHTS > 0", - - "vec3 hemiDiffuse = vec3( 0.0 );", - "vec3 hemiSpecular = vec3( 0.0 );" , - - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( hemisphereLightPosition[ i ], 1.0 );", - "vec3 lVector = normalize( lPosition.xyz + vViewPosition.xyz );", - - // diffuse - - "float dotProduct = dot( normal, lVector );", - "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", - - "hemiDiffuse += uDiffuseColor * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", - - // specular (sky light) - - "float hemiSpecularWeight = 0.0;", - - "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", - "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - "hemiSpecularWeight += specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );", - - // specular (ground light) - - "vec3 lVectorGround = normalize( -lPosition.xyz + vViewPosition.xyz );", - - "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", - "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - "hemiSpecularWeight += specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );", - - "hemiSpecular += uSpecularColor * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ) * hemiSpecularWeight * hemiDiffuseWeight;", - - "}", - - "#endif", - - // all lights contribution summation - - "vec3 totalDiffuse = vec3( 0.0 );", - "vec3 totalSpecular = vec3( 0.0 );", - - "#if MAX_DIR_LIGHTS > 0", - - "totalDiffuse += dirDiffuse;", - "totalSpecular += dirSpecular;", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "totalDiffuse += hemiDiffuse;", - "totalSpecular += hemiSpecular;", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "totalDiffuse += pointDiffuse;", - "totalSpecular += pointSpecular;", - - "#endif", - - //"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor) + totalSpecular;", - "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );", - - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join("\n"), - - vertexShader: [ - - "attribute vec4 tangent;", - - "uniform vec2 uRepeatBase;", - - "uniform sampler2D tNormal;", - - "#ifdef VERTEX_TEXTURES", - - "uniform sampler2D tDisplacement;", - "uniform float uDisplacementScale;", - "uniform float uDisplacementBias;", - - "#endif", - - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", - - "varying vec3 vViewPosition;", - - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - - "void main() {", - - "vNormal = normalize( normalMatrix * normal );", - - // tangent and binormal vectors - - "vTangent = normalize( normalMatrix * tangent.xyz );", - - "vBinormal = cross( vNormal, vTangent ) * tangent.w;", - "vBinormal = normalize( vBinormal );", - - // texture coordinates - - "vUv = uv;", - - "vec2 uvBase = uv * uRepeatBase;", - - // displacement mapping - - "#ifdef VERTEX_TEXTURES", - - "vec3 dv = texture2D( tDisplacement, uvBase ).xyz;", - "float df = uDisplacementScale * dv.x + uDisplacementBias;", - "vec3 displacedPosition = normal * df + position;", - - "vec4 mPosition = modelMatrix * vec4( displacedPosition, 1.0 );", - "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", - - "#else", - - "vec4 mPosition = modelMatrix * vec4( position, 1.0 );", - "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - - "#endif", - - "gl_Position = projectionMatrix * mvPosition;", - - "vViewPosition = -mvPosition.xyz;", - - "vec3 normalTex = texture2D( tNormal, uvBase ).xyz * 2.0 - 1.0;", - "vNormal = normalMatrix * normalTex;", - - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n") - - } - -}; diff --git a/examples/assets/js/helpers/lookaround.js b/examples/assets/js/helpers/lookaround.js index 30f4c50..a5e33eb 100644 --- a/examples/assets/js/helpers/lookaround.js +++ b/examples/assets/js/helpers/lookaround.js @@ -4,7 +4,7 @@ var mouseX = 0; var mouseY = 0; -LookArround = function(e){ +LookAround = function(e){ // the 3d environment is passed as target var $3d = e.target; diff --git a/examples/assets/js/helpers/three.obj.js b/examples/assets/js/helpers/three.bin.js similarity index 59% rename from examples/assets/js/helpers/three.obj.js rename to examples/assets/js/helpers/three.bin.js index 3706233..08a8f74 100644 --- a/examples/assets/js/helpers/three.obj.js +++ b/examples/assets/js/helpers/three.bin.js @@ -1,31 +1,41 @@ (function(){ - + // Requires the BinaryLoader extension - Three.prototype.fn.webgl.obj = function( options, callback ){ + Three.prototype.fn.webgl.obj = function( options, callback ){ // define the group (once) if( !this.groups['obj'] ) this.groups['obj'] = "objects"; - + // model var self = this; - + loader = new THREE.BinaryLoader( true ); - + loader.load( options.src, function ( geometry, materials ) { - + for( var i in materials ){ + //console.log(); + materials[i].side = THREE.DoubleSide; + //materials[i].transparent = true; + //materials[i].depthTest = false; + if( materials[i].transparent ){ + // smooth antialias + materials[i].renderDepth = true; + materials[i].depthWrite = false; + } + } var object = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(materials) ); - + object.geometry = geometry; object.material = new THREE.MeshFaceMaterial(materials); //object.material.side = THREE.DoubleSide; - // save id as name + // save id as name if( options.id ) object.name = options.id; - + self.active.scene.add( object ); - + callback( object ); - + }); - + } - + })(); diff --git a/examples/assets/js/helpers/three.water.js b/examples/assets/js/helpers/three.water.js new file mode 100644 index 0000000..be3bc9d --- /dev/null +++ b/examples/assets/js/helpers/three.water.js @@ -0,0 +1,87 @@ +(function(){ + + // Requires the BinaryLoader extension + Three.prototype.fn.webgl.water = function( attributes, callback ){ + // define the group (once) + if( !this.groups['water'] ) this.groups['water'] = "objects"; + // var self = this; + // plane - by default a 1x1 square + var defaults = { + width: 1, + height: 1, + //color: 0x000000, + wireframe: false, + scene: this.active.scene + }; + // extend options + var options = $.extend(defaults, attributes); + // load normals + var waterNormals; + if( THREE.REVISION < 70 ){ + waterNormals = new THREE.ImageUtils.loadTexture('assets/img/waternormals.jpg'); + } else { + var textureLoader = new THREE.TextureLoader(); // requires THREE > v7x + waterNormals = textureLoader.load('assets/img/waternormals.jpg'); + } + waterNormals.wrapS = waterNormals.wrapT = THREE.RepeatWrapping; + // add a light to see the water reflection + /*var directionalLight = new THREE.DirectionalLight(0xffff55, 1); // light color as option... + directionalLight.position.set(-600, 300, 600); // position as option... + /*var directionalLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 1 ); + directionalLight.color.setHSL( 0.6, 1, 0.6 ); + directionalLight.groundColor.setHSL( 0.095, 1, 0.75 ); + directionalLight.position.set( 0, 500, 0 );*/ + //this.active.scene.add(directionalLight); + // generate geometry + var Constructor = ( THREE.REVISION < 70 ) ? THREE.PlaneGeometry : THREE.PlaneBufferGeometry; + var geometry = new Constructor( options.width, options.height, 10, 10); // polygon density as option... + // make this optional? + //geometry.dynamic = true; + // Create the water effect + var water = new THREE.Water(this.renderer, this.active.camera, this.active.scene, { + textureWidth: 256, + textureHeight: 256, + waterNormals: waterNormals, + alpha: 1.0, + //sunDirection: directionalLight.position.normalize(), + sunColor: 0xffffff, + waterColor: 0x001e0f, + betaVersion: 0, + side: THREE.DoubleSide + }); + + var mesh = new THREE.Mesh( geometry, water.material ); + // preserve reference to water object + mesh.add(water); + + //new THREE.PlaneBufferGeometry(2000, 2000, 10, 10), + + // set attributes + mesh.name = "water"; // use tagName instead? + if( options.id ) mesh.name += options.id; + + // add object to scene (will be done later when an Object3D is created) + //this.active.scene.add( mesh ); + + // events + $(this.el).on('update', function(e){ + var $3d = e.target; + // loop to find the water object(s) + for( var i in $3d.objects ){ + var obj = $3d.objects[i]; + // use .find() instead? + if(obj.name.search('water') === 0){ + var water = obj.children[0].children[0]; // not expecting any other objects here? + water.material.uniforms.time.value += 1.0 / 60.0; + water.render(); + $3d.renderer.render($3d.active.scene, $3d.active.camera); + } + } + }); + + // return using callback + callback( mesh ); + + } + +})(); diff --git a/examples/assets/js/libs/BinaryLoader.js b/examples/assets/js/libs/BinaryLoader.js index ae70d8d..28734b2 100644 --- a/examples/assets/js/libs/BinaryLoader.js +++ b/examples/assets/js/libs/BinaryLoader.js @@ -2,766 +2,718 @@ * @author alteredq / http://alteredqualia.com/ */ -THREE.BinaryLoader = function ( showStatus ) { +THREE.BinaryLoader = function ( manager ) { - THREE.Loader.call( this, showStatus ); + if ( typeof manager === 'boolean' ) { -}; - -THREE.BinaryLoader.prototype = Object.create( THREE.Loader.prototype ); - -// Load models generated by slim OBJ converter with BINARY option (converter_obj_three_slim.py -t binary) -// - binary models consist of two files: JS and BIN -// - parameters -// - url (required) -// - callback (required) -// - texturePath (optional: if not specified, textures will be assumed to be in the same folder as JS model file) -// - binaryPath (optional: if not specified, binary file will be assumed to be in the same folder as JS model file) - -THREE.BinaryLoader.prototype.load = function( url, callback, texturePath, binaryPath ) { - - // todo: unify load API to for easier SceneLoader use - - texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); - binaryPath = binaryPath && ( typeof binaryPath === "string" ) ? binaryPath : this.extractUrlBase( url ); + console.warn( 'THREE.BinaryLoader: showStatus parameter has been removed from constructor.' ); + manager = undefined; - var callbackProgress = this.showProgress ? THREE.Loader.prototype.updateProgress : null; + } - this.onLoadStart(); - - // #1 load JS part via web worker - - this.loadAjaxJSON( this, url, callback, texturePath, binaryPath, callbackProgress ); + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; -THREE.BinaryLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, binaryPath, callbackProgress ) { - - var xhr = new XMLHttpRequest(); +THREE.BinaryLoader.prototype = { - xhr.onreadystatechange = function () { + constructor: THREE.BinaryLoader, - if ( xhr.readyState == 4 ) { + // Deprecated - if ( xhr.status == 200 || xhr.status == 0 ) { + get statusDomElement () { - var json = JSON.parse( xhr.responseText ); - context.loadAjaxBuffers( json, callback, binaryPath, texturePath, callbackProgress ); + if ( this._statusDomElement === undefined ) { - } else { - - console.error( "THREE.BinaryLoader: Couldn't load [" + url + "] [" + xhr.status + "]" ); - - } + this._statusDomElement = document.createElement( 'div' ); } - }; + console.warn( 'THREE.BinaryLoader: .statusDomElement has been removed.' ); + return this._statusDomElement; - xhr.open( "GET", url, true ); - xhr.send( null ); + }, -}; - -THREE.BinaryLoader.prototype.loadAjaxBuffers = function ( json, callback, binaryPath, texturePath, callbackProgress ) { - - var xhr = new XMLHttpRequest(), - url = binaryPath + "/" + json.buffers; + // Load models generated by slim OBJ converter with BINARY option (converter_obj_three_slim.py -t binary) + // - binary models consist of two files: JS and BIN + // - parameters + // - url (required) + // - callback (required) + // - texturePath (optional: if not specified, textures will be assumed to be in the same folder as JS model file) + // - binaryPath (optional: if not specified, binary file will be assumed to be in the same folder as JS model file) + load: function ( url, onLoad, onProgress, onError ) { - var length = 0; + // todo: unify load API to for easier SceneLoader use - xhr.onreadystatechange = function () { + var texturePath = this.texturePath || THREE.Loader.prototype.extractUrlBase( url ); + var binaryPath = this.binaryPath || THREE.Loader.prototype.extractUrlBase( url ); - if ( xhr.readyState == 4 ) { + // #1 load JS part via web worker - if ( xhr.status == 200 || xhr.status == 0 ) { + var scope = this; - var buffer = xhr.response; - if ( buffer === undefined ) buffer = ( new Uint8Array( xhr.responseBody ) ).buffer; // IEWEBGL needs this - THREE.BinaryLoader.prototype.createBinModel( buffer, callback, texturePath, json.materials ); + var jsonloader = new THREE.XHRLoader( this.manager ); + jsonloader.load( url, function ( data ) { - } else { - - console.error( "THREE.BinaryLoader: Couldn't load [" + url + "] [" + xhr.status + "]" ); - - } + var json = JSON.parse( data ); - } else if ( xhr.readyState == 3 ) { + var bufferUrl = binaryPath + json.buffers; - if ( callbackProgress ) { + var bufferLoader = new THREE.XHRLoader( scope.manager ); + bufferLoader.setResponseType( 'arraybuffer' ); + bufferLoader.load( bufferUrl, function ( bufData ) { - if ( length == 0 ) { + // IEWEBGL needs this ??? + //buffer = ( new Uint8Array( xhr.responseBody ) ).buffer; - length = xhr.getResponseHeader( "Content-Length" ); + //// iOS and other XMLHttpRequest level 1 ??? - } + scope.parse( bufData, onLoad, texturePath, json.materials ); - callbackProgress( { total: length, loaded: xhr.responseText.length } ); + }, onProgress, onError ); - } + }, onProgress, onError ); - } else if ( xhr.readyState == 2 ) { + }, - length = xhr.getResponseHeader( "Content-Length" ); + setBinaryPath: function ( value ) { - } + this.binaryPath = value; - }; + }, - xhr.open( "GET", url, true ); - xhr.responseType = "arraybuffer"; - xhr.send( null ); + setCrossOrigin: function ( value ) { -}; + this.crossOrigin = value; -// Binary AJAX parser + }, -THREE.BinaryLoader.prototype.createBinModel = function ( data, callback, texturePath, jsonMaterials ) { + setTexturePath: function ( value ) { - var Model = function ( texturePath ) { + this.texturePath = value; - var scope = this, - currentOffset = 0, - md, - normals = [], - uvs = [], - start_tri_flat, start_tri_smooth, start_tri_flat_uv, start_tri_smooth_uv, - start_quad_flat, start_quad_smooth, start_quad_flat_uv, start_quad_smooth_uv, - tri_size, quad_size, - len_tri_flat, len_tri_smooth, len_tri_flat_uv, len_tri_smooth_uv, - len_quad_flat, len_quad_smooth, len_quad_flat_uv, len_quad_smooth_uv; + }, + parse: function ( data, callback, texturePath, jsonMaterials ) { - THREE.Geometry.call( this ); + var Model = function ( texturePath ) { - md = parseMetaData( data, currentOffset ); + var scope = this, + currentOffset = 0, + md, + normals = [], + uvs = [], + start_tri_flat, start_tri_smooth, start_tri_flat_uv, start_tri_smooth_uv, + start_quad_flat, start_quad_smooth, start_quad_flat_uv, start_quad_smooth_uv, + tri_size, quad_size, + len_tri_flat, len_tri_smooth, len_tri_flat_uv, len_tri_smooth_uv, + len_quad_flat, len_quad_smooth, len_quad_flat_uv, len_quad_smooth_uv; - currentOffset += md.header_bytes; -/* - md.vertex_index_bytes = Uint32Array.BYTES_PER_ELEMENT; - md.material_index_bytes = Uint16Array.BYTES_PER_ELEMENT; - md.normal_index_bytes = Uint32Array.BYTES_PER_ELEMENT; - md.uv_index_bytes = Uint32Array.BYTES_PER_ELEMENT; -*/ - // buffers sizes - tri_size = md.vertex_index_bytes * 3 + md.material_index_bytes; - quad_size = md.vertex_index_bytes * 4 + md.material_index_bytes; + THREE.Geometry.call( this ); - len_tri_flat = md.ntri_flat * ( tri_size ); - len_tri_smooth = md.ntri_smooth * ( tri_size + md.normal_index_bytes * 3 ); - len_tri_flat_uv = md.ntri_flat_uv * ( tri_size + md.uv_index_bytes * 3 ); - len_tri_smooth_uv = md.ntri_smooth_uv * ( tri_size + md.normal_index_bytes * 3 + md.uv_index_bytes * 3 ); + md = parseMetaData( data, currentOffset ); - len_quad_flat = md.nquad_flat * ( quad_size ); - len_quad_smooth = md.nquad_smooth * ( quad_size + md.normal_index_bytes * 4 ); - len_quad_flat_uv = md.nquad_flat_uv * ( quad_size + md.uv_index_bytes * 4 ); - len_quad_smooth_uv = md.nquad_smooth_uv * ( quad_size + md.normal_index_bytes * 4 + md.uv_index_bytes * 4 ); + currentOffset += md.header_bytes; + /* + md.vertex_index_bytes = Uint32Array.BYTES_PER_ELEMENT; + md.material_index_bytes = Uint16Array.BYTES_PER_ELEMENT; + md.normal_index_bytes = Uint32Array.BYTES_PER_ELEMENT; + md.uv_index_bytes = Uint32Array.BYTES_PER_ELEMENT; + */ + // buffers sizes - // read buffers + tri_size = md.vertex_index_bytes * 3 + md.material_index_bytes; + quad_size = md.vertex_index_bytes * 4 + md.material_index_bytes; - currentOffset += init_vertices( currentOffset ); + len_tri_flat = md.ntri_flat * ( tri_size ); + len_tri_smooth = md.ntri_smooth * ( tri_size + md.normal_index_bytes * 3 ); + len_tri_flat_uv = md.ntri_flat_uv * ( tri_size + md.uv_index_bytes * 3 ); + len_tri_smooth_uv = md.ntri_smooth_uv * ( tri_size + md.normal_index_bytes * 3 + md.uv_index_bytes * 3 ); - currentOffset += init_normals( currentOffset ); - currentOffset += handlePadding( md.nnormals * 3 ); + len_quad_flat = md.nquad_flat * ( quad_size ); + len_quad_smooth = md.nquad_smooth * ( quad_size + md.normal_index_bytes * 4 ); + len_quad_flat_uv = md.nquad_flat_uv * ( quad_size + md.uv_index_bytes * 4 ); + len_quad_smooth_uv = md.nquad_smooth_uv * ( quad_size + md.normal_index_bytes * 4 + md.uv_index_bytes * 4 ); - currentOffset += init_uvs( currentOffset ); + // read buffers - start_tri_flat = currentOffset; - start_tri_smooth = start_tri_flat + len_tri_flat + handlePadding( md.ntri_flat * 2 ); - start_tri_flat_uv = start_tri_smooth + len_tri_smooth + handlePadding( md.ntri_smooth * 2 ); - start_tri_smooth_uv = start_tri_flat_uv + len_tri_flat_uv + handlePadding( md.ntri_flat_uv * 2 ); + currentOffset += init_vertices( currentOffset ); - start_quad_flat = start_tri_smooth_uv + len_tri_smooth_uv + handlePadding( md.ntri_smooth_uv * 2 ); - start_quad_smooth = start_quad_flat + len_quad_flat + handlePadding( md.nquad_flat * 2 ); - start_quad_flat_uv = start_quad_smooth + len_quad_smooth + handlePadding( md.nquad_smooth * 2 ); - start_quad_smooth_uv= start_quad_flat_uv + len_quad_flat_uv + handlePadding( md.nquad_flat_uv * 2 ); + currentOffset += init_normals( currentOffset ); + currentOffset += handlePadding( md.nnormals * 3 ); - // have to first process faces with uvs - // so that face and uv indices match + currentOffset += init_uvs( currentOffset ); - init_triangles_flat_uv( start_tri_flat_uv ); - init_triangles_smooth_uv( start_tri_smooth_uv ); + start_tri_flat = currentOffset; + start_tri_smooth = start_tri_flat + len_tri_flat + handlePadding( md.ntri_flat * 2 ); + start_tri_flat_uv = start_tri_smooth + len_tri_smooth + handlePadding( md.ntri_smooth * 2 ); + start_tri_smooth_uv = start_tri_flat_uv + len_tri_flat_uv + handlePadding( md.ntri_flat_uv * 2 ); - init_quads_flat_uv( start_quad_flat_uv ); - init_quads_smooth_uv( start_quad_smooth_uv ); + start_quad_flat = start_tri_smooth_uv + len_tri_smooth_uv + handlePadding( md.ntri_smooth_uv * 2 ); + start_quad_smooth = start_quad_flat + len_quad_flat + handlePadding( md.nquad_flat * 2 ); + start_quad_flat_uv = start_quad_smooth + len_quad_smooth + handlePadding( md.nquad_smooth * 2 ); + start_quad_smooth_uv = start_quad_flat_uv + len_quad_flat_uv + handlePadding( md.nquad_flat_uv * 2 ); - // now we can process untextured faces + // have to first process faces with uvs + // so that face and uv indices match - init_triangles_flat( start_tri_flat ); - init_triangles_smooth( start_tri_smooth ); + init_triangles_flat_uv( start_tri_flat_uv ); + init_triangles_smooth_uv( start_tri_smooth_uv ); - init_quads_flat( start_quad_flat ); - init_quads_smooth( start_quad_smooth ); + init_quads_flat_uv( start_quad_flat_uv ); + init_quads_smooth_uv( start_quad_smooth_uv ); - this.computeCentroids(); - this.computeFaceNormals(); + // now we can process untextured faces - function handlePadding( n ) { + init_triangles_flat( start_tri_flat ); + init_triangles_smooth( start_tri_smooth ); - return ( n % 4 ) ? ( 4 - n % 4 ) : 0; + init_quads_flat( start_quad_flat ); + init_quads_smooth( start_quad_smooth ); - }; + this.computeFaceNormals(); - function parseMetaData( data, offset ) { - - var metaData = { - - 'signature' :parseString( data, offset, 12 ), - 'header_bytes' :parseUChar8( data, offset + 12 ), - - 'vertex_coordinate_bytes' :parseUChar8( data, offset + 13 ), - 'normal_coordinate_bytes' :parseUChar8( data, offset + 14 ), - 'uv_coordinate_bytes' :parseUChar8( data, offset + 15 ), - - 'vertex_index_bytes' :parseUChar8( data, offset + 16 ), - 'normal_index_bytes' :parseUChar8( data, offset + 17 ), - 'uv_index_bytes' :parseUChar8( data, offset + 18 ), - 'material_index_bytes' :parseUChar8( data, offset + 19 ), - - 'nvertices' :parseUInt32( data, offset + 20 ), - 'nnormals' :parseUInt32( data, offset + 20 + 4*1 ), - 'nuvs' :parseUInt32( data, offset + 20 + 4*2 ), - - 'ntri_flat' :parseUInt32( data, offset + 20 + 4*3 ), - 'ntri_smooth' :parseUInt32( data, offset + 20 + 4*4 ), - 'ntri_flat_uv' :parseUInt32( data, offset + 20 + 4*5 ), - 'ntri_smooth_uv' :parseUInt32( data, offset + 20 + 4*6 ), - - 'nquad_flat' :parseUInt32( data, offset + 20 + 4*7 ), - 'nquad_smooth' :parseUInt32( data, offset + 20 + 4*8 ), - 'nquad_flat_uv' :parseUInt32( data, offset + 20 + 4*9 ), - 'nquad_smooth_uv' :parseUInt32( data, offset + 20 + 4*10 ) - - }; -/* - console.log( "signature: " + metaData.signature ); - - console.log( "header_bytes: " + metaData.header_bytes ); - console.log( "vertex_coordinate_bytes: " + metaData.vertex_coordinate_bytes ); - console.log( "normal_coordinate_bytes: " + metaData.normal_coordinate_bytes ); - console.log( "uv_coordinate_bytes: " + metaData.uv_coordinate_bytes ); - - console.log( "vertex_index_bytes: " + metaData.vertex_index_bytes ); - console.log( "normal_index_bytes: " + metaData.normal_index_bytes ); - console.log( "uv_index_bytes: " + metaData.uv_index_bytes ); - console.log( "material_index_bytes: " + metaData.material_index_bytes ); - - console.log( "nvertices: " + metaData.nvertices ); - console.log( "nnormals: " + metaData.nnormals ); - console.log( "nuvs: " + metaData.nuvs ); - - console.log( "ntri_flat: " + metaData.ntri_flat ); - console.log( "ntri_smooth: " + metaData.ntri_smooth ); - console.log( "ntri_flat_uv: " + metaData.ntri_flat_uv ); - console.log( "ntri_smooth_uv: " + metaData.ntri_smooth_uv ); - - console.log( "nquad_flat: " + metaData.nquad_flat ); - console.log( "nquad_smooth: " + metaData.nquad_smooth ); - console.log( "nquad_flat_uv: " + metaData.nquad_flat_uv ); - console.log( "nquad_smooth_uv: " + metaData.nquad_smooth_uv ); - - var total = metaData.header_bytes - + metaData.nvertices * metaData.vertex_coordinate_bytes * 3 - + metaData.nnormals * metaData.normal_coordinate_bytes * 3 - + metaData.nuvs * metaData.uv_coordinate_bytes * 2 - + metaData.ntri_flat * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes ) - + metaData.ntri_smooth * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 ) - + metaData.ntri_flat_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.uv_index_bytes*3 ) - + metaData.ntri_smooth_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 + metaData.uv_index_bytes*3 ) - + metaData.nquad_flat * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes ) - + metaData.nquad_smooth * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 ) - + metaData.nquad_flat_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.uv_index_bytes*4 ) - + metaData.nquad_smooth_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 + metaData.uv_index_bytes*4 ); - console.log( "total bytes: " + total ); -*/ - - return metaData; + function handlePadding( n ) { - }; - - function parseString( data, offset, length ) { - - var charArray = new Uint8Array( data, offset, length ); - - var text = ""; - - for ( var i = 0; i < length; i ++ ) { - - text += String.fromCharCode( charArray[ offset + i ] ); + return ( n % 4 ) ? ( 4 - n % 4 ) : 0; } - return text; + function parseMetaData( data, offset ) { + + var metaData = { + + 'signature' : parseString( data, offset, 12 ), + 'header_bytes' : parseUChar8( data, offset + 12 ), + + 'vertex_coordinate_bytes' : parseUChar8( data, offset + 13 ), + 'normal_coordinate_bytes' : parseUChar8( data, offset + 14 ), + 'uv_coordinate_bytes' : parseUChar8( data, offset + 15 ), + + 'vertex_index_bytes' : parseUChar8( data, offset + 16 ), + 'normal_index_bytes' : parseUChar8( data, offset + 17 ), + 'uv_index_bytes' : parseUChar8( data, offset + 18 ), + 'material_index_bytes' : parseUChar8( data, offset + 19 ), + + 'nvertices' : parseUInt32( data, offset + 20 ), + 'nnormals' : parseUInt32( data, offset + 20 + 4 * 1 ), + 'nuvs' : parseUInt32( data, offset + 20 + 4 * 2 ), + + 'ntri_flat' : parseUInt32( data, offset + 20 + 4 * 3 ), + 'ntri_smooth' : parseUInt32( data, offset + 20 + 4 * 4 ), + 'ntri_flat_uv' : parseUInt32( data, offset + 20 + 4 * 5 ), + 'ntri_smooth_uv' : parseUInt32( data, offset + 20 + 4 * 6 ), + + 'nquad_flat' : parseUInt32( data, offset + 20 + 4 * 7 ), + 'nquad_smooth' : parseUInt32( data, offset + 20 + 4 * 8 ), + 'nquad_flat_uv' : parseUInt32( data, offset + 20 + 4 * 9 ), + 'nquad_smooth_uv' : parseUInt32( data, offset + 20 + 4 * 10 ) + + }; + /* + console.log( "signature: " + metaData.signature ); + + console.log( "header_bytes: " + metaData.header_bytes ); + console.log( "vertex_coordinate_bytes: " + metaData.vertex_coordinate_bytes ); + console.log( "normal_coordinate_bytes: " + metaData.normal_coordinate_bytes ); + console.log( "uv_coordinate_bytes: " + metaData.uv_coordinate_bytes ); + + console.log( "vertex_index_bytes: " + metaData.vertex_index_bytes ); + console.log( "normal_index_bytes: " + metaData.normal_index_bytes ); + console.log( "uv_index_bytes: " + metaData.uv_index_bytes ); + console.log( "material_index_bytes: " + metaData.material_index_bytes ); + + console.log( "nvertices: " + metaData.nvertices ); + console.log( "nnormals: " + metaData.nnormals ); + console.log( "nuvs: " + metaData.nuvs ); + + console.log( "ntri_flat: " + metaData.ntri_flat ); + console.log( "ntri_smooth: " + metaData.ntri_smooth ); + console.log( "ntri_flat_uv: " + metaData.ntri_flat_uv ); + console.log( "ntri_smooth_uv: " + metaData.ntri_smooth_uv ); + + console.log( "nquad_flat: " + metaData.nquad_flat ); + console.log( "nquad_smooth: " + metaData.nquad_smooth ); + console.log( "nquad_flat_uv: " + metaData.nquad_flat_uv ); + console.log( "nquad_smooth_uv: " + metaData.nquad_smooth_uv ); + + var total = metaData.header_bytes + + metaData.nvertices * metaData.vertex_coordinate_bytes * 3 + + metaData.nnormals * metaData.normal_coordinate_bytes * 3 + + metaData.nuvs * metaData.uv_coordinate_bytes * 2 + + metaData.ntri_flat * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes ) + + metaData.ntri_smooth * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 ) + + metaData.ntri_flat_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.uv_index_bytes*3 ) + + metaData.ntri_smooth_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 + metaData.uv_index_bytes*3 ) + + metaData.nquad_flat * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes ) + + metaData.nquad_smooth * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 ) + + metaData.nquad_flat_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.uv_index_bytes*4 ) + + metaData.nquad_smooth_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 + metaData.uv_index_bytes*4 ); + console.log( "total bytes: " + total ); + */ + + return metaData; - }; + } - function parseUChar8( data, offset ) { + function parseString( data, offset, length ) { - var charArray = new Uint8Array( data, offset, 1 ); + var charArray = new Uint8Array( data, offset, length ); - return charArray[ 0 ]; + var text = ""; - }; + for ( var i = 0; i < length; i ++ ) { - function parseUInt32( data, offset ) { + text += String.fromCharCode( charArray[ offset + i ] ); - var intArray = new Uint32Array( data, offset, 1 ); + } - return intArray[ 0 ]; + return text; - }; + } - function init_vertices( start ) { + function parseUChar8( data, offset ) { - var nElements = md.nvertices; + var charArray = new Uint8Array( data, offset, 1 ); - var coordArray = new Float32Array( data, start, nElements * 3 ); + return charArray[ 0 ]; - var i, x, y, z; + } - for( i = 0; i < nElements; i ++ ) { + function parseUInt32( data, offset ) { - x = coordArray[ i * 3 ]; - y = coordArray[ i * 3 + 1 ]; - z = coordArray[ i * 3 + 2 ]; + var intArray = new Uint32Array( data, offset, 1 ); - vertex( scope, x, y, z ); + return intArray[ 0 ]; } - return nElements * 3 * Float32Array.BYTES_PER_ELEMENT; + function init_vertices( start ) { - }; - - function init_normals( start ) { - - var nElements = md.nnormals; + var nElements = md.nvertices; - if ( nElements ) { - - var normalArray = new Int8Array( data, start, nElements * 3 ); + var coordArray = new Float32Array( data, start, nElements * 3 ); var i, x, y, z; - for( i = 0; i < nElements; i ++ ) { + for ( i = 0; i < nElements; i ++ ) { - x = normalArray[ i * 3 ]; - y = normalArray[ i * 3 + 1 ]; - z = normalArray[ i * 3 + 2 ]; + x = coordArray[ i * 3 ]; + y = coordArray[ i * 3 + 1 ]; + z = coordArray[ i * 3 + 2 ]; - normals.push( x/127, y/127, z/127 ); + scope.vertices.push( new THREE.Vector3( x, y, z ) ); } + return nElements * 3 * Float32Array.BYTES_PER_ELEMENT; + } - return nElements * 3 * Int8Array.BYTES_PER_ELEMENT; + function init_normals( start ) { - }; + var nElements = md.nnormals; - function init_uvs( start ) { + if ( nElements ) { - var nElements = md.nuvs; + var normalArray = new Int8Array( data, start, nElements * 3 ); - if ( nElements ) { + var i, x, y, z; - var uvArray = new Float32Array( data, start, nElements * 2 ); + for ( i = 0; i < nElements; i ++ ) { - var i, u, v; + x = normalArray[ i * 3 ]; + y = normalArray[ i * 3 + 1 ]; + z = normalArray[ i * 3 + 2 ]; - for( i = 0; i < nElements; i ++ ) { + normals.push( x / 127, y / 127, z / 127 ); - u = uvArray[ i * 2 ]; - v = uvArray[ i * 2 + 1 ]; - - uvs.push( u, v ); + } } + return nElements * 3 * Int8Array.BYTES_PER_ELEMENT; + } - return nElements * 2 * Float32Array.BYTES_PER_ELEMENT; + function init_uvs( start ) { - }; + var nElements = md.nuvs; - function init_uvs3( nElements, offset ) { + if ( nElements ) { - var i, uva, uvb, uvc, u1, u2, u3, v1, v2, v3; + var uvArray = new Float32Array( data, start, nElements * 2 ); - var uvIndexBuffer = new Uint32Array( data, offset, 3 * nElements ); + var i, u, v; - for( i = 0; i < nElements; i ++ ) { + for ( i = 0; i < nElements; i ++ ) { - uva = uvIndexBuffer[ i * 3 ]; - uvb = uvIndexBuffer[ i * 3 + 1 ]; - uvc = uvIndexBuffer[ i * 3 + 2 ]; + u = uvArray[ i * 2 ]; + v = uvArray[ i * 2 + 1 ]; - u1 = uvs[ uva*2 ]; - v1 = uvs[ uva*2 + 1 ]; + uvs.push( u, v ); - u2 = uvs[ uvb*2 ]; - v2 = uvs[ uvb*2 + 1 ]; + } - u3 = uvs[ uvc*2 ]; - v3 = uvs[ uvc*2 + 1 ]; + } - uv3( scope.faceVertexUvs[ 0 ], u1, v1, u2, v2, u3, v3 ); + return nElements * 2 * Float32Array.BYTES_PER_ELEMENT; } - }; - - function init_uvs4( nElements, offset ) { + function init_uvs3( nElements, offset ) { - var i, uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4; + var i, uva, uvb, uvc, u1, u2, u3, v1, v2, v3; - var uvIndexBuffer = new Uint32Array( data, offset, 4 * nElements ); + var uvIndexBuffer = new Uint32Array( data, offset, 3 * nElements ); - for( i = 0; i < nElements; i ++ ) { + for ( i = 0; i < nElements; i ++ ) { - uva = uvIndexBuffer[ i * 4 ]; - uvb = uvIndexBuffer[ i * 4 + 1 ]; - uvc = uvIndexBuffer[ i * 4 + 2 ]; - uvd = uvIndexBuffer[ i * 4 + 3 ]; + uva = uvIndexBuffer[ i * 3 ]; + uvb = uvIndexBuffer[ i * 3 + 1 ]; + uvc = uvIndexBuffer[ i * 3 + 2 ]; - u1 = uvs[ uva*2 ]; - v1 = uvs[ uva*2 + 1 ]; + u1 = uvs[ uva * 2 ]; + v1 = uvs[ uva * 2 + 1 ]; - u2 = uvs[ uvb*2 ]; - v2 = uvs[ uvb*2 + 1 ]; + u2 = uvs[ uvb * 2 ]; + v2 = uvs[ uvb * 2 + 1 ]; - u3 = uvs[ uvc*2 ]; - v3 = uvs[ uvc*2 + 1 ]; + u3 = uvs[ uvc * 2 ]; + v3 = uvs[ uvc * 2 + 1 ]; - u4 = uvs[ uvd*2 ]; - v4 = uvs[ uvd*2 + 1 ]; + scope.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u2, v2 ), + new THREE.Vector2( u3, v3 ) + ] ); - uv4( scope.faceVertexUvs[ 0 ], u1, v1, u2, v2, u3, v3, u4, v4 ); + } } - }; - - function init_faces3_flat( nElements, offsetVertices, offsetMaterials ) { - - var i, a, b, c, m; - - var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements ); - var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); + function init_uvs4( nElements, offset ) { - for( i = 0; i < nElements; i ++ ) { + var i, uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4; - a = vertexIndexBuffer[ i * 3 ]; - b = vertexIndexBuffer[ i * 3 + 1 ]; - c = vertexIndexBuffer[ i * 3 + 2 ]; + var uvIndexBuffer = new Uint32Array( data, offset, 4 * nElements ); - m = materialIndexBuffer[ i ]; + for ( i = 0; i < nElements; i ++ ) { - f3( scope, a, b, c, m ); + uva = uvIndexBuffer[ i * 4 ]; + uvb = uvIndexBuffer[ i * 4 + 1 ]; + uvc = uvIndexBuffer[ i * 4 + 2 ]; + uvd = uvIndexBuffer[ i * 4 + 3 ]; - } - - }; + u1 = uvs[ uva * 2 ]; + v1 = uvs[ uva * 2 + 1 ]; - function init_faces4_flat( nElements, offsetVertices, offsetMaterials ) { + u2 = uvs[ uvb * 2 ]; + v2 = uvs[ uvb * 2 + 1 ]; - var i, a, b, c, d, m; + u3 = uvs[ uvc * 2 ]; + v3 = uvs[ uvc * 2 + 1 ]; - var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements ); - var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); + u4 = uvs[ uvd * 2 ]; + v4 = uvs[ uvd * 2 + 1 ]; - for( i = 0; i < nElements; i ++ ) { + scope.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u2, v2 ), + new THREE.Vector2( u4, v4 ) + ] ); - a = vertexIndexBuffer[ i * 4 ]; - b = vertexIndexBuffer[ i * 4 + 1 ]; - c = vertexIndexBuffer[ i * 4 + 2 ]; - d = vertexIndexBuffer[ i * 4 + 3 ]; + scope.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( u2, v2 ), + new THREE.Vector2( u3, v3 ), + new THREE.Vector2( u4, v4 ) + ] ); - m = materialIndexBuffer[ i ]; - - f4( scope, a, b, c, d, m ); + } } - }; - - function init_faces3_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) { + function init_faces3_flat( nElements, offsetVertices, offsetMaterials ) { - var i, a, b, c, m; - var na, nb, nc; + var i, a, b, c, m; - var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements ); - var normalIndexBuffer = new Uint32Array( data, offsetNormals, 3 * nElements ); - var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); + var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements ); + var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); - for( i = 0; i < nElements; i ++ ) { + for ( i = 0; i < nElements; i ++ ) { - a = vertexIndexBuffer[ i * 3 ]; - b = vertexIndexBuffer[ i * 3 + 1 ]; - c = vertexIndexBuffer[ i * 3 + 2 ]; + a = vertexIndexBuffer[ i * 3 ]; + b = vertexIndexBuffer[ i * 3 + 1 ]; + c = vertexIndexBuffer[ i * 3 + 2 ]; - na = normalIndexBuffer[ i * 3 ]; - nb = normalIndexBuffer[ i * 3 + 1 ]; - nc = normalIndexBuffer[ i * 3 + 2 ]; + m = materialIndexBuffer[ i ]; - m = materialIndexBuffer[ i ]; + scope.faces.push( new THREE.Face3( a, b, c, null, null, m ) ); - f3n( scope, normals, a, b, c, m, na, nb, nc ); + } } - }; - - function init_faces4_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) { + function init_faces4_flat( nElements, offsetVertices, offsetMaterials ) { - var i, a, b, c, d, m; - var na, nb, nc, nd; + var i, a, b, c, d, m; - var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements ); - var normalIndexBuffer = new Uint32Array( data, offsetNormals, 4 * nElements ); - var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); + var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements ); + var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); - for( i = 0; i < nElements; i ++ ) { + for ( i = 0; i < nElements; i ++ ) { - a = vertexIndexBuffer[ i * 4 ]; - b = vertexIndexBuffer[ i * 4 + 1 ]; - c = vertexIndexBuffer[ i * 4 + 2 ]; - d = vertexIndexBuffer[ i * 4 + 3 ]; + a = vertexIndexBuffer[ i * 4 ]; + b = vertexIndexBuffer[ i * 4 + 1 ]; + c = vertexIndexBuffer[ i * 4 + 2 ]; + d = vertexIndexBuffer[ i * 4 + 3 ]; - na = normalIndexBuffer[ i * 4 ]; - nb = normalIndexBuffer[ i * 4 + 1 ]; - nc = normalIndexBuffer[ i * 4 + 2 ]; - nd = normalIndexBuffer[ i * 4 + 3 ]; + m = materialIndexBuffer[ i ]; - m = materialIndexBuffer[ i ]; + scope.faces.push( new THREE.Face3( a, b, d, null, null, m ) ); + scope.faces.push( new THREE.Face3( b, c, d, null, null, m ) ); - f4n( scope, normals, a, b, c, d, m, na, nb, nc, nd ); + } } - }; + function init_faces3_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) { - function init_triangles_flat( start ) { + var i, a, b, c, m; + var na, nb, nc; - var nElements = md.ntri_flat; + var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements ); + var normalIndexBuffer = new Uint32Array( data, offsetNormals, 3 * nElements ); + var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); - if ( nElements ) { + for ( i = 0; i < nElements; i ++ ) { - var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - init_faces3_flat( nElements, start, offsetMaterials ); + a = vertexIndexBuffer[ i * 3 ]; + b = vertexIndexBuffer[ i * 3 + 1 ]; + c = vertexIndexBuffer[ i * 3 + 2 ]; - } + na = normalIndexBuffer[ i * 3 ]; + nb = normalIndexBuffer[ i * 3 + 1 ]; + nc = normalIndexBuffer[ i * 3 + 2 ]; - }; + m = materialIndexBuffer[ i ]; - function init_triangles_flat_uv( start ) { + var nax = normals[ na * 3 ], + nay = normals[ na * 3 + 1 ], + naz = normals[ na * 3 + 2 ], - var nElements = md.ntri_flat_uv; + nbx = normals[ nb * 3 ], + nby = normals[ nb * 3 + 1 ], + nbz = normals[ nb * 3 + 2 ], - if ( nElements ) { + ncx = normals[ nc * 3 ], + ncy = normals[ nc * 3 + 1 ], + ncz = normals[ nc * 3 + 2 ]; - var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + scope.faces.push( new THREE.Face3( a, b, c, [ + new THREE.Vector3( nax, nay, naz ), + new THREE.Vector3( nbx, nby, nbz ), + new THREE.Vector3( ncx, ncy, ncz ) + ], null, m ) ); - init_faces3_flat( nElements, start, offsetMaterials ); - init_uvs3( nElements, offsetUvs ); + } } - }; + function init_faces4_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) { - function init_triangles_smooth( start ) { + var i, a, b, c, d, m; + var na, nb, nc, nd; - var nElements = md.ntri_smooth; + var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements ); + var normalIndexBuffer = new Uint32Array( data, offsetNormals, 4 * nElements ); + var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); - if ( nElements ) { + for ( i = 0; i < nElements; i ++ ) { - var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + a = vertexIndexBuffer[ i * 4 ]; + b = vertexIndexBuffer[ i * 4 + 1 ]; + c = vertexIndexBuffer[ i * 4 + 2 ]; + d = vertexIndexBuffer[ i * 4 + 3 ]; - init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials ); + na = normalIndexBuffer[ i * 4 ]; + nb = normalIndexBuffer[ i * 4 + 1 ]; + nc = normalIndexBuffer[ i * 4 + 2 ]; + nd = normalIndexBuffer[ i * 4 + 3 ]; - } + m = materialIndexBuffer[ i ]; - }; + var nax = normals[ na * 3 ], + nay = normals[ na * 3 + 1 ], + naz = normals[ na * 3 + 2 ], - function init_triangles_smooth_uv( start ) { + nbx = normals[ nb * 3 ], + nby = normals[ nb * 3 + 1 ], + nbz = normals[ nb * 3 + 2 ], - var nElements = md.ntri_smooth_uv; + ncx = normals[ nc * 3 ], + ncy = normals[ nc * 3 + 1 ], + ncz = normals[ nc * 3 + 2 ], - if ( nElements ) { + ndx = normals[ nd * 3 ], + ndy = normals[ nd * 3 + 1 ], + ndz = normals[ nd * 3 + 2 ]; - var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + scope.faces.push( new THREE.Face3( a, b, d, [ + new THREE.Vector3( nax, nay, naz ), + new THREE.Vector3( nbx, nby, nbz ), + new THREE.Vector3( ndx, ndy, ndz ) + ], null, m ) ); - init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials ); - init_uvs3( nElements, offsetUvs ); + scope.faces.push( new THREE.Face3( b, c, d, [ + new THREE.Vector3( nbx, nby, nbz ), + new THREE.Vector3( ncx, ncy, ncz ), + new THREE.Vector3( ndx, ndy, ndz ) + ], null, m ) ); + + } } - }; + function init_triangles_flat( start ) { - function init_quads_flat( start ) { + var nElements = md.ntri_flat; - var nElements = md.nquad_flat; + if ( nElements ) { - if ( nElements ) { + var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + init_faces3_flat( nElements, start, offsetMaterials ); - var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - init_faces4_flat( nElements, start, offsetMaterials ); + } } - }; + function init_triangles_flat_uv( start ) { - function init_quads_flat_uv( start ) { + var nElements = md.ntri_flat_uv; - var nElements = md.nquad_flat_uv; + if ( nElements ) { - if ( nElements ) { + var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + init_faces3_flat( nElements, start, offsetMaterials ); + init_uvs3( nElements, offsetUvs ); - init_faces4_flat( nElements, start, offsetMaterials ); - init_uvs4( nElements, offsetUvs ); + } } - }; + function init_triangles_smooth( start ) { - function init_quads_smooth( start ) { + var nElements = md.ntri_smooth; - var nElements = md.nquad_smooth; + if ( nElements ) { - if ( nElements ) { + var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials ); - init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials ); + } } - }; + function init_triangles_smooth_uv( start ) { - function init_quads_smooth_uv( start ) { + var nElements = md.ntri_smooth_uv; - var nElements = md.nquad_smooth_uv; + if ( nElements ) { - if ( nElements ) { + var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; + var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; - var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials ); + init_uvs3( nElements, offsetUvs ); - init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials ); - init_uvs4( nElements, offsetUvs ); + } } - }; - - }; + function init_quads_flat( start ) { - function vertex ( scope, x, y, z ) { + var nElements = md.nquad_flat; - scope.vertices.push( new THREE.Vector3( x, y, z ) ); + if ( nElements ) { - }; + var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + init_faces4_flat( nElements, start, offsetMaterials ); - function f3 ( scope, a, b, c, mi ) { + } - scope.faces.push( new THREE.Face3( a, b, c, null, null, mi ) ); + } - }; + function init_quads_flat_uv( start ) { - function f4 ( scope, a, b, c, d, mi ) { + var nElements = md.nquad_flat_uv; - scope.faces.push( new THREE.Face4( a, b, c, d, null, null, mi ) ); + if ( nElements ) { - }; + var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - function f3n ( scope, normals, a, b, c, mi, na, nb, nc ) { + init_faces4_flat( nElements, start, offsetMaterials ); + init_uvs4( nElements, offsetUvs ); - var nax = normals[ na*3 ], - nay = normals[ na*3 + 1 ], - naz = normals[ na*3 + 2 ], + } - nbx = normals[ nb*3 ], - nby = normals[ nb*3 + 1 ], - nbz = normals[ nb*3 + 2 ], + } - ncx = normals[ nc*3 ], - ncy = normals[ nc*3 + 1 ], - ncz = normals[ nc*3 + 2 ]; + function init_quads_smooth( start ) { - scope.faces.push( new THREE.Face3( a, b, c, - [new THREE.Vector3( nax, nay, naz ), - new THREE.Vector3( nbx, nby, nbz ), - new THREE.Vector3( ncx, ncy, ncz )], - null, - mi ) ); + var nElements = md.nquad_smooth; - }; + if ( nElements ) { - function f4n ( scope, normals, a, b, c, d, mi, na, nb, nc, nd ) { + var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - var nax = normals[ na*3 ], - nay = normals[ na*3 + 1 ], - naz = normals[ na*3 + 2 ], + init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials ); - nbx = normals[ nb*3 ], - nby = normals[ nb*3 + 1 ], - nbz = normals[ nb*3 + 2 ], + } - ncx = normals[ nc*3 ], - ncy = normals[ nc*3 + 1 ], - ncz = normals[ nc*3 + 2 ], + } - ndx = normals[ nd*3 ], - ndy = normals[ nd*3 + 1 ], - ndz = normals[ nd*3 + 2 ]; + function init_quads_smooth_uv( start ) { - scope.faces.push( new THREE.Face4( a, b, c, d, - [new THREE.Vector3( nax, nay, naz ), - new THREE.Vector3( nbx, nby, nbz ), - new THREE.Vector3( ncx, ncy, ncz ), - new THREE.Vector3( ndx, ndy, ndz )], - null, - mi ) ); + var nElements = md.nquad_smooth_uv; - }; + if ( nElements ) { - function uv3 ( where, u1, v1, u2, v2, u3, v3 ) { + var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; + var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; - where.push( [ - new THREE.Vector2( u1, v1 ), - new THREE.Vector2( u2, v2 ), - new THREE.Vector2( u3, v3 ) - ] ); + init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials ); + init_uvs4( nElements, offsetUvs ); - }; + } - function uv4 ( where, u1, v1, u2, v2, u3, v3, u4, v4 ) { + } - where.push( [ - new THREE.Vector2( u1, v1 ), - new THREE.Vector2( u2, v2 ), - new THREE.Vector2( u3, v3 ), - new THREE.Vector2( u4, v4 ) - ] ); - }; + }; - Model.prototype = Object.create( THREE.Geometry.prototype ); + Model.prototype = Object.create( THREE.Geometry.prototype ); + Model.prototype.constructor = Model; - var geometry = new Model( texturePath ); - var materials = this.initMaterials( jsonMaterials, texturePath ); + var geometry = new Model( texturePath ); + var materials = THREE.Loader.prototype.initMaterials( jsonMaterials, texturePath, this.crossOrigin ); + // FIX: register materials with transparency + for( var i in jsonMaterials ){ + if( jsonMaterials[i].transparent === true ){ + materials[i].transparent = true; + } + } - if ( this.needsTangents( materials ) ) geometry.computeTangents(); + callback( geometry, materials ); - callback( geometry, materials ); + } }; diff --git a/examples/assets/js/libs/FirstPersonControls.js b/examples/assets/js/libs/FirstPersonControls.js new file mode 100644 index 0000000..2cceb2d --- /dev/null +++ b/examples/assets/js/libs/FirstPersonControls.js @@ -0,0 +1,284 @@ +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author paulirish / http://paulirish.com/ + */ + +THREE.FirstPersonControls = function ( object, domElement ) { + + this.object = object; + this.target = new THREE.Vector3( 0, 0, 0 ); + + this.domElement = ( domElement !== undefined ) ? domElement : document; + + this.movementSpeed = 1.0; + this.lookSpeed = 0.005; + + this.lookVertical = true; + this.autoForward = false; + // this.invertVertical = false; + + this.activeLook = true; + + this.heightSpeed = false; + this.heightCoef = 1.0; + this.heightMin = 0.0; + this.heightMax = 1.0; + + this.constrainVertical = false; + this.verticalMin = 0; + this.verticalMax = Math.PI; + + this.autoSpeedFactor = 0.0; + + this.mouseX = 0; + this.mouseY = 0; + + this.lat = 0; + this.lon = 0; + this.phi = 0; + this.theta = 0; + + this.moveForward = false; + this.moveBackward = false; + this.moveLeft = false; + this.moveRight = false; + this.freeze = false; + + this.mouseDragOn = false; + + this.viewHalfX = 0; + this.viewHalfY = 0; + + if ( this.domElement !== document ) { + + this.domElement.setAttribute( 'tabindex', -1 ); + + } + + // + + this.handleResize = function () { + + if ( this.domElement === document ) { + + this.viewHalfX = window.innerWidth / 2; + this.viewHalfY = window.innerHeight / 2; + + } else { + + this.viewHalfX = this.domElement.offsetWidth / 2; + this.viewHalfY = this.domElement.offsetHeight / 2; + + } + + }; + + this.onMouseDown = function ( event ) { + + if ( this.domElement !== document ) { + + this.domElement.focus(); + + } + + event.preventDefault(); + event.stopPropagation(); + + if ( this.activeLook ) { + + switch ( event.button ) { + + case 0: this.moveForward = true; break; + case 2: this.moveBackward = true; break; + + } + + } + + this.mouseDragOn = true; + + }; + + this.onMouseUp = function ( event ) { + + event.preventDefault(); + event.stopPropagation(); + + if ( this.activeLook ) { + + switch ( event.button ) { + + case 0: this.moveForward = false; break; + case 2: this.moveBackward = false; break; + + } + + } + + this.mouseDragOn = false; + + }; + + this.onMouseMove = function ( event ) { + + if ( this.domElement === document ) { + + this.mouseX = event.pageX - this.viewHalfX; + this.mouseY = event.pageY - this.viewHalfY; + + } else { + + this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX; + this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY; + + } + + }; + + this.onKeyDown = function ( event ) { + + //event.preventDefault(); + + switch ( event.keyCode ) { + + case 38: /*up*/ + case 87: /*W*/ this.moveForward = true; break; + + case 37: /*left*/ + case 65: /*A*/ this.moveLeft = true; break; + + case 40: /*down*/ + case 83: /*S*/ this.moveBackward = true; break; + + case 39: /*right*/ + case 68: /*D*/ this.moveRight = true; break; + + case 82: /*R*/ this.moveUp = true; break; + case 70: /*F*/ this.moveDown = true; break; + + case 81: /*Q*/ this.freeze = !this.freeze; break; + + } + + }; + + this.onKeyUp = function ( event ) { + + switch( event.keyCode ) { + + case 38: /*up*/ + case 87: /*W*/ this.moveForward = false; break; + + case 37: /*left*/ + case 65: /*A*/ this.moveLeft = false; break; + + case 40: /*down*/ + case 83: /*S*/ this.moveBackward = false; break; + + case 39: /*right*/ + case 68: /*D*/ this.moveRight = false; break; + + case 82: /*R*/ this.moveUp = false; break; + case 70: /*F*/ this.moveDown = false; break; + + } + + }; + + this.update = function( delta ) { + + if ( this.freeze ) { + + return; + + } + + if ( this.heightSpeed ) { + + var y = THREE.Math.clamp( this.object.position.y, this.heightMin, this.heightMax ); + var heightDelta = y - this.heightMin; + + this.autoSpeedFactor = delta * ( heightDelta * this.heightCoef ); + + } else { + + this.autoSpeedFactor = 0.0; + + } + + var actualMoveSpeed = delta * this.movementSpeed; + + if ( this.moveForward || ( this.autoForward && !this.moveBackward ) ) this.object.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) ); + if ( this.moveBackward ) this.object.translateZ( actualMoveSpeed ); + + if ( this.moveLeft ) this.object.translateX( - actualMoveSpeed ); + if ( this.moveRight ) this.object.translateX( actualMoveSpeed ); + + if ( this.moveUp ) this.object.translateY( actualMoveSpeed ); + if ( this.moveDown ) this.object.translateY( - actualMoveSpeed ); + + var actualLookSpeed = delta * this.lookSpeed; + + if ( !this.activeLook ) { + + actualLookSpeed = 0; + + } + + var verticalLookRatio = 1; + + if ( this.constrainVertical ) { + + verticalLookRatio = Math.PI / ( this.verticalMax - this.verticalMin ); + + } + + this.lon += this.mouseX * actualLookSpeed; + if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio; + + this.lat = Math.max( - 85, Math.min( 85, this.lat ) ); + this.phi = THREE.Math.degToRad( 90 - this.lat ); + + this.theta = THREE.Math.degToRad( this.lon ); + + if ( this.constrainVertical ) { + + this.phi = THREE.Math.mapLinear( this.phi, 0, Math.PI, this.verticalMin, this.verticalMax ); + + } + + var targetPosition = this.target, + position = this.object.position; + + targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta ); + targetPosition.y = position.y + 100 * Math.cos( this.phi ); + targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta ); + + this.object.lookAt( targetPosition ); + + }; + + + this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); + + this.domElement.addEventListener( 'mousemove', bind( this, this.onMouseMove ), false ); + this.domElement.addEventListener( 'mousedown', bind( this, this.onMouseDown ), false ); + this.domElement.addEventListener( 'mouseup', bind( this, this.onMouseUp ), false ); + + window.addEventListener( 'keydown', bind( this, this.onKeyDown ), false ); + window.addEventListener( 'keyup', bind( this, this.onKeyUp ), false ); + + function bind( scope, fn ) { + + return function () { + + fn.apply( scope, arguments ); + + }; + + }; + + this.handleResize(); + +}; diff --git a/examples/assets/js/libs/FlyControls.js b/examples/assets/js/libs/FlyControls.js index 1437d45..2a033ad 100644 --- a/examples/assets/js/libs/FlyControls.js +++ b/examples/assets/js/libs/FlyControls.js @@ -260,10 +260,10 @@ THREE.FlyControls = function ( object, domElement ) { this.domElement.addEventListener( 'mousedown', bind( this, this.mousedown ), false ); this.domElement.addEventListener( 'mouseup', bind( this, this.mouseup ), false ); - this.domElement.addEventListener( 'keydown', bind( this, this.keydown ), false ); - this.domElement.addEventListener( 'keyup', bind( this, this.keyup ), false ); + window.addEventListener( 'keydown', bind( this, this.keydown ), false ); + window.addEventListener( 'keyup', bind( this, this.keyup ), false ); this.updateMovementVector(); this.updateRotationVector(); -}; \ No newline at end of file +}; diff --git a/examples/assets/js/libs/OBJMTLLoader.js b/examples/assets/js/libs/OBJMTLLoader.js index 82cc8e8..6a18402 100644 --- a/examples/assets/js/libs/OBJMTLLoader.js +++ b/examples/assets/js/libs/OBJMTLLoader.js @@ -5,169 +5,49 @@ * @author angelxuanchang */ -THREE.OBJMTLLoader = function () { - - THREE.EventDispatcher.call( this ); - -}; +THREE.OBJMTLLoader = function () {}; THREE.OBJMTLLoader.prototype = { constructor: THREE.OBJMTLLoader, - /** - * Load a Wavefront OBJ file with materials (MTL file) - * - * Loading progress is indicated by the following events: - * "load" event (successful loading): type = 'load', content = THREE.Object3D - * "error" event (error loading): type = 'load', message - * "progress" event (progress loading): type = 'progress', loaded, total - * - * If the MTL file cannot be loaded, then a MeshLambertMaterial is used as a default - * @param url - Location of OBJ file to load - * @param mtlfileurl - MTL file to load (optional, if not specified, attempts to use MTL specified in OBJ file) - * @param options - Options on how to interpret the material (see THREE.MTLLoader.MaterialCreator ) - */ - - load: function ( url, mtlfileurl, options ) { + load: function ( url, mtlurl, onLoad, onProgress, onError ) { var scope = this; - var xhr = new XMLHttpRequest(); - - var mtlDone; // Is the MTL done (true if no MTL, error loading MTL, or MTL actually loaded) - var obj3d; // Loaded model (from obj file) - var materialsCreator; // Material creator is created when MTL file is loaded - - // Loader for MTL - - var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ), options ); - mtlLoader.addEventListener( 'load', waitReady ); - mtlLoader.addEventListener( 'error', waitReady ); - // Try to load mtlfile + var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) ); + mtlLoader.load( mtlurl, function ( materials ) { - if ( mtlfileurl ) { + var materialsCreator = materials; + materialsCreator.preload(); - mtlLoader.load( mtlfileurl ); - mtlDone = false; + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { - } else { + var object = scope.parse( text ); - mtlDone = true; + object.traverse( function ( object ) { - } - - function waitReady( event ) { - - if ( event.type === 'load' ) { - - if ( event.content instanceof THREE.MTLLoader.MaterialCreator ) { - - // MTL file is loaded - - mtlDone = true; - materialsCreator = event.content; - materialsCreator.preload(); - - } else { + if ( object instanceof THREE.Mesh ) { - // OBJ file is loaded + if ( object.material.name ) { - if ( event.target.status === 200 || event.target.status === 0 ) { + var material = materialsCreator.create( object.material.name ); - var objContent = event.target.responseText; - - if ( mtlfileurl ) { - - // Parse with passed in MTL file - - obj3d = scope.parse( objContent ); - - } else { - - // No passed in MTL file, look for mtlfile in obj file - - obj3d = scope.parse( objContent, function( mtlfile ) { - - mtlDone = false; - mtlLoader.load( mtlLoader.baseUrl + mtlfile ); - - } ); + if ( material ) object.material = material; } - } else { - - // Error loading OBJ file.... - - scope.dispatchEvent( { - type: 'error', - message: 'Couldn\'t load URL [' + url + ']', - response: event.target.responseText } ); - } - } - - } else if ( event.type === 'error' ) { - - // MTL failed to load -- oh well, we will just not have material ... + } ); - mtlDone = true; - - } + onLoad( object ); - if ( mtlDone && obj3d ) { + } ); - // MTL file is loaded and OBJ file is loaded - // Apply materials to model - - if ( materialsCreator ) { -console.log(obj3d); - obj3d.traverse( function( object ) { - - if ( object instanceof THREE.Mesh ) { - - if ( object.material.name ) { - - var material = materialsCreator.create( object.material.name ); - if ( material ) { - - object.material = material; - - } - - } - - } - - } ); - - } - - // Notify listeners - - scope.dispatchEvent( { type: 'load', content: obj3d } ); - } - - } - - xhr.addEventListener( 'load', waitReady, false ); - - xhr.addEventListener( 'progress', function ( event ) { - - scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } ); - - }, false ); - - xhr.addEventListener( 'error', function () { - - scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } ); - - }, false ); - - xhr.open( 'GET', url, true ); - xhr.send( null ); + } ); }, @@ -180,12 +60,6 @@ console.log(obj3d); parse: function ( data, mtllibCallback ) { - // fixes - - data = data.replace( /\ \\\r\n/g, '' ); // rhino adds ' \\r\n' some times. - - // - function vector( x, y, z ) { return new THREE.Vector3( x, y, z ); @@ -204,18 +78,15 @@ console.log(obj3d); } - function face4( a, b, c, d, normals ) { - - return new THREE.Face4( a, b, c, d, normals ); - - } + var face_offset = 0; function meshN( meshName, materialName ) { - if ( geometry.vertices.length > 0 ) { + if ( vertices.length > 0 ) { + + geometry.vertices = vertices; geometry.mergeVertices(); - geometry.computeCentroids(); geometry.computeFaceNormals(); geometry.computeBoundingSphere(); @@ -224,11 +95,10 @@ console.log(obj3d); geometry = new THREE.Geometry(); mesh = new THREE.Mesh( geometry, material ); - verticesCount = 0; - } if ( meshName !== undefined ) mesh.name = meshName; + if ( materialName !== undefined ) { material = new THREE.MeshLambertMaterial(); @@ -248,37 +118,109 @@ console.log(obj3d); var mesh = new THREE.Mesh( geometry, material ); var vertices = []; - var verticesCount = 0; var normals = []; var uvs = []; + function add_face( a, b, c, normals_inds ) { + + if ( normals_inds === undefined ) { + + geometry.faces.push( face3( + parseInt( a ) - (face_offset + 1), + parseInt( b ) - (face_offset + 1), + parseInt( c ) - (face_offset + 1) + ) ); + + } else { + + geometry.faces.push( face3( + parseInt( a ) - (face_offset + 1), + parseInt( b ) - (face_offset + 1), + parseInt( c ) - (face_offset + 1), + [ + normals[ parseInt( normals_inds[ 0 ] ) - 1 ].clone(), + normals[ parseInt( normals_inds[ 1 ] ) - 1 ].clone(), + normals[ parseInt( normals_inds[ 2 ] ) - 1 ].clone() + ] + ) ); + + } + + } + + function add_uvs( a, b, c ) { + + geometry.faceVertexUvs[ 0 ].push( [ + uvs[ parseInt( a ) - 1 ].clone(), + uvs[ parseInt( b ) - 1 ].clone(), + uvs[ parseInt( c ) - 1 ].clone() + ] ); + + } + + function handle_face_line(faces, uvs, normals_inds) { + + if ( faces[ 3 ] === undefined ) { + + add_face( faces[ 0 ], faces[ 1 ], faces[ 2 ], normals_inds ); + + if (!(uvs === undefined) && uvs.length > 0) { + add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] ); + } + + } else { + + if (!(normals_inds === undefined) && normals_inds.length > 0) { + + add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ], [ normals_inds[ 0 ], normals_inds[ 1 ], normals_inds[ 3 ] ]); + add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ], [ normals_inds[ 1 ], normals_inds[ 2 ], normals_inds[ 3 ] ]); + + } else { + + add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ]); + add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ]); + + } + + if (!(uvs === undefined) && uvs.length > 0) { + + add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ); + add_uvs( uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ); + + } + + } + + } + + // v float float float - var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/; + var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; // vn float float float - var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/; + var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; // vt float float - var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/; + var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; // f vertex vertex vertex ... - var face_pattern1 = /f( +[\d]+)( [\d]+)( [\d]+)( [\d]+)?/; + var face_pattern1 = /f( +\d+)( +\d+)( +\d+)( +\d+)?/; // f vertex/uv vertex/uv vertex/uv ... - var face_pattern2 = /f( +([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))?/; + var face_pattern2 = /f( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))?/; // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... - var face_pattern3 = /f( +([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))?/; + var face_pattern3 = /f( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))?/; - // f vertex//normal vertex//normal vertex//normal ... + // f vertex//normal vertex//normal vertex//normal ... - var face_pattern4 = /f( +([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))?/; + var face_pattern4 = /f( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))?/ // @@ -289,8 +231,6 @@ console.log(obj3d); var line = lines[ i ]; line = line.trim(); - // temporary variable storing pattern matching result - var result; if ( line.length === 0 || line.charAt( 0 ) === '#' ) { @@ -330,215 +270,61 @@ console.log(obj3d); // ["f 1 2 3", "1", "2", "3", undefined] - if ( result[ 4 ] === undefined ) { - - geometry.vertices.push( - vertices[ parseInt( result[ 1 ] ) - 1 ], - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 3 ] ) - 1 ] - ); - - geometry.faces.push( face3( - verticesCount ++, - verticesCount ++, - verticesCount ++ - ) ); - - } else { - - geometry.vertices.push( - vertices[ parseInt( result[ 1 ] ) - 1 ], - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 3 ] ) - 1 ], - vertices[ parseInt( result[ 4 ] ) - 1 ] - ); - - geometry.faces.push( face4( - verticesCount ++, - verticesCount ++, - verticesCount ++, - verticesCount ++ - ) ); - - } + handle_face_line([ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] ]); } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] - - if ( result[ 10 ] === undefined ) { - - geometry.vertices.push( - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 5 ] ) - 1 ], - vertices[ parseInt( result[ 8 ] ) - 1 ] - ); - - geometry.faces.push( face3( - verticesCount ++, - verticesCount ++, - verticesCount ++ - ) ); - - geometry.faceVertexUvs[ 0 ].push( [ - uvs[ parseInt( result[ 3 ] ) - 1 ], - uvs[ parseInt( result[ 6 ] ) - 1 ], - uvs[ parseInt( result[ 9 ] ) - 1 ] - ] ); - - } else { - - geometry.vertices.push( - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 5 ] ) - 1 ], - vertices[ parseInt( result[ 8 ] ) - 1 ], - vertices[ parseInt( result[ 11 ] ) - 1 ] - ); - - geometry.faces.push( face4( - verticesCount ++, - verticesCount ++, - verticesCount ++, - verticesCount ++ - ) ); - - geometry.faceVertexUvs[ 0 ].push( [ - uvs[ parseInt( result[ 3 ] ) - 1 ], - uvs[ parseInt( result[ 6 ] ) - 1 ], - uvs[ parseInt( result[ 9 ] ) - 1 ], - uvs[ parseInt( result[ 12 ] ) - 1 ] - ] ); - - } + + handle_face_line( + [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces + [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //uv + ); } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] - if ( result[ 13 ] === undefined ) { - - geometry.vertices.push( - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 6 ] ) - 1 ], - vertices[ parseInt( result[ 10 ] ) - 1 ] - ); - - geometry.faces.push( face3( - verticesCount ++, - verticesCount ++, - verticesCount ++, - [ - normals[ parseInt( result[ 4 ] ) - 1 ], - normals[ parseInt( result[ 8 ] ) - 1 ], - normals[ parseInt( result[ 12 ] ) - 1 ] - ] - ) ); - - geometry.faceVertexUvs[ 0 ].push( [ - uvs[ parseInt( result[ 3 ] ) - 1 ], - uvs[ parseInt( result[ 7 ] ) - 1 ], - uvs[ parseInt( result[ 11 ] ) - 1 ] - ] ); - - } else { - - geometry.vertices.push( - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 6 ] ) - 1 ], - vertices[ parseInt( result[ 10 ] ) - 1 ], - vertices[ parseInt( result[ 14 ] ) - 1 ] - ); - - geometry.faces.push( face4( - verticesCount ++, - verticesCount ++, - verticesCount ++, - verticesCount ++, - [ - normals[ parseInt( result[ 4 ] ) - 1 ], - normals[ parseInt( result[ 8 ] ) - 1 ], - normals[ parseInt( result[ 12 ] ) - 1 ], - normals[ parseInt( result[ 16 ] ) - 1 ] - ] - ) ); - - geometry.faceVertexUvs[ 0 ].push( [ - uvs[ parseInt( result[ 3 ] ) - 1 ], - uvs[ parseInt( result[ 7 ] ) - 1 ], - uvs[ parseInt( result[ 11 ] ) - 1 ], - uvs[ parseInt( result[ 15 ] ) - 1 ] - ] ); - - } + handle_face_line( + [ result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ] ], //faces + [ result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ] ], //uv + [ result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] ] //normal + ); } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] - if ( result[ 10 ] === undefined ) { - - geometry.vertices.push( - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 5 ] ) - 1 ], - vertices[ parseInt( result[ 8 ] ) - 1 ] - ); - - geometry.faces.push( face3( - verticesCount ++, - verticesCount ++, - verticesCount ++, - [ - normals[ parseInt( result[ 3 ] ) - 1 ], - normals[ parseInt( result[ 6 ] ) - 1 ], - normals[ parseInt( result[ 9 ] ) - 1 ] - ] - ) ); - - } else { - - geometry.vertices.push( - vertices[ parseInt( result[ 2 ] ) - 1 ], - vertices[ parseInt( result[ 5 ] ) - 1 ], - vertices[ parseInt( result[ 8 ] ) - 1 ], - vertices[ parseInt( result[ 11 ] ) - 1 ] - ); - - geometry.faces.push( face4( - verticesCount ++, - verticesCount ++, - verticesCount ++, - verticesCount ++, - [ - normals[ parseInt( result[ 3 ] ) - 1 ], - normals[ parseInt( result[ 6 ] ) - 1 ], - normals[ parseInt( result[ 9 ] ) - 1 ], - normals[ parseInt( result[ 12 ] ) - 1 ] - ] - ) ); + handle_face_line( + [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces + [ ], //uv + [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //normal + ); - } - - } else if ( line.startsWith( "o " ) ) { + } else if ( /^o /.test( line ) ) { // object - + + meshN(); + face_offset = face_offset + vertices.length; + vertices = []; object = new THREE.Object3D(); object.name = line.substring( 2 ).trim(); group.add( object ); - } else if ( line.startsWith( "g " ) ) { + } else if ( /^g /.test( line ) ) { // group meshN( line.substring( 2 ).trim(), undefined ); - } else if ( line.startsWith( "usemtl " ) ) { + } else if ( /^usemtl /.test( line ) ) { // material meshN( undefined, line.substring( 7 ).trim() ); - } else if ( line.startsWith( "mtllib ") ) { + } else if ( /^mtllib /.test( line ) ) { // mtl file @@ -550,7 +336,7 @@ console.log(obj3d); } - } else if ( line.startsWith( "s ") ) { + } else if ( /^s /.test( line ) ) { // Smooth shading @@ -562,8 +348,13 @@ console.log(obj3d); } + //Add last object + meshN(undefined, undefined); + return group; } }; + +THREE.EventDispatcher.prototype.apply( THREE.OBJMTLLoader.prototype ); diff --git a/examples/assets/js/libs/OculusRiftEffect.js b/examples/assets/js/libs/OculusRiftEffect.js new file mode 100644 index 0000000..d496334 --- /dev/null +++ b/examples/assets/js/libs/OculusRiftEffect.js @@ -0,0 +1,207 @@ +/** + * @author troffmo5 / http://github.com/troffmo5 + * + * Effect to render the scene in stereo 3d side by side with lens distortion. + * It is written to be used with the Oculus Rift (http://www.oculusvr.com/) but + * it works also with other HMD using the same technology + */ + +THREE.OculusRiftEffect = function ( renderer, options ) { + // worldFactor indicates how many units is 1 meter + var worldFactor = (options && options.worldFactor) ? options.worldFactor: 1.0; + + // Specific HMD parameters + var HMD = (options && options.HMD) ? options.HMD: { + // Parameters from the Oculus Rift DK1 + hResolution: 1280, + vResolution: 800, + hScreenSize: 0.14976, + vScreenSize: 0.0936, + interpupillaryDistance: 0.064, + lensSeparationDistance: 0.064, + eyeToScreenDistance: 0.041, + distortionK : [1.0, 0.22, 0.24, 0.0], + chromaAbParameter: [ 0.996, -0.004, 1.014, 0.0] + }; + + // Perspective camera + var pCamera = new THREE.PerspectiveCamera(); + pCamera.matrixAutoUpdate = false; + pCamera.target = new THREE.Vector3(); + + // Orthographic camera + var oCamera = new THREE.OrthographicCamera( -1, 1, 1, -1, 1, 1000 ); + oCamera.position.z = 1; + + // pre-render hooks + this.preLeftRender = function() {}; + this.preRightRender = function() {}; + + renderer.autoClear = false; + var emptyColor = new THREE.Color("black"); + + // Render target + var RTParams = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat }; + var renderTarget = new THREE.WebGLRenderTarget( 640, 800, RTParams ); + var RTMaterial = new THREE.ShaderMaterial( { + uniforms: { + "texid": { type: "t", value: renderTarget }, + "scale": { type: "v2", value: new THREE.Vector2(1.0,1.0) }, + "scaleIn": { type: "v2", value: new THREE.Vector2(1.0,1.0) }, + "lensCenter": { type: "v2", value: new THREE.Vector2(0.0,0.0) }, + "hmdWarpParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) }, + "chromAbParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) } + }, + vertexShader: [ + "varying vec2 vUv;", + "void main() {", + " vUv = uv;", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + "}" + ].join("\n"), + + fragmentShader: [ + "uniform vec2 scale;", + "uniform vec2 scaleIn;", + "uniform vec2 lensCenter;", + "uniform vec4 hmdWarpParam;", + 'uniform vec4 chromAbParam;', + "uniform sampler2D texid;", + "varying vec2 vUv;", + "void main()", + "{", + " vec2 uv = (vUv*2.0)-1.0;", // range from [0,1] to [-1,1] + " vec2 theta = (uv-lensCenter)*scaleIn;", + " float rSq = theta.x*theta.x + theta.y*theta.y;", + " vec2 rvector = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq);", + ' vec2 rBlue = rvector * (chromAbParam.z + chromAbParam.w * rSq);', + " vec2 tcBlue = (lensCenter + scale * rBlue);", + " tcBlue = (tcBlue+1.0)/2.0;", // range from [-1,1] to [0,1] + " if (any(bvec2(clamp(tcBlue, vec2(0.0,0.0), vec2(1.0,1.0))-tcBlue))) {", + " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);", + " return;}", + " vec2 tcGreen = lensCenter + scale * rvector;", + " tcGreen = (tcGreen+1.0)/2.0;", // range from [-1,1] to [0,1] + " vec2 rRed = rvector * (chromAbParam.x + chromAbParam.y * rSq);", + " vec2 tcRed = lensCenter + scale * rRed;", + " tcRed = (tcRed+1.0)/2.0;", // range from [-1,1] to [0,1] + " gl_FragColor = vec4(texture2D(texid, tcRed).r, texture2D(texid, tcGreen).g, texture2D(texid, tcBlue).b, 1);", + "}" + ].join("\n") + } ); + + var mesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), RTMaterial ); + + // Final scene + var finalScene = new THREE.Scene(); + finalScene.add( oCamera ); + finalScene.add( mesh ); + + var left = {}, right = {}; + var distScale = 1.0; + this.setHMD = function(v) { + HMD = v; + // Compute aspect ratio and FOV + var aspect = HMD.hResolution / (2*HMD.vResolution); + + // Fov is normally computed with: + // THREE.Math.radToDeg( 2*Math.atan2(HMD.vScreenSize,2*HMD.eyeToScreenDistance) ); + // But with lens distortion it is increased (see Oculus SDK Documentation) + var r = -1.0 - (4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize); + distScale = (HMD.distortionK[0] + HMD.distortionK[1] * Math.pow(r,2) + HMD.distortionK[2] * Math.pow(r,4) + HMD.distortionK[3] * Math.pow(r,6)); + var fov = THREE.Math.radToDeg(2*Math.atan2(HMD.vScreenSize*distScale, 2*HMD.eyeToScreenDistance)); + + // Compute camera projection matrices + var proj = (new THREE.Matrix4()).makePerspective( fov, aspect, 0.3, 10000 ); + var h = 4 * (HMD.hScreenSize/4 - HMD.interpupillaryDistance/2) / HMD.hScreenSize; + left.proj = ((new THREE.Matrix4()).makeTranslation( h, 0.0, 0.0 )).multiply(proj); + right.proj = ((new THREE.Matrix4()).makeTranslation( -h, 0.0, 0.0 )).multiply(proj); + + // Compute camera transformation matrices + left.tranform = (new THREE.Matrix4()).makeTranslation( -worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 ); + right.tranform = (new THREE.Matrix4()).makeTranslation( worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 ); + + // Compute Viewport + left.viewport = [0, 0, HMD.hResolution/2, HMD.vResolution]; + right.viewport = [HMD.hResolution/2, 0, HMD.hResolution/2, HMD.vResolution]; + + // Distortion shader parameters + var lensShift = 4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize; + left.lensCenter = new THREE.Vector2(lensShift, 0.0); + right.lensCenter = new THREE.Vector2(-lensShift, 0.0); + + RTMaterial.uniforms['hmdWarpParam'].value = new THREE.Vector4(HMD.distortionK[0], HMD.distortionK[1], HMD.distortionK[2], HMD.distortionK[3]); + RTMaterial.uniforms['chromAbParam'].value = new THREE.Vector4(HMD.chromaAbParameter[0], HMD.chromaAbParameter[1], HMD.chromaAbParameter[2], HMD.chromaAbParameter[3]); + RTMaterial.uniforms['scaleIn'].value = new THREE.Vector2(1.0,1.0/aspect); + RTMaterial.uniforms['scale'].value = new THREE.Vector2(1.0/distScale, 1.0*aspect/distScale); + + // Create render target + if ( renderTarget ) renderTarget.dispose(); + renderTarget = new THREE.WebGLRenderTarget( HMD.hResolution*distScale/2, HMD.vResolution*distScale, RTParams ); + RTMaterial.uniforms[ "texid" ].value = renderTarget; + + } + this.getHMD = function() {return HMD}; + + this.setHMD(HMD); + + this.setSize = function ( width, height ) { + left.viewport = [width/2 - HMD.hResolution/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution]; + right.viewport = [width/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution]; + + renderer.setSize( width, height ); + }; + + this.render = function ( scene, camera ) { + var cc = renderer.getClearColor().clone(); + + // Clear + renderer.setClearColor(emptyColor); + renderer.clear(); + renderer.setClearColor(cc); + + // camera parameters + if (camera.matrixAutoUpdate) camera.updateMatrix(); + + // Render left + this.preLeftRender(); + + pCamera.projectionMatrix.copy(left.proj); + + pCamera.matrix.copy(camera.matrix).multiply(left.tranform); + pCamera.matrixWorldNeedsUpdate = true; + + renderer.setViewport(left.viewport[0], left.viewport[1], left.viewport[2], left.viewport[3]); + + RTMaterial.uniforms['lensCenter'].value = left.lensCenter; + renderer.render( scene, pCamera, renderTarget, true ); + + renderer.render( finalScene, oCamera ); + + // Render right + this.preRightRender(); + + pCamera.projectionMatrix.copy(right.proj); + + pCamera.matrix.copy(camera.matrix).multiply(right.tranform); + pCamera.matrixWorldNeedsUpdate = true; + + renderer.setViewport(right.viewport[0], right.viewport[1], right.viewport[2], right.viewport[3]); + + RTMaterial.uniforms['lensCenter'].value = right.lensCenter; + + renderer.render( scene, pCamera, renderTarget, true ); + renderer.render( finalScene, oCamera ); + + }; + + this.dispose = function() { + if ( RTMaterial ) { + RTMaterial.dispose(); + } + if ( renderTarget ) { + renderTarget.dispose(); + } + }; + +}; diff --git a/examples/assets/js/libs/OrbitControls.js b/examples/assets/js/libs/OrbitControls.js new file mode 100644 index 0000000..e150b58 --- /dev/null +++ b/examples/assets/js/libs/OrbitControls.js @@ -0,0 +1,706 @@ +/** + * @author qiao / https://github.com/qiao + * @author mrdoob / http://mrdoob.com + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author erich666 / http://erichaines.com + */ +/*global THREE, console */ + +// This set of controls performs orbiting, dollying (zooming), and panning. It maintains +// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is +// supported. +// +// Orbit - left mouse / touch: one finger move +// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish +// Pan - right mouse, or arrow keys / touch: three finter swipe + +THREE.OrbitControls = function ( object, domElement ) { + + this.object = object; + this.domElement = ( domElement !== undefined ) ? domElement : document; + + // API + + // Set to false to disable this control + this.enabled = true; + + // "target" sets the location of focus, where the control orbits around + // and where it pans with respect to. + this.target = new THREE.Vector3(); + + // center is old, deprecated; use "target" instead + this.center = this.target; + + // This option actually enables dollying in and out; left as "zoom" for + // backwards compatibility + this.noZoom = false; + this.zoomSpeed = 1.0; + + // Limits to how far you can dolly in and out ( PerspectiveCamera only ) + this.minDistance = 0; + this.maxDistance = Infinity; + + // Limits to how far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; + + // Set to true to disable this control + this.noRotate = false; + this.rotateSpeed = 1.0; + + // Set to true to disable this control + this.noPan = false; + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + + // Set to true to automatically rotate around the target + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + // How far you can orbit horizontally, upper and lower limits. + // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. + this.minAzimuthAngle = - Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians + + // Set to true to disable use of the keys + this.noKeys = false; + + // The four arrow keys + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // Mouse buttons + this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; + + //////////// + // internals + + var scope = this; + + var EPS = 0.000001; + + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); + + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + var panOffset = new THREE.Vector3(); + + var offset = new THREE.Vector3(); + + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); + + var theta; + var phi; + var phiDelta = 0; + var thetaDelta = 0; + var scale = 1; + var pan = new THREE.Vector3(); + + var lastPosition = new THREE.Vector3(); + var lastQuaternion = new THREE.Quaternion(); + + var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; + + var state = STATE.NONE; + + // for reset + + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // so camera.up is the orbit axis + + var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().inverse(); + + // events + + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; + + this.rotateLeft = function ( angle ) { + + if ( angle === undefined ) { + + angle = getAutoRotationAngle(); + + } + + thetaDelta -= angle; + + }; + + this.rotateUp = function ( angle ) { + + if ( angle === undefined ) { + + angle = getAutoRotationAngle(); + + } + + phiDelta -= angle; + + }; + + // pass in distance in world space to move left + this.panLeft = function ( distance ) { + + var te = this.object.matrix.elements; + + // get X column of matrix + panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] ); + panOffset.multiplyScalar( - distance ); + + pan.add( panOffset ); + + }; + + // pass in distance in world space to move up + this.panUp = function ( distance ) { + + var te = this.object.matrix.elements; + + // get Y column of matrix + panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] ); + panOffset.multiplyScalar( distance ); + + pan.add( panOffset ); + + }; + + // pass in x,y of change desired in pixel space, + // right and down are positive + this.pan = function ( deltaX, deltaY ) { + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + // perspective + var position = scope.object.position; + var offset = position.clone().sub( scope.target ); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); + + // we actually don't use screenWidth, since perspective camera is fixed to screen height + scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight ); + scope.panUp( 2 * deltaY * targetDistance / element.clientHeight ); + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + // orthographic + scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth ); + scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight ); + + } else { + + // camera neither orthographic or perspective + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + + } + + }; + + this.dollyIn = function ( dollyScale ) { + + if ( dollyScale === undefined ) { + + dollyScale = getZoomScale(); + + } + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale /= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) ); + scope.object.updateProjectionMatrix(); + scope.dispatchEvent( changeEvent ); + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + + } + + }; + + this.dollyOut = function ( dollyScale ) { + + if ( dollyScale === undefined ) { + + dollyScale = getZoomScale(); + + } + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale *= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) ); + scope.object.updateProjectionMatrix(); + scope.dispatchEvent( changeEvent ); + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + + } + + }; + + this.update = function () { + + var position = this.object.position; + + offset.copy( position ).sub( this.target ); + + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion( quat ); + + // angle from z-axis around y-axis + + theta = Math.atan2( offset.x, offset.z ); + + // angle from y-axis + + phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); + + if ( this.autoRotate && state === STATE.NONE ) { + + this.rotateLeft( getAutoRotationAngle() ); + + } + + theta += thetaDelta; + phi += phiDelta; + + // restrict theta to be between desired limits + theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) ); + + // restrict phi to be between desired limits + phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); + + // restrict phi to be betwee EPS and PI-EPS + phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); + + var radius = offset.length() * scale; + + // restrict radius to be between desired limits + radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); + + // move target to panned location + this.target.add( pan ); + + offset.x = radius * Math.sin( phi ) * Math.sin( theta ); + offset.y = radius * Math.cos( phi ); + offset.z = radius * Math.sin( phi ) * Math.cos( theta ); + + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion( quatInverse ); + + position.copy( this.target ).add( offset ); + + this.object.lookAt( this.target ); + + thetaDelta = 0; + phiDelta = 0; + scale = 1; + pan.set( 0, 0, 0 ); + + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if ( lastPosition.distanceToSquared( this.object.position ) > EPS + || 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > EPS ) { + + this.dispatchEvent( changeEvent ); + + lastPosition.copy( this.object.position ); + lastQuaternion.copy (this.object.quaternion ); + + } + + }; + + + this.reset = function () { + + state = STATE.NONE; + + this.target.copy( this.target0 ); + this.object.position.copy( this.position0 ); + this.object.zoom = this.zoom0; + + this.object.updateProjectionMatrix(); + this.dispatchEvent( changeEvent ); + + this.update(); + + }; + + this.getPolarAngle = function () { + + return phi; + + }; + + this.getAzimuthalAngle = function () { + + return theta + + }; + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function onMouseDown( event ) { + + if ( scope.enabled === false ) return; + event.preventDefault(); + + if ( event.button === scope.mouseButtons.ORBIT ) { + if ( scope.noRotate === true ) return; + + state = STATE.ROTATE; + + rotateStart.set( event.clientX, event.clientY ); + + } else if ( event.button === scope.mouseButtons.ZOOM ) { + if ( scope.noZoom === true ) return; + + state = STATE.DOLLY; + + dollyStart.set( event.clientX, event.clientY ); + + } else if ( event.button === scope.mouseButtons.PAN ) { + if ( scope.noPan === true ) return; + + state = STATE.PAN; + + panStart.set( event.clientX, event.clientY ); + + } + + if ( state !== STATE.NONE ) { + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + scope.dispatchEvent( startEvent ); + } + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + if ( state === STATE.ROTATE ) { + + if ( scope.noRotate === true ) return; + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + } else if ( state === STATE.DOLLY ) { + + if ( scope.noZoom === true ) return; + + dollyEnd.set( event.clientX, event.clientY ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyIn(); + + } else if ( dollyDelta.y < 0 ) { + + scope.dollyOut(); + + } + + dollyStart.copy( dollyEnd ); + + } else if ( state === STATE.PAN ) { + + if ( scope.noPan === true ) return; + + panEnd.set( event.clientX, event.clientY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + } + + if ( state !== STATE.NONE ) scope.update(); + + } + + function onMouseUp( /* event */ ) { + + if ( scope.enabled === false ) return; + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + scope.dispatchEvent( endEvent ); + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + + if ( scope.enabled === false || scope.noZoom === true || state !== STATE.NONE ) return; + + event.preventDefault(); + event.stopPropagation(); + + var delta = 0; + + if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9 + + delta = event.wheelDelta; + + } else if ( event.detail !== undefined ) { // Firefox + + delta = - event.detail; + + } + + if ( delta > 0 ) { + + scope.dollyOut(); + + } else if ( delta < 0 ) { + + scope.dollyIn(); + + } + + scope.update(); + scope.dispatchEvent( startEvent ); + scope.dispatchEvent( endEvent ); + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return; + + switch ( event.keyCode ) { + + case scope.keys.UP: + scope.pan( 0, scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.BOTTOM: + scope.pan( 0, - scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.LEFT: + scope.pan( scope.keyPanSpeed, 0 ); + scope.update(); + break; + + case scope.keys.RIGHT: + scope.pan( - scope.keyPanSpeed, 0 ); + scope.update(); + break; + + } + + } + + function touchstart( event ) { + + if ( scope.enabled === false ) return; + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.noRotate === true ) return; + + state = STATE.TOUCH_ROTATE; + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: // two-fingered touch: dolly + + if ( scope.noZoom === true ) return; + + state = STATE.TOUCH_DOLLY; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + dollyStart.set( 0, distance ); + break; + + case 3: // three-fingered touch: pan + + if ( scope.noPan === true ) return; + + state = STATE.TOUCH_PAN; + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent ); + + } + + function touchmove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.noRotate === true ) return; + if ( state !== STATE.TOUCH_ROTATE ) return; + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + break; + + case 2: // two-fingered touch: dolly + + if ( scope.noZoom === true ) return; + if ( state !== STATE.TOUCH_DOLLY ) return; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyOut(); + + } else if ( dollyDelta.y < 0 ) { + + scope.dollyIn(); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + break; + + case 3: // three-fingered touch: pan + + if ( scope.noPan === true ) return; + if ( state !== STATE.TOUCH_PAN ) return; + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + break; + + default: + + state = STATE.NONE; + + } + + } + + function touchend( /* event */ ) { + + if ( scope.enabled === false ) return; + + scope.dispatchEvent( endEvent ); + state = STATE.NONE; + + } + + this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); + this.domElement.addEventListener( 'mousedown', onMouseDown, false ); + this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.addEventListener( 'touchstart', touchstart, false ); + this.domElement.addEventListener( 'touchend', touchend, false ); + this.domElement.addEventListener( 'touchmove', touchmove, false ); + + window.addEventListener( 'keydown', onKeyDown, false ); + + // force an update at start + this.update(); + +}; + +THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); +THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; diff --git a/examples/assets/js/libs/ShaderTerrain.js b/examples/assets/js/libs/ShaderTerrain.js new file mode 100644 index 0000000..015180d --- /dev/null +++ b/examples/assets/js/libs/ShaderTerrain.js @@ -0,0 +1,323 @@ +/** + * @author alteredq / http://alteredqualia.com/ + * + */ + +THREE.ShaderTerrain = { + + /* ------------------------------------------------------------------------- + // Dynamic terrain shader + // - Blinn-Phong + // - height + normal + diffuse1 + diffuse2 + specular + detail maps + // - point, directional and hemisphere lights (use with "lights: true" material option) + // - shadow maps receiving + ------------------------------------------------------------------------- */ + + 'terrain' : { + + uniforms: Object.assign( + + + { + + "enableDiffuse1": { value: 0 }, + "enableDiffuse2": { value: 0 }, + "enableSpecular": { value: 0 }, + "enableReflection": { value: 0 }, + + "tDiffuse1": { value: null }, + "tDiffuse2": { value: null }, + "tDetail": { value: null }, + "tNormal": { value: null }, + "tSpecular": { value: null }, + "tDisplacement": { value: null }, + + "uNormalScale": { value: 1.0 }, + + "uDisplacementBias": { value: 0.0 }, + "uDisplacementScale": { value: 1.0 }, + + "diffuse": { value: new THREE.Color( 0xeeeeee ) }, + "specular": { value: new THREE.Color( 0x111111 ) }, + "shininess": { value: 30 }, + "opacity": { value: 1 }, + + "uRepeatBase": { value: new THREE.Vector2( 1, 1 ) }, + "uRepeatOverlay": { value: new THREE.Vector2( 1, 1 ) }, + + "uOffset": { value: new THREE.Vector2( 0, 0 ) } + + }, + + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ] + + ), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform vec3 specular;", + "uniform float shininess;", + "uniform float opacity;", + + "uniform bool enableDiffuse1;", + "uniform bool enableDiffuse2;", + "uniform bool enableSpecular;", + + "uniform sampler2D tDiffuse1;", + "uniform sampler2D tDiffuse2;", + "uniform sampler2D tDetail;", + "uniform sampler2D tNormal;", + "uniform sampler2D tSpecular;", + "uniform sampler2D tDisplacement;", + + "uniform float uNormalScale;", + + "uniform vec2 uRepeatOverlay;", + "uniform vec2 uRepeatBase;", + + "uniform vec2 uOffset;", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "bsdfs" ], + THREE.ShaderChunk[ "lights_pars" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + + "float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {", + "if ( decayExponent > 0.0 ) {", + "return pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );", + "}", + "return 1.0;", + "}", + + "void main() {", + + "vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + "vec4 diffuseColor = vec4( diffuse, opacity );", + + "vec3 specularTex = vec3( 1.0 );", + + "vec2 uvOverlay = uRepeatOverlay * vUv + uOffset;", + "vec2 uvBase = uRepeatBase * vUv;", + + "vec3 normalTex = texture2D( tDetail, uvOverlay ).xyz * 2.0 - 1.0;", + "normalTex.xy *= uNormalScale;", + "normalTex = normalize( normalTex );", + + "if( enableDiffuse1 && enableDiffuse2 ) {", + + "vec4 colDiffuse1 = texture2D( tDiffuse1, uvOverlay );", + "vec4 colDiffuse2 = texture2D( tDiffuse2, uvOverlay );", + + "colDiffuse1 = GammaToLinear( colDiffuse1, float( GAMMA_FACTOR ) );", + "colDiffuse2 = GammaToLinear( colDiffuse2, float( GAMMA_FACTOR ) );", + + "diffuseColor *= mix ( colDiffuse1, colDiffuse2, 1.0 - texture2D( tDisplacement, uvBase ) );", + + " } else if( enableDiffuse1 ) {", + + "diffuseColor *= texture2D( tDiffuse1, uvOverlay );", + + "} else if( enableDiffuse2 ) {", + + "diffuseColor *= texture2D( tDiffuse2, uvOverlay );", + + "}", + + "if( enableSpecular )", + "specularTex = texture2D( tSpecular, uvOverlay ).xyz;", + + "mat3 tsb = mat3( vTangent, vBinormal, vNormal );", + "vec3 finalNormal = tsb * normalTex;", + + "vec3 normal = normalize( finalNormal );", + "vec3 viewPosition = normalize( vViewPosition );", + + "vec3 totalDiffuseLight = vec3( 0.0 );", + "vec3 totalSpecularLight = vec3( 0.0 );", + + // point lights + + "#if NUM_POINT_LIGHTS > 0", + + "for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {", + + "vec3 lVector = pointLights[ i ].position + vViewPosition.xyz;", + + "float attenuation = calcLightAttenuation( length( lVector ), pointLights[ i ].distance, pointLights[ i ].decay );", + + "lVector = normalize( lVector );", + + "vec3 pointHalfVector = normalize( lVector + viewPosition );", + + "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + "float pointDiffuseWeight = max( dot( normal, lVector ), 0.0 );", + + "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + + "totalDiffuseLight += attenuation * pointLights[ i ].color * pointDiffuseWeight;", + "totalSpecularLight += attenuation * pointLights[ i ].color * specular * pointSpecularWeight * pointDiffuseWeight;", + + "}", + + "#endif", + + // directional lights + + "#if NUM_DIR_LIGHTS > 0", + + "vec3 dirDiffuse = vec3( 0.0 );", + "vec3 dirSpecular = vec3( 0.0 );", + + "for( int i = 0; i < NUM_DIR_LIGHTS; i++ ) {", + + "vec3 dirVector = directionalLights[ i ].direction;", + "vec3 dirHalfVector = normalize( dirVector + viewPosition );", + + "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", + "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", + + "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );", + + "totalDiffuseLight += directionalLights[ i ].color * dirDiffuseWeight;", + "totalSpecularLight += directionalLights[ i ].color * specular * dirSpecularWeight * dirDiffuseWeight;", + + "}", + + "#endif", + + // hemisphere lights + + "#if NUM_HEMI_LIGHTS > 0", + + "vec3 hemiDiffuse = vec3( 0.0 );", + "vec3 hemiSpecular = vec3( 0.0 );", + + "for( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {", + + "vec3 lVector = hemisphereLightDirection[ i ];", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + + "totalDiffuseLight += mix( hemisphereLights[ i ].groundColor, hemisphereLights[ i ].skyColor, hemiDiffuseWeight );", + + // specular (sky light) + + "float hemiSpecularWeight = 0.0;", + + "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", + "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", + "hemiSpecularWeight += specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + + // specular (ground light) + + "vec3 lVectorGround = -lVector;", + + "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", + "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", + "hemiSpecularWeight += specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + + "totalSpecularLight += specular * mix( hemisphereLights[ i ].groundColor, hemisphereLights[ i ].skyColor, hemiDiffuseWeight ) * hemiSpecularWeight * hemiDiffuseWeight;", + + "}", + + "#endif", + + "outgoingLight += diffuseColor.xyz * ( totalDiffuseLight + ambientLightColor + totalSpecularLight );", + + "gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join( "\n" ), + + vertexShader: [ + + "attribute vec4 tangent;", + + "uniform vec2 uRepeatBase;", + + "uniform sampler2D tNormal;", + + "#ifdef VERTEX_TEXTURES", + + "uniform sampler2D tDisplacement;", + "uniform float uDisplacementScale;", + "uniform float uDisplacementBias;", + + "#endif", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + "vNormal = normalize( normalMatrix * normal );", + + // tangent and binormal vectors + + "vTangent = normalize( normalMatrix * tangent.xyz );", + + "vBinormal = cross( vNormal, vTangent ) * tangent.w;", + "vBinormal = normalize( vBinormal );", + + // texture coordinates + + "vUv = uv;", + + "vec2 uvBase = uv * uRepeatBase;", + + // displacement mapping + + "#ifdef VERTEX_TEXTURES", + + "vec3 dv = texture2D( tDisplacement, uvBase ).xyz;", + "float df = uDisplacementScale * dv.x + uDisplacementBias;", + "vec3 displacedPosition = normal * df + position;", + + "vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", + "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", + + "#else", + + "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + + "#endif", + + "gl_Position = projectionMatrix * mvPosition;", + + "vViewPosition = -mvPosition.xyz;", + + "vec3 normalTex = texture2D( tNormal, uvBase ).xyz * 2.0 - 1.0;", + "vNormal = normalMatrix * normalTex;", + + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join( "\n" ) + + } + +}; diff --git a/examples/assets/js/libs/three.min.js b/examples/assets/js/libs/three.min.js index 9444281..47cb69e 100644 --- a/examples/assets/js/libs/three.min.js +++ b/examples/assets/js/libs/three.min.js @@ -1,699 +1,838 @@ -// three.js - http://github.com/mrdoob/three.js -'use strict';var THREE=THREE||{REVISION:"55"};self.console=self.console||{info:function(){},log:function(){},debug:function(){},warn:function(){},error:function(){}};self.Int32Array=self.Int32Array||Array;self.Float32Array=self.Float32Array||Array;String.prototype.startsWith=String.prototype.startsWith||function(a){return this.slice(0,a.length)===a};String.prototype.endsWith=String.prototype.endsWith||function(a){var a=String(a),b=this.lastIndexOf(a);return(-1>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSV:function(a,b,c){var d,e,f;0===c?this.r=this.g=this.b=0:(d=Math.floor(6*a),e=6*a-d,a=c*(1-b),f=c*(1-b*e),b=c*(1-b*(1-e)),0===d?(this.r=c,this.g=b,this.b=a):1=== -d?(this.r=f,this.g=c,this.b=a):2===d?(this.r=a,this.g=c,this.b=b):3===d?(this.r=a,this.g=f,this.b=c):4===d?(this.r=b,this.g=a,this.b=c):5===d&&(this.r=c,this.g=a,this.b=f));return this},setStyle:function(a){if(/^rgb\((\d+),(\d+),(\d+)\)$/i.test(a))return a=/^rgb\((\d+),(\d+),(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.test(a))return a=/^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.exec(a), -this.r=Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]),this},copy:function(a){this.r=a.r; -this.g=a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255*this.r<<16^ -255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getStyle:function(){return"rgb("+(255*this.r|0)+","+(255*this.g|0)+","+(255*this.b|0)+")"},getHSV:function(a){var b=this.r,c=this.g,d=this.b,e=Math.max(Math.max(b,c),d),f=Math.min(Math.min(b,c),d);if(f===e)f=b=0;else{var g=e-f,f=g/e,b=(b===e?(c-d)/g:c===e?2+(d-b)/g:4+(b-c)/g)/6;0>b&&(b+=1);1f&&c>b?(c=2*Math.sqrt(1+c-f-b),this.w=(h-g)/c,this.x=0.25*c,this.y=(a+e)/c,this.z=(d+i)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this.w=(d-i)/c,this.x=(a+e)/c,this.y=0.25*c,this.z=(g+h)/c):(c=2*Math.sqrt(1+b-c-f),this.w=(e-a)/c,this.x=(d+i)/c,this.y=(g+h)/c,this.z=0.25*c);return this},inverse:function(){this.conjugate().normalize(); -return this},conjugate:function(){this.x*=-1;this.y*=-1;this.z*=-1;return this},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 a=this.length();0===a?(this.z=this.y=this.x=0,this.w=1):(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a);return this},multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Quaternion's .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."), -this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a.x,d=a.y,e=a.z,f=a.w,g=b.x,i=b.y,h=b.z,k=b.w;this.x=c*k+f*g+d*h-e*i;this.y=d*k+f*i+e*g-c*h;this.z=e*k+f*h+c*i-d*g;this.w=f*k-c*g-d*i-e*h;return this},multiplyVector3:function(a){console.warn("DEPRECATED: Quaternion's .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.");return a.applyQuaternion(this)},slerp:function(a,b){var c=this.x,d=this.y,e=this.z, -f=this.w,g=f*a.w+c*a.x+d*a.y+e*a.z;0>g?(this.w=-a.w,this.x=-a.x,this.y=-a.y,this.z=-a.z,g=-g):this.copy(a);if(1<=g)return this.w=f,this.x=c,this.y=d,this.z=e,this;var i=Math.acos(g),h=Math.sqrt(1-g*g);if(0.001>Math.abs(h))return this.w=0.5*(f+this.w),this.x=0.5*(c+this.x),this.y=0.5*(d+this.y),this.z=0.5*(e+this.z),this;g=Math.sin((1-b)*i)/h;i=Math.sin(b*i)/h;this.w=f*g+this.w*i;this.x=c*g+this.x*i;this.y=d*g+this.y*i;this.z=e*g+this.z*i;return this},equals:function(a){return a.x===this.x&&a.y=== -this.y&&a.z===this.z&&a.w===this.w},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; -THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a, -b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-= -a.y;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a):this.set(0,0);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);return this}, -negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.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)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/ -b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; -THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ -a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;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},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), -this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;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(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;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},applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements,e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]); -this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z,a=a.w,i=a*b+f*d-g*c,h=a*c+g*b-e*d,k=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=i*a+b*-e+h*-g-k*-f;this.y=h*a+b*-f+k*-e-i*-g;this.z=k*a+b*-g+i*-f-h*-e;return this},applyEuler:function(a,b){var c=THREE.Vector3.__q1.setFromEuler(a,b);this.applyQuaternion(c);return this},applyAxisAngle:function(a,b){var c=THREE.Vector3.__q1.setFromAxisAngle(a, -b);this.applyQuaternion(c);return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a,this.z/=a):this.z=this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.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(a){var b= -this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y= -a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},angleTo:function(a){return Math.acos(this.dot(a)/this.length()/a.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y,a=this.z-a.z;return b*b+c*c+a*a},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},setEulerFromRotationMatrix:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.elements, -e=d[0],f=d[4],g=d[8],i=d[1],h=d[5],k=d[9],l=d[2],m=d[6],d=d[10];void 0===b||"XYZ"===b?(this.y=Math.asin(c(g)),0.99999>Math.abs(g)?(this.x=Math.atan2(-k,d),this.z=Math.atan2(-f,e)):(this.x=Math.atan2(m,h),this.z=0)):"YXZ"===b?(this.x=Math.asin(-c(k)),0.99999>Math.abs(k)?(this.y=Math.atan2(g,d),this.z=Math.atan2(i,h)):(this.y=Math.atan2(-l,e),this.z=0)):"ZXY"===b?(this.x=Math.asin(c(m)),0.99999>Math.abs(m)?(this.y=Math.atan2(-l,d),this.z=Math.atan2(-f,h)):(this.y=0,this.z=Math.atan2(i,e))):"ZYX"=== -b?(this.y=Math.asin(-c(l)),0.99999>Math.abs(l)?(this.x=Math.atan2(m,d),this.z=Math.atan2(i,e)):(this.x=0,this.z=Math.atan2(-f,h))):"YZX"===b?(this.z=Math.asin(c(i)),0.99999>Math.abs(i)?(this.x=Math.atan2(-k,h),this.y=Math.atan2(-l,e)):(this.x=0,this.y=Math.atan2(g,d))):"XZY"===b&&(this.z=Math.asin(-c(f)),0.99999>Math.abs(f)?(this.x=Math.atan2(m,h),this.y=Math.atan2(g,e)):(this.x=Math.atan2(-k,d),this.y=0));return this},setEulerFromQuaternion:function(a,b){function c(a){return Math.min(Math.max(a, --1),1)}var d=a.x*a.x,e=a.y*a.y,f=a.z*a.z,g=a.w*a.w;void 0===b||"XYZ"===b?(this.x=Math.atan2(2*(a.x*a.w-a.y*a.z),g-d-e+f),this.y=Math.asin(c(2*(a.x*a.z+a.y*a.w))),this.z=Math.atan2(2*(a.z*a.w-a.x*a.y),g+d-e-f)):"YXZ"===b?(this.x=Math.asin(c(2*(a.x*a.w-a.y*a.z))),this.y=Math.atan2(2*(a.x*a.z+a.y*a.w),g-d-e+f),this.z=Math.atan2(2*(a.x*a.y+a.z*a.w),g-d+e-f)):"ZXY"===b?(this.x=Math.asin(c(2*(a.x*a.w+a.y*a.z))),this.y=Math.atan2(2*(a.y*a.w-a.z*a.x),g-d-e+f),this.z=Math.atan2(2*(a.z*a.w-a.x*a.y),g-d+e-f)): -"ZYX"===b?(this.x=Math.atan2(2*(a.x*a.w+a.z*a.y),g-d-e+f),this.y=Math.asin(c(2*(a.y*a.w-a.x*a.z))),this.z=Math.atan2(2*(a.x*a.y+a.z*a.w),g+d-e-f)):"YZX"===b?(this.x=Math.atan2(2*(a.x*a.w-a.z*a.y),g-d+e-f),this.y=Math.atan2(2*(a.y*a.w-a.x*a.z),g+d-e-f),this.z=Math.asin(c(2*(a.x*a.y+a.z*a.w)))):"XZY"===b&&(this.x=Math.atan2(2*(a.x*a.w+a.y*a.z),g-d+e-f),this.y=Math.atan2(2*(a.x*a.z+a.y*a.w),g+d-e-f),this.z=Math.asin(c(2*(a.z*a.w-a.x*a.y))));return this},getScaleFromMatrix:function(a){var b=this.set(a.elements[0], -a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}};THREE.Vector3.__q1=new THREE.Quaternion;THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}; -THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x; -case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;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},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;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(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this}, -applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a,this.z/=a,this.w/=a):(this.z=this.y=this.x=0,this.w=1);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.x< -a.x&&(this.x=a.x);this.yb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);this.wb.w&&(this.w=b.w);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.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(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},equals:function(a){return a.x=== -this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d,a=a.elements,e=a[0];d=a[4];var f=a[8],g=a[1],i=a[5],h=a[9];c=a[2];b=a[6];var k=a[10];if(0.01>Math.abs(d-g)&&0.01>Math.abs(f-c)&&0.01>Math.abs(h-b)){if(0.1> -Math.abs(d+g)&&0.1>Math.abs(f+c)&&0.1>Math.abs(h+b)&&0.1>Math.abs(e+i+k-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;i=(i+1)/2;k=(k+1)/2;d=(d+g)/4;f=(f+c)/4;h=(h+b)/4;e>i&&e>k?0.01>e?(b=0,d=c=0.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):i>k?0.01>i?(b=0.707106781,c=0,d=0.707106781):(c=Math.sqrt(i),b=d/c,d=h/c):0.01>k?(c=b=0.707106781,d=0):(d=Math.sqrt(k),b=f/d,c=h/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-h)*(b-h)+(f-c)*(f-c)+(g-d)*(g-d));0.001>Math.abs(a)&&(a=1);this.x=(b-h)/a;this.y=(f- -c)/a;this.z=(g-d)/a;this.w=Math.acos((e+i+k-1)/2);return this}};THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; -THREE.Box2.prototype={constructor:THREE.Box2,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0this.max.x&&(this.max.x=b.x),b.ythis.max.y&&(this.max.y=b.y)}else this.makeEmpty();return this},setFromCenterAndSize:function(a,b){var c=THREE.Box2.__v1.copy(b).multiplyScalar(0.5);this.min.copy(a).sub(c); -this.max.copy(a).add(c);return this},copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a){return new THREE.Vector2((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/ -(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(a){return THREE.Box2.__v1.copy(a).clamp(this.min,this.max).sub(a).length()},intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a); -this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}};THREE.Box2.__v1=new THREE.Vector2;THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; -THREE.Box3.prototype={constructor:THREE.Box3,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0this.max.x&&(this.max.x=b.x),b.ythis.max.y&&(this.max.y=b.y),b.zthis.max.z&&(this.max.z=b.z)}else this.makeEmpty();return this},setFromCenterAndSize:function(a,b){var c=THREE.Box3.__v1.copy(b).multiplyScalar(0.5); -this.min.copy(a).sub(c);this.max.copy(a).add(c);return this},copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=this.min.z=Infinity;this.max.x=this.max.y=this.max.z=-Infinity;return this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<= -a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a){return new THREE.Vector3((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},clampPoint:function(a,b){b||new THREE.Vector3;return(new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(a){return THREE.Box3.__v1.copy(a).clamp(this.min, -this.max).sub(a).length()},getBoundingSphere:function(a){a=a||new THREE.Sphere;a.center=this.center();a.radius=0.5*this.size(THREE.Box3.__v0).length();return a},intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},transform:function(a){a=[THREE.Box3.__v0.set(this.min.x,this.min.y,this.min.z).applyMatrix4(a),THREE.Box3.__v0.set(this.min.x,this.min.y,this.min.z).applyMatrix4(a),THREE.Box3.__v1.set(this.min.x, -this.min.y,this.max.z).applyMatrix4(a),THREE.Box3.__v2.set(this.min.x,this.max.y,this.min.z).applyMatrix4(a),THREE.Box3.__v3.set(this.min.x,this.max.y,this.max.z).applyMatrix4(a),THREE.Box3.__v4.set(this.max.x,this.min.y,this.min.z).applyMatrix4(a),THREE.Box3.__v5.set(this.max.x,this.min.y,this.max.z).applyMatrix4(a),THREE.Box3.__v6.set(this.max.x,this.max.y,this.min.z).applyMatrix4(a),THREE.Box3.__v7.set(this.max.x,this.max.y,this.max.z).applyMatrix4(a)];this.makeEmpty();this.setFromPoints(a);return this}, -translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}};THREE.Box3.__v0=new THREE.Vector3;THREE.Box3.__v1=new THREE.Vector3;THREE.Box3.__v2=new THREE.Vector3;THREE.Box3.__v3=new THREE.Vector3;THREE.Box3.__v4=new THREE.Vector3;THREE.Box3.__v5=new THREE.Vector3;THREE.Box3.__v6=new THREE.Vector3;THREE.Box3.__v7=new THREE.Vector3;THREE.Matrix3=function(a,b,c,d,e,f,g,i,h){this.elements=new Float32Array(9);this.set(void 0!==a?a:1,b||0,c||0,d||0,void 0!==e?e:1,f||0,g||0,i||0,void 0!==h?h:1)}; -THREE.Matrix3.prototype={constructor:THREE.Matrix3,set:function(a,b,c,d,e,f,g,i,h){var k=this.elements;k[0]=a;k[3]=b;k[6]=c;k[1]=d;k[4]=e;k[7]=f;k[2]=g;k[5]=i;k[8]=h;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},multiplyVector3:function(a){console.warn("DEPRECATED: Matrix3's .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)}, -multiplyVector3Array:function(a){for(var b=THREE.Matrix3.__v1,c=0,d=a.length;c<=a.radius},isIntersectionPlane:function(a){return 0!=a.normal.dot(this.direction)||0==a.distanceToPoint(this.origin)?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction); -if(0==b){if(0==a.distanceToPoint(this.origin))return 0}else return-(this.origin.dot(a.normal)+a.constant)/b},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return void 0===c?void 0:this.at(c,b)},transform:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)},clone:function(){return(new THREE.Ray).copy(this)}}; -THREE.Ray.__v1=new THREE.Vector3;THREE.Ray.__v2=new THREE.Vector3;THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0}; -THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromCenterAndPoints:function(a,b){for(var c=0,d=0,e=b.length;d=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)- -this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius);return a},transform:function(a){this.center.applyMatrix4(a); -this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}};THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; -THREE.Frustum.prototype={set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,a=c[0],d=c[1],e=c[2],f=c[3],g=c[4],i=c[5],h=c[6],k=c[7],l=c[8],m=c[9],n=c[10],r=c[11],p=c[12],q=c[13],s=c[14],c=c[15];b[0].setComponents(f-a,k-g,r-l,c-p).normalize();b[1].setComponents(f+a,k+g,r+l, -c+p).normalize();b[2].setComponents(f+d,k+i,r+m,c+q).normalize();b[3].setComponents(f-d,k-i,r-m,c-q).normalize();b[4].setComponents(f-e,k-h,r-n,c-s).normalize();b[5].setComponents(f+e,k+h,r+n,c+s).normalize();return this},intersectsObject:function(a){for(var b=a.matrixWorld,c=this.planes,d=b.getPosition(),a=-a.geometry.boundingSphere.radius*b.getMaxScaleOnAxis(),b=0;6>b;b++)if(c[b].distanceToPoint(d)d;d++)if(b[d].distanceToPoint(c)c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; -THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(a,b,c){b=THREE.Plane.__v1.subVectors(c,b).cross(THREE.Plane.__v2.subVectors(a,b)).normalize();this.setFromNormalAndCoplanarPoint(b,a);return this},copy:function(a){this.normal.copy(a.normal); +// threejs.org/license +(function(l,sa){"object"===typeof exports&&"undefined"!==typeof module?sa(exports):"function"===typeof define&&define.amd?define(["exports"],sa):sa(l.THREE=l.THREE||{})})(this,function(l){function sa(){}function B(a,b){this.x=a||0;this.y=b||0}function da(a,b,c,d,e,f,g,h,k,m){Object.defineProperty(this,"id",{value:ee++});this.uuid=T.generateUUID();this.sourceFile=this.name="";this.image=void 0!==a?a:da.DEFAULT_IMAGE;this.mipmaps=[];this.mapping=void 0!==b?b:da.DEFAULT_MAPPING;this.wrapS=void 0!==c? +c:1001;this.wrapT=void 0!==d?d:1001;this.magFilter=void 0!==e?e:1006;this.minFilter=void 0!==f?f:1008;this.anisotropy=void 0!==k?k:1;this.format=void 0!==g?g:1023;this.type=void 0!==h?h:1009;this.offset=new B(0,0);this.repeat=new B(1,1);this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this.encoding=void 0!==m?m:3E3;this.version=0;this.onUpdate=null}function ga(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}function Db(a,b,c){this.uuid=T.generateUUID(); +this.width=a;this.height=b;this.scissor=new ga(0,0,a,b);this.scissorTest=!1;this.viewport=new ga(0,0,a,b);c=c||{};void 0===c.minFilter&&(c.minFilter=1006);this.texture=new da(void 0,void 0,c.wrapS,c.wrapT,c.magFilter,c.minFilter,c.format,c.type,c.anisotropy,c.encoding);this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.depthTexture=void 0!==c.depthTexture?c.depthTexture:null}function Eb(a,b,c){Db.call(this,a,b,c);this.activeMipMapLevel= +this.activeCubeFace=0}function ba(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._w=void 0!==d?d:1}function q(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}function J(){this.elements=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);0= +d||0< alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n")); +y.compileShader(P);y.compileShader(R);y.attachShader(N,P);y.attachShader(N,R);y.linkProgram(N);M=N;u=y.getAttribLocation(M,"position");v=y.getAttribLocation(M,"uv");c=y.getUniformLocation(M,"uvOffset");d=y.getUniformLocation(M,"uvScale");e=y.getUniformLocation(M,"rotation");f=y.getUniformLocation(M,"scale");g=y.getUniformLocation(M,"color");h=y.getUniformLocation(M,"map");k=y.getUniformLocation(M,"opacity");m=y.getUniformLocation(M,"modelViewMatrix");w=y.getUniformLocation(M,"projectionMatrix");n= +y.getUniformLocation(M,"fogType");p=y.getUniformLocation(M,"fogDensity");r=y.getUniformLocation(M,"fogNear");x=y.getUniformLocation(M,"fogFar");l=y.getUniformLocation(M,"fogColor");D=y.getUniformLocation(M,"alphaTest");N=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");N.width=8;N.height=8;P=N.getContext("2d");P.fillStyle="white";P.fillRect(0,0,8,8);ca=new da(N);ca.needsUpdate=!0}y.useProgram(M);E.initAttributes();E.enableAttribute(u);E.enableAttribute(v);E.disableUnusedAttributes(); +E.disable(y.CULL_FACE);E.enable(y.BLEND);y.bindBuffer(y.ARRAY_BUFFER,H);y.vertexAttribPointer(u,2,y.FLOAT,!1,16,0);y.vertexAttribPointer(v,2,y.FLOAT,!1,16,8);y.bindBuffer(y.ELEMENT_ARRAY_BUFFER,F);y.uniformMatrix4fv(w,!1,Ka.projectionMatrix.elements);E.activeTexture(y.TEXTURE0);y.uniform1i(h,0);P=N=0;(R=q.fog)?(y.uniform3f(l,R.color.r,R.color.g,R.color.b),R&&R.isFog?(y.uniform1f(r,R.near),y.uniform1f(x,R.far),y.uniform1i(n,1),P=N=1):R&&R.isFogExp2&&(y.uniform1f(p,R.density),y.uniform1i(n,2),P=N=2)): +(y.uniform1i(n,0),P=N=0);for(var R=0,S=b.length;R<([\w\d.]+)>/g,function(a,c){var d=X[c];if(void 0===d)throw Error("Can not resolve #include <"+c+">");return Cd(d)})}function ve(a){return a.replace(/for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g,function(a,c,d,e){a="";for(c=parseInt(c);cb||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);console.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height,a);return d}return a} +function k(a){return T.isPowerOfTwo(a.width)&&T.isPowerOfTwo(a.height)}function m(b){return 1003===b||1004===b||1005===b?a.NEAREST:a.LINEAR}function w(b){b=b.target;b.removeEventListener("dispose",w);a:{var c=d.get(b);if(b.image&&c.__image__webglTextureCube)a.deleteTexture(c.__image__webglTextureCube);else{if(void 0===c.__webglInit)break a;a.deleteTexture(c.__webglTexture)}d["delete"](b)}q.textures--}function n(b){b=b.target;b.removeEventListener("dispose",n);var c=d.get(b),e=d.get(b.texture);if(b){void 0!== +e.__webglTexture&&a.deleteTexture(e.__webglTexture);b.depthTexture&&b.depthTexture.dispose();if(b&&b.isWebGLRenderTargetCube)for(e=0;6>e;e++)a.deleteFramebuffer(c.__webglFramebuffer[e]),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer[e]);else a.deleteFramebuffer(c.__webglFramebuffer),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer);d["delete"](b.texture);d["delete"](b)}q.textures--}function p(b,g){var m=d.get(b);if(0x;x++)l[x]=p||n?n?b.image[x].image:b.image[x]:h(b.image[x],e.maxCubemapSize);var t=k(l[0]),u=f(b.format),ja=f(b.type);r(a.TEXTURE_CUBE_MAP, +b,t);for(x=0;6>x;x++)if(p)for(var B,C=l[x].mipmaps,z=0,N=C.length;zm;m++)e.__webglFramebuffer[m]=a.createFramebuffer()}else e.__webglFramebuffer=a.createFramebuffer();if(g){c.bindTexture(a.TEXTURE_CUBE_MAP,f.__webglTexture);r(a.TEXTURE_CUBE_MAP,b.texture,h);for(m=0;6>m;m++)l(e.__webglFramebuffer[m],b,a.COLOR_ATTACHMENT0,a.TEXTURE_CUBE_MAP_POSITIVE_X+m);b.texture.generateMipmaps&&h&&a.generateMipmap(a.TEXTURE_CUBE_MAP);c.bindTexture(a.TEXTURE_CUBE_MAP, +null)}else c.bindTexture(a.TEXTURE_2D,f.__webglTexture),r(a.TEXTURE_2D,b.texture,h),l(e.__webglFramebuffer,b,a.COLOR_ATTACHMENT0,a.TEXTURE_2D),b.texture.generateMipmaps&&h&&a.generateMipmap(a.TEXTURE_2D),c.bindTexture(a.TEXTURE_2D,null);if(b.depthBuffer){e=d.get(b);f=b&&b.isWebGLRenderTargetCube;if(b.depthTexture){if(f)throw Error("target.depthTexture not supported in Cube render targets");if(b&&b.isWebGLRenderTargetCube)throw Error("Depth Texture with cube render targets is not supported!");a.bindFramebuffer(a.FRAMEBUFFER, +e.__webglFramebuffer);if(!b.depthTexture||!b.depthTexture.isDepthTexture)throw Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");d.get(b.depthTexture).__webglTexture&&b.depthTexture.image.width===b.width&&b.depthTexture.image.height===b.height||(b.depthTexture.image.width=b.width,b.depthTexture.image.height=b.height,b.depthTexture.needsUpdate=!0);p(b.depthTexture,0);e=d.get(b.depthTexture).__webglTexture;if(1026===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER, +a.DEPTH_ATTACHMENT,a.TEXTURE_2D,e,0);else if(1027===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER,a.DEPTH_STENCIL_ATTACHMENT,a.TEXTURE_2D,e,0);else throw Error("Unknown depthTexture format");}else if(f)for(e.__webglDepthbuffer=[],f=0;6>f;f++)a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer[f]),e.__webglDepthbuffer[f]=a.createRenderbuffer(),t(e.__webglDepthbuffer[f],b);else a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer),e.__webglDepthbuffer=a.createRenderbuffer(),t(e.__webglDepthbuffer, +b);a.bindFramebuffer(a.FRAMEBUFFER,null)}};this.updateRenderTargetMipmap=function(b){var e=b.texture;e.generateMipmaps&&k(b)&&1003!==e.minFilter&&1006!==e.minFilter&&(b=b&&b.isWebGLRenderTargetCube?a.TEXTURE_CUBE_MAP:a.TEXTURE_2D,e=d.get(e).__webglTexture,c.bindTexture(b,e),a.generateMipmap(b),c.bindTexture(b,null))}}function xf(){var a={};return{get:function(b){b=b.uuid;var c=a[b];void 0===c&&(c={},a[b]=c);return c},"delete":function(b){delete a[b.uuid]},clear:function(){a={}}}}function yf(a,b,c){function d(b, +c,d){var e=new Uint8Array(4),f=a.createTexture();a.bindTexture(b,f);a.texParameteri(b,a.TEXTURE_MIN_FILTER,a.NEAREST);a.texParameteri(b,a.TEXTURE_MAG_FILTER,a.NEAREST);for(b=0;b=ia.maxTextures&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+ia.maxTextures);da+=1;return a};this.setTexture2D=function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTarget&&(a||(console.warn("THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead."), +a=!0),b=b.texture);ua.setTexture2D(b,c)}}();this.setTexture=function(){var a=!1;return function(b,c){a||(console.warn("THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead."),a=!0);ua.setTexture2D(b,c)}}();this.setTextureCube=function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTargetCube&&(a||(console.warn("THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead."),a=!0),b=b.texture);b&&b.isCubeTexture||Array.isArray(b.image)&& +6===b.image.length?ua.setTextureCube(b,c):ua.setTextureCubeDynamic(b,c)}}();this.getCurrentRenderTarget=function(){return V};this.setRenderTarget=function(a){(V=a)&&void 0===ea.get(a).__webglFramebuffer&&ua.setupRenderTarget(a);var b=a&&a.isWebGLRenderTargetCube,c;a?(c=ea.get(a),c=b?c.__webglFramebuffer[a.activeCubeFace]:c.__webglFramebuffer,X.copy(a.scissor),fb=a.scissorTest,$a.copy(a.viewport)):(c=null,X.copy(ha).multiplyScalar(Qa),fb=la,$a.copy(fa).multiplyScalar(Qa));T!==c&&(A.bindFramebuffer(A.FRAMEBUFFER, +c),T=c);Y.scissor(X);Y.setScissorTest(fb);Y.viewport($a);b&&(b=ea.get(a.texture),A.framebufferTexture2D(A.FRAMEBUFFER,A.COLOR_ATTACHMENT0,A.TEXTURE_CUBE_MAP_POSITIVE_X+a.activeCubeFace,b.__webglTexture,a.activeMipMapLevel))};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(!1===(a&&a.isWebGLRenderTarget))console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");else{var g=ea.get(a).__webglFramebuffer;if(g){var h=!1;g!==T&&(A.bindFramebuffer(A.FRAMEBUFFER, +g),h=!0);try{var k=a.texture,m=k.format,n=k.type;1023!==m&&u(m)!==A.getParameter(A.IMPLEMENTATION_COLOR_READ_FORMAT)?console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format."):1009===n||u(n)===A.getParameter(A.IMPLEMENTATION_COLOR_READ_TYPE)||1015===n&&(ka.get("OES_texture_float")||ka.get("WEBGL_color_buffer_float"))||1016===n&&ka.get("EXT_color_buffer_half_float")?A.checkFramebufferStatus(A.FRAMEBUFFER)===A.FRAMEBUFFER_COMPLETE?0<=b&& +b<=a.width-d&&0<=c&&c<=a.height-e&&A.readPixels(b,c,d,e,u(m),u(n),f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete."):console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.")}finally{h&&A.bindFramebuffer(A.FRAMEBUFFER,T)}}}}}function Ib(a,b){this.name="";this.color=new O(a);this.density=void 0!==b?b:2.5E-4}function Jb(a,b,c){this.name="";this.color= +new O(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3}function jb(){z.call(this);this.type="Scene";this.overrideMaterial=this.fog=this.background=null;this.autoUpdate=!0}function Ed(a,b,c,d,e){z.call(this);this.lensFlares=[];this.positionScreen=new q;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)}function kb(a){U.call(this);this.type="SpriteMaterial";this.color=new O(16777215);this.map=null;this.rotation=0;this.lights=this.fog=!1;this.setValues(a)}function qc(a){z.call(this); +this.type="Sprite";this.material=void 0!==a?a:new kb}function rc(){z.call(this);this.type="LOD";Object.defineProperties(this,{levels:{enumerable:!0,value:[]}})}function lb(a,b,c,d,e,f,g,h,k,m,w,n){da.call(this,null,f,g,h,k,m,d,e,w,n);this.image={data:a,width:b,height:c};this.magFilter=void 0!==k?k:1003;this.minFilter=void 0!==m?m:1003;this.flipY=this.generateMipmaps=!1;this.unpackAlignment=1}function bd(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new J;a=a||[];this.bones=a.slice(0); +this.useVertexTexture?(a=Math.sqrt(4*this.bones.length),a=T.nextPowerOfTwo(Math.ceil(a)),this.boneTextureHeight=this.boneTextureWidth=a=Math.max(a,4),this.boneMatrices=new Float32Array(this.boneTextureWidth*this.boneTextureHeight*4),this.boneTexture=new lb(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,1023,1015)):this.boneMatrices=new Float32Array(16*this.bones.length);if(void 0===b)this.calculateInverses();else if(this.bones.length===b.length)this.boneInverses=b.slice(0);else for(console.warn("THREE.Skeleton bonInverses is the wrong length."), +this.boneInverses=[],b=0,a=this.bones.length;b=a.HAVE_CURRENT_DATA&&(w.needsUpdate=!0)}da.call(this,a,b,c,d,e,f,g,h,k);this.generateMipmaps=!1;var w=this;m()}function Lb(a,b,c,d,e,f,g,h,k,m,w,n){da.call(this,null,f,g,h,k,m,d,e,w,n);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=this.flipY=!1}function fd(a,b,c,d,e,f,g,h,k){da.call(this,a,b,c,d,e,f,g,h,k);this.needsUpdate=!0}function tc(a,b,c,d,e,f,g, +h,k,m){m=void 0!==m?m:1026;if(1026!==m&&1027!==m)throw Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");da.call(this,null,d,e,f,g,h,m,c,k);this.image={width:a,height:b};this.type=void 0!==c?c:1012;this.magFilter=void 0!==g?g:1003;this.minFilter=void 0!==h?h:1003;this.generateMipmaps=this.flipY=!1}function Mb(a){function b(a,b){return a-b}G.call(this);var c=[0,0],d={},e=["a","b","c"];if(a&&a.isGeometry){var f=a.vertices,g=a.faces,h=0,k=new Uint32Array(6*g.length); +a=0;for(var m=g.length;an;n++){c[0]=w[e[n]];c[1]=w[e[(n+1)%3]];c.sort(b);var p=c.toString();void 0===d[p]&&(k[2*h]=c[0],k[2*h+1]=c[1],d[p]=!0,h++)}c=new Float32Array(6*h);a=0;for(m=h;an;n++)d=f[k[2*a+n]],h=6*a+3*n,c[h+0]=d.x,c[h+1]=d.y,c[h+2]=d.z;this.addAttribute("position",new C(c,3))}else if(a&&a.isBufferGeometry){if(null!==a.index){m=a.index.array;f=a.attributes.position;e=a.groups;h=0;0===e.length&&a.addGroup(0,m.length);k=new Uint32Array(2*m.length); +g=0;for(w=e.length;gn;n++)c[0]=m[a+n],c[1]=m[a+(n+1)%3],c.sort(b),p=c.toString(),void 0===d[p]&&(k[2*h]=c[0],k[2*h+1]=c[1],d[p]=!0,h++)}c=new Float32Array(6*h);a=0;for(m=h;an;n++)h=6*a+3*n,d=k[2*a+n],c[h+0]=f.getX(d),c[h+1]=f.getY(d),c[h+2]=f.getZ(d)}else for(f=a.attributes.position.array,h=f.length/3,k=h/3,c=new Float32Array(6*h),a=0,m=k;an;n++)h=18*a+6*n,k=9*a+3*n,c[h+0]=f[k],c[h+1]=f[k+1], +c[h+2]=f[k+2],d=9*a+(n+1)%3*3,c[h+3]=f[d],c[h+4]=f[d+1],c[h+5]=f[d+2];this.addAttribute("position",new C(c,3))}}function Nb(a,b,c){G.call(this);this.type="ParametricBufferGeometry";this.parameters={func:a,slices:b,stacks:c};var d=[],e=[],f,g,h,k,m,w=b+1;for(f=0;f<=c;f++)for(m=f/c,g=0;g<=b;g++)k=g/b,h=a(k,m),d.push(h.x,h.y,h.z),e.push(k,m);a=[];var n;for(f=0;fd&&1===a.x&&(k[b]=a.x-1);0===c.x&&0===c.z&&(k[b]=d/2/Math.PI+.5)}G.call(this);this.type="PolyhedronBufferGeometry";this.parameters= +{vertices:a,indices:b,radius:c,detail:d};c=c||1;var h=[],k=[];(function(a){for(var c=new q,d=new q,g=new q,h=0;he&&(.2>b&&(k[a+0]+=1),.2>c&&(k[a+2]+=1),.2>d&&(k[a+4]+=1))})();this.addAttribute("position",ha(h,3));this.addAttribute("normal",ha(h.slice(),3));this.addAttribute("uv",ha(k,2));this.normalizeNormals();this.boundingSphere=new Ca(new q, +c)}function Ob(a,b){ua.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronBufferGeometry";this.parameters={radius:a,detail:b}}function vc(a,b){Q.call(this);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Ob(a,b));this.mergeVertices()}function Pb(a,b){ua.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronBufferGeometry";this.parameters= +{radius:a,detail:b}}function wc(a,b){Q.call(this);this.type="OctahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Pb(a,b));this.mergeVertices()}function Qb(a,b){var c=(1+Math.sqrt(5))/2;ua.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronBufferGeometry";this.parameters= +{radius:a,detail:b}}function xc(a,b){Q.call(this);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Qb(a,b));this.mergeVertices()}function Rb(a,b){var c=(1+Math.sqrt(5))/2,d=1/c;ua.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2, +6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b);this.type="DodecahedronBufferGeometry";this.parameters={radius:a,detail:b}}function yc(a,b){Q.call(this);this.type="DodecahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Rb(a,b));this.mergeVertices()}function zc(a,b,c,d){Q.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d}; +this.fromBufferGeometry(new ua(a,b,c,d));this.mergeVertices()}function Sb(a,b,c,d,e){function f(e){var f=a.getPointAt(e/b),m=g.normals[e];e=g.binormals[e];for(n=0;n<=d;n++){var w=n/d*Math.PI*2,l=Math.sin(w),w=-Math.cos(w);k.x=w*m.x+l*e.x;k.y=w*m.y+l*e.y;k.z=w*m.z+l*e.z;k.normalize();r.push(k.x,k.y,k.z);h.x=f.x+c*k.x;h.y=f.y+c*k.y;h.z=f.z+c*k.z;p.push(h.x,h.y,h.z)}}G.call(this);this.type="TubeBufferGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c|| +1;d=d||8;e=e||!1;var g=a.computeFrenetFrames(b,e);this.tangents=g.tangents;this.normals=g.normals;this.binormals=g.binormals;var h=new q,k=new q,m=new B,w,n,p=[],r=[],l=[],t=[];for(w=0;w<=b;w++)for(n=0;n<=d;n++)m.x=w/b,m.y=n/d,l.push(m.x,m.y);(function(){for(n=1;n<=b;n++)for(w=1;w<=d;w++){var a=(d+1)*n+(w-1),c=(d+1)*n+w,e=(d+1)*(n-1)+w;t.push((d+1)*(n-1)+(w-1),a,e);t.push(a,c,e)}})();this.setIndex((65535p;p++){e[0]=n[g[p]];e[1]=n[g[(p+1)%3]];e.sort(c);var l=e.toString();void 0===f[l]?f[l]={vert1:e[0],vert2:e[1],face1:m,face2:void 0}:f[l].face2=m}e=[];for(l in f)if(g=f[l],void 0===g.face2||h[g.face1].normal.dot(h[g.face2].normal)<=d)m=k[g.vert1],e.push(m.x),e.push(m.y),e.push(m.z),m=k[g.vert2],e.push(m.x),e.push(m.y),e.push(m.z);this.addAttribute("position",new C(new Float32Array(e),3))}function Ua(a, +b,c,d,e,f,g,h){function k(c){var e,f,k,n=new B,p=new q,l=0,w=!0===c?a:b,I=!0===c?1:-1;f=u;for(e=1;e<=d;e++)x.setXYZ(u,0,y*I,0),t.setXYZ(u,0,I,0),n.x=.5,n.y=.5,D.setXY(u,n.x,n.y),u++;k=u;for(e=0;e<=d;e++){var z=e/d*h+g,C=Math.cos(z),z=Math.sin(z);p.x=w*z;p.y=y*I;p.z=w*C;x.setXYZ(u,p.x,p.y,p.z);t.setXYZ(u,0,I,0);n.x=.5*C+.5;n.y=.5*z*I+.5;D.setXY(u,n.x,n.y);u++}for(e=0;ethis.duration&&this.resetDuration();this.optimize()}function ud(a){this.manager=void 0!==a?a:Ga;this.textures={}}function Id(a){this.manager=void 0!==a?a:Ga}function wb(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}}function Jd(a){"boolean"=== +typeof a&&(console.warn("THREE.JSONLoader: showStatus parameter has been removed from constructor."),a=void 0);this.manager=void 0!==a?a:Ga;this.withCredentials=!1}function xe(a){this.manager=void 0!==a?a:Ga;this.texturePath=""}function ia(){}function Sa(a,b){this.v1=a;this.v2=b}function Oc(){this.curves=[];this.autoClose=!1}function Va(a,b,c,d,e,f,g,h){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g;this.aRotation=h||0}function xb(a){this.points= +void 0===a?[]:a}function yb(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d}function zb(a,b,c){this.v0=a;this.v1=b;this.v2=c}function Ab(){Pc.apply(this,arguments);this.holes=[]}function Pc(a){Oc.call(this);this.currentPoint=new B;a&&this.fromPoints(a)}function Kd(){this.subPaths=[];this.currentPath=null}function Ld(a){this.data=a}function ye(a){this.manager=void 0!==a?a:Ga}function Md(){void 0===Nd&&(Nd=new (window.AudioContext||window.webkitAudioContext));return Nd}function Od(a){this.manager= +void 0!==a?a:Ga}function ze(){this.type="StereoCamera";this.aspect=1;this.eyeSep=.064;this.cameraL=new Ea;this.cameraL.layers.enable(1);this.cameraL.matrixAutoUpdate=!1;this.cameraR=new Ea;this.cameraR.layers.enable(2);this.cameraR.matrixAutoUpdate=!1}function vd(a,b,c){z.call(this);this.type="CubeCamera";var d=new Ea(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new q(1,0,0));this.add(d);var e=new Ea(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new q(-1,0,0));this.add(e);var f=new Ea(90,1,a,b);f.up.set(0,0,1);f.lookAt(new q(0, +1,0));this.add(f);var g=new Ea(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new q(0,-1,0));this.add(g);var h=new Ea(90,1,a,b);h.up.set(0,-1,0);h.lookAt(new q(0,0,1));this.add(h);var k=new Ea(90,1,a,b);k.up.set(0,-1,0);k.lookAt(new q(0,0,-1));this.add(k);this.renderTarget=new Eb(c,c,{format:1022,magFilter:1006,minFilter:1006});this.updateCubeMap=function(a,b){null===this.parent&&this.updateMatrixWorld();var c=this.renderTarget,p=c.texture.generateMipmaps;c.texture.generateMipmaps=!1;c.activeCubeFace=0;a.render(b, +d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace=2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,g,c);c.activeCubeFace=4;a.render(b,h,c);c.texture.generateMipmaps=p;c.activeCubeFace=5;a.render(b,k,c);a.setRenderTarget(null)}}function Pd(){z.call(this);this.type="AudioListener";this.context=Md();this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.filter=null}function dc(a){z.call(this);this.type="Audio";this.context=a.context;this.source=this.context.createBufferSource(); +this.source.onended=this.onEnded.bind(this);this.gain=this.context.createGain();this.gain.connect(a.getInput());this.autoplay=!1;this.startTime=0;this.playbackRate=1;this.isPlaying=!1;this.hasPlaybackControl=!0;this.sourceType="empty";this.filters=[]}function Qd(a){dc.call(this,a);this.panner=this.context.createPanner();this.panner.connect(this.gain)}function Rd(a,b){this.analyser=a.context.createAnalyser();this.analyser.fftSize=void 0!==b?b:2048;this.data=new Uint8Array(this.analyser.frequencyBinCount); +a.getOutput().connect(this.analyser)}function wd(a,b,c){this.binding=a;this.valueSize=c;a=Float64Array;switch(b){case "quaternion":b=this._slerp;break;case "string":case "bool":a=Array;b=this._select;break;default:b=this._lerp}this.buffer=new a(4*c);this._mixBufferRegion=b;this.referenceCount=this.useCount=this.cumulativeWeight=0}function fa(a,b,c){this.path=b;this.parsedPath=c||fa.parseTrackName(b);this.node=fa.findNode(a,this.parsedPath.nodeName)||a;this.rootNode=a}function Sd(a){this.uuid=T.generateUUID(); +this._objects=Array.prototype.slice.call(arguments);this.nCachedObjects_=0;var b={};this._indicesByUUID=b;for(var c=0,d=arguments.length;c!==d;++c)b[arguments[c].uuid]=c;this._paths=[];this._parsedPaths=[];this._bindings=[];this._bindingsIndicesByPath={};var e=this;this.stats={objects:{get total(){return e._objects.length},get inUse(){return this.total-e.nCachedObjects_}},get bindingsPerObject(){return e._bindings.length}}}function Td(a,b,c){this._mixer=a;this._clip=b;this._localRoot=c||null;a=b.tracks; +b=a.length;c=Array(b);for(var d={endingStart:2400,endingEnd:2400},e=0;e!==b;++e){var f=a[e].createInterpolant(null);c[e]=f;f.settings=d}this._interpolantSettings=d;this._interpolants=c;this._propertyBindings=Array(b);this._weightInterpolant=this._timeScaleInterpolant=this._byClipCacheIndex=this._cacheIndex=null;this.loop=2201;this._loopCount=-1;this._startTime=null;this.time=0;this._effectiveWeight=this.weight=this._effectiveTimeScale=this.timeScale=1;this.repetitions=Infinity;this.paused=!1;this.enabled= +!0;this.clampWhenFinished=!1;this.zeroSlopeAtEnd=this.zeroSlopeAtStart=!0}function Ud(a){this._root=a;this._initMemoryManager();this.time=this._accuIndex=0;this.timeScale=1}function Ae(a,b){"string"===typeof a&&(console.warn("THREE.Uniform: Type parameter is no longer needed."),a=b);this.value=a}function Bb(){G.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0}function Vd(a,b,c,d){this.uuid=T.generateUUID();this.data=a;this.itemSize=b;this.offset=c;this.normalized=!0=== +d}function ec(a,b){this.uuid=T.generateUUID();this.array=a;this.stride=b;this.count=void 0!==a?a.length/b:0;this.dynamic=!1;this.updateRange={offset:0,count:-1};this.version=0}function fc(a,b,c){ec.call(this,a,b);this.meshPerAttribute=c||1}function gc(a,b,c){C.call(this,a,b);this.meshPerAttribute=c||1}function Wd(a,b,c,d){this.ray=new ab(a,b);this.near=c||0;this.far=d||Infinity;this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points."); +return this.Points}}})}function Be(a,b){return a.distance-b.distance}function Xd(a,b,c,d){if(!1!==a.visible&&(a.raycast(b,c),!0===d)){a=a.children;d=0;for(var e=a.length;dc;c++,d++){var e=c/32*Math.PI*2,f=d/32*Math.PI*2;b.push(Math.cos(e),Math.sin(e),1,Math.cos(f),Math.sin(f),1)}a.addAttribute("position",new ha(b,3));b=new oa({fog:!1});this.cone=new la(a,b);this.add(this.cone);this.update()}function ic(a){this.bones=this.getBoneList(a);for(var b=new Q, +c=0;cd;d++)c.faces[d].color=this.colors[4>d?0:1];d=new Ma({vertexColors:1,wireframe:!0});this.lightSphere=new ya(c,d);this.add(this.lightSphere);this.update()}function Sc(a,b,c,d){b=b||1;c=new O(void 0!==c?c:4473924);d=new O(void 0!== +d?d:8947848);for(var e=b/2,f=2*a/b,g=[],h=[],k=0,m=0,l=-a;k<=b;k++,l+=f){g.push(-a,0,l,a,0,l);g.push(l,0,-a,l,0,a);var n=k===e?c:d;n.toArray(h,m);m+=3;n.toArray(h,m);m+=3;n.toArray(h,m);m+=3;n.toArray(h,m);m+=3}a=new G;a.addAttribute("position",new ha(g,3));a.addAttribute("color",new ha(h,3));g=new oa({vertexColors:2});la.call(this,a,g)}function Tc(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=0;(c=this.object.geometry)&&c.isGeometry?b=c.faces.length:console.warn("THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead."); +c=new G;b=new ha(6*b,3);c.addAttribute("position",b);la.call(this,c,new oa({color:a,linewidth:d}));this.matrixAutoUpdate=!1;this.update()}function lc(a,b){z.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;void 0===b&&(b=1);var c=new G;c.addAttribute("position",new ha([-b,b,0,b,b,0,b,-b,0,-b,-b,0,-b,b,0],3));var d=new oa({fog:!1});this.add(new Ta(c,d));c=new G;c.addAttribute("position",new ha([0,0,0,0,0,1],3));this.add(new Ta(c,d));this.update()} +function Uc(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new q);d.colors.push(new O(b));void 0===f[a]&&(f[a]=[]);f[a].push(d.vertices.length-1)}var d=new Q,e=new oa({color:16777215,vertexColors:1}),f={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200);b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680); +b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);la.call(this,d,e);this.camera=a;this.camera.updateProjectionMatrix&&this.camera.updateProjectionMatrix();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=f;this.update()}function Vc(a,b){var c=void 0!==b?b:8947848;this.object=a;this.box= +new Ba;ya.call(this,new ob(1,1,1),new Ma({color:c,wireframe:!0}))}function Wc(a,b){void 0===b&&(b=16776960);var c=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7]),d=new Float32Array(24),e=new G;e.setIndex(new C(c,1));e.addAttribute("position",new C(d,3));la.call(this,e,new oa({color:b}));void 0!==a&&this.update(a)}function Cb(a,b,c,d,e,f){z.call(this);void 0===d&&(d=16776960);void 0===c&&(c=1);void 0===e&&(e=.2*c);void 0===f&&(f=.2*e);this.position.copy(b);this.line=new Ta(Ce,new oa({color:d})); +this.line.matrixAutoUpdate=!1;this.add(this.line);this.cone=new ya(De,new Ma({color:d}));this.cone.matrixAutoUpdate=!1;this.add(this.cone);this.setDirection(a);this.setLength(c,e,f)}function xd(a){a=a||1;var b=new Float32Array([0,0,0,a,0,0,0,0,0,0,a,0,0,0,0,0,0,a]),c=new Float32Array([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1]);a=new G;a.addAttribute("position",new C(b,3));a.addAttribute("color",new C(c,3));b=new oa({vertexColors:2});la.call(this,a,b)}function Ee(a){console.warn("THREE.ClosedSplineCurve3 has been deprecated. Please use THREE.CatmullRomCurve3."); +$d.call(this,a);this.type="catmullrom";this.closed=!0}function yd(a,b,c,d,e,f){Va.call(this,a,b,c,c,d,e,f)}void 0===Number.EPSILON&&(Number.EPSILON=Math.pow(2,-52));void 0===Math.sign&&(Math.sign=function(a){return 0>a?-1:0e;e++)8===e||13===e||18===e||23===e?b[e]="-":14===e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19===e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},lerp:function(a,b,c){return(1-c)*a+c*b},smoothstep:function(a, +b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){console.warn("THREE.Math.random16() has been deprecated. Use Math.random() instead.");return Math.random()},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(a){return a* +T.DEG2RAD},radToDeg:function(a){return a*T.RAD2DEG},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},nearestPowerOfTwo:function(a){return Math.pow(2,Math.round(Math.log(a)/Math.LN2))},nextPowerOfTwo:function(a){a--;a|=a>>1;a|=a>>2;a|=a>>4;a|=a>>8;a|=a>>16;a++;return a}};B.prototype={constructor:B,isVector2:!0,get width(){return this.x},set width(a){this.x=a},get height(){return this.y},set height(a){this.y=a},set:function(a,b){this.x=a;this.y=b;return this},setScalar:function(a){this.y=this.x= +a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){if(void 0!== +b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), +this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this},subScalar:function(a){this.x-=a;this.y-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){isFinite(a)?(this.x*=a,this.y*=a):this.y=this.x=0;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y, +a.y);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new B,b=new B);a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.multiplyScalar(Math.max(a,Math.min(b,c))/c)},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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},dot:function(a){return this.x*a.x+this.y*a.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(){var a=Math.atan2(this.y,this.x);0>a&&(a+=2*Math.PI);return a},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x;a=this.y-a.y;return b*b+a*a},distanceToManhattan:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)},setLength:function(a){return this.multiplyScalar(a/ +this.length())},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+ +1];return this},rotateAround:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=this.x-a.x,f=this.y-a.y;this.x=e*c-f*d+a.x;this.y=e*d+f*c+a.y;return this}};da.DEFAULT_IMAGE=void 0;da.DEFAULT_MAPPING=300;da.prototype={constructor:da,isTexture:!0,set needsUpdate(a){!0===a&&this.version++},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.image=a.image;this.mipmaps=a.mipmaps.slice(0);this.mapping=a.mapping;this.wrapS=a.wrapS;this.wrapT=a.wrapT;this.magFilter=a.magFilter;this.minFilter= +a.minFilter;this.anisotropy=a.anisotropy;this.format=a.format;this.type=a.type;this.offset.copy(a.offset);this.repeat.copy(a.repeat);this.generateMipmaps=a.generateMipmaps;this.premultiplyAlpha=a.premultiplyAlpha;this.flipY=a.flipY;this.unpackAlignment=a.unpackAlignment;this.encoding=a.encoding;return this},toJSON:function(a){if(void 0!==a.textures[this.uuid])return a.textures[this.uuid];var b={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(void 0!==this.image){var c=this.image;void 0===c.uuid&&(c.uuid=T.generateUUID());if(void 0===a.images[c.uuid]){var d=a.images,e=c.uuid,f=c.uuid,g;void 0!==c.toDataURL?g=c:(g=document.createElementNS("http://www.w3.org/1999/xhtml","canvas"),g.width=c.width,g.height=c.height,g.getContext("2d").drawImage(c, +0,0,c.width,c.height));g=2048a.x||1a.x?0:1;break;case 1002:a.x=1===Math.abs(Math.floor(a.x)%2)?Math.ceil(a.x)-a.x:a.x-Math.floor(a.x)}if(0> +a.y||1a.y?0:1;break;case 1002:a.y=1===Math.abs(Math.floor(a.y)%2)?Math.ceil(a.y)-a.y:a.y-Math.floor(a.y)}this.flipY&&(a.y=1-a.y)}}};Object.assign(da.prototype,sa.prototype);var ee=0;ga.prototype={constructor:ga,isVector4:!0,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setScalar:function(a){this.w=this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a; +return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x, +this.y,this.z,this.w)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;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(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;this.w-=a;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(a){isFinite(a)? +(this.x*=a,this.y*=a,this.z*=a,this.w*=a):this.w=this.z=this.y=this.x=0;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y= +0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d;a=a.elements;var e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],k=a[9];c=a[2];b=a[6];var m=a[10];if(.01>Math.abs(d-g)&&.01>Math.abs(f-c)&&.01>Math.abs(k-b)){if(.1>Math.abs(d+g)&&.1>Math.abs(f+c)&&.1>Math.abs(k+b)&&.1>Math.abs(e+h+m-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;m=(m+1)/2;d=(d+g)/4;f=(f+c)/4;k=(k+b)/4;e>h&&e>m?.01>e?(b=0,d=c=.707106781):(b=Math.sqrt(e),c=d/b,d=f/b): +h>m?.01>h?(b=.707106781,c=0,d=.707106781):(c=Math.sqrt(h),b=d/c,d=k/c):.01>m?(c=b=.707106781,d=0):(d=Math.sqrt(m),b=f/d,c=k/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-k)*(b-k)+(f-c)*(f-c)+(g-d)*(g-d));.001>Math.abs(a)&&(a=1);this.x=(b-k)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+m-1)/2);return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x); +this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w,this.w));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new ga,b=new ga);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z); +this.w=0>this.w?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(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.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(a){return this.multiplyScalar(a/this.length())},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w= +a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];this.w=a.array[b+3];return this}};Object.assign(Db.prototype,sa.prototype,{isWebGLRenderTarget:!0,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose();this.viewport.set(0,0,a,b);this.scissor.set(0, +0,a,b)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width=a.width;this.height=a.height;this.viewport.copy(a.viewport);this.texture=a.texture.clone();this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuffer;this.depthTexture=a.depthTexture;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});Eb.prototype=Object.create(Db.prototype);Eb.prototype.constructor=Eb;Eb.prototype.isWebGLRenderTargetCube=!0;ba.prototype={constructor:ba,get x(){return this._x}, +set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get w(){return this._w},set w(a){this._w=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this.onChangeCallback(); +return this},setFromEuler:function(a,b){if(!1===(a&&a.isEuler))throw Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var c=Math.cos(a._x/2),d=Math.cos(a._y/2),e=Math.cos(a._z/2),f=Math.sin(a._x/2),g=Math.sin(a._y/2),h=Math.sin(a._z/2),k=a.order;"XYZ"===k?(this._x=f*d*e+c*g*h,this._y=c*g*e-f*d*h,this._z=c*d*h+f*g*e,this._w=c*d*e-f*g*h):"YXZ"===k?(this._x=f*d*e+c*g*h,this._y=c*g*e-f*d*h,this._z=c*d*h-f*g*e,this._w=c*d*e+f*g*h):"ZXY"===k?(this._x= +f*d*e-c*g*h,this._y=c*g*e+f*d*h,this._z=c*d*h+f*g*e,this._w=c*d*e-f*g*h):"ZYX"===k?(this._x=f*d*e-c*g*h,this._y=c*g*e+f*d*h,this._z=c*d*h-f*g*e,this._w=c*d*e+f*g*h):"YZX"===k?(this._x=f*d*e+c*g*h,this._y=c*g*e+f*d*h,this._z=c*d*h-f*g*e,this._w=c*d*e-f*g*h):"XZY"===k&&(this._x=f*d*e-c*g*h,this._y=c*g*e-f*d*h,this._z=c*d*h+f*g*e,this._w=c*d*e+f*g*h);if(!1!==b)this.onChangeCallback();return this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c);this._x=a.x*d;this._y=a.y*d;this._z=a.z*d;this._w= +Math.cos(c);this.onChangeCallback();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0];a=b[4];var d=b[8],e=b[1],f=b[5],g=b[9],h=b[2],k=b[6],b=b[10],m=c+f+b;0f&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y=.25*c,this._z=(g+k)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+ +h)/c,this._y=(g+k)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a,b;return function(c,d){void 0===a&&(a=new q);b=c.dot(d)+1;1E-6>b?(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;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(a){return this._x* +a._x+this._y*a._y+this._z*a._z+this._w*a._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 a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback();return this},multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."), +this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},premultiply:function(a){return this.multiplyQuaternions(a,this)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f=a._w,g=b._x,h=b._y,k=b._z,m=b._w;this._x=c*m+f*g+d*k-e*h;this._y=d*m+f*h+e*g-c*k;this._z=e*m+f*k+c*h-d*g;this._w=f*m-c*g-d*h-e*k;this.onChangeCallback();return this},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z; +0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y=d,this._z=e,this;var h=Math.sqrt(1-g*g);if(.001>Math.abs(h))return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;var k=Math.atan2(h,g),g=Math.sin((1-b)*k)/h,h=Math.sin(b*k)/h;this._w=f*g+this._w*h;this._x=c*g+this._x*h;this._y=d*g+this._y*h;this._z=e*g+this._z*h;this.onChangeCallback();return this},equals:function(a){return a._x=== +this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){}};Object.assign(ba,{slerp:function(a,b,c,d){return c.copy(a).slerp(b,d)},slerpFlat:function(a, +b,c,d,e,f,g){var h=c[d+0],k=c[d+1],m=c[d+2];c=c[d+3];d=e[f+0];var l=e[f+1],n=e[f+2];e=e[f+3];if(c!==e||h!==d||k!==l||m!==n){f=1-g;var p=h*d+k*l+m*n+c*e,r=0<=p?1:-1,x=1-p*p;x>Number.EPSILON&&(x=Math.sqrt(x),p=Math.atan2(x,p*r),f=Math.sin(f*p)/x,g=Math.sin(g*p)/x);r*=g;h=h*f+d*r;k=k*f+l*r;m=m*f+n*r;c=c*f+e*r;f===1-g&&(g=1/Math.sqrt(h*h+k*k+m*m+c*c),h*=g,k*=g,m*=g,c*=g)}a[b]=h;a[b+1]=k;a[b+2]=m;a[b+3]=c}});q.prototype={constructor:q,isVector3:!0,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this}, +setScalar:function(a){this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x, +this.y,this.z)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;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(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+= +a.z*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;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(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."), +this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){isFinite(a)?(this.x*=a,this.y*=a,this.z*=a):this.z=this.y=this.x=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 a;return function(b){!1===(b&&b.isEuler)&&console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.");void 0===a&&(a=new ba);return this.applyQuaternion(a.setFromEuler(b))}}(), +applyAxisAngle:function(){var a;return function(b,c){void 0===a&&(a=new ba);return this.applyQuaternion(a.setFromAxisAngle(b,c))}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b= +this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,m=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-m*-f;this.y=k*a+b*-f+m*-e-h*-g;this.z=m*a+b*-g+h*-f-k*-e;return this},project:function(){var a;return function(b){void 0===a&&(a=new J); +a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyProjection(a)}}(),unproject:function(){var a;return function(b){void 0===a&&(a=new J);a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyProjection(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;return this.normalize()},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/= +a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));return this},clampScalar:function(){var a,b;return function(c, +d){void 0===a&&(a=new q,b=new q);a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.multiplyScalar(Math.max(a,Math.min(b,c))/c)},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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?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(a){return this.x*a.x+this.y*a.y+this.z*a.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(a){return this.multiplyScalar(a/this.length())},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},cross:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a, +b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;this.x=d*h-e*g;this.y=e*f-c*h;this.z=c*g-d*f;return this},projectOnVector:function(a){var b=a.dot(this)/a.lengthSq();return this.copy(a).multiplyScalar(b)},projectOnPlane:function(){var a;return function(b){void 0===a&&(a=new q);a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a;return function(b){void 0=== +a&&(a=new q);return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/Math.sqrt(this.lengthSq()*a.lengthSq());return Math.acos(T.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},distanceToManhattan:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)+Math.abs(this.z-a.z)},setFromSpherical:function(a){var b=Math.sin(a.phi)*a.radius; +this.x=b*Math.sin(a.theta);this.y=Math.cos(a.phi)*a.radius;this.z=b*Math.cos(a.theta);return this},setFromMatrixPosition:function(a){return this.setFromMatrixColumn(a,3)},setFromMatrixScale:function(a){var b=this.setFromMatrixColumn(a,0).length(),c=this.setFromMatrixColumn(a,1).length();a=this.setFromMatrixColumn(a,2).length();this.x=b;this.y=c;this.z=a;return this},setFromMatrixColumn:function(a,b){if("number"===typeof a){console.warn("THREE.Vector3: setFromMatrixColumn now expects ( matrix, index )."); +var c=a;a=b;b=c}return this.fromArray(a.elements,4*b)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];return this}};J.prototype={constructor:J,isMatrix4:!0, +set:function(a,b,c,d,e,f,g,h,k,m,l,n,p,r,x,t){var q=this.elements;q[0]=a;q[4]=b;q[8]=c;q[12]=d;q[1]=e;q[5]=f;q[9]=g;q[13]=h;q[2]=k;q[6]=m;q[10]=l;q[14]=n;q[3]=p;q[7]=r;q[11]=x;q[15]=t;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 J).fromArray(this.elements)},copy:function(a){this.elements.set(a.elements);return this},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a, +b,c){a.setFromMatrixColumn(this,0);b.setFromMatrixColumn(this,1);c.setFromMatrixColumn(this,2);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a;return function(b){void 0===a&&(a=new q);var c=this.elements,d=b.elements,e=1/a.setFromMatrixColumn(b,0).length(),f=1/a.setFromMatrixColumn(b,1).length();b=1/a.setFromMatrixColumn(b,2).length();c[0]=d[0]*e;c[1]=d[1]*e;c[2]=d[2]*e;c[4]=d[4]*f;c[5]=d[5]*f;c[6]=d[6]* +f;c[8]=d[8]*b;c[9]=d[9]*b;c[10]=d[10]*b;return this}}(),makeRotationFromEuler:function(a){!1===(a&&a.isEuler)&&console.error("THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c),c=Math.sin(c),g=Math.cos(d),d=Math.sin(d),h=Math.cos(e),e=Math.sin(e);if("XYZ"===a.order){a=f*h;var k=f*e,m=c*h,l=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=k+m*d;b[5]=a-l*d;b[9]=-c*g;b[2]=l-a*d;b[6]=m+k*d;b[10]=f*g}else"YXZ"=== +a.order?(a=g*h,k=g*e,m=d*h,l=d*e,b[0]=a+l*c,b[4]=m*c-k,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=k*c-m,b[6]=l+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*h,k=g*e,m=d*h,l=d*e,b[0]=a-l*c,b[4]=-f*e,b[8]=m+k*c,b[1]=k+m*c,b[5]=f*h,b[9]=l-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*h,k=f*e,m=c*h,l=c*e,b[0]=g*h,b[4]=m*d-k,b[8]=a*d+l,b[1]=g*e,b[5]=l*d+a,b[9]=k*d-m,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"===a.order?(a=f*g,k=f*d,m=c*g,l=c*d,b[0]=g*h,b[4]=l-a*e,b[8]=m*e+k,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=k* +e+m,b[10]=a-l*e):"XZY"===a.order&&(a=f*g,k=f*d,m=c*g,l=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=a*e+l,b[5]=f*h,b[9]=k*e-m,b[2]=m*e-k,b[6]=c*h,b[10]=l*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,g=c+c,h=d+d,k=e+e;a=c*g;var m=c*h,c=c*k,l=d*h,d=d*k,e=e*k,g=f*g,h=f*h,f=f*k;b[0]=1-(l+e);b[4]=m-f;b[8]=c+h;b[1]=m+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+l);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]= +0;b[14]=0;b[15]=1;return this},lookAt:function(){var a,b,c;return function(d,e,f){void 0===a&&(a=new q,b=new q,c=new q);var g=this.elements;c.subVectors(d,e).normalize();0===c.lengthSq()&&(c.z=1);a.crossVectors(f,c).normalize();0===a.lengthSq()&&(c.z+=1E-4,a.crossVectors(f,c).normalize());b.crossVectors(c,a);g[0]=a.x;g[4]=b.x;g[8]=c.x;g[1]=a.y;g[5]=b.y;g[9]=c.y;g[2]=a.z;g[6]=b.z;g[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."), +this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],g=c[4],h=c[8],k=c[12],m=c[1],l=c[5],n=c[9],p=c[13],r=c[2],x=c[6],t=c[10],q=c[14],u=c[3],v=c[7],I=c[11],c=c[15],y=d[0],E=d[4],H=d[8],F=d[12],M=d[1],B=d[5],K=d[9],z=d[13],C=d[2],G=d[6],J=d[10],N=d[14],P=d[3],R=d[7],S=d[11],d=d[15];e[0]=f*y+g*M+h*C+k*P;e[4]=f*E+g*B+h*G+k*R;e[8]=f*H+g*K+h*J+k*S;e[12]= +f*F+g*z+h*N+k*d;e[1]=m*y+l*M+n*C+p*P;e[5]=m*E+l*B+n*G+p*R;e[9]=m*H+l*K+n*J+p*S;e[13]=m*F+l*z+n*N+p*d;e[2]=r*y+x*M+t*C+q*P;e[6]=r*E+x*B+t*G+q*R;e[10]=r*H+x*K+t*J+q*S;e[14]=r*F+x*z+t*N+q*d;e[3]=u*y+v*M+I*C+c*P;e[7]=u*E+v*B+I*G+c*R;e[11]=u*H+v*K+I*J+c*S;e[15]=u*F+v*z+I*N+c*d;return this},multiplyToArray:function(a,b,c){var d=this.elements;this.multiplyMatrices(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12]; +c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},applyToVector3Array:function(){var a;return function(b,c,d){void 0===a&&(a=new q);void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;ethis.determinant()&&(g=-g);c.x=f[12];c.y=f[13];c.z=f[14];b.elements.set(this.elements);c=1/g;var f=1/h,m=1/k;b.elements[0]*=c;b.elements[1]*=c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=m;b.elements[9]*=m;b.elements[10]*=m;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makeFrustum:function(a,b,c,d,e,f){var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(d-c); +g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0;g[11]=-1;g[15]=0;return this},makePerspective:function(a,b,c,d){a=c*Math.tan(T.DEG2RAD*a*.5);var e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=1/(b-a),k=1/(c-d),m=1/(f-e);g[0]=2*h;g[4]=0;g[8]=0;g[12]=-((b+a)*h);g[1]=0;g[5]=2*k;g[9]=0;g[13]=-((c+d)*k);g[2]=0;g[6]=0;g[10]=-2*m;g[14]=-((f+e)*m);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},equals:function(a){var b= +this.elements;a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;16>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a}};Xa.prototype=Object.create(da.prototype); +Xa.prototype.constructor=Xa;Xa.prototype.isCubeTexture=!0;Object.defineProperty(Xa.prototype,"images",{get:function(){return this.image},set:function(a){this.image=a}});var ie=new da,je=new Xa,fe=[],he=[];ne.prototype.setValue=function(a,b){for(var c=this.seq,d=0,e=c.length;d!==e;++d){var f=c[d];f.setValue(a,b[f.id])}};var zd=/([\w\d_]+)(\])?(\[|\.)?/g;Ya.prototype.setValue=function(a,b,c){b=this.map[b];void 0!==b&&b.setValue(a,c,this.renderer)};Ya.prototype.set=function(a,b,c){var d=this.map[c]; +void 0!==d&&d.setValue(a,b[c],this.renderer)};Ya.prototype.setOptional=function(a,b,c){b=b[c];void 0!==b&&this.setValue(a,c,b)};Ya.upload=function(a,b,c,d){for(var e=0,f=b.length;e!==f;++e){var g=b[e],h=c[g.id];!1!==h.needsUpdate&&g.setValue(a,h.value,d)}};Ya.seqWithValue=function(a,b){for(var c=[],d=0,e=a.length;d!==e;++d){var f=a[d];f.id in b&&c.push(f)}return c};var La={merge:function(a){for(var b={},c=0;c< ALPHATEST ) discard;\n#endif\n", +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",aomap_pars_fragment:"#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif", +begin_vertex:"\nvec3 transformed = vec3( position );\n",beginnormal_vertex:"\nvec3 objectNormal = vec3( normal );\n",bsdfs:"bool testLightInRange( const in float lightDistance, const in float cutoffDistance ) {\n\treturn any( bvec2( cutoffDistance == 0.0, lightDistance < cutoffDistance ) );\n}\nfloat 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}\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", +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", +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", +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",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n", +color_fragment:"#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n",color_pars_vertex:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif",common:"#define PI 3.14159265359\n#define PI2 6.28318530718\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}\n", +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", +defaultnormal_vertex:"#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n", +emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n",encodings_fragment:" gl_FragColor = linearToOutputTexel( gl_FragColor );\n",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", +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", +envmap_pars_fragment:"#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntenstiy;\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", +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",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", +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",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", +lightmap_fragment:"#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",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_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", +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\tif ( testLightInRange( lightDistance, pointLight.distance ) ) {\n\t\t\tdirectLight.color = pointLight.color;\n\t\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.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_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 ( all( bvec2( angleCos > spotLight.coneCos, testLightInRange( lightDistance, spotLight.distance ) ) ) ) {\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_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\t#include \n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = flipNormal * 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 = flipNormal * 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\t#include \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 = flipNormal * 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 = flipNormal * 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( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * 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 = flipNormal * 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", +lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n",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};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial 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\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_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n", +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", +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}\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_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", +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 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", +logdepthbuf_fragment:"#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif",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",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",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", +map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n",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",map_particle_pars_fragment:"#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n", +metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.r;\n#endif\n",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",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", +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",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", +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",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", +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", +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", +premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n",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",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.r;\n#endif\n", +roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",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\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", +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#endif\n", +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#endif\n", +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#endif\n\treturn shadow;\n}\n", +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",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", +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",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", +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",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n",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", +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",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", +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",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif", +uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif",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",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", +cube_vert:"varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n",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", +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", +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",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", +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",equirect_vert:"varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n", +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", +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",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 \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;\n\treflectedLight.directDiffuse = vec3( 0.0 );\n\treflectedLight.directSpecular = vec3( 0.0 );\n\treflectedLight.indirectDiffuse = diffuseColor.rgb;\n\treflectedLight.indirectSpecular = vec3( 0.0 );\n\t#include \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", +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", +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", +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", +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 \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", +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 \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}\n", +meshphysical_frag:"#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nuniform float envMapIntensity;\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 \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\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n", +meshphysical_vert:"#define PHYSICAL\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 \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n}\n", +normal_frag:"uniform float opacity;\nvarying vec3 vNormal;\n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( vNormal ), opacity );\n\t#include \n}\n",normal_vert:"varying vec3 vNormal;\n#include \n#include \n#include \n#include \nvoid main() {\n\tvNormal = normalize( normalMatrix * normal );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", +points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \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", +points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}\n", +shadow_frag:"uniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\n}\n",shadow_vert:"#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"};O.prototype={constructor:O, +isColor:!0,r:1,g:1,b:1,set:function(a){a&&a.isColor?this.copy(a):"number"===typeof a?this.setHex(a):"string"===typeof a&&this.setStyle(a);return this},setScalar:function(a){this.b=this.g=this.r=a;return this},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(){function a(a,c,d){0>d&&(d+=1);1<1/6?a+6*(c-a)*d:.5>d?c:d<2/3?a+6*(c-a)*(2/3-d):a}return function(b, +c,d){b=T.euclideanModulo(b,1);c=T.clamp(c,0,1);d=T.clamp(d,0,1);0===c?this.r=this.g=this.b=d:(c=.5>=d?d*(1+c):d+c-d*c,d=2*d-c,this.r=a(d,c,b+1/3),this.g=a(d,c,b),this.b=a(d,c,b-1/3));return this}}(),setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&&console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r= +Math.min(255,parseInt(c[1],10))/255,this.g=Math.min(255,parseInt(c[2],10))/255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100,parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){var d=parseFloat(c[1])/ +360,e=parseInt(c[2],10)/100,f=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d,e,f)}}}else if(c=/^\#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}a&&0<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){a=a||{h:0,s:0,l:0};var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var k=e-f,f=.5>=h?k/(e+f): +k/(2-e-f);switch(e){case b:g=(c-d)/k+(cthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&& +this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a,b){return(b||new B).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){return(b||new B).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new B;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min); +this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}};U.prototype={constructor:U,isMaterial:!0,get needsUpdate(){return this._needsUpdate},set needsUpdate(a){!0===a&&this.update();this._needsUpdate=a},setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0===c)console.warn("THREE.Material: '"+ +b+"' parameter is undefined.");else{var d=this[b];void 0===d?console.warn("THREE."+this.type+": '"+b+"' is not a property of this material."):d&&d.isColor?d.set(c):d&&d.isVector3&&c&&c.isVector3?d.copy(c):this[b]="overdraw"===b?Number(c):c}}},toJSON:function(a){function b(a){var b=[],c;for(c in a){var d=a[c];delete d.metadata;b.push(d)}return b}var c=void 0===a;c&&(a={textures:{},images:{}});var d={metadata:{version:4.4,type:"Material",generator:"Material.toJSON"}};d.uuid=this.uuid;d.type=this.type; +""!==this.name&&(d.name=this.name);this.color&&this.color.isColor&&(d.color=this.color.getHex());void 0!==this.roughness&&(d.roughness=this.roughness);void 0!==this.metalness&&(d.metalness=this.metalness);this.emissive&&this.emissive.isColor&&(d.emissive=this.emissive.getHex());this.specular&&this.specular.isColor&&(d.specular=this.specular.getHex());void 0!==this.shininess&&(d.shininess=this.shininess);this.map&&this.map.isTexture&&(d.map=this.map.toJSON(a).uuid);this.alphaMap&&this.alphaMap.isTexture&& +(d.alphaMap=this.alphaMap.toJSON(a).uuid);this.lightMap&&this.lightMap.isTexture&&(d.lightMap=this.lightMap.toJSON(a).uuid);this.bumpMap&&this.bumpMap.isTexture&&(d.bumpMap=this.bumpMap.toJSON(a).uuid,d.bumpScale=this.bumpScale);this.normalMap&&this.normalMap.isTexture&&(d.normalMap=this.normalMap.toJSON(a).uuid,d.normalScale=this.normalScale.toArray());this.displacementMap&&this.displacementMap.isTexture&&(d.displacementMap=this.displacementMap.toJSON(a).uuid,d.displacementScale=this.displacementScale, +d.displacementBias=this.displacementBias);this.roughnessMap&&this.roughnessMap.isTexture&&(d.roughnessMap=this.roughnessMap.toJSON(a).uuid);this.metalnessMap&&this.metalnessMap.isTexture&&(d.metalnessMap=this.metalnessMap.toJSON(a).uuid);this.emissiveMap&&this.emissiveMap.isTexture&&(d.emissiveMap=this.emissiveMap.toJSON(a).uuid);this.specularMap&&this.specularMap.isTexture&&(d.specularMap=this.specularMap.toJSON(a).uuid);this.envMap&&this.envMap.isTexture&&(d.envMap=this.envMap.toJSON(a).uuid,d.reflectivity= +this.reflectivity);void 0!==this.size&&(d.size=this.size);void 0!==this.sizeAttenuation&&(d.sizeAttenuation=this.sizeAttenuation);1!==this.blending&&(d.blending=this.blending);2!==this.shading&&(d.shading=this.shading);0!==this.side&&(d.side=this.side);0!==this.vertexColors&&(d.vertexColors=this.vertexColors);1>this.opacity&&(d.opacity=this.opacity);!0===this.transparent&&(d.transparent=this.transparent);d.depthFunc=this.depthFunc;d.depthTest=this.depthTest;d.depthWrite=this.depthWrite;0e&&(e=m);l>f&&(f=l);n>g&&(g=n)}this.min.set(b,c,d);this.max.set(e,f,g)},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y|| +a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a,b){return(b||new q).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},intersectsSphere:function(){var a;return function(b){void 0===a&&(a=new q);this.clampPoint(b.center,a);return a.distanceToSquared(b.center)<=b.radius*b.radius}}(),intersectsPlane:function(a){var b,c;0<=a.constant&&c>=a.constant},clampPoint:function(a,b){return(b||new q).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new q;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a=new q;return function(b){b=b||new Ca;this.getCenter(b.center);b.radius=.5*this.getSize(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max); +this.isEmpty()&&this.makeEmpty();return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new q,new q,new q,new q,new q,new q,new q,new q];return function(b){if(this.isEmpty())return this;a[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x, +this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}};Ca.prototype={constructor:Ca,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a= +new Ba;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).getCenter(d);for(var e=0,f=0,g=b.length;f=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)- +this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},intersectsBox:function(a){return a.intersectsSphere(this)},intersectsPlane:function(a){return Math.abs(this.center.dot(a.normal)-a.constant)<=this.radius},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new q;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a= +a||new Ba;a.set(this.center,this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius}};Ia.prototype={constructor:Ia,isMatrix3:!0,set:function(a,b,c,d,e,f,g,h,k){var m=this.elements;m[0]=a;m[1]=d;m[2]=g;m[3]=b;m[4]=e;m[5]=h;m[6]=c;m[7]=f;m[8]=k;return this},identity:function(){this.set(1, +0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},setFromMatrix4:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[1],a[5],a[9],a[2],a[6],a[10]);return this},applyToVector3Array:function(){var a;return function(b,c,d){void 0===a&&(a=new q);void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;ec;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a}};va.prototype={constructor:va,set:function(a,b){this.normal.copy(a); +this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new q,b=new q;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,c);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.normal.copy(a.normal); this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a,b){var c=this.distanceToPoint(a);return(b|| -new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a,b){var c=this.distanceToPoint(a),d=this.distanceToPoint(b);return 0>c&&0d&&0d||1c?c:a},clampBottom:function(a,b){return aa?-1:0this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1: -f+2;k=this.points[c[0]];l=this.points[c[1]];m=this.points[c[2]];n=this.points[c[3]];i=g*g;h=g*i;d.x=b(k.x,l.x,m.x,n.x,g,i,h);d.y=b(k.y,l.y,m.y,n.y,g,i,h);d.z=b(k.z,l.z,m.z,n.z,g,i,h);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<=a.x&&0<=a.y&&1>=a.x+a.y}; -THREE.Triangle.prototype={constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){THREE.Triangle.__v0.subVectors(this.c,this.b);THREE.Triangle.__v1.subVectors(this.a,this.b);return 0.5*THREE.Triangle.__v0.cross(THREE.Triangle.__v1).length()},midpoint:function(a){return(a|| -new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}, -clone:function(){return(new THREE.Triangle).copy(this)}};THREE.Triangle.__v0=new THREE.Vector3;THREE.Triangle.__v1=new THREE.Vector3;THREE.Triangle.__v2=new THREE.Vector3;THREE.Triangle.__v3=new THREE.Vector3;THREE.Vertex=function(a){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.");return a};THREE.UV=function(a,b){console.warn("THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.");return new THREE.Vector2(a,b)};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1};THREE.Clock.prototype.start=function(){this.oldTime=this.startTime=Date.now();this.running=!0};THREE.Clock.prototype.stop=function(){this.getElapsedTime();this.running=!1};THREE.Clock.prototype.getElapsedTime=function(){this.getDelta();return this.elapsedTime}; -THREE.Clock.prototype.getDelta=function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=Date.now(),a=0.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a};THREE.EventDispatcher=function(){var a={};this.addEventListener=function(b,c){void 0===a[b]&&(a[b]=[]);-1===a[b].indexOf(c)&&a[b].push(c)};this.removeEventListener=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)};this.dispatchEvent=function(b){var c=a[b.type];if(void 0!==c){b.target=this;for(var d=0,e=c.length;dg.scale.x)return h;h.push({distance:i,point:g.position,face:null,object:g})}else if(g instanceof a.Mesh){b.set(g.matrixWorld.getPosition(), -g.geometry.boundingSphere.radius*g.matrixWorld.getMaxScaleOnAxis());if(!i.ray.isIntersectionSphere(b))return h;var n=g.geometry,r=n.vertices,p=g.material instanceof a.MeshFaceMaterial,q=!0===p?g.material.materials:null,s=g.material.side,t,x,z,v=i.precision;g.matrixRotationWorld.extractRotation(g.matrixWorld);f.getInverse(g.matrixWorld);c.copy(i.ray).transform(f);for(var I=0,H=n.faces.length;Iy)){s=s.side;if(s!==a.DoubleSide&&(t=c.direction.dot(d.normal),!(s===a.FrontSide?0>t:0i.far)){e=c.at(y,e);if(D instanceof a.Face3){if(s=r[D.a],t=r[D.b],x=r[D.c],!a.Triangle.containsPoint(e,s,t,x))continue}else if(D instanceof a.Face4){if(s=r[D.a],t=r[D.b],x=r[D.c],z=r[D.d],!a.Triangle.containsPoint(e,s,t,z)&&!a.Triangle.containsPoint(e,t,x,z))continue}else throw Error("face type not supported");h.push({distance:y, -point:i.ray.at(y),face:D,faceIndex:I,object:g})}}}}}},h=function(a,b,c){for(var a=a.getDescendants(),d=0,e=a.length;de&&0>f||0>g&&0>i)return!1;0>e?c=Math.max(c,e/(e-f)):0>f&&(d=Math.min(d,e/(e-f)));0>g?c=Math.max(c,g/(g-i)):0>i&&(d=Math.min(d,g/(g-i)));if(d< -c)return!1;a.lerp(b,c);b.lerp(a,1-d);return!0}var e,f,g=[],i=0,h,k,l=[],m=0,n,r,p=[],q=0,s,t=[],x=0,z,v,I=[],H=0,D,y,F=[],E=0,G={objects:[],sprites:[],lights:[],elements:[]},W=new THREE.Vector3,A=new THREE.Vector4,X=new THREE.Box3(new THREE.Vector3(-1,-1,-1),new THREE.Vector3(1,1,1)),B=new THREE.Box3,K=Array(3),L=Array(4),U=new THREE.Matrix4,aa=new THREE.Matrix4,ba,xa=new THREE.Matrix4,J=new THREE.Matrix3,ha=new THREE.Matrix3,ua=new THREE.Vector3,Oa=new THREE.Frustum,M=new THREE.Vector4,fa=new THREE.Vector4; -this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld);aa.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);return a.applyProjection(aa)};this.unprojectVector=function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);aa.multiplyMatrices(b.matrixWorld,b.projectionMatrixInverse);return a.applyProjection(aa)};this.pickingRay=function(a,b){a.z=-1;var c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.sub(a).normalize();return new THREE.Raycaster(a, -c)};this.projectScene=function(g,i,m,Ja){var ma=!1,wa,Ta,Ra,ia,ra,ga,Z,pa,gb,hb,Ea,yb,Cb;y=v=s=r=0;G.elements.length=0;g.updateMatrixWorld();void 0===i.parent&&i.updateMatrixWorld();U.copy(i.matrixWorldInverse.getInverse(i.matrixWorld));aa.multiplyMatrices(i.projectionMatrix,U);ha.getInverse(U);ha.transpose();Oa.setFromMatrix(aa);f=0;G.objects.length=0;G.sprites.length=0;G.lights.length=0;var Lb=function(b){for(var c=0,d=b.children.length;ch.positionScreen.x||1h.positionScreen.y||1h.positionScreen.z||1(Z.positionScreen.x-ia.positionScreen.x)*(ra.positionScreen.y-ia.positionScreen.y)-(Z.positionScreen.y-ia.positionScreen.y)*(ra.positionScreen.x-ia.positionScreen.x),ga===THREE.DoubleSide||ma===(ga===THREE.FrontSide))r===q?(Ea=new THREE.RenderableFace3,p.push(Ea),q++,r++,n=Ea):n=p[r++],n.v1.copy(ia),n.v2.copy(ra),n.v3.copy(Z); -else continue;else continue;else if(Ta instanceof THREE.Face4)if(ia=l[Ta.a],ra=l[Ta.b],Z=l[Ta.c],Ea=l[Ta.d],L[0]=ia.positionScreen,L[1]=ra.positionScreen,L[2]=Z.positionScreen,L[3]=Ea.positionScreen,!0===ia.visible||!0===ra.visible||!0===Z.visible||!0===Ea.visible||X.isIntersectionBox(B.setFromPoints(L)))if(ma=0>(Ea.positionScreen.x-ia.positionScreen.x)*(ra.positionScreen.y-ia.positionScreen.y)-(Ea.positionScreen.y-ia.positionScreen.y)*(ra.positionScreen.x-ia.positionScreen.x)||0>(ra.positionScreen.x- -Z.positionScreen.x)*(Ea.positionScreen.y-Z.positionScreen.y)-(ra.positionScreen.y-Z.positionScreen.y)*(Ea.positionScreen.x-Z.positionScreen.x),ga===THREE.DoubleSide||ma===(ga===THREE.FrontSide)){if(s===x){var na=new THREE.RenderableFace4;t.push(na);x++;s++;n=na}else n=t[s++];n.v1.copy(ia);n.v2.copy(ra);n.v3.copy(Z);n.v4.copy(Ea)}else continue;else continue;n.normalModel.copy(Ta.normal);!1===ma&&(ga===THREE.BackSide||ga===THREE.DoubleSide)&&n.normalModel.negate();n.normalModel.applyMatrix3(J).normalize(); -n.normalModelView.copy(n.normalModel).applyMatrix3(ha);n.centroidModel.copy(Ta.centroid).applyMatrix4(ba);Z=Ta.vertexNormals;ia=0;for(ra=Z.length;iaA.z&&(y===E?(ma=new THREE.RenderableParticle,F.push(ma),E++,y++,D=ma):D=F[y++],D.object=pa,D.x=A.x/A.w,D.y= -A.y/A.w,D.z=A.z,D.rotation=pa.rotation.z,D.scale.x=pa.scale.x*Math.abs(D.x-(A.x+i.projectionMatrix.elements[0])/(A.w+i.projectionMatrix.elements[12])),D.scale.y=pa.scale.y*Math.abs(D.y-(A.y+i.projectionMatrix.elements[5])/(A.w+i.projectionMatrix.elements[13])),D.material=pa.material,G.elements.push(D)));!0===Ja&&G.elements.sort(c);return G}};THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=void 0!==f?f:0;this.centroid=new THREE.Vector3}; -THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;be?-1:1,f.vertexTangents[d]=new THREE.Vector4(A.x,A.y,A.z,e)}this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;ch;h++)if(i[h]==i[(h+1)%3]){e.push(f);break}}else if(a instanceof THREE.Face4){a.a=c[a.a];a.b=c[a.b];a.c=c[a.c];a.d=c[a.d];i=[a.a,a.b,a.c,a.d];d=-1;for(h=0;4>h;h++)i[h]==i[(h+1)%4]&&(0<=d&&e.push(f),d=h);if(0<=d){i.splice(d,1);var l=new THREE.Face3(i[0],i[1],i[2],a.normal,a.color,a.materialIndex);i=0;for(h=this.faceVertexUvs.length;i<=f;f--){this.faces.splice(f,1);i=0;for(h=this.faceVertexUvs.length;ib.max.x&&(b.max.x=c),db.max.y&&(b.max.y=d),eb.max.z&&(b.max.z=e)}if(void 0===a||0===a.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere= -new THREE.Sphere);var a=this.attributes.position.array;if(a){for(var b,c=0,d,e,f=0,g=a.length;fc&&(c=b);this.boundingSphere.radius=Math.sqrt(c)}},computeVertexNormals:function(){if(this.attributes.position){var a,b,c,d;a=this.attributes.position.array.length;if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(a),numItems:a};else{a=0;for(b=this.attributes.normal.array.length;aua?-1:1;i[4*a]=U.x;i[4*a+1]=U.y;i[4*a+2]=U.z;i[4*a+3]=J}if(void 0===this.attributes.index||void 0===this.attributes.position|| -void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var b=this.attributes.index.array,c=this.attributes.position.array,d=this.attributes.normal.array,e=this.attributes.uv.array,f=c.length/3;if(void 0===this.attributes.tangent){var g=4*f;this.attributes.tangent={itemSize:4,array:new Float32Array(g),numItems:g}}for(var i=this.attributes.tangent.array,h=[],k=[],g=0;ga.length?".":a.join("/"))+"/"},initMaterials:function(a,b){for(var c=[],d=0;d<<16)+(255*a[1]<<8)+255*a[2]}var g=this,i="MeshLambertMaterial",h={color:15658734,opacity:1, -map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var k=a.shading.toLowerCase();"phong"===k?i="MeshPhongMaterial":"basic"===k&&(i="MeshBasicMaterial")}void 0!==a.blending&&void 0!==THREE[a.blending]&&(h.blending=THREE[a.blending]);if(void 0!==a.transparent||1>a.opacity)h.transparent=a.transparent;void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide); -void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"===a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=f(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=f(a.colorSpecular));a.colorAmbient&&(h.ambient=f(a.colorAmbient));a.transparency&&(h.opacity=a.transparency);a.specularCoef&&(h.shininess=a.specularCoef);a.mapDiffuse&& -b&&e(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&e(h,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&e(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&e(h,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&e(h,"specularMap",a.mapSpecular,a.mapSpecularRepeat, -a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormal?(i=THREE.ShaderLib.normalmap,k=THREE.UniformsUtils.clone(i.uniforms),k.tNormal.value=h.normalMap,a.mapNormalFactor&&k.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),h.map&&(k.tDiffuse.value=h.map,k.enableDiffuse.value=!0),h.specularMap&&(k.tSpecular.value=h.specularMap,k.enableSpecular.value=!0),h.lightMap&&(k.tAO.value=h.lightMap,k.enableAO.value=!0),k.uDiffuseColor.value.setHex(h.color), -k.uSpecularColor.value.setHex(h.specular),k.uAmbientColor.value.setHex(h.ambient),k.uShininess.value=h.shininess,void 0!==h.opacity&&(k.uOpacity.value=h.opacity),i=new THREE.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:k,lights:!0,fog:!0}),h.transparent&&(i.transparent=!0)):i=new THREE[i](h);void 0!==a.DbgName&&(i.name=a.DbgName);return i}};THREE.ImageLoader=function(){THREE.EventDispatcher.call(this);this.crossOrigin=null};THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b){var c=this;void 0===b&&(b=new Image);b.addEventListener("load",function(){c.dispatchEvent({type:"load",content:b})},!1);b.addEventListener("error",function(){c.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},!1);c.crossOrigin&&(b.crossOrigin=c.crossOrigin);b.src=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)}; -THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,g=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var i=JSON.parse(f.responseText);a.createModel(i,c,d)}else console.warn("THREE.JSONLoader: ["+b+"] seems to be unreachable or file there is empty");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load ["+b+"] ["+f.status+"]");else f.readyState===f.LOADING?e&&(0===g&&(g=f.getResponseHeader("Content-Length")), -e({total:g,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&(g=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)}; -THREE.JSONLoader.prototype.createModel=function(a,b,c){var d=new THREE.Geometry,e=void 0!==a.scale?1/a.scale:1,f,g,i,h,k,l,m,n,r,p,q,s,t,x,z,v=a.faces;p=a.vertices;var I=a.normals,H=a.colors,D=0;for(f=0;fB.parameters.opacity&& -(B.parameters.transparent=!0);B.parameters.normalMap?(G=THREE.ShaderLib.normalmap,A=THREE.UniformsUtils.clone(G.uniforms),s=B.parameters.color,X=B.parameters.specular,q=B.parameters.ambient,W=B.parameters.shininess,A.tNormal.value=y.textures[B.parameters.normalMap],B.parameters.normalScale&&A.uNormalScale.value.set(B.parameters.normalScale[0],B.parameters.normalScale[1]),B.parameters.map&&(A.tDiffuse.value=B.parameters.map,A.enableDiffuse.value=!0),B.parameters.envMap&&(A.tCube.value=B.parameters.envMap, -A.enableReflection.value=!0,A.uReflectivity.value=B.parameters.reflectivity),B.parameters.lightMap&&(A.tAO.value=B.parameters.lightMap,A.enableAO.value=!0),B.parameters.specularMap&&(A.tSpecular.value=y.textures[B.parameters.specularMap],A.enableSpecular.value=!0),B.parameters.displacementMap&&(A.tDisplacement.value=y.textures[B.parameters.displacementMap],A.enableDisplacement.value=!0,A.uDisplacementBias.value=B.parameters.displacementBias,A.uDisplacementScale.value=B.parameters.displacementScale), -A.uDiffuseColor.value.setHex(s),A.uSpecularColor.value.setHex(X),A.uAmbientColor.value.setHex(q),A.uShininess.value=W,B.parameters.opacity&&(A.uOpacity.value=B.parameters.opacity),r=new THREE.ShaderMaterial({fragmentShader:G.fragmentShader,vertexShader:G.vertexShader,uniforms:A,lights:!0,fog:!0})):r=new THREE[B.type](B.parameters);y.materials[K]=r}for(K in E.materials)if(B=E.materials[K],B.parameters.materials){L=[];for(s=0;si.end&&(i.end=e);b||(b=g)}}a.firstAnimation=b}; -THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1E3*((c.end-c.start)/b),this.time=0):console.warn("animation["+a+"] undefined")}; -THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& -(this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; -THREE.MorphAnimMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.MorphAnimMesh(this.geometry,this.material));a.duration=this.duration;a.mirroredLoop=this.mirroredLoop;a.time=this.time;a.lastKeyframe=this.lastKeyframe;a.currentKeyframe=this.currentKeyframe;a.direction=this.direction;a.directionBackwards=this.directionBackwards;THREE.Mesh.prototype.clone.call(this,a);return a};THREE.Ribbon=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=b};THREE.Ribbon.prototype=Object.create(THREE.Object3D.prototype);THREE.Ribbon.prototype.clone=function(a){void 0===a&&(a=new THREE.Ribbon(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.LOD=function(){THREE.Object3D.call(this);this.LODs=[]};THREE.LOD.prototype=Object.create(THREE.Object3D.prototype);THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);for(var b=Math.abs(b),c=0;c=this.LODs[b].visibleAtDistance)this.LODs[b-1].object3D.visible=!1,this.LODs[b].object3D.visible=!0;else break;for(;bt&&q.clearRect(na.min.x|0,na.min.y|0,na.max.x-na.min.x|0,na.max.y-na.min.y|0),0=j||(j*=f.intensity,c.add(Ta.multiplyScalar(j)))}else f instanceof THREE.PointLight&&(g=f.matrixWorld.getPosition(),j=b.dot(ib.subVectors(g,a).normalize()), -0>=j||(j*=0==f.distance?1:1-Math.min(a.distanceTo(g)/f.distance,1),0!=j&&(j*=f.intensity,c.add(Ta.multiplyScalar(j)))))}}function m(a,d,e,g,j,i,h,Y){f.info.render.vertices+=3;f.info.render.faces++;b(Y.opacity);c(Y.blending);B=a.positionScreen.x;K=a.positionScreen.y;L=d.positionScreen.x;U=d.positionScreen.y;aa=e.positionScreen.x;ba=e.positionScreen.y;s(B,K,L,U,aa,ba);(Y instanceof THREE.MeshLambertMaterial||Y instanceof THREE.MeshPhongMaterial)&&null===Y.map&&null===Y.map?(ma.copy(Y.color),wa.copy(Y.emissive), -Y.vertexColors===THREE.FaceColors&&ma.multiply(h.color),!0===Db?!1===Y.wireframe&&Y.shading==THREE.SmoothShading&&3==h.vertexNormalsLength?(Da.copy(nb),Aa.copy(nb),Ia.copy(nb),n(h.v1.positionWorld,h.vertexNormalsModel[0],Da),n(h.v2.positionWorld,h.vertexNormalsModel[1],Aa),n(h.v3.positionWorld,h.vertexNormalsModel[2],Ia),Da.multiply(ma).add(wa),Aa.multiply(ma).add(wa),Ia.multiply(ma).add(wa),Ja.addColors(Aa,Ia).multiplyScalar(0.5),Z=jb(Da,Aa,Ia,Ja),I(B,K,L,U,aa,ba,0,0,1,0,0,1,Z)):(fa.copy(nb),n(h.centroidModel, -h.normalModel,fa),fa.multiply(ma).add(wa),!0===Y.wireframe?v(fa,Y.wireframeLinewidth,Y.wireframeLinecap,Y.wireframeLinejoin):x(fa)):!0===Y.wireframe?v(Y.color,Y.wireframeLinewidth,Y.wireframeLinecap,Y.wireframeLinejoin):x(Y.color)):Y instanceof THREE.MeshBasicMaterial||Y instanceof THREE.MeshLambertMaterial||Y instanceof THREE.MeshPhongMaterial?null!==Y.map?Y.map.mapping instanceof THREE.UVMapping&&(pa=h.uvs[0],z(B,K,L,U,aa,ba,pa[g].x,pa[g].y,pa[j].x,pa[j].y,pa[i].x,pa[i].y,Y.map)):null!==Y.envMap? -Y.envMap.mapping instanceof THREE.SphericalReflectionMapping&&(ib.copy(h.vertexNormalsModelView[g]),gb=0.5*ib.x+0.5,hb=0.5*ib.y+0.5,ib.copy(h.vertexNormalsModelView[j]),Ea=0.5*ib.x+0.5,yb=0.5*ib.y+0.5,ib.copy(h.vertexNormalsModelView[i]),Cb=0.5*ib.x+0.5,Lb=0.5*ib.y+0.5,z(B,K,L,U,aa,ba,gb,hb,Ea,yb,Cb,Lb,Y.envMap)):(fa.copy(Y.color),Y.vertexColors===THREE.FaceColors&&fa.multiply(h.color),!0===Y.wireframe?v(fa,Y.wireframeLinewidth,Y.wireframeLinecap,Y.wireframeLinejoin):x(fa)):Y instanceof THREE.MeshDepthMaterial? -(ra=l.near,ga=l.far,j=1-cb(a.positionScreen.z*a.positionScreen.w,ra,ga),Da.setRGB(j,j,j),j=1-cb(d.positionScreen.z*d.positionScreen.w,ra,ga),Aa.setRGB(j,j,j),j=1-cb(e.positionScreen.z*e.positionScreen.w,ra,ga),Ia.setRGB(j,j,j),Ja.addColors(Aa,Ia).multiplyScalar(0.5),Z=jb(Da,Aa,Ia,Ja),I(B,K,L,U,aa,ba,0,0,1,0,0,1,Z)):Y instanceof THREE.MeshNormalMaterial&&(Y.shading==THREE.FlatShading?(d=h.normalModelView,fa.setRGB(d.x,d.y,d.z).multiplyScalar(0.5).addScalar(0.5),!0===Y.wireframe?v(fa,Y.wireframeLinewidth, -Y.wireframeLinecap,Y.wireframeLinejoin):x(fa)):Y.shading==THREE.SmoothShading&&(d=h.vertexNormalsModelView[g],Da.setRGB(d.x,d.y,d.z).multiplyScalar(0.5).addScalar(0.5),d=h.vertexNormalsModelView[j],Aa.setRGB(d.x,d.y,d.z).multiplyScalar(0.5).addScalar(0.5),d=h.vertexNormalsModelView[i],Ia.setRGB(d.x,d.y,d.z).multiplyScalar(0.5).addScalar(0.5),Ja.addColors(Aa,Ia).multiplyScalar(0.5),Z=jb(Da,Aa,Ia,Ja),I(B,K,L,U,aa,ba,0,0,1,0,0,1,Z)))}function s(a,b,c,d,e,f){q.beginPath();q.moveTo(a,b);q.lineTo(c,d); -q.lineTo(e,f);q.closePath()}function t(a,b,c,d,e,f,g,j){q.beginPath();q.moveTo(a,b);q.lineTo(c,d);q.lineTo(e,f);q.lineTo(g,j);q.closePath()}function v(a,b,c,e){H!==b&&(H=q.lineWidth=b);D!==c&&(D=q.lineCap=c);y!==e&&(y=q.lineJoin=e);d(a.getStyle());q.stroke();Ya.expandByScalar(2*b)}function x(a){e(a.getStyle());q.fill()}function z(a,b,c,d,f,g,j,i,h,Y,k,l,n){if(!(n instanceof THREE.DataTexture||void 0===n.image||0==n.image.width)){if(!0===n.needsUpdate){var m=n.wrapS==THREE.RepeatWrapping,p=n.wrapT== -THREE.RepeatWrapping;Ra[n.id]=q.createPattern(n.image,!0===m&&!0===p?"repeat":!0===m&&!1===p?"repeat-x":!1===m&&!0===p?"repeat-y":"no-repeat");n.needsUpdate=!1}void 0===Ra[n.id]?e("rgba(0,0,0,1)"):e(Ra[n.id]);var m=n.offset.x/n.repeat.x,p=n.offset.y/n.repeat.y,s=n.image.width*n.repeat.x,r=n.image.height*n.repeat.y,j=(j+m)*s,i=(1-i+p)*r,c=c-a,d=d-b,f=f-a,g=g-b,h=(h+m)*s-j,Y=(1-Y+p)*r-i,k=(k+m)*s-j,l=(1-l+p)*r-i,m=h*l-k*Y;0===m?(void 0===ia[n.id]&&(b=document.createElement("canvas"),b.width=n.image.width, -b.height=n.image.height,b=b.getContext("2d"),b.drawImage(n.image,0,0),ia[n.id]=b.getImageData(0,0,n.image.width,n.image.height).data),b=ia[n.id],j=4*(Math.floor(j)+Math.floor(i)*n.image.width),fa.setRGB(b[j]/255,b[j+1]/255,b[j+2]/255),x(fa)):(m=1/m,n=(l*c-Y*f)*m,Y=(l*d-Y*g)*m,c=(h*f-k*c)*m,d=(h*g-k*d)*m,a=a-n*j-c*i,j=b-Y*j-d*i,q.save(),q.transform(n,Y,c,d,a,j),q.fill(),q.restore())}}function I(a,b,c,d,e,f,g,j,i,h,Y,k,n){var l,m;l=n.width-1;m=n.height-1;g*=l;j*=m;c-=a;d-=b;e-=a;f-=b;i=i*l-g;h=h*m- -j;Y=Y*l-g;k=k*m-j;m=1/(i*k-Y*h);l=(k*c-h*e)*m;h=(k*d-h*f)*m;c=(i*e-Y*c)*m;d=(i*f-Y*d)*m;a=a-l*g-c*j;b=b-h*g-d*j;q.save();q.transform(l,h,c,d,a,b);q.clip();q.drawImage(n,0,0);q.restore()}function jb(a,b,c,d){ob[0]=255*a.r|0;ob[1]=255*a.g|0;ob[2]=255*a.b|0;ob[4]=255*b.r|0;ob[5]=255*b.g|0;ob[6]=255*b.b|0;ob[8]=255*c.r|0;ob[9]=255*c.g|0;ob[10]=255*c.b|0;ob[12]=255*d.r|0;ob[13]=255*d.g|0;ob[14]=255*d.b|0;Ob.putImageData(rc,0,0);sb.drawImage(zb,0,0);return Fa}function cb(a,b,c){a=(a-b)/(c-b);return a*a* -(3-2*a)}function kb(a,b){var c=b.x-a.x,d=b.y-a.y,e=c*c+d*d;0!==e&&(e=1/Math.sqrt(e),c*=e,d*=e,b.x+=c,b.y+=d,a.x-=c,a.y-=d)}if(!1===l instanceof THREE.Camera)console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");else{!0===this.autoClear&&this.clear();q.setTransform(1,0,0,-1,r,p);f.info.render.vertices=0;f.info.render.faces=0;g=k.projectScene(a,l,this.sortObjects,this.sortElements);i=g.elements;h=g.lights;Db=0>1,dd=ja.height>>1,Wa=Za.scale.x*r,Pa=Za.scale.y*p,Va=Wa*Y,$a=Pa*dd,Ya.min.set(T.x-Va,T.y-$a),Ya.max.set(T.x+Va,T.y+$a),!1!==Ua.isIntersectionBox(Ya)&&(q.save(),q.translate(T.x, -T.y),q.rotate(-Za.rotation),q.scale(Wa,-Pa),q.translate(-Y,-dd),q.drawImage(ja,0,0),q.restore())):S instanceof THREE.ParticleCanvasMaterial&&(Va=Za.scale.x*r,$a=Za.scale.y*p,Ya.min.set(T.x-Va,T.y-$a),Ya.max.set(T.x+Va,T.y+$a),!1!==Ua.isIntersectionBox(Ya)&&(d(S.color.getStyle()),e(S.color.getStyle()),q.save(),q.translate(T.x,T.y),q.rotate(-Za.rotation),q.scale(Va,$a),S.program(q),q.restore()))}else if(ja instanceof THREE.RenderableLine)F=ja.v1,E=ja.v2,F.positionScreen.x*=r,F.positionScreen.y*=p,E.positionScreen.x*= -r,E.positionScreen.y*=p,Ya.setFromPoints([F.positionScreen,E.positionScreen]),!0===Ua.isIntersectionBox(Ya)&&(T=F,Za=E,b(S.opacity),c(S.blending),q.beginPath(),q.moveTo(T.positionScreen.x,T.positionScreen.y),q.lineTo(Za.positionScreen.x,Za.positionScreen.y),S instanceof THREE.LineBasicMaterial&&(T=S.linewidth,H!==T&&(H=q.lineWidth=T),T=S.linecap,D!==T&&(D=q.lineCap=T),T=S.linejoin,y!==T&&(y=q.lineJoin=T),d(S.color.getStyle()),q.stroke(),Ya.expandByScalar(2*S.linewidth)));else if(ja instanceof THREE.RenderableFace3){F= -ja.v1;E=ja.v2;G=ja.v3;if(-1>F.positionScreen.z||1E.positionScreen.z||1G.positionScreen.z||1F.positionScreen.z||1E.positionScreen.z||1G.positionScreen.z||1W.positionScreen.z||1 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif", -lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\nspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\nspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n#ifdef DOUBLE_SIDED\nvLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\nvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n#ifdef DOUBLE_SIDED\nvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n#endif\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;\n#endif", -lights_phong_pars_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif", -lights_phong_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nvSpotLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvWorldPosition = worldPosition.xyz;\n#endif", -lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#else\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;", -lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#ifdef USE_NORMALMAP\nnormal = perturbNormal2Arb( -viewPosition, normal );\n#elif defined( USE_BUMPMAP )\nnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vSpotLight[ i ].xyz );\nfloat lDistance = vSpotLight[ i ].w;\n#endif\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n#endif\nspotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\nvec3 spotHalfVector = normalize( lVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += diffuse * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif", -color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, opacity );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n#ifdef BONE_TEXTURE\nuniform sampler2D boneTexture;\nmat4 getBoneMatrix( const in float i ) {\nfloat j = i * 4.0;\nfloat x = mod( j, N_BONE_PIXEL_X );\nfloat y = floor( j / N_BONE_PIXEL_X );\nconst float dx = 1.0 / N_BONE_PIXEL_X;\nconst float dy = 1.0 / N_BONE_PIXEL_Y;\ny = dy * ( y + 0.5 );\nvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\nvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\nvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\nvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\nmat4 bone = mat4( v1, v2, v3, v4 );\nreturn bone;\n}\n#else\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\nmat4 getBoneMatrix( const in float i ) {\nmat4 bone = boneGlobalMatrices[ int(i) ];\nreturn bone;\n}\n#endif\n#endif", -skinbase_vertex:"#ifdef USE_SKINNING\nmat4 boneMatX = getBoneMatrix( skinIndex.x );\nmat4 boneMatY = getBoneMatrix( skinIndex.y );\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n#ifdef USE_MORPHTARGETS\nvec4 skinVertex = vec4( morphed, 1.0 );\n#else\nvec4 skinVertex = vec4( position, 1.0 );\n#endif\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif", -morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\n#endif", -default_vertex:"vec4 mvPosition;\n#ifdef USE_SKINNING\nmvPosition = modelViewMatrix * skinned;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( position, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\n#endif", -skinnormal_vertex:"#ifdef USE_SKINNING\nmat4 skinMatrix = skinWeight.x * boneMatX;\nskinMatrix \t+= skinWeight.y * boneMatY;\n#ifdef USE_MORPHNORMALS\nvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n#else\nvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n#endif\n#endif",defaultnormal_vertex:"vec3 objectNormal;\n#ifdef USE_SKINNING\nobjectNormal = skinnedNormal.xyz;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )\nobjectNormal = morphedNormal;\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )\nobjectNormal = normal;\n#endif\n#ifdef FLIP_SIDED\nobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;", -shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#if defined( SHADOWMAP_TYPE_PCF )\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\nfloat shadow = 0.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.0 * xPixelOffset;\nfloat dy0 = -1.0 * yPixelOffset;\nfloat dx1 = 1.0 * xPixelOffset;\nfloat dy1 = 1.0 * yPixelOffset;\nmat3 shadowKernel;\nmat3 depthKernel;\ndepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( depthKernel[0][0] < shadowCoord.z ) shadowKernel[0][0] = 0.25;\nelse shadowKernel[0][0] = 0.0;\ndepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( depthKernel[0][1] < shadowCoord.z ) shadowKernel[0][1] = 0.25;\nelse shadowKernel[0][1] = 0.0;\ndepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( depthKernel[0][2] < shadowCoord.z ) shadowKernel[0][2] = 0.25;\nelse shadowKernel[0][2] = 0.0;\ndepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( depthKernel[1][0] < shadowCoord.z ) shadowKernel[1][0] = 0.25;\nelse shadowKernel[1][0] = 0.0;\ndepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( depthKernel[1][1] < shadowCoord.z ) shadowKernel[1][1] = 0.25;\nelse shadowKernel[1][1] = 0.0;\ndepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( depthKernel[1][2] < shadowCoord.z ) shadowKernel[1][2] = 0.25;\nelse shadowKernel[1][2] = 0.0;\ndepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( depthKernel[2][0] < shadowCoord.z ) shadowKernel[2][0] = 0.25;\nelse shadowKernel[2][0] = 0.0;\ndepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( depthKernel[2][1] < shadowCoord.z ) shadowKernel[2][1] = 0.25;\nelse shadowKernel[2][1] = 0.0;\ndepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( depthKernel[2][2] < shadowCoord.z ) shadowKernel[2][2] = 0.25;\nelse shadowKernel[2][2] = 0.0;\nvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\nshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\nshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\nvec4 shadowValues;\nshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\nshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\nshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\nshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\nshadow = dot( shadowValues, vec4( 1.0 ) );\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif", -shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif",linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"}; -THREE.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b dashSize ) {\ndiscard;\n}\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f", -value:1}},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float mNear;\nuniform float mFar;\nuniform float opacity;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), opacity );\n}"},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:"varying vec3 vNormal;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvNormal = normalize( normalMatrix * normal );\ngl_Position = projectionMatrix * mvPosition;\n}", -fragmentShader:"uniform float opacity;\nvarying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );\n}"},normalmap:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null}, -tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},uDiffuseColor:{type:"c",value:new THREE.Color(16777215)},uSpecularColor:{type:"c",value:new THREE.Color(1118481)},uAmbientColor:{type:"c",value:new THREE.Color(16777215)},uShininess:{type:"f",value:30},uOpacity:{type:"f",value:1},useRefract:{type:"i",value:0}, -uRefractionRatio:{type:"f",value:0.98},uReflectivity:{type:"f",value:0.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 uAmbientColor;\nuniform vec3 uDiffuseColor;\nuniform vec3 uSpecularColor;\nuniform float uShininess;\nuniform float uOpacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float uRefractionRatio;\nuniform float uReflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", -THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\n#ifdef FLIP_SIDED\nfinalNormal = -finalNormal;\n#endif\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 pointVector = lPosition.xyz + vViewPosition.xyz;\nfloat pointDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\npointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );\npointVector = normalize( pointVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n#else\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 spotVector = lPosition.xyz + vViewPosition.xyz;\nfloat spotDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nspotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );\nspotVector = normalize( spotVector );\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );\n#endif\nspotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;\nvec3 spotHalfVector = normalize( spotVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += uDiffuseColor * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;\n#endif\nif ( enableReflection ) {\nvec3 vReflect;\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nvReflect = refract( cameraToVertex, normal, uRefractionRatio );\n} else {\nvReflect = reflect( cameraToVertex, normal );\n}\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}", -THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\nuniform bool enableDisplacement;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", -THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,"#ifdef USE_SKINNING\nvNormal = normalize( normalMatrix * skinnedNormal.xyz );\nvec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );\nvTangent = normalize( normalMatrix * skinnedTangent.xyz );\n#else\nvNormal = normalize( normalMatrix * normal );\nvTangent = normalize( normalMatrix * tangent.xyz );\n#endif\nvBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );\nvUv = uv * uRepeat + uOffset;\nvec3 displacedPosition;\n#ifdef VERTEX_TEXTURES\nif ( enableDisplacement ) {\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\ndisplacedPosition = position + normalize( normal ) * df;\n} else {\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n}\n#else\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n#endif\nvec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );\nvec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\nvWorldPosition = worldPosition.xyz;\nvViewPosition = -mvPosition.xyz;\n#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif\n}"].join("\n")}, -cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vWorldPosition;\nvoid main() {\nvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\nvWorldPosition = worldPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\nvoid main() {\ngl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n}"}, -depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"vec4 pack_depth( const in float depth ) {\nconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\nconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\nvec4 res = fract( depth * bit_shift );\nres -= res.xxyz * bit_mask;\nreturn res;\n}\nvoid main() {\ngl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n}"}};THREE.WebGLRenderer=function(a){function b(a){if(a.__webglCustomAttributesList)for(var b in a.__webglCustomAttributesList)j.deleteBuffer(a.__webglCustomAttributesList[b].buffer)}function c(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var e in d.attributes){var f=d.attributes[e];if(!f.__webglInitialized||f.createUniqueBuffers){f.__webglInitialized=!0;var g=1;"v2"===f.type?g=2:"v3"===f.type?g=3:"v4"===f.type? -g=4:"c"===f.type&&(g=3);f.size=g;f.array=new Float32Array(c*g);f.buffer=j.createBuffer();f.buffer.belongsToAttribute=e;f.needsUpdate=!0}a.__webglCustomAttributesList.push(f)}}}function d(a,b){var c=b.geometry,d=a.faces3,i=a.faces4,h=3*d.length+4*i.length,k=1*d.length+2*i.length,i=3*d.length+4*i.length,d=e(b,a),n=g(d),l=f(d),m=d.vertexColors?d.vertexColors:!1;a.__vertexArray=new Float32Array(3*h);l&&(a.__normalArray=new Float32Array(3*h));c.hasTangents&&(a.__tangentArray=new Float32Array(4*h));m&& -(a.__colorArray=new Float32Array(3*h));if(n){if(0l;l++)M.autoScaleCubemaps&&!f?(m=k,r=l,t=c.image[l],x=ad,t.width<=x&&t.height<=x||(z=Math.max(t.width,t.height),v=Math.floor(t.width*x/z),x=Math.floor(t.height*x/z),z=document.createElement("canvas"),z.width=v,z.height=x,z.getContext("2d").drawImage(t,0,0,t.width,t.height,0,0,v,x),t=z),m[r]=t):k[l]=c.image[l];l=k[0];m=0===(l.width&l.width-1)&&0===(l.height&l.height-1);r=K(c.format);t=K(c.type);A(j.TEXTURE_CUBE_MAP,c,m);for(l=0;6>l;l++)if(f){x= -k[l].mipmaps;z=0;for(D=x.length;z=Bc&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Bc); -Ra+=1;return a}function D(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getInverse(a._modelViewMatrix);a._normalMatrix.transpose()}function y(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}function F(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function E(a,b,c){yb!==a&&(a?j.enable(j.POLYGON_OFFSET_FILL):j.disable(j.POLYGON_OFFSET_FILL),yb=a);if(a&&(Cb!==b||Lb!==c))j.polygonOffset(b,c),Cb=b,Lb=c}function G(a){for(var a=a.split("\n"),b=0,c= -a.length;bb;b++)j.deleteFramebuffer(a.__webglFramebuffer[b]),j.deleteRenderbuffer(a.__webglRenderbuffer[b]);else j.deleteFramebuffer(a.__webglFramebuffer),j.deleteRenderbuffer(a.__webglRenderbuffer);M.info.memory.textures--},Wa=function(a){a=a.target;a.removeEventListener("dispose",Wa);Pa(a)},Pa=function(a){var b= -a.program;if(void 0!==b){a.program=void 0;var c,d,e=!1,a=0;for(c=fa.length;a<=b.position)a&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglVertexBuffer),k(b.position),j.vertexAttribPointer(b.position,3,j.FLOAT,!1,0,0));else if(f.morphTargetBase){c=d.program.attributes;-1!==f.morphTargetBase&&0<=c.position?(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]),k(c.position),j.vertexAttribPointer(c.position,3,j.FLOAT,!1,0,0)):0<=c.position&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglVertexBuffer),k(c.position),j.vertexAttribPointer(c.position,3,j.FLOAT,!1,0,0));if(f.morphTargetForcedOrder.length){var i= -0;h=f.morphTargetForcedOrder;for(g=f.morphTargetInfluences;i<=c["morphTarget"+i]&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[h[i]]),k(c["morphTarget"+i]),j.vertexAttribPointer(c["morphTarget"+i],3,j.FLOAT,!1,0,0)),0<=c["morphNormal"+i]&&d.morphNormals&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[h[i]]),k(c["morphNormal"+i]),j.vertexAttribPointer(c["morphNormal"+i],3,j.FLOAT,!1,0,0)),f.__webglMorphTargetInfluences[i]=g[h[i]],i++}else{h= -[];g=f.morphTargetInfluences;var m,p=g.length;for(m=0;md.numSupportedMorphTargets?(h.sort(n),h.length=d.numSupportedMorphTargets):h.length>d.numSupportedMorphNormals?h.sort(n):0===h.length&&h.push([0,0]);for(i=0;i<=c["morphTarget"+i]&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[m]),k(c["morphTarget"+i]),j.vertexAttribPointer(c["morphTarget"+i],3,j.FLOAT,!1,0,0)),0<=c["morphNormal"+i]&&d.morphNormals&& -(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[m]),k(c["morphNormal"+i]),j.vertexAttribPointer(c["morphNormal"+i],3,j.FLOAT,!1,0,0)),f.__webglMorphTargetInfluences[i]=g[m]):f.__webglMorphTargetInfluences[i]=0,i++}null!==d.program.uniforms.morphTargetInfluences&&j.uniform1fv(d.program.uniforms.morphTargetInfluences,f.__webglMorphTargetInfluences)}if(a){if(e.__webglCustomAttributesList){g=0;for(h=e.__webglCustomAttributesList.length;g<=b[c.buffer.belongsToAttribute]&& -(j.bindBuffer(j.ARRAY_BUFFER,c.buffer),k(b[c.buffer.belongsToAttribute]),j.vertexAttribPointer(b[c.buffer.belongsToAttribute],c.size,j.FLOAT,!1,0,0))}0<=b.color&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglColorBuffer),k(b.color),j.vertexAttribPointer(b.color,3,j.FLOAT,!1,0,0));0<=b.normal&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglNormalBuffer),k(b.normal),j.vertexAttribPointer(b.normal,3,j.FLOAT,!1,0,0));0<=b.tangent&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglTangentBuffer),k(b.tangent),j.vertexAttribPointer(b.tangent, -4,j.FLOAT,!1,0,0));0<=b.uv&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglUVBuffer),k(b.uv),j.vertexAttribPointer(b.uv,2,j.FLOAT,!1,0,0));0<=b.uv2&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglUV2Buffer),k(b.uv2),j.vertexAttribPointer(b.uv2,2,j.FLOAT,!1,0,0));d.skinning&&(0<=b.skinIndex&&0<=b.skinWeight)&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinIndicesBuffer),k(b.skinIndex),j.vertexAttribPointer(b.skinIndex,4,j.FLOAT,!1,0,0),j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinWeightsBuffer),k(b.skinWeight),j.vertexAttribPointer(b.skinWeight, -4,j.FLOAT,!1,0,0));0<=b.lineDistance&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglLineDistanceBuffer),k(b.lineDistance),j.vertexAttribPointer(b.lineDistance,1,j.FLOAT,!1,0,0))}f instanceof THREE.Mesh?(d.wireframe?(d=d.wireframeLinewidth,d!==Ua&&(j.lineWidth(d),Ua=d),a&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglLineBuffer),j.drawElements(j.LINES,e.__webglLineCount,j.UNSIGNED_SHORT,0)):(a&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer),j.drawElements(j.TRIANGLES,e.__webglFaceCount,j.UNSIGNED_SHORT, -0)),M.info.render.calls++,M.info.render.vertices+=e.__webglFaceCount,M.info.render.faces+=e.__webglFaceCount/3):f instanceof THREE.Line?(f=f.type===THREE.LineStrip?j.LINE_STRIP:j.LINES,d=d.linewidth,d!==Ua&&(j.lineWidth(d),Ua=d),j.drawArrays(f,0,e.__webglLineCount),M.info.render.calls++):f instanceof THREE.ParticleSystem?(j.drawArrays(j.POINTS,0,e.__webglParticleCount),M.info.render.calls++,M.info.render.points+=e.__webglParticleCount):f instanceof THREE.Ribbon&&(j.drawArrays(j.TRIANGLE_STRIP,0,e.__webglVertexCount), -M.info.render.calls++)}};this.render=function(a,b,c,d){if(!1===b instanceof THREE.Camera)console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");else{var e,f,g,h,i=a.__lights,k=a.fog;Ja=-1;sb=!0;this.autoUpdateScene&&a.updateMatrixWorld();void 0===b.parent&&b.updateMatrixWorld();b.matrixWorldInverse.getInverse(b.matrixWorld);Ob.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);zb.setFromMatrix(Ob);this.autoUpdateObjects&&this.initWebGLObjects(a);r(this.renderPluginsPre, -a,b);M.info.render.calls=0;M.info.render.vertices=0;M.info.render.faces=0;M.info.render.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);h=a.__webglObjects;d=0;for(e=h.length;dva;va++)mc=$a[va],Gb[qb]=mc.x,Gb[qb+1]=mc.y,Gb[qb+2]=mc.z,qb+=3;else for(va=0;3>va;va++)Gb[qb]=Wa.x,Gb[qb+1]=Wa.y,Gb[qb+2]=Wa.z,qb+=3;C=0;for(V=ta.length;Cva;va++)mc=$a[va],Gb[qb]=mc.x,Gb[qb+1]=mc.y,Gb[qb+2]=mc.z,qb+=3;else for(va=0;4>va;va++)Gb[qb]=Wa.x,Gb[qb+1]=Wa.y,Gb[qb+ -2]=Wa.z,qb+=3;j.bindBuffer(j.ARRAY_BUFFER,qa.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,Gb,na)}if(Bc&&fd&&pb){C=0;for(V=sa.length;Cva;va++)Eb=hb[va],Mb[gc]=Eb.x,Mb[gc+1]=Eb.y,gc+=2;C=0;for(V=ta.length;Cva;va++)Eb=hb[va],Mb[gc]=Eb.x,Mb[gc+1]=Eb.y,gc+=2;0va;va++)xc=sb[va],Nb[hc]=xc.x,Nb[hc+1]=xc.y,hc+=2;C=0;for(V=ta.length;Cva;va++)xc=sb[va],Nb[hc]=xc.x,Nb[hc+1]=xc.y,hc+=2;0<=y[x]&&a.numSupportedMorphNormals++}a.uniformsList=[];for(i in a.uniforms)a.uniformsList.push([a.uniforms[i],i])};this.setFaceCulling=function(a,b){a===THREE.CullFaceNone?j.disable(j.CULL_FACE):(b===THREE.FrontFaceDirectionCW?j.frontFace(j.CW):j.frontFace(j.CCW),a===THREE.CullFaceBack?j.cullFace(j.BACK):a===THREE.CullFaceFront?j.cullFace(j.FRONT):j.cullFace(j.FRONT_AND_BACK),j.enable(j.CULL_FACE))};this.setMaterialFaces=function(a){var b=a.side===THREE.DoubleSide,a=a.side===THREE.BackSide;ia!== -b&&(b?j.disable(j.CULL_FACE):j.enable(j.CULL_FACE),ia=b);ra!==a&&(a?j.frontFace(j.CW):j.frontFace(j.CCW),ra=a)};this.setDepthTest=function(a){hb!==a&&(a?j.enable(j.DEPTH_TEST):j.disable(j.DEPTH_TEST),hb=a)};this.setDepthWrite=function(a){Ea!==a&&(j.depthMask(a),Ea=a)};this.setBlending=function(a,b,c,d){a!==ga&&(a===THREE.NoBlending?j.disable(j.BLEND):a===THREE.AdditiveBlending?(j.enable(j.BLEND),j.blendEquation(j.FUNC_ADD),j.blendFunc(j.SRC_ALPHA,j.ONE)):a===THREE.SubtractiveBlending?(j.enable(j.BLEND), -j.blendEquation(j.FUNC_ADD),j.blendFunc(j.ZERO,j.ONE_MINUS_SRC_COLOR)):a===THREE.MultiplyBlending?(j.enable(j.BLEND),j.blendEquation(j.FUNC_ADD),j.blendFunc(j.ZERO,j.SRC_COLOR)):a===THREE.CustomBlending?j.enable(j.BLEND):(j.enable(j.BLEND),j.blendEquationSeparate(j.FUNC_ADD,j.FUNC_ADD),j.blendFuncSeparate(j.SRC_ALPHA,j.ONE_MINUS_SRC_ALPHA,j.ONE,j.ONE_MINUS_SRC_ALPHA)),ga=a);if(a===THREE.CustomBlending){if(b!==Z&&(j.blendEquation(K(b)),Z=b),c!==pa||d!==gb)j.blendFunc(K(c),K(d)),pa=c,gb=d}else gb=pa= -Z=null};this.setTexture=function(a,b){if(a.needsUpdate){a.__webglInit||(a.__webglInit=!0,a.addEventListener("dispose",Va),a.__webglTexture=j.createTexture(),M.info.memory.textures++);j.activeTexture(j.TEXTURE0+b);j.bindTexture(j.TEXTURE_2D,a.__webglTexture);j.pixelStorei(j.UNPACK_FLIP_Y_WEBGL,a.flipY);j.pixelStorei(j.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha);j.pixelStorei(j.UNPACK_ALIGNMENT,a.unpackAlignment);var c=a.image,d=0===(c.width&c.width-1)&&0===(c.height&c.height-1),e=K(a.format), -f=K(a.type);A(j.TEXTURE_2D,a,d);var g=a.mipmaps;if(a instanceof THREE.DataTexture)if(0f;f++){a.__webglFramebuffer[f]=j.createFramebuffer();a.__webglRenderbuffer[f]=j.createRenderbuffer();j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=j.TEXTURE_CUBE_MAP_POSITIVE_X+f;j.bindFramebuffer(j.FRAMEBUFFER, -a.__webglFramebuffer[f]);j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,h,g.__webglTexture,0);X(a.__webglRenderbuffer[f],a)}c&&j.generateMipmap(j.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=j.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:j.createRenderbuffer(),j.bindTexture(j.TEXTURE_2D,a.__webglTexture),A(j.TEXTURE_2D,a,c),j.texImage2D(j.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=j.TEXTURE_2D,j.bindFramebuffer(j.FRAMEBUFFER,a.__webglFramebuffer), -j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):X(a.__webglRenderbuffer,a),c&&j.generateMipmap(j.TEXTURE_2D);b?j.bindTexture(j.TEXTURE_CUBE_MAP,null):j.bindTexture(j.TEXTURE_2D,null);j.bindRenderbuffer(j.RENDERBUFFER, -null);j.bindFramebuffer(j.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=Db,a=nb,d=na,e=Ya);b!==Ia&&(j.bindFramebuffer(j.FRAMEBUFFER,b),j.viewport(d,e,c,a),Ia=b);kc=c;Mb=a};this.shadowMapPlugin=new THREE.ShadowMapPlugin;this.addPrePlugin(this.shadowMapPlugin);this.addPostPlugin(new THREE.SpritePlugin);this.addPostPlugin(new THREE.LensFlarePlugin)};THREE.WebGLRenderTarget=function(a,b,c){THREE.EventDispatcher.call(this);this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1); -this.format=void 0!==c.format?c.format:THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=null}; -THREE.WebGLRenderTarget.prototype.clone=function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;a.generateMipmaps=this.generateMipmaps;a.shareDepthFrom=this.shareDepthFrom;return a}; -THREE.WebGLRenderTarget.prototype.dispose=function(){this.dispatchEvent({type:"dispose"})};THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=!0};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};THREE.RenderableFace3=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.material=this.color=null;this.uvs=[[]];this.z=null};THREE.RenderableFace4=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.v4=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3]; -this.material=this.color=null;this.uvs=[[]];this.z=null};THREE.RenderableObject=function(){this.z=this.object=null};THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=this.object=null;this.scale=new THREE.Vector2;this.material=null};THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.material=null};THREE.ColorUtils={adjustHSV:function(a,b,c,d){var e=THREE.ColorUtils.__hsv;a.getHSV(e);e.h=THREE.Math.clamp(e.h+b,0,1);e.s=THREE.Math.clamp(e.s+c,0,1);e.v=THREE.Math.clamp(e.v+d,0,1);a.setHSV(e.h,e.s,e.v)}};THREE.ColorUtils.__hsv={h:0,s:0,v:0};THREE.GeometryUtils={merge:function(a,b){var c,d,e=a.vertices.length,f=b instanceof THREE.Mesh?b.geometry:b,g=a.vertices,i=f.vertices,h=a.faces,k=f.faces,l=a.faceVertexUvs[0],f=f.faceVertexUvs[0];b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),c=b.matrix,d=new THREE.Matrix3,d.getInverse(c),d.transpose());for(var m=0,n=i.length;ma?b(c,e-1):k[e]<=d;c++)a[c].materialIndex=b}};THREE.GeometryUtils.random=THREE.Math.random16;THREE.GeometryUtils.__v1=new THREE.Vector3;THREE.GeometryUtils.__v2=new THREE.Vector3;THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(a,b,c,d){var e=new Image,f=new THREE.Texture(e,b),b=new THREE.ImageLoader;b.addEventListener("load",function(a){f.image=a.content;f.needsUpdate=!0;c&&c(f)});b.addEventListener("error",function(a){d&&d(a.message)});b.crossOrigin=this.crossOrigin;b.load(a,e);f.sourceFile=a;return f},loadCompressedTexture:function(a,b,c,d){var e=new THREE.CompressedTexture;e.mapping=b;var f=new XMLHttpRequest;f.onload=function(){var a=THREE.ImageUtils.parseDDS(f.response, -!0);e.format=a.format;e.mipmaps=a.mipmaps;e.image.width=a.width;e.image.height=a.height;e.generateMipmaps=!1;e.needsUpdate=!0;c&&c(e)};f.onerror=d;f.open("GET",a,!0);f.responseType="arraybuffer";f.send(null);return e},loadTextureCube:function(a,b,c,d){var e=[];e.loadCount=0;var f=new THREE.Texture;f.image=e;void 0!==b&&(f.mapping=b);f.flipY=!1;for(var b=0,g=a.length;b<<8)+(a.charCodeAt(2)<<16)+(a.charCodeAt(3)<<24)}var d={mipmaps:[],width:0,height:0,format:null,mipmapCount:1},e=c("DXT1"),f=c("DXT3"),g=c("DXT5"),i=new Int32Array(a,0,31);if(542327876!==i[0])return console.error("ImageUtils.parseDDS(): Invalid magic number in DDS header"),d;if(!i[20]&4)return console.error("ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code"), -d;var h=i[21];switch(h){case e:e=8;d.format=THREE.RGB_S3TC_DXT1_Format;break;case f:e=16;d.format=THREE.RGBA_S3TC_DXT3_Format;break;case g:e=16;d.format=THREE.RGBA_S3TC_DXT5_Format;break;default:return console.error("ImageUtils.parseDDS(): Unsupported FourCC code: ",String.fromCharCode(h&255,h>>8&255,h>>16&255,h>>24&255)),d}d.mipmapCount=1;i[2]&131072&&!1!==b&&(d.mipmapCount=Math.max(1,i[7]));d.isCubemap=i[28]&512?!0:!1;d.width=i[4];d.height=i[3];for(var i=i[1]+4,f=d.width,g=d.height,h=d.isCubemap? -6:1,k=0;km-1?0:m-1,r=m+1>e-1?e-1:m+1,p=0>l-1?0:l-1,q=l+1>d-1?d-1:l+1,s=[],t=[0,0,i[4*(m*d+l)]/255*b];s.push([-1,0,i[4*(m*d+p)]/255*b]);s.push([-1,-1,i[4*(n*d+p)]/255*b]);s.push([0,-1,i[4*(n*d+l)]/255*b]);s.push([1,-1,i[4*(n*d+q)]/255*b]);s.push([1,0,i[4*(m*d+q)]/255*b]);s.push([1,1,i[4*(r*d+q)]/255*b]);s.push([0,1,i[4*(r*d+l)]/255*b]);s.push([-1,1,i[4*(r*d+p)]/255*b]);n=[];p=s.length;for(r=0;re)return null;var f=[],g=[],i=[],h,k,l;if(0=m--){console.log("Warning, unable to triangulate polygon!");break}h=k;e<=h&&(h=0);k=h+1;e<=k&&(k=0);l=k+1;e<=l&&(l=0);var n;a:{var r=n=void 0,p=void 0,q=void 0,s=void 0,t=void 0,x=void 0,z=void 0,v= -void 0,r=a[g[h]].x,p=a[g[h]].y,q=a[g[k]].x,s=a[g[k]].y,t=a[g[l]].x,x=a[g[l]].y;if(1E-10>(q-r)*(x-p)-(s-p)*(t-r))n=!1;else{var I=void 0,H=void 0,D=void 0,y=void 0,F=void 0,E=void 0,G=void 0,W=void 0,A=void 0,X=void 0,A=W=G=v=z=void 0,I=t-q,H=x-s,D=r-t,y=p-x,F=q-r,E=s-p;for(n=0;n<=A&&0<=W&&0<=G){n=!1;break a}n=!0}}if(n){f.push([a[g[h]],a[g[k]],a[g[l]]]);i.push([g[h],g[k],g[l]]); -h=k;for(l=k+1;lh)g=d+1;else if(0b&&(b=0);1d.length-2?d.length-1:a+1;c[3]=a>d.length-3?d.length-1:a+2;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);return b}; -THREE.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g};THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype);THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;this.aClockwise||(a=1-a);b=this.aStartAngle+a*b;a=this.aX+this.xRadius*Math.cos(b);b=this.aY+this.yRadius*Math.sin(b);return new THREE.Vector2(a,b)}; -THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype); -THREE.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a){return 6*a*a-6*a+(3*a*a-4*a+1)+(-6*a*a+6*a)+(3*a*a-2*a)},interpolate:function(a,b,c,d,e){var a=0.5*(c-a),d=0.5*(d-b),f=e*e;return(2*b-2*c+a+d)*e*f+(-3*b+3*c-2*a-d)*f+a*e+b}}; -THREE.Curve.create=function(a,b){a.prototype=Object.create(THREE.Curve.prototype);a.prototype.getPoint=b;return a};THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b}); -THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b,c;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);c=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);a=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return new THREE.Vector3(b,c,a)}); -THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b,c;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);c=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);a=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return new THREE.Vector3(b,c,a)}); -THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e,a=(d.length-1)*a;e=Math.floor(a);a-=e;c[0]=0==e?e:e-1;c[1]=e;c[2]=e>d.length-2?d.length-1:e+1;c[3]=e>d.length-3?d.length-1:e+2;e=d[c[0]];var f=d[c[1]],g=d[c[2]],c=d[c[3]];b.x=THREE.Curve.Utils.interpolate(e.x,f.x,g.x,c.x,a);b.y=THREE.Curve.Utils.interpolate(e.y,f.y,g.y,c.y,a);b.z=THREE.Curve.Utils.interpolate(e.z,f.z,g.z,c.z,a);return b}); -THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e;e=(d.length-0)*a;a=Math.floor(e);e-=a;a+=0=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; -THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;cb?b=i.x:i.xc?c=i.y:i.yd?d=i.z:i.zMath.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; -THREE.Path.prototype.toShapes=function(){var a,b,c,d,e=[],f=new THREE.Path;a=0;for(b=this.actions.length;a -i&&(i+=c.length);i%=c.length;0>g&&(g+=k.length);g%=k.length;e=0<=i-1?i-1:c.length-1;f=0<=g-1?g-1:k.length-1;q=[k[g],c[i],c[e]];q=THREE.FontUtils.Triangulate.area(q);s=[k[g],k[f],c[i]];s=THREE.FontUtils.Triangulate.area(s);m+n>q+s&&(i=r,g=l,0>i&&(i+=c.length),i%=c.length,0>g&&(g+=k.length),g%=k.length,e=0<=i-1?i-1:c.length-1,f=0<=g-1?g-1:k.length-1);m=c.slice(0,i);n=c.slice(i);r=k.slice(g);l=k.slice(0,g);f=[k[g],k[f],c[i]];p.push([k[g],c[i],c[e]]);p.push(f);c=m.concat(r).concat(l).concat(n)}return{shape:c, -isolatedPts:p,allpoints:d}},triangulateShape:function(a,b){var c=THREE.Shape.Utils.removeHoles(a,b),d=c.allpoints,e=c.isolatedPts,c=THREE.FontUtils.Triangulate(c.shape,!1),f,g,i,h,k={};f=0;for(g=d.length;fd;d++)h=i[d].x+":"+i[d].y,h=k[h],void 0!==h&&(i[d]=h)}f=0;for(g=e.length;fd;d++)h=i[d].x+":"+i[d].y,h=k[h],void 0!==h&&(i[d]=h)}return c.concat(e)}, -isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+ -this.b3p3(a,e)}};THREE.AnimationHandler=function(){var a=[],b={},c={update:function(b){for(var c=0;ca.hierarchy[c].keys[d].time&& -(a.hierarchy[c].keys[d].time=0),void 0!==a.hierarchy[c].keys[d].rot&&!(a.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var i=a.hierarchy[c].keys[d].rot;a.hierarchy[c].keys[d].rot=new THREE.Quaternion(i[0],i[1],i[2],i[3])}if(a.hierarchy[c].keys.length&&void 0!==a.hierarchy[c].keys[0].morphTargets){i={};for(d=0;dr;r++){c=b[r];g=h.prevKey[c];i=h.nextKey[c];if(i.time<=l){if(k< -k;)g=i,i=this.getNextKeyWith(c,m,i.index+1)}else{this.stop();return}else{do g=i,i=this.getNextKeyWith(c,m,i.index+1);while(i.timed||1d?0:1;if("pos"===c)if(c=a.position,this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+ -(f[2]-e[2])*d;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)this.points[0]=this.getPrevKeyWith("pos",m,g.index-1).pos,this.points[1]=e,this.points[2]=f,this.points[3]=this.getNextKeyWith("pos",m,i.index+1).pos,d=0.33*d+0.33,e=this.interpolateCatmullRom(this.points,d),c.x=e[0],c.y=e[1],c.z=e[2],this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(d=this.interpolateCatmullRom(this.points,1.01*d), -this.target.set(d[0],d[1],d[2]),this.target.sub(c),this.target.y=0,this.target.normalize(),d=Math.atan2(this.target.x,this.target.z),a.rotation.set(0,d,0))}else"rot"===c?THREE.Quaternion.slerp(e,f,a.quaternion,d):"scl"===c&&(c=a.scale,c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+(f[2]-e[2])*d)}}}}; -THREE.Animation.prototype.interpolateCatmullRom=function(a,b){var c=[],d=[],e,f,g,i,h,k;e=(a.length-1)*b;f=Math.floor(e);e-=f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>a.length-2?f:f+1;c[3]=f>a.length-3?f:f+2;f=a[c[0]];i=a[c[1]];h=a[c[2]];k=a[c[3]];c=e*e;g=e*c;d[0]=this.interpolate(f[0],i[0],h[0],k[0],e,c,g);d[1]=this.interpolate(f[1],i[1],h[1],k[1],e,c,g);d[2]=this.interpolate(f[2],i[2],h[2],k[2],e,c,g);return d}; -THREE.Animation.prototype.interpolate=function(a,b,c,d,e,f,g){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b};THREE.Animation.prototype.getNextKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c=g?b.interpolate(c,g):b.interpolate(c,c.time)}this.data.hierarchy[a].node.updateMatrix();d.matrixWorldNeedsUpdate=!0}}if(this.JITCompile&&void 0===f[0][e]){this.hierarchy[0].updateMatrixWorld(!0);for(a=0;a< -a){this.vertices.push(new THREE.Vector3(0,g,0));for(i=0;ig?(b=Math.atan2(b.y-a.y,b.x-a.x),a=Math.atan2(c.y-a.y,c.x-a.x),b>a&&(a+=2*Math.PI),c=(b+a)/2,a=-Math.cos(c),c=-Math.sin(c),new THREE.Vector2(a,c)):d.multiplyScalar(g).add(h).sub(a).clone()}function e(c,d){var e,f;for(J=c.length;0<=--J;){e=J;f=J-1;0>f&&(f=c.length-1);for(var g=0,h=r+2*l, -g=0;gMath.abs(c-h)?[new THREE.Vector2(b,1-e),new THREE.Vector2(d,1-f),new THREE.Vector2(k,1-g),new THREE.Vector2(m,1-a)]:[new THREE.Vector2(c,1-e),new THREE.Vector2(h,1-f),new THREE.Vector2(l,1-g),new THREE.Vector2(n,1-a)]}};THREE.ExtrudeGeometry.__v1=new THREE.Vector2;THREE.ExtrudeGeometry.__v2=new THREE.Vector2;THREE.ExtrudeGeometry.__v3=new THREE.Vector2;THREE.ExtrudeGeometry.__v4=new THREE.Vector2; -THREE.ExtrudeGeometry.__v5=new THREE.Vector2;THREE.ExtrudeGeometry.__v6=new THREE.Vector2;THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);!1===a instanceof Array&&(a=[a]);this.shapebb=a[a.length-1].getBoundingBox();this.addShapeList(a,b);this.computeCentroids();this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;cd?(d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]),d.centroid.add(a).add(b).add(c).divideScalar(3),d.normal=d.centroid.clone().normalize(),h.faces.push(d),d=Math.atan2(d.centroid.z,-d.centroid.x),h.faceVertexUvs[0].push([i(a.uv, -a,d),i(b.uv,b,d),i(c.uv,c,d)])):(d-=1,f(a,g(a,b),g(a,c),d),f(g(a,b),b,g(b,c),d),f(g(a,c),g(b,c),c,d),f(g(a,b),g(b,c),g(a,c),d))}function g(a,b){m[a.index]||(m[a.index]=[]);m[b.index]||(m[b.index]=[]);var c=m[a.index][b.index];void 0===c&&(m[a.index][b.index]=m[b.index][a.index]=c=e((new THREE.Vector3).addVectors(a,b).divideScalar(2)));return c}function i(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+0.5,a.y));return a}THREE.Geometry.call(this); -for(var c=c||1,d=d||0,h=this,k=0,l=a.length;k=l){for(k=0;3>k;k++){l=[h[k],h[(k+1)%3]];m=!0;for(n=0;ni;i++)void 0===f[g[i]]&&(f[g[i]]=e++,this.vertices.push(a[g[i]])),g[i]=f[g[i]]}for(d=0;db.y?this.rotation.set(Math.PI,0,0):(a=THREE.ArrowHelper.__v2.set(b.z,0,-b.x).normalize(),b=Math.acos(b.y),a=THREE.ArrowHelper.__q1.setFromAxisAngle(a,b),this.rotation.setEulerFromQuaternion(a,this.eulerOrder))}; -THREE.ArrowHelper.prototype.setLength=function(a){this.scale.set(a,a,a)};THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a);this.cone.material.color.setHex(a)};THREE.ArrowHelper.__v1=new THREE.Vector3;THREE.ArrowHelper.__v2=new THREE.Vector3;THREE.ArrowHelper.__q1=new THREE.Quaternion;THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.geometry.vertices.push(new THREE.Vector3);d.geometry.colors.push(new THREE.Color(b));void 0===d.pointMap[a]&&(d.pointMap[a]=[]);d.pointMap[a].push(d.geometry.vertices.length-1)}THREE.Line.call(this);var d=this;this.geometry=new THREE.Geometry;this.material=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors});this.type=THREE.LinePieces;this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap= -{};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200);b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1", -"cf2",3355443);b("cf3","cf4",3355443);this.camera=a;this.update(a)};THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype); -THREE.CameraHelper.prototype.update=function(){function a(a,d,e,f){THREE.CameraHelper.__v.set(d,e,f);THREE.CameraHelper.__projector.unprojectVector(THREE.CameraHelper.__v,THREE.CameraHelper.__c);a=b.pointMap[a];if(void 0!==a){d=0;for(e=a.length;di.end&&(i.end=f);c||(c=h)}}for(h in d)i=d[h],this.createAnimation(h,i.start,i.end,a);this.firstAnimation=c}; -THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; -THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; -THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; -THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;bd.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight; -f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}};THREE.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";b.shaderSource(e,g+a.fragmentShader);b.shaderSource(f,g+a.vertexShader);b.compileShader(e);b.compileShader(f);b.attachShader(d,e);b.attachShader(d,f);b.linkProgram(d);return d}var b,c,d,e,f,g,i,h,k,l,m,n,r;this.init=function(p){b=p.context;c=p;d=p.getPrecision();e=new Float32Array(16);f=new Uint16Array(6);p=0;e[p++]=-1;e[p++]=-1; -e[p++]=0;e[p++]=0;e[p++]=1;e[p++]=-1;e[p++]=1;e[p++]=0;e[p++]=1;e[p++]=1;e[p++]=1;e[p++]=1;e[p++]=-1;e[p++]=1;e[p++]=0;e[p++]=1;p=0;f[p++]=0;f[p++]=1;f[p++]=2;f[p++]=0;f[p++]=2;f[p++]=3;g=b.createBuffer();i=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,g);b.bufferData(b.ARRAY_BUFFER,e,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,i);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);h=b.createTexture();k=b.createTexture();b.bindTexture(b.TEXTURE_2D,h);b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16, -0,b.RGB,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);b.bindTexture(b.TEXTURE_2D,k);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE); -b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);0>=b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)?(l=!1,m=a(THREE.ShaderFlares.lensFlare,d)):(l=!0,m=a(THREE.ShaderFlares.lensFlareVertexTexture,d));n={};r={};n.vertex=b.getAttribLocation(m,"position");n.uv=b.getAttribLocation(m,"uv");r.renderType=b.getUniformLocation(m,"renderType");r.map=b.getUniformLocation(m,"map");r.occlusionMap=b.getUniformLocation(m,"occlusionMap");r.opacity= -b.getUniformLocation(m,"opacity");r.color=b.getUniformLocation(m,"color");r.scale=b.getUniformLocation(m,"scale");r.rotation=b.getUniformLocation(m,"rotation");r.screenPosition=b.getUniformLocation(m,"screenPosition")};this.render=function(a,d,e,f){var a=a.__webglFlares,x=a.length;if(x){var z=new THREE.Vector3,v=f/e,I=0.5*e,H=0.5*f,D=16/f,y=new THREE.Vector2(D*v,D),F=new THREE.Vector3(1,1,0),E=new THREE.Vector2(1,1),G=r,D=n;b.useProgram(m);b.enableVertexAttribArray(n.vertex);b.enableVertexAttribArray(n.uv); -b.uniform1i(G.occlusionMap,0);b.uniform1i(G.map,1);b.bindBuffer(b.ARRAY_BUFFER,g);b.vertexAttribPointer(D.vertex,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(D.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,i);b.disable(b.CULL_FACE);b.depthMask(!1);var W,A,X,B,K;for(W=0;WD;D++)z[D]=new THREE.Vector3,t[D]=new THREE.Vector3;z=v.shadowCascadeNearZ[x];v=v.shadowCascadeFarZ[x];t[0].set(-1,-1,z);t[1].set(1,-1,z);t[2].set(-1, -1,z);t[3].set(1,1,z);t[4].set(-1,-1,v);t[5].set(1,-1,v);t[6].set(-1,1,v);t[7].set(1,1,v);H.originalCamera=m;t=new THREE.Gyroscope;t.position=p.shadowCascadeOffset;t.add(H);t.add(H.target);m.add(t);p.shadowCascadeArray[s]=H;console.log("Created virtualLight",H)}x=p;z=s;v=x.shadowCascadeArray[z];v.position.copy(x.position);v.target.position.copy(x.target.position);v.lookAt(v.target);v.shadowCameraVisible=x.shadowCameraVisible;v.shadowDarkness=x.shadowDarkness;v.shadowBias=x.shadowCascadeBias[z];t=x.shadowCascadeNearZ[z]; -x=x.shadowCascadeFarZ[z];v=v.pointsFrustum;v[0].z=t;v[1].z=t;v[2].z=t;v[3].z=t;v[4].z=x;v[5].z=x;v[6].z=x;v[7].z=x;I[q]=H;q++}else I[q]=p,q++;n=0;for(r=I.length;nx;x++)z=v[x],z.copy(t[x]),THREE.ShadowMapPlugin.__projector.unprojectVector(z,s),z.applyMatrix4(q.matrixWorldInverse),z.xk.x&&(k.x=z.x),z.yk.y&&(k.y=z.y),z.zk.z&& -(k.z=z.z);q.left=h.x;q.right=k.x;q.top=k.y;q.bottom=h.y;q.updateProjectionMatrix()}q=p.shadowMap;t=p.shadowMatrix;s=p.shadowCamera;s.position.copy(p.matrixWorld.getPosition());s.lookAt(p.target.matrixWorld.getPosition());s.updateMatrixWorld();s.matrixWorldInverse.getInverse(s.matrixWorld);p.cameraHelper&&(p.cameraHelper.visible=p.shadowCameraVisible);p.shadowCameraVisible&&p.cameraHelper.update();t.set(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1);t.multiply(s.projectionMatrix);t.multiply(s.matrixWorldInverse); -i.multiplyMatrices(s.projectionMatrix,s.matrixWorldInverse);g.setFromMatrix(i);b.setRenderTarget(q);b.clear();v=l.__webglObjects;p=0;for(q=v.length;p< alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"}}; +new q).copy(this.normal).multiplyScalar(c)},intersectLine:function(){var a=new q;return function(b,c){var d=c||new q,e=b.delta(a),f=this.normal.dot(e);if(0===f){if(0===this.distanceToPoint(b.start))return d.copy(b.start)}else return f=-(b.start.dot(this.normal)+this.constant)/f,0>f||1b&&0a&&0c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],m=c[7],l=c[8],n=c[9],p=c[10],r=c[11],q=c[12],t=c[13],D=c[14],c=c[15]; +b[0].setComponents(f-a,m-g,r-l,c-q).normalize();b[1].setComponents(f+a,m+g,r+l,c+q).normalize();b[2].setComponents(f+d,m+h,r+n,c+t).normalize();b[3].setComponents(f-d,m-h,r-n,c-t).normalize();b[4].setComponents(f-e,m-k,r-p,c-D).normalize();b[5].setComponents(f+e,m+k,r+p,c+D).normalize();return this},intersectsObject:function(){var a=new Ca;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere).applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(), +intersectsSprite:function(){var a=new Ca;return function(b){a.center.set(0,0,0);a.radius=.7071067811865476;a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes,c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)e;e++){var f=d[e];a.x=0g&&0>f)return!1}return!0}}(),containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0}};ab.prototype={constructor:ab,set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.origin.copy(a.origin); +this.direction.copy(a.direction);return this},at:function(a,b){return(b||new q).copy(this.direction).multiplyScalar(a).add(this.origin)},lookAt:function(a){this.direction.copy(a).sub(this.origin).normalize();return this},recast:function(){var a=new q;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPoint:function(a,b){var c=b||new q;c.subVectors(a,this.origin);var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)}, +distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))},distanceSqToPoint:function(){var a=new q;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceToSquared(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceToSquared(b)}}(),distanceSqToSegment:function(){var a=new q,b=new q,c=new q;return function(d,e,f,g){a.copy(d).add(e).multiplyScalar(.5);b.copy(e).sub(d).normalize();c.copy(this.origin).sub(a); +var h=.5*d.distanceTo(e),k=-this.direction.dot(b),m=c.dot(this.direction),l=-c.dot(b),n=c.lengthSq(),p=Math.abs(1-k*k),r;0<=d?e>=-r?e<=r?(h=1/p,d*=h,e*=h,k=d*(d+k*e+2*m)+e*(k*d+e+2*l)+n):(e=h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):(e=-h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):e<=-r?(d=Math.max(0,-(-k*h+m)),e=0<=r?(d=0,e=Math.min(Math.max(-h,-l),h),k=e*(e+2*l)+n):(d=Math.max(0,-(k*h+m)),e=0f)return null;f=Math.sqrt(f-e);e=d-f;d+=f;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),intersectsSphere:function(a){return this.distanceToPoint(a.center)<= +a.radius},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0===b)return 0===a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},intersectsPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},intersectBox:function(a,b){var c,d,e,f,g;d=1/this.direction.x;f=1/this.direction.y;g=1/this.direction.z; +var h=this.origin;0<=d?(c=(a.min.x-h.x)*d,d*=a.max.x-h.x):(c=(a.max.x-h.x)*d,d*=a.min.x-h.x);0<=f?(e=(a.min.y-h.y)*f,f*=a.max.y-h.y):(e=(a.max.y-h.y)*f,f*=a.min.y-h.y);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(f<=g?(e=(a.min.z-h.z)*g,g*=a.max.z-h.z):(e=(a.max.z-h.z)*g,g*=a.min.z-h.z);if(c>g||e>d)return null;if(e>c||c!==c)c=e;if(gd?null:this.at(0<=c?c:d,b)},intersectsBox:function(){var a=new q;return function(b){return null!==this.intersectBox(b,a)}}(),intersectTriangle:function(){var a= +new q,b=new q,c=new q,d=new q;return function(e,f,g,h,k){b.subVectors(f,e);c.subVectors(g,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0f)h=-1,f=-f;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;g=h*this.direction.dot(b.cross(a));if(0>g||e+g>f)return null;e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a); +this.direction.sub(this.origin);this.direction.normalize();return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}};bb.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");bb.DefaultOrder="XYZ";bb.prototype={constructor:bb,isEuler:!0,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get order(){return this._order}, +set order(a){this._order=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=T.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],m=e[9],l=e[2],n=e[6],e=e[10];b=b|| +this._order;"XYZ"===b?(this._y=Math.asin(d(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-m,e),this._z=Math.atan2(-f,a)):(this._x=Math.atan2(n,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(m,-1,1)),.99999>Math.abs(m)?(this._y=Math.atan2(g,e),this._z=Math.atan2(h,k)):(this._y=Math.atan2(-l,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(n,-1,1)),.99999>Math.abs(n)?(this._y=Math.atan2(-l,e),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(l,-1,1)),.99999> +Math.abs(l)?(this._x=Math.atan2(n,e),this._z=Math.atan2(h,a)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-m,k),this._y=Math.atan2(-l,a)):(this._x=0,this._y=Math.atan2(g,e))):"XZY"===b?(this._z=Math.asin(-d(f,-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(n,k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-m,e),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback(); +return this},setFromQuaternion:function(){var a;return function(b,c,d){void 0===a&&(a=new J);a.makeRotationFromQuaternion(b);return this.setFromRotationMatrix(a,c,d)}}(),setFromVector3:function(a,b){return this.set(a.x,a.y,a.z,b||this._order)},reorder:function(){var a=new ba;return function(b){a.setFromEuler(this);return this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1]; +this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._order;return a},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new q(this._x,this._y,this._z)},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){}};Yc.prototype={constructor:Yc,set:function(a){this.mask=1<<<<<=b.x&&0<=b.y&&1>=b.x+b.y}}();wa.prototype={constructor:wa,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c); +return this},area:function(){var a=new q,b=new q;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return.5*a.cross(b).length()}}(),midpoint:function(a){return(a||new q).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return wa.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new va).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return wa.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return wa.containsPoint(a, +this.a,this.b,this.c)},closestPointToPoint:function(){var a,b,c,d;return function(e,f){void 0===a&&(a=new va,b=[new gb,new gb,new gb],c=new q,d=new q);var g=f||new q,h=Infinity;a.setFromCoplanarPoints(this.a,this.b,this.c);a.projectPoint(e,c);if(!0===this.containsPoint(c))g.copy(c);else{b[0].set(this.a,this.b);b[1].set(this.b,this.c);b[2].set(this.c,this.a);for(var k=0;kd;d++)if(e[d]===e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;c<<b.far?null:{distance:c,point:u.clone(),object:a}}function c(c,d,e,f,m,l,n,w){g.fromArray(f,3*l);h.fromArray(f,3*n);k.fromArray(f, +3*w);if(c=b(c,d,e,g,h,k,D))m&&(p.fromArray(m,2*l),r.fromArray(m,2*n),x.fromArray(m,2*w),c.uv=a(D,g,h,k,p,r,x)),c.face=new ea(l,n,w,wa.normal(g,h,k)),c.faceIndex=l;return c}var d=new J,e=new ab,f=new Ca,g=new q,h=new q,k=new q,m=new q,l=new q,n=new q,p=new B,r=new B,x=new B,t=new q,D=new q,u=new q;return function(q,t){var u=this.geometry,E=this.material,H=this.matrixWorld;if(void 0!==E&&(null===u.boundingSphere&&u.computeBoundingSphere(),f.copy(u.boundingSphere),f.applyMatrix4(H),!1!==q.ray.intersectsSphere(f)&& +(d.getInverse(H),e.copy(q.ray).applyMatrix4(d),null===u.boundingBox||!1!==e.intersectsBox(u.boundingBox)))){var F,M;if(u&&u.isBufferGeometry){var B,K,E=u.index,H=u.attributes,u=H.position.array;void 0!==H.uv&&(F=H.uv.array);if(null!==E)for(var H=E.array,z=0,C=H.length;zthis.scale.x*this.scale.y/4||c.push({distance:Math.sqrt(d),point:this.position, +face:null,object:this})}}(),clone:function(){return(new this.constructor(this.material)).copy(this)}});rc.prototype=Object.assign(Object.create(z.prototype),{constructor:rc,copy:function(a){z.prototype.copy.call(this,a,!1);a=a.levels;for(var b=0,c=a.length;b=d[e].distance)d[e- +1].object.visible=!1,d[e].object.visible=!0;else break;for(;ef||(l.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(l),td.far||e.push({distance:t,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else for(g=0,x=r.length/3-1;gf||(l.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(l),td.far||e.push({distance:t,point:h.clone().applyMatrix4(this.matrixWorld), +index:g,face:null,faceIndex:null,object:this}))}else if(g&&g.isGeometry)for(k=g.vertices,m=k.length,g=0;gf||(l.applyMatrix4(this.matrixWorld),t=d.ray.origin.distanceTo(l),td.far||e.push({distance:t,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}}}(),clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});la.prototype=Object.assign(Object.create(Ta.prototype), +{constructor:la,isLineSegments:!0});xa.prototype=Object.create(U.prototype);xa.prototype.constructor=xa;xa.prototype.isPointsMaterial=!0;xa.prototype.copy=function(a){U.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.size=a.size;this.sizeAttenuation=a.sizeAttenuation;return this};Kb.prototype=Object.assign(Object.create(z.prototype),{constructor:Kb,isPoints:!0,raycast:function(){var a=new J,b=new ab,c=new Ca;return function(d,e){function f(a,c){var f=b.distanceSqToPoint(a); +if(fd.far||e.push({distance:m,distanceToRay:Math.sqrt(f),point:h.clone(),index:c,face:null,object:g})}}var g=this,h=this.geometry,k=this.matrixWorld,m=d.params.Points.threshold;null===h.boundingSphere&&h.computeBoundingSphere();c.copy(h.boundingSphere);c.applyMatrix4(k);if(!1!==d.ray.intersectsSphere(c)){a.getInverse(k);b.copy(d.ray).applyMatrix4(a);var m=m/((this.scale.x+this.scale.y+this.scale.z)/3), +l=m*m,m=new q;if(h&&h.isBufferGeometry){var n=h.index,h=h.attributes.position.array;if(null!==n)for(var p=n.array,n=0,r=p.length;nc)return null;var d=[],e=[],f=[],g,h,k;if(0=m--){console.warn("THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()");break}g=h;c<=g&&(g=0);h=g+1;c<=h&&(h=0);k=h+1;c<=k&&(k=0);var l;a:{var n, +p,r,q,t,D,u,v;n=a[e[g]].x;p=a[e[g]].y;r=a[e[h]].x;q=a[e[h]].y;t=a[e[k]].x;D=a[e[k]].y;if(0>=(r-n)*(D-p)-(q-p)*(t-n))l=!1;else{var I,y,E,H,F,M,B,z,C,G;I=t-r;y=D-q;E=n-t;H=p-D;F=r-n;M=q-p;for(l=0;l=-Number.EPSILON&&z>=-Number.EPSILON&&B>=-Number.EPSILON)){l=!1;break a}l=!0}}if(l){d.push([a[e[g]],a[e[h]],a[e[k]]]);f.push([e[g],e[h],e[k]]);g=h;for(k=h+1;kNumber.EPSILON){if(0q||q>p)return[];k=m*l-k*n;if(0>k||k>p)return[]}else{if(0< +k||k<=p?a<=c?[b,h]:[b,m]:k>c?[]:k===c?f?[]:[g]:a<=c?[g,h]:[g,m]}function f(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return Math.abs(a)>Number.EPSILON?(b=g*c-d*b,0<=e&&0<=b:0<=e||0<=b):0e&&(e=d);var g=a+1;g>d&&(g=0);d=f(h[a],h[e],h[g],k[b]);if(!d)return!1;d=k.length-1;e=b-1;0>e&&(e=d);g=b+1;g>d&&(g=0);return(d=f(k[b],k[e],k[g],h[a]))?!0:!1}function d(a,b){var c,f;for(c=0;cN){console.log("Infinite Loop! Holes left:"+m.length+", Probably Hole outside Shape!");break}for(n=z;n<=l)break;B[w]=!0}if(0<=l)break}}return h}(a,b);var p=ra.triangulate(g,!1);g=0;for(h=p.length;gk;k++)l=m[k].x+":"+m[k].y,l=n[l],void 0!==l&&(m[k]=l);return p.concat()},isClockWise:function(a){return 0>ra.area(a)},b2:function(){return function(a,b,c,d){var e=1-a;return e*e*b+2*(1-a)*a*c+a*a*d}}(),b3:function(){return function(a,b,c,d,e){var f=1-a,g=1-a;return f*f*f*b+3*g*g*a*c+3*(1-a)*a*a*d+a*a*a*e}}()};za.prototype=Object.create(Q.prototype);za.prototype.constructor= +za;za.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;dNumber.EPSILON){var k=Math.sqrt(h),m=Math.sqrt(d*d+g*g),h=b.x-f/k;b=b.y+e/k;g=((c.x-g/m-h)*g-(c.y+d/m-b)*d)/(e*g-f*d);d=h+e*g-a.x;e=b+f*g-a.y;f= +d*d+e*e;if(2>=f)return new B(d,e);f=Math.sqrt(f/2)}else a=!1,e>Number.EPSILON?d>Number.EPSILON&&(a=!0):e<-Number.EPSILON?d<-Number.EPSILON&&(a=!0):Math.sign(f)===Math.sign(g)&&(a=!0),a?(d=-f,f=Math.sqrt(h)):(d=e,e=f,f=Math.sqrt(h/2));return new B(d/f,e/f)}function e(a,b){var c,d;for(L=a.length;0<=--L;){c=L;d=L-1;0>d&&(d=a.length-1);var e,f=r+2*l;for(e=0;eMath.abs(b.y-c.y)?[new B(b.x,1-b.z),new B(c.x,1-c.z),new B(d.x,1-d.z),new B(e.x,1-e.z)]:[new B(b.y,1-b.z),new B(c.y,1-c.z),new B(d.y,1-d.z),new B(e.y, +1-e.z)]}};Dc.prototype=Object.create(za.prototype);Dc.prototype.constructor=Dc;mb.prototype=Object.create(G.prototype);mb.prototype.constructor=mb;Vb.prototype=Object.create(Q.prototype);Vb.prototype.constructor=Vb;Wb.prototype=Object.create(G.prototype);Wb.prototype.constructor=Wb;Ec.prototype=Object.create(Q.prototype);Ec.prototype.constructor=Ec;Fc.prototype=Object.create(Q.prototype);Fc.prototype.constructor=Fc;Xb.prototype=Object.create(G.prototype);Xb.prototype.constructor=Xb;Gc.prototype=Object.create(Q.prototype); +Gc.prototype.constructor=Gc;cb.prototype=Object.create(Q.prototype);cb.prototype.constructor=cb;cb.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;c=e)break a;else{f=b[1];a=e)break b}d=c;c=0}}for(;c>>1,ab;)--f;++f;if(0!==e||f!==d)e>=f&&(f=Math.max(f,1),e=f-1),d=this.getValueSize(),this.times=ma.arraySlice(c,e,f),this.values=ma.arraySlice(this.values,e*d,f*d);return this},validate:function(){var a=!0,b=this.getValueSize();0!==b-Math.floor(b)&&(console.error("invalid value size in track",this),a=!1);var c=this.times,b=this.values,d=c.length;0===d&&(console.error("track is empty", +this),a=!1);for(var e=null,f=0;f!==d;f++){var g=c[f];if("number"===typeof g&&isNaN(g)){console.error("time is not a valid number",this,f,g);a=!1;break}if(null!==e&&e>g){console.error("out of order keys",this,f,g,e);a=!1;break}e=g}if(void 0!==b&&ma.isTypedArray(b))for(f=0,c=b.length;f!==c;++f)if(d=b[f],isNaN(d)){console.error("value is not a valid number",this,f,d);a=!1;break}return a},optimize:function(){for(var a=this.times,b=this.values,c=this.getValueSize(),d=2302===this.getInterpolation(),e=1, +f=a.length-1,g=1;gk.opacity&&(k.transparent=!0);c.setTextures(h);return c.parse(k)}}()};wb.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=this.handlers,c=0,d=b.length;cg;g++)p=v[k++],u=D[2*p],p=D[2*p+1],u=new B(u,p),2!==g&&c.faceVertexUvs[d][h].push(u),0!==g&&c.faceVertexUvs[d][h+1].push(u);n&&(n=3*v[k++],r.normal.set(z[n++],z[n++],z[n]),t.normal.copy(r.normal));if(x)for(d=0;4>d;d++)n=3*v[k++],x=new q(z[n++],z[n++],z[n]),2!==d&&r.vertexNormals.push(x),0!==d&&t.vertexNormals.push(x);w&&(w=v[k++],w=y[w],r.color.setHex(w),t.color.setHex(w));if(b)for(d= +0;4>d;d++)w=v[k++],w=y[w],2!==d&&r.vertexColors.push(new O(w)),0!==d&&t.vertexColors.push(new O(w));c.faces.push(r);c.faces.push(t)}else{r=new ea;r.a=v[k++];r.b=v[k++];r.c=v[k++];h&&(h=v[k++],r.materialIndex=h);h=c.faces.length;if(d)for(d=0;dg;g++)p=v[k++],u=D[2*p],p=D[2*p+1],u=new B(u,p),c.faceVertexUvs[d][h].push(u);n&&(n=3*v[k++],r.normal.set(z[n++],z[n++],z[n]));if(x)for(d=0;3>d;d++)n=3*v[k++],x=new q(z[n++],z[n++],z[n]),r.vertexNormals.push(x); +w&&(w=v[k++],r.color.setHex(y[w]));if(b)for(d=0;3>d;d++)w=v[k++],r.vertexColors.push(new O(y[w]));c.faces.push(r)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;d< +b?a.skinIndices[d+2]:0,3k)g=d+1;else if(0b&&(b=0);1Number.EPSILON&&(g.normalize(),c=Math.acos(T.clamp(d[k-1].dot(d[k]),-1,1)),e[k].applyMatrix4(h.makeRotationAxis(g,c))),f[k].crossVectors(d[k],e[k]);if(!0===b)for(c=Math.acos(T.clamp(e[0].dot(e[a]),-1,1)),c/=a,0<=a;k++)e[k].applyMatrix4(h.makeRotationAxis(d[k],c*k)), +f[k].crossVectors(d[k],e[k]);return{tangents:d,normals:e,binormals:f}}};ia.create=function(a,b){a.prototype=Object.create(ia.prototype);a.prototype.constructor=a;a.prototype.getPoint=b;return a};Sa.prototype=Object.create(ia.prototype);Sa.prototype.constructor=Sa;Sa.prototype.isLineCurve=!0;Sa.prototype.getPoint=function(a){if(1===a)return this.v2.clone();var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};Sa.prototype.getPointAt=function(a){return this.getPoint(a)};Sa.prototype.getTangent= +function(a){return this.v2.clone().sub(this.v1).normalize()};Oc.prototype=Object.assign(Object.create(ia.prototype),{constructor:Oc,add:function(a){this.curves.push(a)},closePath:function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new Sa(b,a))},getPoint:function(a){var b=a*this.getLength(),c=this.getCurveLengths();for(a=0;a=b)return b=c[a]-b,a=this.curves[a],c=a.getLength(),a.getPointAt(0===c?0:1-b/c);a++}return null}, +getLength:function(){var a=this.getCurveLengths();return a[a.length-1]},updateArcLengths:function(){this.needsUpdate=!0;this.cacheLengths=null;this.getLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var a=[],b=0,c=0,d=this.curves.length;cc;)c+=b;for(;c>b;)c-=b;cb.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=Xc.interpolate;return new B(c(d.x,e.x,f.x,b.x,a),c(d.y,e.y,f.y,b.y,a))};yb.prototype=Object.create(ia.prototype); +yb.prototype.constructor=yb;yb.prototype.getPoint=function(a){var b=ra.b3;return new B(b(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),b(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y))};yb.prototype.getTangent=function(a){var b=Xc.tangentCubicBezier;return(new B(b(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),b(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y))).normalize()};zb.prototype=Object.create(ia.prototype);zb.prototype.constructor=zb;zb.prototype.getPoint=function(a){var b=ra.b2;return new B(b(a,this.v0.x, +this.v1.x,this.v2.x),b(a,this.v0.y,this.v1.y,this.v2.y))};zb.prototype.getTangent=function(a){var b=Xc.tangentQuadraticBezier;return(new B(b(a,this.v0.x,this.v1.x,this.v2.x),b(a,this.v0.y,this.v1.y,this.v2.y))).normalize()};var de=Object.assign(Object.create(Oc.prototype),{fromPoints:function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;bNumber.EPSILON){if(0>l&&(g=b[f],k=-k,h=b[e],l=-l),!(a.yh.y))if(a.y=== +g.y){if(a.x===g.x)return!0}else{e=l*(a.x-g.x)-k*(a.y-g.y);if(0===e)return!0;0>e||(d=!d)}}else if(a.y===g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<=h.x))return!0}return d}var e=ra.isClockWise,f=this.subPaths;if(0===f.length)return[];if(!0===b)return c(f);var g,h,k,l=[];if(1===f.length)return h=f[0],k=new Ab,k.curves=h.curves,l.push(k),l;var q=!e(f[0].getPoints()),q=a?!q:q;k=[];var n=[],p=[],r=0,x;n[r]=void 0;p[r]=[];for(var t=0,D=f.length;td&&this._mixBufferRegion(c,a,3*b,1-d,b);for(var d=b,f=b+b;d!==f;++d)if(c[d]!==c[d+b]){e.setValue(c,a);break}},saveOriginalState:function(){var a=this.buffer,b=this.valueSize,c=3*b;this.binding.getValue(a,c);for(var d= +b;d!==c;++d)a[d]=a[c+d%b];this.cumulativeWeight=0},restoreOriginalState:function(){this.binding.setValue(this.buffer,3*this.valueSize)},_select:function(a,b,c,d,e){if(.5<=d)for(d=0;d!==e;++d)a[b+d]=a[c+d]},_slerp:function(a,b,c,d,e){ba.slerpFlat(a,b,a,b,a,c,d)},_lerp:function(a,b,c,d,e){for(var f=1-d,g=0;g!==e;++g){var h=b+g;a[h]=a[h]*f+a[c+g]*d}}};fa.prototype={constructor:fa,getValue:function(a,b){this.bind();this.getValue(a,b)},setValue:function(a,b){this.bind();this.setValue(a,b)},bind:function(){var a= +this.node,b=this.parsedPath,c=b.objectName,d=b.propertyName,e=b.propertyIndex;a||(this.node=a=fa.findNode(this.rootNode,b.nodeName)||this.rootNode);this.getValue=this._getValue_unavailable;this.setValue=this._setValue_unavailable;if(a){if(c){var f=b.objectIndex;switch(c){case "materials":if(!a.material){console.error(" can not bind to material as node does not have a material",this);return}if(!a.material.materials){console.error(" can not bind to material.materials as node.material does not have a materials array", +this);return}a=a.material.materials;break;case "bones":if(!a.skeleton){console.error(" can not bind to bones as node does not have a skeleton",this);return}a=a.skeleton.bones;for(c=0;c=c){var n=c++,p=b[n];d[p.uuid]=q;b[q]=p;d[l]=n;b[n]=k;k=0;for(l=f;k!==l;++k){var p=e[k],r=p[q];p[q]=p[n];p[n]=r}}}this.nCachedObjects_=c},uncache:function(a){for(var b=this._objects,c=b.length,d=this.nCachedObjects_,e=this._indicesByUUID,f=this._bindings,g=f.length,h=0,k=arguments.length;h!==k;++h){var l=arguments[h].uuid,q=e[l];if(void 0!== +q)if(delete e[l],qb||0===c)return;this._startTime=null;b*=c}b*=this._updateTimeScale(a);c=this._updateTime(b);a=this._updateWeight(a);if(0c.parameterPositions[1]&& +(this.stopFading(),0===d&&(this.enabled=!1))}}return this._effectiveWeight=b},_updateTimeScale:function(a){var b=0;if(!this.paused){var b=this.timeScale,c=this._timeScaleInterpolant;if(null!==c){var d=c.evaluate(a)[0],b=b*d;a>c.parameterPositions[1]&&(this.stopWarping(),0===b?this.paused=!0:this.timeScale=b)}}return this._effectiveTimeScale=b},_updateTime:function(a){var b=this.time+a;if(0===a)return b;var c=this._clip.duration,d=this.loop,e=this._loopCount;if(2200===d)a:{if(-1===e&&(this.loopCount= +0,this._setEndings(!0,!0,!1)),b>=c)b=c;else if(0>b)b=0;else break a;this.clampWhenFinished?this.paused=!0:this.enabled=!1;this._mixer.dispatchEvent({type:"finished",action:this,direction:0>a?-1:1})}else{d=2202===d;-1===e&&(0<=a?(e=0,this._setEndings(!0,0===this.repetitions,d)):this._setEndings(0===this.repetitions,!0,d));if(b>=c||0>b){var f=Math.floor(b/c),b=b-c*f,e=e+Math.abs(f),g=this.repetitions-e;0>g?(this.clampWhenFinished?this.paused=!0:this.enabled=!1,b=0a,this._setEndings(a,!a,d)):this._setEndings(!1,!1,d),this._loopCount=e,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:f}))}if(d&&1===(e&1))return this.time=b,c-b}return this.time=b},_setEndings:function(a,b,c){var d=this._interpolantSettings;c?(d.endingStart=2401,d.endingEnd=2401):(d.endingStart=a?this.zeroSlopeAtStart?2401:2400:2402,d.endingEnd=b?this.zeroSlopeAtEnd?2401:2400:2402)},_scheduleFading:function(a,b,c){var d=this._mixer,e=d.time, +f=this._weightInterpolant;null===f&&(this._weightInterpolant=f=d._lendControlInterpolant());d=f.parameterPositions;f=f.sampleValues;d[0]=e;f[0]=b;d[1]=e+a;f[1]=c;return this}};Object.assign(Ud.prototype,sa.prototype,{clipAction:function(a,b){var c=b||this._root,d=c.uuid,e="string"===typeof a?Ha.findByName(c,a):a,c=null!==e?e.uuid:a,f=this._actionsByClip[c],g=null;if(void 0!==f){g=f.actionByRoot[d];if(void 0!==g)return g;g=f.knownActions[0];null===e&&(e=g._clip)}if(null===e)return null;e=new Td(this, +e,b);this._bindAction(e,g);this._addInactiveAction(e,c,d);return e},existingAction:function(a,b){var c=b||this._root,d=c.uuid,c="string"===typeof a?Ha.findByName(c,a):a,c=this._actionsByClip[c?c.uuid:a];return void 0!==c?c.actionByRoot[d]||null:null},stopAllAction:function(){for(var a=this._actions,b=this._nActiveActions,c=this._bindings,d=this._nActiveBindings,e=this._nActiveBindings=this._nActiveActions=0;e!==b;++e)a[e].reset();for(e=0;e!==d;++e)c[e].useCount=0;return this},update:function(a){a*= +this.timeScale;for(var b=this._actions,c=this._nActiveActions,d=this.time+=a,e=Math.sign(a),f=this._accuIndex^=1,g=0;g!==c;++g){var h=b[g];h.enabled&&h._update(d,a,e,f)}a=this._bindings;b=this._nActiveBindings;for(g=0;g!==b;++g)a[g].apply(f);return this},getRoot:function(){return this._root},uncacheClip:function(a){var b=this._actions;a=a.uuid;var c=this._actionsByClip,d=c[a];if(void 0!==d){for(var d=d.knownActions,e=0,f=d.length;e!==f;++e){var g=d[e];this._deactivateAction(g);var h=g._cacheIndex, +k=b[b.length-1];g._cacheIndex=null;g._byClipCacheIndex=null;k._cacheIndex=h;b[h]=k;b.pop();this._removeInactiveBindingsForAction(g)}delete c[a]}},uncacheRoot:function(a){a=a.uuid;var b=this._actionsByClip,c;for(c in b){var d=b[c].actionByRoot[a];void 0!==d&&(this._deactivateAction(d),this._removeInactiveAction(d))}c=this._bindingsByRootAndName[a];if(void 0!==c)for(var e in c)a=c[e],a.restoreOriginalState(),this._removeInactiveBinding(a)},uncacheAction:function(a,b){var c=this.existingAction(a,b); +null!==c&&(this._deactivateAction(c),this._removeInactiveAction(c))}});Object.assign(Ud.prototype,{_bindAction:function(a,b){var c=a._localRoot||this._root,d=a._clip.tracks,e=d.length,f=a._propertyBindings,g=a._interpolants,h=c.uuid,k=this._bindingsByRootAndName,l=k[h];void 0===l&&(l={},k[h]=l);for(k=0;k!==e;++k){var q=d[k],n=q.name,p=l[n];if(void 0===p){p=f[k];if(void 0!==p){null===p._cacheIndex&&(++p.referenceCount,this._addInactiveBinding(p,h,n));continue}p=new wd(fa.create(c,n,b&&b._propertyBindings[k].binding.parsedPath), +q.ValueTypeName,q.getValueSize());++p.referenceCount;this._addInactiveBinding(p,h,n)}f[k]=p;g[k].resultBuffer=p.buffer}},_activateAction:function(a){if(!this._isActiveAction(a)){if(null===a._cacheIndex){var b=(a._localRoot||this._root).uuid,c=a._clip.uuid,d=this._actionsByClip[c];this._bindAction(a,d&&d.knownActions[0]);this._addInactiveAction(a,c,b)}b=a._propertyBindings;c=0;for(d=b.length;c!==d;++c){var e=b[c];0===e.useCount++&&(this._lendBinding(e),e.saveOriginalState())}this._lendAction(a)}}, +_deactivateAction:function(a){if(this._isActiveAction(a)){for(var b=a._propertyBindings,c=0,d=b.length;c!==d;++c){var e=b[c];0===--e.useCount&&(e.restoreOriginalState(),this._takeBackBinding(e))}this._takeBackAction(a)}},_initMemoryManager:function(){this._actions=[];this._nActiveActions=0;this._actionsByClip={};this._bindings=[];this._nActiveBindings=0;this._bindingsByRootAndName={};this._controlInterpolants=[];this._nActiveControlInterpolants=0;var a=this;this.stats={actions:{get total(){return a._actions.length}, +get inUse(){return a._nActiveActions}},bindings:{get total(){return a._bindings.length},get inUse(){return a._nActiveBindings}},controlInterpolants:{get total(){return a._controlInterpolants.length},get inUse(){return a._nActiveControlInterpolants}}}},_isActiveAction:function(a){a=a._cacheIndex;return null!==a&&ah.end&&(h.end=f);c||(c=k)}}for(k in d)h=d[k],this.createAnimation(k,h.start,h.end,a);this.firstAnimation=c};na.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};na.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};na.prototype.setAnimationFPS=function(a,b){var c= +this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)};na.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};na.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};na.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};na.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b};na.prototype.getAnimationDuration= +function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};na.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("THREE.MorphBlendMesh: animation["+a+"] undefined in .playAnimation()")};na.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1};na.prototype.update=function(a){for(var b=0,c=this.animationsList.length;b +d.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.start+T.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight;f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);d.currentFrame!== +d.lastFrame?(this.morphTargetInfluences[d.currentFrame]=e*g,this.morphTargetInfluences[d.lastFrame]=(1-e)*g):this.morphTargetInfluences[d.currentFrame]=g}}};Qc.prototype=Object.create(z.prototype);Qc.prototype.constructor=Qc;Qc.prototype.isImmediateRenderObject=!0;Rc.prototype=Object.create(la.prototype);Rc.prototype.constructor=Rc;Rc.prototype.update=function(){var a=new q,b=new q,c=new Ia;return function(){var d=["a","b","c"];this.object.updateMatrixWorld(!0);c.getNormalMatrix(this.object.matrixWorld); +var e=this.object.matrixWorld,f=this.geometry.attributes.position,g=this.object.geometry;if(g&&g.isGeometry)for(var h=g.vertices,k=g.faces,l=g=0,q=k.length;lc.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();Cb.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,Math.max(0,a-b),1);this.line.updateMatrix(); +this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};Cb.prototype.setColor=function(a){this.line.material.color.copy(a);this.cone.material.color.copy(a)};xd.prototype=Object.create(la.prototype);xd.prototype.constructor=xd;var $d=function(){function a(){}var b=new q,c=new a,d=new a,e=new a;a.prototype.init=function(a,b,c,d){this.c0=a;this.c1=c;this.c2=-3*a+3*b-2*c-d;this.c3=2*a-2*b+c+d};a.prototype.initNonuniformCatmullRom=function(a,b,c,d,e,l,n){this.init(b,c,((b-a)/e-(c-a)/ +(e+l)+(c-b)/l)*l,((c-b)/l-(d-b)/(l+n)+(d-c)/n)*l)};a.prototype.initCatmullRom=function(a,b,c,d,e){this.init(b,c,e*(c-a),e*(d-b))};a.prototype.calc=function(a){var b=a*a;return this.c0+this.c1*a+this.c2*b+this.c3*b*a};return ia.create(function(a){this.points=a||[];this.closed=!1},function(a){var g=this.points,h,k;k=g.length;2>k&&console.log("duh, you need at least 2 points");a*=k-(this.closed?0:1);h=Math.floor(a);a-=h;this.closed?h+=0h&&(h=1);1E-4>k&&(k=h);1E-4>p&&(p=h);c.initNonuniformCatmullRom(l.x,w.x,n.x,g.x,k, +h,p);d.initNonuniformCatmullRom(l.y,w.y,n.y,g.y,k,h,p);e.initNonuniformCatmullRom(l.z,w.z,n.z,g.z,k,h,p)}else"catmullrom"===this.type&&(k=void 0!==this.tension?this.tension:.5,c.initCatmullRom(l.x,w.x,n.x,g.x,k),d.initCatmullRom(l.y,w.y,n.y,g.y,k),e.initCatmullRom(l.z,w.z,n.z,g.z,k));return new q(c.calc(a),d.calc(a),e.calc(a))})}();Ee.prototype=Object.create($d.prototype);var Ef=ia.create(function(a){console.warn("THREE.SplineCurve3 will be deprecated. Please use THREE.CatmullRomCurve3");this.points= +void 0===a?[]:a},function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=Xc.interpolate;return new q(c(d.x,e.x,f.x,b.x,a),c(d.y,e.y,f.y,b.y,a),c(d.z,e.z,f.z,b.z,a))}),Ff=ia.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b=ra.b3;return new q(b(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),b(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),b(a,this.v0.z,this.v1.z,this.v2.z, +this.v3.z))}),Gf=ia.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b=ra.b2;return new q(b(a,this.v0.x,this.v1.x,this.v2.x),b(a,this.v0.y,this.v1.y,this.v2.y),b(a,this.v0.z,this.v1.z,this.v2.z))}),Hf=ia.create(function(a,b){this.v1=a;this.v2=b},function(a){if(1===a)return this.v2.clone();var b=new q;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b});yd.prototype=Object.create(Va.prototype);yd.prototype.constructor=yd;Object.assign(mc.prototype,{center:function(a){console.warn("THREE.Box2: .center() has been renamed to .getCenter()."); +return this.getCenter(a)},empty:function(){console.warn("THREE.Box2: .empty() has been renamed to .isEmpty().");return this.isEmpty()},isIntersectionBox:function(a){console.warn("THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().");return this.intersectsBox(a)},size:function(a){console.warn("THREE.Box2: .size() has been renamed to .getSize().");return this.getSize(a)}});Object.assign(Ba.prototype,{center:function(a){console.warn("THREE.Box3: .center() has been renamed to .getCenter()."); +return this.getCenter(a)},empty:function(){console.warn("THREE.Box3: .empty() has been renamed to .isEmpty().");return this.isEmpty()},isIntersectionBox:function(a){console.warn("THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().");return this.intersectsBox(a)},isIntersectionSphere:function(a){console.warn("THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().");return this.intersectsSphere(a)},size:function(a){console.warn("THREE.Box3: .size() has been renamed to .getSize()."); +return this.getSize(a)}});Object.assign(gb.prototype,{center:function(a){console.warn("THREE.Line3: .center() has been renamed to .getCenter().");return this.getCenter(a)}});Object.assign(Ia.prototype,{multiplyVector3:function(a){console.warn("THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)},multiplyVector3Array:function(a){console.warn("THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead."); +return this.applyToVector3Array(a)}});Object.assign(J.prototype,{extractPosition:function(a){console.warn("THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().");return this.copyPosition(a)},setRotationFromQuaternion:function(a){console.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().");return this.makeRotationFromQuaternion(a)},multiplyVector3:function(a){console.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead."); +return a.applyProjection(this)},multiplyVector4:function(a){console.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector3Array:function(a){console.warn("THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.");return this.applyToVector3Array(a)},rotateAxis:function(a){console.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead."); +a.transformDirection(this)},crossVector:function(a){console.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},translate:function(a){console.error("THREE.Matrix4: .translate() has been removed.")},rotateX:function(a){console.error("THREE.Matrix4: .rotateX() has been removed.")},rotateY:function(a){console.error("THREE.Matrix4: .rotateY() has been removed.")},rotateZ:function(a){console.error("THREE.Matrix4: .rotateZ() has been removed.")}, +rotateByAxis:function(a,b){console.error("THREE.Matrix4: .rotateByAxis() has been removed.")}});Object.assign(va.prototype,{isIntersectionLine:function(a){console.warn("THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().");return this.intersectsLine(a)}});Object.assign(ba.prototype,{multiplyVector3:function(a){console.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.");return a.applyQuaternion(this)}});Object.assign(ab.prototype, +{isIntersectionBox:function(a){console.warn("THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().");return this.intersectsBox(a)},isIntersectionPlane:function(a){console.warn("THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().");return this.intersectsPlane(a)},isIntersectionSphere:function(a){console.warn("THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().");return this.intersectsSphere(a)}});Object.assign(Ab.prototype,{extrude:function(a){console.warn("THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead."); +return new za(this,a)},makeGeometry:function(a){console.warn("THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.");return new cb(this,a)}});Object.assign(q.prototype,{setEulerFromRotationMatrix:function(){console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")},setEulerFromQuaternion:function(){console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")}, +getPositionFromMatrix:function(a){console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().");return this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(b, +a)}});Object.assign(z.prototype,{getChildByName:function(a){console.warn("THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().");return this.getObjectByName(a)},renderDepth:function(a){console.warn("THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.")},translate:function(a,b){console.warn("THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.");return this.translateOnAxis(b,a)}});Object.defineProperties(z.prototype, +{eulerOrder:{get:function(){console.warn("THREE.Object3D: .eulerOrder is now .rotation.order.");return this.rotation.order},set:function(a){console.warn("THREE.Object3D: .eulerOrder is now .rotation.order.");this.rotation.order=a}},useQuaternion:{get:function(){console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")},set:function(a){console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")}}}); +Object.defineProperties(rc.prototype,{objects:{get:function(){console.warn("THREE.LOD: .objects has been renamed to .levels.");return this.levels}}});Ea.prototype.setLens=function(a,b){console.warn("THREE.PerspectiveCamera.setLens is deprecated. Use .setFocalLength and .filmGauge for a photographic setup.");void 0!==b&&(this.filmGauge=b);this.setFocalLength(a)};Object.defineProperties(pa.prototype,{onlyShadow:{set:function(a){console.warn("THREE.Light: .onlyShadow has been removed.")}},shadowCameraFov:{set:function(a){console.warn("THREE.Light: .shadowCameraFov is now .shadow.camera.fov."); +this.shadow.camera.fov=a}},shadowCameraLeft:{set:function(a){console.warn("THREE.Light: .shadowCameraLeft is now .shadow.camera.left.");this.shadow.camera.left=a}},shadowCameraRight:{set:function(a){console.warn("THREE.Light: .shadowCameraRight is now .shadow.camera.right.");this.shadow.camera.right=a}},shadowCameraTop:{set:function(a){console.warn("THREE.Light: .shadowCameraTop is now .shadow.camera.top.");this.shadow.camera.top=a}},shadowCameraBottom:{set:function(a){console.warn("THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom."); +this.shadow.camera.bottom=a}},shadowCameraNear:{set:function(a){console.warn("THREE.Light: .shadowCameraNear is now .shadow.camera.near.");this.shadow.camera.near=a}},shadowCameraFar:{set:function(a){console.warn("THREE.Light: .shadowCameraFar is now .shadow.camera.far.");this.shadow.camera.far=a}},shadowCameraVisible:{set:function(a){console.warn("THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.")}},shadowBias:{set:function(a){console.warn("THREE.Light: .shadowBias is now .shadow.bias."); +this.shadow.bias=a}},shadowDarkness:{set:function(a){console.warn("THREE.Light: .shadowDarkness has been removed.")}},shadowMapWidth:{set:function(a){console.warn("THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.");this.shadow.mapSize.width=a}},shadowMapHeight:{set:function(a){console.warn("THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.");this.shadow.mapSize.height=a}}});Object.defineProperties(C.prototype,{length:{get:function(){console.warn("THREE.BufferAttribute: .length has been deprecated. Please use .count."); +return this.array.length}}});Object.assign(G.prototype,{addIndex:function(a){console.warn("THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().");this.setIndex(a)},addDrawCall:function(a,b,c){void 0!==c&&console.warn("THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.");console.warn("THREE.BufferGeometry: .addDrawCall() is now .addGroup().");this.addGroup(a,b)},clearDrawCalls:function(){console.warn("THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups()."); +this.clearGroups()},computeTangents:function(){console.warn("THREE.BufferGeometry: .computeTangents() has been removed.")},computeOffsets:function(){console.warn("THREE.BufferGeometry: .computeOffsets() has been removed.")}});Object.defineProperties(G.prototype,{drawcalls:{get:function(){console.error("THREE.BufferGeometry: .drawcalls has been renamed to .groups.");return this.groups}},offsets:{get:function(){console.warn("THREE.BufferGeometry: .offsets has been renamed to .groups.");return this.groups}}}); +Object.defineProperties(U.prototype,{wrapAround:{get:function(){console.warn("THREE."+this.type+": .wrapAround has been removed.")},set:function(a){console.warn("THREE."+this.type+": .wrapAround has been removed.")}},wrapRGB:{get:function(){console.warn("THREE."+this.type+": .wrapRGB has been removed.");return new O}}});Object.defineProperties(db.prototype,{metal:{get:function(){console.warn("THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.");return!1},set:function(a){console.warn("THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead")}}}); +Object.defineProperties(Fa.prototype,{derivatives:{get:function(){console.warn("THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.");return this.extensions.derivatives},set:function(a){console.warn("THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.");this.extensions.derivatives=a}}});sa.prototype=Object.assign(Object.create({constructor:sa,apply:function(a){console.warn("THREE.EventDispatcher: .apply is deprecated, just inherit or Object.assign the prototype to mix-in."); +Object.assign(a,this)}}),sa.prototype);Object.defineProperties(Ae.prototype,{dynamic:{set:function(a){console.warn("THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.")}},onUpdate:{value:function(){console.warn("THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.");return this}}});Object.assign(Dd.prototype,{supportsFloatTextures:function(){console.warn("THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( 'OES_texture_float' )."); +return this.extensions.get("OES_texture_float")},supportsHalfFloatTextures:function(){console.warn("THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( 'OES_texture_half_float' ).");return this.extensions.get("OES_texture_half_float")},supportsStandardDerivatives:function(){console.warn("THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( 'OES_standard_derivatives' ).");return this.extensions.get("OES_standard_derivatives")},supportsCompressedTextureS3TC:function(){console.warn("THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( 'WEBGL_compressed_texture_s3tc' )."); +return this.extensions.get("WEBGL_compressed_texture_s3tc")},supportsCompressedTexturePVRTC:function(){console.warn("THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( 'WEBGL_compressed_texture_pvrtc' ).");return this.extensions.get("WEBGL_compressed_texture_pvrtc")},supportsBlendMinMax:function(){console.warn("THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( 'EXT_blend_minmax' ).");return this.extensions.get("EXT_blend_minmax")},supportsVertexTextures:function(){return this.capabilities.vertexTextures}, +supportsInstancedArrays:function(){console.warn("THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( 'ANGLE_instanced_arrays' ).");return this.extensions.get("ANGLE_instanced_arrays")},enableScissorTest:function(a){console.warn("THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().");this.setScissorTest(a)},initMaterial:function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")},addPrePlugin:function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")}, +addPostPlugin:function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")},updateShadowMap:function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")}});Object.defineProperties(Dd.prototype,{shadowMapEnabled:{get:function(){return this.shadowMap.enabled},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.");this.shadowMap.enabled=a}},shadowMapType:{get:function(){return this.shadowMap.type},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type."); +this.shadowMap.type=a}},shadowMapCullFace:{get:function(){return this.shadowMap.cullFace},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.");this.shadowMap.cullFace=a}}});Object.defineProperties(pe.prototype,{cullFace:{get:function(){return this.renderReverseSided?2:1},set:function(a){a=1!==a;console.warn("WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to "+a+".");this.renderReverseSided=a}}});Object.defineProperties(Db.prototype, +{wrapS:{get:function(){console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.");return this.texture.wrapS},set:function(a){console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.");this.texture.wrapS=a}},wrapT:{get:function(){console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.");return this.texture.wrapT},set:function(a){console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.");this.texture.wrapT=a}},magFilter:{get:function(){console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter."); +return this.texture.magFilter},set:function(a){console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.");this.texture.magFilter=a}},minFilter:{get:function(){console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.");return this.texture.minFilter},set:function(a){console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.");this.texture.minFilter=a}},anisotropy:{get:function(){console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy."); +return this.texture.anisotropy},set:function(a){console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.");this.texture.anisotropy=a}},offset:{get:function(){console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset.");return this.texture.offset},set:function(a){console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset.");this.texture.offset=a}},repeat:{get:function(){console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat.");return this.texture.repeat}, +set:function(a){console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat.");this.texture.repeat=a}},format:{get:function(){console.warn("THREE.WebGLRenderTarget: .format is now .texture.format.");return this.texture.format},set:function(a){console.warn("THREE.WebGLRenderTarget: .format is now .texture.format.");this.texture.format=a}},type:{get:function(){console.warn("THREE.WebGLRenderTarget: .type is now .texture.type.");return this.texture.type},set:function(a){console.warn("THREE.WebGLRenderTarget: .type is now .texture.type."); +this.texture.type=a}},generateMipmaps:{get:function(){console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.");return this.texture.generateMipmaps},set:function(a){console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.");this.texture.generateMipmaps=a}}});Object.assign(dc.prototype,{load:function(a){console.warn("THREE.Audio: .load has been deprecated. Please use THREE.AudioLoader.");var b=this;(new Od).load(a,function(a){b.setBuffer(a)}); +return this}});Object.assign(Rd.prototype,{getData:function(a){console.warn("THREE.AudioAnalyser: .getData() is now .getFrequencyData().");return this.getFrequencyData()}});l.WebGLRenderTargetCube=Eb;l.WebGLRenderTarget=Db;l.WebGLRenderer=Dd;l.ShaderLib=Gb;l.UniformsLib=W;l.UniformsUtils=La;l.ShaderChunk=X;l.FogExp2=Ib;l.Fog=Jb;l.Scene=jb;l.LensFlare=Ed;l.Sprite=qc;l.LOD=rc;l.SkinnedMesh=dd;l.Skeleton=bd;l.Bone=cd;l.Mesh=ya;l.LineSegments=la;l.Line=Ta;l.Points=Kb;l.Group=sc;l.VideoTexture=ed;l.DataTexture= +lb;l.CompressedTexture=Lb;l.CubeTexture=Xa;l.CanvasTexture=fd;l.DepthTexture=tc;l.TextureIdCount=function(){return ee++};l.Texture=da;l.MaterialIdCount=function(){return oe++};l.CompressedTextureLoader=we;l.BinaryTextureLoader=Gd;l.DataTextureLoader=Gd;l.CubeTextureLoader=Hd;l.TextureLoader=gd;l.ObjectLoader=xe;l.MaterialLoader=ud;l.BufferGeometryLoader=Id;l.DefaultLoadingManager=Ga;l.LoadingManager=Fd;l.JSONLoader=Jd;l.ImageLoader=Lc;l.FontLoader=ye;l.XHRLoader=Ja;l.Loader=wb;l.Cache=ce;l.AudioLoader= +Od;l.SpotLightShadow=id;l.SpotLight=jd;l.PointLight=kd;l.HemisphereLight=hd;l.DirectionalLightShadow=ld;l.DirectionalLight=md;l.AmbientLight=nd;l.LightShadow=tb;l.Light=pa;l.StereoCamera=ze;l.PerspectiveCamera=Ea;l.OrthographicCamera=Hb;l.CubeCamera=vd;l.Camera=Z;l.AudioListener=Pd;l.PositionalAudio=Qd;l.getAudioContext=Md;l.AudioAnalyser=Rd;l.Audio=dc;l.VectorKeyframeTrack=bc;l.StringKeyframeTrack=rd;l.QuaternionKeyframeTrack=Nc;l.NumberKeyframeTrack=cc;l.ColorKeyframeTrack=td;l.BooleanKeyframeTrack= +sd;l.PropertyMixer=wd;l.PropertyBinding=fa;l.KeyframeTrack=vb;l.AnimationUtils=ma;l.AnimationObjectGroup=Sd;l.AnimationMixer=Ud;l.AnimationClip=Ha;l.Uniform=Ae;l.InstancedBufferGeometry=Bb;l.BufferGeometry=G;l.GeometryIdCount=function(){return ad++};l.Geometry=Q;l.InterleavedBufferAttribute=Vd;l.InstancedInterleavedBuffer=fc;l.InterleavedBuffer=ec;l.InstancedBufferAttribute=gc;l.DynamicBufferAttribute=function(a,b){console.warn("THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead."); +return(new C(a,b)).setDynamic(!0)};l.Float64Attribute=function(a,b){return new C(new Float64Array(a),b)};l.Float32Attribute=ha;l.Uint32Attribute=$c;l.Int32Attribute=function(a,b){return new C(new Int32Array(a),b)};l.Uint16Attribute=Zc;l.Int16Attribute=function(a,b){return new C(new Int16Array(a),b)};l.Uint8ClampedAttribute=function(a,b){return new C(new Uint8ClampedArray(a),b)};l.Uint8Attribute=function(a,b){return new C(new Uint8Array(a),b)};l.Int8Attribute=function(a,b){return new C(new Int8Array(a), +b)};l.BufferAttribute=C;l.Face3=ea;l.Object3DIdCount=function(){return qe++};l.Object3D=z;l.Raycaster=Wd;l.Layers=Yc;l.EventDispatcher=sa;l.Clock=Yd;l.QuaternionLinearInterpolant=qd;l.LinearInterpolant=Mc;l.DiscreteInterpolant=pd;l.CubicInterpolant=od;l.Interpolant=qa;l.Triangle=wa;l.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,l,w,n,p;this.initFromArray=function(a){this.points=[]; +for(var b=0;bthis.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:f+2;l=this.points[c[0]];w=this.points[c[1]];n=this.points[c[2]];p=this.points[c[3]];h=g*g;k=g*h;d.x=b(l.x,w.x,n.x,p.x,g,h,k);d.y=b(l.y,w.y,n.y,p.y,g,h,k);d.z=b(l.z,w.z,n.z,p.z,g,h,k);return d};this.getControlPointsArray=function(){var a, +b,c=this.points.length,d=[];for(a=0;a< 0.0)', + ' distordNormal = distordNormal * -1.0;', + + // Compute diffuse and specular light (use normal and eye direction) + ' vec3 diffuseLight = vec3(0.0);', + ' vec3 specularLight = vec3(0.0);', + ' sunLight(distordNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight);', + + // Compute final 3d distortion, and project it to get the mirror sampling + ' float distance = length(worldToEye);', + ' vec2 distortion = distordCoord.xy * distortionScale * sqrt(distance) * 0.07;', + ' vec3 mirrorDistord = mirrorCoord.xyz + vec3(distortion.x, distortion.y, 1.0);', + ' vec3 reflectionSample = texture2DProj(mirrorSampler, mirrorDistord).xyz;', + + // Compute other parameters as the reflectance and the water appareance + ' float theta = max(dot(eyeDirection, distordNormal), 0.0);', + ' float reflectance = 0.3 + (1.0 - 0.3) * pow((1.0 - theta), 3.0);', + ' vec3 scatter = max(0.0, dot(distordNormal, eyeDirection)) * waterColor;', + + // Compute final pixel color + ' vec3 albedo = mix(sunColor * diffuseLight * 0.3 + scatter, (vec3(0.1) + reflectionSample * 0.9 + reflectionSample * specularLight), reflectance);', + + ' vec3 outgoingLight = albedo;', + THREE.ShaderChunk[ "fog_fragment" ], + + ' gl_FragColor = vec4( outgoingLight, alpha );', + '}' + ].join('\n') + +}; + +THREE.Water = function (renderer, camera, scene, options) { + + THREE.Object3D.call(this); + this.name = 'water_' + this.id; + + function optionalParameter (value, defaultValue) { + return value !== undefined ? value : defaultValue; + }; + + options = options || {}; + + this.matrixNeedsUpdate = true; + + var width = optionalParameter(options.textureWidth, 512); + var height = optionalParameter(options.textureHeight, 512); + this.clipBias = optionalParameter(options.clipBias, -0.0001); + this.alpha = optionalParameter(options.alpha, 1.0); + this.time = optionalParameter(options.time, 0.0); + this.normalSampler = optionalParameter(options.waterNormals, null); + this.sunDirection = optionalParameter(options.sunDirection, new THREE.Vector3(0.70707, 0.70707, 0.0)); + this.sunColor = new THREE.Color(optionalParameter(options.sunColor, 0xffffff)); + this.waterColor = new THREE.Color(optionalParameter(options.waterColor, 0x7F7F7F)); + this.eye = optionalParameter(options.eye, new THREE.Vector3(0, 0, 0)); + this.distortionScale = optionalParameter(options.distortionScale, 20.0); + this.noiseScale = optionalParameter(options.noiseScale, 1.0); + this.side = optionalParameter(options.side, THREE.FrontSide); + this.fog = optionalParameter(options.fog, false); + + this.renderer = renderer; + this.scene = scene; + this.mirrorPlane = new THREE.Plane(); + this.normal = new THREE.Vector3(0, 0, 1); + this.cameraWorldPosition = new THREE.Vector3(); + this.rotationMatrix = new THREE.Matrix4(); + this.lookAtPosition = new THREE.Vector3(0, 0, -1); + this.clipPlane = new THREE.Vector4(); + + if ( camera instanceof THREE.PerspectiveCamera ) { + this.camera = camera; + } + else { + this.camera = new THREE.PerspectiveCamera(); + console.log(this.name + ': camera is not a Perspective Camera!') + } + + this.textureMatrix = new THREE.Matrix4(); + + this.mirrorCamera = this.camera.clone(); + + this.texture = new THREE.WebGLRenderTarget(width, height); + this.tempTexture = new THREE.WebGLRenderTarget(width, height); + + var mirrorShader = THREE.ShaderLib["water"]; + var mirrorUniforms = THREE.UniformsUtils.clone(mirrorShader.uniforms); + + this.material = new THREE.ShaderMaterial({ + fragmentShader: mirrorShader.fragmentShader, + vertexShader: mirrorShader.vertexShader, + uniforms: mirrorUniforms, + transparent: true, + side: this.side, + fog: this.fog + }); + + this.mesh = new THREE.Object3D(); + + this.material.uniforms.mirrorSampler.value = this.texture; + this.material.uniforms.textureMatrix.value = this.textureMatrix; + this.material.uniforms.alpha.value = this.alpha; + this.material.uniforms.time.value = this.time; + this.material.uniforms.normalSampler.value = this.normalSampler; + this.material.uniforms.sunColor.value = this.sunColor; + this.material.uniforms.waterColor.value = this.waterColor; + this.material.uniforms.sunDirection.value = this.sunDirection; + this.material.uniforms.distortionScale.value = this.distortionScale; + this.material.uniforms.noiseScale.value = this.noiseScale; + + this.material.uniforms.eye.value = this.eye; + + if ( !THREE.Math.isPowerOfTwo(width) || !THREE.Math.isPowerOfTwo(height) ) { + this.texture.generateMipmaps = false; + this.tempTexture.generateMipmaps = false; + } +}; + +THREE.Water.prototype = Object.create(THREE.Object3D.prototype); + +THREE.Water.prototype.renderWithMirror = function (otherMirror) { + + // update the mirror matrix to mirror the current view + this.updateTextureMatrix(); + this.matrixNeedsUpdate = false; + + // set the camera of the other mirror so the mirrored view is the reference view + var tempCamera = otherMirror.camera; + otherMirror.camera = this.mirrorCamera; + + // render the other mirror in temp texture + otherMirror.render(true); + + // render the current mirror + this.render(); + this.matrixNeedsUpdate = true; + + // restore material and camera of other mirror + otherMirror.camera = tempCamera; + + // restore texture matrix of other mirror + otherMirror.updateTextureMatrix(); +}; + +THREE.Water.prototype.updateTextureMatrix = function () { + if ( this.parent !== undefined ) { + this.mesh = this.parent; + } + function sign(x) { return x ? x < 0 ? -1 : 1 : 0; } + + this.updateMatrixWorld(); + this.camera.updateMatrixWorld(); + + this.cameraWorldPosition.setFromMatrixPosition(this.camera.matrixWorld); + + this.rotationMatrix.extractRotation(this.matrixWorld); + + this.normal = (new THREE.Vector3(0, 0, 1)).applyEuler(this.mesh.rotation); + var cameraPosition = this.camera.position.clone().sub( this.mesh.position ); + if ( this.normal.dot(cameraPosition) < 0 ) { + var meshNormal = (new THREE.Vector3(0, 0, 1)).applyEuler(this.mesh.rotation); + this.normal.reflect(meshNormal); + } + + var view = this.mesh.position.clone().sub(this.cameraWorldPosition); + view.reflect(this.normal).negate(); + view.add(this.mesh.position); + + this.rotationMatrix.extractRotation(this.camera.matrixWorld); + + this.lookAtPosition.set(0, 0, -1); + this.lookAtPosition.applyMatrix4(this.rotationMatrix); + this.lookAtPosition.add(this.cameraWorldPosition); + + var target = this.mesh.position.clone().sub(this.lookAtPosition); + target.reflect(this.normal).negate(); + target.add(this.mesh.position); + + this.up.set(0, -1, 0); + this.up.applyMatrix4(this.rotationMatrix); + this.up.reflect(this.normal).negate(); + + this.mirrorCamera.position.copy(view); + this.mirrorCamera.up = this.up; + this.mirrorCamera.lookAt(target); + this.mirrorCamera.aspect = this.camera.aspect; + + this.mirrorCamera.updateProjectionMatrix(); + this.mirrorCamera.updateMatrixWorld(); + this.mirrorCamera.matrixWorldInverse.getInverse(this.mirrorCamera.matrixWorld); + + // Update the texture matrix + this.textureMatrix.set(0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0); + this.textureMatrix.multiply(this.mirrorCamera.projectionMatrix); + this.textureMatrix.multiply(this.mirrorCamera.matrixWorldInverse); + + // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html + // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf + this.mirrorPlane.setFromNormalAndCoplanarPoint(this.normal, this.mesh.position); + this.mirrorPlane.applyMatrix4(this.mirrorCamera.matrixWorldInverse); + + this.clipPlane.set(this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant); + + var q = new THREE.Vector4(); + var projectionMatrix = this.mirrorCamera.projectionMatrix; + + q.x = (sign(this.clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0]; + q.y = (sign(this.clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5]; + q.z = -1.0; + q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; + + // Calculate the scaled plane vector + var c = new THREE.Vector4(); + c = this.clipPlane.multiplyScalar(2.0 / this.clipPlane.dot(q)); + + // Replacing the third row of the projection matrix + projectionMatrix.elements[2] = c.x; + projectionMatrix.elements[6] = c.y; + projectionMatrix.elements[10] = c.z + 1.0 - this.clipBias; + projectionMatrix.elements[14] = c.w; + + var worldCoordinates = new THREE.Vector3(); + worldCoordinates.setFromMatrixPosition(this.camera.matrixWorld); + this.eye = worldCoordinates; + this.material.uniforms.eye.value = this.eye; +}; + +THREE.Water.prototype.render = function (isTempTexture) { + + if ( this.matrixNeedsUpdate ) { + this.updateTextureMatrix(); + } + + this.matrixNeedsUpdate = true; + + // Render the mirrored view of the current scene into the target texture + if ( this.scene !== undefined && this.scene instanceof THREE.Scene ) { + // Remove the mirror texture from the scene the moment it is used as render texture + // https://github.com/jbouny/ocean/issues/7 + this.material.visible = false; + + var renderTexture = (isTempTexture !== undefined && isTempTexture)? this.tempTexture : this.texture; + this.renderer.render(this.scene, this.mirrorCamera, renderTexture, true); + + this.material.visible = true; + this.material.uniforms.mirrorSampler.value = renderTexture; + } + +}; \ No newline at end of file diff --git a/examples/binary.html b/examples/binary.html new file mode 100644 index 0000000..bd98c01 --- /dev/null +++ b/examples/binary.html @@ -0,0 +1,90 @@ + + + + jQuery Three :: OBJ Mesh + + + + + + + + + + +
+

jQuery Three

+

A 3D model loader example, loading the Dreamway Palm in binary format | next >

+
+ +
+ + + + +
+ + + + + + + + + + + + + + + + diff --git a/examples/earth.html b/examples/earth.html index 9cd9905..22d66da 100644 --- a/examples/earth.html +++ b/examples/earth.html @@ -3,14 +3,10 @@ jQuery Three :: Earth + + +
+

jQuery Three

+

Texture of a mercator projection applied on a sphere and infinite rotation initiated with CSS | next >

+
+
- +
+ - + + + + + + + + diff --git a/examples/fly.html b/examples/fly.html index 7061656..2f409aa 100644 --- a/examples/fly.html +++ b/examples/fly.html @@ -3,14 +3,10 @@ jQuery Three :: Fly Controls + + - - - - - -
- - - - -
- - - - - - - - - \ No newline at end of file diff --git a/examples/primitives.html b/examples/primitives.html index 235afb4..a3e2a97 100644 --- a/examples/primitives.html +++ b/examples/primitives.html @@ -1,15 +1,12 @@ - -jQuery Three :: Primitives + + jQuery Three :: Primitives + + + - + + + + + +
+

jQuery Three

+

A similar effect to the skybox, only now we use a sphere for geometry and a single texture | next >

+
+ +
+ + + +
+ + + + + + + + + + + + + + + + diff --git a/examples/sprite.html b/examples/sprite.html new file mode 100644 index 0000000..a23ac09 --- /dev/null +++ b/examples/sprite.html @@ -0,0 +1,142 @@ + + + + jQuery Three :: Sprite character + + + + + + + + + +
+

jQuery Three

+

Here we have a character, animated from a sprite sheet; use the controls to change the animations | next >

+
+ +
+ + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + diff --git a/examples/terrain.html b/examples/terrain.html index 6ab96cc..066e6da 100644 --- a/examples/terrain.html +++ b/examples/terrain.html @@ -3,14 +3,10 @@ jQuery Three :: Heightmap Terrain + + + + + + + +
+

jQuery Three

+

The First person example, rendered with the THREE.OculusRiftEffect shader | next >

+
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/examples/water.html b/examples/water.html new file mode 100644 index 0000000..65ad603 --- /dev/null +++ b/examples/water.html @@ -0,0 +1,56 @@ + + + + jQuery Three :: Water Shader + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + diff --git a/lib/_end.js b/lib/_end.js deleted file mode 100644 index 01896e2..0000000 --- a/lib/_end.js +++ /dev/null @@ -1,15 +0,0 @@ - -// Prototype -Three.prototype.css = css; -Three.prototype.find = find; -Three.prototype.fn = fn; -//Three.prototype.fn.webgl = fn.webgl; -//Three.prototype.utils = utils; - -// #39 Wildcard extension - replace this hardcoding list with a proper wildcard method, once available (Proxy) -//Three.prototype.__noSuchMethod__ = fn.three; -Three.prototype.lookAt = function(){ - return this.fn.three.call(this, "lookAt", arguments); -}; - -})); \ No newline at end of file diff --git a/lib/animations.js b/lib/animations.js new file mode 100644 index 0000000..cea0520 --- /dev/null +++ b/lib/animations.js @@ -0,0 +1,239 @@ + +Three.prototype.animate = function( options, el ){ + //this.mesh.rotation.z = Date.now() / 1000; + + // fallbacks + options = options || {}; + el = el || this.last || false; // last processed object + // FIX: we are checking the type of the element to attach to Object3D? + if( el instanceof THREE.Mesh && el.parent instanceof THREE.Object3D ){ + el = el.parent; + } + // prerequisites + if( !el || !options.name ) return; + // create the necessary object containers + // should we be checking the type of the element to attach to Object3D? + el._animations = el._animations || {}; + el._update = el._update || updateAnimations.bind( el ); + + // pickup animation keyframes + options.keyframes = this.fn.animate.getKeyframes.call( this, options.name ); + // exit now... + if( !options.keyframes ) return; + // set the new animation + el._animations[ options.name ] = options; + // add to animate queue (once...) + var inQueue = ( typeof this.fn.animate.queue[el.uuid] !== "undefined" ); + if( !inQueue){ + this.fn.animate.queue[el.uuid] = el._update; // using uuid to be able to remove from queue later + } +}; + +// Internal + +fn.animate = { + // container for all methods to be updated + queue: {}, + + getKeyframes: function( name ){ + var keyframes = {}; + // first find the rules + var animation = findKeyframesRule( name ); + + if(!animation) return; + // parse each one of them + for(var i in animation.cssRules){ + var rule = animation.cssRules[i]; + var frame = {}; + // FIX: only rules parsed + if( !rule.keyText ) continue; + // convert percent to 1-100 number + var key = parseInt( rule.keyText, 10 ), val; + // find rotation values + frame.rotation = this.fn.css.rotate( rule.cssText ); + // find translate values + frame.translation = this.fn.css.translate( rule.cssText ); + // find scale values + frame.scale = this.fn.css.scale( rule.cssText ); + // other attributes + if( rule.cssText.search("background-position-x") > -1 ){ + frame["background-position"] = frame["background-position"] || {}; + val = rule.cssText.match(/:[\d|\s|\w]+\;/); // capture everything between : ; + if( val ) frame["background-position"].x = parseFloat(val[0].substr(1), 10); + } + if( rule.cssText.search("background-position-y") > -1 ){ + frame["background-position"] = frame["background-position"] || {}; + val = rule.cssText.match(/:[\d|\s|\w]+\;/); // capture everything between : ; + if( val ) frame["background-position"].y = parseFloat(val[0].substr(1), 10); + } + // add to the keyframes + keyframes[ key ] = frame; + } + return keyframes; + }, + + // loop through the object's animations and update the object's properties + update: function( el ){ + //console.log( this.queue ); + // loop through the queue + for( var i in this.queue ){ + // execute + this.queue[i](); + } + } + +}; + +// Helpers + +function updateAnimations(){ + // context is the individual object + //console.log( this ); + // loop through animations + for( var i in this._animations){ + var animation = this._animations[i]; + var keyframes = animation.keyframes; + // get current params + animation.start = animation.start || utils.now(); + animation.end = animation.end || ( animation.start + animation.duration ); + animation.offset = animation.offset || registerState( this ); + animation.count = animation.count || 0; + // find the right stage in the animation + var now = utils.now(); + var percent = ( ( now - animation.start) / animation.duration ) * 100; + var start = false, + end = false; + for( var key in keyframes ){ + if( key <= percent ){ + start = keyframes[ key ]; + } + if( key > percent && !end ){ + end = keyframes[ key ]; + } + } + // fallbacks + if( !start ) start = keyframes[ 0 ]; + if( !end ) end = keyframes[ 100 ]; + // apply updates + // NOTE: only linear supported for now... + // - rotate + var rot = { + x: ( typeof start.rotation.x != "undefined" && typeof end.rotation.x != "undefined" ) ? (end.rotation.x - start.rotation.x )*(percent/100) : 0, + y: ( typeof start.rotation.y != "undefined" && typeof end.rotation.y != "undefined" ) ? (end.rotation.y - start.rotation.y )*(percent/100) : 0, + z: ( typeof start.rotation.z != "undefined" && typeof end.rotation.z != "undefined" ) ? (end.rotation.z - start.rotation.z )*(percent/100) : 0 + }; + this.rotation.set( animation.offset.rotation.x+rot.x, animation.offset.rotation.y+rot.y, animation.offset.rotation.z+ rot.z); + // TBA... + // - translate + + // - scale + + // - sprites + if( this instanceof THREE.Sprite ){ + // get current sprite index + var offset = { + x: this.material.map.offset.x, + y: this.material.map.offset.y + }; + // increment + var steps = animation.easing; + var step = 100/steps; + var nextStep = ( (parseInt( percent, 10) % step) === 0 ) ? parseInt( percent, 10) / 100 : 0; // every time we return to zero we have a new step + if( nextStep ){ + // FIX: start index of steps from zero + nextStep -= 1/steps; + // find the right axis + if( typeof animation.keyframes[0]["background-position"].x !== "undefined" ){ + // - numbers go in reverse order (steps-1 to 0) + offset.x = ((steps-1)/steps)-nextStep; + } + if( typeof animation.keyframes[0]["background-position"].y !== "undefined" ){ + // - numbers go in reverse order (steps-1 to 0) + offset.y = ((steps-1)/steps)-nextStep; + } + // update sprite + this.material.map.offset.set( offset.x, offset.y ); + } + + } + // reset if reached completion + if( percent >= 100 ){ + delete animation.start; + delete animation.end; + delete animation.offset; + animation.count++; + } + // + if( animation.count == animation.repeat ){ + delete this._animations[i]; + } else { + // save animation updates + this._animations[i] = animation; + } + } +} + +// register element state +function registerState( el ){ + return { + position: { + x: el.position.x, + y: el.position.y, + z: el.position.z + }, + rotation: { + x: el.rotation.x, + y: el.rotation.y, + z: el.rotation.z + }, + scale: { + x: el.scale.x, + y: el.scale.y, + z: el.scale.z + } + }; +} + +/* + * Access and modify CSS animations @keyFrames with Javascript + * Based on : http://jsfiddle.net/russelluresti/RHhBz/2/ + * Issue : http://stackoverflow.com/questions/10342494/set-webkit-keyframes-values-using-javascript-variable + */ + + // search the CSSOM for a specific -webkit-keyframe rule +function findKeyframesRule(rule){ + // gather all stylesheets into an array + var ss = document.styleSheets; + + // loop through the stylesheets + for (var i = 0; i < ss.length; ++i) { + + // loop through all the rules + for (var j = 0; j < ss[i].cssRules.length; ++j) { + + // find the -webkit-keyframe rule whose name matches our passed over parameter and return that rule + if (ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && ss[i].cssRules[j].name == rule) + return ss[i].cssRules[j]; + } + } + + // rule not found + return null; +} + +// remove old keyframes and add new ones +function changeAnimationKeyframes(anim){ + // find our -webkit-keyframe rule + var keyframes = findKeyframesRule(anim); + + // remove the existing 0% and 100% rules + keyframes.deleteRule("0%"); + keyframes.deleteRule("100%"); + + // create new 0% and 100% rules with random numbers + keyframes.insertRule("0% { -webkit-transform: rotate("+randomFromTo(-360,360)+"deg); }"); + keyframes.insertRule("100% { -webkit-transform: rotate("+randomFromTo(-360,360)+"deg); }"); + + // assign the animation to our element (which will cause the animation to run) + document.getElementById('box').style.webkitAnimationName = anim; +} \ No newline at end of file diff --git a/lib/attributes.js b/lib/attributes.js index fbbe1ac..7ea1379 100644 --- a/lib/attributes.js +++ b/lib/attributes.js @@ -16,6 +16,8 @@ Three.prototype.getAttributes = function( html ){ var val = attr[i].value; // check if it's a number... data[key] = ( parseInt(val, 10) || val === "0" ) ? parseInt(val, 10) : val; + // convert boolean + if( data[key] === "false" || data[key] === "true" ) data[key] = JSON.parse( data[key] ); } else if( attr[i].name && attr[i].name.search("class") === 0 ){ // add classes var classes = attr[i].value.split(" "); diff --git a/lib/core.js b/lib/core.js index 17874d1..352bf42 100644 --- a/lib/core.js +++ b/lib/core.js @@ -1,8 +1,10 @@ var defaults = { - watch : false, + alpha: true, + clock: true, + watch: false, //deps : { "THREE" : "http://cdnjs.cloudflare.com/ajax/libs/three.js/r54/three.min.js" } - deps : { + deps: { "THREE" : "https://raw.github.com/mrdoob/three.js/master/build/three.min.js" //"FresnelShader" : "" }, @@ -18,12 +20,16 @@ this.objects = {}; this.scenes = {}; this.cameras = {}; + this.terrains = {}; this.materials = {}; // defining types (extandable) this.groups = { - "camera" : "cameras", "scene" : "scenes", "mesh" : "objects", "plane" : "objects", "cube" : "objects", "sphere" : "objects", "cylinder" : "objects", "material" : "materials" + "camera" : "cameras", "scene" : "scenes", "terrain" : "terrains", "mesh" : "objects", "plane" : "objects", "cube" : "objects", "sphere" : "objects", "cylinder" : "objects", "material" : "materials" }; - // #43 - calculating 'actual' framerate + + // init clock + if( this.options.clock ) this.clock = new THREE.Clock(); + // #43 - calculating 'actual' framerate (use clock?) this.frame = { current: 0, rate: 0, @@ -57,7 +63,7 @@ Three.prototype = { this.properties = this.setProperties(); // init renderer - this.renderer = new THREE.WebGLRenderer(); + this.renderer = new THREE.WebGLRenderer({ alpha: this.options.alpha }); this.renderer.setSize( this.properties.width, this.properties.height); // condition this! this.renderer.autoClear = false; @@ -144,7 +150,7 @@ Three.prototype = { } else { // new frame, new count this.frame.rate = this.frame.current; - this.frame.current = 1; //start fron 1 to include running frame ;) + this.frame.current = 1; //start from 1 to include running frame ;) this.frame.date = now; } // loop on the next click @@ -152,22 +158,31 @@ Three.prototype = { }, render : function() { - // apply transformations - $(this.el).trigger({ - type: "update", - target: this - }); - // - + // init render if( this.active.scene && this.active.camera ){ - // render the skybox as a first pass + // resize skybox to the limits of the active camera (far attribute) if( this.active.skybox ){ - if( this.active.skybox.camera ) this.active.skybox.camera.rotation.copy( this.active.camera.rotation ); - this.renderer.render( this.active.skybox.scene, this.active.skybox.camera ); + //if( this.active.skybox.camera ) this.active.skybox.camera.rotation.copy( this.active.camera.rotation ); + //this.renderer.render( this.active.skybox.scene, this.active.skybox.camera ); + var horizon = this.active.camera.far; + var scale = this.active.skybox.scale; + if( scale.x !== horizon ) + scale.x = scale.y = scale.z = horizon; + // always center around camera... + var position = this.active.camera.position; + this.active.skybox.position.set( position.x, position.y, position.z ); } + this.renderer.render( this.active.scene, this.active.camera ); } + // update internal animation queue + this.fn.animate.update(); + // trigger update event regardlesss + $(this.el).trigger({ + type: "update", + target: this + }); }, show : function( ) { }, @@ -202,10 +217,10 @@ Three.prototype = { this.cameras[i].updateProjectionMatrix(); } // better way of targeting skybox??? - if( this.active.skybox ){ - this.active.skybox.camera.aspect = this.properties.aspect; - this.active.skybox.camera.updateProjectionMatrix(); - } + //if( this.active.skybox ){ + // this.active.skybox.camera.aspect = this.properties.aspect; + // this.active.skybox.camera.updateProjectionMatrix(); + //} this.renderer.setSize( this.properties.width, this.properties.height ); }, diff --git a/lib/css.js b/lib/css.js old mode 100644 new mode 100755 index 9356776..fde82e1 --- a/lib/css.js +++ b/lib/css.js @@ -10,17 +10,25 @@ css = function ( styles ){ return this; }; - // Internal functions fn.css = { styles: function (a){ var sheets = document.styleSheets, o = {}; + // loop through stylesheets - for(var i in sheets) { - var rules = sheets[i].rules || sheets[i].cssRules; + for( var i in sheets ){ + var sheet = sheets[i]; + var isOutsideOfDomain = sheet.href && sheet.href.indexOf("/") !== 0 && sheet.href.indexOf(origin) !== 0; + // ignore sheets out-of-domain or without CSS rules + if(isOutsideOfDomain || sheet.cssRules === null) continue; + // + var rules = sheet.cssRules || sheet.rules; for(var r in rules) { // #21 - excluding :hover styles from parsing if( rules[r].selectorText && rules[r].selectorText.search(":hover") > -1) continue; + // excluding other pseudo elements + if( rules[r].selectorText && rules[r].selectorText.search("::before") > -1) continue; + if( rules[r].selectorText && rules[r].selectorText.search("::after") > -1) continue; try{ if(a.is(rules[r].selectorText)) { o = $.extend(o, css2json(rules[r].style)); @@ -42,6 +50,13 @@ fn.css = { for( var attr in css ){ // remove prefixes var key = attr.replace('-webkit-','').replace('-moz-',''); + // save attribute reference in the object + object._style = object._style || {}; + object._shaders = object._shaders || {}; + var changed = ( object._style[key] && object._style[key] == css[attr] ) ? false : true; // save old value? + object._style[key] = css[attr]; + // parse only changed atrributes + if( !changed ) continue; // supported attributes switch(key){ // - width @@ -73,7 +88,7 @@ fn.css = { //this.fn.css.skybox.call(this, css[attr]); this.webglLight({color : color}); } else { - object.material.color.setHex(color); + setColor( object, color ); } break; // - transforms @@ -109,25 +124,38 @@ fn.css = { break; // - animation case "animation-duration": - console.log( key, css[attr]); + this.fn.css.animation.duration = parseInt( css[attr], 10) * 1000; // convert seconds to milliseconds break; case "animation-timing": - console.log( key, css[attr]); + this.fn.css.animation.easing = css[attr]; break; case "animation-delay": - console.log( key, css[attr]); + this.fn.css.animation.delay = css[attr]; break; case "animation-iteration-count": - console.log( key, css[attr]); + this.fn.css.animation.repeat = css[attr]; break; case "animation-direction": - console.log( key, css[attr]); + this.fn.css.animation.direction = css[attr]; break; case "animation-fill-mode": - console.log( key, css[attr]); + this.fn.css.animation.fill = css[attr]; break; case "animation-name": - console.log( key, css[attr]); + //console.log( key, css[attr]); + // assumption: name is the last animation attribute processed + this.fn.css.animation.name = css[attr]; + this.animate( this.fn.css.animation, object ); + this.fn.css.animation = {}; + break; + case "animation-timing-function": + // duplicate of animation-timing? + // if counting steps, save the number + var steps = css[attr].match(/steps\((\d)/); // not closed.. + this.fn.css.animation.easing = ( steps ) ? parseInt(steps[1], 10) : css[attr]; + break; + case "animation-play-state": + this.fn.css.animation.state = css[attr]; break; case "display": // set it as the active one... @@ -137,6 +165,8 @@ fn.css = { if( object instanceof THREE.Scene){ this.fn.css.skybox.call(this, css[attr]); } else if( object.type == "terrain" ){ + // make sure this get's processed on the next tick + //utils.delay( this.fn.css.terrain.bind(this), 100, css[attr] ); this.fn.css.terrain.call(this, css[attr]); } else if ( object instanceof THREE.Mesh ) { this.fn.css.texture.call(this, object, css[attr]); @@ -149,19 +179,73 @@ fn.css = { } catch( e ){ console.log(e); } + } else if( object instanceof THREE.Sprite ){ + var src = css[attr].replace(/\s|url\(|"|'|\)/g, ""); + object.material.map = utils.textureLoader( src ); + } + break; + case "background-size": + if( object instanceof THREE.Sprite ){ + // + this.fn.css.sprite.call(this, object, css[attr]); + } + break; + // "background-position" arrives split in axis + case "background-position-x": + if( object instanceof THREE.Sprite ){ + // update sprite + this.fn.css.sprite.call(this, object); } break; + case "background-position-y": + if( object instanceof THREE.Sprite ){ + // update sprite + this.fn.css.sprite.call(this, object); + } + break; + case "filter": + // variables + // - find element + var el, $el; + if( object instanceof THREE.Mesh && object.parent instanceof THREE.Object3D ){ + // parent is always an object...? + el = object.parent; + $el = object.parent.$el; + } else { + el = object; + $el = object.$el; + } + // get URLs + var urls = css[attr].replace(/url\(|"|'|\)/g, "").split('|'); // all shaders in one url? + // prerequisite + if( !urls.length ) break; + // get shaders + el._shaders = el._shaders || {}; + for( var i in urls ){ + var name = urls[i].substring(urls[i].lastIndexOf('/')+1); + el._shaders[name] = utils.getFile( urls[i] ); + } + // add helper method + el.getShader = function( name ){ + return this._shaders[name] || null; + }; + // trigger event + $el.trigger('css-filter'); + break; } } }, + // temporary container for parsed (animation) attributes... + animation: {}, + rotate: function( attr ){ var rot = {}; var val; - // only supporting rotate3d for now... + // if( attr.search("rotate3d") > -1 ){ // replace all the bits we don't need val = attr.match(/rotate3d\(([\s\S]*?)\)/gi); @@ -174,6 +258,32 @@ fn.css = { z: parseFloat( val[2], 10 ) * parseFloat( val[3], 10 ) * (Math.PI/180) }; + } else if( attr.search("rotateX") > -1 ){ + // axis based rotation + val = attr.match(/rotateX\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotateX\(|deg|\)| /gi, ""). + rot = { + x: parseFloat( val, 10 ) * (Math.PI/180) + }; + } else if( attr.search("rotateY") > -1 ){ + val = attr.match(/rotateY\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotateY\(|deg|\)| /gi, ""); + rot = { + y: parseFloat( val, 10 ) * (Math.PI/180) + }; + } else if( attr.search("rotateZ") > -1 ){ + val = attr.match(/rotateZ\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotateZ\(|deg|\)| /gi, ""); + rot = { + z: parseFloat( val, 10 ) * (Math.PI/180) + }; + } else if( attr.search("rotate") > -1 ){ + val = attr.match(/rotate\(([\s\S]*?)\)/gi); + val = val[0].replace(/rotate\(|deg|\)| /gi, ""); + // if no axis is set assume Z? + rot = { + z: parseFloat( val, 10 ) * (Math.PI/180) + }; } return rot; @@ -205,7 +315,7 @@ fn.css = { scale: function( attr ){ var size = {}; - // only supporting rotate3d for now... + // only supporting scale3d for now... if( attr.search("scale3d") > -1 ){ // replace all the bits we don't need var val = attr.match(/scale3d\(([\s\S]*?)\)/gi); @@ -225,71 +335,75 @@ fn.css = { }, texture: function( el, attr ){ - var map = attr.replace(/\s|url\(|\)/g, ""); - var material = this.webglMaterial({ map : map }); + var material; + var img = attr.replace(/\s|url\(|"|'|\)/g, "").split(','); + if( img.length > 1 ){ + // shader material + // add available shaders + var uniforms = {}; + var params = {}; + var textureCube = new THREE.CubeTextureLoader().load( img ); + //var textureCube = app.layout.views.get('back').$3d.active.skybox.material.uniforms.tCube.value ); + textureCube.format = THREE.RGBFormat; + + uniforms.tCube = { + type: "t", + value: textureCube + }; + // add shaders if available + if(el._shaders){ + for( var i in el._shaders ){ + var shader = el._shaders[i]; + if( i.indexOf('.fs') > -1 ){ + params.fragmentShader = shader; + } + if( i.indexOf('.vs') > -1 ){ + params.vertexShader = shader; + } + } + } + + params.uniforms = uniforms; + params.needsUpdate = true; + + material = new THREE.ShaderMaterial( params ); + + } else { + // basic map material + material = this.webglMaterial({ map : img[0] }); + } el.material = material; }, terrain: function( attr ){ - var object = this.last; - - var img = attr.replace(/\s|url\(|\)/g, "").split(','); + var terrain = this.last; + //var img = attr.replace(/\s|url\(|"|'|\)/g, "").split(','); + var img = attr.match(/url\(\s*[\'"]?(([^\\\\\'" \(\)]*(\\\\.)?)+)[\'"]?\s*\)/img); + // if(img instanceof Array){ + var heightmap, diffuse, specular; for( var i in img ){ + // clean url(...) content + img[i] = img[i].replace(/\s|url\(|"|'|\)/g, ""); - if( img[i].search("heightmap") > -1 ){ - - var heightmapTexture = THREE.ImageUtils.loadTexture( img[i] ); - //var heightmapTexture = this.webglTexture( img[i] ); - object.material.uniforms.tDisplacement.value = heightmapTexture; - object.material.uniforms.uDisplacementScale.value = 375; - // heightmap also the second diffuse map? - var diffuseTexture2 = heightmapTexture; - diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; - - object.material.uniforms.tDiffuse2.value = diffuseTexture2; - object.material.uniforms.enableDiffuse2.value = true; - - } - if( img[i].search("diffuse") > -1 ){ - - var diffuseTexture1 = THREE.ImageUtils.loadTexture( img[i] ); - //var diffuseTexture1 = this.webglTexture( img[i] ); - diffuseTexture1.wrapS = diffuseTexture1.wrapT = THREE.RepeatWrapping; - - object.material.uniforms.tDiffuse1.value = diffuseTexture1; - object.material.uniforms.enableDiffuse1.value = true; - - } - if( img[i].search("specular") > -1 ){ + if( img[i].search("heightmap") > -1 ) heightmap = terrain.updateTexture('heightmap', img[i]); - var specularMap = THREE.ImageUtils.loadTexture( img[i] ); - //var specularMap = this.webglTexture( img[i] ); - specularMap.wrapS = specularMap.wrapT = THREE.RepeatWrapping; + if( img[i].search("diffuse") > -1 ) diffuse = terrain.updateTexture('diffuse', img[i]); - object.material.uniforms.tSpecular.value = specularMap; - object.material.uniforms.enableSpecular.value = true; + if( img[i].search("specular") > -1 ) specular = terrain.updateTexture('specular', img[i]); - } } + // fallbacks + if(!heightmap && img[0]) terrain.updateTexture('heightmap', img[0]); + if(!diffuse && img[1]) terrain.updateTexture('diffuse', img[1]); + if(!specular && img[2]) terrain.updateTexture('specular', img[2]); + } else { - // one image... which texture is it?... + // one image... assume it's both heightmap and texture + terrain.updateTexture('heightmap', img); + terrain.updateTexture('diffuse', img); } - /* - - leftovers ( normal and detail textures) - - //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; - - //uniformsTerrain[ "tNormal" ].value = heightmapTexture; - //uniformsTerrain[ "uNormalScale" ].value = 1; - - //uniformsTerrain[ "tDetail" ].value = detailTexture; - - //uniformsTerrain[ "uShininess" ].value = 30; - - */ }, @@ -297,7 +411,7 @@ fn.css = { // remove any whitespace, the url(..) and // attempt to break it into an array - var img = attr.replace(/\s|url\(|\)/g, "").split(','); + var img = attr.replace(/\s|url\(|"|'|\)/g, "").split(','); if(img instanceof Array){ // expect a six-pack of images this.addSkybox( img ); @@ -306,6 +420,39 @@ fn.css = { // this is one image... not implemented yet } + }, + + sprite: function( el, attr ){ + // wait for the image to load + var loaded = setInterval(function(){ + // assume map is available... + if( !el.material.map.image || !el.material.map.image.width ) return; + // fallbacks + attr = attr || el._style["background-size"] || "0 0"; + var size = attr.split(" "); + var width = parseFloat(size[0], 10); + var height = parseFloat(size[1], 10); + // get position from style + var x = parseFloat( el._style["background-position-x"] || 0 ); + var y = parseFloat( el._style["background-position-y"] || 0 ); + + if( !width || !height ) return; + + // image dimensions + var imgWidth = el.material.map.image.width; + var imgHeight = el.material.map.image.height; + // + //el.material.uvOffset.set(1 / 5, 0); + //el.material.uvScale.set(1 / 5, 1); + el.material.map.offset.set( (imgWidth - width - x) / imgWidth, (imgHeight - height - y) / imgHeight ); // start from top left... + el.material.map.repeat.set(width / imgWidth, height / imgHeight); + //el.scale.set( width, height, 1 ); + //console.log("sprite loaded"); + // stop loop + clearInterval(loaded); + }, 200); + + } }; @@ -348,3 +495,17 @@ var css2json = function (css){ return s; }; +function setColor( object, color ){ + object = object || {}; + // prerequisite + if( !object.material ) return; // create material instead? + // in case we have more than one materials + if( object.material.materials ){ + // check it it's an array first? + for(var i in object.material.materials ){ + object.material.materials[i].color.setHex(color); + } + } else { + object.material.color.setHex(color); + } +} diff --git a/lib/effects.js b/lib/effects.js index 8ef1293..e6a025e 100644 --- a/lib/effects.js +++ b/lib/effects.js @@ -1,5 +1,5 @@ -Three.prototype.animate = function(){ +Three.prototype.fx = function(){ //this.mesh.rotation.z = Date.now() / 1000; - + }; diff --git a/lib/events.js b/lib/events.js index beece7a..0d4d4e2 100644 --- a/lib/events.js +++ b/lib/events.js @@ -1,9 +1,45 @@ // watch an element for changes Three.prototype.watch = function( el ) { var self = this; - var element = $(this.el).toSelector() +" "+ $( el ).selector; + var selector = $( el ).selector || "shadow-root"; // fallback to main root + var element = $(this.el).toSelector() +" "+ selector; + + var node = document.getElementById("main").querySelector("shadow-root"), //$(this.el)[0], //$(element)[0], + bubbles = false; + + // shim + var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; + + var whatToObserve = { childList: true, attributes: true, subtree: true, attributeOldValue: true, attributeFilter: ['class', 'style']}; + //var whatToObserve = { childList: true, attributes: false, subtree: true }; + var attrObserver = new MutationObserver(function(mutationRecords) { + $.each(mutationRecords, function(index, mutationRecord) { + var e = mutationRecord; + if (mutationRecord.type === 'childList') { + if (mutationRecord.addedNodes.length > 0) { + //DOM node added, do something + //console.log("execute", mutationRecord ); + //console.log('DOMSubtreeModified', e.target.innerHTML.length, e.target ); + self.eventSubtree(e); + } else if (mutationRecord.removedNodes.length > 0) { + //DOM node removed, do something + } + } + else if (mutationRecord.type === 'attributes') { + if (mutationRecord.attributeName === 'class') { + //class changed, do something + self.eventAttribute(e); + } + } + }); + }); + + attrObserver.observe(node, whatToObserve); + // monitor new elements + /* $('body').on('DOMSubtreeModified', element, function(e){ + console.log(e); self.eventSubtree(e); }); // monitor attribute changes @@ -17,13 +53,39 @@ Three.prototype.watch = function( el ) { self.eventAttribute(e); }); } + */ + + var observeStyles = new MutationObserver(function (mutations) { + mutations.forEach(stylesModified); + }); + observeStyles.observe(node, { childList: false, attributes: true, subtree: true, attributeFilter: ['class', 'style'] }); + + // monitor css style changes + function stylesModified(mutation) { + var el = mutation.target, + name = mutation.attributeName, + newValue = mutation.target.getAttribute(name), + oldValue = mutation.oldValue; + // skip all id, data-id updates (not editable from the user) + //if( name == 'id' || name == 'data-id' ) return; + // styling updates + if( name == 'style' ){ + var object = self.objects[ el.getAttribute('data-id') ] || self.active.terrain; + var webgl = object.children[0] || object; + var css = css2json(newValue); // validate? + // HACK: why is terrain using this.last? + self.last = webgl; + self.fn.css.set.call(self, webgl, css ); + } + //console.log(name, newValue, oldValue); + } }; // - new element Three.prototype.eventSubtree = function(e) { - e.stopPropagation(); + //e.stopPropagation(); // mutation event doesn't propagate? // variables var $root = $( $(this.el).toSelector() +" shadow-root" ).get(0); @@ -33,25 +95,32 @@ Three.prototype.eventSubtree = function(e) { this.parent = ( $root == $target ) ? $(e.target) : $(e.target).parent(); this.target = $(e.target); - if (e.target.innerHTML.length > 0) { - // Handle new content - //var html = e.target.innerHTML; - var html = $(e.target).html(); - //this.newEl = $(e.target).children().last(); - // #46 parsing one tag at a time - //html = $(html).html("").get(0); - //this.newEl = $(html).last(); - this.append( html, { silent : true, target: this.target, traverse: false, watch: true }); - } + // exclude shadow-root + //if( $root == $target ) return; + // exclude empty targets + if(e.target.innerHTML.length === 0) return; + // Handle new content + //var html = e.target.innerHTML; + var html = $(e.target).html(); + //var wrapper = $(html).eq(0)[0]; + // FIX: exclude empty div tags (dead-ends) + //if( wrapper.tagName == "DIV" && + //if( wrapper.toString().substr(0, 5).toLowerCase() == "
" ) return; + // html = wrapper.childNodes[0].toString().trim(); + //this.newEl = $(e.target).children().last(); + // #46 parsing one tag at a time + //html = $(html).html("").get(0); + //this.newEl = $(html).last(); + this.append( html, { silent : true, target: this.target, traverse: false, watch: true }); + }; // - updated attribute Three.prototype.eventAttribute = function(e) { - e.stopPropagation(); + //e.stopPropagation(); console.log("attribute", e.target ); }; // - updated style(s) - diff --git a/lib/_start.js b/lib/main.js similarity index 57% rename from lib/_start.js rename to lib/main.js index 338db9d..abf0bf4 100644 --- a/lib/_start.js +++ b/lib/main.js @@ -25,12 +25,12 @@ window.requestAnimFrame = ( function( callback ) { (function (root, factory) { - "use strict"; + //"use strict"; - var define = define || false; + //var define = define || false; var jquery = root.$ || root.jQuery || root.ender; - if (define && typeof define === 'function' && define.amd) { + if (typeof define === 'function' && define.amd){ // AMD. Register as an anonymous module. define(['jquery'], factory); } else { @@ -42,8 +42,29 @@ window.requestAnimFrame = ( function( callback ) { // Local variables var css, _css; +var files = {}; +var origin = location.origin || location.protocol + "//" + location.hostname + (location.port ? ":" + location.port: ""); // Create a fn container for internal methods var fn = { - self : function(){ return this; } - }; + self : function(){ return this; } +}; + + +{{{lib}}} + + +// Prototype +Three.prototype.css = css; +Three.prototype.find = find; +Three.prototype.fn = fn; +//Three.prototype.fn.webgl = fn.webgl; +//Three.prototype.utils = utils; + +// #39 Wildcard extension - replace this hardcoding list with a proper wildcard method, once available (Proxy) +//Three.prototype.__noSuchMethod__ = fn.three; +Three.prototype.lookAt = function(){ + return this.fn.three.call(this, "lookAt", arguments); +}; + +})); diff --git a/lib/manipulation.js b/lib/manipulation.js index 4c71e14..1e4ade5 100644 --- a/lib/manipulation.js +++ b/lib/manipulation.js @@ -38,21 +38,16 @@ Three.prototype.add = function( attributes, options ){ object = webgl; } //this[ attributes.type+"s" ][0] = webgl; + // condition which elements have an active flag? self.active[ attributes.type ] = object; - // - if( container ){ - // save in the objects bucket - self[container][object.id] = object; - } - // add to scene - if( attributes.type == "scene"){ - self.active.scene = object; - } else if( self.active.scene ){ - self.active.scene.add( object ); - } + // keep a reference of the object id attributes["data-id"] = object.id || false; + + // FIX: stop now if duplicate id was generated (why?) + if( attributes.el.data('id') ) return; + // create the tag in the shadow dom var $html; if( options.silent && attributes.el){ @@ -65,10 +60,26 @@ Three.prototype.add = function( attributes, options ){ $html = self.createHTML( attributes ); self.target = $html; } + + // save reference of html tag in object + object.$el = $html; + // apply css var css = self.fn.css.styles.call(self, $html ); self.fn.css.set.call(self, webgl, css ); + // save in the objects bucket + if( container ){ + self[container][object.id] = object; + } + + // add to scene + if( attributes.type == "scene"){ + self.active.scene = object; + } else if( self.active.scene ){ + self.active.scene.add( object ); + } + }); return this; @@ -179,38 +190,69 @@ Three.prototype.addAsset = function( obj ){ Three.prototype.addSkybox = function( img ){ - // does this camera have set values?? - var camera = new THREE.PerspectiveCamera( 50, $(this.el).width() / $(this.el).height(), 1, 100 ); - - var scene = new THREE.Scene(); - - var reflectionCube = THREE.ImageUtils.loadTextureCube( img ); - reflectionCube.format = THREE.RGBFormat; - - //var shader = THREE.ShaderUtils.lib.cube; - var shader = THREE.ShaderLib.cube; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - uniforms.tCube.value = reflectionCube; - - var material = new THREE.ShaderMaterial( { - - fragmentShader: shader.fragmentShader, - vertexShader: shader.vertexShader, - uniforms: uniforms, - depthWrite: false, - side: THREE.BackSide - - }); - - var mesh = new THREE.Mesh( new THREE.CubeGeometry( 100, 100, 100 ), material ); - - scene.add( mesh ); + //var scene = new THREE.Scene(); + var camera, geometry, material; + + if( img.length == 1){ + + //camera = new THREE.PerspectiveCamera( 50, $(this.el).width() / $(this.el).height(), 1, 1100 ); + //camera.target = new THREE.Vector3( 0, 0, 0 ); + + // skysphere + geometry = new THREE.SphereGeometry( 1, 60, 40 ); + geometry.applyMatrix( new THREE.Matrix4().makeScale( -1, 1, 1 ) ); + material = new THREE.MeshBasicMaterial({ + map: utils.textureLoader( img[0] ) + }); + + } else { + // + var reflectionCube; + // skybox (with legacy support) + if(THREE.REVISION < 70){ + reflectionCube = THREE.ImageUtils.loadTextureCube( img ); + } else { + var cubeTextureLoader = new THREE.CubeTextureLoader(); + reflectionCube = cubeTextureLoader.load( img ); + } + reflectionCube.format = THREE.RGBFormat; + + // does this camera have set values?? + //camera = new THREE.PerspectiveCamera( 50, $(this.el).width() / $(this.el).height(), 1, 100 ); + + //var shader = THREE.ShaderUtils.lib.cube; + var shader = THREE.ShaderLib.cube; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + uniforms.tCube.value = reflectionCube; + + material = new THREE.ShaderMaterial( { + + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader, + uniforms: uniforms, + depthWrite: false, + side: THREE.BackSide + + }); + // the dimensions of the skybox will be resized to the limits of the active camera (far) + geometry = new THREE.BoxGeometry( 1, 1, 1 ); + } + + var mesh = new THREE.Mesh( geometry, material ); + /* + var object = new THREE.Object3D(); + object.add( mesh ); + // #40 copy name from mesh + object.name = mesh.name = "skybox"; + */ + this.active.scene.add( mesh ); // save as active - this.active.skybox = { - scene : scene, - camera : camera - }; + this.active.skybox = mesh; + //this.active.skybox = { + // scene : scene, + // camera : camera + //}; }; Three.prototype.addTerrain = function( obj ){ diff --git a/lib/selectors.js b/lib/selectors.js index 5071693..cf292b6 100644 --- a/lib/selectors.js +++ b/lib/selectors.js @@ -2,7 +2,7 @@ Three.prototype.get = function( id ){ // find the element in the containers - var el = this.objects[id] || this.cameras[id] || this.scenes[id] || null; + var el = this.objects[id] || this.cameras[id] || this.scenes[id] || this.terrains[id] || null; return el; @@ -28,7 +28,7 @@ fn.find = { var id = $(this.el).find("shadow-root "+ query).attr("data-id"); // find the element in the containers - var el = this.objects[id] || this.cameras[id] || this.scenes[id] || null; + var el = this.objects[id] || this.cameras[id] || this.scenes[id] || this.terrains[id] || null; return el; } diff --git a/lib/terrain.js b/lib/terrain.js new file mode 100644 index 0000000..0ab63e8 --- /dev/null +++ b/lib/terrain.js @@ -0,0 +1,270 @@ + +// internal constructor for Terrain +var Terrain = function( options ){ + // prerequisites? + + // reference to the options + this.options = options; + + // binding resolution across axis + var resX = options.resolution, + resY = options.resolution; + + // in both cases the geometry is Buffer + var plane = new THREE.PlaneBufferGeometry( options.width, options.height, resX, resY ); + + // update normals after images are loaded? + plane.computeFaceNormals(); + plane.computeVertexNormals(); + //plane.computeTangents( plane ); + //THREE.BufferGeometryUtils.computeTangents( plane ); + utils.computeTangents( plane ); + + // look if we're rendering using a shader + var material = ( options.shader ) ? this.shaderMaterial() : this.basicMaterial(); + + // exit now id we didn't generate a material? + + // generate mesh + var terrain = new THREE.Mesh( plane, material ); + // needsUpdate as attribute + //terrain.geometry.attributes.normal.needsUpdate = true; + + // save type as part of the mesh + terrain.type = "terrain"; + + // save attributes + terrain._attributes = options; + + // helper methods + if( options.shader ){ + terrain.updateTexture = this.shaderTexture.bind(terrain); + } else { + terrain.computeElevation = this.computeElevation.bind(terrain); + terrain.updateTexture = this.basicTexture.bind(terrain); + } + + // save reference + this.terrain = terrain; + + return this; +}; + + +Terrain.prototype.shaderMaterial = function(){ + // prerequisites + if( !THREE.ShaderTerrain ) + return console.log("THREE.ShaderTerrain not loaded. Use data-shader='false' to generate a poly terrain"); + + var options = this.options; + var terrainShader = THREE.ShaderTerrain.terrain; + + var uniformsTerrain = THREE.UniformsUtils.clone( terrainShader.uniforms ); + + /* these are all moved to the css styling... + var heightmapTexture = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); + var diffuseTexture1 = THREE.ImageUtils.loadTexture( "assets/img/terrain/diffuse.jpg" ); + var diffuseTexture2 = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); + var specularMap = THREE.ImageUtils.loadTexture( "assets/img/terrain/specular.png"); + + diffuseTexture1.wrapS = diffuseTexture1.wrapT = THREE.RepeatWrapping; + diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; + //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; + specularMap.wrapS = specularMap.wrapT = THREE.RepeatWrapping; + + //uniformsTerrain[ "tNormal" ].value = heightmapTexture; + //uniformsTerrain[ "uNormalScale" ].value = 1; + + uniformsTerrain[ "tDisplacement" ].value = heightmapTexture; + uniformsTerrain[ "uDisplacementScale" ].value = 375; + + uniformsTerrain[ "tDiffuse1" ].value = diffuseTexture1; + uniformsTerrain[ "tDiffuse2" ].value = diffuseTexture2; + uniformsTerrain[ "tSpecular" ].value = specularMap; + //uniformsTerrain[ "tDetail" ].value = diffuseTexture1; + + uniformsTerrain[ "enableDiffuse1" ].value = true; + uniformsTerrain[ "enableDiffuse2" ].value = true; + uniformsTerrain[ "enableSpecular" ].value = true; + + uniformsTerrain[ "uDiffuseColor" ].value.setHex( 0xffffff ); + uniformsTerrain[ "uSpecularColor" ].value.setHex( 0xffffff ); + uniformsTerrain[ "uAmbientColor" ].value.setHex( 0x111111 ); + + //uniformsTerrain[ "uShininess" ].value = 30; + */ + + // allow the terrain to emit ambient light from the scene + if( THREE.REVISION < 70 ){ + uniformsTerrain.uDiffuseColor.value.setHex( 0xffffff ); + uniformsTerrain.uSpecularColor.value.setHex( 0xffffff ); + uniformsTerrain.uAmbientColor.value.setHex( 0x111111 ); + } else { + uniformsTerrain.diffuse.value.setHex( 0xffffff ); + uniformsTerrain.specular.value.setHex( 0xffffff ); + //uniformsTerrain.ambient.value.setHex( 0x111111 ); + } + + // this should also be accessible by a background-size value (with percentage conversion) + uniformsTerrain.uRepeatOverlay.value.set( options.repeat, options.repeat ); + // + + var material = new THREE.ShaderMaterial( { + uniforms : uniformsTerrain, + vertexShader : terrainShader.vertexShader, + fragmentShader : terrainShader.fragmentShader, + lights : options.lights, + fog : options.fog, + needsUpdate: true + }); + + return material; + +}; + +Terrain.prototype.basicMaterial = function(){ + + var material = new THREE.MeshBasicMaterial( { map: utils.pixel(), overdraw: 0.5 } ); + // + return material; +}; + +// Helpers + +// Terrain helper to compute elevation from heightmap +Terrain.prototype.computeElevation = function( texture ){ + // prerequisite + if( this._attributes.shader ) return; + var terrain = this; // method binded to terrain object + + // canvas for image processing + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext("2d"); + var img = texture.image; + // canvas takes the polygon dimensions | vertices = faces +1 for every side + var width = terrain.geometry.parameters.widthSegments + 1; + var height = terrain.geometry.parameters.heightSegments + 1; + var terrainScale = terrain._attributes.scale; //terrain.material.uniforms.uDisplacementScale.value; + var terrainBias = - terrain._attributes.scale/2; //terrain.material.uniforms.uDisplacementBias.value; + var size = terrain.geometry.parameters.width; // option? + //var scale = size / width; + // - main data + var vertices = terrain.geometry.attributes.position; + var d = []; + + canvas.width = width; + canvas.height = height; + + ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height); + // scale image to polygons + //ctx.scale(width/img.width, height/img.height); // already resized from drawImage + // loop through image data + var data = ctx.getImageData(0,0, width, height).data; + + for( var i in data ){ + if ( i % 4 ) continue; // pick only every forth - item size 4: RGBA + // OLD method: calculating the whole vector + //var z = ( Math.floor(i/width) ) - (size/2); + //var x = (i - ( Math.floor(i/width)*width)) - (size/2); + //var y = (data[i]/255 * terrainScale) + terrainBias; // normalize height to a fraction + //vertices.push( new THREE.Vector3(x, y, z) ); + //vertices.push( (data[i]/255 * terrainScale) + terrainBias ); + + // updating the z axis of the vertices directly + var z = ( (data[i]/255 * terrainScale) + terrainBias ); // terrain has z axis up... + // instead combine all colors? + //var decimal = (data[i]+data[i+1]+data[i+2])/(3*255); + d.push( z ); + vertices.setZ( i/4, z ); + } + + // update the vertices in the terrain object + terrain.geometry.attributes.position.needsUpdate = true; +}; + +Terrain.prototype.shaderTexture = function(type, img){ + + var texture = utils.textureLoader( img ); //this.webglTexture( img ); + + if( type == 'heightmap' ){ + var terrainScale = this._attributes.scale; // modified through an option + + this.material.uniforms.tDisplacement.value = texture; + this.material.uniforms.uDisplacementScale.value = terrainScale; + this.material.uniforms.uDisplacementBias.value = - terrainScale/2; + // heightmap also the second diffuse map? + //var diffuseTexture2 = texture; + //diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; + //this.material.uniforms.tDiffuse2.value = diffuseTexture2; + //this.material.uniforms.enableDiffuse2.value = true; + } + if( type == 'diffuse' ){ + + texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + + this.material.uniforms.tDiffuse1.value = texture; + this.material.uniforms.enableDiffuse1.value = true; + + } + if( type == 'specular' ){ + //var texture = this.webglTexture( img ); + //texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + + this.material.uniforms.tSpecular.value = texture; + this.material.uniforms.enableSpecular.value = true; + + } + // always update vertices... + // why don't these work with ShaderTerrain? + //this.geometry.attributes.position.needsUpdate = true; + //this.geometry.verticesNeedUpdate = true; + + /* + leftovers ( normal and detail textures) + + //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; + //uniformsTerrain[ "tNormal" ].value = heightmapTexture; + //uniformsTerrain[ "uNormalScale" ].value = 1; + //uniformsTerrain[ "tDetail" ].value = detailTexture; + //uniformsTerrain[ "uShininess" ].value = 30; + */ + + return texture; +}; + + +Terrain.prototype.basicTexture = function(type, img){ + var texture; + + if( type == 'heightmap' ){ + texture = utils.textureLoader( img, 'heightmap-loaded' ); + // texture isn't loaded in material, just used in computeElevation + // monitoring event + var self = this; + // remove pre-existing event... + var cb = function(e){ + self.computeElevation( texture ); + // trigger element event + self.$el.trigger('heightmap-updated'); + }; + document.removeEventListener('heightmap-loaded', cb); + document.addEventListener('heightmap-loaded', cb, false); + } + if( type == 'diffuse' ){ + texture = utils.textureLoader( img ); + var repeat = this._attributes.repeat; + // dirty re-write + texture.wrapT = THREE.RepeatWrapping; + texture.wrapS = THREE.RepeatWrapping; + texture.repeat.set( repeat, repeat ); + //texture.offset.set( 1, 1 ); + texture.needsUpdate = true; + + this.material.map = texture; + } + if( type == 'specular' ){ + // not supported? + } + + return texture; +}; diff --git a/lib/utils.js b/lib/utils.js index a270943..6f43186 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -25,6 +25,7 @@ Three.prototype.setProperties = function() { }; }; + // internal object of utilities var utils = { // Convert Dashed to CamelCase @@ -33,12 +34,287 @@ var utils = { return string.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); }, + // Based on undercore _.delay + delay: function (fn, timeout) { + timeout = timeout || 0; + var args = Array.prototype.slice.call(arguments, 2); + return setTimeout(function () { return fn.apply(null, args); }, timeout); + }, + // unique (but not universal) id generator unid: function(){ return Math.round( Math.random() * (new Date()).getTime() ); + }, + + now: function(){ + if( !performance || !performance.now ) return new Date().getTime(); + return Math.floor( performance.now() ); // are the fractions of a millisecond significant? + }, + // returns a 1x1 invisible texture + // used when we have no texture data + pixel: function(){ + var image = document.createElement( 'img' ); + var texture = new THREE.Texture( image ); + // not neeeded? + image.addEventListener( 'load', function ( event ) { + texture.needsUpdate = true; + } ); + image.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; + return texture; + }, + // texture loader (support legacy) + textureLoader: function( image, eventName ){ + var map = this.pixel(); + + if( THREE.REVISION < 70 ){ + // FIX: support base64 images + if( image.search(";base64,") > -1 ) image = image.replace(/data:image\/(png|jpg|jpeg);base64,/, ""); + map = THREE.ImageUtils.loadTexture( image ); + } else { + (new THREE.TextureLoader()).load(image, function( texture ){ + // update image source on the original map + map.image = texture.image; + map.needsUpdate = true; + // trigger event + if( eventName ){ + var event = new Event(eventName); + document.dispatchEvent( event ); + } + }); + } + // return immediantely (update asychronously) + return map; + }, + + // Convert the color information of an image to height data + // source: http://oos.moxiecode.com/js_webgl/terrain/index.html + getHeightData: function(img) { + var canvas = document.createElement( 'canvas' ); + canvas.width = 128; + canvas.height = 128; + var context = canvas.getContext( '2d' ); + + var size = 128 * 128, data = new Float32Array( size ); + + context.drawImage(img,0,0); + + for ( var i = 0; i < size; i ++ ) { + data[i] = 0; + } + + var imgd = context.getImageData(0, 0, 128, 128); + var pix = imgd.data; + + var j=0; + for (var k = 0, n = pix.length; k < n; k += (4)) { + var all = pix[k]+pix[k+1]+pix[k+2]; + data[j++] = all/30; + } + + return data; + }, + + getFile: function (url) { + // if already downloaded return the same content + if( files[url] ) return files[url]; + files[url] = $.ajax({ + type : "GET", + url : url, + dataType : "string", + async : false, + success : function(data) { + files[url] = data; + } + }).responseText; + return files[url]; + }, + + //THREE.BufferGeometryUtils + // @author mrdoob / http://mrdoob.com/ + computeTangents: function ( geometry ) { + + var index = geometry.index; + var attributes = geometry.attributes; + + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) + + if ( index === null || + attributes.position === undefined || + attributes.normal === undefined || + attributes.uv === undefined ) { + + console.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' ); + return; + + } + + var indices = index.array; + var positions = attributes.position.array; + var normals = attributes.normal.array; + var uvs = attributes.uv.array; + + var nVertices = positions.length / 3; + + if ( attributes.tangent === undefined ) { + + geometry.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); + + } + + var tangents = attributes.tangent.array; + + var tan1 = [], tan2 = []; + + for ( var k = 0; k < nVertices; k ++ ) { + + tan1[ k ] = new THREE.Vector3(); + tan2[ k ] = new THREE.Vector3(); + + } + + var vA = new THREE.Vector3(), + vB = new THREE.Vector3(), + vC = new THREE.Vector3(), + + uvA = new THREE.Vector2(), + uvB = new THREE.Vector2(), + uvC = new THREE.Vector2(), + + sdir = new THREE.Vector3(), + tdir = new THREE.Vector3(); + + function handleTriangle( a, b, c ) { + + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); + + uvA.fromArray( uvs, a * 2 ); + uvB.fromArray( uvs, b * 2 ); + uvC.fromArray( uvs, c * 2 ); + + var x1 = vB.x - vA.x; + var x2 = vC.x - vA.x; + + var y1 = vB.y - vA.y; + var y2 = vC.y - vA.y; + + var z1 = vB.z - vA.z; + var z2 = vC.z - vA.z; + + var s1 = uvB.x - uvA.x; + var s2 = uvC.x - uvA.x; + + var t1 = uvB.y - uvA.y; + var t2 = uvC.y - uvA.y; + + var r = 1.0 / ( s1 * t2 - s2 * t1 ); + + sdir.set( + ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r + ); + + tdir.set( + ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r + ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + var groups = geometry.groups; + var group, start, count; + + if ( groups.length === 0 ) { + + groups = [ { + start: 0, + count: indices.length + } ]; + + } + + for ( var j = 0; j < groups.length; ++ j ) { + + group = groups[ j ]; + + start = group.start; + count = group.count; + + for ( var g = start, gl = start + count; g < gl; g += 3 ) { + + handleTriangle( + indices[ g + 0 ], + indices[ g + 1 ], + indices[ g + 2 ] + ); + + } + + } + + var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); + var n = new THREE.Vector3(), n2 = new THREE.Vector3(); + var w, t, test; + + function handleVertex( v ) { + + n.fromArray( normals, v * 3 ); + n2.copy( n ); + + t = tan1[ v ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( n2, t ); + test = tmp2.dot( tan2[ v ] ); + w = ( test < 0.0 ) ? - 1.0 : 1.0; + + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; + + } + + for ( var l = 0; l < groups.length; ++ l ) { + + group = groups[ l ]; + + start = group.start; + count = group.count; + + for ( var i = start, il = start + count; i < il; i += 3 ) { + + handleVertex( indices[ i + 0 ] ); + handleVertex( indices[ i + 1 ] ); + handleVertex( indices[ i + 2 ] ); + + } + + } + } + }; + /** * jQuery.toSelector - get the selector text of a jQuery object * https://gist.github.com/tracend/6402299 diff --git a/lib/webgl.js b/lib/webgl.js index fe2f9e5..c318d24 100644 --- a/lib/webgl.js +++ b/lib/webgl.js @@ -33,6 +33,9 @@ Three.prototype.webgl = function( options, callback ){ case "cylinder": el = this.webglCylinder( options ); break; + case "sprite": + el = this.webglSprite( options ); + break; case "terrain": el = this.webglTerrain( options ); break; @@ -51,19 +54,22 @@ fn.webgl = { }; -Three.prototype.webglScene = function( options ){ +Three.prototype.webglScene = function( attributes ){ var defaults = { id : false }; - var settings = $.extend(defaults, options); + var options = $.extend(defaults, attributes); var scene = new THREE.Scene(); // save in the objects bucket this.scenes[scene.id] = scene; + // save attributes + scene._attributes = options; + return scene; }; @@ -89,6 +95,9 @@ Three.prototype.webglCamera = function( attributes ){ camera = new THREE.PerspectiveCamera( options.fov, options.aspect, options.near, options.far ); } + // save attributes + camera._attributes = options; + return camera; }; @@ -133,13 +142,13 @@ Three.prototype.webglMaterial = function( attributes ){ if( shader.uniforms ) settings.uniforms = THREE.UniformsUtils.clone(shader.uniforms); if( shader.vertexShader ) settings.vertexShader = shader.vertexShader; if( shader.fragmentShader ) settings.fragmentShader = shader.fragmentShader; - if( options.map && shader.uniforms) settings.uniforms.texture.texture= THREE.ImageUtils.loadTexture( options.map ); + if( options.map && shader.uniforms) settings.uniforms.texture.texture= utils.textureLoader( options.map ); material = new THREE.ShaderMaterial( settings ); } else { // create a basic material settings = {}; - if( options.map ) settings.map = THREE.ImageUtils.loadTexture( options.map ); + if( options.map ) settings.map = utils.textureLoader( options.map ); if( options.color && !options.map ) settings.color = options.color; if( options.wireframe ) settings.wireframe = options.wireframe; material = new THREE.MeshBasicMaterial( settings ); @@ -190,7 +199,9 @@ Three.prototype.webglPlane = function( attributes ){ var options = $.extend(defaults, attributes); - var geometry = new THREE.PlaneGeometry( options.width, options.height ); + var Constructor = ( options.buffer ) ? THREE.PlaneBufferGeometry : THREE.PlaneGeometry; + + var geometry = new Constructor( options.width, options.height ); // make this optional? geometry.dynamic = true; var material = new THREE.MeshBasicMaterial( { color: options.color, wireframe: options.wireframe } ); @@ -199,6 +210,9 @@ Three.prototype.webglPlane = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; @@ -228,6 +242,9 @@ Three.prototype.webglSphere = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; @@ -245,7 +262,7 @@ Three.prototype.webglCube = function( attributes ){ var options = $.extend(defaults, attributes); - var geometry = new THREE.CubeGeometry( options.width, options.height, options.depth); + var geometry = new THREE.BoxGeometry( options.width, options.height, options.depth); // make this optional? geometry.dynamic = true; var material = new THREE.MeshBasicMaterial( { color: options.color, wireframe: options.wireframe } ); @@ -254,6 +271,9 @@ Three.prototype.webglCube = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; @@ -283,92 +303,81 @@ Three.prototype.webglCylinder = function( attributes ){ // set attributes if( options.id ) mesh.name = options.id; + // save attributes + mesh._attributes = options; + return mesh; }; -Three.prototype.webglTerrain = function( attributes ){ - // assuming that terrain is generated from a heightmap - support class="mesh" in the future? - var terrain; - - var defaults = { - - }; - - - this.active.scene.add( new THREE.AmbientLight( 0x111111 ) ); - - directionalLight = new THREE.DirectionalLight( 0xffffff, 1.15 ); - directionalLight.position.set( 500, 2000, 0 ); - this.active.scene.add( directionalLight ); - +Three.prototype.webglSprite = function( attributes ){ - var plane = new THREE.PlaneGeometry( 6000, 6000, 256, 256 ); + // sprite - plane.computeFaceNormals(); - plane.computeVertexNormals(); - plane.computeTangents(); + attributes = attributes || {}; - // - - var terrainShader = THREE.ShaderTerrain.terrain; - - uniformsTerrain = THREE.UniformsUtils.clone( terrainShader.uniforms ); - /* - var heightmapTexture = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); - var diffuseTexture1 = THREE.ImageUtils.loadTexture( "assets/img/terrain/diffuse.jpg" ); - var diffuseTexture2 = THREE.ImageUtils.loadTexture( "assets/img/terrain/heightmap.png" ); - var specularMap = THREE.ImageUtils.loadTexture( "assets/img/terrain/specular.png"); - - diffuseTexture1.wrapS = diffuseTexture1.wrapT = THREE.RepeatWrapping; - diffuseTexture2.wrapS = diffuseTexture2.wrapT = THREE.RepeatWrapping; - //detailTexture.wrapS = detailTexture.wrapT = THREE.RepeatWrapping; - specularMap.wrapS = specularMap.wrapT = THREE.RepeatWrapping; - - //uniformsTerrain[ "tNormal" ].value = heightmapTexture; - //uniformsTerrain[ "uNormalScale" ].value = 1; - - uniformsTerrain[ "tDisplacement" ].value = heightmapTexture; - uniformsTerrain[ "uDisplacementScale" ].value = 375; + var defaults = { + map : false, + color: 0xffffff, + fog: false, + transparent: true, + opacity: 1 + //alignment: THREE.SpriteAlignment.topLeft + //useScreenCoordinates: true + //scene: this.active.scene + }; - uniformsTerrain[ "tDiffuse1" ].value = diffuseTexture1; - uniformsTerrain[ "tDiffuse2" ].value = diffuseTexture2; - uniformsTerrain[ "tSpecular" ].value = specularMap; - //uniformsTerrain[ "tDetail" ].value = diffuseTexture1; + var options = $.extend(defaults, attributes); + // FIX map + if ( attributes.map ) { + options.map = utils.textureLoader( attributes.map ); + } else { + //placeholder pixel + options.map = utils.pixel(); + } + // save id (name) for later + var name = options.id; + // FIX: delete unsupported options (why not define the options supported?) + delete options.id; + delete options['class']; + delete options.el; + delete options.style; - uniformsTerrain[ "enableDiffuse1" ].value = true; - uniformsTerrain[ "enableDiffuse2" ].value = true; - uniformsTerrain[ "enableSpecular" ].value = true; + var material = new THREE.SpriteMaterial( options ); + material.scaleByViewport = true; + material.blending = THREE.AdditiveBlending; - uniformsTerrain[ "uDiffuseColor" ].value.setHex( 0xffffff ); - uniformsTerrain[ "uSpecularColor" ].value.setHex( 0xffffff ); - uniformsTerrain[ "uAmbientColor" ].value.setHex( 0x111111 ); + var sprite = new THREE.Sprite( material ); + // save name (id) back to the object + sprite.name = name; - //uniformsTerrain[ "uShininess" ].value = 30; + // save attributes + sprite._attributes = options; - uniformsTerrain[ "uRepeatOverlay" ].value.set( 6, 6 ); - */ + return sprite; - uniformsTerrain.uDiffuseColor.value.setHex( 0xffffff ); - uniformsTerrain.uSpecularColor.value.setHex( 0xffffff ); - uniformsTerrain.uAmbientColor.value.setHex( 0x111111 ); + }; - uniformsTerrain.uRepeatOverlay.value.set( 6, 6 ); - // +Three.prototype.webglTerrain = function( attributes ){ + // fallbacks + attributes = attributes || {}; - // fog is expensive - disable for now... - var material = new THREE.ShaderMaterial( { - uniforms : uniformsTerrain, - vertexShader : terrainShader.vertexShader, - fragmentShader : terrainShader.fragmentShader, - lights : true, - fog : false - }); + var defaults = { + lights: true, + fog: true, + scale: 256, + width: 6000, + height: 6000, + resolution: 256, + shader: true, + repeat: 1 // diffuse map repeat + }; - terrain = new THREE.Mesh( plane, material ); + var options = $.extend(defaults, attributes); - // save type as part of the mesh - terrain.type = "terrain"; + // logic contained + // assuming that terrain is generated from a heightmap - support class="mesh" in the future? + var terrain = (new Terrain( options )).terrain; //terrain.visible=false; this.active.scene.add( terrain ); diff --git a/package.json b/package.json index fc45659..87b1947 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { - "private" : true, "name" : "jquery.three", - "version" : "0.8.0", + "version" : "0.9.8", "author" : "makesites", "homepage" : "http://github.com/makesites/jquery-three", "description" : "jQuery Three() - jQuery extension with 3D methods (using Three.js)", + "keywords": ["jquery-plugin"], "licenses" : [ { "type": "MIT License", @@ -16,8 +16,8 @@ }, "devDependencies" : { "commander" : "~0.5", - "jshint" : "~0.9", - "uglify-js" : "2.x", + "jshint" : "jshint@2.9.1", + "uglify-js" : "2.6.2", "hbs" : "~1.0" } } diff --git a/readme.md b/readme.md index 8c3c2b0..2d10c38 100644 --- a/readme.md +++ b/readme.md @@ -1,25 +1,41 @@ -## jQuery Three +# jQuery Three -A plugin / extension of the jQuery API for 3d objects (using Three.js) +A plugin / extension of the jQuery API for 3d objects (using Three.js) +jQuery Three was developed to bridge the gap between WebGL and the DOM by using existing conventions web designers are already familiar with. -## Introduction +Effectively it provides a higher level api that abstracts Three.js methods to known common conventions from regular web development. + + +## Dependencies + +* jQuery v2.x +* THREE.js rev.75 -jQuery Three was developed to bridge the gap between WebGL and the DOM by using existing conventions web designers are already familiar with. -Effectively it provides a higher level api that abstracts Three.js methods to known common conventions from web development. +## Examples + +* [Skybox](http://makesites.org/jquery-three/examples/skybox.html) +* [Skysphere](http://makesites.org/jquery-three/examples/skysphere.html) +* [First Person controls](http://makesites.org/jquery-three/examples/fps.html) +* [Earth Texture](http://makesites.org/jquery-three/examples/earth.html) +* [Append with Handlebars,js](http://makesites.org/jquery-three/examples/handlebars.html) +* [Binary Loader](http://makesites.org/jquery-three/examples/binary.html) +* [Sprite animation](http://makesites.org/jquery-three/examples/sprite.html) +* [VR shader](http://makesites.org/jquery-three/examples/vr.html) +* [Water shader](http://makesites.org/jquery-three/examples/water.html) ## Install -Get the latest (stable) version using bower: +Get the latest (stable) version using bower: ``` bower install jquery.three ``` ## Usage -Enable 3D actions on any container using: +Enable 3D actions on any container using: ``` $("container").three( options, callback ); @@ -28,6 +44,16 @@ $("container").three( options, callback ); Read the [wiki](https://github.com/makesites/jquery-three/wiki) docs for more details on the [methods](https://github.com/makesites/jquery-three/wiki/Methods) and [tag support](https://github.com/makesites/jquery-three/wiki/Tags). +## Options + +There are the setup options used when initiating the ```.three()``` method: + +* **alpha**: (boolean, default: true) Renders the WebGL canvas transparent so you can stack other elements behind it. +* **deps**: (object, default: {}) Listing dependency scripts loaded as extensions of THREE.js +* **paused**: (boolean, default: false) Start with a paused loop - or set as a flag to pause anytime. +* **watch**: (boolean, default: false) If set it monitors the DOM for updates and syncs the changes with THREE.js + + ## Credits Created by [Makis Tracend](http://github.com/tracend) [ [full list of contributors](https://github.com/makesites/jquery-three/graphs/contributors) ] diff --git a/three.jquery.json b/three.jquery.json index fc5f2bb..6a14a3f 100644 --- a/three.jquery.json +++ b/three.jquery.json @@ -1,6 +1,6 @@ { "name": "three", - "version": "0.8.0", + "version": "0.9.8", "title": "jQuery Three", "description": "A plugin / extension of the jQuery API for 3d objects (using Three.js)", "keywords": [