Published
Edited
Jul 19, 2019
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
funPart = `
vec4 sample = texture2D(positions, vec2(vUv.x, 1.0 - vUv.y));
vec3 pos = sample.xyz;
float lifetime = sample.a;

// increase lifetime by delta, cap it at 1 and start over
lifetime = mod(lifetime + delta, 1.0);

float x = floor(vUv.x * ${textureSize}.0);
float y = floor(vUv.y * ${textureSize}.0);
float index = x + y * ${textureSize}.0;
//lifetime = x;
float speed = 2.0;

if (x == 0.0) {
pos.x = cos(elapsedTime + index * speed) * (sin(elapsedTime * speed) * 40.0);
pos.z = sin(elapsedTime + index * speed) * (sin(elapsedTime * speed) * 40.0);
pos.y = -25.0;
pos.y += sin(elapsedTime * 2.0 + index * 3.25) * 2.0;

} else {
vec4 neighborLeft = texture2D(positions, vec2((vUv.x - (1.0 / ${textureSize}.0)), 1.0 - vUv.y));
pos.xyz = lerp(pos.xyz, neighborLeft.xyz, 0.003);
float gravity = 15.0;
pos.y -= gravity * delta - y/30.0;
}


gl_FragColor = vec4(pos.rgb, lifetime);`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function createRenderMaterial (textureSize) {
const textureLoader = new THREE.TextureLoader()
const material = new THREE.RawShaderMaterial( {
uniforms: {
time: { value: 1.0 },
orientation: {type: 'v4', value: new THREE.Quaternion()},
gpgpuOffsets: {type: 't', value: null },
mapper: textureLoader,
// map: new THREE.TextureLoader().load('https://i.imgur.com/h1v0P5s.jpg'),
colorBase: new THREE.Uniform(new THREE.Color(0xd9ff0e)),
colorStart: new THREE.Uniform(new THREE.Color(0x8674fd)),
colorPeak: new THREE.Uniform(new THREE.Color(0x0ed9ff)),
colorEnd: new THREE.Uniform(new THREE.Color(0x333333)),
},
// transparent: true,
// alpha: true,
side: THREE.DoubleSide,
// alphaTest: 0.1,
vertexShader: `
precision highp float;

#define PI 3.1415926536
#define PI2 6.28318530718

attribute vec3 position;
attribute vec3 offset;
attribute float scale;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

uniform float time;

attribute vec2 uv;
varying vec2 vUv;
attribute float particleIndex;

uniform sampler2D gpgpuOffsets;
varying float vParticleIndex;

uniform vec4 orientation;
uniform sampler2D mapper;
varying vec4 vColor;

vec3 applyQuaternionToVector( vec4 q, vec3 v ){
return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}

void main(){
vec4 positions = texture2D(gpgpuOffsets, vec2(
mod(particleIndex-1.0, ${textureSize}.0)/${textureSize}.0,
floor((particleIndex-1.0)/${textureSize}.0)/${textureSize}.0)
);
float lifetime = positions.a;
float i = particleIndex - 1.0;
vec4 sample = texture2D(mapper, vec2(
mod(i, ${textureSize}.0) / ${textureSize}.0,
1.0 - i / ${textureSize}.0 / ${textureSize}.0
));
vec3 pos = position * vec3(scale * lifetime * 2.0, scale * lifetime * 2.0, 1.0);
pos = applyQuaternionToVector(orientation, pos);
pos = pos + offset + positions.xyz;

vParticleIndex = particleIndex;
vUv = vec2(uv.x, 1.0-uv.y);

vColor.xyz = sample.xyz;
// vColor.a = lifetime;
vColor.a = sample.a;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0 );
}
`,
fragmentShader: `
precision highp float;

varying vec4 vColor;
varying vec2 vUv;
varying float vParticleIndex;
varying vec2 vLifetime;

uniform float time;

uniform vec3 colorBase;
uniform vec3 colorStart;
uniform vec3 colorPeak;
uniform vec3 colorEnd;
uniform sampler2D mapper;

#define PI 3.1415926536
#define PI2 6.28318530718


float drawBase (in vec2 uv, in float min, in float max) {
float dist = sqrt(dot(uv, uv));
if (dist >= max || dist <= min) {
return 0.0;
}
float sm = smoothstep(max, max - 0.01, dist);
float sm2 = smoothstep(min, min - 0.01, dist);
float alpha = sm * sm2;
return (1.0-alpha);
}

void main() {
float alpha = drawBase(vUv - vec2(0.5), 0.0, 0.5);
// discard if not needed
if (alpha == 0.0) {
discard;
}

gl_FragColor = vColor;
}
`,
// side: THREE.DoubleSide,
side: THREE.FrontSide, // only front since the plane will always face the camera
transparent: true,
alphaTest: 0.1,
//blending: THREE.NormalBlending
//blending: THREE.MultiplyBlending
blending: THREE.AdditiveBlending
})
textureLoader.load(imageURI, (texture) => {
material.uniforms.mapper.value = texture
})
return material
}
Insert cell
Insert cell
Insert cell
Insert cell
THREE = {
const THREE = window.THREE = await require('three@0.105/build/three.min.js')
await require('three@0.105/examples/js/controls/OrbitControls.js').catch(() => {})
return THREE
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more