<script id="Mosaic_ComputeVelocity" type="x-shader/x-vertex">
        vec3 mod289(vec3 x) {
          return x - floor(x * (1.0 / 289.0)) * 289.0;
        }

        vec4 mod289(vec4 x) {
          return x - floor(x * (1.0 / 289.0)) * 289.0;
        }

        vec4 permute(vec4 x) {
             return mod289(((x*34.0)+1.0)*x);
        }

        vec4 taylorInvSqrt(vec4 r)
        {
          return 1.79284291400159 - 0.85373472095314 * r;
        }

        float snoise(vec3 v)
          {
          const vec2  C = vec2(1.0/6.0, 1.0/3.0) ;
          const vec4  D = vec4(0.0, 0.5, 1.0, 2.0);

        // First corner
          vec3 i  = floor(v + dot(v, C.yyy) );
          vec3 x0 =   v - i + dot(i, C.xxx) ;

        // Other corners
          vec3 g = step(x0.yzx, x0.xyz);
          vec3 l = 1.0 - g;
          vec3 i1 = min( g.xyz, l.zxy );
          vec3 i2 = max( g.xyz, l.zxy );

          //   x0 = x0 - 0.0 + 0.0 * C.xxx;
          //   x1 = x0 - i1  + 1.0 * C.xxx;
          //   x2 = x0 - i2  + 2.0 * C.xxx;
          //   x3 = x0 - 1.0 + 3.0 * C.xxx;
          vec3 x1 = x0 - i1 + C.xxx;
          vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
          vec3 x3 = x0 - D.yyy;      // -1.0+3.0*C.x = -0.5 = -D.y

        // Permutations
          i = mod289(i);
          vec4 p = permute( permute( permute(
                     i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
                   + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
                   + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));

        // Gradients: 7x7 points over a square, mapped onto an octahedron.
        // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
          float n_ = 0.142857142857; // 1.0/7.0
          vec3  ns = n_ * D.wyz - D.xzx;

          vec4 j = p - 49.0 * floor(p * ns.z * ns.z);  //  mod(p,7*7)

          vec4 x_ = floor(j * ns.z);
          vec4 y_ = floor(j - 7.0 * x_ );    // mod(j,N)

          vec4 x = x_ *ns.x + ns.yyyy;
          vec4 y = y_ *ns.x + ns.yyyy;
          vec4 h = 1.0 - abs(x) - abs(y);

          vec4 b0 = vec4( x.xy, y.xy );
          vec4 b1 = vec4( x.zw, y.zw );

          //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
          //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
          vec4 s0 = floor(b0)*2.0 + 1.0;
          vec4 s1 = floor(b1)*2.0 + 1.0;
          vec4 sh = -step(h, vec4(0.0));

          vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
          vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;

          vec3 p0 = vec3(a0.xy,h.x);
          vec3 p1 = vec3(a0.zw,h.y);
          vec3 p2 = vec3(a1.xy,h.z);
          vec3 p3 = vec3(a1.zw,h.w);

        //Normalise gradients
          vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
          p0 *= norm.x;
          p1 *= norm.y;
          p2 *= norm.z;
          p3 *= norm.w;

        // Mix final noise value
          vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
          m = m * m;
          return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
                                        dot(p2,x2), dot(p3,x3) ) );
          }

        vec3 snoiseVec3( vec3 x ){

          float s  = snoise(vec3( x ));
          float s1 = snoise(vec3( x.y - 19.1 , x.z + 33.4 , x.x + 47.2 ));
          float s2 = snoise(vec3( x.z + 74.2 , x.x - 124.5 , x.y + 99.4 ));
          vec3 c = vec3( s , s1 , s2 );
          return c;

        }


        vec3 curlNoise( vec3 p ){

          const float e = .1;
          vec3 dx = vec3( e   , 0.0 , 0.0 );
          vec3 dy = vec3( 0.0 , e   , 0.0 );
          vec3 dz = vec3( 0.0 , 0.0 , e   );

          vec3 p_x0 = snoiseVec3( p - dx );
          vec3 p_x1 = snoiseVec3( p + dx );
          vec3 p_y0 = snoiseVec3( p - dy );
          vec3 p_y1 = snoiseVec3( p + dy );
          vec3 p_z0 = snoiseVec3( p - dz );
          vec3 p_z1 = snoiseVec3( p + dz );

          float x = p_y1.z - p_y0.z - p_z1.y + p_z0.y;
          float y = p_z1.x - p_z0.x - p_x1.z + p_x0.z;
          float z = p_x1.y - p_x0.y - p_y1.x + p_y0.x;

          const float divisor = 1.0 / ( 2.0 * e );
          return normalize( vec3( x , y , z ) * divisor );

        }


        void main() {
            vec2 uv = gl_FragCoord.xy / resolution.xy;
            float idParticle = uv.y * resolution.x + uv.x;
            vec4 tmpVel = texture2D( textureVelocity, uv );
            vec4 tmpPos = texture2D( texturePosition, uv );

            vec3 vel = curlNoise(tmpPos.xyz*0.04);
            tmpVel.w -= 0.8;
        //    vel.z *= 2.0;
        //    vec3 vel = tmpVel.xyz;
        //    vel.x *= 2.0;
        //    vel. *= 2.0;
        //    vel.x = abs(vel.x);
        //    vel.z = abs(vel.z);

            if(tmpVel.w < -1.0)
            {
                tmpVel.w = 100.;
            }

            gl_FragColor = vec4( vel.xyz, tmpVel.w );
        }

    </script>
    <script id="Mosaic_ComputePosition" type="x-shader/x-vertex">
        #define delta 0.08
        void main() {
            vec2 uv = gl_FragCoord.xy / resolution.xy;
            vec4 tmpPos = texture2D( texturePosition, uv );
            vec3 pos = tmpPos.xyz;
            vec4 tmpVel = texture2D( textureVelocity, uv );
            vec4 tmpOrgPos = texture2D( textureOriginal, uv );
            vec3 vel = tmpVel.xyz;
            pos += vel * delta;
        //    if(tmpVel.w == 100.)
            if(distance(pos,tmpOrgPos.xyz) > 20.)
            {
                pos = tmpOrgPos.xyz;
            }
            gl_FragColor = vec4( pos, 1.0 );
        }

    </script>
    <script id="Mosaic_ComputeOriginal" type="x-shader/x-vertex">
        uniform sampler2D pre_texturePosition;


        void main() {
            vec2 uv = gl_FragCoord.xy / resolution.xy;

            vec4 q = texture2D( textureOriginal, uv );

            gl_FragColor = q;
        }

    </script>
    <script id="Mosaic_ComputeShadow" type="x-shader/x-vertex">

        precision highp float;
        const float PackUpscale = 256. / 255.;
        const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );
        const float ShiftRight8 = 1. / 256.;

        vec4 packDepthToRGBA( const in float v ) {
          vec4 r = vec4( fract( v * PackFactors ), v );
          r.yzw -= r.xyz * ShiftRight8; // tidy overflow
          return r * PackUpscale;
        }

        void main() {

          gl_FragColor = packDepthToRGBA( gl_FragCoord.z );

        }

    </script>
    <script id="vertex" type="x-shader/x-vertex">
        precision highp float;

        attribute vec3 offset;

        attribute vec2 pos_uv;
        attribute vec4 orientation;
        varying vec2 vUv;
        varying vec2 vTuv;
        uniform sampler2D map;
        uniform mat4 shadowMatrix;
        varying vec4 vShadowCoord;
        uniform sampler2D shadowMap;
        uniform vec2 shadowMapSize;
        uniform float shadowBias;
        uniform float shadowRadius;


        uniform float time;
        uniform sampler2D texturePosition;
        uniform sampler2D textureVelocity;
        uniform sampler2D textureOriginal;
        varying vec4 vPosition;
        varying vec3 vColor;
        varying vec3 vNormal;
        uniform mat4 uMatrix;
        varying mat4 vModelMatrix;

        uniform float imgWidth;
        uniform float imgHeight;



        mat3 calcLookAtMatrix(vec3 vector, float roll) {
          vec3 rr = vec3(sin(roll), cos(roll), 0.0);
          vec3 ww = normalize(vector);
          vec3 uu = normalize(cross(ww, rr));
          vec3 vv = normalize(cross(uu, ww));

          return mat3(uu, ww, vv);
        }

        const float DEG_TO_RAD = 3.141592653589793 / 180.0;
        mat2 rotationMatrix( float a ) {
          return mat2( cos( a ), sin( a ),
                  -sin( a ), cos( a ) );
        }

        const float PI = 3.141592653589793;
        uniform float near;
        uniform float far;
        uniform vec3 cameraPos;
        float fogStart = 0.1;
        float fogEnd = 30.0;
        varying float fogFactor;
        uniform float isStart;

          mat2 calcRotate2D(float _time){
            float _sin = sin(_time);
            float _cos = cos(_time);
            return mat2(_cos, _sin, -_sin, _cos);
          }



        void main() {
            vPosition = vec4(position.xyz,1.);
            vec4 posTemp = texture2D( texturePosition, pos_uv );
            vec4 velTemp = texture2D( textureVelocity, pos_uv );
            vec4 orgTemp = texture2D( textureOriginal, pos_uv );

        //    float scale = 1.0 - velTemp.w/100.0;

            float scale = 1.0 - distance(posTemp.xyz,orgTemp.xyz)/20.;
            scale = sin(scale*PI)*1.0;
        //    scale = mix(sin(scale*PI)*1.2,1.0,isStart);

        //    scale= 1.0;

            vTuv = pos_uv;

            mat4 localRotationMat = mat4( calcLookAtMatrix( velTemp.xyz, 0.0 ) );


            vec2 tUv =vec2( posTemp.x/imgWidth+0.5,posTemp.y/imgHeight+0.5);

            vColor = texture2D( map, tUv ).xyz;







            vec3 modifiedVertex =  (localRotationMat * vec4( position*vec3(0.1,1.3,0.1)*scale,1.0 )).xyz;
            vec3 modifiedPosition = modifiedVertex + posTemp.xyz;

            modifiedPosition.yz = calcRotate2D(time) * modifiedPosition.yz;
            modifiedPosition.xz = calcRotate2D(time) * modifiedPosition.xz;

            float linerDepth = 1.0 / (30.0 - 0.01);
            float linerPos = length(cameraPos - modifiedPosition.xyz) * linerDepth;
            fogFactor      = clamp((fogEnd - linerPos) / (fogEnd - fogStart), 0.0, 1.0);

            vPosition =  vec4( modifiedPosition, 1.0 );
            vShadowCoord = shadowMatrix * modelMatrix * vec4( vPosition.xyz, 1. );

            gl_Position = projectionMatrix * modelViewMatrix * vec4( modifiedPosition, 1.0 );

        }

    </script>

    <script id="fragment" type="x-shader/x-vertex">
        precision highp float;
        uniform sampler2D map;
        varying vec2 vUv;
        varying vec3 vColor;

        varying vec4 vShadowCoord;
        uniform sampler2D shadowMap;
        uniform vec2 shadowMapSize;
        uniform float shadowBias;
        uniform float shadowRadius;
        uniform float bias;

        const float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)
        const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );
        const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );

        float unpackRGBAToDepth( const in vec4 v ) {
          return dot( v, UnpackFactors );
        }

        float texture2DCompare( sampler2D depths, vec2 uv, float compare ) {
          return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );
        }

        float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {

          float shadow = 1.0;

          shadowCoord.xyz /= shadowCoord.w;
          shadowCoord.z += shadowBias;

          // if ( something && something ) breaks ATI OpenGL shader compiler
          // if ( all( something, something ) ) using this instead

          bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
          bool inFrustum = all( inFrustumVec );

          bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );
          bool frustumTest = all( frustumTestVec );

          if ( frustumTest ) {

            vec2 texelSize = vec2( 1.0 ) / shadowMapSize;

            float dx0 = - texelSize.x * shadowRadius;
            float dy0 = - texelSize.y * shadowRadius;
            float dx1 = + texelSize.x * shadowRadius;
            float dy1 = + texelSize.y * shadowRadius;

            shadow = (
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +
              texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )
            ) * ( 1.0 / 9.0 );
          }

          return shadow;
        }
      
      
         vec3 rgb2hsv(vec3 c)
        {
            vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
            vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
            vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

            float d = q.x - min(q.w, q.y);
            float e = 1.0e-10;
            return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
        }
        vec3 hsv2rgb(vec3 c)
        {
            vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
            vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
            return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
        }

        varying vec4 vPosition;
        uniform sampler2D textureVelocity;
        uniform sampler2D texturePosition;
        varying vec2 vTuv;
        varying mat4 vModelMatrix;
        varying vec3 vNormal;
        uniform mat4 uMatrix;
        uniform float near;
        uniform float far;
        uniform vec3 cameraPos;
        float fogStart = 0.1;
        float fogEnd = 10.0;
        varying float fogFactor;

        vec3 calcIrradiance_dir(vec3 newNormal, vec3 lightPos, vec3 light){
            float dotNL = dot(newNormal, normalize(lightPos));

            return light * max(0.0, dotNL);
          }

        vec3 calcIrradiance_hemi(vec3 newNormal, vec3 lightPos, vec3 grd, vec3 sky){
            float dotNL = dot(newNormal, normalize(lightPos));
            float hemiDiffuseWeight = 0.5 * dotNL + 0.5;

            return mix(grd, sky, hemiDiffuseWeight);
          }

        const vec3 hemiLight_g = vec3(0.86,0.86,0.86);

        // hemisphere sky color
        const vec3 hemiLight_s_1 = vec3(0.5882352941176471,0.8274509803921568,0.8823529411764706);
        const vec3 hemiLight_s_2 = vec3(0.9686274509803922,0.8509803921568627,0.6666666666666666);
        const vec3 hemiLight_s_3 = vec3(0.8784313725490196,0.5882352941176471,0.7647058823529411);

        const vec3 hemiLightPos_1 = vec3(100.0, 100.0, -100.0);
          const vec3 hemiLightPos_2 = vec3(-100.0, -100.0, 100.0);
          const vec3 hemiLightPos_3 = vec3(-100.0, 100.0, 100.0);
        //uniform sampler2D map;
        void main() {
            vec4 velTemp = texture2D( textureVelocity, vUv );
            vec4 posTemp = texture2D( texturePosition, vTuv );
            vec3 _normal = normalize(cross(dFdx(vPosition.xyz), dFdy(vPosition.xyz)));


            vec3 hemiColor = vec3(0.0);
            hemiColor += calcIrradiance_hemi(_normal, hemiLightPos_1, hemiLight_g, hemiLight_s_1) * 0.38;
            hemiColor += calcIrradiance_hemi(_normal, hemiLightPos_2, hemiLight_g, hemiLight_s_2) * 0.26;
            hemiColor += calcIrradiance_hemi(_normal, hemiLightPos_3, hemiLight_g, hemiLight_s_3) * 0.36;
            vec3 dirColor = vec3(0.0);
            dirColor += calcIrradiance_dir(_normal, vec3(0.,0.,1.), vec3(1.));
            float shadow = 1.0;
            shadow *= getShadow(shadowMap, shadowMapSize, bias, shadowRadius, vShadowCoord);



            dirColor.x = max(dirColor.x,0.8);
            dirColor.y = max(dirColor.y,0.8);
            dirColor.z = max(dirColor.z,0.8);

            vec3 color = vColor.xyz*dirColor;
            color = mix(vec3(0.,0.,0.),color,fogFactor);
          
            vec3 hsv = rgb2hsv(color);
            hsv.z *= 1.3;
            color = hsv2rgb(hsv);
            gl_FragColor = vec4(color,1.0);
        }
    </script>

