├── README.md ├── areaLight.html ├── basicTexture.html ├── card.html ├── dynamic.html ├── images ├── basicTexture.gif ├── bathroom-normal.jpg ├── bathroom.jpg ├── brick-wall.jpg ├── darker_wood.jpg ├── dmngp.gif ├── dynamic.gif ├── floor-wood.jpg ├── lineMaterial.gif ├── meshMaterial.gif ├── metal-floor-normal.jpg ├── metal-floor.jpg ├── metal-rust.jpg ├── negx.jpg ├── negy.jpg ├── negz.jpg ├── normalMap.gif ├── plaster-diffuse.jpg ├── plaster-normal.jpg ├── plaster.jpg ├── pointCloud.gif ├── posx.jpg ├── posy.jpg ├── posz.jpg ├── raindrop.png ├── rainyScene.gif ├── snowflake1.png ├── snowflake2.png ├── snowflake3.png ├── snowflake4.png ├── snowflake5.png ├── snowyScene.gif ├── stone-bump.jpg ├── stone.jpg ├── textGeometry.jpg ├── weave-bump.jpg ├── weave.jpg └── wood-2.jpg ├── libs ├── CanvasRenderer.js ├── CopyShader.js ├── EffectComposer.js ├── FXAAShader.js ├── MaskPass.js ├── OrbitControls.js ├── Projector.js ├── RenderPass.js ├── ShaderDeferred.js ├── ShaderPass.js ├── WebGLDeferredRenderer.js ├── ammo.js ├── chroma.js ├── dat.gui.js ├── fonts │ ├── bitstream_vera_sans_mono_roman.typeface.js │ ├── helvetiker_bold.typeface.js │ └── helvetiker_regular.typeface.js ├── physi.js ├── physijs_worker.js ├── stats.js └── three.js ├── lineMaterial.html ├── meshMaterial.html ├── normalMap.html ├── pointCloud.html ├── rainyScene.html ├── snowyScene.html └── textGeometry.html /README.md: -------------------------------------------------------------------------------- 1 | # ThreejsLab 2 | 3 | 记录自己学习的一个过程。 4 | 5 | 所有项目均使用了2个开发环境用的测试辅助库: 6 | * stats.js性能监视器来监视3d性能,详见各个demo左上角(它的介绍在 ) 7 | * GUI库( dat.gui.js ),详见各个demo右上角,用户可进行控制操作( ) 8 | 9 | ## Demo: 10 | (所有demo页右上角有`GUI渲染控制器`,可通过调节它来控制页面的3d效果变化) 11 | 12 | 13 | 1、[平面光3d光源](http://imzouyang.com/project/threejs/areaLight.html)(该页面右上角各GUI参数可控制3d变化) 14 | * 该光源:属于复杂光源、使用它可以定义一个发光的矩形、此光源不再Three.js标准库中,而在它的扩展库中,它不能再使用渲染器WebGLRenderer对象了,而是使用渲染器WebGLDeferredRenderer,俗称延迟渲染器(使用此渲染器还需引入其他js,详见demo,才能使用延迟渲染器),该渲染器专门处理复杂光源。 15 |

