SimulationRenderer.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. if ( ! renderer.extensions.get( "OES_texture_float" ) ) {
  17. alert( "No OES_texture_float support for float textures!" );
  18. return;
  19. }
  20. if ( renderer.capabilities.maxVertexTextures === 0 ) {
  21. alert( "No support for vertex shader textures!" );
  22. return;
  23. }
  24. var scene = new THREE.Scene();
  25. var uniforms = {
  26. time: { type: "f", value: 1.0 },
  27. resolution: { type: "v2", value: new THREE.Vector2( WIDTH, WIDTH ) },
  28. texture: { type: "t", value: null }
  29. };
  30. var passThruShader = new THREE.ShaderMaterial( {
  31. uniforms: uniforms,
  32. vertexShader: document.getElementById( 'vertexShader' ).textContent,
  33. fragmentShader: document.getElementById( 'fragmentShader' ).textContent
  34. } );
  35. var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), passThruShader );
  36. var positionShader = new THREE.ShaderMaterial( {
  37. uniforms: {
  38. time: { type: "f", value: 1.0 },
  39. delta: { type: "f", value: 0.0 },
  40. resolution: { type: "v2", value: new THREE.Vector2( WIDTH, WIDTH ) },
  41. texturePosition: { type: "t", value: null },
  42. textureVelocity: { type: "t", value: null },
  43. },
  44. vertexShader: document.getElementById( 'vertexShader' ).textContent,
  45. fragmentShader: document.getElementById( 'fragmentShaderPosition' ).textContent
  46. } );
  47. this.positionShader = positionShader;
  48. var velocityShader = new THREE.ShaderMaterial( {
  49. uniforms: {
  50. time: { type: "f", value: 1.0 },
  51. delta: { type: "f", value: 0.0 },
  52. resolution: { type: "v2", value: new THREE.Vector2( WIDTH, WIDTH ) },
  53. texturePosition: { type: "t", value: null },
  54. textureVelocity: { type: "t", value: null },
  55. testing: { type: "f", value: 1.0 },
  56. seperationDistance: { type: "f", value: 1.0 },
  57. alignmentDistance: { type: "f", value: 1.0 },
  58. cohesionDistance: { type: "f", value: 1.0 },
  59. freedomFactor: { type: "f", value: 1.0 },
  60. predator: { type: "v3", value: new THREE.Vector3() }
  61. },
  62. defines: {
  63. WIDTH: WIDTH.toFixed( 2 )
  64. },
  65. vertexShader: document.getElementById( 'vertexShader' ).textContent,
  66. fragmentShader: document.getElementById( 'fragmentShaderVelocity' ).textContent
  67. } );
  68. this.velocityUniforms = velocityShader.uniforms;
  69. scene.add( mesh );
  70. var flipflop = true;
  71. var rtPosition1, rtPosition2, rtVelocity1, rtVelocity2;
  72. function init() {
  73. var dtPosition = generatePositionTexture();
  74. var dtVelocity = generateVelocityTexture();
  75. rtPosition1 = getRenderTarget( THREE.RGBAFormat );
  76. rtPosition2 = rtPosition1.clone();
  77. rtVelocity1 = getRenderTarget( THREE.RGBAFormat );
  78. rtVelocity2 = rtVelocity1.clone();
  79. simulator.renderTexture( dtPosition, rtPosition1 );
  80. simulator.renderTexture( rtPosition1.texture, rtPosition2 );
  81. simulator.renderTexture( dtVelocity, rtVelocity1 );
  82. simulator.renderTexture( rtVelocity1.texture, rtVelocity2 );
  83. simulator.velocityUniforms.testing.value = 10;
  84. }
  85. this.init = init;
  86. function getRenderTarget( type ) {
  87. var renderTarget = new THREE.WebGLRenderTarget( WIDTH, WIDTH, {
  88. wrapS: THREE.RepeatWrapping,
  89. wrapT: THREE.RepeatWrapping,
  90. minFilter: THREE.NearestFilter,
  91. magFilter: THREE.NearestFilter,
  92. format: type,
  93. type: THREE.FloatType,
  94. stencilBuffer: false
  95. } );
  96. return renderTarget;
  97. }
  98. // Takes a texture, and render out as another texture
  99. this.renderTexture = function ( input, output ) {
  100. mesh.material = passThruShader;
  101. uniforms.texture.value = input;
  102. renderer.render( scene, camera, output );
  103. };
  104. this.renderPosition = function( position, velocity, output, delta ) {
  105. mesh.material = positionShader;
  106. positionShader.uniforms.texturePosition.value = position;
  107. positionShader.uniforms.textureVelocity.value = velocity;
  108. positionShader.uniforms.time.value = performance.now();
  109. positionShader.uniforms.delta.value = delta;
  110. renderer.render( scene, camera, output );
  111. this.currentPosition = output.texture;
  112. };
  113. this.renderVelocity = function( position, velocity, output, delta ) {
  114. mesh.material = velocityShader;
  115. velocityShader.uniforms.texturePosition.value = position;
  116. velocityShader.uniforms.textureVelocity.value = velocity;
  117. velocityShader.uniforms.time.value = performance.now();
  118. velocityShader.uniforms.delta.value = delta;
  119. renderer.render( scene, camera, output );
  120. this.currentVelocity = output.texture;
  121. };
  122. this.simulate = function( delta ) {
  123. if ( flipflop ) {
  124. simulator.renderVelocity( rtPosition1.texture, rtVelocity1.texture, rtVelocity2, delta );
  125. simulator.renderPosition( rtPosition1.texture, rtVelocity2.texture, rtPosition2, delta );
  126. } else {
  127. simulator.renderVelocity( rtPosition2.texture, rtVelocity2.texture, rtVelocity1, delta );
  128. simulator.renderPosition( rtPosition2.texture, rtVelocity1.texture, rtPosition1, delta );
  129. }
  130. flipflop = ! flipflop;
  131. };
  132. function generatePositionTexture() {
  133. var a = new Float32Array( PARTICLES * 4 );
  134. for ( var k = 0, kl = a.length; k < kl; k += 4 ) {
  135. var x = Math.random() * BOUNDS - BOUNDS_HALF;
  136. var y = Math.random() * BOUNDS - BOUNDS_HALF;
  137. var z = Math.random() * BOUNDS - BOUNDS_HALF;
  138. a[ k + 0 ] = x;
  139. a[ k + 1 ] = y;
  140. a[ k + 2 ] = z;
  141. a[ k + 3 ] = 1;
  142. }
  143. var texture = new THREE.DataTexture( a, WIDTH, WIDTH, THREE.RGBAFormat, THREE.FloatType );
  144. texture.needsUpdate = true;
  145. return texture;
  146. }
  147. function generateVelocityTexture() {
  148. var a = new Float32Array( PARTICLES * 4 );
  149. for ( var k = 0, kl = a.length; k < kl; k += 4 ) {
  150. var x = Math.random() - 0.5;
  151. var y = Math.random() - 0.5;
  152. var z = Math.random() - 0.5;
  153. a[ k + 0 ] = x * 10;
  154. a[ k + 1 ] = y * 10;
  155. a[ k + 2 ] = z * 10;
  156. a[ k + 3 ] = 1;
  157. }
  158. var texture = new THREE.DataTexture( a, WIDTH, WIDTH, THREE.RGBAFormat, THREE.FloatType ); // was RGB format. changed to RGBA format. see discussion in #8415 / #8450
  159. texture.needsUpdate = true;
  160. return texture;
  161. }
  162. }