<div id="container"></div>
   
<div id="info">
    <span>
      <h1>Impressionists Blobs -The Starry Night-</h1>
    </span>
    <br>
    <span>
      <a href="https://twitter.com/murasaki_0606" target="_blank">@murasaki_0606</a>
    </span>
    <br>
    <span>
      <p>click: Start / Restart</p>
        <br>
      <p>key"H": Hide info</p>
    </span>

</div>
a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}html{height:100%}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:"";content:none}table{border-collapse:collapse;border-spacing:0}body{margin:0;font-family:Monospace;font-size:13px;text-align:center}
#container,body{
    position:relative;width:100%;height:100%;overflow:hidden
}
#container{
    background:radial-gradient(ellipse at center,#7e2f9c 1%,#191325 100%)
}
#stats{display:none}canvas{position:fixed;left:0;top:0}
#info {
    width:100%;height:100%;
    top: 40px;
    left: 40px;
    position: fixed;
    z-index: 999;
    text-align: left;
    color: #fff;
    font-family: 'Khula', sans-serif;
}

h1 {
    font-size: 22px;

    display: inline-block;
    margin: 0;
    margin-bottom: 10px;
    padding: 8px;
    padding-top: 12px;
 
    background: linear-gradient(135deg, rgba(37,219,237,0.8) 0%,rgba(183,60,210,0.8) 100%);
}
a {
    color: #fff;
    margin: 0;
    font-size: 14px;
    display: inline-block;
    padding: 6px;
    padding-top: 8px;
    margin-bottom: 20px;
    background: linear-gradient(135deg, rgba(37,219,237,0.8) 0%,rgba(183,60,210,0.8) 100%);
}

