spring physics shader
by gromiczek
HTML
<script src=" https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.js"></script>
<div id="container"></div>
<script id="texture_vertex_simulation_shader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
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">
// This shader handles only the math to move the various points. Adding the sprites and point opacity comes in the following shader.
// simulation
uniform sampler2D tPositions;
uniform sampler2D tOffsets;
uniform float uTime;
uniform float uXOffW;
varying vec2 vUv;
void main() {
float damping = 0.98;
vec4 nowPos = texture2D( tPositions, vUv ).xyzw;
vec4 offsets = texture2D( tOffsets, vUv ).xyzw;
vec2 velocity = vec2(nowPos.z, nowPos.w);
float anchorHeight = 130.0;
float yAnchor = anchorHeight;
vec2 anchor = vec2( offsets.x, yAnchor );
// Newton's law: F = M * A
float mass = 24.0;
vec2 acceleration = vec2(0.0, 0.0);
// 1. apply gravity's force:
vec2 gravity = vec2(0.0, 2.0);
gravity /= mass;
acceleration += gravity;
// 2. apply the spring force
float restLength = yAnchor - offsets.y;
float springConstant = 0.2;
// Vector pointing from anchor to point position
vec2 springForce = vec2(nowPos.x - anchor.x, nowPos.y - anchor.y);
// length of the vector
float distance = length( springForce );
// stretch is the difference between the current distance and restLength
float stretch = distance - restLength;
// Calculate springForce according to Hooke's Law
springForce = normalize(springForce);
springForce *= (springConstant *...
CSS
body {
color: #ffffff;
background-color: #000000;
margin: 0;
overflow: hidden;
}
JavaScript
/*
@author zz85
updated by @gromiczek
*/
// Utils for FBO Particles Simulations
THREE.FBOUtils = function( textureWidth, renderer, simulationShader, attributes ) {
// Init RTT stuff
gl = renderer.getContext();
if( !gl.getExtension( "OES_texture_float" )) {
alert( "No OES_texture_float support for float textures!" );
return;
}
if( gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) === 0) {
alert( "No support for vertex shader textures!" );
return;
}
var cameraRTT = new THREE.OrthographicCamera(-textureWidth/2, textureWidth/2, textureWidth/2, -textureWidth/2, -1000000, 1000000);
cameraRTT.position.z = 100;
var rtTexturePos = new THREE.WebGLRenderTarget(textureWidth, textureWidth, {
wrapS:THREE.RepeatWrapping,
wrapT:THREE.RepeatWrapping,
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat,
type:THREE.FloatType,
stencilBuffer: false
});
// Shader Stuff
var texture_cpu_to_gpu_vertex_shader = [
"varying vec2 vUv;",
"void main() {",
"vUv = vec2(uv.x, 1.0 - uv.y);",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"} "
].join("\n");
var texture_cpu_to_gpu_fragment_shader = [
"varying vec2 vUv;",
"uniform sampler2D tPositions;",
"void main() {",
"vec4 pos = texture2D( tPositions, vUv );",
"gl_FragColor = pos;",
"};"
].join("\n");
var cpu_gpu_material = new THREE.ShaderMaterial({
uniforms: {
tPositions: { type: "t", value: null }
},
vertexShader: texture_cpu_to_gpu_vertex_shader,
fragmentShader: texture_cpu_to_gpu_fragment_shader
});
var sceneRTTPos = new THREE.Scene();
sceneRTTPos.add(cameraRTT);
// var plane = new THREE.PlaneBufferGeometry(textureWidth, textureWidth);
var plane = new THREE.PlaneGeometry(textureWidth, textureWidth);
quad = new THREE.Mesh(plane, simulationShader);
quad.position.z = -5000;
sceneRTTPos.add(quad);
this.textureWidth = textureWidth;
this.sceneRTTPos =...