├── .gitignore ├── README.md ├── dst ├── assets │ ├── css │ │ └── styles.css │ ├── glsl │ │ ├── output_box.frag │ │ ├── output_box.vert │ │ ├── output_floor.frag │ │ ├── output_floor.vert │ │ └── shadow.frag │ └── js │ │ └── main.min.js ├── fb.png ├── index.html └── tw.png ├── gulp ├── config.js └── tasks │ ├── browsersync.js │ ├── glsl.js │ ├── html.js │ ├── imagemin.js │ ├── javascript.js │ └── sass.js ├── gulpfile.js ├── package.json ├── screenshot1.png ├── screenshot2.png ├── screenshot3.png └── src ├── assets ├── css │ └── styles.scss ├── glsl │ ├── output_box.frag │ ├── output_box.vert │ ├── output_floor.frag │ ├── output_floor.vert │ ├── shadow.frag │ └── utils │ │ ├── blendOverlay.glsl │ │ ├── blendSoftlight.glsl │ │ ├── getShadow.glsl │ │ ├── noise2D.glsl │ │ ├── noise3D.glsl │ │ ├── noise4D.glsl │ │ └── random.glsl └── js │ ├── lib-head │ ├── modernizr-custom.js │ └── useragnt-all.min.js │ ├── lib │ ├── CustomEase.min.js │ ├── EasePack.min.js │ ├── GPUComputationRenderer.js │ ├── OrbitControls.js │ ├── ShadowMapViewer.js │ ├── TweenMax.min.js │ └── UnpackDepthRGBAShader.js │ ├── main.js │ └── module │ ├── controls.js │ ├── loading.js │ ├── objs.js │ ├── resize-watch.js │ ├── toonManager.js │ └── webgl.js └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | # MacOS 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | 7 | # Thumbnails 8 | ._* 9 | 10 | # Files that might appear on external disk 11 | .Spotlight-V100 12 | .Trashes 13 | 14 | 15 | # node.js 16 | lib-cov 17 | *.seed 18 | *.log 19 | *.csv 20 | *.dat 21 | *.out 22 | *.pid 23 | *.gz 24 | pids 25 | logs 26 | results 27 | npm-debug.log 28 | node_modules 29 | 30 | # Sass 31 | .sass-cache 32 | 33 | # SublimeText 34 | *.sublime-project 35 | *.sublime-workspace 36 | sftp-config.json 37 | 38 | #vim 39 | .*.s[a-w][a-z] 40 | *.un~ 41 | Session.vim 42 | .netrwhist 43 | *~ 44 | 45 | .idea 46 | .htaccess 47 | .htpasswd 48 | pull.php 49 | 50 | #dev 51 | #dst 52 | build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Halftone Effect 2 | * [demo](https://mnmxmx.github.io/halftone-effect/dst/) 3 | 4 | [](./screenshot1.png) 5 | [](./screenshot2.png) 6 | [](./screenshot3.png) 7 | 8 | ## Resources 9 | * [halftone(in Japanese)](https://wgld.org/d/webgl/w076.html) 10 | * [line shading(in Japanese)](https://wgld.org/d/webgl/w077.html) 11 | 12 | ## Usage 13 | * Clone repository 14 | * Install Node.js 15 | * Run following commands 16 | ``` 17 | npm install 18 | npm start 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /dst/assets/css/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | overflow: hidden; 3 | margin: 0; 4 | } 5 | -------------------------------------------------------------------------------- /dst/assets/glsl/output_box.frag: -------------------------------------------------------------------------------- 1 | #define GLSLIFY 1 2 | uniform float uTick; 3 | uniform vec3 uDirLightPos; 4 | uniform float uDotScale; 5 | uniform float uLineScale; 6 | uniform int uTonePattern; 7 | 8 | uniform vec3 uFogColor; 9 | 10 | varying vec3 vPos; 11 | varying vec3 vNormal; 12 | 13 | varying vec3 vColor; 14 | varying vec3 vToneColor; 15 | 16 | varying float vFogFactor; 17 | 18 | float bias; 19 | uniform sampler2D shadowMap; 20 | uniform vec2 shadowMapSize; 21 | 22 | varying vec4 vShadowCoord; 23 | 24 | float unpackDepth( const in vec4 rgba_depth ) { 25 | const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); 26 | return dot(rgba_depth, bit_shift); 27 | } 28 | 29 | float sampleVisibility( vec3 coord ) { 30 | return step( coord.z, unpackDepth( texture2D( shadowMap, coord.xy ) ) + bias ); 31 | } 32 | 33 | float getShadow(vec3 normal, vec3 lightPos, vec4 _shadowCoord){ 34 | bias = 0.0;//max(0.05 * (1.0 - dot(normal, lightPos)), 0.001); 35 | 36 | float shadow = 0.0; 37 | vec3 shadowCoord = _shadowCoord.xyz / _shadowCoord.w; 38 | 39 | float step = 1.0; 40 | 41 | vec2 inc = vec2( step ) / shadowMapSize; 42 | 43 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, -inc.y, 0. ) ); 44 | shadow += sampleVisibility( shadowCoord + vec3( 0., -inc.y, 0. ) ); 45 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, -inc.y, 0. ) ); 46 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, 0., 0. ) ); 47 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, inc.y, 0. ) ); 48 | shadow += sampleVisibility( shadowCoord + vec3( 0., inc.y, 0. ) ); 49 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, inc.y, 0. ) ); 50 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, 0., 0. ) ); 51 | shadow += sampleVisibility( shadowCoord + vec3( 0., 0, 0. ) ); 52 | shadow /= 9.; 53 | 54 | return shadow; 55 | } 56 | 57 | float blendSoftLight(float base, float blend) { 58 | return (blend < 0.5)?( 2.0 * base * blend + base * base * (1.0-2.0*blend)):(sqrt(base)*(2.0*blend-1.0)+2.0*base*(1.0-blend)); 59 | } 60 | 61 | vec3 blendSoftLight(vec3 base, vec3 blend) { 62 | return vec3(blendSoftLight(base.r,blend.r),blendSoftLight(base.g,blend.g),blendSoftLight(base.b,blend.b)); 63 | } 64 | 65 | vec3 blendSoftLight(vec4 base, vec4 blend) { 66 | return base.rgb * (1.0 - blend.a) + blend.a * (blendSoftLight(base.rgb, blend.rgb) * base.a + blend.rgb * (1.0 - base.a)); 67 | } 68 | float blendOverlay(float base, float blend) { 69 | return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend)); 70 | } 71 | 72 | vec3 blendOverlay(vec3 base, vec3 blend) { 73 | return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b)); 74 | } 75 | 76 | vec3 blendOverlay(vec3 base, vec3 blend, float opacity) { 77 | return (blendOverlay(base, blend) * opacity + base * (1.0 - opacity)); 78 | } 79 | 80 | const float PI = 3.1415926; 81 | 82 | // hemisphere ground color 83 | const vec3 hemiLight_g = vec3(1.0, 0.96, 0.8); 84 | 85 | // hemisphere sky color 86 | const vec3 hemiLight_s_1 = vec3(0.9,0.8,0.6); 87 | const vec3 hemiLight_s_2 = vec3(0.9,0.6,0.7); 88 | 89 | const vec3 hemiLightPos_1 = vec3(-100.0, -100.0, 100.0); 90 | const vec3 hemiLightPos_2 = vec3(-100.0, 100.0, -100.0); 91 | 92 | // directional light color 93 | const vec3 dirLight_1 = vec3(1.0); 94 | 95 | vec3 calcIrradiance_hemi(vec3 newNormal, vec3 lightPos, vec3 grd, vec3 sky){ 96 | float dotNL = clamp(dot(newNormal, normalize(lightPos)), 0.0, 1.0); 97 | 98 | return mix(grd, sky, dotNL); 99 | } 100 | 101 | vec3 calcIrradiance_dir(vec3 normal, vec3 lightPos, vec3 light){ 102 | float dotNL = dot(normal, normalize(lightPos)); 103 | 104 | return light * max(dotNL, 0.0); 105 | } 106 | 107 | float getScreenToneEffect(float dotDiffuse){ 108 | 109 | vec2 v_dot; 110 | vec2 v_line; 111 | 112 | float f_dot; 113 | float f_line; 114 | float g_line; 115 | 116 | float result; 117 | 118 | if(uTonePattern == 1){ 119 | v_dot = gl_FragCoord.xy * uDotScale; 120 | f_dot = max(sin(v_dot.x) * cos(v_dot.y) * 1.5, 0.0); 121 | 122 | if(dotDiffuse > 0.6){ 123 | result = 1.0; 124 | }else if(dotDiffuse > 0.2){ 125 | result = 1.0 - (pow(f_dot, 1.0)); 126 | }else{ 127 | result = pow(f_dot, 2.0); 128 | } 129 | 130 | } else if(uTonePattern == 2){ 131 | v_line = gl_FragCoord.xy * uLineScale; 132 | f_line = max(sin(v_line.x + v_line.y), 0.0); 133 | g_line = max(sin(v_line.x - v_line.y), 0.0); 134 | 135 | if(dotDiffuse > 0.6){ 136 | result = 0.8; 137 | }else if(dotDiffuse > 0.2){ 138 | result = 1.0 - pow(f_line, 2.0); 139 | }else{ 140 | result = 1.0 - (pow(f_line, 2.0) + pow(g_line, 2.0)); 141 | } 142 | } 143 | 144 | result = clamp(result, 0.0, 1.0); 145 | 146 | return result; 147 | } 148 | 149 | void main(){ 150 | vec3 dirColor = vec3(0.0); 151 | 152 | float dirColorRatio = 0.2; 153 | dirColor += calcIrradiance_dir(vNormal, uDirLightPos, dirLight_1) * dirColorRatio; 154 | 155 | vec3 hemiColor = vec3(0.0); 156 | hemiColor += calcIrradiance_hemi(vNormal, hemiLightPos_1, hemiLight_g, hemiLight_s_1) * (0.7 - dirColorRatio) * 0.5; 157 | hemiColor += calcIrradiance_hemi(vNormal, hemiLightPos_2, hemiLight_g, hemiLight_s_2) * (0.7 - dirColorRatio) * 0.5; 158 | 159 | float shadow = getShadow(vNormal, uDirLightPos, vShadowCoord); 160 | 161 | vec3 _color = vColor * 0.8; 162 | vec3 ambient = _color; 163 | 164 | vec3 color = (ambient + shadow * dirColor) * (1.0 + hemiColor); 165 | 166 | // half-tone effect 167 | float dotDiffuse = clamp(dot(vNormal, normalize(uDirLightPos)), 0.0, 1.0); 168 | dotDiffuse *= shadow; 169 | 170 | float f = getScreenToneEffect(dotDiffuse); 171 | 172 | vec3 dotColor = vToneColor;//blendOverlay(color, vToneColor); 173 | 174 | color = mix(dotColor, color, f); 175 | color = mix(uFogColor, color, min(1.0, vFogFactor)); 176 | 177 | gl_FragColor = vec4(color, 1.0); 178 | } -------------------------------------------------------------------------------- /dst/assets/glsl/output_box.vert: -------------------------------------------------------------------------------- 1 | #define GLSLIFY 1 2 | // #pragma glslify: snoise = require("./noise2D") 3 | attribute float aNum; 4 | attribute float aRandom; 5 | 6 | attribute float aColorNum; 7 | 8 | attribute vec3 aDefTranslate; 9 | attribute vec3 aTranslate; 10 | attribute vec3 aScale; 11 | attribute float aRotateY; 12 | 13 | uniform float uRange; 14 | 15 | uniform float uTick; 16 | uniform vec3 uTileSize; 17 | 18 | uniform mat4 shadowP; 19 | uniform mat4 shadowV; 20 | uniform vec3 uDirLightPos; 21 | 22 | uniform vec3 uEyePosition; 23 | uniform float uFogNear; 24 | uniform float uFogFar; 25 | uniform float uFogStart; 26 | uniform float uFogEnd; 27 | 28 | uniform float uOffsetHeight; 29 | 30 | uniform vec3 uColorArray[2]; 31 | uniform vec3 uToneColorArray[2]; 32 | 33 | varying vec3 vColor; 34 | varying vec3 vToneColor; 35 | varying vec3 vNormal; 36 | 37 | varying vec3 vPos; 38 | varying vec4 vShadowCoord; 39 | varying float vFogFactor; 40 | 41 | const float PI = 3.1415926; 42 | 43 | const mat4 biasMatrix = mat4( 44 | 0.5, 0.0, 0.0, 0.0, 45 | 0.0, 0.5, 0.0, 0.0, 46 | 0.0, 0.0, 0.5, 0.0, 47 | 0.5, 0.5, 0.5, 1.0 48 | ); 49 | 50 | mat2 calcRotate2D(float _radian){ 51 | float _sin = sin(_radian); 52 | float _cos = cos(_radian); 53 | return mat2(_cos, _sin, -_sin, _cos); 54 | } 55 | 56 | float parabola( float x) { 57 | return 4.0 * (1.0 - x) * x; 58 | } 59 | 60 | mat3 calcLookAtMatrix(vec3 vector, float roll) { 61 | vec3 rr = vec3(sin(roll), cos(roll), 0.0); 62 | vec3 ww = normalize(vector); 63 | vec3 uu = normalize(cross(ww, rr)); 64 | vec3 vv = normalize(cross(uu, ww)); 65 | 66 | return mat3(uu, ww, vv); 67 | } 68 | 69 | void main(){ 70 | 71 | vec3 pos = (position + vec3(0.0, uTileSize.y / 2.0, 0.0)) * aScale * (1.0 + aRandom - 0.5); 72 | pos.xz = calcRotate2D(aRotateY * 2.0 * PI) * pos.xz; 73 | pos += aTranslate + aDefTranslate + vec3(0.0, uOffsetHeight, 0.0); 74 | 75 | vec4 worldPosition = modelMatrix * vec4(pos, 1.0); 76 | 77 | gl_Position = projectionMatrix * viewMatrix * worldPosition; 78 | 79 | vPos = worldPosition.xyz; 80 | vColor = uColorArray[int(aColorNum)]; 81 | vToneColor = uToneColorArray[int(aColorNum)]; 82 | 83 | vNormal = normal; 84 | vNormal.xz = calcRotate2D(aRotateY * 2.0 * PI) * vNormal.xz; 85 | 86 | // vDotDiffuse = dot(normal, uDirLightPos); 87 | 88 | float fogLinerDepth = 1.0 / (uFogFar - uFogNear); 89 | 90 | float fogLinerPos = length(uEyePosition - pos) * fogLinerDepth; 91 | vFogFactor = clamp((uFogEnd - fogLinerPos) / (uFogEnd - uFogStart), 0.0, 1.0); 92 | 93 | vShadowCoord = biasMatrix * shadowP * shadowV * worldPosition; 94 | } -------------------------------------------------------------------------------- /dst/assets/glsl/output_floor.frag: -------------------------------------------------------------------------------- 1 | #define GLSLIFY 1 2 | uniform float uTick; 3 | uniform vec3 uDirLightPos; 4 | uniform float uDotScale; 5 | uniform float uLineScale; 6 | uniform vec3 uFloorToneColor; 7 | 8 | uniform int uTonePattern; 9 | 10 | varying vec3 vNormal; 11 | 12 | uniform vec3 uFogColor; 13 | varying float vFogFactor; 14 | 15 | const float PI = 3.1415926; 16 | 17 | float bias; 18 | uniform sampler2D shadowMap; 19 | uniform vec2 shadowMapSize; 20 | 21 | varying vec4 vShadowCoord; 22 | 23 | float unpackDepth( const in vec4 rgba_depth ) { 24 | const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); 25 | return dot(rgba_depth, bit_shift); 26 | } 27 | 28 | float sampleVisibility( vec3 coord ) { 29 | return step( coord.z, unpackDepth( texture2D( shadowMap, coord.xy ) ) + bias ); 30 | } 31 | 32 | float getShadow(vec3 normal, vec3 lightPos, vec4 _shadowCoord){ 33 | bias = 0.0;//max(0.05 * (1.0 - dot(normal, lightPos)), 0.001); 34 | 35 | float shadow = 0.0; 36 | vec3 shadowCoord = _shadowCoord.xyz / _shadowCoord.w; 37 | 38 | float step = 1.0; 39 | 40 | vec2 inc = vec2( step ) / shadowMapSize; 41 | 42 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, -inc.y, 0. ) ); 43 | shadow += sampleVisibility( shadowCoord + vec3( 0., -inc.y, 0. ) ); 44 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, -inc.y, 0. ) ); 45 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, 0., 0. ) ); 46 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, inc.y, 0. ) ); 47 | shadow += sampleVisibility( shadowCoord + vec3( 0., inc.y, 0. ) ); 48 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, inc.y, 0. ) ); 49 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, 0., 0. ) ); 50 | shadow += sampleVisibility( shadowCoord + vec3( 0., 0, 0. ) ); 51 | shadow /= 9.; 52 | 53 | return shadow; 54 | } 55 | 56 | float getHalfToneEffect(float dotDiffuse){ 57 | vec2 v_dot; 58 | vec2 v_line; 59 | 60 | float f_dot; 61 | float f_line; 62 | float g_line; 63 | 64 | float result; 65 | 66 | if(uTonePattern == 1){ 67 | v_dot = gl_FragCoord.xy * uDotScale; 68 | f_dot = max(sin(v_dot.x) * cos(v_dot.y) * 1.5, 0.0); 69 | 70 | if(dotDiffuse > 0.2){ 71 | result = 1.0; 72 | } else{ 73 | result = f_dot; 74 | } 75 | 76 | } else if(uTonePattern == 2){ 77 | v_line = gl_FragCoord.xy * uLineScale; 78 | f_line = max(sin(v_line.x + v_line.y), 0.0); 79 | g_line = max(sin(v_line.x - v_line.y), 0.0); 80 | 81 | if(dotDiffuse > 0.2){ 82 | result = 1.0; 83 | } else{ 84 | result = (pow(f_line, 2.0) + pow(g_line, 2.0)); 85 | } 86 | } 87 | 88 | 89 | 90 | 91 | result = min(1.0, result); 92 | 93 | return result; 94 | } 95 | 96 | void main(){ 97 | float shadow = getShadow(vNormal, uDirLightPos, vShadowCoord); 98 | 99 | // half tone effect 100 | float dotDiffuse = clamp(dot(vNormal, normalize(uDirLightPos)), 0.0, 1.0); 101 | dotDiffuse *= shadow; 102 | 103 | float f = getHalfToneEffect(dotDiffuse); 104 | 105 | vec3 color = uFogColor; 106 | 107 | color = mix(uFloorToneColor, color, f); 108 | color = mix(uFogColor, color, min(1.0, vFogFactor)); 109 | 110 | gl_FragColor = vec4(color, 1.0); 111 | } -------------------------------------------------------------------------------- /dst/assets/glsl/output_floor.vert: -------------------------------------------------------------------------------- 1 | #define GLSLIFY 1 2 | uniform mat4 shadowP; 3 | uniform mat4 shadowV; 4 | uniform vec3 uDirLightPos; 5 | 6 | uniform vec3 uEyePosition; 7 | uniform float uFogNear; 8 | uniform float uFogFar; 9 | uniform float uFogStart; 10 | uniform float uFogEnd; 11 | 12 | uniform float uOffsetHeight; 13 | 14 | varying vec3 vNormal; 15 | 16 | varying vec4 vShadowCoord; 17 | varying float vFogFactor; 18 | 19 | const float PI = 3.1415926; 20 | 21 | const mat4 biasMatrix = mat4( 22 | 0.5, 0.0, 0.0, 0.0, 23 | 0.0, 0.5, 0.0, 0.0, 24 | 0.0, 0.0, 0.5, 0.0, 25 | 0.5, 0.5, 0.5, 1.0 26 | ); 27 | 28 | void main(){ 29 | vec3 pos = position + vec3(0.0, uOffsetHeight, 0.0); 30 | 31 | vec4 worldPosition = modelMatrix * vec4(pos, 1.0); 32 | gl_Position = projectionMatrix * viewMatrix * worldPosition; 33 | 34 | float fogLinerDepth = 1.0 / (uFogFar - uFogNear); 35 | 36 | float fogLinerPos = length(uEyePosition - pos) * fogLinerDepth; 37 | vFogFactor = clamp((uFogEnd - fogLinerPos) / (uFogEnd - uFogStart), 0.0, 1.0); 38 | 39 | vNormal = normal; 40 | 41 | // vDotDiffuse = dot(normal, uDirLightPos) * 0.5 + 0.5; 42 | 43 | vShadowCoord = biasMatrix * shadowP * shadowV * worldPosition; 44 | } -------------------------------------------------------------------------------- /dst/assets/glsl/shadow.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | #define GLSLIFY 1 3 | vec4 packDepth(const in float depth) { 4 | const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0); 5 | const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0); 6 | vec4 res = mod(depth*bit_shift*vec4(255), vec4(256))/vec4(255); 7 | res -= res.xxyz * bit_mask; 8 | return res; 9 | } 10 | void main() { 11 | gl_FragColor = packDepth( gl_FragCoord.z ); 12 | } -------------------------------------------------------------------------------- /dst/fb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmxmx/halftone-effect/97446f172f5ee982ffa7e5cfeec7a8b622765c65/dst/fb.png -------------------------------------------------------------------------------- /dst/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Halftone Effects 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 |
33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /dst/tw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmxmx/halftone-effect/97446f172f5ee982ffa7e5cfeec7a8b622765c65/dst/tw.png -------------------------------------------------------------------------------- /gulp/config.js: -------------------------------------------------------------------------------- 1 | 2 | var PATH = { 3 | BASE: { 4 | SRC: 'src/', 5 | DST: 'dst/', 6 | BUILD: 'build/' 7 | }, 8 | URL: '/', 9 | SRC: 'src/', 10 | DST: 'dst/', 11 | BUILD: 'build/' 12 | }; 13 | 14 | module.exports = { 15 | isProduction: process.env.NODE_ENV === 'production', 16 | 17 | PATH: PATH, 18 | 19 | AUTOPREFIXER: [ 20 | 'ie >= 9', 21 | 'ie_mob >= 10', 22 | 'ff >= 31', 23 | 'chrome >= 36', 24 | 'safari >= 8', 25 | 'opera >= 23', 26 | 'ios >= 8', 27 | 'android >= 4' 28 | ], 29 | 30 | IMAGEMIN: { 31 | build: { 32 | src: [PATH.BASE.SRC + 'assets/img/**/*.{png,svg,jpg,jpeg}'], 33 | dst: PATH.BASE.DST + 'assets/img', 34 | opts: { 35 | progressive: true, 36 | use: [ 37 | require('imagemin-pngquant')() 38 | ] 39 | } 40 | } 41 | }, 42 | 43 | BrowserSync: { 44 | open: 'local', 45 | reloadDebounce: 2000, 46 | ui: false, 47 | notify: false, 48 | startPath: PATH.BASE.URL, 49 | ghostMode: false, 50 | server: { 51 | baseDir: PATH.BASE.DST 52 | //index: `${DIR.DST}${DIR.PATH}`, 53 | //routes: { 54 | // [DIR.PATH]: `${DIR.DST}${DIR.PATH}` 55 | //} 56 | }, 57 | files: [ 58 | PATH.BASE.DST + "**/*.obj", 59 | 60 | PATH.BASE.DST + "**/*.json", 61 | PATH.BASE.DST + "**/*.xml", 62 | 63 | PATH.BASE.DST + "**/*.mp4", 64 | PATH.BASE.DST + "**/*.mp3", 65 | 66 | PATH.BASE.DST + "**/*.png", 67 | PATH.BASE.DST + "**/*.jpg", 68 | PATH.BASE.DST + "**/*.gif", 69 | PATH.BASE.DST + "**/*.svg", 70 | 71 | PATH.BASE.DST + "**/*.html", 72 | PATH.BASE.DST + "**/*.css", 73 | PATH.BASE.DST + "**/*.js", 74 | 75 | PATH.BASE.DST + "**/*.mp3", 76 | PATH.BASE.DST + "**/*.json", 77 | 78 | PATH.BASE.DST + "**/*.vert", 79 | PATH.BASE.DST + "**/*.frag", 80 | 81 | ] 82 | }, 83 | 84 | EJS: { 85 | jsonPath: 'ejs/param.json', 86 | // qaPath: 'ejs/qa.json', 87 | templatePath: PATH.BASE.SRC + '/**/*.{html,ejs}', 88 | }, 89 | }; 90 | -------------------------------------------------------------------------------- /gulp/tasks/browsersync.js: -------------------------------------------------------------------------------- 1 | // browsersync設定 2 | var gulp = require('gulp'); 3 | var browserSync = require('browser-sync'); 4 | var config = require('../config'); 5 | var isProduction = require('../config').isProduction; 6 | 7 | 8 | if (isProduction) { 9 | config.BrowserSync.server.baseDir = config.PATH.BASE.BUILD; 10 | } 11 | 12 | 13 | gulp.task('browserSync', function(){ 14 | browserSync(config.BrowserSync); 15 | }); 16 | -------------------------------------------------------------------------------- /gulp/tasks/glsl.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var glslify = require("gulp-glslify"); 3 | 4 | var gulpif = require("gulp-if"); 5 | var config = require("../config"); 6 | var isProduction = require('../config').isProduction; 7 | 8 | // var path = "assets/test"; 9 | 10 | 11 | gulp.task("glsl", null, function() { 12 | gulp.src("src/**/*.{vert,frag}") 13 | .pipe(glslify()) 14 | .pipe(gulpif(isProduction, gulp.dest(config.PATH.BUILD), gulp.dest(config.PATH.DST))); 15 | }); -------------------------------------------------------------------------------- /gulp/tasks/html.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var plumber = require('gulp-plumber'); 3 | 4 | var gulpif = require("gulp-if"); 5 | var config = require("../config"); 6 | var isProduction = require('../config').isProduction; 7 | 8 | gulp.task('html', function() 9 | { 10 | gulp.src("src/**/*.html") 11 | .pipe(gulpif(isProduction, gulp.dest(config.PATH.BUILD), gulp.dest(config.PATH.DST))); 12 | }); -------------------------------------------------------------------------------- /gulp/tasks/imagemin.js: -------------------------------------------------------------------------------- 1 | // 画像圧縮 2 | // ※圧縮が弱い・・・ 3 | 4 | var gulp = require('gulp'); 5 | var changed = require('gulp-changed'); 6 | var imagemin = require('gulp-imagemin'); 7 | var config = require('../config'); 8 | var ext = '{png,svg,jpg,jpeg,gif}'; 9 | 10 | 11 | gulp.task('imagemin:dst', function(){ 12 | gulp.src(config.PATH.SRC + 'assets/img/**/*.' + ext) 13 | .pipe(changed(config.PATH.SRC + 'assets/img/**/*.' + ext)) 14 | .pipe(gulp.dest(config.PATH.DST + 'assets/img/')); 15 | }); 16 | 17 | 18 | gulp.task('imagemin:build', function(){ 19 | gulp.src(config.PATH.SRC + 'assets/img/**/*.' + ext) 20 | .pipe(changed(config.PATH.SRC + 'assets/img/**/*.' + ext)) 21 | .pipe(imagemin( 22 | { 23 | progressive: true, 24 | use: [ 25 | require('imagemin-pngquant')() 26 | ], 27 | optimizationLevel : 7 28 | } 29 | )) 30 | .pipe(gulp.dest(config.PATH.BUILD + 'assets/img/')); 31 | }); 32 | -------------------------------------------------------------------------------- /gulp/tasks/javascript.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var changed = require("gulp-changed"); 3 | var concat = require("gulp-concat"); 4 | var runSequence = require('run-sequence'); 5 | var stripDebug = require('gulp-strip-debug'); 6 | var babel = require('gulp-babel'); 7 | var plumber = require('gulp-plumber'); 8 | 9 | 10 | 11 | gulp.task("js", function(){ 12 | return runSequence( 13 | "js.concat" 14 | ); 15 | }); 16 | 17 | 18 | gulp.task("js.concat", function(){ 19 | return gulp.src([ 20 | "src/assets/js/lib-head/*.js", 21 | "src/assets/js/lib/*.js", 22 | "src/assets/js/module/*.js", 23 | "src/assets/js/main.js" 24 | ], 25 | { base: "src" } 26 | ) 27 | .pipe(plumber()) 28 | .pipe(babel()) 29 | .pipe(concat("main.min.js")) 30 | .pipe(gulp.dest("dst/assets/js/")); 31 | }) 32 | -------------------------------------------------------------------------------- /gulp/tasks/sass.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var gulpif = require("gulp-if"); 3 | var sass = require("gulp-sass"); 4 | var plumber = require('gulp-plumber'); 5 | var csswring = require('csswring'); 6 | var config = require("../config"); 7 | var AUTOPREFIXER = require("../config").AUTOPREFIXER; 8 | var isProduction = require('../config').isProduction; 9 | 10 | gulp.task("css", function () { 11 | 12 | var postcss = require("gulp-postcss"); 13 | var postcssOptions = [ 14 | require('postcss-mixins'), 15 | require("autoprefixer")({ browsers: AUTOPREFIXER }), 16 | require("css-mqpacker")({ sort: function (a, b) { return b.localeCompare(a); } }), 17 | require("postcss-flexbugs-fixes"), 18 | require("postcss-partial-import")() 19 | ]; 20 | 21 | if (isProduction) 22 | { 23 | postcssOptions.push(csswring); 24 | } 25 | 26 | gulp.src(config.PATH.SRC + "assets/css/styles.scss") 27 | .pipe(plumber()) 28 | .pipe(sass({outputStyle: "expanded"})) 29 | .pipe(postcss(postcssOptions)) 30 | .pipe(gulpif(isProduction, gulp.dest(config.PATH.BUILD + "assets/css/"), gulp.dest(config.PATH.DST + "assets/css/"))); 31 | }); 32 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var requireDir = require('require-dir'); 3 | var runSequence = require('run-sequence'); 4 | 5 | 6 | requireDir('./gulp/tasks'); 7 | 8 | 9 | // watch 10 | gulp.task('watch', function(){ 11 | // gulp.watch('src/assets/img/mobile/topic/*.png', ["sprite"]); 12 | gulp.watch(['src/assets/css/**/*.{scss,css}'], ['css']); 13 | gulp.watch('src/assets/js/**/*.js', ['js']); 14 | gulp.watch('src/assets/glsl/**/*.{vert,frag}', ['glsl']); 15 | gulp.watch('src/**/*.html', ['html']); 16 | gulp.watch(['src/assets/img/**/*.{png,jpg,jpeg,gif,svg}', 'src/assets/video/**/*.webm'], ['imagemin:dst']); 17 | }); 18 | 19 | 20 | // task 21 | gulp.task('predefault', function(){ 22 | runSequence( 23 | 'css', 24 | 'html', 25 | 'glsl', 26 | 'js', 27 | 'imagemin:dst', 28 | 'browserSync', 29 | 'watch' 30 | ); 31 | }); 32 | 33 | 34 | gulp.task('default', ['predefault'], function(){ 35 | console.log('running default tasks...'); 36 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "screentones-effect", 3 | "version": "1.0.0", 4 | "description": "* [demo](https://mnmxmx.github.io/shadowmap-fog-demo/dst/) * inspired by [spite - polygon-shredder](https://github.com/spite/polygon-shredder)", 5 | "main": "gulpfile.js", 6 | "scripts": { 7 | "start": "cross-env gulp" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "autoprefixer": "^6.4.0", 12 | "babel-core": "^5.5.8", 13 | "babel-loader": "^5.1.4", 14 | "browser-sync": "^2.13.0", 15 | "cross-env": "^2.0.0", 16 | "css-loader": "^0.25.0", 17 | "css-mqpacker": "^5.0.1", 18 | "csswring": "^5.1.0", 19 | "del": "^2.2.2", 20 | "ejs": "^2.5.1", 21 | "fs": "0.0.1-security", 22 | "glslify": "^6.0.2", 23 | "glslify-hex": "^2.1.1", 24 | "glslify-import": "^3.0.0", 25 | "gulp": "^3.9.1", 26 | "gulp-babel": "^5.1.0", 27 | "gulp-changed": "^1.3.2", 28 | "gulp-concat": "^2.6.0", 29 | "gulp-ejs": "^2.3.0", 30 | "gulp-glslify": "git+https://github.com/yuichiroharai/gulp-glslify.git", 31 | "gulp-if": "^2.0.1", 32 | "gulp-imagemin": "^3.0.2", 33 | "gulp-load-plugins": "^1.2.4", 34 | "gulp-notify": "^2.2.0", 35 | "gulp-plumber": "^1.1.0", 36 | "gulp-postcss": "^6.1.1", 37 | "gulp-sass": "^2.3.2", 38 | "gulp-strip-debug": "^1.1.0", 39 | "gulp-uglify": "^2.0.0", 40 | "gulp-util": "^3.0.7", 41 | "gulp-watch": "^4.3.9", 42 | "gulp-webpack": "^1.5.0", 43 | "gulp.spritesmith": "^6.2.1", 44 | "html-loader": "^0.4.4", 45 | "imagemin": "^5.2.2", 46 | "imagemin-pngquant": "^5.0.0", 47 | "postcss-flexbugs-fixes": "^2.0.0", 48 | "postcss-mixins": "^5.2.0", 49 | "postcss-partial-import": "^2.0.0", 50 | "require-dir": "^0.3.0", 51 | "run-sequence": "^1.2.2", 52 | "sass-variables-loader": "^0.1.3", 53 | "strip-loader": "^0.1.2", 54 | "style-loader": "^0.13.1", 55 | "through2": "^2.0.3", 56 | "vue-loader": "^9.7.0", 57 | "vue-style-loader": "^1.0.0", 58 | "webpack": "^2.2.1" 59 | }, 60 | "author": "", 61 | "license": "ISC" 62 | } 63 | -------------------------------------------------------------------------------- /screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmxmx/halftone-effect/97446f172f5ee982ffa7e5cfeec7a8b622765c65/screenshot1.png -------------------------------------------------------------------------------- /screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmxmx/halftone-effect/97446f172f5ee982ffa7e5cfeec7a8b622765c65/screenshot2.png -------------------------------------------------------------------------------- /screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmxmx/halftone-effect/97446f172f5ee982ffa7e5cfeec7a8b622765c65/screenshot3.png -------------------------------------------------------------------------------- /src/assets/css/styles.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | body{ 4 | overflow: hidden; 5 | margin: 0; 6 | // background: linear-gradient(90deg, #fff, #b7d3dc); 7 | } -------------------------------------------------------------------------------- /src/assets/glsl/output_box.frag: -------------------------------------------------------------------------------- 1 | uniform float uTick; 2 | uniform vec3 uDirLightPos; 3 | uniform float uDotScale; 4 | uniform float uLineScale; 5 | uniform int uTonePattern; 6 | 7 | uniform vec3 uFogColor; 8 | 9 | 10 | varying vec3 vPos; 11 | varying vec3 vNormal; 12 | 13 | varying vec3 vColor; 14 | varying vec3 vToneColor; 15 | 16 | varying float vFogFactor; 17 | 18 | #pragma glslify: import("./utils/getShadow.glsl") 19 | #pragma glslify: import("./utils/blendSoftlight.glsl") 20 | #pragma glslify: import("./utils/blendOverlay.glsl") 21 | 22 | 23 | 24 | const float PI = 3.1415926; 25 | 26 | // hemisphere ground color 27 | const vec3 hemiLight_g = vec3(1.0, 0.96, 0.8); 28 | 29 | // hemisphere sky color 30 | const vec3 hemiLight_s_1 = vec3(0.9,0.8,0.6); 31 | const vec3 hemiLight_s_2 = vec3(0.9,0.6,0.7); 32 | 33 | const vec3 hemiLightPos_1 = vec3(-100.0, -100.0, 100.0); 34 | const vec3 hemiLightPos_2 = vec3(-100.0, 100.0, -100.0); 35 | 36 | // directional light color 37 | const vec3 dirLight_1 = vec3(1.0); 38 | 39 | 40 | vec3 calcIrradiance_hemi(vec3 newNormal, vec3 lightPos, vec3 grd, vec3 sky){ 41 | float dotNL = clamp(dot(newNormal, normalize(lightPos)), 0.0, 1.0); 42 | 43 | return mix(grd, sky, dotNL); 44 | } 45 | 46 | vec3 calcIrradiance_dir(vec3 normal, vec3 lightPos, vec3 light){ 47 | float dotNL = dot(normal, normalize(lightPos)); 48 | 49 | return light * max(dotNL, 0.0); 50 | } 51 | 52 | 53 | float getScreenToneEffect(float dotDiffuse){ 54 | 55 | vec2 v_dot; 56 | vec2 v_line; 57 | 58 | float f_dot; 59 | float f_line; 60 | float g_line; 61 | 62 | float result; 63 | 64 | if(uTonePattern == 1){ 65 | v_dot = gl_FragCoord.xy * uDotScale; 66 | f_dot = max(sin(v_dot.x) * cos(v_dot.y) * 1.5, 0.0); 67 | 68 | if(dotDiffuse > 0.6){ 69 | result = 1.0; 70 | }else if(dotDiffuse > 0.2){ 71 | result = 1.0 - (pow(f_dot, 1.0)); 72 | }else{ 73 | result = pow(f_dot, 2.0); 74 | } 75 | 76 | } else if(uTonePattern == 2){ 77 | v_line = gl_FragCoord.xy * uLineScale; 78 | f_line = max(sin(v_line.x + v_line.y), 0.0); 79 | g_line = max(sin(v_line.x - v_line.y), 0.0); 80 | 81 | 82 | if(dotDiffuse > 0.6){ 83 | result = 0.8; 84 | }else if(dotDiffuse > 0.2){ 85 | result = 1.0 - pow(f_line, 2.0); 86 | }else{ 87 | result = 1.0 - (pow(f_line, 2.0) + pow(g_line, 2.0)); 88 | } 89 | } 90 | 91 | result = clamp(result, 0.0, 1.0); 92 | 93 | return result; 94 | } 95 | 96 | 97 | 98 | void main(){ 99 | vec3 dirColor = vec3(0.0); 100 | 101 | float dirColorRatio = 0.2; 102 | dirColor += calcIrradiance_dir(vNormal, uDirLightPos, dirLight_1) * dirColorRatio; 103 | 104 | vec3 hemiColor = vec3(0.0); 105 | hemiColor += calcIrradiance_hemi(vNormal, hemiLightPos_1, hemiLight_g, hemiLight_s_1) * (0.7 - dirColorRatio) * 0.5; 106 | hemiColor += calcIrradiance_hemi(vNormal, hemiLightPos_2, hemiLight_g, hemiLight_s_2) * (0.7 - dirColorRatio) * 0.5; 107 | 108 | float shadow = getShadow(vNormal, uDirLightPos, vShadowCoord); 109 | 110 | 111 | vec3 _color = vColor * 0.8; 112 | vec3 ambient = _color; 113 | 114 | vec3 color = (ambient + shadow * dirColor) * (1.0 + hemiColor); 115 | 116 | 117 | // half-tone effect 118 | float dotDiffuse = clamp(dot(vNormal, normalize(uDirLightPos)), 0.0, 1.0); 119 | dotDiffuse *= shadow; 120 | 121 | float f = getScreenToneEffect(dotDiffuse); 122 | 123 | vec3 dotColor = vToneColor;//blendOverlay(color, vToneColor); 124 | 125 | 126 | color = mix(dotColor, color, f); 127 | color = mix(uFogColor, color, min(1.0, vFogFactor)); 128 | 129 | 130 | gl_FragColor = vec4(color, 1.0); 131 | } -------------------------------------------------------------------------------- /src/assets/glsl/output_box.vert: -------------------------------------------------------------------------------- 1 | // #pragma glslify: snoise = require("./noise2D") 2 | attribute float aNum; 3 | attribute float aRandom; 4 | 5 | attribute float aColorNum; 6 | 7 | attribute vec3 aDefTranslate; 8 | attribute vec3 aTranslate; 9 | attribute vec3 aScale; 10 | attribute float aRotateY; 11 | 12 | uniform float uRange; 13 | 14 | uniform float uTick; 15 | uniform vec3 uTileSize; 16 | 17 | uniform mat4 shadowP; 18 | uniform mat4 shadowV; 19 | uniform vec3 uDirLightPos; 20 | 21 | uniform vec3 uEyePosition; 22 | uniform float uFogNear; 23 | uniform float uFogFar; 24 | uniform float uFogStart; 25 | uniform float uFogEnd; 26 | 27 | uniform float uOffsetHeight; 28 | 29 | uniform vec3 uColorArray[2]; 30 | uniform vec3 uToneColorArray[2]; 31 | 32 | varying vec3 vColor; 33 | varying vec3 vToneColor; 34 | varying vec3 vNormal; 35 | 36 | varying vec3 vPos; 37 | varying vec4 vShadowCoord; 38 | varying float vFogFactor; 39 | 40 | 41 | 42 | const float PI = 3.1415926; 43 | 44 | 45 | const mat4 biasMatrix = mat4( 46 | 0.5, 0.0, 0.0, 0.0, 47 | 0.0, 0.5, 0.0, 0.0, 48 | 0.0, 0.0, 0.5, 0.0, 49 | 0.5, 0.5, 0.5, 1.0 50 | ); 51 | 52 | mat2 calcRotate2D(float _radian){ 53 | float _sin = sin(_radian); 54 | float _cos = cos(_radian); 55 | return mat2(_cos, _sin, -_sin, _cos); 56 | } 57 | 58 | float parabola( float x) { 59 | return 4.0 * (1.0 - x) * x; 60 | } 61 | 62 | mat3 calcLookAtMatrix(vec3 vector, float roll) { 63 | vec3 rr = vec3(sin(roll), cos(roll), 0.0); 64 | vec3 ww = normalize(vector); 65 | vec3 uu = normalize(cross(ww, rr)); 66 | vec3 vv = normalize(cross(uu, ww)); 67 | 68 | return mat3(uu, ww, vv); 69 | } 70 | 71 | 72 | 73 | void main(){ 74 | 75 | vec3 pos = (position + vec3(0.0, uTileSize.y / 2.0, 0.0)) * aScale * (1.0 + aRandom - 0.5); 76 | pos.xz = calcRotate2D(aRotateY * 2.0 * PI) * pos.xz; 77 | pos += aTranslate + aDefTranslate + vec3(0.0, uOffsetHeight, 0.0); 78 | 79 | vec4 worldPosition = modelMatrix * vec4(pos, 1.0); 80 | 81 | gl_Position = projectionMatrix * viewMatrix * worldPosition; 82 | 83 | vPos = worldPosition.xyz; 84 | vColor = uColorArray[int(aColorNum)]; 85 | vToneColor = uToneColorArray[int(aColorNum)]; 86 | 87 | vNormal = normal; 88 | vNormal.xz = calcRotate2D(aRotateY * 2.0 * PI) * vNormal.xz; 89 | 90 | // vDotDiffuse = dot(normal, uDirLightPos); 91 | 92 | float fogLinerDepth = 1.0 / (uFogFar - uFogNear); 93 | 94 | float fogLinerPos = length(uEyePosition - pos) * fogLinerDepth; 95 | vFogFactor = clamp((uFogEnd - fogLinerPos) / (uFogEnd - uFogStart), 0.0, 1.0); 96 | 97 | vShadowCoord = biasMatrix * shadowP * shadowV * worldPosition; 98 | } -------------------------------------------------------------------------------- /src/assets/glsl/output_floor.frag: -------------------------------------------------------------------------------- 1 | uniform float uTick; 2 | uniform vec3 uDirLightPos; 3 | uniform float uDotScale; 4 | uniform float uLineScale; 5 | uniform vec3 uFloorToneColor; 6 | 7 | uniform int uTonePattern; 8 | 9 | 10 | 11 | 12 | varying vec3 vNormal; 13 | 14 | uniform vec3 uFogColor; 15 | varying float vFogFactor; 16 | 17 | 18 | const float PI = 3.1415926; 19 | 20 | #pragma glslify: import("./utils/getShadow.glsl") 21 | 22 | float getHalfToneEffect(float dotDiffuse){ 23 | vec2 v_dot; 24 | vec2 v_line; 25 | 26 | float f_dot; 27 | float f_line; 28 | float g_line; 29 | 30 | float result; 31 | 32 | if(uTonePattern == 1){ 33 | v_dot = gl_FragCoord.xy * uDotScale; 34 | f_dot = max(sin(v_dot.x) * cos(v_dot.y) * 1.5, 0.0); 35 | 36 | if(dotDiffuse > 0.2){ 37 | result = 1.0; 38 | } else{ 39 | result = f_dot; 40 | } 41 | 42 | } else if(uTonePattern == 2){ 43 | v_line = gl_FragCoord.xy * uLineScale; 44 | f_line = max(sin(v_line.x + v_line.y), 0.0); 45 | g_line = max(sin(v_line.x - v_line.y), 0.0); 46 | 47 | if(dotDiffuse > 0.2){ 48 | result = 1.0; 49 | } else{ 50 | result = (pow(f_line, 2.0) + pow(g_line, 2.0)); 51 | } 52 | } 53 | 54 | 55 | 56 | 57 | result = min(1.0, result); 58 | 59 | return result; 60 | } 61 | 62 | 63 | void main(){ 64 | float shadow = getShadow(vNormal, uDirLightPos, vShadowCoord); 65 | 66 | // half tone effect 67 | float dotDiffuse = clamp(dot(vNormal, normalize(uDirLightPos)), 0.0, 1.0); 68 | dotDiffuse *= shadow; 69 | 70 | float f = getHalfToneEffect(dotDiffuse); 71 | 72 | vec3 color = uFogColor; 73 | 74 | color = mix(uFloorToneColor, color, f); 75 | color = mix(uFogColor, color, min(1.0, vFogFactor)); 76 | 77 | gl_FragColor = vec4(color, 1.0); 78 | } -------------------------------------------------------------------------------- /src/assets/glsl/output_floor.vert: -------------------------------------------------------------------------------- 1 | uniform mat4 shadowP; 2 | uniform mat4 shadowV; 3 | uniform vec3 uDirLightPos; 4 | 5 | uniform vec3 uEyePosition; 6 | uniform float uFogNear; 7 | uniform float uFogFar; 8 | uniform float uFogStart; 9 | uniform float uFogEnd; 10 | 11 | uniform float uOffsetHeight; 12 | 13 | varying vec3 vNormal; 14 | 15 | varying vec4 vShadowCoord; 16 | varying float vFogFactor; 17 | 18 | const float PI = 3.1415926; 19 | 20 | const mat4 biasMatrix = mat4( 21 | 0.5, 0.0, 0.0, 0.0, 22 | 0.0, 0.5, 0.0, 0.0, 23 | 0.0, 0.0, 0.5, 0.0, 24 | 0.5, 0.5, 0.5, 1.0 25 | ); 26 | 27 | void main(){ 28 | vec3 pos = position + vec3(0.0, uOffsetHeight, 0.0); 29 | 30 | vec4 worldPosition = modelMatrix * vec4(pos, 1.0); 31 | gl_Position = projectionMatrix * viewMatrix * worldPosition; 32 | 33 | float fogLinerDepth = 1.0 / (uFogFar - uFogNear); 34 | 35 | float fogLinerPos = length(uEyePosition - pos) * fogLinerDepth; 36 | vFogFactor = clamp((uFogEnd - fogLinerPos) / (uFogEnd - uFogStart), 0.0, 1.0); 37 | 38 | vNormal = normal; 39 | 40 | // vDotDiffuse = dot(normal, uDirLightPos) * 0.5 + 0.5; 41 | 42 | vShadowCoord = biasMatrix * shadowP * shadowV * worldPosition; 43 | } -------------------------------------------------------------------------------- /src/assets/glsl/shadow.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | vec4 packDepth(const in float depth) { 3 | const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0); 4 | const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0); 5 | vec4 res = mod(depth*bit_shift*vec4(255), vec4(256))/vec4(255); 6 | res -= res.xxyz * bit_mask; 7 | return res; 8 | } 9 | void main() { 10 | gl_FragColor = packDepth( gl_FragCoord.z ); 11 | } -------------------------------------------------------------------------------- /src/assets/glsl/utils/blendOverlay.glsl: -------------------------------------------------------------------------------- 1 | float blendOverlay(float base, float blend) { 2 | return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend)); 3 | } 4 | 5 | vec3 blendOverlay(vec3 base, vec3 blend) { 6 | return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b)); 7 | } 8 | 9 | vec3 blendOverlay(vec3 base, vec3 blend, float opacity) { 10 | return (blendOverlay(base, blend) * opacity + base * (1.0 - opacity)); 11 | } -------------------------------------------------------------------------------- /src/assets/glsl/utils/blendSoftlight.glsl: -------------------------------------------------------------------------------- 1 | float blendSoftLight(float base, float blend) { 2 | return (blend < 0.5)?( 2.0 * base * blend + base * base * (1.0-2.0*blend)):(sqrt(base)*(2.0*blend-1.0)+2.0*base*(1.0-blend)); 3 | } 4 | 5 | vec3 blendSoftLight(vec3 base, vec3 blend) { 6 | return vec3(blendSoftLight(base.r,blend.r),blendSoftLight(base.g,blend.g),blendSoftLight(base.b,blend.b)); 7 | } 8 | 9 | vec3 blendSoftLight(vec4 base, vec4 blend) { 10 | return base.rgb * (1.0 - blend.a) + blend.a * (blendSoftLight(base.rgb, blend.rgb) * base.a + blend.rgb * (1.0 - base.a)); 11 | } -------------------------------------------------------------------------------- /src/assets/glsl/utils/getShadow.glsl: -------------------------------------------------------------------------------- 1 | float bias; 2 | uniform sampler2D shadowMap; 3 | uniform vec2 shadowMapSize; 4 | 5 | varying vec4 vShadowCoord; 6 | 7 | 8 | float unpackDepth( const in vec4 rgba_depth ) { 9 | const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); 10 | return dot(rgba_depth, bit_shift); 11 | } 12 | 13 | float sampleVisibility( vec3 coord ) { 14 | return step( coord.z, unpackDepth( texture2D( shadowMap, coord.xy ) ) + bias ); 15 | } 16 | 17 | float getShadow(vec3 normal, vec3 lightPos, vec4 _shadowCoord){ 18 | bias = 0.0;//max(0.05 * (1.0 - dot(normal, lightPos)), 0.001); 19 | 20 | float shadow = 0.0; 21 | vec3 shadowCoord = _shadowCoord.xyz / _shadowCoord.w; 22 | 23 | float step = 1.0; 24 | 25 | vec2 inc = vec2( step ) / shadowMapSize; 26 | 27 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, -inc.y, 0. ) ); 28 | shadow += sampleVisibility( shadowCoord + vec3( 0., -inc.y, 0. ) ); 29 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, -inc.y, 0. ) ); 30 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, 0., 0. ) ); 31 | shadow += sampleVisibility( shadowCoord + vec3( -inc.x, inc.y, 0. ) ); 32 | shadow += sampleVisibility( shadowCoord + vec3( 0., inc.y, 0. ) ); 33 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, inc.y, 0. ) ); 34 | shadow += sampleVisibility( shadowCoord + vec3( inc.x, 0., 0. ) ); 35 | shadow += sampleVisibility( shadowCoord + vec3( 0., 0, 0. ) ); 36 | shadow /= 9.; 37 | 38 | return shadow; 39 | } 40 | -------------------------------------------------------------------------------- /src/assets/glsl/utils/noise2D.glsl: -------------------------------------------------------------------------------- 1 | #pragma glslify: export(snoise2D) 2 | 3 | // 4 | // Description : Array and textureless GLSL 2D simplex noise function. 5 | // Author : Ian McEwan, Ashima Arts. 6 | // Maintainer : stegu 7 | // Lastmod : 20110822 (ijm) 8 | // License : Copyright (C) 2011 Ashima Arts. All rights reserved. 9 | // Distributed under the MIT License. See LICENSE file. 10 | // https://github.com/ashima/webgl-noise 11 | // https://github.com/stegu/webgl-noise 12 | // 13 | 14 | vec3 mod289(vec3 x) { 15 | return x - floor(x * (1.0 / 289.0)) * 289.0; 16 | } 17 | 18 | vec2 mod289(vec2 x) { 19 | return x - floor(x * (1.0 / 289.0)) * 289.0; 20 | } 21 | 22 | vec3 permute(vec3 x) { 23 | return mod289(((x*34.0)+1.0)*x); 24 | } 25 | 26 | float snoise2D(vec2 v) 27 | { 28 | const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 29 | 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) 30 | -0.577350269189626, // -1.0 + 2.0 * C.x 31 | 0.024390243902439); // 1.0 / 41.0 32 | // First corner 33 | vec2 i = floor(v + dot(v, C.yy) ); 34 | vec2 x0 = v - i + dot(i, C.xx); 35 | 36 | // Other corners 37 | vec2 i1; 38 | //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 39 | //i1.y = 1.0 - i1.x; 40 | i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); 41 | // x0 = x0 - 0.0 + 0.0 * C.xx ; 42 | // x1 = x0 - i1 + 1.0 * C.xx ; 43 | // x2 = x0 - 1.0 + 2.0 * C.xx ; 44 | vec4 x12 = x0.xyxy + C.xxzz; 45 | x12.xy -= i1; 46 | 47 | // Permutations 48 | i = mod289(i); // Avoid truncation effects in permutation 49 | vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) 50 | + i.x + vec3(0.0, i1.x, 1.0 )); 51 | 52 | vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); 53 | m = m*m ; 54 | m = m*m ; 55 | 56 | // Gradients: 41 points uniformly over a line, mapped onto a diamond. 57 | // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) 58 | 59 | vec3 x = 2.0 * fract(p * C.www) - 1.0; 60 | vec3 h = abs(x) - 0.5; 61 | vec3 ox = floor(x + 0.5); 62 | vec3 a0 = x - ox; 63 | 64 | // Normalise gradients implicitly by scaling m 65 | // Approximation of: m *= inversesqrt( a0*a0 + h*h ); 66 | m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); 67 | 68 | // Compute final noise value at P 69 | vec3 g; 70 | g.x = a0.x * x0.x + h.x * x0.y; 71 | g.yz = a0.yz * x12.xz + h.yz * x12.yw; 72 | return 130.0 * dot(m, g); 73 | } -------------------------------------------------------------------------------- /src/assets/glsl/utils/noise3D.glsl: -------------------------------------------------------------------------------- 1 | #pragma glslify: export(snoise3D) 2 | 3 | // 4 | // Description : Array and textureless GLSL 2D/3D/4D simplex 5 | // noise functions. 6 | // Author : Ian McEwan, Ashima Arts. 7 | // Maintainer : stegu 8 | // Lastmod : 20110822 (ijm) 9 | // License : Copyright (C) 2011 Ashima Arts. All rights reserved. 10 | // Distributed under the MIT License. See LICENSE file. 11 | // https://github.com/ashima/webgl-noise 12 | // https://github.com/stegu/webgl-noise 13 | // 14 | 15 | vec3 mod289(vec3 x) { 16 | return x - floor(x * (1.0 / 289.0)) * 289.0; 17 | } 18 | 19 | vec4 mod289(vec4 x) { 20 | return x - floor(x * (1.0 / 289.0)) * 289.0; 21 | } 22 | 23 | vec4 permute(vec4 x) { 24 | return mod289(((x*34.0)+1.0)*x); 25 | } 26 | 27 | vec4 taylorInvSqrt(vec4 r) 28 | { 29 | return 1.79284291400159 - 0.85373472095314 * r; 30 | } 31 | 32 | float snoise3D(vec3 v) 33 | { 34 | const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; 35 | const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); 36 | 37 | // First corner 38 | vec3 i = floor(v + dot(v, C.yyy) ); 39 | vec3 x0 = v - i + dot(i, C.xxx) ; 40 | 41 | // Other corners 42 | vec3 g = step(x0.yzx, x0.xyz); 43 | vec3 l = 1.0 - g; 44 | vec3 i1 = min( g.xyz, l.zxy ); 45 | vec3 i2 = max( g.xyz, l.zxy ); 46 | 47 | // x0 = x0 - 0.0 + 0.0 * C.xxx; 48 | // x1 = x0 - i1 + 1.0 * C.xxx; 49 | // x2 = x0 - i2 + 2.0 * C.xxx; 50 | // x3 = x0 - 1.0 + 3.0 * C.xxx; 51 | vec3 x1 = x0 - i1 + C.xxx; 52 | vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y 53 | vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y 54 | 55 | // Permutations 56 | i = mod289(i); 57 | vec4 p = permute( permute( permute( 58 | i.z + vec4(0.0, i1.z, i2.z, 1.0 )) 59 | + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) 60 | + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); 61 | 62 | // Gradients: 7x7 points over a square, mapped onto an octahedron. 63 | // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 64 | float n_ = 0.142857142857; // 1.0/7.0 65 | vec3 ns = n_ * D.wyz - D.xzx; 66 | 67 | vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) 68 | 69 | vec4 x_ = floor(j * ns.z); 70 | vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) 71 | 72 | vec4 x = x_ *ns.x + ns.yyyy; 73 | vec4 y = y_ *ns.x + ns.yyyy; 74 | vec4 h = 1.0 - abs(x) - abs(y); 75 | 76 | vec4 b0 = vec4( x.xy, y.xy ); 77 | vec4 b1 = vec4( x.zw, y.zw ); 78 | 79 | //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; 80 | //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; 81 | vec4 s0 = floor(b0)*2.0 + 1.0; 82 | vec4 s1 = floor(b1)*2.0 + 1.0; 83 | vec4 sh = -step(h, vec4(0.0)); 84 | 85 | vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; 86 | vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; 87 | 88 | vec3 p0 = vec3(a0.xy,h.x); 89 | vec3 p1 = vec3(a0.zw,h.y); 90 | vec3 p2 = vec3(a1.xy,h.z); 91 | vec3 p3 = vec3(a1.zw,h.w); 92 | 93 | //Normalise gradients 94 | vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); 95 | p0 *= norm.x; 96 | p1 *= norm.y; 97 | p2 *= norm.z; 98 | p3 *= norm.w; 99 | 100 | // Mix final noise value 101 | vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); 102 | m = m * m; 103 | return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), 104 | dot(p2,x2), dot(p3,x3) ) ); 105 | } -------------------------------------------------------------------------------- /src/assets/glsl/utils/noise4D.glsl: -------------------------------------------------------------------------------- 1 | #pragma glslify: export(snoise4D) 2 | 3 | 4 | // 5 | // Description : Array and textureless GLSL 2D/3D/4D simplex 6 | // noise functions. 7 | // Author : Ian McEwan, Ashima Arts. 8 | // Maintainer : stegu 9 | // Lastmod : 20110822 (ijm) 10 | // License : Copyright (C) 2011 Ashima Arts. All rights reserved. 11 | // Distributed under the MIT License. See LICENSE file. 12 | // https://github.com/ashima/webgl-noise 13 | // https://github.com/stegu/webgl-noise 14 | // 15 | 16 | vec4 mod289(vec4 x) { 17 | return x - floor(x * (1.0 / 289.0)) * 289.0; } 18 | 19 | float mod289(float x) { 20 | return x - floor(x * (1.0 / 289.0)) * 289.0; } 21 | 22 | vec4 permute(vec4 x) { 23 | return mod289(((x*34.0)+1.0)*x); 24 | } 25 | 26 | float permute(float x) { 27 | return mod289(((x*34.0)+1.0)*x); 28 | } 29 | 30 | vec4 taylorInvSqrt(vec4 r) 31 | { 32 | return 1.79284291400159 - 0.85373472095314 * r; 33 | } 34 | 35 | float taylorInvSqrt(float r) 36 | { 37 | return 1.79284291400159 - 0.85373472095314 * r; 38 | } 39 | 40 | vec4 grad4(float j, vec4 ip) 41 | { 42 | const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); 43 | vec4 p,s; 44 | 45 | p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0; 46 | p.w = 1.5 - dot(abs(p.xyz), ones.xyz); 47 | s = vec4(lessThan(p, vec4(0.0))); 48 | p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www; 49 | 50 | return p; 51 | } 52 | 53 | // (sqrt(5) - 1)/4 = F4, used once below 54 | #define F4 0.309016994374947451 55 | 56 | float snoise4D(vec4 v) 57 | { 58 | const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4 59 | 0.276393202250021, // 2 * G4 60 | 0.414589803375032, // 3 * G4 61 | -0.447213595499958); // -1 + 4 * G4 62 | 63 | // First corner 64 | vec4 i = floor(v + dot(v, vec4(F4)) ); 65 | vec4 x0 = v - i + dot(i, C.xxxx); 66 | 67 | // Other corners 68 | 69 | // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) 70 | vec4 i0; 71 | vec3 isX = step( x0.yzw, x0.xxx ); 72 | vec3 isYZ = step( x0.zww, x0.yyz ); 73 | // i0.x = dot( isX, vec3( 1.0 ) ); 74 | i0.x = isX.x + isX.y + isX.z; 75 | i0.yzw = 1.0 - isX; 76 | // i0.y += dot( isYZ.xy, vec2( 1.0 ) ); 77 | i0.y += isYZ.x + isYZ.y; 78 | i0.zw += 1.0 - isYZ.xy; 79 | i0.z += isYZ.z; 80 | i0.w += 1.0 - isYZ.z; 81 | 82 | // i0 now contains the unique values 0,1,2,3 in each channel 83 | vec4 i3 = clamp( i0, 0.0, 1.0 ); 84 | vec4 i2 = clamp( i0-1.0, 0.0, 1.0 ); 85 | vec4 i1 = clamp( i0-2.0, 0.0, 1.0 ); 86 | 87 | // x0 = x0 - 0.0 + 0.0 * C.xxxx 88 | // x1 = x0 - i1 + 1.0 * C.xxxx 89 | // x2 = x0 - i2 + 2.0 * C.xxxx 90 | // x3 = x0 - i3 + 3.0 * C.xxxx 91 | // x4 = x0 - 1.0 + 4.0 * C.xxxx 92 | vec4 x1 = x0 - i1 + C.xxxx; 93 | vec4 x2 = x0 - i2 + C.yyyy; 94 | vec4 x3 = x0 - i3 + C.zzzz; 95 | vec4 x4 = x0 + C.wwww; 96 | 97 | // Permutations 98 | i = mod289(i); 99 | float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x); 100 | vec4 j1 = permute( permute( permute( permute ( 101 | i.w + vec4(i1.w, i2.w, i3.w, 1.0 )) 102 | + i.z + vec4(i1.z, i2.z, i3.z, 1.0 )) 103 | + i.y + vec4(i1.y, i2.y, i3.y, 1.0 )) 104 | + i.x + vec4(i1.x, i2.x, i3.x, 1.0 )); 105 | 106 | // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope 107 | // 7*7*6 = 294, which is close to the ring size 17*17 = 289. 108 | vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ; 109 | 110 | vec4 p0 = grad4(j0, ip); 111 | vec4 p1 = grad4(j1.x, ip); 112 | vec4 p2 = grad4(j1.y, ip); 113 | vec4 p3 = grad4(j1.z, ip); 114 | vec4 p4 = grad4(j1.w, ip); 115 | 116 | // Normalise gradients 117 | vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); 118 | p0 *= norm.x; 119 | p1 *= norm.y; 120 | p2 *= norm.z; 121 | p3 *= norm.w; 122 | p4 *= taylorInvSqrt(dot(p4,p4)); 123 | 124 | // Mix contributions from the five corners 125 | vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0); 126 | vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0); 127 | m0 = m0 * m0; 128 | m1 = m1 * m1; 129 | return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 ))) 130 | + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ; 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/assets/glsl/utils/random.glsl: -------------------------------------------------------------------------------- 1 | #pragma glslify: export(rand); 2 | 3 | float rand(vec2 co){ 4 | float a = fract(dot(co, vec2(2.067390879775102, 12.451168662908249))) - 0.5; 5 | float s = a * (6.182785114200511 + a * a * (-38.026512460676566 + a * a * 53.392573080032137)); 6 | float t = fract(s * 43758.5453); 7 | 8 | return t; 9 | } -------------------------------------------------------------------------------- /src/assets/js/lib-head/modernizr-custom.js: -------------------------------------------------------------------------------- 1 | /*! modernizr 3.3.1 (Custom Build) | MIT * 2 | * https://modernizr.com/download/?-webgl-setclasses !*/ 3 | !function(e,n,t){function o(e,n){return typeof e===n}function s(){var e,n,t,s,a,i,f;for(var c in l)if(l.hasOwnProperty(c)){if(e=[],n=l[c],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t0?parseInt(o[0])||0:0,i.minor=o.length>1?parseInt(o[1])||0:0,i.build=o.length>2?parseInt(o[2])||0:0,i.revision=o.length>3?parseInt(o[3])||0:0,i}var a={};a._detects=["mobile","tablet","pc","windows","mac","linux","ios","android","edge","ie","safari","chrome","firefox","opera"];var n=a.userAgent=e.navigator.userAgent.toLowerCase();a.mobile=i("iphone")||i("ipod")||i("android")&&i("mobile")||i("windows")&&i("phone")||i("firefox")&&i("mobile")||i("blackberry"),a.tablet=i("ipad")||i("android")&&!i("mobile")||i("windows")&&i("touch")&&!i("tablet pc")||i("firefox")&&i("tablet")||i("kindle")||i("silk")||i("playbook"),a.pc=!i("iphone")&&!i("ipod")&&!i("ipad")&&!i("android")&&(!i("windows")||!i("phone")&&(!i("touch")||i("tablet pc")))&&(!i("firefox")||!i("mobile")&&!i("tablet"))&&!i("blackberry")&&!i("kindle")&&!i("silk")&&!i("playbook"),a.windows=i("windows"),a.mac=i("mac os x")&&!i("iphone")&&!i("ipad")&&!i("ipod"),a.linux=i("linux")&&!i("android"),a.ios=i("iphone")||i("ipad")||i("ipod"),a.ios&&(a.ios=new Boolean(!0),n.match(/ os ([\d_]+)/g),a.ios.version=r(RegExp.$1.replace("_","."))),a.android=i("android"),a.android&&(a.android=new Boolean(!0),n.match(/android ([\d\.]+)/g),a.android.version=r(RegExp.$1)),a.edge=i("edge"),a.ie=i("trident")||i("msie"),a.safari=i("safari")&&!i("android")&&!i("edge")&&!i("opera")&&!i("opr")&&!i("chrome"),a.chrome=i("chrome")&&!i("edge")&&!i("opera")&&!i("opr"),a.chrome&&(a.chrome=new Boolean(!0),n.match(/chrome\/([\d.]+)/g),a.chrome.version=r(RegExp.$1)),a.firefox=i("firefox")&&!i("edge"),a.opera=i("opera")||i("opr");var d,t,s,l=a._classPrefix="",p=o.documentElement,c=p.className;for(t=a._detects.length,d=0;dj*(z*z+A*A)&&(m=k.length,g(a,b,n,o,t,u,x,y,j,k,l),g(x,y,v,w,r,s,h,i,j,k,l+1+(k.length-m))),k},h=function(a){var b,e,g,h,i,j,k,l,m,n,o,p=(a+"").replace(d,function(a){var b=+a;return 1e-4>b&&b>-1e-4?0:b}).match(c)||[],q=[],r=0,s=0,t=p.length,u=2;for(b=0;t>b;b++)if(m=h,isNaN(p[b])?(h=p[b].toUpperCase(),i=h!==p[b]):b--,e=+p[b+1],g=+p[b+2],i&&(e+=r,g+=s),b||(k=e,l=g),"M"===h)j&&j.length<8&&(q.length-=1,u=0),r=k=e,s=l=g,j=[e,g],u=2,q.push(j),b+=2,h="L";else if("C"===h)j||(j=[0,0]),j[u++]=e,j[u++]=g,i||(r=s=0),j[u++]=r+1*p[b+3],j[u++]=s+1*p[b+4],j[u++]=r+=1*p[b+5],j[u++]=s+=1*p[b+6],b+=6;else if("S"===h)"C"===m||"S"===m?(n=r-j[u-4],o=s-j[u-3],j[u++]=r+n,j[u++]=s+o):(j[u++]=r,j[u++]=s),j[u++]=e,j[u++]=g,i||(r=s=0),j[u++]=r+=1*p[b+3],j[u++]=s+=1*p[b+4],b+=4;else{if("L"!==h&&"Z"!==h)throw f;"Z"===h&&(e=k,g=l,j.closed=!0),("L"===h||Math.abs(r-e)>.5||Math.abs(s-g)>.5)&&(j[u++]=r+(e-r)/3,j[u++]=s+(g-s)/3,j[u++]=r+2*(e-r)/3,j[u++]=s+2*(g-s)/3,j[u++]=e,j[u++]=g,"L"===h&&(b+=2)),r=e,s=g}return q[0]},i=function(a){var b,c=a.length,d=999999999999;for(b=1;c>b;b+=6)+a[b]d;d+=2)a[d]=(+a[d]+e)*h,a[d+1]=(+a[d+1]+f)*j},k=function(a){var b=this.lookup[a*this.l|0]||this.lookup[this.l-1];return b.nx=r,(e.test(a)||-1!==a.indexOf("M")&&-1===a.indexOf("C"))&&(s=h(a)),d=s.length,4===d)s.unshift(0,0),s.push(1,1),d=8;else if((d-2)%6)throw f;for((0!==+s[0]||1!==+s[d-2])&&j(s,c.height,c.originY),this.rawBezier=s,l=2;d>l;l+=6)i={x:+s[l-2],y:+s[l-1]},k={x:+s[l+4],y:+s[l+5]},u.push(i,k),g(i.x,i.y,+s[l],+s[l+1],+s[l+2],+s[l+3],k.x,k.y,1/(2e5*r),u,u.length-1);for(d=u.length,l=0;d>l;l++)o=u[l],p=u[l-1]||o,o.x>p.x||p.y!==o.y&&p.x===o.x||o===p?(p.cx=o.x-p.x,p.cy=o.y-p.y,p.n=o,p.nx=o.x,this.fast&&l>1&&Math.abs(p.cy/p.cx-u[l-2].cy/u[l-2].cx)>2&&(this.fast=!1),p.cxl;l++)q=l*m,o.nxl;l++)o.nxf;f+=2)d.push(((q+b.rawBezier[f]*o)*n|0)/n+","+((r+b.rawBezier[f+1]*-p)*n|0)/n);d[0]="M"+d[0],d[1]="C"+d[1]}else for(d=["M"+q+","+r],j=Math.max(5,200*(c.precision||1)),g=1/j,j+=2,k=5/j,l=((q+g*o)*n|0)/n,m=((r+b.getRatio(g)*-p)*n|0)/n,e=(m-r)/(l-q),f=2;j>f;f++)h=((q+f*g*o)*n|0)/n,i=((r+b.getRatio(f*g)*-p)*n|0)/n,(Math.abs((i-m)/(h-l)-e)>k||f===j-1)&&(d.push(l+","+m),e=(i-m)/(h-l)),l=h,m=i;return s&&("string"==typeof s?document.querySelector(s):s).setAttribute("d",d.join(" ")),d.join(" ")},l},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(),function(a){"use strict";var b=function(){return(_gsScope.GreenSockGlobals||_gsScope)[a]};"undefined"!=typeof module&&module.exports?(require("../TweenLite.min.js"),module.exports=b()):"function"==typeof define&&define.amd&&define(["TweenLite"],b)}("CustomEase"); -------------------------------------------------------------------------------- /src/assets/js/lib/EasePack.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * VERSION: 1.16.0 3 | * DATE: 2018-02-15 4 | * UPDATES AND DOCS AT: http://greensock.com 5 | * 6 | * @license Copyright (c) 2008-2018, GreenSock. All rights reserved. 7 | * This work is subject to the terms at http://greensock.com/standard-license or for 8 | * Club GreenSock members, the software agreement that was issued with your membership. 9 | * 10 | * @author: Jack Doyle, jack@greensock.com 11 | **/ 12 | var _gsScope="undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window;(_gsScope._gsQueue||(_gsScope._gsQueue=[])).push(function(){"use strict";_gsScope._gsDefine("easing.Back",["easing.Ease"],function(a){var b,c,d,e,f=_gsScope.GreenSockGlobals||_gsScope,g=f.com.greensock,h=2*Math.PI,i=Math.PI/2,j=g._class,k=function(b,c){var d=j("easing."+b,function(){},!0),e=d.prototype=new a;return e.constructor=d,e.getRatio=c,d},l=a.register||function(){},m=function(a,b,c,d,e){var f=j("easing."+a,{easeOut:new b,easeIn:new c,easeInOut:new d},!0);return l(f,a),f},n=function(a,b,c){this.t=a,this.v=b,c&&(this.next=c,c.prev=this,this.c=c.v-b,this.gap=c.t-a)},o=function(b,c){var d=j("easing."+b,function(a){this._p1=a||0===a?a:1.70158,this._p2=1.525*this._p1},!0),e=d.prototype=new a;return e.constructor=d,e.getRatio=c,e.config=function(a){return new d(a)},d},p=m("Back",o("BackOut",function(a){return(a-=1)*a*((this._p1+1)*a+this._p1)+1}),o("BackIn",function(a){return a*a*((this._p1+1)*a-this._p1)}),o("BackInOut",function(a){return(a*=2)<1?.5*a*a*((this._p2+1)*a-this._p2):.5*((a-=2)*a*((this._p2+1)*a+this._p2)+2)})),q=j("easing.SlowMo",function(a,b,c){b=b||0===b?b:.7,null==a?a=.7:a>1&&(a=1),this._p=1!==a?b:0,this._p1=(1-a)/2,this._p2=a,this._p3=this._p1+this._p2,this._calcEnd=c===!0},!0),r=q.prototype=new a;return r.constructor=q,r.getRatio=function(a){var b=a+(.5-a)*this._p;return athis._p3?this._calcEnd?1===a?0:1-(a=(a-this._p3)/this._p1)*a:b+(a-b)*(a=(a-this._p3)/this._p1)*a*a*a:this._calcEnd?1:b},q.ease=new q(.7,.7),r.config=q.config=function(a,b,c){return new q(a,b,c)},b=j("easing.SteppedEase",function(a,b){a=a||1,this._p1=1/a,this._p2=a+(b?0:1),this._p3=b?1:0},!0),r=b.prototype=new a,r.constructor=b,r.getRatio=function(a){return 0>a?a=0:a>=1&&(a=.999999999),((this._p2*a|0)+this._p3)*this._p1},r.config=b.config=function(a,c){return new b(a,c)},c=j("easing.ExpoScaleEase",function(a,b,c){this._p1=Math.log(b/a),this._p2=b-a,this._p3=a,this._ease=c},!0),r=c.prototype=new a,r.constructor=c,r.getRatio=function(a){return this._ease&&(a=this._ease.getRatio(a)),(this._p3*Math.exp(this._p1*a)-this._p3)/this._p2},r.config=c.config=function(a,b,d){return new c(a,b,d)},d=j("easing.RoughEase",function(b){b=b||{};for(var c,d,e,f,g,h,i=b.taper||"none",j=[],k=0,l=0|(b.points||20),m=l,o=b.randomize!==!1,p=b.clamp===!0,q=b.template instanceof a?b.template:null,r="number"==typeof b.strength?.4*b.strength:.4;--m>-1;)c=o?Math.random():1/l*m,d=q?q.getRatio(c):c,"none"===i?e=r:"out"===i?(f=1-c,e=f*f*r):"in"===i?e=c*c*r:.5>c?(f=2*c,e=f*f*.5*r):(f=2*(1-c),e=f*f*.5*r),o?d+=Math.random()*e-.5*e:m%2?d+=.5*e:d-=.5*e,p&&(d>1?d=1:0>d&&(d=0)),j[k++]={x:c,y:d};for(j.sort(function(a,b){return a.x-b.x}),h=new n(1,1,null),m=l;--m>-1;)g=j[m],h=new n(g.x,g.y,h);this._prev=new n(0,0,0!==h.t?h:h.next)},!0),r=d.prototype=new a,r.constructor=d,r.getRatio=function(a){var b=this._prev;if(a>b.t){for(;b.next&&a>=b.t;)b=b.next;b=b.prev}else for(;b.prev&&a<=b.t;)b=b.prev;return this._prev=b,b.v+(a-b.t)/b.gap*b.c},r.config=function(a){return new d(a)},d.ease=new d,m("Bounce",k("BounceOut",function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375}),k("BounceIn",function(a){return(a=1-a)<1/2.75?1-7.5625*a*a:2/2.75>a?1-(7.5625*(a-=1.5/2.75)*a+.75):2.5/2.75>a?1-(7.5625*(a-=2.25/2.75)*a+.9375):1-(7.5625*(a-=2.625/2.75)*a+.984375)}),k("BounceInOut",function(a){var b=.5>a;return a=b?1-2*a:2*a-1,a=1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375,b?.5*(1-a):.5*a+.5})),m("Circ",k("CircOut",function(a){return Math.sqrt(1-(a-=1)*a)}),k("CircIn",function(a){return-(Math.sqrt(1-a*a)-1)}),k("CircInOut",function(a){return(a*=2)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)})),e=function(b,c,d){var e=j("easing."+b,function(a,b){this._p1=a>=1?a:1,this._p2=(b||d)/(1>a?a:1),this._p3=this._p2/h*(Math.asin(1/this._p1)||0),this._p2=h/this._p2},!0),f=e.prototype=new a;return f.constructor=e,f.getRatio=c,f.config=function(a,b){return new e(a,b)},e},m("Elastic",e("ElasticOut",function(a){return this._p1*Math.pow(2,-10*a)*Math.sin((a-this._p3)*this._p2)+1},.3),e("ElasticIn",function(a){return-(this._p1*Math.pow(2,10*(a-=1))*Math.sin((a-this._p3)*this._p2))},.3),e("ElasticInOut",function(a){return(a*=2)<1?-.5*(this._p1*Math.pow(2,10*(a-=1))*Math.sin((a-this._p3)*this._p2)):this._p1*Math.pow(2,-10*(a-=1))*Math.sin((a-this._p3)*this._p2)*.5+1},.45)),m("Expo",k("ExpoOut",function(a){return 1-Math.pow(2,-10*a)}),k("ExpoIn",function(a){return Math.pow(2,10*(a-1))-.001}),k("ExpoInOut",function(a){return(a*=2)<1?.5*Math.pow(2,10*(a-1)):.5*(2-Math.pow(2,-10*(a-1)))})),m("Sine",k("SineOut",function(a){return Math.sin(a*i)}),k("SineIn",function(a){return-Math.cos(a*i)+1}),k("SineInOut",function(a){return-.5*(Math.cos(Math.PI*a)-1)})),j("easing.EaseLookup",{find:function(b){return a.map[b]}},!0),l(f.SlowMo,"SlowMo","ease,"),l(d,"RoughEase","ease,"),l(b,"SteppedEase","ease,"),p},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(),function(){"use strict";var a=function(){return _gsScope.GreenSockGlobals||_gsScope};"undefined"!=typeof module&&module.exports?(require("../TweenLite.min.js"),module.exports=a()):"function"==typeof define&&define.amd&&define(["TweenLite"],a)}(); -------------------------------------------------------------------------------- /src/assets/js/lib/GPUComputationRenderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author yomboprime https://github.com/yomboprime 3 | * 4 | * GPUComputationRenderer, based on SimulationRenderer by zz85 5 | * 6 | * The GPUComputationRenderer uses the concept of variables. These variables are RGBA float textures that hold 4 floats 7 | * for each compute element (texel) 8 | * 9 | * Each variable has a fragment shader that defines the computation made to obtain the variable in question. 10 | * You can use as many variables you need, and make dependencies so you can use textures of other variables in the shader 11 | * (the sampler uniforms are added automatically) Most of the variables will need themselves as dependency. 12 | * 13 | * The renderer has actually two render targets per variable, to make ping-pong. Textures from the current frame are used 14 | * as inputs to render the textures of the next frame. 15 | * 16 | * The render targets of the variables can be used as input textures for your visualization shaders. 17 | * 18 | * Variable names should be valid identifiers and should not collide with THREE GLSL used identifiers. 19 | * a common approach could be to use 'texture' prefixing the variable name; i.e texturePosition, textureVelocity... 20 | * 21 | * The size of the computation (sizeX * sizeY) is defined as 'resolution' automatically in the shader. For example: 22 | * #DEFINE resolution vec2( 1024.0, 1024.0 ) 23 | * 24 | * ------------- 25 | * 26 | * Basic use: 27 | * 28 | * // Initialization... 29 | * 30 | * // Create computation renderer 31 | * var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer ); 32 | * 33 | * // Create initial state float textures 34 | * var pos0 = gpuCompute.createTexture(); 35 | * var vel0 = gpuCompute.createTexture(); 36 | * // and fill in here the texture data... 37 | * 38 | * // Add texture variables 39 | * var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 ); 40 | * var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 ); 41 | * 42 | * // Add variable dependencies 43 | * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] ); 44 | * gpuCompute.setVariableDependencies( posVar, [ velVar, posVar ] ); 45 | * 46 | * // Add custom uniforms 47 | * velVar.material.uniforms.time = { value: 0.0 }; 48 | * 49 | * // Check for completeness 50 | * var error = gpuCompute.init(); 51 | * if ( error !== null ) { 52 | * console.error( error ); 53 | * } 54 | * 55 | * 56 | * // In each frame... 57 | * 58 | * // Compute! 59 | * gpuCompute.compute(); 60 | * 61 | * // Update texture uniforms in your visualization materials with the gpu renderer output 62 | * myMaterial.uniforms.myTexture.value = gpuCompute.getCurrentRenderTarget( posVar ).texture; 63 | * 64 | * // Do your rendering 65 | * renderer.render( myScene, myCamera ); 66 | * 67 | * ------------- 68 | * 69 | * Also, you can use utility functions to create ShaderMaterial and perform computations (rendering between textures) 70 | * Note that the shaders can have multiple input textures. 71 | * 72 | * var myFilter1 = gpuCompute.createShaderMaterial( myFilterFragmentShader1, { theTexture: { value: null } } ); 73 | * var myFilter2 = gpuCompute.createShaderMaterial( myFilterFragmentShader2, { theTexture: { value: null } } ); 74 | * 75 | * var inputTexture = gpuCompute.createTexture(); 76 | * 77 | * // Fill in here inputTexture... 78 | * 79 | * myFilter1.uniforms.theTexture.value = inputTexture; 80 | * 81 | * var myRenderTarget = gpuCompute.createRenderTarget(); 82 | * myFilter2.uniforms.theTexture.value = myRenderTarget.texture; 83 | * 84 | * var outputRenderTarget = gpuCompute.createRenderTarget(); 85 | * 86 | * // Now use the output texture where you want: 87 | * myMaterial.uniforms.map.value = outputRenderTarget.texture; 88 | * 89 | * // And compute each frame, before rendering to screen: 90 | * gpuCompute.doRenderTarget( myFilter1, myRenderTarget ); 91 | * gpuCompute.doRenderTarget( myFilter2, outputRenderTarget ); 92 | * 93 | * 94 | * 95 | * @param {int} sizeX Computation problem size is always 2d: sizeX * sizeY elements. 96 | * @param {int} sizeY Computation problem size is always 2d: sizeX * sizeY elements. 97 | * @param {WebGLRenderer} renderer The renderer 98 | */ 99 | 100 | function GPUComputationRenderer( sizeX, sizeY, renderer ) { 101 | 102 | this.variables = []; 103 | 104 | this.currentTextureIndex = 0; 105 | 106 | var scene = new THREE.Scene(); 107 | 108 | var camera = new THREE.Camera(); 109 | camera.position.z = 1; 110 | 111 | var passThruUniforms = { 112 | texture: { value: null } 113 | }; 114 | 115 | var passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms ); 116 | 117 | var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), passThruShader ); 118 | scene.add( mesh ); 119 | 120 | 121 | this.addVariable = function( variableName, computeFragmentShader, initialValueTexture ) { 122 | 123 | var material = this.createShaderMaterial( computeFragmentShader ); 124 | 125 | var variable = { 126 | name: variableName, 127 | initialValueTexture: initialValueTexture, 128 | material: material, 129 | dependencies: null, 130 | renderTargets: [], 131 | wrapS: null, 132 | wrapT: null, 133 | minFilter: THREE.NearestFilter, 134 | magFilter: THREE.NearestFilter 135 | }; 136 | 137 | this.variables.push( variable ); 138 | 139 | return variable; 140 | 141 | }; 142 | 143 | this.setVariableDependencies = function( variable, dependencies ) { 144 | 145 | variable.dependencies = dependencies; 146 | 147 | }; 148 | 149 | this.init = function() { 150 | 151 | if ( ! renderer.extensions.get( "OES_texture_float" ) ) { 152 | 153 | return "No OES_texture_float support for float textures."; 154 | 155 | } 156 | 157 | if ( renderer.capabilities.maxVertexTextures === 0 ) { 158 | 159 | return "No support for vertex shader textures."; 160 | 161 | } 162 | 163 | for ( var i = 0; i < this.variables.length; i++ ) { 164 | 165 | var variable = this.variables[ i ]; 166 | 167 | // Creates rendertargets and initialize them with input texture 168 | variable.renderTargets[ 0 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter ); 169 | variable.renderTargets[ 1 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter ); 170 | this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 0 ] ); 171 | this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 1 ] ); 172 | 173 | // Adds dependencies uniforms to the ShaderMaterial 174 | var material = variable.material; 175 | var uniforms = material.uniforms; 176 | if ( variable.dependencies !== null ) { 177 | 178 | for ( var d = 0; d < variable.dependencies.length; d++ ) { 179 | 180 | var depVar = variable.dependencies[ d ]; 181 | 182 | if ( depVar.name !== variable.name ) { 183 | 184 | // Checks if variable exists 185 | var found = false; 186 | for ( var j = 0; j < this.variables.length; j++ ) { 187 | 188 | if ( depVar.name === this.variables[ j ].name ) { 189 | found = true; 190 | break; 191 | } 192 | 193 | } 194 | if ( ! found ) { 195 | return "Variable dependency not found. Variable=" + variable.name + ", dependency=" + depVar.name; 196 | } 197 | 198 | } 199 | 200 | uniforms[ depVar.name ] = { value: null }; 201 | 202 | material.fragmentShader = "\nuniform sampler2D " + depVar.name + ";\n" + material.fragmentShader; 203 | 204 | } 205 | } 206 | } 207 | 208 | this.currentTextureIndex = 0; 209 | 210 | return null; 211 | 212 | }; 213 | 214 | this.compute = function() { 215 | 216 | var currentTextureIndex = this.currentTextureIndex; 217 | var nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0; 218 | 219 | for ( var i = 0, il = this.variables.length; i < il; i++ ) { 220 | 221 | var variable = this.variables[ i ]; 222 | 223 | // Sets texture dependencies uniforms 224 | if ( variable.dependencies !== null ) { 225 | 226 | var uniforms = variable.material.uniforms; 227 | for ( var d = 0, dl = variable.dependencies.length; d < dl; d++ ) { 228 | 229 | var depVar = variable.dependencies[ d ]; 230 | // console.log(depVar); 231 | 232 | uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture; 233 | 234 | } 235 | 236 | } 237 | 238 | // Performs the computation for this variable 239 | this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] ); 240 | 241 | } 242 | 243 | this.currentTextureIndex = nextTextureIndex; 244 | }; 245 | 246 | this.getCurrentRenderTarget = function( variable ) { 247 | 248 | return variable.renderTargets[ this.currentTextureIndex ]; 249 | 250 | }; 251 | 252 | this.getAlternateRenderTarget = function( variable ) { 253 | 254 | return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ]; 255 | 256 | }; 257 | 258 | function addResolutionDefine( materialShader ) { 259 | 260 | materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed( 1 ) + ', ' + sizeY.toFixed( 1 ) + " )"; 261 | 262 | }; 263 | this.addResolutionDefine = addResolutionDefine; 264 | 265 | 266 | // The following functions can be used to compute things manually 267 | 268 | function createShaderMaterial( computeFragmentShader, uniforms ) { 269 | 270 | uniforms = uniforms || {}; 271 | 272 | var material = new THREE.ShaderMaterial( { 273 | uniforms: uniforms, 274 | vertexShader: getPassThroughVertexShader(), 275 | fragmentShader: computeFragmentShader 276 | } ); 277 | 278 | addResolutionDefine( material ); 279 | 280 | return material; 281 | }; 282 | this.createShaderMaterial = createShaderMaterial; 283 | 284 | this.createRenderTarget = function( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) { 285 | 286 | sizeXTexture = sizeXTexture || sizeX; 287 | sizeYTexture = sizeYTexture || sizeY; 288 | 289 | wrapS = wrapS || THREE.ClampToEdgeWrapping; 290 | wrapT = wrapT || THREE.ClampToEdgeWrapping; 291 | 292 | minFilter = minFilter || THREE.NearestFilter; 293 | magFilter = magFilter || THREE.NearestFilter; 294 | 295 | var floatType = (Useragnt.ios) ? THREE.HalfFloatType : THREE.FloatType; 296 | 297 | var renderTarget = new THREE.WebGLRenderTarget( sizeXTexture, sizeYTexture, { 298 | wrapS: wrapS, 299 | wrapT: wrapT, 300 | minFilter: minFilter, 301 | magFilter: magFilter, 302 | format: THREE.RGBAFormat, 303 | type: floatType, 304 | stencilBuffer: false 305 | } ); 306 | 307 | return renderTarget; 308 | 309 | }; 310 | 311 | this.createTexture = function( sizeXTexture, sizeYTexture ) { 312 | 313 | sizeXTexture = sizeXTexture || sizeX; 314 | sizeYTexture = sizeYTexture || sizeY; 315 | 316 | var floatType = (Useragnt.ios) ? THREE.HalfFloatType : THREE.FloatType; 317 | 318 | var a = new Float32Array( sizeXTexture * sizeYTexture * 4 ); 319 | var texture = new THREE.DataTexture( a, sizeX, sizeY, THREE.RGBAFormat, THREE.FloatType ); 320 | texture.needsUpdate = true; 321 | 322 | return texture; 323 | 324 | }; 325 | 326 | 327 | this.renderTexture = function( input, output ) { 328 | 329 | // Takes a texture, and render out in rendertarget 330 | // input = Texture 331 | // output = RenderTarget 332 | 333 | passThruUniforms.texture.value = input; 334 | 335 | this.doRenderTarget( passThruShader, output); 336 | 337 | passThruUniforms.texture.value = null; 338 | 339 | }; 340 | 341 | this.doRenderTarget = function( material, output ) { 342 | 343 | mesh.material = material; 344 | renderer.render( scene, camera, output ); 345 | mesh.material = passThruShader; 346 | 347 | }; 348 | 349 | // Shaders 350 | 351 | function getPassThroughVertexShader() { 352 | 353 | return "void main() {\n" + 354 | "\n" + 355 | " gl_Position = vec4( position, 1.0 );\n" + 356 | "\n" + 357 | "}\n"; 358 | 359 | } 360 | 361 | function getPassThroughFragmentShader() { 362 | 363 | return "uniform sampler2D texture;\n" + 364 | "\n" + 365 | "void main() {\n" + 366 | "\n" + 367 | " vec2 uv = gl_FragCoord.xy / resolution.xy;\n" + 368 | "\n" + 369 | " gl_FragColor = texture2D( texture, uv );\n" + 370 | "\n" + 371 | "}\n"; 372 | 373 | } 374 | 375 | } -------------------------------------------------------------------------------- /src/assets/js/lib/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 | * @author erich666 / http://erichaines.com 7 | */ 8 | 9 | // This set of controls performs orbiting, dollying (zooming), and panning. 10 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). 11 | // 12 | // Orbit - left mouse / touch: one finger move 13 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish 14 | // Pan - right mouse, or arrow keys / touch: three finger swipe 15 | 16 | THREE.OrbitControls = function ( object, domElement ) { 17 | 18 | this.object = object; 19 | 20 | this.domElement = ( domElement !== undefined ) ? domElement : document; 21 | 22 | // Set to false to disable this control 23 | this.enabled = true; 24 | 25 | // "target" sets the location of focus, where the object orbits around 26 | this.target = new THREE.Vector3(); 27 | 28 | // How far you can dolly in and out ( PerspectiveCamera only ) 29 | this.minDistance = 0; 30 | this.maxDistance = Infinity; 31 | 32 | // How far you can zoom in and out ( OrthographicCamera only ) 33 | this.minZoom = 0; 34 | this.maxZoom = Infinity; 35 | 36 | // How far you can orbit vertically, upper and lower limits. 37 | // Range is 0 to Math.PI radians. 38 | this.minPolarAngle = 0; // radians 39 | this.maxPolarAngle = Math.PI; // radians 40 | 41 | // How far you can orbit horizontally, upper and lower limits. 42 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. 43 | this.minAzimuthAngle = - Infinity; // radians 44 | this.maxAzimuthAngle = Infinity; // radians 45 | 46 | // Set to true to enable damping (inertia) 47 | // If damping is enabled, you must call controls.update() in your animation loop 48 | this.enableDamping = false; 49 | this.dampingFactor = 0.25; 50 | 51 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. 52 | // Set to false to disable zooming 53 | this.enableZoom = true; 54 | this.zoomSpeed = 1.0; 55 | 56 | // Set to false to disable rotating 57 | this.enableRotate = true; 58 | this.rotateSpeed = 1.0; 59 | 60 | // Set to false to disable panning 61 | this.enablePan = true; 62 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push 63 | 64 | // Set to true to automatically rotate around the target 65 | // If auto-rotate is enabled, you must call controls.update() in your animation loop 66 | this.autoRotate = false; 67 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 68 | 69 | // Set to false to disable use of the keys 70 | this.enableKeys = true; 71 | 72 | // The four arrow keys 73 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 74 | 75 | // Mouse buttons 76 | this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; 77 | 78 | // for reset 79 | this.target0 = this.target.clone(); 80 | this.position0 = this.object.position.clone(); 81 | this.zoom0 = this.object.zoom; 82 | 83 | // 84 | // public methods 85 | // 86 | 87 | this.getPolarAngle = function () { 88 | 89 | return spherical.phi; 90 | 91 | }; 92 | 93 | this.getAzimuthalAngle = function () { 94 | 95 | return spherical.theta; 96 | 97 | }; 98 | 99 | this.reset = function () { 100 | 101 | scope.target.copy( scope.target0 ); 102 | scope.object.position.copy( scope.position0 ); 103 | scope.object.zoom = scope.zoom0; 104 | 105 | scope.object.updateProjectionMatrix(); 106 | scope.dispatchEvent( changeEvent ); 107 | 108 | scope.update(); 109 | 110 | state = STATE.NONE; 111 | 112 | }; 113 | 114 | // this method is exposed, but perhaps it would be better if we can make it private... 115 | this.update = function () { 116 | 117 | var offset = new THREE.Vector3(); 118 | 119 | // so camera.up is the orbit axis 120 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); 121 | var quatInverse = quat.clone().inverse(); 122 | 123 | var lastPosition = new THREE.Vector3(); 124 | var lastQuaternion = new THREE.Quaternion(); 125 | 126 | return function update() { 127 | 128 | var position = scope.object.position; 129 | 130 | offset.copy( position ).sub( scope.target ); 131 | 132 | // rotate offset to "y-axis-is-up" space 133 | offset.applyQuaternion( quat ); 134 | 135 | // angle from z-axis around y-axis 136 | spherical.setFromVector3( offset ); 137 | 138 | if ( scope.autoRotate && state === STATE.NONE ) { 139 | 140 | rotateLeft( getAutoRotationAngle() ); 141 | 142 | } 143 | 144 | spherical.theta += sphericalDelta.theta; 145 | spherical.phi += sphericalDelta.phi; 146 | 147 | // restrict theta to be between desired limits 148 | spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); 149 | 150 | // restrict phi to be between desired limits 151 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); 152 | 153 | spherical.makeSafe(); 154 | 155 | 156 | spherical.radius *= scale; 157 | 158 | // restrict radius to be between desired limits 159 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); 160 | 161 | // move target to panned location 162 | scope.target.add( panOffset ); 163 | 164 | offset.setFromSpherical( spherical ); 165 | 166 | // rotate offset back to "camera-up-vector-is-up" space 167 | offset.applyQuaternion( quatInverse ); 168 | 169 | position.copy( scope.target ).add( offset ); 170 | 171 | scope.object.lookAt( scope.target ); 172 | 173 | if ( scope.enableDamping === true ) { 174 | 175 | sphericalDelta.theta *= ( 1 - scope.dampingFactor ); 176 | sphericalDelta.phi *= ( 1 - scope.dampingFactor ); 177 | 178 | } else { 179 | 180 | sphericalDelta.set( 0, 0, 0 ); 181 | 182 | } 183 | 184 | scale = 1; 185 | panOffset.set( 0, 0, 0 ); 186 | 187 | // update condition is: 188 | // min(camera displacement, camera rotation in radians)^2 > EPS 189 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8 190 | 191 | if ( zoomChanged || 192 | lastPosition.distanceToSquared( scope.object.position ) > EPS || 193 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { 194 | 195 | scope.dispatchEvent( changeEvent ); 196 | 197 | lastPosition.copy( scope.object.position ); 198 | lastQuaternion.copy( scope.object.quaternion ); 199 | zoomChanged = false; 200 | 201 | return true; 202 | 203 | } 204 | 205 | return false; 206 | 207 | }; 208 | 209 | }(); 210 | 211 | this.dispose = function () { 212 | 213 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); 214 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); 215 | scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); 216 | 217 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); 218 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); 219 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); 220 | 221 | document.removeEventListener( 'mousemove', onMouseMove, false ); 222 | document.removeEventListener( 'mouseup', onMouseUp, false ); 223 | 224 | window.removeEventListener( 'keydown', onKeyDown, false ); 225 | 226 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? 227 | 228 | }; 229 | 230 | // 231 | // internals 232 | // 233 | 234 | var scope = this; 235 | 236 | var changeEvent = { type: 'change' }; 237 | var startEvent = { type: 'start' }; 238 | var endEvent = { type: 'end' }; 239 | 240 | var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5 }; 241 | 242 | var state = STATE.NONE; 243 | 244 | var EPS = 0.000001; 245 | 246 | // current position in spherical coordinates 247 | var spherical = new THREE.Spherical(); 248 | var sphericalDelta = new THREE.Spherical(); 249 | 250 | var scale = 1; 251 | var panOffset = new THREE.Vector3(); 252 | var zoomChanged = false; 253 | 254 | var rotateStart = new THREE.Vector2(); 255 | var rotateEnd = new THREE.Vector2(); 256 | var rotateDelta = new THREE.Vector2(); 257 | 258 | var panStart = new THREE.Vector2(); 259 | var panEnd = new THREE.Vector2(); 260 | var panDelta = new THREE.Vector2(); 261 | 262 | var dollyStart = new THREE.Vector2(); 263 | var dollyEnd = new THREE.Vector2(); 264 | var dollyDelta = new THREE.Vector2(); 265 | 266 | function getAutoRotationAngle() { 267 | 268 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; 269 | 270 | } 271 | 272 | function getZoomScale() { 273 | 274 | return Math.pow( 0.95, scope.zoomSpeed ); 275 | 276 | } 277 | 278 | function rotateLeft( angle ) { 279 | 280 | sphericalDelta.theta -= angle; 281 | 282 | } 283 | 284 | function rotateUp( angle ) { 285 | 286 | sphericalDelta.phi -= angle; 287 | 288 | } 289 | 290 | var panLeft = function () { 291 | 292 | var v = new THREE.Vector3(); 293 | 294 | return function panLeft( distance, objectMatrix ) { 295 | 296 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix 297 | v.multiplyScalar( - distance ); 298 | 299 | panOffset.add( v ); 300 | 301 | }; 302 | 303 | }(); 304 | 305 | var panUp = function () { 306 | 307 | var v = new THREE.Vector3(); 308 | 309 | return function panUp( distance, objectMatrix ) { 310 | 311 | v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix 312 | v.multiplyScalar( distance ); 313 | 314 | panOffset.add( v ); 315 | 316 | }; 317 | 318 | }(); 319 | 320 | // deltaX and deltaY are in pixels; right and down are positive 321 | var pan = function () { 322 | 323 | var offset = new THREE.Vector3(); 324 | 325 | return function pan( deltaX, deltaY ) { 326 | 327 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 328 | 329 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 330 | 331 | // perspective 332 | var position = scope.object.position; 333 | offset.copy( position ).sub( scope.target ); 334 | var targetDistance = offset.length(); 335 | 336 | // half of the fov is center to top of screen 337 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); 338 | 339 | // we actually don't use screenWidth, since perspective camera is fixed to screen height 340 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); 341 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); 342 | 343 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 344 | 345 | // orthographic 346 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); 347 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); 348 | 349 | } else { 350 | 351 | // camera neither orthographic nor perspective 352 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); 353 | scope.enablePan = false; 354 | 355 | } 356 | 357 | }; 358 | 359 | }(); 360 | 361 | function dollyIn( dollyScale ) { 362 | 363 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 364 | 365 | scale /= dollyScale; 366 | 367 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 368 | 369 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); 370 | scope.object.updateProjectionMatrix(); 371 | zoomChanged = true; 372 | 373 | } else { 374 | 375 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 376 | scope.enableZoom = false; 377 | 378 | } 379 | 380 | } 381 | 382 | function dollyOut( dollyScale ) { 383 | 384 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 385 | 386 | scale *= dollyScale; 387 | 388 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 389 | 390 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); 391 | scope.object.updateProjectionMatrix(); 392 | zoomChanged = true; 393 | 394 | } else { 395 | 396 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 397 | scope.enableZoom = false; 398 | 399 | } 400 | 401 | } 402 | 403 | // 404 | // event callbacks - update the object state 405 | // 406 | 407 | function handleMouseDownRotate( event ) { 408 | 409 | //console.log( 'handleMouseDownRotate' ); 410 | 411 | rotateStart.set( event.clientX, event.clientY ); 412 | 413 | } 414 | 415 | function handleMouseDownDolly( event ) { 416 | 417 | //console.log( 'handleMouseDownDolly' ); 418 | 419 | dollyStart.set( event.clientX, event.clientY ); 420 | 421 | } 422 | 423 | function handleMouseDownPan( event ) { 424 | 425 | //console.log( 'handleMouseDownPan' ); 426 | 427 | panStart.set( event.clientX, event.clientY ); 428 | 429 | } 430 | 431 | function handleMouseMoveRotate( event ) { 432 | 433 | //console.log( 'handleMouseMoveRotate' ); 434 | 435 | rotateEnd.set( event.clientX, event.clientY ); 436 | rotateDelta.subVectors( rotateEnd, rotateStart ); 437 | 438 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 439 | 440 | // rotating across whole screen goes 360 degrees around 441 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 442 | 443 | // rotating up and down along whole screen attempts to go 360, but limited to 180 444 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 445 | 446 | rotateStart.copy( rotateEnd ); 447 | 448 | scope.update(); 449 | 450 | } 451 | 452 | function handleMouseMoveDolly( event ) { 453 | 454 | //console.log( 'handleMouseMoveDolly' ); 455 | 456 | dollyEnd.set( event.clientX, event.clientY ); 457 | 458 | dollyDelta.subVectors( dollyEnd, dollyStart ); 459 | 460 | if ( dollyDelta.y > 0 ) { 461 | 462 | dollyIn( getZoomScale() ); 463 | 464 | } else if ( dollyDelta.y < 0 ) { 465 | 466 | dollyOut( getZoomScale() ); 467 | 468 | } 469 | 470 | dollyStart.copy( dollyEnd ); 471 | 472 | scope.update(); 473 | 474 | } 475 | 476 | function handleMouseMovePan( event ) { 477 | 478 | //console.log( 'handleMouseMovePan' ); 479 | 480 | panEnd.set( event.clientX, event.clientY ); 481 | 482 | panDelta.subVectors( panEnd, panStart ); 483 | 484 | pan( panDelta.x, panDelta.y ); 485 | 486 | panStart.copy( panEnd ); 487 | 488 | scope.update(); 489 | 490 | } 491 | 492 | function handleMouseUp( event ) { 493 | 494 | // console.log( 'handleMouseUp' ); 495 | 496 | } 497 | 498 | function handleMouseWheel( event ) { 499 | 500 | // console.log( 'handleMouseWheel' ); 501 | 502 | if ( event.deltaY < 0 ) { 503 | 504 | dollyOut( getZoomScale() ); 505 | 506 | } else if ( event.deltaY > 0 ) { 507 | 508 | dollyIn( getZoomScale() ); 509 | 510 | } 511 | 512 | scope.update(); 513 | 514 | } 515 | 516 | function handleKeyDown( event ) { 517 | 518 | //console.log( 'handleKeyDown' ); 519 | 520 | switch ( event.keyCode ) { 521 | 522 | case scope.keys.UP: 523 | pan( 0, scope.keyPanSpeed ); 524 | scope.update(); 525 | break; 526 | 527 | case scope.keys.BOTTOM: 528 | pan( 0, - scope.keyPanSpeed ); 529 | scope.update(); 530 | break; 531 | 532 | case scope.keys.LEFT: 533 | pan( scope.keyPanSpeed, 0 ); 534 | scope.update(); 535 | break; 536 | 537 | case scope.keys.RIGHT: 538 | pan( - scope.keyPanSpeed, 0 ); 539 | scope.update(); 540 | break; 541 | 542 | } 543 | 544 | } 545 | 546 | function handleTouchStartRotate( event ) { 547 | 548 | //console.log( 'handleTouchStartRotate' ); 549 | 550 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 551 | 552 | } 553 | 554 | function handleTouchStartDolly( event ) { 555 | 556 | //console.log( 'handleTouchStartDolly' ); 557 | 558 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 559 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 560 | 561 | var distance = Math.sqrt( dx * dx + dy * dy ); 562 | 563 | dollyStart.set( 0, distance ); 564 | 565 | } 566 | 567 | function handleTouchStartPan( event ) { 568 | 569 | //console.log( 'handleTouchStartPan' ); 570 | 571 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 572 | 573 | } 574 | 575 | function handleTouchMoveRotate( event ) { 576 | 577 | //console.log( 'handleTouchMoveRotate' ); 578 | 579 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 580 | rotateDelta.subVectors( rotateEnd, rotateStart ); 581 | 582 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 583 | 584 | // rotating across whole screen goes 360 degrees around 585 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 586 | 587 | // rotating up and down along whole screen attempts to go 360, but limited to 180 588 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 589 | 590 | rotateStart.copy( rotateEnd ); 591 | 592 | scope.update(); 593 | 594 | } 595 | 596 | function handleTouchMoveDolly( event ) { 597 | 598 | //console.log( 'handleTouchMoveDolly' ); 599 | 600 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 601 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 602 | 603 | var distance = Math.sqrt( dx * dx + dy * dy ); 604 | 605 | dollyEnd.set( 0, distance ); 606 | 607 | dollyDelta.subVectors( dollyEnd, dollyStart ); 608 | 609 | if ( dollyDelta.y > 0 ) { 610 | 611 | dollyOut( getZoomScale() ); 612 | 613 | } else if ( dollyDelta.y < 0 ) { 614 | 615 | dollyIn( getZoomScale() ); 616 | 617 | } 618 | 619 | dollyStart.copy( dollyEnd ); 620 | 621 | scope.update(); 622 | 623 | } 624 | 625 | function handleTouchMovePan( event ) { 626 | 627 | //console.log( 'handleTouchMovePan' ); 628 | 629 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 630 | 631 | panDelta.subVectors( panEnd, panStart ); 632 | 633 | pan( panDelta.x, panDelta.y ); 634 | 635 | panStart.copy( panEnd ); 636 | 637 | scope.update(); 638 | 639 | } 640 | 641 | function handleTouchEnd( event ) { 642 | 643 | //console.log( 'handleTouchEnd' ); 644 | 645 | } 646 | 647 | // 648 | // event handlers - FSM: listen for events and reset state 649 | // 650 | 651 | function onMouseDown( event ) { 652 | 653 | if ( scope.enabled === false ) return; 654 | 655 | event.preventDefault(); 656 | 657 | if ( event.button === scope.mouseButtons.ORBIT ) { 658 | 659 | if ( scope.enableRotate === false ) return; 660 | 661 | handleMouseDownRotate( event ); 662 | 663 | state = STATE.ROTATE; 664 | 665 | } else if ( event.button === scope.mouseButtons.ZOOM ) { 666 | 667 | if ( scope.enableZoom === false ) return; 668 | 669 | handleMouseDownDolly( event ); 670 | 671 | state = STATE.DOLLY; 672 | 673 | } else if ( event.button === scope.mouseButtons.PAN ) { 674 | 675 | if ( scope.enablePan === false ) return; 676 | 677 | handleMouseDownPan( event ); 678 | 679 | state = STATE.PAN; 680 | 681 | } 682 | 683 | if ( state !== STATE.NONE ) { 684 | 685 | document.addEventListener( 'mousemove', onMouseMove, false ); 686 | document.addEventListener( 'mouseup', onMouseUp, false ); 687 | 688 | scope.dispatchEvent( startEvent ); 689 | 690 | } 691 | 692 | } 693 | 694 | function onMouseMove( event ) { 695 | 696 | if ( scope.enabled === false ) return; 697 | 698 | event.preventDefault(); 699 | 700 | if ( state === STATE.ROTATE ) { 701 | 702 | if ( scope.enableRotate === false ) return; 703 | 704 | handleMouseMoveRotate( event ); 705 | 706 | } else if ( state === STATE.DOLLY ) { 707 | 708 | if ( scope.enableZoom === false ) return; 709 | 710 | handleMouseMoveDolly( event ); 711 | 712 | } else if ( state === STATE.PAN ) { 713 | 714 | if ( scope.enablePan === false ) return; 715 | 716 | handleMouseMovePan( event ); 717 | 718 | } 719 | 720 | } 721 | 722 | function onMouseUp( event ) { 723 | 724 | if ( scope.enabled === false ) return; 725 | 726 | handleMouseUp( event ); 727 | 728 | document.removeEventListener( 'mousemove', onMouseMove, false ); 729 | document.removeEventListener( 'mouseup', onMouseUp, false ); 730 | 731 | scope.dispatchEvent( endEvent ); 732 | 733 | state = STATE.NONE; 734 | 735 | } 736 | 737 | function onMouseWheel( event ) { 738 | 739 | if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; 740 | 741 | event.preventDefault(); 742 | event.stopPropagation(); 743 | 744 | handleMouseWheel( event ); 745 | 746 | scope.dispatchEvent( startEvent ); // not sure why these are here... 747 | scope.dispatchEvent( endEvent ); 748 | 749 | } 750 | 751 | function onKeyDown( event ) { 752 | 753 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; 754 | 755 | handleKeyDown( event ); 756 | 757 | } 758 | 759 | function onTouchStart( event ) { 760 | 761 | if ( scope.enabled === false ) return; 762 | 763 | switch ( event.touches.length ) { 764 | 765 | case 1: // one-fingered touch: rotate 766 | 767 | if ( scope.enableRotate === false ) return; 768 | 769 | handleTouchStartRotate( event ); 770 | 771 | state = STATE.TOUCH_ROTATE; 772 | 773 | break; 774 | 775 | case 2: // two-fingered touch: dolly 776 | 777 | if ( scope.enableZoom === false ) return; 778 | 779 | handleTouchStartDolly( event ); 780 | 781 | state = STATE.TOUCH_DOLLY; 782 | 783 | break; 784 | 785 | case 3: // three-fingered touch: pan 786 | 787 | if ( scope.enablePan === false ) return; 788 | 789 | handleTouchStartPan( event ); 790 | 791 | state = STATE.TOUCH_PAN; 792 | 793 | break; 794 | 795 | default: 796 | 797 | state = STATE.NONE; 798 | 799 | } 800 | 801 | if ( state !== STATE.NONE ) { 802 | 803 | scope.dispatchEvent( startEvent ); 804 | 805 | } 806 | 807 | } 808 | 809 | function onTouchMove( event ) { 810 | 811 | if ( scope.enabled === false ) return; 812 | 813 | event.preventDefault(); 814 | event.stopPropagation(); 815 | 816 | switch ( event.touches.length ) { 817 | 818 | case 1: // one-fingered touch: rotate 819 | 820 | if ( scope.enableRotate === false ) return; 821 | if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... 822 | 823 | handleTouchMoveRotate( event ); 824 | 825 | break; 826 | 827 | case 2: // two-fingered touch: dolly 828 | 829 | if ( scope.enableZoom === false ) return; 830 | if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... 831 | 832 | handleTouchMoveDolly( event ); 833 | 834 | break; 835 | 836 | case 3: // three-fingered touch: pan 837 | 838 | if ( scope.enablePan === false ) return; 839 | if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... 840 | 841 | handleTouchMovePan( event ); 842 | 843 | break; 844 | 845 | default: 846 | 847 | state = STATE.NONE; 848 | 849 | } 850 | 851 | } 852 | 853 | function onTouchEnd( event ) { 854 | 855 | if ( scope.enabled === false ) return; 856 | 857 | handleTouchEnd( event ); 858 | 859 | scope.dispatchEvent( endEvent ); 860 | 861 | state = STATE.NONE; 862 | 863 | } 864 | 865 | function onContextMenu( event ) { 866 | 867 | event.preventDefault(); 868 | 869 | } 870 | 871 | // 872 | 873 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); 874 | 875 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); 876 | scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); 877 | 878 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); 879 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); 880 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); 881 | 882 | window.addEventListener( 'keydown', onKeyDown, false ); 883 | 884 | // force an update at start 885 | 886 | this.update(); 887 | 888 | }; 889 | 890 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 891 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; 892 | 893 | Object.defineProperties( THREE.OrbitControls.prototype, { 894 | 895 | center: { 896 | 897 | get: function () { 898 | 899 | console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); 900 | return this.target; 901 | 902 | } 903 | 904 | }, 905 | 906 | // backward compatibility 907 | 908 | noZoom: { 909 | 910 | get: function () { 911 | 912 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 913 | return ! this.enableZoom; 914 | 915 | }, 916 | 917 | set: function ( value ) { 918 | 919 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 920 | this.enableZoom = ! value; 921 | 922 | } 923 | 924 | }, 925 | 926 | noRotate: { 927 | 928 | get: function () { 929 | 930 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 931 | return ! this.enableRotate; 932 | 933 | }, 934 | 935 | set: function ( value ) { 936 | 937 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 938 | this.enableRotate = ! value; 939 | 940 | } 941 | 942 | }, 943 | 944 | noPan: { 945 | 946 | get: function () { 947 | 948 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 949 | return ! this.enablePan; 950 | 951 | }, 952 | 953 | set: function ( value ) { 954 | 955 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 956 | this.enablePan = ! value; 957 | 958 | } 959 | 960 | }, 961 | 962 | noKeys: { 963 | 964 | get: function () { 965 | 966 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 967 | return ! this.enableKeys; 968 | 969 | }, 970 | 971 | set: function ( value ) { 972 | 973 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 974 | this.enableKeys = ! value; 975 | 976 | } 977 | 978 | }, 979 | 980 | staticMoving: { 981 | 982 | get: function () { 983 | 984 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 985 | return ! this.enableDamping; 986 | 987 | }, 988 | 989 | set: function ( value ) { 990 | 991 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 992 | this.enableDamping = ! value; 993 | 994 | } 995 | 996 | }, 997 | 998 | dynamicDampingFactor: { 999 | 1000 | get: function () { 1001 | 1002 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1003 | return this.dampingFactor; 1004 | 1005 | }, 1006 | 1007 | set: function ( value ) { 1008 | 1009 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1010 | this.dampingFactor = value; 1011 | 1012 | } 1013 | 1014 | } 1015 | 1016 | } ); 1017 | -------------------------------------------------------------------------------- /src/assets/js/lib/ShadowMapViewer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author arya-s / https://github.com/arya-s 3 | * 4 | * This is a helper for visualising a given light's shadow map. 5 | * It works for shadow casting lights: THREE.DirectionalLight and THREE.SpotLight. 6 | * It renders out the shadow map and displays it on a HUD. 7 | * 8 | * Example usage: 9 | * 1) Include 34 | 35 | 36 | 37 | --------------------------------------------------------------------------------