p {
    color: #fff;
    margin: 0;
    font-size: 16px;
    display: inline-block;
    margin-bottom: 14px;
    /*padding: 8px;*/
    /*padding-top: 12px;*/
    /*background: linear-gradient(135deg, rgba(37,219,237,0.8) 0%,rgba(143,60,210,0.8) 100%);*/
}
/*# sourceMappingURL=main.css.map*/
// via curl noise https://codepen.io/mnmxmx/pen/rzqoeW
// via polygon-shader https://github.com/spite/polygon-shredder
var container, stats;
var camera, scene, renderer;
var mesh;

var geometry;
// var material:THREE.MeshBasicMaterial;
var cube;
var offsetAttribute;
var orientationAttribute;
var lastTime = 0;
var mesh;
var uniforms;

var WIDTH = 128;
var PARTICLES = WIDTH * WIDTH;


var gpuCompute;
var velocityVariable;
var positionVariable;
var quaternionVariable;
var quaternionUniforms;

var material;
var shadowMaterial;
var light;
var shadowCamera;

var imgWidth = 75;
var imgHeight = 50;
var rotateVec = new THREE.Vector3(0,0,0);
var isRotate = false;
var timer = 0.0;
var cameraStartZ = 100;
var startTimer = 0.8;
var enableInfo = true;
var texture;
texture = new THREE.TextureLoader().load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/311372/gogh_small.jpg',function (){
  init();
});
                                         
           


