There's a great experiment made by Jaume Sanchez (https://experiments.withgoogle.com/the-polygon-shredder, https://github.com/spite/polygon-shredder).
If you set scaleX = scale Y = scale Z = 1.0, you would see that each particle becomes a box. Pretty sure that it's a three square polygons looking at you.
Pretty sure that all magic is in just one vertex shader:
<script id="vs-particles" type="x-shader/x-vertex">
precision highp float;
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform vec3 cameraPosition;
uniform sampler2D map;
uniform sampler2D prevMap;
uniform vec3 boxVertices[ 36 ];
uniform vec3 boxNormals[ 3 ];
uniform float width;
uniform float height;
uniform float timer;
uniform vec3 boxScale;
uniform float meshScale;
varying vec3 vPosition;
varying vec4 vColor;
varying vec4 vShadowCoord;
uniform mat4 shadowV;
uniform mat4 shadowP;
uniform vec3 lightPosition;
varying vec3 vLightPosition;
uniform sampler2D diffuse;
const mat4 biasMatrix = mat4(
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
);
mat4 rotationMatrix(vec3 axis, float angle) {
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0,
0.0, 0.0, 0.0, 1.0);
}
float ramp( float x ) {
return 1. - 1. - pow( 1. - x, 4. );
}
float parabola( float x, float k ) {
return pow( 4. * x * ( 1. - x ), k );
}
float random(vec4 seed4){
//return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
return fract(sin(dot_product) * 43758.5453);
}
mat3 calcLookAtMatrix(vec3 origin, vec3 target, float roll) {
vec3 rr = vec3(sin(roll), cos(roll), 0.0);
vec3 ww = normalize(target - origin);
vec3 uu = normalize(cross(ww, rr));
vec3 vv = normalize(cross(uu, ww));
return mat3(uu, vv, ww);
}
void main() {
vec2 dimensions = vec2( width, height );
float px = position.y;
float vi = position.z;
float x = mod( px, dimensions.x );
float y = mod( floor( px / dimensions.x ), dimensions.y );
vec2 uv = vec2( x, y ) / dimensions;
vec4 cubePosition = texture2D( map, uv );
vec4 prevPosition = texture2D( prevMap, uv );
float alpha = cubePosition.a / 100.;
float scale = .025 * parabola( 1. - alpha, 1. );
vec3 faceNormal = boxNormals[ int( vi / 6. ) ];
mat4 localRotation = mat4( calcLookAtMatrix( cubePosition.xyz, prevPosition.xyz, 0. ) );
vec4 rotatedNormal = localRotation * vec4( faceNormal, 1. );
vec3 visPosition = ( modelMatrix * ( cubePosition + rotatedNormal * scale ) ).xyz;
float d = dot( normalize( visPosition - cameraPosition ), normalize( ( modelMatrix * rotatedNormal ).xyz ) );
vec3 boxVertex = boxVertices[ int( vi + ( 1. - step( 0., d ) ) * 18. ) ];
vec3 modifiedVertex = ( ( localRotation * vec4( boxVertex * scale * boxScale * meshScale, 1. ) ).xyz );
vec3 modifiedPosition = cubePosition.xyz + modifiedVertex;
gl_Position = projectionMatrix * modelViewMatrix * vec4( modifiedPosition, 1.0 );
vPosition = modifiedPosition;
vShadowCoord = biasMatrix * shadowP * shadowV * modelMatrix * vec4( modifiedPosition, 1. );
vColor = texture2D( diffuse, uv );
vLightPosition = lightPosition;
}
</script>
I'm trying to downshift this vertex shader, so you would have just one sprite looking at you.
https://bl.ocks.org/vkuchinov/0942e561a993ce91d789299b44adfee0
Pretty sure that it's something with boxVertices and boxNormals uniforms, I need somehow to do away from them. As well, I don't understand why there are so many positions attributes, multipled by 18:
var positionsLength = curlNoiseModel.width * curlNoiseModel.height * 3 * 18;
var positions = new Float32Array( positionsLength );
var p = 0;
for( var j = 0; j < positionsLength; j += 3 ) {
positions[ j ] = p
positions[ j + 1 ] = Math.floor( p / 18 )
positions[ j + 2 ] = p % 18
p++;
}
Does anyone has any idea how to downshift shaders?
var T=THREE;var config={camera:new T.Vector3(0,0,-5),background:"#1D3557",colors:["#457B9D","#A8DADC","#F1FAEE","#E63946"]};var scale=0,nScale=1;var params={type:2,spread:4,factor:0.5,evolution:0.5,rotation:0.5,radius:2,pulsate:false,scaleX:1,scaleY:1,scaleZ:1,scale:1};var t=new T.Clock();var m=new T.Matrix4();var v=new T.Vector3();var nOffset=new T.Vector3(0,0,0);var tmpVector=new T.Vector3();var isMobile=false;var current="intro",rndr,scene,camera,controls,CNM,particles,particleGLSL,shadowParticleGLSL,sCamera,sBuffer,sBufferSize=512;var diffuseData,diffuseTexture,lt,en;function CurlNoise(e,c,g){this.width=c;this.height=g;this.rndr=e;this.targetPos=0;this.data=new Float32Array(this.width*this.height*4);var a=1;for(var f=0,d=this.width*this.height;f<d;f++){var h=Math.random()*2*Math.PI;var k=Math.random()*2-1;var b=Math.acos(k);a=0.85+0.15*Math.random();this.data[f*4]=a*Math.sin(b)*Math.cos(h);this.data[f*4+1]=a*Math.sin(b)*Math.sin(h);this.data[f*4+2]=a*Math.cos(b);this.data[f*4+3]=Math.random()*100}var j=isMobile?T.HalfFloatType:T.FloatType;this.texture=new T.DataTexture(this.data,this.width,this.height,T.RGBAFormat,T.FloatType);this.texture.minFilter=T.NearestFilter;this.texture.magFilter=T.NearestFilter;this.texture.needsUpdate=true;this.rtTexturePos=new T.WebGLRenderTarget(this.width,this.height,{wrapS:T.ClampToEdgeWrapping,wrapT:T.ClampToEdgeWrapping,minFilter:T.NearestFilter,magFilter:T.NearestFilter,format:T.RGBAFormat,type:j,stencilBuffer:false,depthBuffer:false,generateMipmaps:false});this.targets=[this.rtTexturePos,this.rtTexturePos.clone()];this.simulationShader=new T.ShaderMaterial({uniforms:{active:{type:"f",value:1},width:{type:"f",value:this.width},height:{type:"f",value:this.height},oPositions:{type:"t",value:this.texture},tPositions:{type:"t",value:null},timer:{type:"f",value:0},delta:{type:"f",value:0},speed:{type:"f",value:0.5},reset:{type:"f",value:0},offset:{type:"v3",value:new T.Vector3(0,0,0)},genScale:{type:"f",value:1},factor:{type:"f",value:0.5},evolution:{type:"f",value:0.5},inverseModelViewMatrix:{type:"m4",value:new T.Matrix4()},radius:{type:"f",value:2}},vertexShader:document.getElementById("texture_vertex_simulation_shader").textContent,fragmentShader:document.getElementById("texture_fragment_simulation_shader").textContent,side:T.DoubleSide});this.simulationShader.uniforms.tPositions.value=this.texture;this.rtScene=new T.Scene();this.rtCamera=new T.OrthographicCamera(-this.width/2,this.width/2,-this.height/2,this.height/2,-500,1000);this.rtQuad=new T.Mesh(new T.PlaneBufferGeometry(this.width,this.height),this.simulationShader);this.rtScene.add(this.rtQuad);this.rndr.setRenderTarget(this.rtTexturePos);this.rndr.render(this.rtScene,this.rtCamera);this.rndr.setRenderTarget(null);this.plane=new T.Mesh(new T.PlaneGeometry(64,64),new T.MeshBasicMaterial({map:this.rtTexturePos.texture,side:T.DoubleSide}))}CurlNoise.prototype.render=function(b,a){this.simulationShader.uniforms.timer.value=b;this.simulationShader.uniforms.delta.value=a;this.simulationShader.uniforms.tPositions.value=this.targets[this.targetPos].texture;this.targetPos=1-this.targetPos;this.rndr.setRenderTarget(this.targets[this.targetPos]);this.rndr.render(this.rtScene,this.rtCamera);this.rndr.setRenderTarget(null)};inits();function inits(){rndr=new T.WebGLRenderer({antialias:true});rndr.setPixelRatio(window.devicePixelRatio);rndr.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(rndr.domElement);scene=new T.Scene();scene.background=new T.Color(config.background);camera=new T.PerspectiveCamera(35,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(config.camera.x,config.camera.y,config.camera.z);controls=new T.OrbitControls(camera,rndr.domElement);controls.enabled=false;var e=15;sCamera=new T.OrthographicCamera(-e,e,e,-e,0.1,20);sCamera.position.set(10,4,10);sCamera.lookAt(scene.position);sBuffer=new T.WebGLRenderTarget(sBufferSize,sBufferSize,{wrapS:T.ClampToEdgeWrapping,wrapT:T.ClampToEdgeWrapping,minFilter:isMobile.any?T.NearestFilter:T.LinearMipMapLinear,magFilter:isMobile.any?T.NearestFilter:T.LinearFilter,format:T.RGBAFormat});var f=new T.AmbientLight(16777215);scene.add(f);lt=new T.Mesh(new T.CylinderGeometry(5,6,1,36),new T.MeshBasicMaterial({color:16777215}));lt.position.copy(sCamera.position);lt.lookAt(scene.position);lt.rotation.y+=Math.PI/2;lt.rotation.z+=Math.PI/2;en=new T.Mesh(new T.CylinderGeometry(5.1,6.1,0.9,36),new T.MeshBasicMaterial({color:1052688}));en.position.copy(sCamera.position);en.lookAt(scene.position);en.rotation.y+=Math.PI/2;en.rotation.z+=Math.PI/2;CNM=new CurlNoise(rndr,128,128);var h=new T.BufferGeometry();var d=CNM.width*CNM.height*3*18;var a=new Float32Array(d);var g=0;for(var b=0;b<d;b+=3){a[b]=g;a[b+1]=Math.floor(g/18);a[b+2]=g%18;g++}h.addAttribute("position",new T.BufferAttribute(a,3));diffuseData=new Uint8Array(CNM.width*CNM.height*4);for(var b=0;b<CNM.width*CNM.height*4;b+=4){var i=new T.Color(interpolateColors(b/4,CNM.width*CNM.height));diffuseData[b+0]=i.r*255;diffuseData[b+1]=i.g*255;diffuseData[b+2]=i.b*255}diffuseTexture=new T.DataTexture(diffuseData,CNM.width,CNM.height,T.RGBAFormat);diffuseTexture.minFilter=T.NearestFilter;diffuseTexture.magFilter=T.NearestFilter;diffuseTexture.needsUpdate=true;particleGLSL=new T.ShaderMaterial({uniforms:{map:{type:"t",value:CNM.rtTexturePos.texture},prevMap:{type:"t",value:CNM.rtTexturePos.texture},diffuse:{type:"t",value:diffuseTexture},width:{type:"f",value:CNM.width},height:{type:"f",value:CNM.height},dimensions:{type:"v2",value:new T.Vector2(sBufferSize,sBufferSize)},timer:{type:"f",value:0},spread:{type:"f",value:4},boxScale:{type:"v3",value:new T.Vector3()},meshScale:{type:"f",value:1},depthTexture:{type:"t",value:sBuffer.texture},shadowV:{type:"m4",value:new T.Matrix4()},shadowP:{type:"m4",value:new T.Matrix4()},resolution:{type:"v2",value:new T.Vector2(sBufferSize,sBufferSize)},ltPosition:{type:"v3",value:new T.Vector3()},projector:{type:"t",value:null},boxVertices:{type:"3fv",value:[-1,-1,-1,-1,-1,1,-1,1,1,-1,-1,-1,-1,1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,1,-1,1,-1,1,-1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,1,1,1,-1,-1,-1,-1,1,1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,1,1,-1,1,-1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,1,1,1]},boxNormals:{type:"3fv",value:[1,0,0,0,0,1,0,1,0]}},vertexShader:document.getElementById("vs-particles").textContent,fragmentShader:document.getElementById("fs-particles").textContent,side:T.DoubleSide,flatShading:T.FlatShading,transparent:true});shadowParticleGLSL=new T.ShaderMaterial({uniforms:{map:{type:"t",value:CNM.rtTexturePos.texture},prevMap:{type:"t",value:CNM.rtTexturePos.texture},width:{type:"f",value:CNM.width},height:{type:"f",value:CNM.height},timer:{type:"f",value:0},boxScale:{type:"v3",value:new T.Vector3()},meshScale:{type:"f",value:1},shadowV:{type:"m4",value:new T.Matrix4()},shadowP:{type:"m4",value:new T.Matrix4()},resolution:{type:"v2",value:new T.Vector2(sBufferSize,sBufferSize)},ltPosition:{type:"v3",value:new T.Vector3()},boxVertices:{type:"3fv",value:[-1,-1,-1,-1,-1,1,-1,1,1,-1,-1,-1,-1,1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,1,-1,1,-1,1,-1,-1,1,-1,-1,-1,1,-1,1,-1,-1,-1,1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,1,1,1,-1,-1,-1,-1,1,1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,1,1,-1,1,-1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,1,1,1]},boxNormals:{type:"3fv",value:[1,0,0,0,0,1,0,1,0,-1,0,0,0,0,-1,0,-1,0]}},vertexShader:document.getElementById("vs-particles").textContent,fragmentShader:document.getElementById("fs-particles-shadow").textContent,side:T.DoubleSide,transparent:true});particles=new T.Mesh(h,particleGLSL);scene.add(particles);window.addEventListener("resize",onWindowResize,false);animate()}function animate(){controls.update();scale+=(nScale-scale)*0.1;var c=t.getDelta()*10;var b=t.elapsedTime;var a=3;nOffset.set(a*Math.sin(b),a*Math.cos(0.9*b),0);tmpVector.copy(nOffset);tmpVector.sub(CNM.simulationShader.uniforms.offset.value);tmpVector.multiplyScalar(0.1);CNM.simulationShader.uniforms.offset.value.add(tmpVector);CNM.simulationShader.uniforms.factor.value=params.factor;CNM.simulationShader.uniforms.evolution.value=params.evolution;CNM.simulationShader.uniforms.radius.value=params.pulsate?(0.5+0.5*Math.cos(b))*params.radius:params.radius;if(CNM.simulationShader.uniforms.active.value){particles.rotation.y=params.rotation*b}m.copy(particles.matrixWorld);CNM.simulationShader.uniforms.inverseModelViewMatrix.value.getInverse(m);CNM.simulationShader.uniforms.genScale.value=scale;if(CNM.simulationShader.uniforms.active.value===1){CNM.render(b,c)}particleGLSL.uniforms.map.value=shadowParticleGLSL.uniforms.map.value=CNM.targets[CNM.targetPos].texture;particleGLSL.uniforms.prevMap.value=shadowParticleGLSL.uniforms.prevMap.value=CNM.targets[1-CNM.targetPos].texture;particleGLSL.uniforms.spread.value=params.spread;particleGLSL.uniforms.timer.value=shadowParticleGLSL.uniforms.timer.value=b;particleGLSL.uniforms.boxScale.value.set(params.scaleX,params.scaleY,params.scaleZ);shadowParticleGLSL.uniforms.boxScale.value.set(params.scaleX,params.scaleY,params.scaleZ);particleGLSL.uniforms.meshScale.value=params.scale;shadowParticleGLSL.uniforms.meshScale.value=params.scale;rndr.setClearColor(0);particles.material=shadowParticleGLSL;lt.material.visible=false;en.material.visible=false;rndr.setRenderTarget(sBuffer);rndr.render(scene,sCamera);rndr.setRenderTarget(null);lt.material.visible=true;en.material.visible=true;tmpVector.copy(scene.position);tmpVector.sub(sCamera.position);tmpVector.normalize();m.makeRotationY(-particles.rotation.y);v.copy(sCamera.position);v.applyMatrix4(m);particleGLSL.uniforms.shadowP.value.copy(sCamera.projectionMatrix);particleGLSL.uniforms.shadowV.value.copy(sCamera.matrixWorldInverse);particleGLSL.uniforms.ltPosition.value.copy(v);rndr.setClearColor(16777215);particles.material=particleGLSL;rndr.render(scene,camera);requestAnimationFrame(animate);rndr.render(scene,camera)}function onWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();rndr.setSize(window.innerWidth,window.innerHeight)}function interpolateColors(d,b){var a=remapFloat(d,0,b,0,3);var f=Math.floor(a);var e=Math.ceil(a);var c=a-f;return lerpHexColors(config.colors[f],config.colors[e],c)}function lerpHexColors(l,f,g){var i=parseInt(l.replace(/#/g,""),16),b=i>>16,j=i>>8&255,o=i&255,d=parseInt(f.replace(/#/g,""),16),n=d>>16,e=d>>8&255,h=d&255,c=b+g*(n-b),k=j+g*(e-j),a=o+g*(h-o);return"#"+((1<<24)+(c<<16)+(k<<8)+a|0).toString(16).slice(1)}function remapFloat(d,e,b,a,c){return a+(d-e)/(b-e)*(c-a)}function hexToRGB(b){var a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(b);return a?{r:parseInt(a[1],16)/255,g:parseInt(a[2],16)/255,b:parseInt(a[3],16)/255}:null};
body { margin: 0; background-color: dimgrey; }
<!DOCTYPE html>
<html lang="en">
<head>
<title>Particle Clover [PoC] tweaked version of particle-love.com by Edan Kwan</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0">
<script src="https://unpkg.com/[email protected]/build/three.min.js"></script>
<script src="https://unpkg.com/[email protected]/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
</head>
<body>
<script id="texture_vertex_simulation_shader" type="x-shader/x-vertex">
varying vec2 vUv;
varying vec3 vOffset;
uniform vec3 offset;
uniform mat4 inverseModelViewMatrix;
void main() {
vOffset=(inverseModelViewMatrix*vec4(offset,1.)).xyz;
vUv=vec2(uv.x,1.0-uv.y);
gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);
}
</script>
<script id="texture_fragment_simulation_shader" type="x-shader/x-fragment">
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);
vec3 i=floor(v_+dot(v_,C.yyy));
vec3 x0=v_-i+dot(i,C.xxx);
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);
vec3 x1=x0-i1+C.xxx;
vec3 x2=x0-i2+C.yyy;
vec3 x3=x0-D.yyy;
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));
float n_=0.142857142857;
vec3 ns=n_*D.wyz-D.xzx;
vec4 j=p-49.0*floor(p*ns.z*ns.z);
vec4 x_=floor(j*ns.z);
vec4 y_=floor(j-7.0*x_);
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=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);
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;
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);
}
varying vec2 vUv;
varying vec3 vOffset;
uniform float active;
uniform sampler2D tPositions;
uniform sampler2D oPositions;
uniform float width;
uniform float height;
uniform vec3 offset;
uniform float timer;
uniform float delta;
uniform float speed;
uniform float reset;
uniform float genScale;
uniform float factor;
uniform float evolution;
uniform float radius;
mat4 rotationMatrix(vec3 axis_,float angle_) {
axis_=normalize(axis_);
float s=sin(angle_);
float c=cos(angle_);
float oc=1.0-c;
return mat4(oc*axis_.x*axis_.x+c,oc*axis_.x*axis_.y-axis_.z*s,oc*axis_.z*axis_.x+axis_.y*s,0.0,oc*axis_.x*axis_.y+axis_.z*s,oc*axis_.y*axis_.y+c,oc*axis_.y*axis_.z-axis_.x*s,0.0,oc*axis_.z*axis_.x-axis_.y*s, oc*axis_.y*axis_.z+axis_.x*s, oc*axis_.z*axis_.z+c,0.0,0.0,0.0,0.0,1.0);
}
void main() {
vec4 c=texture2D(tPositions,vUv);
vec3 pos=c.xyz;
float life=c.a;
float s=vUv.x*life/100.;
float speedInc=1.;
if(s > .95) speedInc=.75;
else if(s > .9) speedInc=.85;
else speedInc=1.;
vec3 v=factor*speedInc*delta*speed*(curlNoise(.2*pos+factor*evolution*.1*timer));
pos += v;
life -= factor*1.;
if(length(pos) < radius) { pos=normalize(pos)*radius; }
if(life <= 0. || reset == 1.) {
pos=(rotationMatrix(vec3(1.,0.,0.),timer)*texture2D(oPositions,vUv)).xyz+vOffset;
life=100.;
}
gl_FragColor=vec4(pos,life);
}
</script>
<script id="vs-particles" type="x-shader/x-vertex">
precision highp float;
uniform sampler2D map;
uniform sampler2D prevMap;
uniform vec3 boxVertices[ 36 ];
uniform vec3 boxNormals[ 3 ];
uniform float width;
uniform float height;
uniform float timer;
uniform vec3 boxScale;
uniform float meshScale;
varying vec3 vPosition;
varying vec4 vColor;
varying vec4 vShadowCoord;
uniform mat4 shadowV;
uniform mat4 shadowP;
uniform vec3 lightPosition;
varying vec3 vLightPosition;
uniform sampler2D diffuse;
const mat4 biasMatrix=mat4(
.5,.0,.0,0.,
.0,.5,.0,0.,
.0,.0,.5,0.,
.5,.5,.5,1.
);
mat4 rotationMatrix(vec3 axis_,float angle_) {
axis_=normalize(axis_);
float s=sin(angle_);
float c=cos(angle_);
float oc=1.0-c;
return mat4(oc*axis_.x*axis_.x+c,oc*axis_.x*axis_.y-axis_.z*s,oc*axis_.z*axis_.x+axis_.y*s,0.0,oc*axis_.x*axis_.y+axis_.z*s,oc*axis_.y*axis_.y+c,oc*axis_.y*axis_.z-axis_.x*s,0.0,oc*axis_.z*axis_.x-axis_.y*s, oc*axis_.y*axis_.z+axis_.x*s, oc*axis_.z*axis_.z+c,0.0,0.0,0.0,0.0,1.0);
}
float parabola(float x_,float k_) { return pow(4.*x_*(1.-x_),k_); }
mat3 calcLookAtMatrix(vec3 origin_,vec3 target_,float roll_) {
vec3 rr=vec3(sin(roll_),cos(roll_),0.0);
vec3 ww=normalize(target_-origin_);
vec3 uu=normalize(cross(ww,rr));
vec3 vv=normalize(cross(uu,ww));
return mat3(uu,vv,ww);
}
void main() {
vec2 dimensions=vec2(width,height);
float px=position.y;
float vi=position.z;
float x=mod(px,dimensions.x);
float y=mod(floor(px/dimensions.x),dimensions.y);
vec2 uv=vec2(x,y)/dimensions;
vec4 cubePosition=texture2D(map,uv);
vec4 prevPosition=texture2D(prevMap,uv);
float alpha=cubePosition.a/100.;
float scale=.025*parabola(1.-alpha,1.);
vec3 faceNormal=boxNormals[ int(vi/6.) ];
mat4 localRotation=mat4(calcLookAtMatrix(cubePosition.xyz,prevPosition.xyz,0.));
vec4 rotatedNormal=localRotation*vec4(faceNormal,1.);
vec3 visPosition=(modelMatrix*(cubePosition+rotatedNormal*scale)).xyz;
float d=dot(normalize(visPosition-cameraPosition),normalize((modelMatrix*rotatedNormal).xyz));
vec3 boxVertex=boxVertices[ int(vi+(1.-step(0.,d))*50.) ];
vec3 modifiedVertex=vec3((localRotation*vec4(boxVertex*scale*boxScale*meshScale,1.)).xyz);
vec3 modifiedPosition=cubePosition.xyz+modifiedVertex;
gl_Position=projectionMatrix*modelViewMatrix*vec4(modifiedPosition,1.0);
vPosition=modifiedPosition;
vShadowCoord=biasMatrix*shadowP*shadowV*modelMatrix*vec4(modifiedPosition,1.);
vColor=texture2D(diffuse,uv);
vLightPosition=lightPosition;
}
</script>
<script id="fs-particles" type="x-shader/x-fragment">
#extension GL_OES_standard_derivatives : enable
precision highp float;
uniform float spread;
varying vec3 vPosition;
varying vec4 vColor;
varying vec4 vShadowCoord;
uniform sampler2D depthTexture;
uniform sampler2D projector;
varying vec3 vLightPosition;
uniform vec2 resolution;
uniform sampler2D blob;
float bias;
float unpackDepth(const in vec4 rgba_depth_) {
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);
return dot(rgba_depth_,bit_shift);
}
float random(vec4 seed4_){
float dot_product=dot(seed4_,vec4(12.9898,78.233,45.164,94.673));
return fract(sin(dot_product)*43758.5453);
}
float sampleVisibility(vec3 coord_) { return step(coord_.z,unpackDepth(texture2D(depthTexture,coord_.xy+0.*(.5-random(vec4(coord_,bias)))/2048.))+bias); }
mat2 rotationMatrix(float a_) { return mat2(cos(a_),sin(a_),-sin(a_),cos(a_)); }
const float PI=3.14159265358979323846264;
void main() {
vec3 fdx=dFdx(vPosition);
vec3 fdy=dFdy(vPosition);
vec3 n=normalize(cross(fdx,fdy));
vec4 base=vec4(1.);
vec3 L=normalize(vLightPosition-vPosition);
vec3 E=normalize(cameraPosition-vPosition);
float diffuse=max(0.,dot(L,n));
float theta=clamp(-diffuse,0.,1.);
bias=0.005*tan(acos(theta));
bias=clamp(bias,0.,0.01);
float shadow=0.;
vec3 shadowCoord=vShadowCoord.xyz/vShadowCoord.w;
float step=spread;
vec2 inc=vec2(step)/resolution;
shadow += sampleVisibility(shadowCoord+vec3( 0.,-inc.y,0.));
shadow += sampleVisibility(shadowCoord+vec3(-inc.x, 0.,0.));
shadow += sampleVisibility(shadowCoord+vec3( 0., 0.,0.));
shadow += sampleVisibility(shadowCoord+vec3( inc.x, 0.,0.));
shadow += sampleVisibility(shadowCoord+vec3( 0., inc.y,0.));
shadow /= 5.;
vec4 mask=texture2D(projector,vShadowCoord.xy);
float shininess=2.;
vec3 halfVector=normalize(E+L);
float specular=dot(n,halfVector)*.5;
specular=max(0.0,specular);
specular=pow(specular,shininess);
float ambient=1.;
float o=diffuse*shadow*mask.r;
vec3 color=mix(vColor.rgb,vec3(1.),.8*clamp(-n.y,0.,1.));
vec3 diffuseColor=color*mix(vec3(o),vec3(1.),ambient);
vec3 specularColor=vec3(1.);
base.rgb=mix(diffuseColor,specularColor,specular*o);
gl_FragColor=base;
}
</script>
<script id="fs-particles-shadow" type="x-shader/x-fragment">
precision highp float;
vec4 packDepth(const in float depth_) {
const vec4 bit_shift=vec4(256.0*256.0*256.0,256.0*256.0,256.0,1.0);
const vec4 bit_mask =vec4(0.0,1.0/256.0,1.0/256.0,1.0/256.0);
vec4 res=mod(depth_*bit_shift*vec4(255),vec4(256))/vec4(255);
res -= res.xxyz*bit_mask;
return res;
}
void main() {
gl_FragColor=vec4(1.0,0.0,1.0,1.0);
}
</script>
</body>
</html>
I have attached tweaked version here as snippet. Had to compress JS to fit 30.000 limits.