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 =...