function init() {
    container = document.getElementById( 'container' );
    //
    camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.z = cameraStartZ;
    scene = new THREE.Scene();
   
    renderer = new THREE.WebGLRenderer({antialias: true, alpha:true});
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.gammaInput = true;
    renderer.gammaOutput = true;
    container.appendChild( renderer.domElement );
    renderer.setClearColor(0xebe8ed,0);


    light = new THREE.DirectionalLight( 0xFFAA55,0.5 );
    light.position.set(0, 1, 1);
    light.castShadow = true;
    shadowCamera = light.shadow.camera;
    shadowCamera.lookAt( scene.position );

    light.shadow.matrix.set(
        0.5, 0.0, 0.0, 0.5,
        0.0, 0.5, 0.0, 0.5,
        0.0, 0.0, 0.5, 0.5,
        0.0, 0.0, 0.0, 1.0
    );

    light.shadow.matrix.multiply( shadowCamera.projectionMatrix );
    light.shadow.matrix.multiply( shadowCamera.matrixWorldInverse );

    if(light.shadow.map === null){
        light.shadow.mapSize.x = 2048;
        light.shadow.mapSize.y = 2048;

        var pars = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat };

        light.shadow.map = new THREE.WebGLRenderTarget( light.shadow.mapSize.x,light.shadow.mapSize.y, pars );
        // light.shadow.map.texture.name = light.name + ".shadowMap";
    }

    initComputeRenderer();



    var instances = PARTICLES;
    var bufferGeometry = new THREE.BoxBufferGeometry( 2, 1, 1 );
    // copying data from a simple box geometry, but you can specify a custom geometry if you want
    geometry = new THREE.InstancedBufferGeometry();
    geometry.index = bufferGeometry.index;
    geometry.attributes.position = bufferGeometry.attributes.position;
    geometry.attributes.uv = bufferGeometry.attributes.uv;
    geometry.attributes.normal = bufferGeometry.attributes.normal;

    var offsets = [];
    // var pos_uv = [];
    var orientations = [];
    var vector = new THREE.Vector4();
    var x, y, z, w;

    var uvs = new Float32Array( PARTICLES * 2 );
    var xywidth = new Float64Array( 3 );
    xywidth[2] = WIDTH;
    var p = 0;
    for ( var j = 1; j < WIDTH; j++ ) {
        for ( var i = 1; i < WIDTH; i++ ) {
            xywidth[0] = i;
            xywidth[1] = j;
            uvs[ p++ ] = xywidth[0] / ( xywidth[2] )-(1.0/xywidth[2]);
            uvs[ p++ ] = xywidth[1] / ( xywidth[2] )-(1.0/xywidth[2]);
        }
    }


    for ( var i = 0; i < instances; i ++ ) {
        // offsets
        x = Math.random() * 50 - 25;
        y = Math.random() * 50 - 25;
        z = Math.random() *0;

        vector.set( x, y, z, 0 ).normalize();
        vector.multiplyScalar( 5 ); // move out at least 5 units from center in current direction
        offsets.push( x + vector.x, y + vector.y, z + vector.z,i );

        x = Math.random() * 2 - 1;
        y = Math.random() * 2 - 1;
        z = Math.random() * 2 - 1;
        w = Math.random() * 2 - 1;
        vector.set( x, y, z, w ).normalize();
        orientations.push( vector.x, vector.y, vector.z, vector.w );
    }
    offsetAttribute = new THREE.InstancedBufferAttribute( new Float32Array( offsets ), 4 );

    orientationAttribute = new THREE.InstancedBufferAttribute( new Float32Array( orientations ), 4 ).setDynamic( true );


    

    texture.wrapS = THREE.ClampToEdgeWrapping;
    texture.wrapT = THREE.ClampToEdgeWrapping;


    var pos_uvsAttribute = new THREE.InstancedBufferAttribute( uvs, 2 );
    geometry.addAttribute( 'offset', offsetAttribute );
    geometry.addAttribute( 'orientation', orientationAttribute );
    geometry.addAttribute( 'pos_uv', pos_uvsAttribute );
    // material

    uniforms = {
        map: { value: texture},
        // monalisa:{value:texture},
        time:{value:0.0},
        texturePosition:{value:null},
        textureVelocity:{value:null},
        // pre_texturePosition:{value:null},
        // pre_textureVelocity:{value:null}
        textureOriginal:{value:null},
        shadowMap: { type: 't', value: light.shadow.map },
        shadowMapSize: {type: "v2", value: light.shadow.mapSize},
        shadowBias: {type: "f", value: light.shadow.bias},
        shadowRadius: {type: "f", value: light.shadow.radius},
        uMatrix:{value:null},
        imgWidth:{value:imgWidth},
        imgHeight:{value:imgHeight},
        near:{value:camera.near},
        far:{value:camera.far},
        cameraPos:{value:camera.position},
        sceneInvMatrix:{value:null},
        isStart:{value:startTimer}
    };
    material = new THREE.ShaderMaterial( {
        uniforms: uniforms,
        vertexShader: document.getElementById( 'vertex' ).textContent,
        fragmentShader: document.getElementById( 'fragment' ).textContent,
        shading: THREE.FlatShading,
        transparent:true
    } );

    shadowMaterial = new THREE.ShaderMaterial( {
        uniforms: {
            map: { value: texture},
            time:{value:0.0},
            texturePosition:{value:null},
            textureVelocity:{value:null},
            size: { type: "f", value: WIDTH },

            timer: { type: 'f', value: 0 },

            shadowMatrix: { type: 'm4', value: light.shadow.matrix},
            lightPosition: { type: 'v3', value: light.position }
        },
        vertexShader: document.getElementById( 'vertex' ).textContent,
        fragmentShader: document.getElementById( 'Mosaic_ComputeShadow' ).textContent,
    });


    mesh = new THREE.Mesh( geometry, material );
    mesh.frustumCulled = false;
    scene.add( mesh );
    
    window.addEventListener( 'resize', onWindowResize, false );
    window.addEventListener( 'click', click, false);
   animate();
}

