├── .gitignore
├── Screen Shot 2017-12-23 at 12.47.10 PM.png
├── README.md
├── index.html
├── package.json
└── sketch.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.vscode
--------------------------------------------------------------------------------
/Screen Shot 2017-12-23 at 12.47.10 PM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juniorxsound/Particle-Curl-Noise/HEAD/Screen Shot 2017-12-23 at 12.47.10 PM.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Particle-Curl-Noise
2 | A Three.js FBO particle system with curl noise based on [@edankwan](https://github.com/edankwan) example.
3 |
4 | [Live demo](https://juniorxsound.github.io/Particle-Curl-Noise/)
5 | 
6 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Curl test
6 |
7 |
8 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "curl_particale_test",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "sketch.js",
6 | "scripts": {
7 | "start": "http-server",
8 | "watch": "watchify sketch.js -o dist/bundle.js -v"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "babel-preset-es2015": "^6.24.1",
14 | "babelify": "^7.3.0",
15 | "browserify": "^14.4.0",
16 | "three": "^0.86.0",
17 | "watchify": "^3.9.0"
18 | },
19 | "browserify": {
20 | "transform": [
21 | [
22 | "babelify",
23 | {
24 | "presets": [
25 | "es2015"
26 | ]
27 | }
28 | ]
29 | ]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/sketch.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three';
2 |
3 | var gui;
4 | var now = Date.now();
5 |
6 | var width = 0;
7 | var height = 0;
8 |
9 | var TEXTURE_SIZE = 256;
10 | var AMOUNT = TEXTURE_SIZE * TEXTURE_SIZE;
11 |
12 | var camera;
13 | var scene;
14 | var renderer;
15 |
16 | var particles;
17 | var geometry;
18 | var copyShader;
19 | var velocityShader;
20 | var velocity4dShader;
21 | var positionShader;
22 | var velocityRenderTarget;
23 | var positionRenderTarget;
24 | var positionRenderTarget2;
25 | var fboMesh;
26 | var fboScene;
27 | var fboCamera;
28 |
29 | var config = {
30 | color1: '#ffffff',
31 | color2: '#ffcd2d',
32 | speed: 0.3,
33 | use4d: true,
34 | message: 'fire'
35 | };
36 |
37 | function preInit() {
38 |
39 | renderer = new THREE.WebGLRenderer({});
40 |
41 | var gl = renderer.getContext();
42 |
43 | if (!gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)) {
44 | alert('No support for vertex shader textures!');
45 | return;
46 | }
47 | // high precision
48 | if (!gl.getExtension('OES_texture_float')) {
49 | alert('No OES_texture_float support for float textures!');
50 | return;
51 | }
52 |
53 | camera = new THREE.PerspectiveCamera(45, width / height, 1, 3000);
54 | camera.position.z = 1000;
55 | scene = new THREE.Scene();
56 |
57 | document.body.appendChild(renderer.domElement);
58 |
59 | geometry = new THREE.BufferGeometry();
60 | geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(AMOUNT * 3), 3));
61 |
62 | var fboUV = new Float32Array(AMOUNT * 2);
63 | geometry.addAttribute('fboUV', new THREE.BufferAttribute(fboUV, 2));
64 | for (var i = 0; i < AMOUNT; i++) {
65 | fboUV[i * 2] = (i % TEXTURE_SIZE) / TEXTURE_SIZE;
66 | fboUV[i * 2 + 1] = ~~(i / TEXTURE_SIZE) / TEXTURE_SIZE;
67 | }
68 |
69 | var material = new THREE.ShaderMaterial({
70 | uniforms: {
71 | texturePosition: {
72 | type: 't',
73 | value: null
74 | },
75 | color1: {
76 | type: 'c',
77 | value: new THREE.Color(config.color1)
78 | },
79 | color2: {
80 | type: 'c',
81 | value: new THREE.Color(config.color2)
82 | },
83 | opacity: {
84 | type: 'f',
85 | value: 0.25
86 | },
87 | sizeBase: {
88 | type: 'f',
89 | value: 0
90 | },
91 | sizeExtra: {
92 | type: 'f',
93 | value: 9.9
94 | },
95 | hardness: {
96 | type: 'f',
97 | value: 0.16
98 | }
99 | },
100 | vertexShader: "#define GLSLIFY 1\n\n// uniform mat4 modelViewMatrix;\n// uniform mat4 projectionMatrix;\n// attribute vec3 position;\n\nattribute vec2 fboUV;\n\nvarying float vColor;\nvarying float vAlpha;\n\nuniform sampler2D texturePosition;\nuniform float opacity;\nuniform float sizeBase;\nuniform float sizeExtra;\n\nhighp float random_1_0(vec2 co)\n{\n highp float a = 12.9898;\n highp float b = 78.233;\n highp float c = 43758.5453;\n highp float dt= dot(co.xy ,vec2(a,b));\n highp float sn= mod(dt,3.14);\n return fract(sin(sn) * c);\n}\n\n\n\nvoid main() {\n vec3 pos = texture2D( texturePosition, fboUV ).xyz;\n\n float r = (1.0 - cos(smoothstep(500.0, 300.0, pos.x) * 3.141592654)) * 0.5;\n pos.yz *= r;\n\n pos.x = clamp(pos.x, -500.0, 500.0);\n\n vColor = random_1_0(fboUV + vec2(23.0, 31.22));\n\n gl_Position = projectionMatrix * viewMatrix * vec4( pos, 1.0 );\n\n vAlpha = smoothstep(-500.0 + 200.0 * random_1_0(fboUV + 1.0), -200.0, pos.x) * clamp(1000.0 / gl_Position.z, 0.0, 1.0) * opacity;\n\n gl_PointSize = (sizeBase + random_1_0(fboUV) * sizeExtra) * (500.0 / gl_Position.z);\n\n}\n",
101 | fragmentShader: "#define GLSLIFY 1\n\nvarying float vColor;\n\nvarying float vAlpha;\n\nuniform vec3 color1;\nuniform vec3 color2;\nuniform float hardness;\n\nvoid main() {\n\n float d = length(gl_PointCoord.xy - .5) * 2.0;\n\n float c = 1.0 - smoothstep(hardness, 1.0, d);\n // float c = 1.0 - d;\n\n gl_FragColor = vec4(mix(\n color1,\n color2,\n vColor) * c, 1.0) * vAlpha;\n}\n",
102 | blending: THREE.AdditiveBlending,
103 | transparent: true,
104 | depthWrite: true,
105 | depthTest: false
106 | });
107 |
108 | particles = new THREE.Points(geometry, material);
109 | scene.add(particles);
110 |
111 | initFbo();
112 |
113 | gui = new dat.GUI();
114 | gui.addColor(config, 'color1').listen().onChange(onColorChange.bind(material.uniforms.color1.value));
115 | gui.addColor(config, 'color2').listen().onChange(onColorChange.bind(material.uniforms.color2.value));
116 | gui.add(material.uniforms.opacity, 'value', 0, 1).name('opacity').listen();
117 | gui.add(material.uniforms.sizeBase, 'value', 0, 8).name('sizeBase').listen();
118 | gui.add(material.uniforms.sizeExtra, 'value', 0, 48).name('sizeExtra').listen();
119 | gui.add(material.uniforms.hardness, 'value', 0, 1).name('hardness').listen();
120 | gui.add(config, 'speed', 0, 3).listen();
121 | gui.add(config, 'use4d');
122 |
123 | window.addEventListener('resize', onResize);
124 | window.addEventListener('mousedown', () => {
125 | console.log(positionRenderTarget);
126 | console.log(positionRenderTarget2);
127 | // copyTexture(createVelocityTexture(), velocityRenderTarget);
128 | copyTexture(createPositionTexture(), positionRenderTarget);
129 | // copyTexture(positionRenderTarget, positionRenderTarget2);
130 | });
131 | onResize();
132 | loop();
133 | }
134 |
135 | function onColorChange(value) {
136 | this.setHex(value.replace('#', '0x'));
137 | }
138 |
139 | function initFbo() {
140 |
141 | fboScene = new THREE.Scene();
142 | fboCamera = new THREE.Camera();
143 | fboCamera.position.z = 1;
144 |
145 | copyShader = new THREE.ShaderMaterial({
146 | uniforms: {
147 | resolution: {
148 | type: 'v2',
149 | value: new THREE.Vector2(TEXTURE_SIZE, TEXTURE_SIZE)
150 | },
151 | texture: {
152 | type: 't',
153 | value: null
154 | }
155 | },
156 | vertexShader: "#define GLSLIFY 1\n\nvoid main() {\n gl_Position = vec4( position, 1.0 );\n}\n",
157 | fragmentShader: "#define GLSLIFY 1\n\nuniform vec2 resolution;\nuniform sampler2D texture;\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n vec3 color = texture2D( texture, uv ).xyz;\n gl_FragColor = vec4( color, 1.0 );\n}\n"
158 | });
159 |
160 | velocityShader = new THREE.ShaderMaterial({
161 | uniforms: {
162 | time: {
163 | type: 'f',
164 | value: 0.0
165 | },
166 | speed: {
167 | type: 'f',
168 | value: 1.0
169 | },
170 | resolution: {
171 | type: 'v2',
172 | value: new THREE.Vector2(TEXTURE_SIZE, TEXTURE_SIZE)
173 | },
174 | texturePosition: {
175 | type: 't',
176 | value: null
177 | }
178 | },
179 | vertexShader: "#define GLSLIFY 1\n\nvoid main() {\n gl_Position = vec4( position, 1.0 );\n}\n",
180 | fragmentShader: "#define GLSLIFY 1\n\nuniform vec2 resolution;\n\nuniform sampler2D texturePosition;\n\nuniform float speed;\n\n//\n// Description : Array and textureless GLSL 2D/3D/4D simplex\n// noise functions.\n// Author : Ian McEwan, Ashima Arts.\n// Maintainer : ijm\n// Lastmod : 20110822 (ijm)\n// License : Copyright (C) 2011 Ashima Arts. All rights reserved.\n// Distributed under the MIT License. See LICENSE file.\n// https://github.com/ashima/webgl-noise\n//\n\nvec3 mod289_3_0(vec3 x) {\n return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec4 mod289_3_0(vec4 x) {\n return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec4 permute_3_1(vec4 x) {\n return mod289_3_0(((x*34.0)+1.0)*x);\n}\n\nvec4 taylorInvSqrt_3_2(vec4 r)\n{\n return 1.79284291400159 - 0.85373472095314 * r;\n}\n\nfloat snoise_3_3(vec3 v)\n {\n const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;\n const vec4 D_3_4 = vec4(0.0, 0.5, 1.0, 2.0);\n\n// First corner\n vec3 i = floor(v + dot(v, C.yyy) );\n vec3 x0 = v - i + dot(i, C.xxx) ;\n\n// Other corners\n vec3 g_3_5 = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g_3_5;\n vec3 i1 = min( g_3_5.xyz, l.zxy );\n vec3 i2 = max( g_3_5.xyz, l.zxy );\n\n // x0 = x0 - 0.0 + 0.0 * C.xxx;\n // x1 = x0 - i1 + 1.0 * C.xxx;\n // x2 = x0 - i2 + 2.0 * C.xxx;\n // x3 = x0 - 1.0 + 3.0 * C.xxx;\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y\n vec3 x3 = x0 - D_3_4.yyy; // -1.0+3.0*C.x = -0.5 = -D.y\n\n// Permutations\n i = mod289_3_0(i);\n vec4 p = permute_3_1( permute_3_1( permute_3_1(\n i.z + vec4(0.0, i1.z, i2.z, 1.0 ))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));\n\n// Gradients: 7x7 points over a square, mapped onto an octahedron.\n// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)\n float n_ = 0.142857142857; // 1.0/7.0\n vec3 ns = n_ * D_3_4.wyz - D_3_4.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)\n\n vec4 x = x_ *ns.x + ns.yyyy;\n vec4 y = y_ *ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4( x.xy, y.xy );\n vec4 b1 = vec4( x.zw, y.zw );\n\n //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;\n //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;\n vec4 s0 = floor(b0)*2.0 + 1.0;\n vec4 s1 = floor(b1)*2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;\n vec4 a1_3_6 = b1.xzyw + s1.xzyw*sh.zzww ;\n\n vec3 p0_3_7 = vec3(a0.xy,h.x);\n vec3 p1 = vec3(a0.zw,h.y);\n vec3 p2 = vec3(a1_3_6.xy,h.z);\n vec3 p3 = vec3(a1_3_6.zw,h.w);\n\n//Normalise gradients\n vec4 norm = taylorInvSqrt_3_2(vec4(dot(p0_3_7,p0_3_7), dot(p1,p1), dot(p2, p2), dot(p3,p3)));\n p0_3_7 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n// Mix final noise value\n vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 42.0 * dot( m*m, vec4( dot(p0_3_7,x0), dot(p1,x1),\n dot(p2,x2), dot(p3,x3) ) );\n }\n\n\n\n\nvec3 snoiseVec3_1_8( vec3 x ){\n\n float s = snoise_3_3(vec3( x ));\n float s1 = snoise_3_3(vec3( x.y - 19.1 , x.z + 33.4 , x.x + 47.2 ));\n float s2 = snoise_3_3(vec3( x.z + 74.2 , x.x - 124.5 , x.y + 99.4 ));\n vec3 c = vec3( s , s1 , s2 );\n return c;\n\n}\n\n\nvec3 curlNoise_1_9( vec3 p ){\n \n const float e = .1;\n vec3 dx = vec3( e , 0.0 , 0.0 );\n vec3 dy = vec3( 0.0 , e , 0.0 );\n vec3 dz = vec3( 0.0 , 0.0 , e );\n\n vec3 p_x0 = snoiseVec3_1_8( p - dx );\n vec3 p_x1 = snoiseVec3_1_8( p + dx );\n vec3 p_y0 = snoiseVec3_1_8( p - dy );\n vec3 p_y1 = snoiseVec3_1_8( p + dy );\n vec3 p_z0 = snoiseVec3_1_8( p - dz );\n vec3 p_z1 = snoiseVec3_1_8( p + dz );\n\n float x = p_y1.z - p_y0.z - p_z1.y + p_z0.y;\n float y = p_z1.x - p_z0.x - p_x1.z + p_x0.z;\n float z = p_x1.y - p_x0.y - p_y1.x + p_y0.x;\n\n const float divisor = 1.0 / ( 2.0 * e );\n return normalize( vec3( x , y , z ) * divisor );\n\n}\n\n\n\nhighp float random_2_10(vec2 co)\n{\n highp float a = 12.9898;\n highp float b = 78.233;\n highp float c = 43758.5453;\n highp float dt= dot(co.xy ,vec2(a,b));\n highp float sn= mod(dt,3.14);\n return fract(sin(sn) * c);\n}\n\n\n\nvoid main() {\n\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n vec3 position = texture2D( texturePosition, uv ).xyz;\n\n vec3 velocity = curlNoise_1_9(position * 0.02) * 0.1;\n\n float l = pow(smoothstep(500.0, -500.0, position.x), 2.0);\n\n velocity.x += -0.05 + l * - (0.2 + random_2_10(uv) * 0.2);\n\n velocity.x = clamp(velocity.x, -5.0, -0.01);\n\n velocity *= speed;\n\n gl_FragColor = vec4( velocity, 1.0 );\n\n}\n"
181 | });
182 |
183 | velocity4dShader = new THREE.ShaderMaterial({
184 | uniforms: {
185 | time: {
186 | type: 'f',
187 | value: 0.0
188 | },
189 | speed: {
190 | type: 'f',
191 | value: 1.0
192 | },
193 | resolution: {
194 | type: 'v2',
195 | value: new THREE.Vector2(TEXTURE_SIZE, TEXTURE_SIZE)
196 | },
197 | texturePosition: {
198 | type: 't',
199 | value: null
200 | }
201 | },
202 | vertexShader: "#define GLSLIFY 1\n\nvoid main() {\n gl_Position = vec4( position, 1.0 );\n}\n",
203 | fragmentShader: "#define GLSLIFY 1\n\nuniform vec2 resolution;\n\nuniform sampler2D texturePosition;\n\nuniform float time;\nuniform float speed;\n\n//\n// Description : Array and textureless GLSL 2D/3D/4D simplex\n// noise functions.\n// Author : Ian McEwan, Ashima Arts.\n// Maintainer : ijm\n// Lastmod : 20110822 (ijm)\n// License : Copyright (C) 2011 Ashima Arts. All rights reserved.\n// Distributed under the MIT License. See LICENSE file.\n// https://github.com/ashima/webgl-noise\n//\n\nvec4 mod289_2_0(vec4 x) {\n return x - floor(x * (1.0 / 289.0)) * 289.0; }\n\nfloat mod289_2_0(float x) {\n return x - floor(x * (1.0 / 289.0)) * 289.0; }\n\nvec4 permute_2_1(vec4 x) {\n return mod289_2_0(((x*34.0)+1.0)*x);\n}\n\nfloat permute_2_1(float x) {\n return mod289_2_0(((x*34.0)+1.0)*x);\n}\n\nvec4 taylorInvSqrt_2_2(vec4 r)\n{\n return 1.79284291400159 - 0.85373472095314 * r;\n}\n\nfloat taylorInvSqrt_2_2(float r)\n{\n return 1.79284291400159 - 0.85373472095314 * r;\n}\n\nvec4 grad4_2_3(float j, vec4 ip)\n {\n const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);\n vec4 p,s;\n\n p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;\n p.w = 1.5 - dot(abs(p.xyz), ones.xyz);\n s = vec4(lessThan(p, vec4(0.0)));\n p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www;\n\n return p;\n }\n\n// (sqrt(5) - 1)/4 = F4, used once below\n#define F4 0.309016994374947451\n\nfloat snoise_2_4(vec4 v)\n {\n const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4\n 0.276393202250021, // 2 * G4\n 0.414589803375032, // 3 * G4\n -0.447213595499958); // -1 + 4 * G4\n\n// First corner\n vec4 i = floor(v + dot(v, vec4(F4)) );\n vec4 x0 = v - i + dot(i, C.xxxx);\n\n// Other corners\n\n// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)\n vec4 i0;\n vec3 isX = step( x0.yzw, x0.xxx );\n vec3 isYZ = step( x0.zww, x0.yyz );\n// i0.x = dot( isX, vec3( 1.0 ) );\n i0.x = isX.x + isX.y + isX.z;\n i0.yzw = 1.0 - isX;\n// i0.y += dot( isYZ.xy, vec2( 1.0 ) );\n i0.y += isYZ.x + isYZ.y;\n i0.zw += 1.0 - isYZ.xy;\n i0.z += isYZ.z;\n i0.w += 1.0 - isYZ.z;\n\n // i0 now contains the unique values 0,1,2,3 in each channel\n vec4 i3 = clamp( i0, 0.0, 1.0 );\n vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );\n vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );\n\n // x0 = x0 - 0.0 + 0.0 * C.xxxx\n // x1 = x0 - i1 + 1.0 * C.xxxx\n // x2 = x0 - i2 + 2.0 * C.xxxx\n // x3 = x0 - i3 + 3.0 * C.xxxx\n // x4 = x0 - 1.0 + 4.0 * C.xxxx\n vec4 x1 = x0 - i1 + C.xxxx;\n vec4 x2 = x0 - i2 + C.yyyy;\n vec4 x3 = x0 - i3 + C.zzzz;\n vec4 x4 = x0 + C.wwww;\n\n// Permutations\n i = mod289_2_0(i);\n float j0 = permute_2_1( permute_2_1( permute_2_1( permute_2_1(i.w) + i.z) + i.y) + i.x);\n vec4 j1 = permute_2_1( permute_2_1( permute_2_1( permute_2_1 (\n i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))\n + i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))\n + i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))\n + i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));\n\n// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope\n// 7*7*6 = 294, which is close to the ring size 17*17 = 289.\n vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;\n\n vec4 p0_2_5 = grad4_2_3(j0, ip);\n vec4 p1 = grad4_2_3(j1.x, ip);\n vec4 p2 = grad4_2_3(j1.y, ip);\n vec4 p3 = grad4_2_3(j1.z, ip);\n vec4 p4 = grad4_2_3(j1.w, ip);\n\n// Normalise gradients\n vec4 norm = taylorInvSqrt_2_2(vec4(dot(p0_2_5,p0_2_5), dot(p1,p1), dot(p2, p2), dot(p3,p3)));\n p0_2_5 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n p4 *= taylorInvSqrt_2_2(dot(p4,p4));\n\n// Mix contributions from the five corners\n vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);\n vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0);\n m0 = m0 * m0;\n m1 = m1 * m1;\n return 49.0 * ( dot(m0*m0, vec3( dot( p0_2_5, x0 ), dot( p1, x1 ), dot( p2, x2 )))\n + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;\n\n }\n\n\n\n\nvec4 snoiseVec4_1_6( vec4 x ){\n\n float s = snoise_2_4(vec4( x ));\n float s1 = snoise_2_4(vec4( x.y - 19.1 , x.z + 33.4 , x.w + 47.2 , x.x + 12.2 ));\n float s2 = snoise_2_4(vec4( x.z + 74.2 , x.w - 124.5 , x.x + 99.4 , x.y - 123.2 ));\n float s3 = snoise_2_4(vec4( x.w + 21.2 , x.x - 52.5 , x.y + 60.4 , x.z + 42.2 ));\n vec4 c = vec4( s , s1 , s2 , s3 );\n return c;\n\n}\n\n\nvec4 curlNoise_1_7( vec4 p ){\n\n const float e = .1;\n vec4 dx = vec4( e , 0.0 , 0.0 , 0.0 );\n vec4 dy = vec4( 0.0 , e , 0.0 , 0.0 );\n vec4 dz = vec4( 0.0 , 0.0 , e , 0.0 );\n vec4 dw = vec4( 0.0 , 0.0 , 0.0 , e );\n\n vec4 p_x0 = snoiseVec4_1_6( p - dx );\n vec4 p_x1 = snoiseVec4_1_6( p + dx );\n vec4 p_y0 = snoiseVec4_1_6( p - dy );\n vec4 p_y1 = snoiseVec4_1_6( p + dy );\n vec4 p_z0 = snoiseVec4_1_6( p - dz );\n vec4 p_z1 = snoiseVec4_1_6( p + dz );\n vec4 p_w0 = snoiseVec4_1_6( p - dw );\n vec4 p_w1 = snoiseVec4_1_6( p + dw );\n\n float x = p_y1.z - p_y0.z - p_z1.w + p_z0.w + p_w0.y - p_w1.y;\n float y = p_z1.w - p_z0.w - p_w1.x + p_w0.x + p_x0.z - p_x1.z;\n float z = p_w1.x - p_w0.x - p_x1.y + p_x0.y + p_y0.w - p_y1.w;\n float w = p_x1.y - p_x0.y - p_y1.z + p_y0.z + p_z0.x - p_y1.x;\n\n const float divisor = 1.0 / ( 2.0 * e );\n return normalize( vec4( x , y , z, w ) * divisor );\n\n}\n\n\n\nhighp float random_3_8(vec2 co)\n{\n highp float a = 12.9898;\n highp float b = 78.233;\n highp float c = 43758.5453;\n highp float dt= dot(co.xy ,vec2(a,b));\n highp float sn= mod(dt,3.14);\n return fract(sin(sn) * c);\n}\n\n\n\nvoid main() {\n\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n vec3 position = texture2D( texturePosition, uv ).xyz;\n\n vec3 velocity = curlNoise_1_7(vec4(position * 0.02, time * 0.001 * speed)).xyz * 0.1;\n\n float l = pow(smoothstep(500.0, -500.0, position.x), 2.0);\n\n velocity.x += -0.05 + l * - (0.2 + random_3_8(uv) * 0.2);\n\n velocity.x = clamp(velocity.x, -5.0, -0.01);\n\n velocity *= speed;\n\n gl_FragColor = vec4( velocity, 1.0 );\n\n}\n"
204 | });
205 |
206 | positionShader = new THREE.ShaderMaterial({
207 | uniforms: {
208 | delta: {
209 | type: 'f',
210 | value: 0.0
211 | },
212 | resolution: {
213 | type: 'v2',
214 | value: new THREE.Vector2(TEXTURE_SIZE, TEXTURE_SIZE)
215 | },
216 | texturePosition: {
217 | type: 't',
218 | value: null
219 | },
220 | textureVelocity: {
221 | type: 't',
222 | value: null
223 | }
224 | },
225 | vertexShader: "#define GLSLIFY 1\n\nvoid main() {\n gl_Position = vec4( position, 1.0 );\n}\n",
226 | fragmentShader: "#define GLSLIFY 1\n\nuniform vec2 resolution;\nuniform sampler2D textureVelocity;\nuniform sampler2D texturePosition;\n\nuniform float delta;\n\nhighp float random_1_0(vec2 co)\n{\n highp float a = 12.9898;\n highp float b = 78.233;\n highp float c = 43758.5453;\n highp float dt= dot(co.xy ,vec2(a,b));\n highp float sn= mod(dt,3.14);\n return fract(sin(sn) * c);\n}\n\n\n\nvoid main() {\n\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n vec3 position = texture2D( texturePosition, uv ).xyz;\n vec3 velocity = texture2D( textureVelocity, uv ).xyz;\n\n position += velocity * delta * 1.0;\n\n if(position.x < -500.0) {\n position.x = 500.0 + random_1_0(uv + vec2(21.3, 63.21)) * 500.0;\n position.y = random_1_0(uv + vec2(32.3, 734.21));\n position.z = random_1_0(uv + vec2(127.3, 31.21));\n }\n\n gl_FragColor = vec4( position, 1.0 );\n\n}\n"
227 | });
228 |
229 | fboMesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2), copyShader);
230 | fboScene.add(fboMesh);
231 |
232 | velocityRenderTarget = new THREE.WebGLRenderTarget(TEXTURE_SIZE, TEXTURE_SIZE, {
233 | wrapS: THREE.RepeatWrapping,
234 | wrapT: THREE.RepeatWrapping,
235 | minFilter: THREE.NearestFilter,
236 | magFilter: THREE.NearestFilter,
237 | format: THREE.RGBAFormat,
238 | type: THREE.FloatType,
239 | stencilBuffer: false
240 | });
241 |
242 | positionRenderTarget = velocityRenderTarget.clone();
243 | positionRenderTarget2 = velocityRenderTarget.clone();
244 | copyTexture(createVelocityTexture(), velocityRenderTarget);
245 | copyTexture(createPositionTexture(), positionRenderTarget);
246 | copyTexture(positionRenderTarget, positionRenderTarget2);
247 | }
248 |
249 | function updatePosition(dt) {
250 |
251 | fboMesh.material = config.use4d ? velocity4dShader : velocityShader;
252 | fboMesh.material.uniforms.time.value += dt;
253 | fboMesh.material.uniforms.texturePosition.value = positionRenderTarget;
254 | fboMesh.material.uniforms.speed.value = config.speed;
255 | renderer.render(fboScene, fboCamera, velocityRenderTarget);
256 |
257 | fboMesh.material = positionShader;
258 | positionShader.uniforms.texturePosition.value = positionRenderTarget;
259 | positionShader.uniforms.textureVelocity.value = velocityRenderTarget;
260 | positionShader.uniforms.delta.value = dt || 0;
261 | renderer.render(fboScene, fboCamera, positionRenderTarget2);
262 |
263 | // swap
264 | var tmp = positionRenderTarget;
265 | positionRenderTarget = positionRenderTarget2;
266 | positionRenderTarget2 = tmp;
267 | }
268 |
269 | function copyTexture(input, output) {
270 | fboMesh.material = copyShader;
271 | copyShader.uniforms.texture.value = input;
272 | renderer.render(fboScene, fboCamera, output);
273 | }
274 |
275 | function createVelocityTexture() {
276 | var a = new Float32Array(AMOUNT * 3);
277 | var texture = new THREE.DataTexture(a, TEXTURE_SIZE, TEXTURE_SIZE, THREE.RGBFormat, THREE.FloatType);
278 | texture.minFilter = THREE.NearestFilter;
279 | texture.magFilter = THREE.NearestFilter;
280 | texture.needsUpdate = true;
281 | texture.flipY = false;
282 | return texture;
283 | }
284 |
285 | function createPositionTexture() {
286 | var a = new Float32Array(AMOUNT * 3);
287 | for (var i = 0, len = a.length; i < len; i += 3) {
288 | a[i + 0] = -1000;
289 | a[i + 1] = (Math.random() - 0.5) - 1000;
290 | a[i + 2] = (Math.random() - 0.5) - 1000;
291 | }
292 | var texture = new THREE.DataTexture(a, TEXTURE_SIZE, TEXTURE_SIZE, THREE.RGBFormat, THREE.FloatType);
293 | texture.minFilter = THREE.NearestFilter;
294 | texture.magFilter = THREE.NearestFilter;
295 | texture.needsUpdate = true;
296 | texture.flipY = false;
297 | return texture;
298 | }
299 |
300 | function onResize() {
301 | width = window.innerWidth;
302 | height = window.innerHeight;
303 |
304 | camera.aspect = width / height;
305 | camera.updateProjectionMatrix();
306 | renderer.setSize(width, height);
307 | }
308 |
309 | function loop() {
310 | var newNow = Date.now();
311 | var dt = newNow - now;
312 | now = newNow;
313 | render(Math.min(dt, 16));
314 | requestAnimationFrame(loop);
315 | }
316 |
317 | function render(dt) {
318 | dt = dt || 0;
319 |
320 | updatePosition(dt);
321 |
322 | particles.material.uniforms.texturePosition.value = positionRenderTarget;
323 |
324 | renderer.render(scene, camera);
325 | }
326 |
327 | preInit();
--------------------------------------------------------------------------------