SimulationRenderer.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /**
  2. * @author zz85 https://github.com/zz85 / http://www.lab4games.net/zz85/blog
  3. *
  4. * Bird Simulation Render
  5. *
  6. * A simple scene rendering a quad of the following shaders
  7. * 1. Pass-thru Shader,
  8. * 2. Bird Position Update Shader,
  9. * 3. Bird Velocity Update Shader
  10. *
  11. */
  12. function SimulationRenderer(WIDTH, renderer) {
  13. WIDTH = WIDTH || 4;
  14. var camera = new THREE.Camera();
  15. camera.position.z = 1;
  16. // Init RTT stuff
  17. gl = renderer.getContext();
  18. if ( !gl.getExtension( "OES_texture_float" )) {
  19. alert( "No OES_texture_float support for float textures!" );
  20. return;
  21. }
  22. if ( gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) == 0) {
  23. alert( "No support for vertex shader textures!" );
  24. return;
  25. }
  26. var scene = new THREE.Scene();
  27. var uniforms = {
  28. time: { type: "f", value: 1.0 },
  29. resolution: { type: "v2", value: new THREE.Vector2( WIDTH, WIDTH ) },
  30. texture: { type: "t", value: null }
  31. };
  32. var passThruShader = new THREE.ShaderMaterial( {
  33. uniforms: uniforms,
  34. vertexShader: document.getElementById( 'vertexShader' ).textContent,
  35. fragmentShader: document.getElementById( 'fragmentShader' ).textContent
  36. } );
  37. var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), passThruShader );
  38. var positionShader = new THREE.ShaderMaterial( {
  39. uniforms: {
  40. time: { type: "f", value: 1.0 },
  41. delta: { type: "f", value: 0.0 },
  42. resolution: { type: "v2", value: new THREE.Vector2( WIDTH, WIDTH ) },
  43. texturePosition: { type: "t", value: null },
  44. textureVelocity: { type: "t", value: null },
  45. },
  46. vertexShader: document.getElementById( 'vertexShader' ).textContent,
  47. fragmentShader: document.getElementById( 'fragmentShaderPosition' ).textContent
  48. } );
  49. this.positionShader = positionShader;
  50. var velocityShader = new THREE.ShaderMaterial( {
  51. uniforms: {
  52. time: { type: "f", value: 1.0 },
  53. delta: { type: "f", value: 0.0 },
  54. resolution: { type: "v2", value: new THREE.Vector2( WIDTH, WIDTH ) },
  55. texturePosition: { type: "t", value: null },
  56. textureVelocity: { type: "t", value: null },
  57. testing: { type: "f", value: 1.0 },
  58. seperationDistance: { type: "f", value: 1.0 },
  59. alignmentDistance: { type: "f", value: 1.0 },
  60. cohesionDistance: { type: "f", value: 1.0 },
  61. freedomFactor: { type: "f", value: 1.0 },
  62. predator: { type: "v3", value: new THREE.Vector3() }
  63. },
  64. defines: {
  65. WIDTH: WIDTH.toFixed(2)
  66. },
  67. vertexShader: document.getElementById( 'vertexShader' ).textContent,
  68. fragmentShader: document.getElementById( 'fragmentShaderVelocity' ).textContent
  69. } );
  70. this.velocityUniforms = velocityShader.uniforms;
  71. scene.add( mesh );
  72. var flipflop = true;
  73. var rtPosition1, rtPosition2, rtVelocity1, rtVelocity2;
  74. function init() {
  75. var dtPosition = generatePositionTexture();
  76. var dtVelocity = generateVelocityTexture();
  77. rtPosition1 = getRenderTarget( THREE.RGBAFormat );
  78. rtPosition2 = rtPosition1.clone();
  79. rtVelocity1 = getRenderTarget( THREE.RGBFormat );
  80. rtVelocity2 = rtVelocity1.clone();
  81. simulator.renderTexture(dtPosition, rtPosition1);
  82. simulator.renderTexture(rtPosition1, rtPosition2);
  83. simulator.renderTexture(dtVelocity, rtVelocity1);
  84. simulator.renderTexture(rtVelocity1, rtVelocity2);
  85. simulator.velocityUniforms.testing.value = 10;
  86. }
  87. this.init = init;
  88. function getRenderTarget( type ) {
  89. var renderTarget = new THREE.WebGLRenderTarget(WIDTH, WIDTH, {
  90. wrapS: THREE.RepeatWrapping,
  91. wrapT: THREE.RepeatWrapping,
  92. minFilter: THREE.NearestFilter,
  93. magFilter: THREE.NearestFilter,
  94. format: type,
  95. type: THREE.FloatType,
  96. stencilBuffer: false
  97. });
  98. return renderTarget;
  99. }
  100. // Takes a texture, and render out as another texture
  101. this.renderTexture = function ( input, output ) {
  102. mesh.material = passThruShader;
  103. uniforms.texture.value = input;
  104. renderer.render( scene, camera, output );
  105. }
  106. this.renderPosition = function(position, velocity, output, delta) {
  107. mesh.material = positionShader;
  108. positionShader.uniforms.texturePosition.value = position;
  109. positionShader.uniforms.textureVelocity.value = velocity;
  110. positionShader.uniforms.time.value = performance.now();
  111. positionShader.uniforms.delta.value = delta;
  112. renderer.render( scene, camera, output );
  113. this.currentPosition = output;
  114. }
  115. this.renderVelocity = function(position, velocity, output, delta) {
  116. mesh.material = velocityShader;
  117. velocityShader.uniforms.texturePosition.value = position;
  118. velocityShader.uniforms.textureVelocity.value = velocity;
  119. velocityShader.uniforms.time.value = performance.now();
  120. velocityShader.uniforms.delta.value = delta;
  121. renderer.render( scene, camera, output );
  122. this.currentVelocity = output;
  123. }
  124. this.simulate = function( delta ) {
  125. if (flipflop) {
  126. simulator.renderVelocity( rtPosition1, rtVelocity1, rtVelocity2, delta );
  127. simulator.renderPosition( rtPosition1, rtVelocity2, rtPosition2, delta );
  128. } else {
  129. simulator.renderVelocity( rtPosition2, rtVelocity2, rtVelocity1, delta );
  130. simulator.renderPosition( rtPosition2, rtVelocity1, rtPosition1, delta );
  131. }
  132. flipflop = !flipflop;
  133. }
  134. function generatePositionTexture() {
  135. var a = new Float32Array( PARTICLES * 4 );
  136. for ( var k = 0, kl = a.length; k < kl; k += 4 ) {
  137. var x = Math.random() * BOUNDS - BOUNDS_HALF;
  138. var y = Math.random() * BOUNDS - BOUNDS_HALF;
  139. var z = Math.random() * BOUNDS - BOUNDS_HALF;
  140. a[ k + 0 ] = x;
  141. a[ k + 1 ] = y;
  142. a[ k + 2 ] = z;
  143. a[ k + 3 ] = 1;
  144. }
  145. var texture = new THREE.DataTexture( a, WIDTH, WIDTH, THREE.RGBAFormat, THREE.FloatType );
  146. texture.minFilter = THREE.NearestFilter;
  147. texture.magFilter = THREE.NearestFilter;
  148. texture.needsUpdate = true;
  149. texture.flipY = false;
  150. return texture;
  151. }
  152. function generateVelocityTexture() {
  153. var a = new Float32Array( PARTICLES * 3 );
  154. for ( var k = 0, kl = a.length; k < kl; k += 3 ) {
  155. var x = Math.random() - 0.5;
  156. var y = Math.random() - 0.5;
  157. var z = Math.random() - 0.5;
  158. a[ k + 0 ] = x * 10;
  159. a[ k + 1 ] = y * 10;
  160. a[ k + 2 ] = z * 10;
  161. }
  162. var texture = new THREE.DataTexture( a, WIDTH, WIDTH, THREE.RGBFormat, THREE.FloatType );
  163. texture.minFilter = THREE.NearestFilter;
  164. texture.magFilter = THREE.NearestFilter;
  165. texture.needsUpdate = true;
  166. texture.flipY = false;
  167. return texture;
  168. }
  169. }