function initComputeRenderer()
{

    gpuCompute = new GPUComputationRenderer( WIDTH, WIDTH, renderer );

    // 今回はパーティクルの位置情報と、移動方向を保存するテクスチャを2つ用意します
    var dtPosition = gpuCompute.createTexture();
    var dtVelocity = gpuCompute.createTexture();
    var dtOriginal = gpuCompute.createTexture();

  fillTextures( dtPosition, dtVelocity,dtOriginal );

    velocityVariable = gpuCompute.addVariable( "textureVelocity", document.getElementById( 'Mosaic_ComputeVelocity' ).textContent, dtVelocity );
    positionVariable = gpuCompute.addVariable( "texturePosition", document.getElementById( 'Mosaic_ComputePosition' ).textContent, dtPosition );
    quaternionVariable = gpuCompute.addVariable( "textureOriginal", document.getElementById( 'Mosaic_ComputeOriginal' ).textContent, dtOriginal );

    let variables = [ positionVariable, velocityVariable, quaternionVariable ];
    gpuCompute.setVariableDependencies( velocityVariable, variables );
    gpuCompute.setVariableDependencies( positionVariable, variables );
    gpuCompute.setVariableDependencies( quaternionVariable, variables );


    quaternionUniforms = quaternionVariable.material.uniforms;
    quaternionUniforms.pre_texturePosition = {value:dtPosition};


    var error = gpuCompute.init();
    if ( error !== null ) {
        console.error( error );
    }
}


