spring physics shader - GPUComputationRenderer

by gromiczek

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.js"></script>
<div id="container"></div>


<script id="position_fragment_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.		
	  uniform sampler2D tOffsets; 
	  uniform float uTime;
    
	  varying vec2 vUv;
    
	  float hash(float n) { return fract(sin(n) * 1e4); }
	    
	  float noise(float x) {
	      float i = floor(x);
	      float f = fract(x);
	      float u = f * f * (3.0 - 2.0 * f);
	      return mix(hash(i), hash(i + 1.0), u);
	  }
			
	  void main() {
	      vec2 uv = gl_FragCoord.xy / resolution.xy;
	            
	       float damping = 0.98;
	            
	       vec4 nowPos = texture2D( tPositions, uv ).xyzw;
	       vec4 offsets = texture2D( tOffsets, uv ).xyzw;
	       vec2 velocity = vec2(nowPos.z, nowPos.w);
	                      
	       float anchorHeight = 100.0;
	       float yAnchor = anchorHeight;
	       vec2 anchor = vec2( -(uTime * 50.0) + offsets.x, yAnchor + (noise(uTime) * 30.0) );

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

JavaScript

/**
 * @author yomboprime https://github.com/yomboprime
 *
 * GPUComputationRenderer, based on SimulationRenderer by zz85
 *
 * The GPUComputationRenderer uses the concept of variables. These variables are RGBA float textures that hold 4 floats
 * for each compute element (texel)
 *
 * Each variable has a fragment shader that defines the computation made to obtain the variable in question.
 * You can use as many variables you need, and make dependencies so you can use textures of other variables in the shader
 * (the sampler uniforms are added automatically) Most of the variables will need themselves as dependency.
 *
 * The renderer has actually two render targets per variable, to make ping-pong. Textures from the current frame are used
 * as inputs to render the textures of the next frame.
 *
 * The render targets of the variables can be used as input textures for your visualization shaders.
 *
 * Variable names should be valid identifiers and should not collide with THREE GLSL used identifiers.
 * a common approach could be to use 'texture' prefixing the variable name; i.e texturePosition, textureVelocity...
 *
 * The size of the computation (sizeX * sizeY) is defined as 'resolution' automatically in the shader. For example:
 * #DEFINE resolution vec2( 1024.0, 1024.0 )
 *
 * -------------
 *
 * Basic use:
 *
 * // Initialization...
 *
 * // Create computation renderer
 * var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
 *
 * // Create initial state float textures
 * var pos0 = gpuCompute.createTexture();
 * var vel0 = gpuCompute.createTexture();
 * // and fill in here the texture data...
 *
 * // Add texture variables
 * var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
 * var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
 *
 * // Add variable dependencies
 * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
 * gpuCompute.setVariableDependencies( posVar, [...