16 | 17 | 2、[几何体及网格](http://imzouyang.com/project/threejs/meshMaterial.html) 18 | * 注释:Mesh几何体为groundGeom;通过MeshNormalMaterial作为几何体材质展示旋转色变(MeshNormalMaterial :通过计算法向颜色来决定每个面颜色的材质)。
19 | ![几何体及网格示意图](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/meshMaterial.gif) 20 |

21 | 22 | 3、[gosper曲线](http://imzouyang.com/project/threejs/lineMaterial.html) 23 | * gosper(),该函数返回的是一个gosper曲线。wiki有相关介绍:(
24 | ![osper曲线示意图](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/lineMaterial.gif) 25 |

26 | 27 | 4、[创建三维文本](http://imzouyang.com/project/threejs/textGeometry.html) 28 | * 实例化new THREE.TextGeometry(),并操作相关属性即可
29 | ![创建三维文本示意图](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/textGeometry.jpg) 30 |

31 | 32 | 5、[创建粒子材质](http://imzouyang.com/project/threejs/pointCloud.html) 33 | * 实例化new THREE.ParticleBasicMaterial(),创建粒子材质,该材质有9个可控属性
34 | ![创建粒子材质示意图](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/pointCloud.gif) 35 |

36 | 37 | 6、[创建下雨3d动画](http://imzouyang.com/project/threejs/rainyScene.html) 38 | * 使用ParticleBasicMaterial的map属性来加载外部图片;并使用 THREE.AdditiveBlending融合模式,此模式会在画新像素时,背景像素的颜色会被添加到新像素上
39 | ![创建下雨3d动画](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/rainyScene.gif) 40 |

41 | 42 | 7、[创建下雪3d动画](http://imzouyang.com/project/threejs/snowyScene.html)
43 | ![创建下雨3d动画](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/snowyScene.gif) 44 |

45 | 46 | 8、[基础材质应用](http://imzouyang.com/project/threejs/basicTexture.html) 47 | * 使用THREE.ImageUtils.loadTexture 来加载一个外部图片 48 | * threejs内有2种材质对光源产生反应:MeshLamberMaterial 和 MeshPhongMaterial,MeshPhongMaterial一般用于创建光亮表面
49 | ![基础材质应用](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/basicTexture.gif) 50 |

51 | 52 | 9、[基础材质应用2](http://imzouyang.com/project/threejs/normalMap.html) 53 | * 使用THREE.UniformsUtils的clone方法 54 | * 创建立方体BoxGeometry
55 | ![基础材质应用2](https://github.com/zouyang1230/ThreejsDemos/raw/master/images/normalMap.gif) 56 |

57 | 58 | 10、[构建真实动态3d场景](http://imzouyang.com/project/threejs/dynamic.html)
59 | * 拖动(滚动)鼠标可360度查看全景,整个场景是由6张jpg图片够成。 60 | ![构建真实动态3d场景](c) 61 |

62 | 63 | 64 | # 以下是一些记录: 65 | 1、Three.js本质上是Webgl,如果你的浏览器不支持Webgl,那么肯定你就不能完整的运行Three.js。支持Webgl的浏览器很多,例如Chrome、FireFox、360安 全浏览器6.0等,而IE浏览器对Webgl标准的支持就不太好。
66 | 67 | 2、在Three.js中,要渲染物体到网页中,我们需要3个组件:场景(scene)、相机(camera)和渲染器(renderer)。有了这三样东西,才能将物体渲染到网页中去。 68 | ```javascript 69 | var scene = new THREE.Scene(); // 场景 70 | 71 | var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);// 透视相机 72 | 73 | var renderer = new THREE.WebGLRenderer(); // 渲染器 74 | 75 | renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器的大小为窗口的内宽度,也就是内容区的宽度 76 | document.body.appendChild(renderer.domElement); 77 | ``` 78 | 79 | 3、场景与相机 80 | * 1)场景只有一种,用THREE.Scene来表示,通过new THREE.Scene(); 81 | * 2)相机有2种,决定了场景中那个角度的景色会显示出来。 82 | * 透视投影相机:THREE.PerspectiveCamera 83 | * 正投影相机:THREE.OrthographicCamera ( left, right, top, bottom, near, far ) 里面的参数分别代表各个面与相机镜头中心点的垂直距离。 84 | 85 | 4、Threejs使用的是右手坐标系,这源于opengl默认情况下,也是右手坐标系。 86 | 87 | 5、和three.js紧密结合的动画引擎是Tween.js,可以在这里下载 https://github.com/sole 88 | ``` 89 | 1)引入js
90 | 2)构建对象:
91 | function initTween() 92 | { 93 | new TWEEN.Tween( mesh.position) 94 | .to( { x: -400 }, 3000 ).repeat( Infinity ).start(); 95 | } 96 | TWEEN.Tween的构造函数接受的是要改变属性的对象,这里传入的是mesh的位置。 97 | Tween的任何一个函数返回的都是自身,所以可以用串联的方式直接调用各个函数。 98 | to函数,接受两个参数: 99 | 第一个参数是一个集合,里面存放的键值对,键x表示mesh.position的x属性,值-400表示,动画结束的时候需要移动到的位置。 100 | 第二个参数,是完成动画需要的时间,这里是3000ms。 101 | repeat( Infinity )表示重复无穷次,也可以接受一个整形数值,例如5次。 102 | Start表示开始动画,默认情况下是匀速的将mesh.position.x移动到-400的位置。 103 | 3)渲染函数中执行:TWEEN.update(); 104 | ``` 105 | 106 | 6、Threejs中的各种光源: 107 | * 光源基类 THREE.Light ( hex ) 108 | ``` 109 | 参数hex,接受一个16进制的颜色值。例如要定义一种红色的光源,我们可以这样来定义: 110 | var redLight = new THREE.Light(0xFF0000); 111 | ``` 112 | * 由基类派生出来的其他种类光源 113 | 114 | 7、环境光
115 | 是经过多次反射而来的光称为环境光,无法确定其最初的方向。环境光是一种无处不在的光。环境光源放出的光线被认为来自任何方向。因此,当你仅为场景指定环境光时,所有的物体无论法向量如何,都将表现为同样的明暗程度。 (这是因为,反射光可以从各个方向进入您的眼睛) 116 | 构造函数 : THREE.AmbientLight( hex ) 117 | var light = new THREE.AmbientLight( 0xff0000 ); 118 | scene.add( light ); 119 | 120 | 8、聚光灯
121 | 构造:THREE.SpotLight( hex, intensity, distance, angle, exponent ) 122 | 这种光源的光线从一个锥体中射出,在被照射的物体上产生聚光的效果。 123 | 使用这种光源需要指定光的射出方向以及锥体的顶角α。 124 | 125 | 126 | 9、方向光(平行光) 127 | * 它是一组没有衰减的平行的光线,类似太阳光的效果。 128 | * THREE.DirectionalLight = function ( hex, intensity ) 129 | 130 | 10、点光源 131 | * 点光源的特点是发光部分为一个小圆面,近似一个点 132 | * 是理想化为质点的向四面八方发出光线的光源。点光源是抽象化了的物理概念,为了把物理问题的研究简单化。就像平时说的光滑平面,质点,无空气阻力一样,点光源在现实中也是不存在的,指的是从一个点向周围空间均匀发光的光源。 133 | * 点光源不会产生投影,原因是光源是朝所有方向发出,计算阴影对GPU来说,负担太重。 134 | 135 | ### 省略一大坨 136 | ``` 137 | 更多详细笔记,如有需要的童鞋可以私信我邮箱 138 | ``` 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /areaLight.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Area Light 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 |
29 |
30 |
31 |
32 | 33 | 203 | 204 | -------------------------------------------------------------------------------- /basicTexture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 基础textures 7 | 8 | 9 | 10 | 11 | 17 | 18 | 19 | 20 |
21 |
22 |
23 |
24 | 25 | 118 | 119 | -------------------------------------------------------------------------------- /card.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | Physijs 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 195 | 196 | 197 | 198 |
199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /dynamic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dynamic 5 | 6 | 7 | 8 | 14 | 15 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /images/basicTexture.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/basicTexture.gif -------------------------------------------------------------------------------- /images/bathroom-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/bathroom-normal.jpg -------------------------------------------------------------------------------- /images/bathroom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/bathroom.jpg -------------------------------------------------------------------------------- /images/brick-wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/brick-wall.jpg -------------------------------------------------------------------------------- /images/darker_wood.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/darker_wood.jpg -------------------------------------------------------------------------------- /images/dmngp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/dmngp.gif -------------------------------------------------------------------------------- /images/dynamic.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/dynamic.gif -------------------------------------------------------------------------------- /images/floor-wood.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/floor-wood.jpg -------------------------------------------------------------------------------- /images/lineMaterial.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/lineMaterial.gif -------------------------------------------------------------------------------- /images/meshMaterial.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/meshMaterial.gif -------------------------------------------------------------------------------- /images/metal-floor-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/metal-floor-normal.jpg -------------------------------------------------------------------------------- /images/metal-floor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/metal-floor.jpg -------------------------------------------------------------------------------- /images/metal-rust.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/metal-rust.jpg -------------------------------------------------------------------------------- /images/negx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/negx.jpg -------------------------------------------------------------------------------- /images/negy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/negy.jpg -------------------------------------------------------------------------------- /images/negz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/negz.jpg -------------------------------------------------------------------------------- /images/normalMap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/normalMap.gif -------------------------------------------------------------------------------- /images/plaster-diffuse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/plaster-diffuse.jpg -------------------------------------------------------------------------------- /images/plaster-normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/plaster-normal.jpg -------------------------------------------------------------------------------- /images/plaster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/plaster.jpg -------------------------------------------------------------------------------- /images/pointCloud.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/pointCloud.gif -------------------------------------------------------------------------------- /images/posx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/posx.jpg -------------------------------------------------------------------------------- /images/posy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/posy.jpg -------------------------------------------------------------------------------- /images/posz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/posz.jpg -------------------------------------------------------------------------------- /images/raindrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/raindrop.png -------------------------------------------------------------------------------- /images/rainyScene.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/rainyScene.gif -------------------------------------------------------------------------------- /images/snowflake1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/snowflake1.png -------------------------------------------------------------------------------- /images/snowflake2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/snowflake2.png -------------------------------------------------------------------------------- /images/snowflake3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/snowflake3.png -------------------------------------------------------------------------------- /images/snowflake4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/snowflake4.png -------------------------------------------------------------------------------- /images/snowflake5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/snowflake5.png -------------------------------------------------------------------------------- /images/snowyScene.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/snowyScene.gif -------------------------------------------------------------------------------- /images/stone-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/stone-bump.jpg -------------------------------------------------------------------------------- /images/stone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/stone.jpg -------------------------------------------------------------------------------- /images/textGeometry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/textGeometry.jpg -------------------------------------------------------------------------------- /images/weave-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/weave-bump.jpg -------------------------------------------------------------------------------- /images/weave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/weave.jpg -------------------------------------------------------------------------------- /images/wood-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyang1230/ThreejsLab/b4c9ecf87f2695c201e72d3cc9af7ecf662ec499/images/wood-2.jpg -------------------------------------------------------------------------------- /libs/CanvasRenderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.SpriteCanvasMaterial = function ( parameters ) { 6 | 7 | THREE.Material.call( this ); 8 | 9 | this.type = 'SpriteCanvasMaterial'; 10 | 11 | this.color = new THREE.Color( 0xffffff ); 12 | this.program = function ( context, color ) {}; 13 | 14 | this.setValues( parameters ); 15 | 16 | }; 17 | 18 | THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); 19 | 20 | THREE.SpriteCanvasMaterial.prototype.clone = function () { 21 | 22 | var material = new THREE.SpriteCanvasMaterial(); 23 | 24 | THREE.Material.prototype.clone.call( this, material ); 25 | 26 | material.color.copy( this.color ); 27 | material.program = this.program; 28 | 29 | return material; 30 | 31 | }; 32 | 33 | // 34 | 35 | THREE.CanvasRenderer = function ( parameters ) { 36 | 37 | console.log( 'THREE.CanvasRenderer', THREE.REVISION ); 38 | 39 | var smoothstep = THREE.Math.smoothstep; 40 | 41 | parameters = parameters || {}; 42 | 43 | var _this = this, 44 | _renderData, _elements, _lights, 45 | _projector = new THREE.Projector(), 46 | 47 | _canvas = parameters.canvas !== undefined 48 | ? parameters.canvas 49 | : document.createElement( 'canvas' ), 50 | 51 | _canvasWidth = _canvas.width, 52 | _canvasHeight = _canvas.height, 53 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), 54 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), 55 | 56 | _viewportX = 0, 57 | _viewportY = 0, 58 | _viewportWidth = _canvasWidth, 59 | _viewportHeight = _canvasHeight, 60 | 61 | _context = _canvas.getContext( '2d', { 62 | alpha: parameters.alpha === true 63 | } ), 64 | 65 | _clearColor = new THREE.Color( 0x000000 ), 66 | _clearAlpha = 0, 67 | 68 | _contextGlobalAlpha = 1, 69 | _contextGlobalCompositeOperation = 0, 70 | _contextStrokeStyle = null, 71 | _contextFillStyle = null, 72 | _contextLineWidth = null, 73 | _contextLineCap = null, 74 | _contextLineJoin = null, 75 | _contextLineDash = [], 76 | 77 | _camera, 78 | 79 | _v1, _v2, _v3, _v4, 80 | _v5 = new THREE.RenderableVertex(), 81 | _v6 = new THREE.RenderableVertex(), 82 | 83 | _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 84 | _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, 85 | 86 | _color = new THREE.Color(), 87 | _color1 = new THREE.Color(), 88 | _color2 = new THREE.Color(), 89 | _color3 = new THREE.Color(), 90 | _color4 = new THREE.Color(), 91 | 92 | _diffuseColor = new THREE.Color(), 93 | _emissiveColor = new THREE.Color(), 94 | 95 | _lightColor = new THREE.Color(), 96 | 97 | _patterns = {}, 98 | 99 | _image, _uvs, 100 | _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, 101 | 102 | _clipBox = new THREE.Box2(), 103 | _clearBox = new THREE.Box2(), 104 | _elemBox = new THREE.Box2(), 105 | 106 | _ambientLight = new THREE.Color(), 107 | _directionalLights = new THREE.Color(), 108 | _pointLights = new THREE.Color(), 109 | 110 | _vector3 = new THREE.Vector3(), // Needed for PointLight 111 | _centroid = new THREE.Vector3(), 112 | _normal = new THREE.Vector3(), 113 | _normalViewMatrix = new THREE.Matrix3(); 114 | 115 | // dash+gap fallbacks for Firefox and everything else 116 | 117 | if ( _context.setLineDash === undefined ) { 118 | 119 | _context.setLineDash = function () {} 120 | 121 | } 122 | 123 | this.domElement = _canvas; 124 | 125 | this.devicePixelRatio = parameters.devicePixelRatio !== undefined 126 | ? parameters.devicePixelRatio 127 | : self.devicePixelRatio !== undefined 128 | ? self.devicePixelRatio 129 | : 1; 130 | 131 | this.autoClear = true; 132 | this.sortObjects = true; 133 | this.sortElements = true; 134 | 135 | this.info = { 136 | 137 | render: { 138 | 139 | vertices: 0, 140 | faces: 0 141 | 142 | } 143 | 144 | } 145 | 146 | // WebGLRenderer compatibility 147 | 148 | this.supportsVertexTextures = function () {}; 149 | this.setFaceCulling = function () {}; 150 | 151 | this.setSize = function ( width, height, updateStyle ) { 152 | 153 | _canvasWidth = width * this.devicePixelRatio; 154 | _canvasHeight = height * this.devicePixelRatio; 155 | 156 | _canvas.width = _canvasWidth; 157 | _canvas.height = _canvasHeight; 158 | 159 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); 160 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); 161 | 162 | if ( updateStyle !== false ) { 163 | 164 | _canvas.style.width = width + 'px'; 165 | _canvas.style.height = height + 'px'; 166 | 167 | } 168 | 169 | _clipBox.min.set( -_canvasWidthHalf, -_canvasHeightHalf ), 170 | _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); 171 | 172 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); 173 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); 174 | 175 | _contextGlobalAlpha = 1; 176 | _contextGlobalCompositeOperation = 0; 177 | _contextStrokeStyle = null; 178 | _contextFillStyle = null; 179 | _contextLineWidth = null; 180 | _contextLineCap = null; 181 | _contextLineJoin = null; 182 | 183 | this.setViewport( 0, 0, width, height ); 184 | 185 | }; 186 | 187 | this.setViewport = function ( x, y, width, height ) { 188 | 189 | _viewportX = x * this.devicePixelRatio; 190 | _viewportY = y * this.devicePixelRatio; 191 | 192 | _viewportWidth = width * this.devicePixelRatio; 193 | _viewportHeight = height * this.devicePixelRatio; 194 | 195 | }; 196 | 197 | this.setScissor = function () {}; 198 | this.enableScissorTest = function () {}; 199 | 200 | this.setClearColor = function ( color, alpha ) { 201 | 202 | _clearColor.set( color ); 203 | _clearAlpha = alpha !== undefined ? alpha : 1; 204 | 205 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); 206 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); 207 | 208 | }; 209 | 210 | this.setClearColorHex = function ( hex, alpha ) { 211 | 212 | console.warn( 'THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); 213 | this.setClearColor( hex, alpha ); 214 | 215 | }; 216 | 217 | this.getClearColor = function () { 218 | 219 | return _clearColor; 220 | 221 | }; 222 | 223 | this.getClearAlpha = function () { 224 | 225 | return _clearAlpha; 226 | 227 | }; 228 | 229 | this.getMaxAnisotropy = function () { 230 | 231 | return 0; 232 | 233 | }; 234 | 235 | this.clear = function () { 236 | 237 | if ( _clearBox.empty() === false ) { 238 | 239 | _clearBox.intersect( _clipBox ); 240 | _clearBox.expandByScalar( 2 ); 241 | 242 | _clearBox.min.x = _clearBox.min.x + _canvasWidthHalf; 243 | _clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; 244 | _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf; 245 | _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; 246 | 247 | if ( _clearAlpha < 1 ) { 248 | 249 | _context.clearRect( 250 | _clearBox.min.x | 0, 251 | _clearBox.min.y | 0, 252 | ( _clearBox.max.x - _clearBox.min.x ) | 0, 253 | ( _clearBox.max.y - _clearBox.min.y ) | 0 254 | ); 255 | 256 | } 257 | 258 | if ( _clearAlpha > 0 ) { 259 | 260 | setBlending( THREE.NormalBlending ); 261 | setOpacity( 1 ); 262 | 263 | setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); 264 | 265 | _context.fillRect( 266 | _clearBox.min.x | 0, 267 | _clearBox.min.y | 0, 268 | ( _clearBox.max.x - _clearBox.min.x ) | 0, 269 | ( _clearBox.max.y - _clearBox.min.y ) | 0 270 | ); 271 | 272 | } 273 | 274 | _clearBox.makeEmpty(); 275 | 276 | } 277 | 278 | }; 279 | 280 | // compatibility 281 | 282 | this.clearColor = function () {}; 283 | this.clearDepth = function () {}; 284 | this.clearStencil = function () {}; 285 | 286 | this.render = function ( scene, camera ) { 287 | 288 | if ( camera instanceof THREE.Camera === false ) { 289 | 290 | console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); 291 | return; 292 | 293 | } 294 | 295 | if ( this.autoClear === true ) this.clear(); 296 | 297 | _this.info.render.vertices = 0; 298 | _this.info.render.faces = 0; 299 | 300 | _context.setTransform( _viewportWidth / _canvasWidth, 0, 0, - _viewportHeight / _canvasHeight, _viewportX, _canvasHeight - _viewportY ); 301 | _context.translate( _canvasWidthHalf, _canvasHeightHalf ); 302 | 303 | _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); 304 | _elements = _renderData.elements; 305 | _lights = _renderData.lights; 306 | _camera = camera; 307 | 308 | _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); 309 | 310 | /* DEBUG 311 | setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); 312 | _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); 313 | */ 314 | 315 | calculateLights(); 316 | 317 | for ( var e = 0, el = _elements.length; e < el; e ++ ) { 318 | 319 | var element = _elements[ e ]; 320 | 321 | var material = element.material; 322 | 323 | if ( material === undefined || material.opacity === 0 ) continue; 324 | 325 | _elemBox.makeEmpty(); 326 | 327 | if ( element instanceof THREE.RenderableSprite ) { 328 | 329 | _v1 = element; 330 | _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; 331 | 332 | renderSprite( _v1, element, material ); 333 | 334 | } else if ( element instanceof THREE.RenderableLine ) { 335 | 336 | _v1 = element.v1; _v2 = element.v2; 337 | 338 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; 339 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; 340 | 341 | _elemBox.setFromPoints( [ 342 | _v1.positionScreen, 343 | _v2.positionScreen 344 | ] ); 345 | 346 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { 347 | 348 | renderLine( _v1, _v2, element, material ); 349 | 350 | } 351 | 352 | } else if ( element instanceof THREE.RenderableFace ) { 353 | 354 | _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; 355 | 356 | if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue; 357 | if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue; 358 | if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue; 359 | 360 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; 361 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; 362 | _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; 363 | 364 | if ( material.overdraw > 0 ) { 365 | 366 | expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); 367 | expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); 368 | expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); 369 | 370 | } 371 | 372 | _elemBox.setFromPoints( [ 373 | _v1.positionScreen, 374 | _v2.positionScreen, 375 | _v3.positionScreen 376 | ] ); 377 | 378 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { 379 | 380 | renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); 381 | 382 | } 383 | 384 | } 385 | 386 | /* DEBUG 387 | setLineWidth( 1 ); 388 | setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); 389 | _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); 390 | */ 391 | 392 | _clearBox.union( _elemBox ); 393 | 394 | } 395 | 396 | /* DEBUG 397 | setLineWidth( 1 ); 398 | setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); 399 | _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); 400 | */ 401 | 402 | _context.setTransform( 1, 0, 0, 1, 0, 0 ); 403 | 404 | }; 405 | 406 | // 407 | 408 | function calculateLights() { 409 | 410 | _ambientLight.setRGB( 0, 0, 0 ); 411 | _directionalLights.setRGB( 0, 0, 0 ); 412 | _pointLights.setRGB( 0, 0, 0 ); 413 | 414 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { 415 | 416 | var light = _lights[ l ]; 417 | var lightColor = light.color; 418 | 419 | if ( light instanceof THREE.AmbientLight ) { 420 | 421 | _ambientLight.add( lightColor ); 422 | 423 | } else if ( light instanceof THREE.DirectionalLight ) { 424 | 425 | // for sprites 426 | 427 | _directionalLights.add( lightColor ); 428 | 429 | } else if ( light instanceof THREE.PointLight ) { 430 | 431 | // for sprites 432 | 433 | _pointLights.add( lightColor ); 434 | 435 | } 436 | 437 | } 438 | 439 | } 440 | 441 | function calculateLight( position, normal, color ) { 442 | 443 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { 444 | 445 | var light = _lights[ l ]; 446 | 447 | _lightColor.copy( light.color ); 448 | 449 | if ( light instanceof THREE.DirectionalLight ) { 450 | 451 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); 452 | 453 | var amount = normal.dot( lightPosition ); 454 | 455 | if ( amount <= 0 ) continue; 456 | 457 | amount *= light.intensity; 458 | 459 | color.add( _lightColor.multiplyScalar( amount ) ); 460 | 461 | } else if ( light instanceof THREE.PointLight ) { 462 | 463 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); 464 | 465 | var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); 466 | 467 | if ( amount <= 0 ) continue; 468 | 469 | amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); 470 | 471 | if ( amount == 0 ) continue; 472 | 473 | amount *= light.intensity; 474 | 475 | color.add( _lightColor.multiplyScalar( amount ) ); 476 | 477 | } 478 | 479 | } 480 | 481 | } 482 | 483 | function renderSprite( v1, element, material ) { 484 | 485 | setOpacity( material.opacity ); 486 | setBlending( material.blending ); 487 | 488 | var scaleX = element.scale.x * _canvasWidthHalf; 489 | var scaleY = element.scale.y * _canvasHeightHalf; 490 | 491 | var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite 492 | _elemBox.min.set( v1.x - dist, v1.y - dist ); 493 | _elemBox.max.set( v1.x + dist, v1.y + dist ); 494 | 495 | if ( material instanceof THREE.SpriteMaterial ) { 496 | 497 | var texture = material.map; 498 | 499 | if ( texture !== null && texture.image !== undefined ) { 500 | 501 | if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { 502 | 503 | if ( texture.image.width > 0 ) { 504 | 505 | textureToPattern( texture ); 506 | 507 | } 508 | 509 | texture.addEventListener( 'update', onTextureUpdate ); 510 | 511 | } 512 | 513 | var pattern = _patterns[ texture.id ]; 514 | 515 | if ( pattern !== undefined ) { 516 | 517 | setFillStyle( pattern ); 518 | 519 | } else { 520 | 521 | setFillStyle( 'rgba( 0, 0, 0, 1 )' ); 522 | 523 | } 524 | 525 | // 526 | 527 | var bitmap = texture.image; 528 | 529 | var ox = bitmap.width * texture.offset.x; 530 | var oy = bitmap.height * texture.offset.y; 531 | 532 | var sx = bitmap.width * texture.repeat.x; 533 | var sy = bitmap.height * texture.repeat.y; 534 | 535 | var cx = scaleX / sx; 536 | var cy = scaleY / sy; 537 | 538 | _context.save(); 539 | _context.translate( v1.x, v1.y ); 540 | if ( material.rotation !== 0 ) _context.rotate( material.rotation ); 541 | _context.translate( - scaleX / 2, - scaleY / 2 ); 542 | _context.scale( cx, cy ); 543 | _context.translate( - ox, - oy ); 544 | _context.fillRect( ox, oy, sx, sy ); 545 | _context.restore(); 546 | 547 | } else { 548 | 549 | // no texture 550 | 551 | setFillStyle( material.color.getStyle() ); 552 | 553 | _context.save(); 554 | _context.translate( v1.x, v1.y ); 555 | if ( material.rotation !== 0 ) _context.rotate( material.rotation ); 556 | _context.scale( scaleX, - scaleY ); 557 | _context.fillRect( - 0.5, - 0.5, 1, 1 ); 558 | _context.restore(); 559 | 560 | } 561 | 562 | } else if ( material instanceof THREE.SpriteCanvasMaterial ) { 563 | 564 | setStrokeStyle( material.color.getStyle() ); 565 | setFillStyle( material.color.getStyle() ); 566 | 567 | _context.save(); 568 | _context.translate( v1.x, v1.y ); 569 | if ( material.rotation !== 0 ) _context.rotate( material.rotation ); 570 | _context.scale( scaleX, scaleY ); 571 | 572 | material.program( _context ); 573 | 574 | _context.restore(); 575 | 576 | } 577 | 578 | /* DEBUG 579 | setStrokeStyle( 'rgb(255,255,0)' ); 580 | _context.beginPath(); 581 | _context.moveTo( v1.x - 10, v1.y ); 582 | _context.lineTo( v1.x + 10, v1.y ); 583 | _context.moveTo( v1.x, v1.y - 10 ); 584 | _context.lineTo( v1.x, v1.y + 10 ); 585 | _context.stroke(); 586 | */ 587 | 588 | } 589 | 590 | function renderLine( v1, v2, element, material ) { 591 | 592 | setOpacity( material.opacity ); 593 | setBlending( material.blending ); 594 | 595 | _context.beginPath(); 596 | _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); 597 | _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); 598 | 599 | if ( material instanceof THREE.LineBasicMaterial ) { 600 | 601 | setLineWidth( material.linewidth ); 602 | setLineCap( material.linecap ); 603 | setLineJoin( material.linejoin ); 604 | 605 | if ( material.vertexColors !== THREE.VertexColors ) { 606 | 607 | setStrokeStyle( material.color.getStyle() ); 608 | 609 | } else { 610 | 611 | var colorStyle1 = element.vertexColors[ 0 ].getStyle(); 612 | var colorStyle2 = element.vertexColors[ 1 ].getStyle(); 613 | 614 | if ( colorStyle1 === colorStyle2 ) { 615 | 616 | setStrokeStyle( colorStyle1 ); 617 | 618 | } else { 619 | 620 | try { 621 | 622 | var grad = _context.createLinearGradient( 623 | v1.positionScreen.x, 624 | v1.positionScreen.y, 625 | v2.positionScreen.x, 626 | v2.positionScreen.y 627 | ); 628 | grad.addColorStop( 0, colorStyle1 ); 629 | grad.addColorStop( 1, colorStyle2 ); 630 | 631 | } catch ( exception ) { 632 | 633 | grad = colorStyle1; 634 | 635 | } 636 | 637 | setStrokeStyle( grad ); 638 | 639 | } 640 | 641 | } 642 | 643 | _context.stroke(); 644 | _elemBox.expandByScalar( material.linewidth * 2 ); 645 | 646 | } else if ( material instanceof THREE.LineDashedMaterial ) { 647 | 648 | setLineWidth( material.linewidth ); 649 | setLineCap( material.linecap ); 650 | setLineJoin( material.linejoin ); 651 | setStrokeStyle( material.color.getStyle() ); 652 | setLineDash( [ material.dashSize, material.gapSize ] ); 653 | 654 | _context.stroke(); 655 | 656 | _elemBox.expandByScalar( material.linewidth * 2 ); 657 | 658 | setLineDash( [] ); 659 | 660 | } 661 | 662 | } 663 | 664 | function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { 665 | 666 | _this.info.render.vertices += 3; 667 | _this.info.render.faces ++; 668 | 669 | setOpacity( material.opacity ); 670 | setBlending( material.blending ); 671 | 672 | _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; 673 | _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; 674 | _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; 675 | 676 | drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); 677 | 678 | if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { 679 | 680 | _diffuseColor.copy( material.color ); 681 | _emissiveColor.copy( material.emissive ); 682 | 683 | if ( material.vertexColors === THREE.FaceColors ) { 684 | 685 | _diffuseColor.multiply( element.color ); 686 | 687 | } 688 | 689 | _color.copy( _ambientLight ); 690 | 691 | _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 ); 692 | 693 | calculateLight( _centroid, element.normalModel, _color ); 694 | 695 | _color.multiply( _diffuseColor ).add( _emissiveColor ); 696 | 697 | material.wireframe === true 698 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 699 | : fillPath( _color ); 700 | 701 | } else if ( material instanceof THREE.MeshBasicMaterial || 702 | material instanceof THREE.MeshLambertMaterial || 703 | material instanceof THREE.MeshPhongMaterial ) { 704 | 705 | if ( material.map !== null ) { 706 | 707 | if ( material.map.mapping instanceof THREE.UVMapping ) { 708 | 709 | _uvs = element.uvs; 710 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); 711 | 712 | } 713 | 714 | } else if ( material.envMap !== null ) { 715 | 716 | if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { 717 | 718 | _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); 719 | _uv1x = 0.5 * _normal.x + 0.5; 720 | _uv1y = 0.5 * _normal.y + 0.5; 721 | 722 | _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); 723 | _uv2x = 0.5 * _normal.x + 0.5; 724 | _uv2y = 0.5 * _normal.y + 0.5; 725 | 726 | _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); 727 | _uv3x = 0.5 * _normal.x + 0.5; 728 | _uv3y = 0.5 * _normal.y + 0.5; 729 | 730 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); 731 | 732 | } else if ( material.envMap.mapping instanceof THREE.SphericalRefractionMapping ) { 733 | 734 | _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); 735 | _uv1x = - 0.5 * _normal.x + 0.5; 736 | _uv1y = - 0.5 * _normal.y + 0.5; 737 | 738 | _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); 739 | _uv2x = - 0.5 * _normal.x + 0.5; 740 | _uv2y = - 0.5 * _normal.y + 0.5; 741 | 742 | _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); 743 | _uv3x = - 0.5 * _normal.x + 0.5; 744 | _uv3y = - 0.5 * _normal.y + 0.5; 745 | 746 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); 747 | 748 | } 749 | 750 | 751 | } else { 752 | 753 | _color.copy( material.color ); 754 | 755 | if ( material.vertexColors === THREE.FaceColors ) { 756 | 757 | _color.multiply( element.color ); 758 | 759 | } 760 | 761 | material.wireframe === true 762 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 763 | : fillPath( _color ); 764 | 765 | } 766 | 767 | } else if ( material instanceof THREE.MeshDepthMaterial ) { 768 | 769 | _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far ); 770 | 771 | material.wireframe === true 772 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 773 | : fillPath( _color ); 774 | 775 | } else if ( material instanceof THREE.MeshNormalMaterial ) { 776 | 777 | _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); 778 | 779 | _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); 780 | 781 | material.wireframe === true 782 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 783 | : fillPath( _color ); 784 | 785 | } else { 786 | 787 | _color.setRGB( 1, 1, 1 ); 788 | 789 | material.wireframe === true 790 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 791 | : fillPath( _color ); 792 | 793 | } 794 | 795 | } 796 | 797 | // 798 | 799 | function drawTriangle( x0, y0, x1, y1, x2, y2 ) { 800 | 801 | _context.beginPath(); 802 | _context.moveTo( x0, y0 ); 803 | _context.lineTo( x1, y1 ); 804 | _context.lineTo( x2, y2 ); 805 | _context.closePath(); 806 | 807 | } 808 | 809 | function strokePath( color, linewidth, linecap, linejoin ) { 810 | 811 | setLineWidth( linewidth ); 812 | setLineCap( linecap ); 813 | setLineJoin( linejoin ); 814 | setStrokeStyle( color.getStyle() ); 815 | 816 | _context.stroke(); 817 | 818 | _elemBox.expandByScalar( linewidth * 2 ); 819 | 820 | } 821 | 822 | function fillPath( color ) { 823 | 824 | setFillStyle( color.getStyle() ); 825 | _context.fill(); 826 | 827 | } 828 | 829 | function onTextureUpdate ( event ) { 830 | 831 | textureToPattern( event.target ); 832 | 833 | } 834 | 835 | function textureToPattern( texture ) { 836 | 837 | if ( texture instanceof THREE.CompressedTexture ) return; 838 | 839 | var repeatX = texture.wrapS === THREE.RepeatWrapping; 840 | var repeatY = texture.wrapT === THREE.RepeatWrapping; 841 | 842 | var image = texture.image; 843 | 844 | var canvas = document.createElement( 'canvas' ); 845 | canvas.width = image.width; 846 | canvas.height = image.height; 847 | 848 | var context = canvas.getContext( '2d' ); 849 | context.setTransform( 1, 0, 0, - 1, 0, image.height ); 850 | context.drawImage( image, 0, 0 ); 851 | 852 | _patterns[ texture.id ] = _context.createPattern( 853 | canvas, repeatX === true && repeatY === true 854 | ? 'repeat' 855 | : repeatX === true && repeatY === false 856 | ? 'repeat-x' 857 | : repeatX === false && repeatY === true 858 | ? 'repeat-y' 859 | : 'no-repeat' 860 | ); 861 | 862 | } 863 | 864 | function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { 865 | 866 | if ( texture instanceof THREE.DataTexture ) return; 867 | 868 | if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { 869 | 870 | if ( texture.image !== undefined && texture.image.width > 0 ) { 871 | 872 | textureToPattern( texture ); 873 | 874 | } 875 | 876 | texture.addEventListener( 'update', onTextureUpdate ); 877 | 878 | } 879 | 880 | var pattern = _patterns[ texture.id ]; 881 | 882 | if ( pattern !== undefined ) { 883 | 884 | setFillStyle( pattern ); 885 | 886 | } else { 887 | 888 | setFillStyle( 'rgba(0,0,0,1)' ); 889 | _context.fill(); 890 | 891 | return; 892 | 893 | } 894 | 895 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 896 | 897 | var a, b, c, d, e, f, det, idet, 898 | offsetX = texture.offset.x / texture.repeat.x, 899 | offsetY = texture.offset.y / texture.repeat.y, 900 | width = texture.image.width * texture.repeat.x, 901 | height = texture.image.height * texture.repeat.y; 902 | 903 | u0 = ( u0 + offsetX ) * width; 904 | v0 = ( v0 + offsetY ) * height; 905 | 906 | u1 = ( u1 + offsetX ) * width; 907 | v1 = ( v1 + offsetY ) * height; 908 | 909 | u2 = ( u2 + offsetX ) * width; 910 | v2 = ( v2 + offsetY ) * height; 911 | 912 | x1 -= x0; y1 -= y0; 913 | x2 -= x0; y2 -= y0; 914 | 915 | u1 -= u0; v1 -= v0; 916 | u2 -= u0; v2 -= v0; 917 | 918 | det = u1 * v2 - u2 * v1; 919 | 920 | if ( det === 0 ) return; 921 | 922 | idet = 1 / det; 923 | 924 | a = ( v2 * x1 - v1 * x2 ) * idet; 925 | b = ( v2 * y1 - v1 * y2 ) * idet; 926 | c = ( u1 * x2 - u2 * x1 ) * idet; 927 | d = ( u1 * y2 - u2 * y1 ) * idet; 928 | 929 | e = x0 - a * u0 - c * v0; 930 | f = y0 - b * u0 - d * v0; 931 | 932 | _context.save(); 933 | _context.transform( a, b, c, d, e, f ); 934 | _context.fill(); 935 | _context.restore(); 936 | 937 | } 938 | 939 | function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { 940 | 941 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 942 | 943 | var a, b, c, d, e, f, det, idet, 944 | width = image.width - 1, 945 | height = image.height - 1; 946 | 947 | u0 *= width; v0 *= height; 948 | u1 *= width; v1 *= height; 949 | u2 *= width; v2 *= height; 950 | 951 | x1 -= x0; y1 -= y0; 952 | x2 -= x0; y2 -= y0; 953 | 954 | u1 -= u0; v1 -= v0; 955 | u2 -= u0; v2 -= v0; 956 | 957 | det = u1 * v2 - u2 * v1; 958 | 959 | idet = 1 / det; 960 | 961 | a = ( v2 * x1 - v1 * x2 ) * idet; 962 | b = ( v2 * y1 - v1 * y2 ) * idet; 963 | c = ( u1 * x2 - u2 * x1 ) * idet; 964 | d = ( u1 * y2 - u2 * y1 ) * idet; 965 | 966 | e = x0 - a * u0 - c * v0; 967 | f = y0 - b * u0 - d * v0; 968 | 969 | _context.save(); 970 | _context.transform( a, b, c, d, e, f ); 971 | _context.clip(); 972 | _context.drawImage( image, 0, 0 ); 973 | _context.restore(); 974 | 975 | } 976 | 977 | // Hide anti-alias gaps 978 | 979 | function expand( v1, v2, pixels ) { 980 | 981 | var x = v2.x - v1.x, y = v2.y - v1.y, 982 | det = x * x + y * y, idet; 983 | 984 | if ( det === 0 ) return; 985 | 986 | idet = pixels / Math.sqrt( det ); 987 | 988 | x *= idet; y *= idet; 989 | 990 | v2.x += x; v2.y += y; 991 | v1.x -= x; v1.y -= y; 992 | 993 | } 994 | 995 | // Context cached methods. 996 | 997 | function setOpacity( value ) { 998 | 999 | if ( _contextGlobalAlpha !== value ) { 1000 | 1001 | _context.globalAlpha = value; 1002 | _contextGlobalAlpha = value; 1003 | 1004 | } 1005 | 1006 | } 1007 | 1008 | function setBlending( value ) { 1009 | 1010 | if ( _contextGlobalCompositeOperation !== value ) { 1011 | 1012 | if ( value === THREE.NormalBlending ) { 1013 | 1014 | _context.globalCompositeOperation = 'source-over'; 1015 | 1016 | } else if ( value === THREE.AdditiveBlending ) { 1017 | 1018 | _context.globalCompositeOperation = 'lighter'; 1019 | 1020 | } else if ( value === THREE.SubtractiveBlending ) { 1021 | 1022 | _context.globalCompositeOperation = 'darker'; 1023 | 1024 | } 1025 | 1026 | _contextGlobalCompositeOperation = value; 1027 | 1028 | } 1029 | 1030 | } 1031 | 1032 | function setLineWidth( value ) { 1033 | 1034 | if ( _contextLineWidth !== value ) { 1035 | 1036 | _context.lineWidth = value; 1037 | _contextLineWidth = value; 1038 | 1039 | } 1040 | 1041 | } 1042 | 1043 | function setLineCap( value ) { 1044 | 1045 | // "butt", "round", "square" 1046 | 1047 | if ( _contextLineCap !== value ) { 1048 | 1049 | _context.lineCap = value; 1050 | _contextLineCap = value; 1051 | 1052 | } 1053 | 1054 | } 1055 | 1056 | function setLineJoin( value ) { 1057 | 1058 | // "round", "bevel", "miter" 1059 | 1060 | if ( _contextLineJoin !== value ) { 1061 | 1062 | _context.lineJoin = value; 1063 | _contextLineJoin = value; 1064 | 1065 | } 1066 | 1067 | } 1068 | 1069 | function setStrokeStyle( value ) { 1070 | 1071 | if ( _contextStrokeStyle !== value ) { 1072 | 1073 | _context.strokeStyle = value; 1074 | _contextStrokeStyle = value; 1075 | 1076 | } 1077 | 1078 | } 1079 | 1080 | function setFillStyle( value ) { 1081 | 1082 | if ( _contextFillStyle !== value ) { 1083 | 1084 | _context.fillStyle = value; 1085 | _contextFillStyle = value; 1086 | 1087 | } 1088 | 1089 | } 1090 | 1091 | function setLineDash( value ) { 1092 | 1093 | if ( _contextLineDash.length !== value.length ) { 1094 | 1095 | _context.setLineDash( value ); 1096 | _contextLineDash = value; 1097 | 1098 | } 1099 | 1100 | } 1101 | 1102 | }; 1103 | -------------------------------------------------------------------------------- /libs/CopyShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Full-screen textured quad shader 5 | */ 6 | 7 | THREE.CopyShader = { 8 | 9 | uniforms: { 10 | 11 | "tDiffuse": { type: "t", value: null }, 12 | "opacity": { type: "f", value: 1.0 } 13 | 14 | }, 15 | 16 | vertexShader: [ 17 | 18 | "varying vec2 vUv;", 19 | 20 | "void main() {", 21 | 22 | "vUv = uv;", 23 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 24 | 25 | "}" 26 | 27 | ].join("\n"), 28 | 29 | fragmentShader: [ 30 | 31 | "uniform float opacity;", 32 | 33 | "uniform sampler2D tDiffuse;", 34 | 35 | "varying vec2 vUv;", 36 | 37 | "void main() {", 38 | 39 | "vec4 texel = texture2D( tDiffuse, vUv );", 40 | "gl_FragColor = opacity * texel;", 41 | 42 | "}" 43 | 44 | ].join("\n") 45 | 46 | }; 47 | -------------------------------------------------------------------------------- /libs/EffectComposer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.EffectComposer = function ( renderer, renderTarget ) { 6 | 7 | this.renderer = renderer; 8 | 9 | if ( renderTarget === undefined ) { 10 | 11 | var width = window.innerWidth || 1; 12 | var height = window.innerHeight || 1; 13 | var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; 14 | 15 | renderTarget = new THREE.WebGLRenderTarget( width, height, parameters ); 16 | 17 | } 18 | 19 | this.renderTarget1 = renderTarget; 20 | this.renderTarget2 = renderTarget.clone(); 21 | 22 | this.writeBuffer = this.renderTarget1; 23 | this.readBuffer = this.renderTarget2; 24 | 25 | this.passes = []; 26 | 27 | if ( THREE.CopyShader === undefined ) 28 | console.error( "THREE.EffectComposer relies on THREE.CopyShader" ); 29 | 30 | this.copyPass = new THREE.ShaderPass( THREE.CopyShader ); 31 | 32 | }; 33 | 34 | THREE.EffectComposer.prototype = { 35 | 36 | swapBuffers: function() { 37 | 38 | var tmp = this.readBuffer; 39 | this.readBuffer = this.writeBuffer; 40 | this.writeBuffer = tmp; 41 | 42 | }, 43 | 44 | addPass: function ( pass ) { 45 | 46 | this.passes.push( pass ); 47 | 48 | }, 49 | 50 | insertPass: function ( pass, index ) { 51 | 52 | this.passes.splice( index, 0, pass ); 53 | 54 | }, 55 | 56 | render: function ( delta ) { 57 | 58 | this.writeBuffer = this.renderTarget1; 59 | this.readBuffer = this.renderTarget2; 60 | 61 | var maskActive = false; 62 | 63 | var pass, i, il = this.passes.length; 64 | 65 | for ( i = 0; i < il; i ++ ) { 66 | 67 | pass = this.passes[ i ]; 68 | 69 | if ( !pass.enabled ) continue; 70 | 71 | pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive ); 72 | 73 | if ( pass.needsSwap ) { 74 | 75 | if ( maskActive ) { 76 | 77 | var context = this.renderer.context; 78 | 79 | context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff ); 80 | 81 | this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta ); 82 | 83 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); 84 | 85 | } 86 | 87 | this.swapBuffers(); 88 | 89 | } 90 | 91 | if ( pass instanceof THREE.MaskPass ) { 92 | 93 | maskActive = true; 94 | 95 | } else if ( pass instanceof THREE.ClearMaskPass ) { 96 | 97 | maskActive = false; 98 | 99 | } 100 | 101 | } 102 | 103 | }, 104 | 105 | reset: function ( renderTarget ) { 106 | 107 | if ( renderTarget === undefined ) { 108 | 109 | renderTarget = this.renderTarget1.clone(); 110 | 111 | renderTarget.width = window.innerWidth; 112 | renderTarget.height = window.innerHeight; 113 | 114 | } 115 | 116 | this.renderTarget1 = renderTarget; 117 | this.renderTarget2 = renderTarget.clone(); 118 | 119 | this.writeBuffer = this.renderTarget1; 120 | this.readBuffer = this.renderTarget2; 121 | 122 | }, 123 | 124 | setSize: function ( width, height ) { 125 | 126 | var renderTarget = this.renderTarget1.clone(); 127 | 128 | renderTarget.width = width; 129 | renderTarget.height = height; 130 | 131 | this.reset( renderTarget ); 132 | 133 | } 134 | 135 | }; 136 | 137 | // shared ortho camera 138 | 139 | THREE.EffectComposer.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 ); 140 | 141 | THREE.EffectComposer.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null ); 142 | 143 | THREE.EffectComposer.scene = new THREE.Scene(); 144 | THREE.EffectComposer.scene.add( THREE.EffectComposer.quad ); 145 | -------------------------------------------------------------------------------- /libs/FXAAShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * @author davidedc / http://www.sketchpatch.net/ 4 | * 5 | * NVIDIA FXAA by Timothy Lottes 6 | * http://timothylottes.blogspot.com/2011/06/fxaa3-source-released.html 7 | * - WebGL port by @supereggbert 8 | * http://www.glge.org/demos/fxaa/ 9 | */ 10 | 11 | THREE.FXAAShader = { 12 | 13 | uniforms: { 14 | 15 | "tDiffuse": { type: "t", value: null }, 16 | "resolution": { type: "v2", value: new THREE.Vector2( 1 / 1024, 1 / 512 ) } 17 | 18 | }, 19 | 20 | vertexShader: [ 21 | 22 | "varying vec2 vUv;", 23 | 24 | "void main() {", 25 | 26 | "vUv = uv;", 27 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 28 | 29 | "}" 30 | 31 | ].join("\n"), 32 | 33 | fragmentShader: [ 34 | 35 | "uniform sampler2D tDiffuse;", 36 | "uniform vec2 resolution;", 37 | 38 | "varying vec2 vUv;", 39 | 40 | "#define FXAA_REDUCE_MIN (1.0/128.0)", 41 | "#define FXAA_REDUCE_MUL (1.0/8.0)", 42 | "#define FXAA_SPAN_MAX 8.0", 43 | 44 | "void main() {", 45 | 46 | "vec3 rgbNW = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ).xyz;", 47 | "vec3 rgbNE = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ).xyz;", 48 | "vec3 rgbSW = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ).xyz;", 49 | "vec3 rgbSE = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ).xyz;", 50 | "vec4 rgbaM = texture2D( tDiffuse, gl_FragCoord.xy * resolution );", 51 | "vec3 rgbM = rgbaM.xyz;", 52 | "float opacity = rgbaM.w;", 53 | 54 | "vec3 luma = vec3( 0.299, 0.587, 0.114 );", 55 | 56 | "float lumaNW = dot( rgbNW, luma );", 57 | "float lumaNE = dot( rgbNE, luma );", 58 | "float lumaSW = dot( rgbSW, luma );", 59 | "float lumaSE = dot( rgbSE, luma );", 60 | "float lumaM = dot( rgbM, luma );", 61 | "float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );", 62 | "float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );", 63 | 64 | "vec2 dir;", 65 | "dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));", 66 | "dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));", 67 | 68 | "float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );", 69 | 70 | "float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );", 71 | "dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),", 72 | "max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),", 73 | "dir * rcpDirMin)) * resolution;", 74 | 75 | "vec3 rgbA = 0.5 * (", 76 | "texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ).xyz +", 77 | "texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ).xyz );", 78 | 79 | "vec3 rgbB = rgbA * 0.5 + 0.25 * (", 80 | "texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * -0.5 ).xyz +", 81 | "texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * 0.5 ).xyz );", 82 | 83 | "float lumaB = dot( rgbB, luma );", 84 | 85 | "if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) ) {", 86 | 87 | "gl_FragColor = vec4( rgbA, opacity );", 88 | 89 | "} else {", 90 | 91 | "gl_FragColor = vec4( rgbB, opacity );", 92 | 93 | "}", 94 | 95 | "}" 96 | 97 | ].join("\n") 98 | 99 | }; 100 | -------------------------------------------------------------------------------- /libs/MaskPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.MaskPass = function ( scene, camera ) { 6 | 7 | this.scene = scene; 8 | this.camera = camera; 9 | 10 | this.enabled = true; 11 | this.clear = true; 12 | this.needsSwap = false; 13 | 14 | this.inverse = false; 15 | 16 | }; 17 | 18 | THREE.MaskPass.prototype = { 19 | 20 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 21 | 22 | var context = renderer.context; 23 | 24 | // don't update color or depth 25 | 26 | context.colorMask( false, false, false, false ); 27 | context.depthMask( false ); 28 | 29 | // set up stencil 30 | 31 | var writeValue, clearValue; 32 | 33 | if ( this.inverse ) { 34 | 35 | writeValue = 0; 36 | clearValue = 1; 37 | 38 | } else { 39 | 40 | writeValue = 1; 41 | clearValue = 0; 42 | 43 | } 44 | 45 | context.enable( context.STENCIL_TEST ); 46 | context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE ); 47 | context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff ); 48 | context.clearStencil( clearValue ); 49 | 50 | // draw into the stencil buffer 51 | 52 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 53 | renderer.render( this.scene, this.camera, writeBuffer, this.clear ); 54 | 55 | // re-enable update of color and depth 56 | 57 | context.colorMask( true, true, true, true ); 58 | context.depthMask( true ); 59 | 60 | // only render where stencil is set to 1 61 | 62 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1 63 | context.stencilOp( context.KEEP, context.KEEP, context.KEEP ); 64 | 65 | } 66 | 67 | }; 68 | 69 | 70 | THREE.ClearMaskPass = function () { 71 | 72 | this.enabled = true; 73 | 74 | }; 75 | 76 | THREE.ClearMaskPass.prototype = { 77 | 78 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 79 | 80 | var context = renderer.context; 81 | 82 | context.disable( context.STENCIL_TEST ); 83 | 84 | } 85 | 86 | }; 87 | -------------------------------------------------------------------------------- /libs/OrbitControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author qiao / https://github.com/qiao 3 | * @author mrdoob / http://mrdoob.com 4 | * @author alteredq / http://alteredqualia.com/ 5 | * @author WestLangley / http://github.com/WestLangley 6 | */ 7 | 8 | THREE.OrbitControls = function ( object, domElement ) { 9 | 10 | this.object = object; 11 | this.domElement = ( domElement !== undefined ) ? domElement : document; 12 | 13 | // API 14 | 15 | this.enabled = true; 16 | 17 | this.center = new THREE.Vector3(); 18 | 19 | this.userZoom = true; 20 | this.userZoomSpeed = 1.0; 21 | 22 | this.userRotate = true; 23 | this.userRotateSpeed = 1.0; 24 | 25 | this.userPan = true; 26 | this.userPanSpeed = 2.0; 27 | 28 | this.autoRotate = false; 29 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 30 | 31 | this.minPolarAngle = 0; // radians 32 | this.maxPolarAngle = Math.PI; // radians 33 | 34 | this.minDistance = 0; 35 | this.maxDistance = Infinity; 36 | 37 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 38 | 39 | // internals 40 | 41 | var scope = this; 42 | 43 | var EPS = 0.000001; 44 | var PIXELS_PER_ROUND = 1800; 45 | 46 | var rotateStart = new THREE.Vector2(); 47 | var rotateEnd = new THREE.Vector2(); 48 | var rotateDelta = new THREE.Vector2(); 49 | 50 | var zoomStart = new THREE.Vector2(); 51 | var zoomEnd = new THREE.Vector2(); 52 | var zoomDelta = new THREE.Vector2(); 53 | 54 | var phiDelta = 0; 55 | var thetaDelta = 0; 56 | var scale = 1; 57 | 58 | var lastPosition = new THREE.Vector3(); 59 | 60 | var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2 }; 61 | var state = STATE.NONE; 62 | 63 | // events 64 | 65 | var changeEvent = { type: 'change' }; 66 | 67 | 68 | this.rotateLeft = function ( angle ) { 69 | 70 | if ( angle === undefined ) { 71 | 72 | angle = getAutoRotationAngle(); 73 | 74 | } 75 | 76 | thetaDelta -= angle; 77 | 78 | }; 79 | 80 | this.rotateRight = function ( angle ) { 81 | 82 | if ( angle === undefined ) { 83 | 84 | angle = getAutoRotationAngle(); 85 | 86 | } 87 | 88 | thetaDelta += angle; 89 | 90 | }; 91 | 92 | this.rotateUp = function ( angle ) { 93 | 94 | if ( angle === undefined ) { 95 | 96 | angle = getAutoRotationAngle(); 97 | 98 | } 99 | 100 | phiDelta -= angle; 101 | 102 | }; 103 | 104 | this.rotateDown = function ( angle ) { 105 | 106 | if ( angle === undefined ) { 107 | 108 | angle = getAutoRotationAngle(); 109 | 110 | } 111 | 112 | phiDelta += angle; 113 | 114 | }; 115 | 116 | this.zoomIn = function ( zoomScale ) { 117 | 118 | if ( zoomScale === undefined ) { 119 | 120 | zoomScale = getZoomScale(); 121 | 122 | } 123 | 124 | scale /= zoomScale; 125 | 126 | }; 127 | 128 | this.zoomOut = function ( zoomScale ) { 129 | 130 | if ( zoomScale === undefined ) { 131 | 132 | zoomScale = getZoomScale(); 133 | 134 | } 135 | 136 | scale *= zoomScale; 137 | 138 | }; 139 | 140 | this.pan = function ( distance ) { 141 | 142 | distance.transformDirection( this.object.matrix ); 143 | distance.multiplyScalar( scope.userPanSpeed ); 144 | 145 | this.object.position.add( distance ); 146 | this.center.add( distance ); 147 | 148 | }; 149 | 150 | this.update = function () { 151 | 152 | var position = this.object.position; 153 | var offset = position.clone().sub( this.center ); 154 | 155 | // angle from z-axis around y-axis 156 | 157 | var theta = Math.atan2( offset.x, offset.z ); 158 | 159 | // angle from y-axis 160 | 161 | var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); 162 | 163 | if ( this.autoRotate ) { 164 | 165 | this.rotateLeft( getAutoRotationAngle() ); 166 | 167 | } 168 | 169 | theta += thetaDelta; 170 | phi += phiDelta; 171 | 172 | // restrict phi to be between desired limits 173 | phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); 174 | 175 | // restrict phi to be betwee EPS and PI-EPS 176 | phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); 177 | 178 | var radius = offset.length() * scale; 179 | 180 | // restrict radius to be between desired limits 181 | radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); 182 | 183 | offset.x = radius * Math.sin( phi ) * Math.sin( theta ); 184 | offset.y = radius * Math.cos( phi ); 185 | offset.z = radius * Math.sin( phi ) * Math.cos( theta ); 186 | 187 | position.copy( this.center ).add( offset ); 188 | 189 | this.object.lookAt( this.center ); 190 | 191 | thetaDelta = 0; 192 | phiDelta = 0; 193 | scale = 1; 194 | 195 | if ( lastPosition.distanceTo( this.object.position ) > 0 ) { 196 | 197 | this.dispatchEvent( changeEvent ); 198 | 199 | lastPosition.copy( this.object.position ); 200 | 201 | } 202 | 203 | }; 204 | 205 | 206 | function getAutoRotationAngle() { 207 | 208 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; 209 | 210 | } 211 | 212 | function getZoomScale() { 213 | 214 | return Math.pow( 0.95, scope.userZoomSpeed ); 215 | 216 | } 217 | 218 | function onMouseDown( event ) { 219 | 220 | if ( scope.enabled === false ) return; 221 | if ( scope.userRotate === false ) return; 222 | 223 | event.preventDefault(); 224 | 225 | if ( event.button === 0 ) { 226 | 227 | state = STATE.ROTATE; 228 | 229 | rotateStart.set( event.clientX, event.clientY ); 230 | 231 | } else if ( event.button === 1 ) { 232 | 233 | state = STATE.ZOOM; 234 | 235 | zoomStart.set( event.clientX, event.clientY ); 236 | 237 | } else if ( event.button === 2 ) { 238 | 239 | state = STATE.PAN; 240 | 241 | } 242 | 243 | document.addEventListener( 'mousemove', onMouseMove, false ); 244 | document.addEventListener( 'mouseup', onMouseUp, false ); 245 | 246 | } 247 | 248 | function onMouseMove( event ) { 249 | 250 | if ( scope.enabled === false ) return; 251 | 252 | event.preventDefault(); 253 | 254 | if ( state === STATE.ROTATE ) { 255 | 256 | rotateEnd.set( event.clientX, event.clientY ); 257 | rotateDelta.subVectors( rotateEnd, rotateStart ); 258 | 259 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed ); 260 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed ); 261 | 262 | rotateStart.copy( rotateEnd ); 263 | 264 | } else if ( state === STATE.ZOOM ) { 265 | 266 | zoomEnd.set( event.clientX, event.clientY ); 267 | zoomDelta.subVectors( zoomEnd, zoomStart ); 268 | 269 | if ( zoomDelta.y > 0 ) { 270 | 271 | scope.zoomIn(); 272 | 273 | } else { 274 | 275 | scope.zoomOut(); 276 | 277 | } 278 | 279 | zoomStart.copy( zoomEnd ); 280 | 281 | } else if ( state === STATE.PAN ) { 282 | 283 | var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0; 284 | var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0; 285 | 286 | scope.pan( new THREE.Vector3( - movementX, movementY, 0 ) ); 287 | 288 | } 289 | 290 | } 291 | 292 | function onMouseUp( event ) { 293 | 294 | if ( scope.enabled === false ) return; 295 | if ( scope.userRotate === false ) return; 296 | 297 | document.removeEventListener( 'mousemove', onMouseMove, false ); 298 | document.removeEventListener( 'mouseup', onMouseUp, false ); 299 | 300 | state = STATE.NONE; 301 | 302 | } 303 | 304 | function onMouseWheel( event ) { 305 | 306 | if ( scope.enabled === false ) return; 307 | if ( scope.userZoom === false ) return; 308 | 309 | var delta = 0; 310 | 311 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 312 | 313 | delta = event.wheelDelta; 314 | 315 | } else if ( event.detail ) { // Firefox 316 | 317 | delta = - event.detail; 318 | 319 | } 320 | 321 | if ( delta > 0 ) { 322 | 323 | scope.zoomOut(); 324 | 325 | } else { 326 | 327 | scope.zoomIn(); 328 | 329 | } 330 | 331 | } 332 | 333 | function onKeyDown( event ) { 334 | 335 | if ( scope.enabled === false ) return; 336 | if ( scope.userPan === false ) return; 337 | 338 | switch ( event.keyCode ) { 339 | 340 | case scope.keys.UP: 341 | scope.pan( new THREE.Vector3( 0, 1, 0 ) ); 342 | break; 343 | case scope.keys.BOTTOM: 344 | scope.pan( new THREE.Vector3( 0, - 1, 0 ) ); 345 | break; 346 | case scope.keys.LEFT: 347 | scope.pan( new THREE.Vector3( - 1, 0, 0 ) ); 348 | break; 349 | case scope.keys.RIGHT: 350 | scope.pan( new THREE.Vector3( 1, 0, 0 ) ); 351 | break; 352 | } 353 | 354 | } 355 | 356 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); 357 | this.domElement.addEventListener( 'mousedown', onMouseDown, false ); 358 | this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); 359 | this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox 360 | this.domElement.addEventListener( 'keydown', onKeyDown, false ); 361 | 362 | }; 363 | 364 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); -------------------------------------------------------------------------------- /libs/Projector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | * @author supereggbert / http://www.paulbrunt.co.uk/ 4 | * @author julianwa / https://github.com/julianwa 5 | */ 6 | 7 | THREE.RenderableObject = function () { 8 | 9 | this.id = 0; 10 | 11 | this.object = null; 12 | this.z = 0; 13 | 14 | }; 15 | 16 | // 17 | 18 | THREE.RenderableFace = function () { 19 | 20 | this.id = 0; 21 | 22 | this.v1 = new THREE.RenderableVertex(); 23 | this.v2 = new THREE.RenderableVertex(); 24 | this.v3 = new THREE.RenderableVertex(); 25 | 26 | this.normalModel = new THREE.Vector3(); 27 | 28 | this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; 29 | this.vertexNormalsLength = 0; 30 | 31 | this.color = new THREE.Color(); 32 | this.material = null; 33 | this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ]; 34 | 35 | this.z = 0; 36 | 37 | }; 38 | 39 | // 40 | 41 | THREE.RenderableVertex = function () { 42 | 43 | this.position = new THREE.Vector3(); 44 | this.positionWorld = new THREE.Vector3(); 45 | this.positionScreen = new THREE.Vector4(); 46 | 47 | this.visible = true; 48 | 49 | }; 50 | 51 | THREE.RenderableVertex.prototype.copy = function ( vertex ) { 52 | 53 | this.positionWorld.copy( vertex.positionWorld ); 54 | this.positionScreen.copy( vertex.positionScreen ); 55 | 56 | }; 57 | 58 | // 59 | 60 | THREE.RenderableLine = function () { 61 | 62 | this.id = 0; 63 | 64 | this.v1 = new THREE.RenderableVertex(); 65 | this.v2 = new THREE.RenderableVertex(); 66 | 67 | this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; 68 | this.material = null; 69 | 70 | this.z = 0; 71 | 72 | }; 73 | 74 | // 75 | 76 | THREE.RenderableSprite = function () { 77 | 78 | this.id = 0; 79 | 80 | this.object = null; 81 | 82 | this.x = 0; 83 | this.y = 0; 84 | this.z = 0; 85 | 86 | this.rotation = 0; 87 | this.scale = new THREE.Vector2(); 88 | 89 | this.material = null; 90 | 91 | }; 92 | 93 | // 94 | 95 | THREE.Projector = function () { 96 | 97 | var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, 98 | _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, 99 | _face, _faceCount, _facePool = [], _facePoolLength = 0, 100 | _line, _lineCount, _linePool = [], _linePoolLength = 0, 101 | _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, 102 | 103 | _renderData = { objects: [], lights: [], elements: [] }, 104 | 105 | _vA = new THREE.Vector3(), 106 | _vB = new THREE.Vector3(), 107 | _vC = new THREE.Vector3(), 108 | 109 | _vector3 = new THREE.Vector3(), 110 | _vector4 = new THREE.Vector4(), 111 | 112 | _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ), 113 | _boundingBox = new THREE.Box3(), 114 | _points3 = new Array( 3 ), 115 | _points4 = new Array( 4 ), 116 | 117 | _viewMatrix = new THREE.Matrix4(), 118 | _viewProjectionMatrix = new THREE.Matrix4(), 119 | 120 | _modelMatrix, 121 | _modelViewProjectionMatrix = new THREE.Matrix4(), 122 | 123 | _normalMatrix = new THREE.Matrix3(), 124 | 125 | _frustum = new THREE.Frustum(), 126 | 127 | _clippedVertex1PositionScreen = new THREE.Vector4(), 128 | _clippedVertex2PositionScreen = new THREE.Vector4(); 129 | 130 | // 131 | 132 | this.projectVector = function ( vector, camera ) { 133 | 134 | console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); 135 | vector.project( camera ); 136 | 137 | }; 138 | 139 | this.unprojectVector = function ( vector, camera ) { 140 | 141 | console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); 142 | vector.unproject( camera ); 143 | 144 | }; 145 | 146 | this.pickingRay = function ( vector, camera ) { 147 | 148 | console.error( 'THREE.Projector: .pickingRay() has been removed.' ); 149 | 150 | }; 151 | 152 | // 153 | 154 | var RenderList = function () { 155 | 156 | var normals = []; 157 | var uvs = []; 158 | 159 | var object = null; 160 | var material = null; 161 | 162 | var normalMatrix = new THREE.Matrix3(); 163 | 164 | var setObject = function ( value ) { 165 | 166 | object = value; 167 | material = object.material; 168 | 169 | normalMatrix.getNormalMatrix( object.matrixWorld ); 170 | 171 | normals.length = 0; 172 | uvs.length = 0; 173 | 174 | }; 175 | 176 | var projectVertex = function ( vertex ) { 177 | 178 | var position = vertex.position; 179 | var positionWorld = vertex.positionWorld; 180 | var positionScreen = vertex.positionScreen; 181 | 182 | positionWorld.copy( position ).applyMatrix4( _modelMatrix ); 183 | positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); 184 | 185 | var invW = 1 / positionScreen.w; 186 | 187 | positionScreen.x *= invW; 188 | positionScreen.y *= invW; 189 | positionScreen.z *= invW; 190 | 191 | vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 && 192 | positionScreen.y >= - 1 && positionScreen.y <= 1 && 193 | positionScreen.z >= - 1 && positionScreen.z <= 1; 194 | 195 | }; 196 | 197 | var pushVertex = function ( x, y, z ) { 198 | 199 | _vertex = getNextVertexInPool(); 200 | _vertex.position.set( x, y, z ); 201 | 202 | projectVertex( _vertex ); 203 | 204 | }; 205 | 206 | var pushNormal = function ( x, y, z ) { 207 | 208 | normals.push( x, y, z ); 209 | 210 | }; 211 | 212 | var pushUv = function ( x, y ) { 213 | 214 | uvs.push( x, y ); 215 | 216 | }; 217 | 218 | var checkTriangleVisibility = function ( v1, v2, v3 ) { 219 | 220 | if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true; 221 | 222 | _points3[ 0 ] = v1.positionScreen; 223 | _points3[ 1 ] = v2.positionScreen; 224 | _points3[ 2 ] = v3.positionScreen; 225 | 226 | return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ); 227 | 228 | }; 229 | 230 | var checkBackfaceCulling = function ( v1, v2, v3 ) { 231 | 232 | return ( ( v3.positionScreen.x - v1.positionScreen.x ) * 233 | ( v2.positionScreen.y - v1.positionScreen.y ) - 234 | ( v3.positionScreen.y - v1.positionScreen.y ) * 235 | ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; 236 | 237 | }; 238 | 239 | var pushLine = function ( a, b ) { 240 | 241 | var v1 = _vertexPool[ a ]; 242 | var v2 = _vertexPool[ b ]; 243 | 244 | _line = getNextLineInPool(); 245 | 246 | _line.id = object.id; 247 | _line.v1.copy( v1 ); 248 | _line.v2.copy( v2 ); 249 | _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; 250 | 251 | _line.material = object.material; 252 | 253 | _renderData.elements.push( _line ); 254 | 255 | }; 256 | 257 | var pushTriangle = function ( a, b, c ) { 258 | 259 | var v1 = _vertexPool[ a ]; 260 | var v2 = _vertexPool[ b ]; 261 | var v3 = _vertexPool[ c ]; 262 | 263 | if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return; 264 | 265 | if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) { 266 | 267 | _face = getNextFaceInPool(); 268 | 269 | _face.id = object.id; 270 | _face.v1.copy( v1 ); 271 | _face.v2.copy( v2 ); 272 | _face.v3.copy( v3 ); 273 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; 274 | 275 | for ( var i = 0; i < 3; i ++ ) { 276 | 277 | var offset = arguments[ i ] * 3; 278 | var normal = _face.vertexNormalsModel[ i ]; 279 | 280 | normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] ); 281 | normal.applyMatrix3( normalMatrix ).normalize(); 282 | 283 | var offset2 = arguments[ i ] * 2; 284 | 285 | var uv = _face.uvs[ i ]; 286 | uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] ); 287 | 288 | } 289 | 290 | _face.vertexNormalsLength = 3; 291 | 292 | _face.material = object.material; 293 | 294 | _renderData.elements.push( _face ); 295 | 296 | } 297 | 298 | }; 299 | 300 | return { 301 | setObject: setObject, 302 | projectVertex: projectVertex, 303 | checkTriangleVisibility: checkTriangleVisibility, 304 | checkBackfaceCulling: checkBackfaceCulling, 305 | pushVertex: pushVertex, 306 | pushNormal: pushNormal, 307 | pushUv: pushUv, 308 | pushLine: pushLine, 309 | pushTriangle: pushTriangle 310 | } 311 | 312 | }; 313 | 314 | var renderList = new RenderList(); 315 | 316 | this.projectScene = function ( scene, camera, sortObjects, sortElements ) { 317 | 318 | _faceCount = 0; 319 | _lineCount = 0; 320 | _spriteCount = 0; 321 | 322 | _renderData.elements.length = 0; 323 | 324 | if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); 325 | if ( camera.parent === undefined ) camera.updateMatrixWorld(); 326 | 327 | _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); 328 | _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); 329 | 330 | _frustum.setFromMatrix( _viewProjectionMatrix ); 331 | 332 | // 333 | 334 | _objectCount = 0; 335 | 336 | _renderData.objects.length = 0; 337 | _renderData.lights.length = 0; 338 | 339 | scene.traverseVisible( function ( object ) { 340 | 341 | if ( object instanceof THREE.Light ) { 342 | 343 | _renderData.lights.push( object ); 344 | 345 | } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { 346 | 347 | if ( object.material.visible === false ) return; 348 | 349 | if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { 350 | 351 | _object = getNextObjectInPool(); 352 | _object.id = object.id; 353 | _object.object = object; 354 | 355 | if ( object.renderDepth !== null ) { 356 | 357 | _object.z = object.renderDepth; 358 | 359 | } else { 360 | 361 | _vector3.setFromMatrixPosition( object.matrixWorld ); 362 | _vector3.applyProjection( _viewProjectionMatrix ); 363 | _object.z = _vector3.z; 364 | 365 | } 366 | 367 | _renderData.objects.push( _object ); 368 | 369 | } 370 | 371 | } 372 | 373 | } ); 374 | 375 | if ( sortObjects === true ) { 376 | 377 | _renderData.objects.sort( painterSort ); 378 | 379 | } 380 | 381 | // 382 | 383 | for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { 384 | 385 | var object = _renderData.objects[ o ].object; 386 | var geometry = object.geometry; 387 | 388 | renderList.setObject( object ); 389 | 390 | _modelMatrix = object.matrixWorld; 391 | 392 | _vertexCount = 0; 393 | 394 | if ( object instanceof THREE.Mesh ) { 395 | 396 | if ( geometry instanceof THREE.BufferGeometry ) { 397 | 398 | var attributes = geometry.attributes; 399 | var offsets = geometry.offsets; 400 | 401 | if ( attributes.position === undefined ) continue; 402 | 403 | var positions = attributes.position.array; 404 | 405 | for ( var i = 0, l = positions.length; i < l; i += 3 ) { 406 | 407 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); 408 | 409 | } 410 | 411 | if ( attributes.normal !== undefined ) { 412 | 413 | var normals = attributes.normal.array; 414 | 415 | for ( var i = 0, l = normals.length; i < l; i += 3 ) { 416 | 417 | renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); 418 | 419 | } 420 | 421 | } 422 | 423 | if ( attributes.uv !== undefined ) { 424 | 425 | var uvs = attributes.uv.array; 426 | 427 | for ( var i = 0, l = uvs.length; i < l; i += 2 ) { 428 | 429 | renderList.pushUv( uvs[ i ], uvs[ i + 1 ] ); 430 | 431 | } 432 | 433 | } 434 | 435 | if ( attributes.index !== undefined ) { 436 | 437 | var indices = attributes.index.array; 438 | 439 | if ( offsets.length > 0 ) { 440 | 441 | for ( var o = 0; o < offsets.length; o ++ ) { 442 | 443 | var offset = offsets[ o ]; 444 | var index = offset.index; 445 | 446 | for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { 447 | 448 | renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); 449 | 450 | } 451 | 452 | } 453 | 454 | } else { 455 | 456 | for ( var i = 0, l = indices.length; i < l; i += 3 ) { 457 | 458 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); 459 | 460 | } 461 | 462 | } 463 | 464 | } else { 465 | 466 | for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { 467 | 468 | renderList.pushTriangle( i, i + 1, i + 2 ); 469 | 470 | } 471 | 472 | } 473 | 474 | } else if ( geometry instanceof THREE.Geometry ) { 475 | 476 | var vertices = geometry.vertices; 477 | var faces = geometry.faces; 478 | var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; 479 | 480 | _normalMatrix.getNormalMatrix( _modelMatrix ); 481 | 482 | var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; 483 | var objectMaterials = isFaceMaterial === true ? object.material : null; 484 | 485 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { 486 | 487 | var vertex = vertices[ v ]; 488 | renderList.pushVertex( vertex.x, vertex.y, vertex.z ); 489 | 490 | } 491 | 492 | for ( var f = 0, fl = faces.length; f < fl; f ++ ) { 493 | 494 | var face = faces[ f ]; 495 | 496 | var material = isFaceMaterial === true 497 | ? objectMaterials.materials[ face.materialIndex ] 498 | : object.material; 499 | 500 | if ( material === undefined ) continue; 501 | 502 | var side = material.side; 503 | 504 | var v1 = _vertexPool[ face.a ]; 505 | var v2 = _vertexPool[ face.b ]; 506 | var v3 = _vertexPool[ face.c ]; 507 | 508 | if ( material.morphTargets === true ) { 509 | 510 | var morphTargets = geometry.morphTargets; 511 | var morphInfluences = object.morphTargetInfluences; 512 | 513 | var v1p = v1.position; 514 | var v2p = v2.position; 515 | var v3p = v3.position; 516 | 517 | _vA.set( 0, 0, 0 ); 518 | _vB.set( 0, 0, 0 ); 519 | _vC.set( 0, 0, 0 ); 520 | 521 | for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { 522 | 523 | var influence = morphInfluences[ t ]; 524 | 525 | if ( influence === 0 ) continue; 526 | 527 | var targets = morphTargets[ t ].vertices; 528 | 529 | _vA.x += ( targets[ face.a ].x - v1p.x ) * influence; 530 | _vA.y += ( targets[ face.a ].y - v1p.y ) * influence; 531 | _vA.z += ( targets[ face.a ].z - v1p.z ) * influence; 532 | 533 | _vB.x += ( targets[ face.b ].x - v2p.x ) * influence; 534 | _vB.y += ( targets[ face.b ].y - v2p.y ) * influence; 535 | _vB.z += ( targets[ face.b ].z - v2p.z ) * influence; 536 | 537 | _vC.x += ( targets[ face.c ].x - v3p.x ) * influence; 538 | _vC.y += ( targets[ face.c ].y - v3p.y ) * influence; 539 | _vC.z += ( targets[ face.c ].z - v3p.z ) * influence; 540 | 541 | } 542 | 543 | v1.position.add( _vA ); 544 | v2.position.add( _vB ); 545 | v3.position.add( _vC ); 546 | 547 | renderList.projectVertex( v1 ); 548 | renderList.projectVertex( v2 ); 549 | renderList.projectVertex( v3 ); 550 | 551 | } 552 | 553 | if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue; 554 | 555 | var visible = renderList.checkBackfaceCulling( v1, v2, v3 ); 556 | 557 | if ( side !== THREE.DoubleSide ) { 558 | if ( side === THREE.FrontSide && visible === false ) continue; 559 | if ( side === THREE.BackSide && visible === true ) continue; 560 | } 561 | 562 | _face = getNextFaceInPool(); 563 | 564 | _face.id = object.id; 565 | _face.v1.copy( v1 ); 566 | _face.v2.copy( v2 ); 567 | _face.v3.copy( v3 ); 568 | 569 | _face.normalModel.copy( face.normal ); 570 | 571 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { 572 | 573 | _face.normalModel.negate(); 574 | 575 | } 576 | 577 | _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); 578 | 579 | var faceVertexNormals = face.vertexNormals; 580 | 581 | for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { 582 | 583 | var normalModel = _face.vertexNormalsModel[ n ]; 584 | normalModel.copy( faceVertexNormals[ n ] ); 585 | 586 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { 587 | 588 | normalModel.negate(); 589 | 590 | } 591 | 592 | normalModel.applyMatrix3( _normalMatrix ).normalize(); 593 | 594 | } 595 | 596 | _face.vertexNormalsLength = faceVertexNormals.length; 597 | 598 | var vertexUvs = faceVertexUvs[ f ]; 599 | 600 | if ( vertexUvs !== undefined ) { 601 | 602 | for ( var u = 0; u < 3; u ++ ) { 603 | 604 | _face.uvs[ u ].copy( vertexUvs[ u ] ); 605 | 606 | } 607 | 608 | } 609 | 610 | _face.color = face.color; 611 | _face.material = material; 612 | 613 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; 614 | 615 | _renderData.elements.push( _face ); 616 | 617 | } 618 | 619 | } 620 | 621 | } else if ( object instanceof THREE.Line ) { 622 | 623 | if ( geometry instanceof THREE.BufferGeometry ) { 624 | 625 | var attributes = geometry.attributes; 626 | 627 | if ( attributes.position !== undefined ) { 628 | 629 | var positions = attributes.position.array; 630 | 631 | for ( var i = 0, l = positions.length; i < l; i += 3 ) { 632 | 633 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); 634 | 635 | } 636 | 637 | if ( attributes.index !== undefined ) { 638 | 639 | var indices = attributes.index.array; 640 | 641 | for ( var i = 0, l = indices.length; i < l; i += 2 ) { 642 | 643 | renderList.pushLine( indices[ i ], indices[ i + 1 ] ); 644 | 645 | } 646 | 647 | } else { 648 | 649 | var step = object.mode === THREE.LinePieces ? 2 : 1; 650 | 651 | for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) { 652 | 653 | renderList.pushLine( i, i + 1 ); 654 | 655 | } 656 | 657 | } 658 | 659 | } 660 | 661 | } else if ( geometry instanceof THREE.Geometry ) { 662 | 663 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); 664 | 665 | var vertices = object.geometry.vertices; 666 | 667 | if ( vertices.length === 0 ) continue; 668 | 669 | v1 = getNextVertexInPool(); 670 | v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); 671 | 672 | // Handle LineStrip and LinePieces 673 | var step = object.mode === THREE.LinePieces ? 2 : 1; 674 | 675 | for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { 676 | 677 | v1 = getNextVertexInPool(); 678 | v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); 679 | 680 | if ( ( v + 1 ) % step > 0 ) continue; 681 | 682 | v2 = _vertexPool[ _vertexCount - 2 ]; 683 | 684 | _clippedVertex1PositionScreen.copy( v1.positionScreen ); 685 | _clippedVertex2PositionScreen.copy( v2.positionScreen ); 686 | 687 | if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { 688 | 689 | // Perform the perspective divide 690 | _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); 691 | _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); 692 | 693 | _line = getNextLineInPool(); 694 | 695 | _line.id = object.id; 696 | _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); 697 | _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); 698 | 699 | _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); 700 | 701 | _line.material = object.material; 702 | 703 | if ( object.material.vertexColors === THREE.VertexColors ) { 704 | 705 | _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); 706 | _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); 707 | 708 | } 709 | 710 | _renderData.elements.push( _line ); 711 | 712 | } 713 | 714 | } 715 | 716 | } 717 | 718 | } else if ( object instanceof THREE.Sprite ) { 719 | 720 | _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 ); 721 | _vector4.applyMatrix4( _viewProjectionMatrix ); 722 | 723 | var invW = 1 / _vector4.w; 724 | 725 | _vector4.z *= invW; 726 | 727 | if ( _vector4.z >= - 1 && _vector4.z <= 1 ) { 728 | 729 | _sprite = getNextSpriteInPool(); 730 | _sprite.id = object.id; 731 | _sprite.x = _vector4.x * invW; 732 | _sprite.y = _vector4.y * invW; 733 | _sprite.z = _vector4.z; 734 | _sprite.object = object; 735 | 736 | _sprite.rotation = object.rotation; 737 | 738 | _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) ); 739 | _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) ); 740 | 741 | _sprite.material = object.material; 742 | 743 | _renderData.elements.push( _sprite ); 744 | 745 | } 746 | 747 | } 748 | 749 | } 750 | 751 | if ( sortElements === true ) { 752 | 753 | _renderData.elements.sort( painterSort ); 754 | 755 | } 756 | 757 | return _renderData; 758 | 759 | }; 760 | 761 | // Pools 762 | 763 | function getNextObjectInPool() { 764 | 765 | if ( _objectCount === _objectPoolLength ) { 766 | 767 | var object = new THREE.RenderableObject(); 768 | _objectPool.push( object ); 769 | _objectPoolLength ++; 770 | _objectCount ++; 771 | return object; 772 | 773 | } 774 | 775 | return _objectPool[ _objectCount ++ ]; 776 | 777 | } 778 | 779 | function getNextVertexInPool() { 780 | 781 | if ( _vertexCount === _vertexPoolLength ) { 782 | 783 | var vertex = new THREE.RenderableVertex(); 784 | _vertexPool.push( vertex ); 785 | _vertexPoolLength ++; 786 | _vertexCount ++; 787 | return vertex; 788 | 789 | } 790 | 791 | return _vertexPool[ _vertexCount ++ ]; 792 | 793 | } 794 | 795 | function getNextFaceInPool() { 796 | 797 | if ( _faceCount === _facePoolLength ) { 798 | 799 | var face = new THREE.RenderableFace(); 800 | _facePool.push( face ); 801 | _facePoolLength ++; 802 | _faceCount ++; 803 | return face; 804 | 805 | } 806 | 807 | return _facePool[ _faceCount ++ ]; 808 | 809 | 810 | } 811 | 812 | function getNextLineInPool() { 813 | 814 | if ( _lineCount === _linePoolLength ) { 815 | 816 | var line = new THREE.RenderableLine(); 817 | _linePool.push( line ); 818 | _linePoolLength ++; 819 | _lineCount ++ 820 | return line; 821 | 822 | } 823 | 824 | return _linePool[ _lineCount ++ ]; 825 | 826 | } 827 | 828 | function getNextSpriteInPool() { 829 | 830 | if ( _spriteCount === _spritePoolLength ) { 831 | 832 | var sprite = new THREE.RenderableSprite(); 833 | _spritePool.push( sprite ); 834 | _spritePoolLength ++; 835 | _spriteCount ++ 836 | return sprite; 837 | 838 | } 839 | 840 | return _spritePool[ _spriteCount ++ ]; 841 | 842 | } 843 | 844 | // 845 | 846 | function painterSort( a, b ) { 847 | 848 | if ( a.z !== b.z ) { 849 | 850 | return b.z - a.z; 851 | 852 | } else if ( a.id !== b.id ) { 853 | 854 | return a.id - b.id; 855 | 856 | } else { 857 | 858 | return 0; 859 | 860 | } 861 | 862 | } 863 | 864 | function clipLine( s1, s2 ) { 865 | 866 | var alpha1 = 0, alpha2 = 1, 867 | 868 | // Calculate the boundary coordinate of each vertex for the near and far clip planes, 869 | // Z = -1 and Z = +1, respectively. 870 | bc1near = s1.z + s1.w, 871 | bc2near = s2.z + s2.w, 872 | bc1far = - s1.z + s1.w, 873 | bc2far = - s2.z + s2.w; 874 | 875 | if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { 876 | 877 | // Both vertices lie entirely within all clip planes. 878 | return true; 879 | 880 | } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) { 881 | 882 | // Both vertices lie entirely outside one of the clip planes. 883 | return false; 884 | 885 | } else { 886 | 887 | // The line segment spans at least one clip plane. 888 | 889 | if ( bc1near < 0 ) { 890 | 891 | // v1 lies outside the near plane, v2 inside 892 | alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); 893 | 894 | } else if ( bc2near < 0 ) { 895 | 896 | // v2 lies outside the near plane, v1 inside 897 | alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); 898 | 899 | } 900 | 901 | if ( bc1far < 0 ) { 902 | 903 | // v1 lies outside the far plane, v2 inside 904 | alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); 905 | 906 | } else if ( bc2far < 0 ) { 907 | 908 | // v2 lies outside the far plane, v2 inside 909 | alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); 910 | 911 | } 912 | 913 | if ( alpha2 < alpha1 ) { 914 | 915 | // The line segment spans two boundaries, but is outside both of them. 916 | // (This can't happen when we're only clipping against just near/far but good 917 | // to leave the check here for future usage if other clip planes are added.) 918 | return false; 919 | 920 | } else { 921 | 922 | // Update the s1 and s2 vertices to match the clipped line segment. 923 | s1.lerp( s2, alpha1 ); 924 | s2.lerp( s1, 1 - alpha2 ); 925 | 926 | return true; 927 | 928 | } 929 | 930 | } 931 | 932 | } 933 | 934 | }; 935 | -------------------------------------------------------------------------------- /libs/RenderPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) { 6 | 7 | this.scene = scene; 8 | this.camera = camera; 9 | 10 | this.overrideMaterial = overrideMaterial; 11 | 12 | this.clearColor = clearColor; 13 | this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1; 14 | 15 | this.oldClearColor = new THREE.Color(); 16 | this.oldClearAlpha = 1; 17 | 18 | this.enabled = true; 19 | this.clear = true; 20 | this.needsSwap = false; 21 | 22 | }; 23 | 24 | THREE.RenderPass.prototype = { 25 | 26 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 27 | 28 | this.scene.overrideMaterial = this.overrideMaterial; 29 | 30 | if ( this.clearColor ) { 31 | 32 | this.oldClearColor.copy( renderer.getClearColor() ); 33 | this.oldClearAlpha = renderer.getClearAlpha(); 34 | 35 | renderer.setClearColor( this.clearColor, this.clearAlpha ); 36 | 37 | } 38 | 39 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 40 | 41 | if ( this.clearColor ) { 42 | 43 | renderer.setClearColor( this.oldClearColor, this.oldClearAlpha ); 44 | 45 | } 46 | 47 | this.scene.overrideMaterial = null; 48 | 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /libs/ShaderDeferred.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * @author MPanknin / http://www.redplant.de/ 4 | * @author benaadams / http://blog.illyriad.co.uk/ 5 | * 6 | */ 7 | 8 | 9 | THREE.DeferredShaderChunk = { 10 | 11 | // decode float to vec3 12 | 13 | unpackFloat: [ 14 | 15 | "vec3 float_to_vec3( float data ) {", 16 | 17 | "vec3 uncompressed;", 18 | "uncompressed.x = fract( data );", 19 | "float zInt = floor( data / 255.0 );", 20 | "uncompressed.z = fract( zInt / 255.0 );", 21 | "uncompressed.y = fract( floor( data - ( zInt * 255.0 ) ) / 255.0 );", 22 | "return uncompressed;", 23 | 24 | "}" 25 | 26 | ].join("\n"), 27 | 28 | computeVertexPositionVS: [ 29 | 30 | "vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );", 31 | 32 | "vec4 normalDepth = texture2D( samplerNormalDepth, texCoord );", 33 | "float z = normalDepth.w;", 34 | 35 | "if ( z == 0.0 ) discard;", 36 | 37 | "vec2 xy = texCoord * 2.0 - 1.0;", 38 | 39 | "vec4 vertexPositionProjected = vec4( xy, z, 1.0 );", 40 | "vec4 vertexPositionVS = matProjInverse * vertexPositionProjected;", 41 | "vertexPositionVS.xyz /= vertexPositionVS.w;", 42 | "vertexPositionVS.w = 1.0;" 43 | 44 | ].join("\n"), 45 | 46 | computeNormal: [ 47 | 48 | "vec3 normal = normalDepth.xyz * 2.0 - 1.0;" 49 | 50 | ].join("\n"), 51 | 52 | unpackColorMap: [ 53 | 54 | "vec4 colorMap = texture2D( samplerColor, texCoord );", 55 | 56 | "vec3 albedo = float_to_vec3( abs( colorMap.x ) );", 57 | "vec3 specularColor = float_to_vec3( abs( colorMap.y ) );", 58 | "float shininess = abs( colorMap.z );", 59 | "float wrapAround = sign( colorMap.z );", 60 | "float additiveSpecular = sign( colorMap.y );" 61 | 62 | ].join("\n"), 63 | 64 | computeDiffuse: [ 65 | 66 | "float dotProduct = dot( normal, lightVector );", 67 | "float diffuseFull = max( dotProduct, 0.0 );", 68 | 69 | "vec3 diffuse;", 70 | 71 | "if ( wrapAround < 0.0 ) {", 72 | 73 | // wrap around lighting 74 | 75 | "float diffuseHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", 76 | 77 | "const vec3 wrapRGB = vec3( 1.0, 1.0, 1.0 );", 78 | "diffuse = mix( vec3( diffuseFull ), vec3( diffuseHalf ), wrapRGB );", 79 | 80 | "} else {", 81 | 82 | // simple lighting 83 | 84 | "diffuse = vec3( diffuseFull );", 85 | 86 | "}" 87 | 88 | ].join("\n"), 89 | 90 | computeSpecular: [ 91 | 92 | "vec3 halfVector = normalize( lightVector - normalize( vertexPositionVS.xyz ) );", 93 | "float dotNormalHalf = max( dot( normal, halfVector ), 0.0 );", 94 | 95 | // simple specular 96 | 97 | //"vec3 specular = specularColor * max( pow( dotNormalHalf, shininess ), 0.0 ) * diffuse;", 98 | 99 | // physically based specular 100 | 101 | "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", 102 | 103 | "vec3 schlick = specularColor + vec3( 1.0 - specularColor ) * pow( 1.0 - dot( lightVector, halfVector ), 5.0 );", 104 | "vec3 specular = schlick * max( pow( dotNormalHalf, shininess ), 0.0 ) * diffuse * specularNormalization;" 105 | 106 | ].join("\n"), 107 | 108 | combine: [ 109 | 110 | "vec3 light = lightIntensity * lightColor;", 111 | "gl_FragColor = vec4( light * ( albedo * diffuse + specular ), attenuation );" 112 | 113 | ].join("\n") 114 | 115 | }; 116 | 117 | THREE.ShaderDeferred = { 118 | 119 | "color" : { 120 | 121 | uniforms: THREE.UniformsUtils.merge( [ 122 | 123 | THREE.UniformsLib[ "common" ], 124 | THREE.UniformsLib[ "fog" ], 125 | THREE.UniformsLib[ "shadowmap" ], 126 | 127 | { 128 | "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, 129 | "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, 130 | "shininess": { type: "f", value: 30 }, 131 | "wrapAround": { type: "f", value: 1 }, 132 | "additiveSpecular": { type: "f", value: 1 }, 133 | 134 | "samplerNormalDepth": { type: "t", value: null }, 135 | "viewWidth": { type: "f", value: 800 }, 136 | "viewHeight": { type: "f", value: 600 } 137 | } 138 | 139 | ] ), 140 | 141 | fragmentShader : [ 142 | 143 | "uniform vec3 diffuse;", 144 | "uniform vec3 specular;", 145 | "uniform vec3 emissive;", 146 | "uniform float shininess;", 147 | "uniform float wrapAround;", 148 | "uniform float additiveSpecular;", 149 | 150 | THREE.ShaderChunk[ "color_pars_fragment" ], 151 | THREE.ShaderChunk[ "map_pars_fragment" ], 152 | THREE.ShaderChunk[ "lightmap_pars_fragment" ], 153 | 154 | "#ifdef USE_ENVMAP", 155 | 156 | "varying vec3 vWorldPosition;", 157 | 158 | "uniform float reflectivity;", 159 | "uniform samplerCube envMap;", 160 | "uniform float flipEnvMap;", 161 | "uniform int combine;", 162 | 163 | "uniform bool useRefract;", 164 | "uniform float refractionRatio;", 165 | 166 | "uniform sampler2D samplerNormalDepth;", 167 | "uniform float viewHeight;", 168 | "uniform float viewWidth;", 169 | 170 | "#endif", 171 | 172 | THREE.ShaderChunk[ "fog_pars_fragment" ], 173 | THREE.ShaderChunk[ "shadowmap_pars_fragment" ], 174 | THREE.ShaderChunk[ "specularmap_pars_fragment" ], 175 | 176 | "const float unit = 255.0/256.0;", 177 | 178 | "float vec3_to_float( vec3 data ) {", 179 | 180 | "highp float compressed = fract( data.x * unit ) + floor( data.y * unit * 255.0 ) + floor( data.z * unit * 255.0 ) * 255.0;", 181 | "return compressed;", 182 | 183 | "}", 184 | 185 | "void main() {", 186 | 187 | "const float opacity = 1.0;", 188 | 189 | "gl_FragColor = vec4( diffuse, opacity );", 190 | 191 | THREE.ShaderChunk[ "map_fragment" ], 192 | THREE.ShaderChunk[ "alphatest_fragment" ], 193 | THREE.ShaderChunk[ "specularmap_fragment" ], 194 | THREE.ShaderChunk[ "lightmap_fragment" ], 195 | THREE.ShaderChunk[ "color_fragment" ], 196 | 197 | "#ifdef USE_ENVMAP", 198 | 199 | "vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );", 200 | "vec4 normalDepth = texture2D( samplerNormalDepth, texCoord );", 201 | "vec3 normal = normalDepth.xyz * 2.0 - 1.0;", 202 | 203 | "vec3 reflectVec;", 204 | 205 | "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", 206 | 207 | "if ( useRefract ) {", 208 | 209 | "reflectVec = refract( cameraToVertex, normal, refractionRatio );", 210 | 211 | "} else { ", 212 | 213 | "reflectVec = reflect( cameraToVertex, normal );", 214 | 215 | "}", 216 | 217 | "#ifdef DOUBLE_SIDED", 218 | 219 | "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", 220 | "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", 221 | 222 | "#else", 223 | 224 | "vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", 225 | 226 | "#endif", 227 | 228 | "#ifdef GAMMA_INPUT", 229 | 230 | "cubeColor.xyz *= cubeColor.xyz;", 231 | 232 | "#endif", 233 | 234 | "if ( combine == 1 ) {", 235 | 236 | "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );", 237 | 238 | "} else if ( combine == 2 ) {", 239 | 240 | "gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;", 241 | 242 | "} else {", 243 | 244 | "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );", 245 | 246 | "}", 247 | 248 | "#endif", 249 | 250 | THREE.ShaderChunk[ "shadowmap_fragment" ], 251 | THREE.ShaderChunk[ "fog_fragment" ], 252 | 253 | // 254 | 255 | "const float compressionScale = 0.999;", 256 | 257 | // 258 | 259 | "vec3 diffuseMapColor;", 260 | 261 | "#ifdef USE_MAP", 262 | 263 | "diffuseMapColor = texelColor.xyz;", 264 | 265 | "#else", 266 | 267 | "diffuseMapColor = vec3( 1.0 );", 268 | 269 | "#endif", 270 | 271 | // diffuse color 272 | 273 | "gl_FragColor.x = vec3_to_float( compressionScale * gl_FragColor.xyz );", 274 | 275 | // specular color 276 | 277 | "if ( additiveSpecular < 0.0 ) {", 278 | 279 | "gl_FragColor.y = vec3_to_float( compressionScale * specular );", 280 | 281 | "} else {", 282 | 283 | "gl_FragColor.y = vec3_to_float( compressionScale * specular * diffuseMapColor );", 284 | 285 | "}", 286 | 287 | "gl_FragColor.y *= additiveSpecular;", 288 | 289 | // shininess 290 | 291 | "gl_FragColor.z = wrapAround * shininess;", 292 | 293 | // emissive color 294 | 295 | "#ifdef USE_COLOR", 296 | 297 | "gl_FragColor.w = vec3_to_float( compressionScale * emissive * diffuseMapColor * vColor );", 298 | 299 | "#else", 300 | 301 | "gl_FragColor.w = vec3_to_float( compressionScale * emissive * diffuseMapColor );", 302 | 303 | "#endif", 304 | 305 | "}" 306 | 307 | ].join("\n"), 308 | 309 | vertexShader : [ 310 | 311 | THREE.ShaderChunk[ "map_pars_vertex" ], 312 | THREE.ShaderChunk[ "lightmap_pars_vertex" ], 313 | THREE.ShaderChunk[ "color_pars_vertex" ], 314 | THREE.ShaderChunk[ "morphtarget_pars_vertex" ], 315 | THREE.ShaderChunk[ "skinning_pars_vertex" ], 316 | THREE.ShaderChunk[ "shadowmap_pars_vertex" ], 317 | 318 | "#ifdef USE_ENVMAP", 319 | 320 | "varying vec3 vWorldPosition;", 321 | 322 | "#endif", 323 | 324 | "void main() {", 325 | 326 | THREE.ShaderChunk[ "map_vertex" ], 327 | THREE.ShaderChunk[ "lightmap_vertex" ], 328 | THREE.ShaderChunk[ "color_vertex" ], 329 | 330 | THREE.ShaderChunk[ "skinbase_vertex" ], 331 | 332 | THREE.ShaderChunk[ "morphtarget_vertex" ], 333 | THREE.ShaderChunk[ "skinning_vertex" ], 334 | THREE.ShaderChunk[ "default_vertex" ], 335 | 336 | THREE.ShaderChunk[ "worldpos_vertex" ], 337 | THREE.ShaderChunk[ "shadowmap_vertex" ], 338 | 339 | "#ifdef USE_ENVMAP", 340 | 341 | "vWorldPosition = worldPosition.xyz;", 342 | 343 | "#endif", 344 | 345 | "}" 346 | 347 | ].join("\n") 348 | 349 | }, 350 | 351 | "normalDepth" : { 352 | 353 | uniforms: { 354 | 355 | bumpMap: { type: "t", value: null }, 356 | bumpScale: { type: "f", value: 1 }, 357 | offsetRepeat: { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) } 358 | 359 | }, 360 | 361 | fragmentShader : [ 362 | 363 | "#ifdef USE_BUMPMAP", 364 | 365 | "#extension GL_OES_standard_derivatives : enable\n", 366 | 367 | "varying vec2 vUv;", 368 | "varying vec3 vViewPosition;", 369 | 370 | THREE.ShaderChunk[ "bumpmap_pars_fragment" ], 371 | 372 | "#endif", 373 | 374 | "varying vec3 normalView;", 375 | "varying vec4 clipPos;", 376 | 377 | "void main() {", 378 | 379 | "vec3 normal = normalize( normalView );", 380 | 381 | "#ifdef USE_BUMPMAP", 382 | 383 | "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", 384 | 385 | "#endif", 386 | 387 | "gl_FragColor.xyz = normal * 0.5 + 0.5;", 388 | "gl_FragColor.w = clipPos.z / clipPos.w;", 389 | 390 | "}" 391 | 392 | ].join("\n"), 393 | 394 | vertexShader : [ 395 | 396 | "varying vec3 normalView;", 397 | "varying vec4 clipPos;", 398 | 399 | "#ifdef USE_BUMPMAP", 400 | 401 | "varying vec2 vUv;", 402 | "varying vec3 vViewPosition;", 403 | 404 | "uniform vec4 offsetRepeat;", 405 | 406 | "#endif", 407 | 408 | THREE.ShaderChunk[ "morphtarget_pars_vertex" ], 409 | THREE.ShaderChunk[ "skinning_pars_vertex" ], 410 | 411 | "void main() {", 412 | 413 | THREE.ShaderChunk[ "morphnormal_vertex" ], 414 | THREE.ShaderChunk[ "skinbase_vertex" ], 415 | THREE.ShaderChunk[ "skinnormal_vertex" ], 416 | THREE.ShaderChunk[ "defaultnormal_vertex" ], 417 | 418 | THREE.ShaderChunk[ "morphtarget_vertex" ], 419 | THREE.ShaderChunk[ "skinning_vertex" ], 420 | THREE.ShaderChunk[ "default_vertex" ], 421 | 422 | "normalView = normalize( normalMatrix * objectNormal );", 423 | 424 | "#ifdef USE_BUMPMAP", 425 | 426 | "vUv = uv * offsetRepeat.zw + offsetRepeat.xy;", 427 | "vViewPosition = -mvPosition.xyz;", 428 | 429 | "#endif", 430 | 431 | "clipPos = gl_Position;", 432 | 433 | "}" 434 | 435 | ].join("\n") 436 | 437 | }, 438 | 439 | "composite" : { 440 | 441 | uniforms: { 442 | 443 | samplerLight: { type: "t", value: null }, 444 | brightness: { type: "f", value: 1 } 445 | 446 | }, 447 | 448 | fragmentShader : [ 449 | 450 | "varying vec2 texCoord;", 451 | "uniform sampler2D samplerLight;", 452 | "uniform float brightness;", 453 | 454 | // tonemapping operators 455 | // based on John Hable's HLSL snippets 456 | // from http://filmicgames.com/archives/75 457 | 458 | "#ifdef TONEMAP_UNCHARTED", 459 | 460 | "const float A = 0.15;", 461 | "const float B = 0.50;", 462 | "const float C = 0.10;", 463 | "const float D = 0.20;", 464 | "const float E = 0.02;", 465 | "const float F = 0.30;", 466 | "const float W = 11.2;", 467 | 468 | "vec3 Uncharted2Tonemap( vec3 x ) {", 469 | 470 | "return ( ( x * ( A * x + C * B ) + D * E ) / ( x * ( A * x + B ) + D * F ) ) - E / F;", 471 | 472 | "}", 473 | 474 | "#endif", 475 | 476 | "void main() {", 477 | 478 | "vec3 inColor = texture2D( samplerLight, texCoord ).xyz;", 479 | "inColor *= brightness;", 480 | 481 | "vec3 outColor;", 482 | 483 | "#if defined( TONEMAP_SIMPLE )", 484 | 485 | "outColor = sqrt( inColor );", 486 | 487 | "#elif defined( TONEMAP_LINEAR )", 488 | 489 | // simple linear to gamma conversion 490 | 491 | "outColor = pow( inColor, vec3( 1.0 / 2.2 ) );", 492 | 493 | "#elif defined( TONEMAP_REINHARD )", 494 | 495 | // Reinhard operator 496 | 497 | "inColor = inColor / ( 1.0 + inColor );", 498 | "outColor = pow( inColor, vec3( 1.0 / 2.2 ) );", 499 | 500 | "#elif defined( TONEMAP_FILMIC )", 501 | 502 | // filmic operator by Jim Hejl and Richard Burgess-Dawson 503 | 504 | "vec3 x = max( vec3( 0.0 ), inColor - 0.004 );", 505 | "outColor = ( x * ( 6.2 * x + 0.5 ) ) / ( x * ( 6.2 * x + 1.7 ) + 0.06 );", 506 | 507 | "#elif defined( TONEMAP_UNCHARTED )", 508 | 509 | // tonemapping operator from Uncharted 2 by John Hable 510 | 511 | "float ExposureBias = 2.0;", 512 | "vec3 curr = Uncharted2Tonemap( ExposureBias * inColor );", 513 | 514 | "vec3 whiteScale = vec3( 1.0 ) / Uncharted2Tonemap( vec3( W ) );", 515 | "vec3 color = curr * whiteScale;", 516 | 517 | "outColor = pow( color, vec3( 1.0 / 2.2 ) );", 518 | 519 | "#else", 520 | 521 | "outColor = inColor;", 522 | 523 | "#endif", 524 | 525 | "gl_FragColor = vec4( outColor, 1.0 );", 526 | 527 | "}" 528 | 529 | ].join("\n"), 530 | 531 | vertexShader : [ 532 | 533 | "varying vec2 texCoord;", 534 | 535 | "void main() {", 536 | 537 | "vec4 pos = vec4( sign( position.xy ), 0.0, 1.0 );", 538 | "texCoord = pos.xy * vec2( 0.5 ) + 0.5;", 539 | "gl_Position = pos;", 540 | 541 | "}" 542 | 543 | ].join("\n") 544 | 545 | }, 546 | 547 | "pointLight" : { 548 | 549 | uniforms: { 550 | 551 | samplerNormalDepth: { type: "t", value: null }, 552 | samplerColor: { type: "t", value: null }, 553 | matProjInverse: { type: "m4", value: new THREE.Matrix4() }, 554 | viewWidth: { type: "f", value: 800 }, 555 | viewHeight: { type: "f", value: 600 }, 556 | 557 | lightPositionVS:{ type: "v3", value: new THREE.Vector3( 0, 0, 0 ) }, 558 | lightColor: { type: "c", value: new THREE.Color( 0x000000 ) }, 559 | lightIntensity: { type: "f", value: 1.0 }, 560 | lightRadius: { type: "f", value: 1.0 } 561 | 562 | }, 563 | 564 | fragmentShader : [ 565 | 566 | "uniform sampler2D samplerColor;", 567 | "uniform sampler2D samplerNormalDepth;", 568 | 569 | "uniform float lightRadius;", 570 | "uniform float lightIntensity;", 571 | "uniform float viewHeight;", 572 | "uniform float viewWidth;", 573 | 574 | "uniform vec3 lightColor;", 575 | "uniform vec3 lightPositionVS;", 576 | 577 | "uniform mat4 matProjInverse;", 578 | 579 | THREE.DeferredShaderChunk[ "unpackFloat" ], 580 | 581 | "void main() {", 582 | 583 | THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], 584 | 585 | // bail out early when pixel outside of light sphere 586 | 587 | "vec3 lightVector = lightPositionVS - vertexPositionVS.xyz;", 588 | "float distance = length( lightVector );", 589 | 590 | "if ( distance > lightRadius ) discard;", 591 | 592 | THREE.DeferredShaderChunk[ "computeNormal" ], 593 | THREE.DeferredShaderChunk[ "unpackColorMap" ], 594 | 595 | // compute light 596 | 597 | "lightVector = normalize( lightVector );", 598 | 599 | THREE.DeferredShaderChunk[ "computeDiffuse" ], 600 | THREE.DeferredShaderChunk[ "computeSpecular" ], 601 | 602 | // combine 603 | 604 | "float cutoff = 0.3;", 605 | "float denom = distance / lightRadius + 1.0;", 606 | "float attenuation = 1.0 / ( denom * denom );", 607 | "attenuation = ( attenuation - cutoff ) / ( 1.0 - cutoff );", 608 | "attenuation = max( attenuation, 0.0 );", 609 | "attenuation *= attenuation;", 610 | 611 | THREE.DeferredShaderChunk[ "combine" ], 612 | 613 | "}" 614 | 615 | ].join("\n"), 616 | 617 | vertexShader : [ 618 | 619 | "void main() { ", 620 | 621 | // sphere proxy needs real position 622 | 623 | "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", 624 | "gl_Position = projectionMatrix * mvPosition;", 625 | 626 | "}" 627 | 628 | ].join("\n") 629 | 630 | }, 631 | 632 | "spotLight" : { 633 | 634 | uniforms: { 635 | 636 | samplerNormalDepth: { type: "t", value: null }, 637 | samplerColor: { type: "t", value: null }, 638 | matProjInverse: { type: "m4", value: new THREE.Matrix4() }, 639 | viewWidth: { type: "f", value: 800 }, 640 | viewHeight: { type: "f", value: 600 }, 641 | 642 | lightPositionVS :{ type: "v3", value: new THREE.Vector3( 0, 1, 0 ) }, 643 | lightDirectionVS:{ type: "v3", value: new THREE.Vector3( 0, 1, 0 ) }, 644 | lightColor: { type: "c", value: new THREE.Color( 0x000000 ) }, 645 | lightIntensity: { type: "f", value: 1.0 }, 646 | lightDistance: { type: "f", value: 1.0 }, 647 | lightAngle: { type: "f", value: 1.0 } 648 | 649 | }, 650 | 651 | fragmentShader : [ 652 | 653 | "uniform vec3 lightPositionVS;", 654 | "uniform vec3 lightDirectionVS;", 655 | 656 | "uniform sampler2D samplerColor;", 657 | "uniform sampler2D samplerNormalDepth;", 658 | 659 | "uniform float viewHeight;", 660 | "uniform float viewWidth;", 661 | 662 | "uniform float lightAngle;", 663 | "uniform float lightIntensity;", 664 | "uniform vec3 lightColor;", 665 | 666 | "uniform mat4 matProjInverse;", 667 | 668 | THREE.DeferredShaderChunk[ "unpackFloat" ], 669 | 670 | "void main() {", 671 | 672 | THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], 673 | THREE.DeferredShaderChunk[ "computeNormal" ], 674 | THREE.DeferredShaderChunk[ "unpackColorMap" ], 675 | 676 | // compute light 677 | 678 | "vec3 lightVector = normalize( lightPositionVS.xyz - vertexPositionVS.xyz );", 679 | 680 | "float rho = dot( lightDirectionVS, lightVector );", 681 | "float rhoMax = cos( lightAngle * 0.5 );", 682 | 683 | "if ( rho <= rhoMax ) discard;", 684 | 685 | "float theta = rhoMax + 0.0001;", 686 | "float phi = rhoMax + 0.05;", 687 | "float falloff = 4.0;", 688 | 689 | "float spot = 0.0;", 690 | 691 | "if ( rho >= phi ) {", 692 | 693 | "spot = 1.0;", 694 | 695 | "} else if ( rho <= theta ) {", 696 | 697 | "spot = 0.0;", 698 | 699 | "} else { ", 700 | 701 | "spot = pow( ( rho - theta ) / ( phi - theta ), falloff );", 702 | 703 | "}", 704 | 705 | THREE.DeferredShaderChunk[ "computeDiffuse" ], 706 | 707 | "diffuse *= spot;", 708 | 709 | THREE.DeferredShaderChunk[ "computeSpecular" ], 710 | 711 | // combine 712 | 713 | "const float attenuation = 1.0;", 714 | 715 | THREE.DeferredShaderChunk[ "combine" ], 716 | 717 | "}" 718 | 719 | ].join("\n"), 720 | 721 | vertexShader : [ 722 | 723 | "void main() { ", 724 | 725 | // full screen quad proxy 726 | 727 | "gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", 728 | 729 | "}" 730 | 731 | ].join("\n") 732 | 733 | }, 734 | 735 | "directionalLight" : { 736 | 737 | uniforms: { 738 | 739 | samplerNormalDepth: { type: "t", value: null }, 740 | samplerColor: { type: "t", value: null }, 741 | matProjInverse: { type: "m4", value: new THREE.Matrix4() }, 742 | viewWidth: { type: "f", value: 800 }, 743 | viewHeight: { type: "f", value: 600 }, 744 | 745 | lightDirectionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) }, 746 | lightColor: { type: "c", value: new THREE.Color( 0x000000 ) }, 747 | lightIntensity: { type: "f", value: 1.0 } 748 | 749 | }, 750 | 751 | fragmentShader : [ 752 | 753 | "uniform sampler2D samplerColor;", 754 | "uniform sampler2D samplerNormalDepth;", 755 | 756 | "uniform float lightRadius;", 757 | "uniform float lightIntensity;", 758 | "uniform float viewHeight;", 759 | "uniform float viewWidth;", 760 | 761 | "uniform vec3 lightColor;", 762 | "uniform vec3 lightDirectionVS;", 763 | 764 | "uniform mat4 matProjInverse;", 765 | 766 | THREE.DeferredShaderChunk[ "unpackFloat" ], 767 | 768 | "void main() {", 769 | 770 | THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], 771 | THREE.DeferredShaderChunk[ "computeNormal" ], 772 | THREE.DeferredShaderChunk[ "unpackColorMap" ], 773 | 774 | // compute light 775 | 776 | "vec3 lightVector = lightDirectionVS;", 777 | 778 | THREE.DeferredShaderChunk[ "computeDiffuse" ], 779 | THREE.DeferredShaderChunk[ "computeSpecular" ], 780 | 781 | // combine 782 | 783 | "const float attenuation = 1.0;", 784 | 785 | THREE.DeferredShaderChunk[ "combine" ], 786 | 787 | "}" 788 | 789 | ].join("\n"), 790 | 791 | vertexShader : [ 792 | 793 | "void main() { ", 794 | 795 | // full screen quad proxy 796 | 797 | "gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", 798 | 799 | "}" 800 | 801 | ].join("\n") 802 | 803 | }, 804 | 805 | "hemisphereLight" : { 806 | 807 | uniforms: { 808 | 809 | samplerNormalDepth: { type: "t", value: null }, 810 | samplerColor: { type: "t", value: null }, 811 | matProjInverse: { type: "m4", value: new THREE.Matrix4() }, 812 | viewWidth: { type: "f", value: 800 }, 813 | viewHeight: { type: "f", value: 600 }, 814 | 815 | lightDirectionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) }, 816 | lightColorSky: { type: "c", value: new THREE.Color( 0x000000 ) }, 817 | lightColorGround: { type: "c", value: new THREE.Color( 0x000000 ) }, 818 | lightIntensity: { type: "f", value: 1.0 } 819 | 820 | }, 821 | 822 | fragmentShader : [ 823 | 824 | "uniform sampler2D samplerColor;", 825 | "uniform sampler2D samplerNormalDepth;", 826 | 827 | "uniform float lightRadius;", 828 | "uniform float lightIntensity;", 829 | "uniform float viewHeight;", 830 | "uniform float viewWidth;", 831 | 832 | "uniform vec3 lightColorSky;", 833 | "uniform vec3 lightColorGround;", 834 | "uniform vec3 lightDirectionVS;", 835 | 836 | "uniform mat4 matProjInverse;", 837 | 838 | THREE.DeferredShaderChunk[ "unpackFloat" ], 839 | 840 | "void main() {", 841 | 842 | THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], 843 | THREE.DeferredShaderChunk[ "computeNormal" ], 844 | THREE.DeferredShaderChunk[ "unpackColorMap" ], 845 | 846 | // compute light 847 | 848 | "vec3 lightVector = lightDirectionVS;", 849 | 850 | // diffuse 851 | 852 | "float dotProduct = dot( normal, lightVector );", 853 | "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", 854 | 855 | "vec3 hemiColor = mix( lightColorGround, lightColorSky, hemiDiffuseWeight );", 856 | 857 | "vec3 diffuse = hemiColor;", 858 | 859 | // specular (sky light) 860 | 861 | "vec3 hemiHalfVectorSky = normalize( lightVector - vertexPositionVS.xyz );", 862 | "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", 863 | "float hemiSpecularWeightSky = max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", 864 | 865 | // specular (ground light) 866 | 867 | "vec3 lVectorGround = -lightVector;", 868 | 869 | "vec3 hemiHalfVectorGround = normalize( lVectorGround - vertexPositionVS.xyz );", 870 | "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", 871 | "float hemiSpecularWeightGround = max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", 872 | 873 | "float dotProductGround = dot( normal, lVectorGround );", 874 | 875 | "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", 876 | 877 | "vec3 schlickSky = specularColor + vec3( 1.0 - specularColor ) * pow( 1.0 - dot( lightVector, hemiHalfVectorSky ), 5.0 );", 878 | "vec3 schlickGround = specularColor + vec3( 1.0 - specularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", 879 | "vec3 specular = hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", 880 | 881 | // combine 882 | 883 | "gl_FragColor = vec4( lightIntensity * ( albedo * diffuse + specular ), 1.0 );", 884 | 885 | "}" 886 | 887 | ].join("\n"), 888 | 889 | vertexShader : [ 890 | 891 | "void main() { ", 892 | 893 | // full screen quad proxy 894 | 895 | "gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", 896 | 897 | "}" 898 | 899 | ].join("\n") 900 | 901 | }, 902 | 903 | "areaLight" : { 904 | 905 | uniforms: { 906 | 907 | samplerNormalDepth: { type: "t", value: null }, 908 | samplerColor: { type: "t", value: null }, 909 | matProjInverse: { type: "m4", value: new THREE.Matrix4() }, 910 | viewWidth: { type: "f", value: 800 }, 911 | viewHeight: { type: "f", value: 600 }, 912 | 913 | lightPositionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) }, 914 | lightNormalVS: { type: "v3", value: new THREE.Vector3( 0, -1, 0 ) }, 915 | lightRightVS: { type: "v3", value: new THREE.Vector3( 1, 0, 0 ) }, 916 | lightUpVS: { type: "v3", value: new THREE.Vector3( 1, 0, 0 ) }, 917 | 918 | lightColor: { type: "c", value: new THREE.Color( 0x000000 ) }, 919 | lightIntensity: { type: "f", value: 1.0 }, 920 | 921 | lightWidth: { type: "f", value: 1.0 }, 922 | lightHeight: { type: "f", value: 1.0 }, 923 | 924 | constantAttenuation: { type: "f", value: 1.5 }, 925 | linearAttenuation: { type: "f", value: 0.5 }, 926 | quadraticAttenuation: { type: "f", value: 0.1 } 927 | 928 | }, 929 | 930 | fragmentShader : [ 931 | 932 | "uniform vec3 lightPositionVS;", 933 | "uniform vec3 lightNormalVS;", 934 | "uniform vec3 lightRightVS;", 935 | "uniform vec3 lightUpVS;", 936 | 937 | "uniform sampler2D samplerColor;", 938 | "uniform sampler2D samplerNormalDepth;", 939 | 940 | "uniform float lightWidth;", 941 | "uniform float lightHeight;", 942 | 943 | "uniform float constantAttenuation;", 944 | "uniform float linearAttenuation;", 945 | "uniform float quadraticAttenuation;", 946 | 947 | "uniform float lightIntensity;", 948 | "uniform vec3 lightColor;", 949 | 950 | "uniform float viewHeight;", 951 | "uniform float viewWidth;", 952 | 953 | "uniform mat4 matProjInverse;", 954 | 955 | THREE.DeferredShaderChunk[ "unpackFloat" ], 956 | 957 | "vec3 projectOnPlane( vec3 point, vec3 planeCenter, vec3 planeNorm ) {", 958 | 959 | "return point - dot( point - planeCenter, planeNorm ) * planeNorm;", 960 | 961 | "}", 962 | 963 | "bool sideOfPlane( vec3 point, vec3 planeCenter, vec3 planeNorm ) {", 964 | 965 | "return ( dot( point - planeCenter, planeNorm ) >= 0.0 );", 966 | 967 | "}", 968 | 969 | "vec3 linePlaneIntersect( vec3 lp, vec3 lv, vec3 pc, vec3 pn ) {", 970 | 971 | "return lp + lv * ( dot( pn, pc - lp ) / dot( pn, lv ) );", 972 | 973 | "}", 974 | 975 | "float calculateAttenuation( float dist ) {", 976 | 977 | "return ( 1.0 / ( constantAttenuation + linearAttenuation * dist + quadraticAttenuation * dist * dist ) );", 978 | 979 | "}", 980 | 981 | "void main() {", 982 | 983 | THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], 984 | THREE.DeferredShaderChunk[ "computeNormal" ], 985 | THREE.DeferredShaderChunk[ "unpackColorMap" ], 986 | 987 | "float w = lightWidth;", 988 | "float h = lightHeight;", 989 | 990 | "vec3 proj = projectOnPlane( vertexPositionVS.xyz, lightPositionVS, lightNormalVS );", 991 | "vec3 dir = proj - lightPositionVS;", 992 | 993 | "vec2 diagonal = vec2( dot( dir, lightRightVS ), dot( dir, lightUpVS ) );", 994 | "vec2 nearest2D = vec2( clamp( diagonal.x, -w, w ), clamp( diagonal.y, -h, h ) );", 995 | "vec3 nearestPointInside = vec3( lightPositionVS ) + ( lightRightVS * nearest2D.x + lightUpVS * nearest2D.y );", 996 | 997 | "vec3 lightDir = normalize( nearestPointInside - vertexPositionVS.xyz );", 998 | "float NdotL = max( dot( lightNormalVS, -lightDir ), 0.0 );", 999 | "float NdotL2 = max( dot( normal, lightDir ), 0.0 );", 1000 | 1001 | //"if ( NdotL2 * NdotL > 0.0 && sideOfPlane( vertexPositionVS.xyz, lightPositionVS, lightNormalVS ) ) {", 1002 | "if ( NdotL2 * NdotL > 0.0 ) {", 1003 | 1004 | // diffuse 1005 | 1006 | "vec3 diffuse = vec3( sqrt( NdotL * NdotL2 ) );", 1007 | 1008 | // specular 1009 | 1010 | "vec3 specular = vec3( 0.0 );", 1011 | 1012 | "vec3 R = reflect( normalize( -vertexPositionVS.xyz ), normal );", 1013 | "vec3 E = linePlaneIntersect( vertexPositionVS.xyz, R, vec3( lightPositionVS ), lightNormalVS );", 1014 | 1015 | "float specAngle = dot( R, lightNormalVS );", 1016 | 1017 | "if ( specAngle > 0.0 ) {", 1018 | 1019 | "vec3 dirSpec = E - vec3( lightPositionVS );", 1020 | "vec2 dirSpec2D = vec2( dot( dirSpec, lightRightVS ), dot( dirSpec, lightUpVS ) );", 1021 | "vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -w, w ), clamp( dirSpec2D.y, -h, h ) );", 1022 | "float specFactor = 1.0 - clamp( length( nearestSpec2D - dirSpec2D ) * 0.05 * shininess, 0.0, 1.0 );", 1023 | "specular = specularColor * specFactor * specAngle * diffuse;", 1024 | 1025 | "}", 1026 | 1027 | // combine 1028 | 1029 | "float dist = distance( vertexPositionVS.xyz, nearestPointInside );", 1030 | "float attenuation = calculateAttenuation( dist );", 1031 | 1032 | THREE.DeferredShaderChunk[ "combine" ], 1033 | 1034 | "} else {", 1035 | 1036 | "discard;", 1037 | 1038 | "}", 1039 | 1040 | "}" 1041 | 1042 | ].join("\n"), 1043 | 1044 | vertexShader : [ 1045 | 1046 | "void main() {", 1047 | 1048 | // full screen quad proxy 1049 | 1050 | "gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", 1051 | 1052 | "}" 1053 | 1054 | ].join("\n") 1055 | 1056 | }, 1057 | 1058 | "emissiveLight" : { 1059 | 1060 | uniforms: { 1061 | 1062 | samplerColor: { type: "t", value: null }, 1063 | viewWidth: { type: "f", value: 800 }, 1064 | viewHeight: { type: "f", value: 600 }, 1065 | 1066 | }, 1067 | 1068 | fragmentShader : [ 1069 | 1070 | "uniform sampler2D samplerColor;", 1071 | 1072 | "uniform float viewHeight;", 1073 | "uniform float viewWidth;", 1074 | 1075 | THREE.DeferredShaderChunk[ "unpackFloat" ], 1076 | 1077 | "void main() {", 1078 | 1079 | "vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );", 1080 | 1081 | "vec4 colorMap = texture2D( samplerColor, texCoord );", 1082 | "vec3 emissiveColor = float_to_vec3( abs( colorMap.w ) );", 1083 | 1084 | "gl_FragColor = vec4( emissiveColor, 1.0 );", 1085 | 1086 | "}" 1087 | 1088 | ].join("\n"), 1089 | 1090 | vertexShader : [ 1091 | 1092 | "void main() { ", 1093 | 1094 | // full screen quad proxy 1095 | 1096 | "gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", 1097 | 1098 | "}" 1099 | 1100 | ].join("\n") 1101 | 1102 | } 1103 | 1104 | }; 1105 | -------------------------------------------------------------------------------- /libs/ShaderPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.ShaderPass = function ( shader, textureID ) { 6 | 7 | this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse"; 8 | 9 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 10 | 11 | this.material = new THREE.ShaderMaterial( { 12 | 13 | uniforms: this.uniforms, 14 | vertexShader: shader.vertexShader, 15 | fragmentShader: shader.fragmentShader 16 | 17 | } ); 18 | 19 | this.renderToScreen = false; 20 | 21 | this.enabled = true; 22 | this.needsSwap = true; 23 | this.clear = false; 24 | 25 | }; 26 | 27 | THREE.ShaderPass.prototype = { 28 | 29 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 30 | 31 | if ( this.uniforms[ this.textureID ] ) { 32 | 33 | this.uniforms[ this.textureID ].value = readBuffer; 34 | 35 | } 36 | 37 | THREE.EffectComposer.quad.material = this.material; 38 | 39 | if ( this.renderToScreen ) { 40 | 41 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera ); 42 | 43 | } else { 44 | 45 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, this.clear ); 46 | 47 | } 48 | 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /libs/chroma.js: -------------------------------------------------------------------------------- 1 | (function(){var Color,ColorScale,K,PITHIRD,TWOPI,X,Y,Z,brewer,chroma,clip_rgb,colors,cos,css2rgb,hex2rgb,hsi2rgb,hsl2rgb,hsv2rgb,lab2lch,lab2rgb,lab_xyz,lch2lab,lch2rgb,limit,luminance,luminance_x,rgb2hex,rgb2hsi,rgb2hsl,rgb2hsv,rgb2lab,rgb2lch,rgb_xyz,root,type,unpack,xyz_lab,xyz_rgb,_ref,_ref1,_ref2,_ref3,_ref4,_ref5;root=typeof exports!=="undefined"&&exports!==null?exports:this;chroma=(_ref=root.chroma)!=null?_ref:root.chroma={};if(typeof module!=="undefined"&&module!==null){module.exports=chroma}Color=function(){function Color(x,y,z,m){var me,me_rgb,_ref1;me=this;if(x==null&&y==null&&z==null&&m==null){x=[255,0,255]}if(type(x)==="array"&&x.length===3){if(m==null){m=y}_ref1=x,x=_ref1[0],y=_ref1[1],z=_ref1[2]}if(type(x)==="string"){m="hex"}else{if(m==null){m="rgb"}}if(m==="rgb"){me._rgb=[x,y,z]}else if(m==="hsl"){me._rgb=hsl2rgb(x,y,z)}else if(m==="hsv"){me._rgb=hsv2rgb(x,y,z)}else if(m==="hex"){me._rgb=hex2rgb(x)}else if(m==="lab"){me._rgb=lab2rgb(x,y,z)}else if(m==="lch"){me._rgb=lch2rgb(x,y,z)}else if(m==="hsi"){me._rgb=hsi2rgb(x,y,z)}me_rgb=clip_rgb(me._rgb)}Color.prototype.rgb=function(){return this._rgb};Color.prototype.hex=function(){return rgb2hex(this._rgb)};Color.prototype.toString=function(){return this.hex()};Color.prototype.hsl=function(){return rgb2hsl(this._rgb)};Color.prototype.hsv=function(){return rgb2hsv(this._rgb)};Color.prototype.lab=function(){return rgb2lab(this._rgb)};Color.prototype.lch=function(){return rgb2lch(this._rgb)};Color.prototype.hsi=function(){return rgb2hsi(this._rgb)};Color.prototype.luminance=function(){return luminance(this._rgb)};Color.prototype.name=function(){var h,k;h=this.hex();for(k in chroma.colors){if(h===chroma.colors[k]){return k}}return h};Color.prototype.interpolate=function(f,col,m){var dh,hue,hue0,hue1,lbv,lbv0,lbv1,me,sat,sat0,sat1,xyz0,xyz1;me=this;if(m==null){m="rgb"}if(type(col)==="string"){col=new Color(col)}if(m==="hsl"||m==="hsv"||m==="lch"||m==="hsi"){if(m==="hsl"){xyz0=me.hsl();xyz1=col.hsl()}else if(m==="hsv"){xyz0=me.hsv();xyz1=col.hsv()}else if(m==="hsi"){xyz0=me.hsi();xyz1=col.hsi()}else if(m==="lch"){xyz0=me.lch();xyz1=col.lch()}if(m.substr(0,1)==="h"){hue0=xyz0[0],sat0=xyz0[1],lbv0=xyz0[2];hue1=xyz1[0],sat1=xyz1[1],lbv1=xyz1[2]}else{lbv0=xyz0[0],sat0=xyz0[1],hue0=xyz0[2];lbv1=xyz1[0],sat1=xyz1[1],hue1=xyz1[2]}if(!isNaN(hue0)&&!isNaN(hue1)){if(hue1>hue0&&hue1-hue0>180){dh=hue1-(hue0+360)}else if(hue1180){dh=hue1+360-hue0}else{dh=hue1-hue0}hue=hue0+f*dh}else if(!isNaN(hue0)){hue=hue0;if(lbv1===1||lbv1===0){sat=sat0}}else if(!isNaN(hue1)){hue=hue1;if(lbv0===1||lbv0===0){sat=sat1}}else{hue=void 0}if(sat==null){sat=sat0+f*(sat1-sat0)}lbv=lbv0+f*(lbv1-lbv0);if(m.substr(0,1)==="h"){return new Color(hue,sat,lbv,m)}else{return new Color(lbv,sat,hue,m)}}else if(m==="rgb"){xyz0=me._rgb;xyz1=col._rgb;return new Color(xyz0[0]+f*(xyz1[0]-xyz0[0]),xyz0[1]+f*(xyz1[1]-xyz0[1]),xyz0[2]+f*(xyz1[2]-xyz0[2]),m)}else if(m==="lab"){xyz0=me.lab();xyz1=col.lab();return new Color(xyz0[0]+f*(xyz1[0]-xyz0[0]),xyz0[1]+f*(xyz1[1]-xyz0[1]),xyz0[2]+f*(xyz1[2]-xyz0[2]),m)}else{throw"color mode "+m+" is not supported"}};Color.prototype.darken=function(amount){var lch,me;if(amount==null){amount=20}me=this;lch=me.lch();lch[0]-=amount;return chroma.lch(lch)};Color.prototype.brighten=function(amount){if(amount==null){amount=20}return this.darker(-amount)};Color.prototype.saturate=function(amount){var lch,me;if(amount==null){amount=20}me=this;lch=me.lch();lch[1]+=amount;return chroma.lch(lch)};Color.prototype.desaturate=function(amount){if(amount==null){amount=20}return this.saturate(-amount)};return Color}();hex2rgb=function(hex){var b,g,r,rgb,u;if(hex.match(/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)){if(hex.length===4||hex.length===7){hex=hex.substr(1)}if(hex.length===3){hex=hex.split("");hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2]}u=parseInt(hex,16);r=u>>16;g=u>>8&255;b=u&255;return[r,g,b]}if(rgb=css2rgb(hex)){return rgb}throw"unknown color: "+hex};css2rgb=function(css){var hsl,i,m,rgb;if(chroma.colors!=null&&chroma.colors[css]){return hex2rgb(chroma.colors[css])}if(m=css.match(/rgb\(\s*(\-?\d+),\s*(\-?\d+)\s*,\s*(\-?\d+)\s*\)/)){return m.slice(1,4)}if(m=css.match(/rgb\(\s*(\-?\d+)%,\s*(\-?\d+)%\s*,\s*(\-?\d+)%\s*\)/)){rgb=m.slice(1,4);for(i in rgb){rgb[i]=Math.round(rgb[i]*2.55)}return rgb}if(m=css.match(/hsl\(\s*(\-?\d+),\s*(\-?\d+)%\s*,\s*(\-?\d+)%\s*\)/)){hsl=m.slice(1,4);hsl[1]*=.01;hsl[2]*=.01;return hsl2rgb(hsl)}};rgb2hex=function(){var b,g,r,str,u,_ref1;_ref1=unpack(arguments),r=_ref1[0],g=_ref1[1],b=_ref1[2];u=r<<16|g<<8|b;str="000000"+u.toString(16);return"#"+str.substr(str.length-6)};hsv2rgb=function(){var b,f,g,h,i,p,q,r,s,t,v,_ref1,_ref2,_ref3,_ref4,_ref5,_ref6,_ref7;_ref1=unpack(arguments),h=_ref1[0],s=_ref1[1],v=_ref1[2];v*=255;if(s===0){r=g=b=v}else{if(h===360){h=0}if(h>360){h-=360}if(h<0){h+=360}h/=60;i=Math.floor(h);f=h-i;p=v*(1-s);q=v*(1-s*f);t=v*(1-s*(1-f));switch(i){case 0:_ref2=[v,t,p],r=_ref2[0],g=_ref2[1],b=_ref2[2];break;case 1:_ref3=[q,v,p],r=_ref3[0],g=_ref3[1],b=_ref3[2];break;case 2:_ref4=[p,v,t],r=_ref4[0],g=_ref4[1],b=_ref4[2];break;case 3:_ref5=[p,q,v],r=_ref5[0],g=_ref5[1],b=_ref5[2];break;case 4:_ref6=[t,p,v],r=_ref6[0],g=_ref6[1],b=_ref6[2];break;case 5:_ref7=[v,p,q],r=_ref7[0],g=_ref7[1],b=_ref7[2]}}r=Math.round(r);g=Math.round(g);b=Math.round(b);return[r,g,b]};rgb2hsv=function(){var b,delta,g,h,max,min,r,s,v,_ref1;_ref1=unpack(arguments),r=_ref1[0],g=_ref1[1],b=_ref1[2];min=Math.min(r,g,b);max=Math.max(r,g,b);delta=max-min;v=max/255;if(max===0){h=void 0;s=0}else{s=delta/max;if(r===max){h=(g-b)/delta}if(g===max){h=2+(b-r)/delta}if(b===max){h=4+(r-g)/delta}h*=60;if(h<0){h+=360}}return[h,s,v]};hsl2rgb=function(){var b,c,g,h,i,l,r,s,t1,t2,t3,_i,_ref1,_ref2;_ref1=unpack(arguments),h=_ref1[0],s=_ref1[1],l=_ref1[2];if(s===0){r=g=b=l*255}else{t3=[0,0,0];c=[0,0,0];t2=l<.5?l*(1+s):l+s-l*s;t1=2*l-t2;h/=360;t3[0]=h+1/3;t3[1]=h;t3[2]=h-1/3;for(i=_i=0;_i<=2;i=++_i){if(t3[i]<0){t3[i]+=1}if(t3[i]>1){t3[i]-=1}if(6*t3[i]<1){c[i]=t1+(t2-t1)*6*t3[i]}else if(2*t3[i]<1){c[i]=t2}else if(3*t3[i]<2){c[i]=t1+(t2-t1)*(2/3-t3[i])*6}else{c[i]=t1}}_ref2=[Math.round(c[0]*255),Math.round(c[1]*255),Math.round(c[2]*255)],r=_ref2[0],g=_ref2[1],b=_ref2[2]}return[r,g,b]};rgb2hsl=function(r,g,b){var h,l,max,min,s,_ref1;if(r!==void 0&&r.length===3){_ref1=r,r=_ref1[0],g=_ref1[1],b=_ref1[2]}r/=255;g/=255;b/=255;min=Math.min(r,g,b);max=Math.max(r,g,b);l=(max+min)/2;if(max===min){s=0;h=void 0}else{s=l<.5?(max-min)/(max+min):(max-min)/(2-max-min)}if(r===max){h=(g-b)/(max-min)}else if(g===max){h=2+(b-r)/(max-min)}else if(b===max){h=4+(r-g)/(max-min)}h*=60;if(h<0){h+=360}return[h,s,l]};K=18;X=.95047;Y=1;Z=1.08883;lab2rgb=function(l,a,b){var g,r,x,y,z,_ref1,_ref2;if(l!==void 0&&l.length===3){_ref1=l,l=_ref1[0],a=_ref1[1],b=_ref1[2]}if(l!==void 0&&l.length===3){_ref2=l,l=_ref2[0],a=_ref2[1],b=_ref2[2]}y=(l+16)/116;x=y+a/500;z=y-b/200;x=lab_xyz(x)*X;y=lab_xyz(y)*Y;z=lab_xyz(z)*Z;r=xyz_rgb(3.2404542*x-1.5371385*y-.4985314*z);g=xyz_rgb(-.969266*x+1.8760108*y+.041556*z);b=xyz_rgb(.0556434*x-.2040259*y+1.0572252*z);return[limit(r,0,255),limit(g,0,255),limit(b,0,255)]};rgb2lab=function(){var b,g,r,x,y,z,_ref1;_ref1=unpack(arguments),r=_ref1[0],g=_ref1[1],b=_ref1[2];r=rgb_xyz(r);g=rgb_xyz(g);b=rgb_xyz(b);x=xyz_lab((.4124564*r+.3575761*g+.1804375*b)/X);y=xyz_lab((.2126729*r+.7151522*g+.072175*b)/Y);z=xyz_lab((.0193339*r+.119192*g+.9503041*b)/Z);return[116*y-16,500*(x-y),200*(y-z)]};lch2lab=function(){var c,h,l,_ref1;_ref1=unpack(arguments),l=_ref1[0],c=_ref1[1],h=_ref1[2];h=h*Math.PI/180;return[l,Math.cos(h)*c,Math.sin(h)*c]};lch2rgb=function(l,c,h){var L,a,b,g,r,_ref1,_ref2;_ref1=lch2lab(l,c,h),L=_ref1[0],a=_ref1[1],b=_ref1[2];_ref2=lab2rgb(L,a,b),r=_ref2[0],g=_ref2[1],b=_ref2[2];return[limit(r,0,255),limit(g,0,255),limit(b,0,255)]};lab_xyz=function(x){if(x>.206893034){return x*x*x}else{return(x-4/29)/7.787037}};xyz_lab=function(x){if(x>.008856){return Math.pow(x,1/3)}else{return 7.787037*x+4/29}};xyz_rgb=function(r){return Math.round(255*(r<=.00304?12.92*r:1.055*Math.pow(r,1/2.4)-.055))};rgb_xyz=function(r){if((r/=255)<=.04045){return r/12.92}else{return Math.pow((r+.055)/1.055,2.4)}};lab2lch=function(){var a,b,c,h,l,_ref1;_ref1=unpack(arguments),l=_ref1[0],a=_ref1[1],b=_ref1[2];c=Math.sqrt(a*a+b*b);h=Math.atan2(b,a)/Math.PI*180;return[l,c,h]};rgb2lch=function(){var a,b,g,l,r,_ref1,_ref2;_ref1=unpack(arguments),r=_ref1[0],g=_ref1[1],b=_ref1[2];_ref2=rgb2lab(r,g,b),l=_ref2[0],a=_ref2[1],b=_ref2[2];return lab2lch(l,a,b)};rgb2hsi=function(){var TWOPI,b,g,h,i,min,r,s,_ref1;_ref1=unpack(arguments),r=_ref1[0],g=_ref1[1],b=_ref1[2];TWOPI=Math.PI*2;r/=255;g/=255;b/=255;min=Math.min(r,g,b);i=(r+g+b)/3;s=1-min/i;if(s===0){h=0}else{h=(r-g+(r-b))/2;h/=Math.sqrt((r-g)*(r-g)+(r-b)*(g-b));h=Math.acos(h);if(b>g){h=TWOPI-h}h/=TWOPI}return[h*360,s,i]};hsi2rgb=function(h,s,i){var b,g,r,_ref1;_ref1=unpack(arguments),h=_ref1[0],s=_ref1[1],i=_ref1[2];h/=360;if(h<1/3){b=(1-s)/3;r=(1+s*cos(TWOPI*h)/cos(PITHIRD-TWOPI*h))/3;g=1-(b+r)}else if(h<2/3){h-=1/3;r=(1-s)/3;g=(1+s*cos(TWOPI*h)/cos(PITHIRD-TWOPI*h))/3;b=1-(r+g)}else{h-=2/3;g=(1-s)/3;b=(1+s*cos(TWOPI*h)/cos(PITHIRD-TWOPI*h))/3;r=1-(g+b)}r=limit(i*r*3);g=limit(i*g*3);b=limit(i*b*3);return[r*255,g*255,b*255]};clip_rgb=function(rgb){var i;for(i in rgb){if(rgb[i]<0){rgb[i]=0}if(rgb[i]>255){rgb[i]=255}}return rgb};luminance=function(r,g,b){var _ref1;_ref1=unpack(arguments),r=_ref1[0],g=_ref1[1],b=_ref1[2];r=luminance_x(r);g=luminance_x(g);b=luminance_x(b);return.2126*r+.7152*g+.0722*b};luminance_x=function(x){x/=255;if(x<=.03928){return x/12.92}else{return Math.pow((x+.055)/1.055,2.4)}};chroma.Color=Color;chroma.color=function(x,y,z,m){return new Color(x,y,z,m)};chroma.hsl=function(h,s,l){return new Color(h,s,l,"hsl")};chroma.hsv=function(h,s,v){return new Color(h,s,v,"hsv")};chroma.rgb=function(r,g,b){return new Color(r,g,b,"rgb")};chroma.hex=function(x){return new Color(x)};chroma.css=function(x){return new Color(x)};chroma.lab=function(l,a,b){return new Color(l,a,b,"lab")};chroma.lch=function(l,c,h){return new Color(l,c,h,"lch")};chroma.hsi=function(h,s,i){return new Color(h,s,i,"hsi")};chroma.interpolate=function(a,b,f,m){if(a==null||b==null){return"#000"}if(type(a)==="string"){a=new Color(a)}if(type(b)==="string"){b=new Color(b)}return a.interpolate(f,b,m)};chroma.contrast=function(a,b){var l1,l2;if(type(a)==="string"){a=new Color(a)}if(type(b)==="string"){b=new Color(b)}l1=a.luminance();l2=b.luminance();if(l1>l2){return(l1+.05)/(l2+.05)}else{return(l2+.05)/(l1+.05)}};root=typeof exports!=="undefined"&&exports!==null?exports:this;chroma=(_ref1=root.chroma)!=null?_ref1:root.chroma={};Color=chroma.Color;ColorScale=function(){function ColorScale(opts){var me,_ref2,_ref3;if(opts==null){opts={}}me=this;me.range(opts.colors,opts.positions);me._mode=(_ref2=opts.mode)!=null?_ref2:"rgb";me._nacol=chroma.hex((_ref3=opts.nacol)!=null?_ref3:chroma.hex("#ccc"));me.domain([0,1]);me}ColorScale.prototype.range=function(colors,positions){var c,col,me,_i,_j,_ref2,_ref3,_ref4;me=this;if(colors==null){colors=["#ddd","#222"]}if(colors!=null&&type(colors)==="string"&&((_ref2=chroma.brewer)!=null?_ref2[colors]:void 0)!=null){colors=chroma.brewer[colors].slice(0)}for(c=_i=0,_ref3=colors.length-1;0<=_ref3?_i<=_ref3:_i>=_ref3;c=0<=_ref3?++_i:--_i){col=colors[c];if(type(col)==="string"){colors[c]=new Color(col)}}me._colors=colors;if(positions!=null){me._pos=positions}else{me._pos=[];for(c=_j=0,_ref4=colors.length-1;0<=_ref4?_j<=_ref4:_j>=_ref4;c=0<=_ref4?++_j:--_j){me._pos.push(c/(colors.length-1))}}return me};ColorScale.prototype.domain=function(domain){var me;if(domain==null){domain=[]}me=this;me._domain=domain;me._min=domain[0];me._max=domain[domain.length-1];if(domain.length===2){me._numClasses=0}else{me._numClasses=domain.length-1}return me};ColorScale.prototype.get=function(value){var c,f,f0,me;me=this;if(isNaN(value)){return me._nacol}if(me._domain.length>2){c=me.getClass(value);f=c/(me._numClasses-1)}else{f=f0=(value-me._min)/(me._max-me._min);f=Math.min(1,Math.max(0,f))}return me.fColor(f)};ColorScale.prototype.fColor=function(f){var col,cols,i,me,p,_i,_ref2;me=this;cols=me._colors;for(i=_i=0,_ref2=me._pos.length-1;0<=_ref2?_i<=_ref2:_i>=_ref2;i=0<=_ref2?++_i:--_i){p=me._pos[i];if(f<=p){col=cols[i];break}if(f>=p&&i===me._pos.length-1){col=cols[i];break}if(f>p&&f2){n=domain.length-1;i=me.getClass(value);val=domain[i]+(domain[i+1]-domain[i])*.5;minc=domain[0];maxc=domain[n-1];val=me._min+(val-minc)/(maxc-minc)*(me._max-me._min)}return val};ColorScale.prototype.getClass=function(value){var domain,i,n,self;self=this;domain=self._domain;if(domain!=null){n=domain.length-1;i=0;while(i=domain[i]){i++}return i-1}return 0};ColorScale.prototype.validValue=function(value){return!isNaN(value)};return ColorScale}();chroma.ColorScale=ColorScale;chroma.scale=function(colors,positions){var colscale,f,out;colscale=new chroma.ColorScale;colscale.range(colors,positions);out=false;f=function(v){var c;c=colscale.get(v);if(out&&c[out]){return c[out]()}else{return c}};f.domain=function(domain,classes,mode,key){var d;if(mode==null){mode="e"}if(classes!=null){d=chroma.analyze(domain,key);if(classes===0){domain=[d.min,d.max]}else{domain=chroma.limits(d,mode,classes)}}colscale.domain(domain);return f};f.mode=function(_m){colscale._mode=_m;return f};f.range=function(_colors,_pos){colscale.range(_colors,_pos);return f};f.out=function(_o){out=_o;return f};f.getColor=function(val){return f(val)};return f};if((_ref2=chroma.scales)==null){chroma.scales={}}chroma.scales.cool=function(){return chroma.scale([chroma.hsl(180,1,.9),chroma.hsl(250,.7,.4)])};chroma.scales.hot=function(){return chroma.scale(["#000","#f00","#ff0","#fff"],[0,.25,.75,1]).mode("rgb")};chroma.analyze=function(data,key,filter){var add,k,r,val,visit,_i,_len;r={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};if(filter==null){filter=function(){return true}}add=function(val){if(val!=null&&!isNaN(val)){r.values.push(val);r.sum+=val;if(valr.max){r.max=val}r.count+=1}};visit=function(val,k){if(filter(val,k)){if(key!=null&&type(key)==="function"){return add(key(val))}else if(key!=null&&type(key)==="string"||type(key)==="number"){return add(val[key])}else{return add(val)}}};if(type(data)==="array"){for(_i=0,_len=data.length;_i<_len;_i++){val=data[_i];visit(val)}}else{for(k in data){val=data[k];visit(val,k)}}r.domain=[r.min,r.max];r.limits=function(mode,num){return chroma.limits(r,mode,num)};return r};chroma.limits=function(data,mode,num){var assignments,best,centroids,cluster,clusterSizes,dist,i,j,kClusters,limits,max,max_log,min,min_log,mindist,n,nb_iters,newCentroids,p,pb,pr,repeat,sum,tmpKMeansBreaks,value,values,_i,_j,_k,_l,_m,_n,_o,_p,_q,_r,_ref10,_ref11,_ref12,_ref13,_ref14,_ref15,_ref16,_ref17,_ref3,_ref4,_ref5,_ref6,_ref7,_ref8,_ref9,_s,_t,_u,_v,_w;if(mode==null){mode="equal"}if(num==null){num=7}if(data.values==null){data=chroma.analyze(data)}min=data.min;max=data.max;sum=data.sum;values=data.values.sort(function(a,b){return a-b});limits=[];if(mode.substr(0,1)==="c"){limits.push(min);limits.push(max)}if(mode.substr(0,1)==="e"){limits.push(min);for(i=_i=1,_ref3=num-1;1<=_ref3?_i<=_ref3:_i>=_ref3;i=1<=_ref3?++_i:--_i){limits.push(min+i/num*(max-min))}limits.push(max)}else if(mode.substr(0,1)==="l"){if(min<=0){throw"Logarithmic scales are only possible for values > 0"}min_log=Math.LOG10E*Math.log(min);max_log=Math.LOG10E*Math.log(max);limits.push(min);for(i=_j=1,_ref4=num-1;1<=_ref4?_j<=_ref4:_j>=_ref4;i=1<=_ref4?++_j:--_j){limits.push(Math.pow(10,min_log+i/num*(max_log-min_log)))}limits.push(max)}else if(mode.substr(0,1)==="q"){limits.push(min);for(i=_k=1,_ref5=num-1;1<=_ref5?_k<=_ref5:_k>=_ref5;i=1<=_ref5?++_k:--_k){p=values.length*i/num;pb=Math.floor(p);if(pb===p){limits.push(values[pb])}else{pr=p-pb;limits.push(values[pb]*pr+values[pb+1]*(1-pr))}}limits.push(max)}else if(mode.substr(0,1)==="k"){n=values.length;assignments=new Array(n);clusterSizes=new Array(num);repeat=true;nb_iters=0;centroids=null;centroids=[];centroids.push(min);for(i=_l=1,_ref6=num-1;1<=_ref6?_l<=_ref6:_l>=_ref6;i=1<=_ref6?++_l:--_l){centroids.push(min+i/num*(max-min))}centroids.push(max);while(repeat){for(j=_m=0,_ref7=num-1;0<=_ref7?_m<=_ref7:_m>=_ref7;j=0<=_ref7?++_m:--_m){clusterSizes[j]=0}for(i=_n=0,_ref8=n-1;0<=_ref8?_n<=_ref8:_n>=_ref8;i=0<=_ref8?++_n:--_n){value=values[i];mindist=Number.MAX_VALUE;for(j=_o=0,_ref9=num-1;0<=_ref9?_o<=_ref9:_o>=_ref9;j=0<=_ref9?++_o:--_o){dist=Math.abs(centroids[j]-value);if(dist=_ref10;j=0<=_ref10?++_p:--_p){newCentroids[j]=null}for(i=_q=0,_ref11=n-1;0<=_ref11?_q<=_ref11:_q>=_ref11;i=0<=_ref11?++_q:--_q){cluster=assignments[i];if(newCentroids[cluster]===null){newCentroids[cluster]=values[i]}else{newCentroids[cluster]+=values[i]}}for(j=_r=0,_ref12=num-1;0<=_ref12?_r<=_ref12:_r>=_ref12;j=0<=_ref12?++_r:--_r){newCentroids[j]*=1/clusterSizes[j]}repeat=false;for(j=_s=0,_ref13=num-1;0<=_ref13?_s<=_ref13:_s>=_ref13;j=0<=_ref13?++_s:--_s){if(newCentroids[j]!==centroids[i]){repeat=true;break}}centroids=newCentroids;nb_iters++;if(nb_iters>200){repeat=false}}kClusters={};for(j=_t=0,_ref14=num-1;0<=_ref14?_t<=_ref14:_t>=_ref14;j=0<=_ref14?++_t:--_t){kClusters[j]=[]}for(i=_u=0,_ref15=n-1;0<=_ref15?_u<=_ref15:_u>=_ref15;i=0<=_ref15?++_u:--_u){cluster=assignments[i];kClusters[cluster].push(values[i])}tmpKMeansBreaks=[];for(j=_v=0,_ref16=num-1;0<=_ref16?_v<=_ref16:_v>=_ref16;j=0<=_ref16?++_v:--_v){tmpKMeansBreaks.push(kClusters[j][0]);tmpKMeansBreaks.push(kClusters[j][kClusters[j].length-1])}tmpKMeansBreaks=tmpKMeansBreaks.sort(function(a,b){return a-b});limits.push(tmpKMeansBreaks[0]);for(i=_w=1,_ref17=tmpKMeansBreaks.length-1;_w<=_ref17;i=_w+=2){if(!isNaN(tmpKMeansBreaks[i])){limits.push(tmpKMeansBreaks[i])}}}return limits};root=typeof exports!=="undefined"&&exports!==null?exports:this;type=function(){var classToType,name,_i,_len,_ref3;classToType={};_ref3="Boolean Number String Function Array Date RegExp Undefined Null".split(" ");for(_i=0,_len=_ref3.length;_i<_len;_i++){name=_ref3[_i];classToType["[object "+name+"]"]=name.toLowerCase()}return function(obj){var strType;strType=Object.prototype.toString.call(obj);return classToType[strType]||"object"}}();if((_ref3=root.type)==null){root.type=type}Array.max=function(array){return Math.max.apply(Math,array)};Array.min=function(array){return Math.min.apply(Math,array)};limit=function(x,min,max){if(min==null){min=0}if(max==null){max=1}if(xmax){x=max}return x};unpack=function(args){if(args.length===3){return args}else{return args[0]}};TWOPI=Math.PI*2;PITHIRD=Math.PI/3;cos=Math.cos;root=typeof exports!=="undefined"&&exports!==null?exports:this;chroma=(_ref4=root.chroma)!=null?_ref4:root.chroma={};chroma.brewer=brewer={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]};root=typeof exports!=="undefined"&&exports!==null?exports:this;chroma=(_ref5=root.chroma)!=null?_ref5:root.chroma={};chroma.colors=colors={indigo:"#4b0082",gold:"#ffd700",hotpink:"#ff69b4",firebrick:"#b22222",indianred:"#cd5c5c",yellow:"#ffff00",mistyrose:"#ffe4e1",darkolivegreen:"#556b2f",olive:"#808000",darkseagreen:"#8fbc8f",pink:"#ffc0cb",tomato:"#ff6347",lightcoral:"#f08080",orangered:"#ff4500",navajowhite:"#ffdead",lime:"#00ff00",palegreen:"#98fb98",darkslategrey:"#2f4f4f",greenyellow:"#adff2f",burlywood:"#deb887",seashell:"#fff5ee",mediumspringgreen:"#00fa9a",fuchsia:"#ff00ff",papayawhip:"#ffefd5",blanchedalmond:"#ffebcd",chartreuse:"#7fff00",dimgray:"#696969",black:"#000000",peachpuff:"#ffdab9",springgreen:"#00ff7f",aquamarine:"#7fffd4",white:"#ffffff",orange:"#ffa500",lightsalmon:"#ffa07a",darkslategray:"#2f4f4f",brown:"#a52a2a",ivory:"#fffff0",dodgerblue:"#1e90ff",peru:"#cd853f",lawngreen:"#7cfc00",chocolate:"#d2691e",crimson:"#dc143c",forestgreen:"#228b22",darkgrey:"#a9a9a9",lightseagreen:"#20b2aa",cyan:"#00ffff",mintcream:"#f5fffa",silver:"#c0c0c0",antiquewhite:"#faebd7",mediumorchid:"#ba55d3",skyblue:"#87ceeb",gray:"#808080",darkturquoise:"#00ced1",goldenrod:"#daa520",darkgreen:"#006400",floralwhite:"#fffaf0",darkviolet:"#9400d3",darkgray:"#a9a9a9",moccasin:"#ffe4b5",saddlebrown:"#8b4513",grey:"#808080",darkslateblue:"#483d8b",lightskyblue:"#87cefa",lightpink:"#ffb6c1",mediumvioletred:"#c71585",slategrey:"#708090",red:"#ff0000",deeppink:"#ff1493",limegreen:"#32cd32",darkmagenta:"#8b008b",palegoldenrod:"#eee8aa",plum:"#dda0dd",turquoise:"#40e0d0",lightgrey:"#d3d3d3",lightgoldenrodyellow:"#fafad2",darkgoldenrod:"#b8860b",lavender:"#e6e6fa",maroon:"#800000",yellowgreen:"#9acd32",sandybrown:"#f4a460",thistle:"#d8bfd8",violet:"#ee82ee",navy:"#000080",magenta:"#ff00ff",dimgrey:"#696969",tan:"#d2b48c",rosybrown:"#bc8f8f",olivedrab:"#6b8e23",blue:"#0000ff",lightblue:"#add8e6",ghostwhite:"#f8f8ff",honeydew:"#f0fff0",cornflowerblue:"#6495ed",slateblue:"#6a5acd",linen:"#faf0e6",darkblue:"#00008b",powderblue:"#b0e0e6",seagreen:"#2e8b57",darkkhaki:"#bdb76b",snow:"#fffafa",sienna:"#a0522d",mediumblue:"#0000cd",royalblue:"#4169e1",lightcyan:"#e0ffff",green:"#008000",mediumpurple:"#9370db",midnightblue:"#191970",cornsilk:"#fff8dc",paleturquoise:"#afeeee",bisque:"#ffe4c4",slategray:"#708090",darkcyan:"#008b8b",khaki:"#f0e68c",wheat:"#f5deb3",teal:"#008080",darkorchid:"#9932cc",deepskyblue:"#00bfff",salmon:"#fa8072",darkred:"#8b0000",steelblue:"#4682b4",palevioletred:"#db7093",lightslategray:"#778899",aliceblue:"#f0f8ff",lightslategrey:"#778899",lightgreen:"#90ee90",orchid:"#da70d6",gainsboro:"#dcdcdc",mediumseagreen:"#3cb371",lightgray:"#d3d3d3",mediumturquoise:"#48d1cc",lemonchiffon:"#fffacd",cadetblue:"#5f9ea0",lightyellow:"#ffffe0",lavenderblush:"#fff0f5",coral:"#ff7f50",purple:"#800080",aqua:"#00ffff",whitesmoke:"#f5f5f5",mediumslateblue:"#7b68ee",darkorange:"#ff8c00",mediumaquamarine:"#66cdaa",darksalmon:"#e9967a",beige:"#f5f5dc",blueviolet:"#8a2be2",azure:"#f0ffff",lightsteelblue:"#b0c4de",oldlace:"#fdf5e6"}}).call(this); -------------------------------------------------------------------------------- /libs/stats.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var Stats = function () { 6 | 7 | var startTime = Date.now(), prevTime = startTime; 8 | var ms = 0, msMin = Infinity, msMax = 0; 9 | var fps = 0, fpsMin = Infinity, fpsMax = 0; 10 | var frames = 0, mode = 0; 11 | 12 | var container = document.createElement( 'div' ); 13 | container.id = 'stats'; 14 | container.addEventListener( 'mousedown', function ( event ) { event.preventDefault(); setMode( ++ mode % 2 ) }, false ); 15 | container.style.cssText = 'width:80px;opacity:0.9;cursor:pointer'; 16 | 17 | var fpsDiv = document.createElement( 'div' ); 18 | fpsDiv.id = 'fps'; 19 | fpsDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#002'; 20 | container.appendChild( fpsDiv ); 21 | 22 | var fpsText = document.createElement( 'div' ); 23 | fpsText.id = 'fpsText'; 24 | fpsText.style.cssText = 'color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 25 | fpsText.innerHTML = 'FPS'; 26 | fpsDiv.appendChild( fpsText ); 27 | 28 | var fpsGraph = document.createElement( 'div' ); 29 | fpsGraph.id = 'fpsGraph'; 30 | fpsGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0ff'; 31 | fpsDiv.appendChild( fpsGraph ); 32 | 33 | while ( fpsGraph.children.length < 74 ) { 34 | 35 | var bar = document.createElement( 'span' ); 36 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#113'; 37 | fpsGraph.appendChild( bar ); 38 | 39 | } 40 | 41 | var msDiv = document.createElement( 'div' ); 42 | msDiv.id = 'ms'; 43 | msDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#020;display:none'; 44 | container.appendChild( msDiv ); 45 | 46 | var msText = document.createElement( 'div' ); 47 | msText.id = 'msText'; 48 | msText.style.cssText = 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 49 | msText.innerHTML = 'MS'; 50 | msDiv.appendChild( msText ); 51 | 52 | var msGraph = document.createElement( 'div' ); 53 | msGraph.id = 'msGraph'; 54 | msGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0f0'; 55 | msDiv.appendChild( msGraph ); 56 | 57 | while ( msGraph.children.length < 74 ) { 58 | 59 | var bar = document.createElement( 'span' ); 60 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#131'; 61 | msGraph.appendChild( bar ); 62 | 63 | } 64 | 65 | var setMode = function ( value ) { 66 | 67 | mode = value; 68 | 69 | switch ( mode ) { 70 | 71 | case 0: 72 | fpsDiv.style.display = 'block'; 73 | msDiv.style.display = 'none'; 74 | break; 75 | case 1: 76 | fpsDiv.style.display = 'none'; 77 | msDiv.style.display = 'block'; 78 | break; 79 | } 80 | 81 | } 82 | 83 | var updateGraph = function ( dom, value ) { 84 | 85 | var child = dom.appendChild( dom.firstChild ); 86 | child.style.height = value + 'px'; 87 | 88 | } 89 | 90 | return { 91 | 92 | REVISION: 11, 93 | 94 | domElement: container, 95 | 96 | setMode: setMode, 97 | 98 | begin: function () { 99 | 100 | startTime = Date.now(); 101 | 102 | }, 103 | 104 | end: function () { 105 | 106 | var time = Date.now(); 107 | 108 | ms = time - startTime; 109 | msMin = Math.min( msMin, ms ); 110 | msMax = Math.max( msMax, ms ); 111 | 112 | msText.textContent = ms + ' MS (' + msMin + '-' + msMax + ')'; 113 | updateGraph( msGraph, Math.min( 30, 30 - ( ms / 200 ) * 30 ) ); 114 | 115 | frames ++; 116 | 117 | if ( time > prevTime + 1000 ) { 118 | 119 | fps = Math.round( ( frames * 1000 ) / ( time - prevTime ) ); 120 | fpsMin = Math.min( fpsMin, fps ); 121 | fpsMax = Math.max( fpsMax, fps ); 122 | 123 | fpsText.textContent = fps + ' FPS (' + fpsMin + '-' + fpsMax + ')'; 124 | updateGraph( fpsGraph, Math.min( 30, 30 - ( fps / 100 ) * 30 ) ); 125 | 126 | prevTime = time; 127 | frames = 0; 128 | 129 | } 130 | 131 | return time; 132 | 133 | }, 134 | 135 | update: function () { 136 | 137 | startTime = this.end(); 138 | 139 | } 140 | 141 | } 142 | 143 | }; 144 | -------------------------------------------------------------------------------- /lineMaterial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Linematerial 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 | 227 | 228 | -------------------------------------------------------------------------------- /meshMaterial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | meshMaterial 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 | 277 | 278 | -------------------------------------------------------------------------------- /normalMap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | normalMap 7 | 8 | 9 | 10 | 11 | 17 | 18 | 19 | 20 |
21 |
22 |
23 |
24 | 25 | 227 | 228 | -------------------------------------------------------------------------------- /pointCloud.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | pointCloud 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 |
22 |
23 |
24 |
25 | 26 | 142 | 143 | -------------------------------------------------------------------------------- /rainyScene.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | rainyScene 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 |
22 |
23 |
24 |
25 | 26 | 149 | 150 | -------------------------------------------------------------------------------- /snowyScene.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | snowyScene 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 | 176 | 177 | -------------------------------------------------------------------------------- /textGeometry.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Text geometry 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 | 168 | 169 | --------------------------------------------------------------------------------