function fillTextures( texturePosition, textureVelocity, textureQuaternion ) {

    var posArray = texturePosition.image.data;
    var velArray = textureVelocity.image.data;
    var qtArray = textureQuaternion.image.data;

   
    for ( var k = 0, kl = posArray.length; k < kl; k += 4 ) {
        // Position
        var x, y, z;
        x = Math.random()*imgWidth-imgWidth/2;
        y = Math.random()*imgHeight-imgHeight/2;
        z = Math.random()*10-5;
        posArray[ k + 0 ] = x;
        posArray[ k + 1 ] = y;
        posArray[ k + 2 ] = z;
        posArray[ k + 3 ] = 0;

        qtArray[ k + 0 ] = x;
        qtArray[ k + 1 ] = y;
        qtArray[ k + 2 ] = z;
        qtArray[ k + 3 ] = 0;

        velArray[ k + 0 ] = Math.random()*2-1;
        velArray[ k + 1 ] = Math.random()*2-1;
        velArray[ k + 2 ] = Math.random()*2-1;
        velArray[ k + 3 ] = 100*Math.random();
    }
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( window.innerWidth, window.innerHeight );
}

function click()
{
    isRotate = !isRotate;
    startTimer = 3.0;
}

function animate() {
    requestAnimationFrame( animate );
    render();

}
function render() {
    var time = performance.now();

    if(startTimer > 0)
    {
        startTimer -=0.008;
    } else
    {
        uniforms.isStart.value = startTimer;
        isRotate = true;
    }

    if(isRotate)
    {
        timer += 0.003;
        timer = timer%(Math.PI*2);
      
        cameraStartZ += (30.0 - cameraStartZ) * 0.02;
        camera.position.z = cameraStartZ + Math.sin(timer) * 40.0;
    } else
    {
        var speed = 0.045;
        rotateVec.x += (0.0 - rotateVec.x) * speed;
        rotateVec.y += (0.0 - rotateVec.y) * speed;
        rotateVec.z += (0.0 - rotateVec.z) * speed;
        scene.position.z +=(0.0 - scene.position.z) * speed;
        mesh.position.z +=(0.0 - scene.position.z) * speed;
        camera.position.z +=( cameraStartZ  - camera.position.z) * speed;
        cameraStartZ += (70.0 - cameraStartZ) * speed;
        timer +=(0.0 -timer)*speed;
    }

    scene.rotation.setFromVector3(rotateVec);
    quaternionUniforms.pre_texturePosition = gpuCompute.getCurrentRenderTarget( positionVariable ).texture;

    // uniforms.pre_texturePosition.value = gpuCompute.getCurrentRenderTarget( positionVariable ).texture;
    // uniforms.pre_textureVelocity.value = gpuCompute.getCurrentRenderTarget( velocityVariable ).texture;

    gpuCompute.compute();

    uniforms.textureOriginal.value = gpuCompute.getCurrentRenderTarget( quaternionVariable ).texture;
    uniforms.texturePosition.value = gpuCompute.getCurrentRenderTarget( positionVariable ).texture;
    uniforms.textureVelocity.value = gpuCompute.getCurrentRenderTarget( velocityVariable ).texture;

    shadowMaterial.uniforms.texturePosition.value = gpuCompute.getCurrentRenderTarget( positionVariable ).texture;
    shadowMaterial.uniforms.textureVelocity.value = gpuCompute.getCurrentRenderTarget( velocityVariable ).texture;



    uniforms.time.value = timer;
    shadowMaterial.uniforms.time.value = timer;
    lastTime = timer;


    // mesh.material = shadowMaterial;
    // renderer.render( scene, shadowCamera, light.shadow.map);



    mesh.material = material;
    material.uniforms.shadowMap.value = light.shadow.map;
    let m = new THREE.Matrix4();
    material.uniforms.uMatrix.value = m.getInverse(mesh.matrix);
    renderer.render( scene, camera );
}

document.onkeydown = function (e){
    if(!e) e = window.event; 

    

    if(e.key === "h")
    {
        console.log($);
        console.log($("#info"));
        if(enableInfo)
        {
            $("#info").fadeOut("0.3");
            enableInfo = false;
        }else
        {
            $("#info").fadeIn("0.3");
            enableInfo = true;
        }
    }
};

External CSS

  1. https://fonts.googleapis.com/css?family=Khula:300|Open+Sans

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js
  3. https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/GPUComputationRenderer.js