webgl_buffergeometry_drawrange.html 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js webgl - buffergeometry - lines drawrange</title>
  5. <meta charset="utf-8">
  6. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  7. <link type="text/css" rel="stylesheet" href="main.css">
  8. </head>
  9. <body>
  10. <div id="container"></div>
  11. <div id="info">
  12. <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - buffergeometry drawrange<br/>
  13. by <a href="https://twitter.com/fernandojsg">fernandojsg</a>
  14. </div>
  15. <script type="module">
  16. import * as THREE from '../build/three.module.js';
  17. import Stats from './jsm/libs/stats.module.js';
  18. import { GUI } from './jsm/libs/dat.gui.module.js';
  19. import { OrbitControls } from './jsm/controls/OrbitControls.js';
  20. let group;
  21. let container, stats;
  22. const particlesData = [];
  23. let camera, scene, renderer;
  24. let positions, colors;
  25. let particles;
  26. let pointCloud;
  27. let particlePositions;
  28. let linesMesh;
  29. const maxParticleCount = 1000;
  30. let particleCount = 500;
  31. const r = 800;
  32. const rHalf = r / 2;
  33. const effectController = {
  34. showDots: true,
  35. showLines: true,
  36. minDistance: 150,
  37. limitConnections: false,
  38. maxConnections: 20,
  39. particleCount: 500
  40. };
  41. init();
  42. animate();
  43. function initGUI() {
  44. const gui = new GUI();
  45. gui.add( effectController, "showDots" ).onChange( function ( value ) {
  46. pointCloud.visible = value;
  47. } );
  48. gui.add( effectController, "showLines" ).onChange( function ( value ) {
  49. linesMesh.visible = value;
  50. } );
  51. gui.add( effectController, "minDistance", 10, 300 );
  52. gui.add( effectController, "limitConnections" );
  53. gui.add( effectController, "maxConnections", 0, 30, 1 );
  54. gui.add( effectController, "particleCount", 0, maxParticleCount, 1 ).onChange( function ( value ) {
  55. particleCount = parseInt( value );
  56. particles.setDrawRange( 0, particleCount );
  57. } );
  58. }
  59. function init() {
  60. initGUI();
  61. container = document.getElementById( 'container' );
  62. camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 4000 );
  63. camera.position.z = 1750;
  64. const controls = new OrbitControls( camera, container );
  65. controls.minDistance = 1000;
  66. controls.maxDistance = 3000;
  67. scene = new THREE.Scene();
  68. group = new THREE.Group();
  69. scene.add( group );
  70. const helper = new THREE.BoxHelper( new THREE.Mesh( new THREE.BoxGeometry( r, r, r ) ) );
  71. helper.material.color.setHex( 0x101010 );
  72. helper.material.blending = THREE.AdditiveBlending;
  73. helper.material.transparent = true;
  74. group.add( helper );
  75. const segments = maxParticleCount * maxParticleCount;
  76. positions = new Float32Array( segments * 3 );
  77. colors = new Float32Array( segments * 3 );
  78. const pMaterial = new THREE.PointsMaterial( {
  79. color: 0xFFFFFF,
  80. size: 3,
  81. blending: THREE.AdditiveBlending,
  82. transparent: true,
  83. sizeAttenuation: false
  84. } );
  85. particles = new THREE.BufferGeometry();
  86. particlePositions = new Float32Array( maxParticleCount * 3 );
  87. for ( let i = 0; i < maxParticleCount; i ++ ) {
  88. const x = Math.random() * r - r / 2;
  89. const y = Math.random() * r - r / 2;
  90. const z = Math.random() * r - r / 2;
  91. particlePositions[ i * 3 ] = x;
  92. particlePositions[ i * 3 + 1 ] = y;
  93. particlePositions[ i * 3 + 2 ] = z;
  94. // add it to the geometry
  95. particlesData.push( {
  96. velocity: new THREE.Vector3( - 1 + Math.random() * 2, - 1 + Math.random() * 2, - 1 + Math.random() * 2 ),
  97. numConnections: 0
  98. } );
  99. }
  100. particles.setDrawRange( 0, particleCount );
  101. particles.setAttribute( 'position', new THREE.BufferAttribute( particlePositions, 3 ).setUsage( THREE.DynamicDrawUsage ) );
  102. // create the particle system
  103. pointCloud = new THREE.Points( particles, pMaterial );
  104. group.add( pointCloud );
  105. const geometry = new THREE.BufferGeometry();
  106. geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).setUsage( THREE.DynamicDrawUsage ) );
  107. geometry.setAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).setUsage( THREE.DynamicDrawUsage ) );
  108. geometry.computeBoundingSphere();
  109. geometry.setDrawRange( 0, 0 );
  110. const material = new THREE.LineBasicMaterial( {
  111. vertexColors: true,
  112. blending: THREE.AdditiveBlending,
  113. transparent: true
  114. } );
  115. linesMesh = new THREE.LineSegments( geometry, material );
  116. group.add( linesMesh );
  117. //
  118. renderer = new THREE.WebGLRenderer( { antialias: true } );
  119. renderer.setPixelRatio( window.devicePixelRatio );
  120. renderer.setSize( window.innerWidth, window.innerHeight );
  121. renderer.outputEncoding = THREE.sRGBEncoding;
  122. container.appendChild( renderer.domElement );
  123. //
  124. stats = new Stats();
  125. container.appendChild( stats.dom );
  126. window.addEventListener( 'resize', onWindowResize );
  127. }
  128. function onWindowResize() {
  129. camera.aspect = window.innerWidth / window.innerHeight;
  130. camera.updateProjectionMatrix();
  131. renderer.setSize( window.innerWidth, window.innerHeight );
  132. }
  133. function animate() {
  134. let vertexpos = 0;
  135. let colorpos = 0;
  136. let numConnected = 0;
  137. for ( let i = 0; i < particleCount; i ++ )
  138. particlesData[ i ].numConnections = 0;
  139. for ( let i = 0; i < particleCount; i ++ ) {
  140. // get the particle
  141. const particleData = particlesData[ i ];
  142. particlePositions[ i * 3 ] += particleData.velocity.x;
  143. particlePositions[ i * 3 + 1 ] += particleData.velocity.y;
  144. particlePositions[ i * 3 + 2 ] += particleData.velocity.z;
  145. if ( particlePositions[ i * 3 + 1 ] < - rHalf || particlePositions[ i * 3 + 1 ] > rHalf )
  146. particleData.velocity.y = - particleData.velocity.y;
  147. if ( particlePositions[ i * 3 ] < - rHalf || particlePositions[ i * 3 ] > rHalf )
  148. particleData.velocity.x = - particleData.velocity.x;
  149. if ( particlePositions[ i * 3 + 2 ] < - rHalf || particlePositions[ i * 3 + 2 ] > rHalf )
  150. particleData.velocity.z = - particleData.velocity.z;
  151. if ( effectController.limitConnections && particleData.numConnections >= effectController.maxConnections )
  152. continue;
  153. // Check collision
  154. for ( let j = i + 1; j < particleCount; j ++ ) {
  155. const particleDataB = particlesData[ j ];
  156. if ( effectController.limitConnections && particleDataB.numConnections >= effectController.maxConnections )
  157. continue;
  158. const dx = particlePositions[ i * 3 ] - particlePositions[ j * 3 ];
  159. const dy = particlePositions[ i * 3 + 1 ] - particlePositions[ j * 3 + 1 ];
  160. const dz = particlePositions[ i * 3 + 2 ] - particlePositions[ j * 3 + 2 ];
  161. const dist = Math.sqrt( dx * dx + dy * dy + dz * dz );
  162. if ( dist < effectController.minDistance ) {
  163. particleData.numConnections ++;
  164. particleDataB.numConnections ++;
  165. const alpha = 1.0 - dist / effectController.minDistance;
  166. positions[ vertexpos ++ ] = particlePositions[ i * 3 ];
  167. positions[ vertexpos ++ ] = particlePositions[ i * 3 + 1 ];
  168. positions[ vertexpos ++ ] = particlePositions[ i * 3 + 2 ];
  169. positions[ vertexpos ++ ] = particlePositions[ j * 3 ];
  170. positions[ vertexpos ++ ] = particlePositions[ j * 3 + 1 ];
  171. positions[ vertexpos ++ ] = particlePositions[ j * 3 + 2 ];
  172. colors[ colorpos ++ ] = alpha;
  173. colors[ colorpos ++ ] = alpha;
  174. colors[ colorpos ++ ] = alpha;
  175. colors[ colorpos ++ ] = alpha;
  176. colors[ colorpos ++ ] = alpha;
  177. colors[ colorpos ++ ] = alpha;
  178. numConnected ++;
  179. }
  180. }
  181. }
  182. linesMesh.geometry.setDrawRange( 0, numConnected * 2 );
  183. linesMesh.geometry.attributes.position.needsUpdate = true;
  184. linesMesh.geometry.attributes.color.needsUpdate = true;
  185. pointCloud.geometry.attributes.position.needsUpdate = true;
  186. requestAnimationFrame( animate );
  187. stats.update();
  188. render();
  189. }
  190. function render() {
  191. const time = Date.now() * 0.001;
  192. group.rotation.y = time * 0.1;
  193. renderer.render( scene, camera );
  194. }
  195. </script>
  196. </body>
  197. </html>