x_ite 5.0.2 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/.vscode/settings.json +12 -5
  2. package/.vscode/tasks.json +21 -0
  3. package/Makefile +10 -15
  4. package/README.md +6 -11
  5. package/build/bin/dist.pl +0 -6
  6. package/build/bin/version.pl +1 -4
  7. package/dist/assets/components/annotation.js +2 -2
  8. package/dist/assets/components/annotation.min.js +1 -1
  9. package/dist/assets/components/cad-geometry.js +2 -2
  10. package/dist/assets/components/cad-geometry.min.js +1 -1
  11. package/dist/assets/components/cube-map-texturing.js +6 -19
  12. package/dist/assets/components/cube-map-texturing.min.js +1 -1
  13. package/dist/assets/components/dis.js +2 -2
  14. package/dist/assets/components/dis.min.js +1 -1
  15. package/dist/assets/components/event-utilities.js +3 -3
  16. package/dist/assets/components/event-utilities.min.js +1 -1
  17. package/dist/assets/components/geometry2d.js +4 -4
  18. package/dist/assets/components/geometry2d.min.js +1 -1
  19. package/dist/assets/components/geospatial.js +32 -1685
  20. package/dist/assets/components/geospatial.min.js +1 -1
  21. package/dist/assets/components/h-anim.js +70 -77
  22. package/dist/assets/components/h-anim.min.js +1 -1
  23. package/dist/assets/components/key-device-sensor.js +3 -3
  24. package/dist/assets/components/key-device-sensor.min.js +1 -1
  25. package/dist/assets/components/layout.js +38 -52
  26. package/dist/assets/components/layout.min.js +1 -1
  27. package/dist/assets/components/nurbs.js +277 -194
  28. package/dist/assets/components/nurbs.min.js +1 -1
  29. package/dist/assets/components/particle-systems.js +1918 -1658
  30. package/dist/assets/components/particle-systems.min.js +1 -1
  31. package/dist/assets/components/picking.js +33 -41
  32. package/dist/assets/components/picking.min.js +1 -1
  33. package/dist/assets/components/projective-texture-mapping.js +72 -86
  34. package/dist/assets/components/projective-texture-mapping.min.js +1 -1
  35. package/dist/assets/components/rigid-body-physics.js +36 -57
  36. package/dist/assets/components/rigid-body-physics.min.js +1 -1
  37. package/dist/assets/components/scripting.js +2 -2
  38. package/dist/assets/components/scripting.min.js +1 -1
  39. package/dist/assets/components/texturing-3d.js +26 -75
  40. package/dist/assets/components/texturing-3d.min.js +3 -3
  41. package/dist/assets/components/volume-rendering.js +10 -10
  42. package/dist/assets/components/volume-rendering.min.js +1 -1
  43. package/dist/assets/components/x_ite.js +2 -2
  44. package/dist/assets/components/x_ite.min.js +1 -1
  45. package/dist/assets/linetype/1.png +0 -0
  46. package/dist/assets/linetype/10.png +0 -0
  47. package/dist/assets/linetype/11.png +0 -0
  48. package/dist/assets/linetype/12.png +0 -0
  49. package/dist/assets/linetype/13.png +0 -0
  50. package/dist/assets/linetype/14.png +0 -0
  51. package/dist/assets/linetype/15.png +0 -0
  52. package/dist/assets/linetype/16.png +0 -0
  53. package/dist/assets/linetype/2.png +0 -0
  54. package/dist/assets/linetype/3.png +0 -0
  55. package/dist/assets/linetype/4.png +0 -0
  56. package/dist/assets/linetype/5.png +0 -0
  57. package/dist/assets/linetype/6.png +0 -0
  58. package/dist/assets/linetype/7.png +0 -0
  59. package/dist/assets/linetype/8.png +0 -0
  60. package/dist/assets/linetype/9.png +0 -0
  61. package/dist/assets/shaders/webgl1/Line.fs +0 -21
  62. package/dist/assets/shaders/webgl1/Line.vs +0 -10
  63. package/dist/assets/shaders/webgl1/PBR.vs +1 -1
  64. package/dist/assets/shaders/webgl2/Depth.vs +29 -1
  65. package/dist/assets/shaders/webgl2/Gouraud.vs +31 -3
  66. package/dist/assets/shaders/webgl2/Line.fs +24 -12
  67. package/dist/assets/shaders/webgl2/Line.vs +36 -11
  68. package/dist/assets/shaders/webgl2/LineTransform.fs +4 -0
  69. package/dist/assets/shaders/webgl2/LineTransform.vs +57 -0
  70. package/dist/assets/shaders/webgl2/PBR.vs +35 -7
  71. package/dist/assets/shaders/webgl2/Phong.vs +31 -3
  72. package/dist/assets/shaders/webgl2/Point.vs +29 -1
  73. package/dist/assets/shaders/webgl2/Unlit.vs +31 -3
  74. package/dist/example.html +6 -6
  75. package/dist/x_ite.css +180 -208
  76. package/dist/x_ite.js +16477 -16629
  77. package/dist/x_ite.min.js +17 -17
  78. package/dist/x_ite.zip +0 -0
  79. package/docs/404.md +6 -0
  80. package/docs/Accessing-the-External-Browser.md +20 -14
  81. package/docs/Browser-Support.md +6 -0
  82. package/docs/Custom-Shaders.md +17 -24
  83. package/docs/Features.md +7 -1
  84. package/docs/Gemfile +44 -0
  85. package/docs/Gemfile.lock +122 -0
  86. package/docs/Glossary.md +6 -0
  87. package/docs/How-To-Configure-Your-Web-Server.md +6 -0
  88. package/docs/Supported-Nodes.md +9 -1
  89. package/docs/What's-New.md +31 -0
  90. package/docs/XHTML-DOM-Integration.md +6 -0
  91. package/docs/_config.yml +1 -1
  92. package/docs/assets/css/main.scss +26 -0
  93. package/docs/index.md +38 -46
  94. package/docs/reference/Browser-Services.md +9 -3
  95. package/docs/reference/Constants-Services.md +6 -0
  96. package/docs/reference/ECMAScript-Object-and-Function-Definitions.md +6 -0
  97. package/docs/reference/Field-Services-and-Objects.md +6 -0
  98. package/docs/reference/Prototype-Services.md +6 -0
  99. package/docs/reference/Route-Services.md +6 -0
  100. package/docs/reference/Scene-Services.md +8 -2
  101. package/docs/reference/Script-Node-Authoring-Interface.md +7 -1
  102. package/docs/tutorials/Adding-backgrounds.md +6 -0
  103. package/docs/tutorials/Adding-fog.md +6 -0
  104. package/docs/tutorials/Adding-sound.md +6 -0
  105. package/docs/tutorials/Animating-transforms.md +6 -0
  106. package/docs/tutorials/Basic-Nodes.md +6 -0
  107. package/docs/tutorials/Building-a-X3D-world.md +6 -0
  108. package/docs/tutorials/Building-elevation-grids.md +6 -0
  109. package/docs/tutorials/Building-extruded-shapes.md +6 -0
  110. package/docs/tutorials/Building-primitive-shapes.md +6 -0
  111. package/docs/tutorials/Building-shapes-out-of-points,-lines,-and-faces.md +6 -0
  112. package/docs/tutorials/Controlling-appearance-with-materials.md +6 -0
  113. package/docs/tutorials/Controlling-color-on-coordinate-based-geometry.md +6 -0
  114. package/docs/tutorials/Controlling-detail.md +6 -0
  115. package/docs/tutorials/Controlling-how-textures-are-mapped.md +6 -0
  116. package/docs/tutorials/Controlling-navigation.md +6 -0
  117. package/docs/tutorials/Controlling-shading-on-coordinate-based-geometry.md +6 -0
  118. package/docs/tutorials/Controlling-the-viewpoint.md +6 -0
  119. package/docs/tutorials/Creating-new-node-types.md +6 -0
  120. package/docs/tutorials/Grouping-nodes.md +6 -0
  121. package/docs/tutorials/Hello,-World!.md +6 -0
  122. package/docs/tutorials/Improving-Performance.md +6 -0
  123. package/docs/tutorials/Increasing-Rendering-Speed.md +6 -0
  124. package/docs/tutorials/Introducing-X3D.md +6 -0
  125. package/docs/tutorials/Introducing-animation.md +6 -0
  126. package/docs/tutorials/Introducing-script-use.md +6 -0
  127. package/docs/tutorials/Lighting-your-world.md +6 -0
  128. package/docs/tutorials/Mapping-textures.md +6 -0
  129. package/docs/tutorials/Naming-nodes.md +6 -0
  130. package/docs/tutorials/Providing-information-about-your-world.md +6 -0
  131. package/docs/tutorials/Sensing-the-viewer.md +6 -0
  132. package/docs/tutorials/Sensing-viewer-actions.md +6 -0
  133. package/docs/tutorials/Transforming-Shapes.md +6 -0
  134. package/docs/tutorials/Writing-program-scripts-with-ECMAScript.md +6 -0
  135. package/docs/tutorials/index.md +6 -0
  136. package/package.json +6 -7
  137. package/src/assets/components/geometry2d.js +1 -1
  138. package/src/assets/components/key-device-sensor.js +1 -1
  139. package/src/assets/components/layout.js +1 -1
  140. package/src/assets/components/particle-systems.js +1 -1
  141. package/src/assets/components/volume-rendering.js +1 -1
  142. package/src/assets/linetype/1.png +0 -0
  143. package/src/assets/linetype/10.png +0 -0
  144. package/src/assets/linetype/11.png +0 -0
  145. package/src/assets/linetype/12.png +0 -0
  146. package/src/assets/linetype/13.png +0 -0
  147. package/src/assets/linetype/14.png +0 -0
  148. package/src/assets/linetype/15.png +0 -0
  149. package/src/assets/linetype/16.png +0 -0
  150. package/src/assets/linetype/2.png +0 -0
  151. package/src/assets/linetype/3.png +0 -0
  152. package/src/assets/linetype/4.png +0 -0
  153. package/src/assets/linetype/5.png +0 -0
  154. package/src/assets/linetype/6.png +0 -0
  155. package/src/assets/linetype/7.png +0 -0
  156. package/src/assets/linetype/8.png +0 -0
  157. package/src/assets/linetype/9.png +0 -0
  158. package/src/assets/shaders/Types.glsl +1 -9
  159. package/src/assets/shaders/webgl1/Line.fs +3 -28
  160. package/src/assets/shaders/webgl1/Line.vs +5 -19
  161. package/src/assets/shaders/webgl1/PBR.vs +1 -1
  162. package/src/assets/shaders/webgl1/Point.vs +2 -3
  163. package/src/assets/shaders/webgl2/Depth.vs +4 -1
  164. package/src/assets/shaders/webgl2/Gouraud.vs +5 -3
  165. package/src/assets/shaders/webgl2/Line.fs +11 -17
  166. package/src/assets/shaders/webgl2/Line.vs +16 -20
  167. package/src/assets/shaders/webgl2/LineTransform.fs +6 -0
  168. package/src/assets/shaders/webgl2/LineTransform.vs +77 -0
  169. package/src/assets/shaders/webgl2/PBR.vs +10 -7
  170. package/src/assets/shaders/webgl2/Phong.vs +6 -3
  171. package/src/assets/shaders/webgl2/Point.vs +6 -6
  172. package/src/assets/shaders/webgl2/Unlit.vs +6 -3
  173. package/src/assets/shaders/webgl2/include/Line2.glsl +20 -0
  174. package/src/assets/shaders/webgl2/include/Particle.glsl +36 -0
  175. package/src/example.html +6 -6
  176. package/src/standard/Math/Algorithm.js +12 -28
  177. package/src/standard/Math/Geometry/Plane3.js +0 -2
  178. package/src/standard/Math/Geometry/ViewVolume.js +88 -83
  179. package/src/standard/Math/Numbers/Color3.js +6 -0
  180. package/src/standard/Math/Numbers/Color4.js +7 -0
  181. package/src/standard/Math/Numbers/Complex.js +5 -0
  182. package/src/standard/Math/Numbers/Matrix2.js +20 -2
  183. package/src/standard/Math/Numbers/Matrix3.js +129 -110
  184. package/src/standard/Math/Numbers/Matrix4.js +138 -119
  185. package/src/standard/Math/Numbers/Quaternion.js +7 -0
  186. package/src/standard/Math/Numbers/Rotation4.js +7 -0
  187. package/src/standard/Math/Numbers/Vector2.js +8 -5
  188. package/src/standard/Math/Numbers/Vector3.js +16 -10
  189. package/src/standard/Math/Numbers/Vector4.js +12 -7
  190. package/src/standard/Math/Utility/BVH.js +45 -17
  191. package/src/tests.js +6 -1
  192. package/src/x_ite/Base/X3DBaseNode.js +22 -11
  193. package/src/x_ite/Base/X3DField.js +1 -1
  194. package/src/x_ite/Browser/Core/BrowserOptions.js +2 -2
  195. package/src/x_ite/Browser/Core/BrowserTimings.js +4 -2
  196. package/src/x_ite/Browser/Core/Context.js +185 -0
  197. package/src/x_ite/Browser/Core/ContextMenu.js +299 -193
  198. package/src/x_ite/Browser/Core/Notification.js +1 -0
  199. package/src/x_ite/Browser/Core/X3DCoreContext.js +35 -146
  200. package/src/x_ite/Browser/Layout/ScreenText.js +11 -4
  201. package/src/x_ite/Browser/Layout/X3DLayoutContext.js +4 -15
  202. package/src/x_ite/Browser/Navigation/ExamineViewer.js +12 -19
  203. package/src/x_ite/Browser/Navigation/LookAtViewer.js +0 -3
  204. package/src/x_ite/Browser/Navigation/PlaneViewer.js +0 -3
  205. package/src/x_ite/Browser/Navigation/X3DFlyViewer.js +14 -7
  206. package/src/x_ite/Browser/Navigation/X3DViewer.js +12 -20
  207. package/src/x_ite/Browser/Networking/X3DNetworkingContext.js +11 -7
  208. package/src/x_ite/Browser/ParticleSystems/BVH.glsl +183 -0
  209. package/src/x_ite/Browser/ParticleSystems/Box3.glsl +47 -0
  210. package/src/x_ite/Browser/ParticleSystems/GeometryTypes.js +66 -0
  211. package/src/x_ite/Browser/ParticleSystems/Line3.glsl +55 -0
  212. package/src/x_ite/Browser/ParticleSystems/Plane3.glsl +160 -0
  213. package/src/x_ite/Browser/PointingDeviceSensor/PointingDevice.js +27 -3
  214. package/src/x_ite/Browser/PointingDeviceSensor/X3DPointingDeviceSensorContext.js +37 -37
  215. package/src/x_ite/Browser/Rendering/X3DRenderingContext.js +19 -13
  216. package/src/x_ite/Browser/Shaders/Shader.js +33 -12
  217. package/src/x_ite/Browser/Shaders/ShaderSource.js +6 -0
  218. package/src/x_ite/Browser/Shaders/ShaderTest.js +16 -10
  219. package/src/x_ite/Browser/Shape/X3DShapeContext.js +50 -9
  220. package/src/x_ite/Browser/Text/X3DTextContext.js +4 -13
  221. package/src/x_ite/Browser/Texturing/X3DTexturingContext.js +23 -33
  222. package/src/x_ite/Browser/Texturing3D/DICOMParser.js +2 -2
  223. package/src/x_ite/Browser/Time/X3DTimeContext.js +3 -1
  224. package/src/x_ite/Browser/VERSION.js +1 -1
  225. package/src/x_ite/Browser/X3DBrowser.js +7 -6
  226. package/src/x_ite/Browser/X3DBrowserContext.js +35 -10
  227. package/src/x_ite/Components/Core/X3DNode.js +4 -0
  228. package/src/x_ite/Components/Core/X3DPrototypeInstance.js +0 -2
  229. package/src/x_ite/Components/CubeMapTexturing/ComposedCubeMapTexture.js +3 -4
  230. package/src/x_ite/Components/CubeMapTexturing/GeneratedCubeMapTexture.js +1 -12
  231. package/src/x_ite/Components/CubeMapTexturing/ImageCubeMapTexture.js +0 -1
  232. package/src/x_ite/Components/EnvironmentalEffects/TextureBackground.js +1 -1
  233. package/src/x_ite/Components/EnvironmentalEffects/X3DBackgroundNode.js +76 -77
  234. package/src/x_ite/Components/EnvironmentalEffects/X3DFogObject.js +2 -9
  235. package/src/x_ite/Components/EnvironmentalSensor/ProximitySensor.js +51 -65
  236. package/src/x_ite/Components/EventUtilities/X3DSequencerNode.js +1 -1
  237. package/src/x_ite/Components/Followers/X3DChaserNode.js +18 -32
  238. package/src/x_ite/Components/Followers/X3DDamperNode.js +1 -6
  239. package/src/x_ite/Components/Geometry2D/TriangleSet2D.js +1 -1
  240. package/src/x_ite/Components/Geometry3D/ElevationGrid.js +12 -4
  241. package/src/x_ite/Components/Geometry3D/IndexedFaceSet.js +4 -4
  242. package/src/x_ite/Components/Geospatial/GeoCoordinate.js +10 -27
  243. package/src/x_ite/Components/Geospatial/GeoPositionInterpolator.js +5 -10
  244. package/src/x_ite/Components/Geospatial/GeoTouchSensor.js +9 -16
  245. package/src/x_ite/Components/Geospatial/GeoTransform.js +6 -18
  246. package/src/x_ite/Components/Geospatial/X3DGeospatialObject.js +20 -27
  247. package/src/x_ite/Components/Grouping/X3DGroupingNode.js +8 -8
  248. package/src/x_ite/Components/Grouping/X3DTransformNode.js +0 -4
  249. package/src/x_ite/Components/HAnim/HAnimHumanoid.js +68 -75
  250. package/src/x_ite/Components/Interpolation/OrientationInterpolator.js +4 -11
  251. package/src/x_ite/Components/Interpolation/X3DInterpolatorNode.js +1 -1
  252. package/src/x_ite/Components/Layout/LayoutGroup.js +4 -9
  253. package/src/x_ite/Components/Layout/ScreenFontStyle.js +1 -1
  254. package/src/x_ite/Components/Layout/ScreenGroup.js +18 -23
  255. package/src/x_ite/Components/Lighting/DirectionalLight.js +28 -36
  256. package/src/x_ite/Components/Lighting/PointLight.js +32 -47
  257. package/src/x_ite/Components/Lighting/SpotLight.js +33 -48
  258. package/src/x_ite/Components/Navigation/Billboard.js +49 -56
  259. package/src/x_ite/Components/Navigation/LOD.js +1 -1
  260. package/src/x_ite/Components/Navigation/X3DViewpointNode.js +82 -111
  261. package/src/x_ite/Components/Networking/Anchor.js +10 -4
  262. package/src/x_ite/Components/ParticleSystems/BoundedPhysicsModel.js +6 -6
  263. package/src/x_ite/Components/ParticleSystems/ConeEmitter.js +44 -36
  264. package/src/x_ite/Components/ParticleSystems/ExplosionEmitter.js +26 -17
  265. package/src/x_ite/Components/ParticleSystems/ForcePhysicsModel.js +20 -7
  266. package/src/x_ite/Components/ParticleSystems/ParticleSystem.js +461 -876
  267. package/src/x_ite/Components/ParticleSystems/PointEmitter.js +39 -35
  268. package/src/x_ite/Components/ParticleSystems/PolylineEmitter.js +112 -128
  269. package/src/x_ite/Components/ParticleSystems/SurfaceEmitter.js +105 -112
  270. package/src/x_ite/Components/ParticleSystems/VolumeEmitter.js +138 -176
  271. package/src/x_ite/Components/ParticleSystems/WindPhysicsModel.js +16 -11
  272. package/src/x_ite/Components/ParticleSystems/X3DParticleEmitterNode.js +807 -217
  273. package/src/x_ite/Components/Picking/LinePickSensor.js +31 -39
  274. package/src/x_ite/Components/PointingDeviceSensor/CylinderSensor.js +90 -107
  275. package/src/x_ite/Components/PointingDeviceSensor/PlaneSensor.js +48 -55
  276. package/src/x_ite/Components/PointingDeviceSensor/SphereSensor.js +53 -70
  277. package/src/x_ite/Components/PointingDeviceSensor/TouchSensor.js +8 -15
  278. package/src/x_ite/Components/ProjectiveTextureMapping/TextureProjectorParallel.js +43 -50
  279. package/src/x_ite/Components/ProjectiveTextureMapping/TextureProjectorPerspective.js +32 -39
  280. package/src/x_ite/Components/Rendering/ClipPlane.js +3 -11
  281. package/src/x_ite/Components/Rendering/Color.js +12 -37
  282. package/src/x_ite/Components/Rendering/ColorRGBA.js +13 -38
  283. package/src/x_ite/Components/Rendering/IndexedLineSet.js +12 -4
  284. package/src/x_ite/Components/Rendering/LineSet.js +21 -13
  285. package/src/x_ite/Components/Rendering/PointSet.js +21 -13
  286. package/src/x_ite/Components/Rendering/X3DColorNode.js +13 -0
  287. package/src/x_ite/Components/Rendering/X3DComposedGeometryNode.js +13 -5
  288. package/src/x_ite/Components/Rendering/X3DGeometryNode.js +248 -325
  289. package/src/x_ite/Components/Rendering/X3DLineGeometryNode.js +305 -134
  290. package/src/x_ite/Components/Rendering/X3DPointGeometryNode.js +99 -122
  291. package/src/x_ite/Components/RigidBodyPhysics/DoubleAxisHingeJoint.js +24 -38
  292. package/src/x_ite/Components/RigidBodyPhysics/SingleAxisHingeJoint.js +10 -17
  293. package/src/x_ite/Components/Shaders/ComposedShader.js +35 -75
  294. package/src/x_ite/Components/Shaders/FloatVertexAttribute.js +5 -15
  295. package/src/x_ite/Components/Shaders/Matrix3VertexAttribute.js +7 -24
  296. package/src/x_ite/Components/Shaders/Matrix4VertexAttribute.js +7 -24
  297. package/src/x_ite/Components/Shaders/ShaderPart.js +1 -10
  298. package/src/x_ite/Components/Shaders/X3DProgrammableShaderObject.js +219 -209
  299. package/src/x_ite/Components/Shaders/X3DShaderNode.js +1 -1
  300. package/src/x_ite/Components/Shaders/X3DVertexAttributeNode.js +23 -1
  301. package/src/x_ite/Components/Shape/Appearance.js +12 -0
  302. package/src/x_ite/Components/Shape/FillProperties.js +12 -1
  303. package/src/x_ite/Components/Shape/LineProperties.js +33 -1
  304. package/src/x_ite/Components/Shape/PointProperties.js +23 -1
  305. package/src/x_ite/Components/Shape/Shape.js +27 -34
  306. package/src/x_ite/Components/Sound/Sound.js +30 -40
  307. package/src/x_ite/Components/Text/Text.js +6 -20
  308. package/src/x_ite/Components/Texturing/TextureCoordinate.js +5 -26
  309. package/src/x_ite/Components/Texturing/TextureProperties.js +4 -4
  310. package/src/x_ite/Components/Texturing/X3DSingleTextureCoordinateNode.js +21 -0
  311. package/src/x_ite/Components/Texturing/X3DSingleTextureNode.js +5 -4
  312. package/src/x_ite/Components/Texturing/X3DTexture2DNode.js +24 -33
  313. package/src/x_ite/Components/Texturing3D/TextureCoordinate3D.js +5 -26
  314. package/src/x_ite/Components/Texturing3D/TextureCoordinate4D.js +5 -26
  315. package/src/x_ite/Components/Texturing3D/X3DTexture3DNode.js +12 -19
  316. package/src/x_ite/Components/VolumeRendering/X3DVolumeDataNode.js +7 -7
  317. package/src/x_ite/Components.js +2 -2
  318. package/src/x_ite/Fallback.js +9 -3
  319. package/src/x_ite/Fields/SFColor.js +4 -0
  320. package/src/x_ite/Fields/SFColorRGBA.js +4 -0
  321. package/src/x_ite/Fields/SFMatrixPrototypeTemplate.js +4 -0
  322. package/src/x_ite/Fields/SFRotation.js +4 -0
  323. package/src/x_ite/Fields/SFString.js +4 -0
  324. package/src/x_ite/Fields/SFVecPrototypeTemplate.js +4 -0
  325. package/src/x_ite/Parser/XMLParser.js +1 -1
  326. package/src/x_ite/Rendering/TextureBuffer.js +43 -36
  327. package/src/x_ite/Rendering/VertexArray.js +101 -0
  328. package/src/x_ite/Rendering/X3DRenderObject.js +123 -144
  329. package/src/x_ite/X3D.js +32 -26
  330. package/src/x_ite.config.js +0 -5
  331. package/src/x_ite.css +200 -162
  332. package/src/x_ite.html +26 -10
  333. package/src/x_ite.js +42 -0
  334. package/x_ite.min.html +26 -10
  335. package/dist/assets/hatching/0.png +0 -0
  336. package/dist/assets/linetype/0.png +0 -0
  337. package/src/assets/hatching/0.png +0 -0
  338. package/src/assets/linetype/0.png +0 -0
  339. package/src/spinner.css +0 -67
  340. package/src/x_ite/Browser/Shape/LineStipples.xcf +0 -0
@@ -4,8 +4,87 @@
4
4
  var module = { }, exports, process;
5
5
 
6
6
  const
7
- define = window [Symbol .for ("X_ITE.X3D-5.0.2")] .define,
8
- require = window [Symbol .for ("X_ITE.X3D-5.0.2")] .require;
7
+ define = window [Symbol .for ("X_ITE.X3D-6.0.0")] .define,
8
+ require = window [Symbol .for ("X_ITE.X3D-6.0.0")] .require;
9
+ /* -*- Mode: JavaScript; coding: utf-8; tab-width: 3; indent-tabs-mode: tab; c-basic-offset: 3 -*-
10
+ *******************************************************************************
11
+ *
12
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
13
+ *
14
+ * Copyright create3000, Scheffelstraße 31a, Leipzig, Germany 2011.
15
+ *
16
+ * All rights reserved. Holger Seelig <holger.seelig@yahoo.de>.
17
+ *
18
+ * The copyright notice above does not evidence any actual of intended
19
+ * publication of such source code, and is an unpublished work by create3000.
20
+ * This material contains CONFIDENTIAL INFORMATION that is the property of
21
+ * create3000.
22
+ *
23
+ * No permission is granted to copy, distribute, or create derivative works from
24
+ * the contents of this software, in whole or in part, without the prior written
25
+ * permission of create3000.
26
+ *
27
+ * NON-MILITARY USE ONLY
28
+ *
29
+ * All create3000 software are effectively free software with a non-military use
30
+ * restriction. It is free. Well commented source is provided. You may reuse the
31
+ * source in any way you please with the exception anything that uses it must be
32
+ * marked to indicate is contains 'non-military use only' components.
33
+ *
34
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
35
+ *
36
+ * Copyright 2015, 2016 Holger Seelig <holger.seelig@yahoo.de>.
37
+ *
38
+ * This file is part of the X_ITE Project.
39
+ *
40
+ * X_ITE is free software: you can redistribute it and/or modify it under the
41
+ * terms of the GNU General Public License version 3 only, as published by the
42
+ * Free Software Foundation.
43
+ *
44
+ * X_ITE is distributed in the hope that it will be useful, but WITHOUT ANY
45
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
46
+ * A PARTICULAR PURPOSE. See the GNU General Public License version 3 for more
47
+ * details (a copy is included in the LICENSE file that accompanied this code).
48
+ *
49
+ * You should have received a copy of the GNU General Public License version 3
50
+ * along with X_ITE. If not, see <http://www.gnu.org/licenses/gpl.html> for a
51
+ * copy of the GPLv3 License.
52
+ *
53
+ * For Silvio, Joy and Adi.
54
+ *
55
+ ******************************************************************************/
56
+
57
+
58
+ define ('x_ite/Browser/ParticleSystems/GeometryTypes',[],function ()
59
+ {
60
+ "use strict";
61
+
62
+ let i = 0;
63
+
64
+ const GeometryTypes = {
65
+ POINT: i ++,
66
+ LINE: i ++,
67
+ TRIANGLE: i ++,
68
+ QUAD: i ++,
69
+ SPRITE: i ++,
70
+ GEOMETRY: i ++,
71
+ };
72
+
73
+ return GeometryTypes;
74
+ });
75
+
76
+
77
+ define('text!x_ite/Browser/ParticleSystems/Line3.glsl',[],function () { return 'struct Line3 {\n vec3 point;\n vec3 direction;\n};\n\n// Line3\n// line3 (const in vec3 point1, const in vec3 point2)\n// {\n// return Line3 (point1, normalize (point2 - point1));\n// }\n\n/* Line intersect triangle */\n\nbool\nintersects (const in Line3 line, const in vec3 a, const in vec3 b, const in vec3 c, out vec3 r)\n{\n // find vectors for two edges sharing vert0\n vec3 edge1 = b - a;\n vec3 edge2 = c - a;\n\n // begin calculating determinant - also used to calculate U parameter\n vec3 pvec = cross (line .direction, edge2);\n\n // if determinant is near zero, ray lies in plane of triangle\n float det = dot (edge1, pvec);\n\n // Non culling intersection\n\n if (det == 0.0)\n return false;\n\n float inv_det = 1.0 / det;\n\n // calculate distance from vert0 to ray point\n vec3 tvec = line .point - a;\n\n // calculate U parameter and test bounds\n float u = dot (tvec, pvec) * inv_det;\n\n if (u < 0.0 || u > 1.0)\n return false;\n\n // prepare to test V parameter\n vec3 qvec = cross (tvec, edge1);\n\n // calculate V parameter and test bounds\n float v = dot (line .direction, qvec) * inv_det;\n\n if (v < 0.0 || u + v > 1.0)\n return false;\n\n r = vec3 (u, v, 1.0 - u - v);\n\n return true;\n}\n';});
78
+
79
+
80
+ define('text!x_ite/Browser/ParticleSystems/Plane3.glsl',[],function () { return 'struct Plane3\n{\n vec3 normal;\n float distanceFromOrigin;\n};\n\nPlane3\nplane3 (const in vec3 point, const in vec3 normal)\n{\n return Plane3 (normal, dot (normal, point));\n}\n\nfloat\nplane_distance (const in Plane3 plane, const in vec3 point)\n{\n return dot (point, plane .normal) - plane .distanceFromOrigin;\n}\n\n/* Plane intersect line */\nbool\nintersects (const in Plane3 plane, const in Line3 line, out vec3 point)\n{\n // Check if the line is parallel to the plane.\n float theta = dot (line .direction, plane .normal);\n\n // Plane and line are parallel.\n if (theta == 0.0)\n return false;\n\n // Plane and line are not parallel. The intersection point can be calculated now.\n float t = (plane .distanceFromOrigin - dot (plane .normal, line .point)) / theta;\n\n point = line .point + line .direction * t;\n\n return true;\n}\n\n/* Find find the first point that is farther to the plane than value. */\n// int\n// upper_bound (const in vec4 points [ARRAY_SIZE], in int count, const in float value, const in Plane3 plane)\n// {\n// int first = 0;\n// int step = 0;\n\n// while (count > 0)\n// {\n// int index = first;\n\n// step = count >> 1;\n\n// index += step;\n\n// if (value < plane_distance (plane, points [index] .xyz))\n// {\n// count = step;\n// }\n// else\n// {\n// first = ++ index;\n// count -= step + 1;\n// }\n// }\n\n// return first;\n// }\n\n/* CombSort: sort points in distance to a plane. */\nvoid\nsort (inout vec4 points [ARRAY_SIZE], const in int count, const in Plane3 plane)\n{\n const float shrink = 1.0 / 1.3;\n\n int gap = count;\n bool exchanged = true;\n\n while (exchanged)\n {\n gap = int (float (gap) * shrink);\n\n if (gap <= 1)\n {\n exchanged = false;\n gap = 1;\n }\n\n for (int i = 0, l = count - gap; i < l; ++ i)\n {\n int j = gap + i;\n\n if (plane_distance (plane, points [i] .xyz) > plane_distance (plane, points [j] .xyz))\n {\n vec4 tmp1 = points [i];\n points [i] = points [j];\n points [j] = tmp1;\n\n exchanged = true;\n }\n }\n }\n}\n\n\n// /* CombSort: sort points and normals in distance to a plane. */\n// void\n// sort (inout vec4 points [ARRAY_SIZE], inout vec3 normals [ARRAY_SIZE], const in int count, const in Plane3 plane)\n// {\n// const float shrink = 1.0 / 1.3;\n\n// int gap = count;\n// bool exchanged = true;\n\n// while (exchanged)\n// {\n// gap = int (float (gap) * shrink);\n\n// if (gap <= 1)\n// {\n// exchanged = false;\n// gap = 1;\n// }\n\n// for (int i = 0, l = count - gap; i < l; ++ i)\n// {\n// int j = gap + i;\n\n// if (plane_distance (plane, points [i] .xyz) > plane_distance (plane, points [j] .xyz))\n// {\n// vec4 tmp1 = points [i];\n// points [i] = points [j];\n// points [j] = tmp1;\n\n// vec3 tmp2 = normals [i];\n// normals [i] = normals [j];\n// normals [j] = tmp2;\n\n// exchanged = true;\n// }\n// }\n// }\n// }\n\nint\nmin_index (const in vec4 points [ARRAY_SIZE], const in int count, const in float value, const in Plane3 plane)\n{\n int index = -1;\n float dist = 1000000.0;\n\n for (int i = 0; i < count; ++ i)\n {\n float d = plane_distance (plane, points [i] .xyz);\n\n if (d >= value && d < dist)\n {\n dist = d;\n index = i;\n }\n }\n\n return index;\n}\n';});
81
+
82
+
83
+ define('text!x_ite/Browser/ParticleSystems/Box3.glsl',[],function () { return 'bool\nintersects (const in vec3 min, const in vec3 max, const in Line3 line)\n{\n vec3 intersection;\n\n // front\n\n if (intersects (plane3 (max, vec3 (0.0, 0.0, 1.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xy, max .xy), vec4 (min .xy, intersection .xy))))\n return true;\n }\n\n // back\n\n if (intersects (plane3 (min, vec3 (0.0, 0.0, -1.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xy, max .xy), vec4 (min .xy, intersection .xy))))\n return true;\n }\n\n // top\n\n if (intersects (plane3 (max, vec3 (0.0, 1.0, 0.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xz, max .xz), vec4 (min .xz, intersection .xz))))\n return true;\n }\n\n // bottom\n\n if (intersects (plane3 (min, vec3 (0.0, -1.0, 0.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xz, max .xz), vec4 (min .xz, intersection .xz))))\n return true;\n }\n\n // right\n\n if (intersects (plane3 (max, vec3 (1.0, 0.0, 0.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .yz, max .yz), vec4 (min .yz, intersection .yz))))\n return true;\n }\n\n return false;\n}\n';});
84
+
85
+
86
+ define('text!x_ite/Browser/ParticleSystems/BVH.glsl',[],function () { return '#define BVH_NODE 0\n#define BVH_TRIANGLE 1\n#define BVH_STACK_SIZE 32\n\nint bvhNodeIndex = 0;\n\nvoid\nsetBVHIndex (const in int index)\n{\n bvhNodeIndex = index;\n}\n\nint\ngetBVHRoot (const in sampler2D volume, const in int hierarchyIndex, const in int rootIndex)\n{\n return int (texelFetch (volume, rootIndex, 0) .x) + hierarchyIndex;\n}\n\nint\ngetBVHType (const in sampler2D volume)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .x);\n}\n\nvec3\ngetBVHMin (const in sampler2D volume)\n{\n return texelFetch (volume, bvhNodeIndex + 1, 0) .xyz;\n}\n\nvec3\ngetBVHMax (const in sampler2D volume)\n{\n return texelFetch (volume, bvhNodeIndex + 2, 0) .xyz;\n}\n\nint\ngetBVHLeft (const in sampler2D volume, const in int hierarchyIndex)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .y) + hierarchyIndex;\n}\n\nint\ngetBVHRight (const in sampler2D volume, const in int hierarchyIndex)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .z) + hierarchyIndex;\n}\n\nint\ngetBVHTriangle (const in sampler2D volume)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .y);\n}\n\n/* Ray triangle intersection test */\n\nint\ngetIntersections (const in sampler2D volume, const in int verticesIndex, const in int hierarchyIndex, const in int rootIndex, const in Line3 line, out vec4 points [ARRAY_SIZE])\n{\n int current = getBVHRoot (volume, hierarchyIndex, rootIndex);\n int count = 0;\n int stackIndex = -1;\n int stack [BVH_STACK_SIZE];\n\n while (stackIndex >= 0 || current >= 0)\n {\n if (current >= 0)\n {\n setBVHIndex (current);\n\n if (getBVHType (volume) == BVH_NODE)\n {\n // Node\n\n if (intersects (getBVHMin (volume), getBVHMax (volume), line))\n {\n stack [++ stackIndex] = current;\n\n current = getBVHLeft (volume, hierarchyIndex);\n }\n else\n {\n current = -1;\n }\n }\n else\n {\n // Triangle\n\n int t = getBVHTriangle (volume);\n int v = verticesIndex + t;\n vec3 r = vec3 (0.0);\n\n vec3 a = texelFetch (volume, v, 0) .xyz;\n vec3 b = texelFetch (volume, v + 1, 0) .xyz;\n vec3 c = texelFetch (volume, v + 2, 0) .xyz;\n\n if (intersects (line, a, b, c, r))\n points [count ++] = vec4 (r .z * a + r .x * b + r .y * c, 1.0);\n\n current = -1;\n }\n }\n else\n {\n setBVHIndex (stack [stackIndex --]);\n\n current = getBVHRight (volume, hierarchyIndex);\n }\n }\n\n return count;\n}\n\nint\ngetIntersections (const in sampler2D volume, const in int verticesIndex, const in int normalsIndex, const in int hierarchyIndex, const in int rootIndex, const in Line3 line, out vec4 points [ARRAY_SIZE], out vec3 normals [ARRAY_SIZE])\n{\n int current = getBVHRoot (volume, hierarchyIndex, rootIndex);\n int count = 0;\n int stackIndex = -1;\n int stack [BVH_STACK_SIZE];\n\n while (stackIndex >= 0 || current >= 0)\n {\n if (current >= 0)\n {\n setBVHIndex (current);\n\n if (getBVHType (volume) == BVH_NODE)\n {\n // Node\n\n if (intersects (getBVHMin (volume), getBVHMax (volume), line))\n {\n stack [++ stackIndex] = current;\n\n current = getBVHLeft (volume, hierarchyIndex);\n }\n else\n {\n current = -1;\n }\n }\n else\n {\n // Triangle\n\n int t = getBVHTriangle (volume);\n int v = verticesIndex + t;\n vec3 r = vec3 (0.0);\n\n vec3 a = texelFetch (volume, v, 0) .xyz;\n vec3 b = texelFetch (volume, v + 1, 0) .xyz;\n vec3 c = texelFetch (volume, v + 2, 0) .xyz;\n\n if (intersects (line, a, b, c, r))\n {\n points [count] = vec4 (r .z * a + r .x * b + r .y * c, 1.0);\n\n int n = normalsIndex + t;\n\n vec3 n0 = texelFetch (volume, n, 0) .xyz;\n vec3 n1 = texelFetch (volume, n + 1, 0) .xyz;\n vec3 n2 = texelFetch (volume, n + 2, 0) .xyz;\n\n normals [count] = save_normalize (r .z * n0 + r .x * n1 + r .y * n2);\n\n ++ count;\n }\n\n current = -1;\n }\n }\n else\n {\n setBVHIndex (stack [stackIndex --]);\n\n current = getBVHRight (volume, hierarchyIndex);\n }\n }\n\n return count;\n}\n';});
87
+
9
88
  /* -*- Mode: JavaScript; coding: utf-8; tab-width: 3; indent-tabs-mode: tab; c-basic-offset: 3 -*-
10
89
  *******************************************************************************
11
90
  *
@@ -57,41 +136,23 @@ const
57
136
 
58
137
  define ('x_ite/Components/ParticleSystems/X3DParticleEmitterNode',[
59
138
  "x_ite/Components/Core/X3DNode",
139
+ "x_ite/Browser/ParticleSystems/GeometryTypes",
60
140
  "x_ite/Base/X3DConstants",
61
- "standard/Math/Numbers/Vector3",
62
- "standard/Math/Numbers/Rotation4",
63
- "standard/Math/Geometry/Line3",
64
- "standard/Math/Geometry/Plane3",
65
- "standard/Math/Algorithm",
66
- "standard/Math/Algorithms/QuickSort",
141
+ "text!x_ite/Browser/ParticleSystems/Line3.glsl",
142
+ "text!x_ite/Browser/ParticleSystems/Plane3.glsl",
143
+ "text!x_ite/Browser/ParticleSystems/Box3.glsl",
144
+ "text!x_ite/Browser/ParticleSystems/BVH.glsl",
67
145
  ],
68
146
  function (X3DNode,
147
+ GeometryTypes,
69
148
  X3DConstants,
70
- Vector3,
71
- Rotation4,
72
- Line3,
73
- Plane3,
74
- Algorithm,
75
- QuickSort)
149
+ Line3Source,
150
+ Plane3Source,
151
+ Box3Source,
152
+ BVHSource)
76
153
  {
77
154
  "use strict";
78
155
 
79
- var
80
- normal = new Vector3 (0, 0, 0),
81
- fromPosition = new Vector3 (0, 0, 0),
82
- line = new Line3 (Vector3 .Zero, Vector3 .zAxis),
83
- plane = new Plane3 (Vector3 .Zero, Vector3 .zAxis);
84
-
85
- function PlaneCompare (a, b)
86
- {
87
- return plane .getDistanceToPoint (a) < plane .getDistanceToPoint (b);
88
- }
89
-
90
- function PlaneCompareValue (a, b)
91
- {
92
- return a < plane .getDistanceToPoint (b);
93
- }
94
-
95
156
  function X3DParticleEmitterNode (executionContext)
96
157
  {
97
158
  X3DNode .call (this, executionContext);
@@ -102,10 +163,23 @@ function (X3DNode,
102
163
  this ._mass .setUnit ("mass");
103
164
  this ._surfaceArea .setUnit ("area");
104
165
 
105
- this .rotations = [ ];
106
- this .intersections = [ ];
107
- this .intersectionNormals = [ ];
108
- this .sorter = new QuickSort (this .intersections, PlaneCompare);
166
+ this .samplers = [ ];
167
+ this .uniforms = { };
168
+ this .functions = [ ];
169
+ this .program = null;
170
+
171
+ this .addSampler ("forces");
172
+ this .addSampler ("boundedVolume");
173
+ this .addSampler ("colorRamp");
174
+ this .addSampler ("texCoordRamp");
175
+
176
+ this .addUniform ("speed", "uniform float speed;");
177
+ this .addUniform ("variation", "uniform float variation;");
178
+
179
+ this .addFunction (Line3Source);
180
+ this .addFunction (Plane3Source);
181
+ this .addFunction (Box3Source);
182
+ this .addFunction (BVHSource);
109
183
  }
110
184
 
111
185
  X3DParticleEmitterNode .prototype = Object .assign (Object .create (X3DNode .prototype),
@@ -115,26 +189,28 @@ function (X3DNode,
115
189
  {
116
190
  X3DNode .prototype .initialize .call (this);
117
191
 
118
- this ._speed .addInterest ("set_speed__", this);
192
+ const gl = this .getBrowser () .getContext ();
193
+
194
+ if (gl .getVersion () < 2)
195
+ return;
196
+
197
+ // Create program.
198
+
199
+ this .program = this .createProgram ();
200
+ this .transformFeedback = gl .createTransformFeedback ();
201
+
202
+ // Initialize fields.
203
+
204
+ this ._on .addInterest ("set_on__", this);
205
+ this ._speed .addInterest ("set_speed__", this);
119
206
  this ._variation .addInterest ("set_variation__", this);
120
- this ._mass .addInterest ("set_mass__", this);
207
+ this ._mass .addInterest ("set_mass__", this);
121
208
 
209
+ this .set_on__ ();
122
210
  this .set_speed__ ();
123
211
  this .set_variation__ ();
124
212
  this .set_mass__ ();
125
213
  },
126
- set_speed__: function ()
127
- {
128
- this .speed = this ._speed .getValue ();
129
- },
130
- set_variation__: function ()
131
- {
132
- this .variation = this ._variation .getValue ();
133
- },
134
- set_mass__: function ()
135
- {
136
- this .mass = this ._mass .getValue ();
137
- },
138
214
  isExplosive: function ()
139
215
  {
140
216
  return false;
@@ -143,28 +219,21 @@ function (X3DNode,
143
219
  {
144
220
  return this .mass;
145
221
  },
146
- getRandomLifetime: function (particleLifetime, lifetimeVariation)
222
+ set_on__: function ()
147
223
  {
148
- var
149
- v = particleLifetime * lifetimeVariation,
150
- min = Math .max (0, particleLifetime - v),
151
- max = particleLifetime + v;
152
-
153
- return Math .random () * (max - min) + min;
224
+ this .on = this ._on .getValue ();
154
225
  },
155
- getRandomSpeed: function ()
226
+ set_speed__: function ()
156
227
  {
157
- var
158
- speed = this .speed,
159
- v = speed * this .variation,
160
- min = Math .max (0, speed - v),
161
- max = speed + v;
162
-
163
- return Math .random () * (max - min) + min;
228
+ this .setUniform ("uniform1f", "speed", this ._speed .getValue ());
164
229
  },
165
- getSphericalRandomVelocity: function (velocity)
230
+ set_variation__: function ()
231
+ {
232
+ this .setUniform ("uniform1f", "variation", this ._variation .getValue ());
233
+ },
234
+ set_mass__: function ()
166
235
  {
167
- return this .getRandomNormal (velocity) .multiply (this .getRandomSpeed ());
236
+ this .mass = this ._mass .getValue ();
168
237
  },
169
238
  getRandomValue: function (min, max)
170
239
  {
@@ -172,7 +241,7 @@ function (X3DNode,
172
241
  },
173
242
  getRandomNormal: function (normal)
174
243
  {
175
- var
244
+ const
176
245
  theta = this .getRandomValue (-1, 1) * Math .PI,
177
246
  cphi = this .getRandomValue (-1, 1),
178
247
  phi = Math .acos (cphi),
@@ -182,234 +251,834 @@ function (X3DNode,
182
251
  Math .cos (theta) * r,
183
252
  cphi);
184
253
  },
185
- getRandomNormalWithAngle: function (angle, normal)
254
+ animate: function (particleSystem, deltaTime)
186
255
  {
187
- var
188
- theta = (Math .random () * 2 - 1) * Math .PI,
189
- cphi = this .getRandomValue (Math .cos (angle), 1),
190
- phi = Math .acos (cphi),
191
- r = Math .sin (phi);
256
+ const
257
+ browser = this .getBrowser (),
258
+ gl = browser .getContext (),
259
+ inputParticles = particleSystem .inputParticles,
260
+ particleStride = particleSystem .particleStride,
261
+ particleOffsets = particleSystem .particleOffsets,
262
+ program = this .program;
263
+
264
+ // Start
265
+
266
+ gl .useProgram (program);
267
+
268
+ // Uniforms
269
+
270
+ gl .uniform1i (program .randomSeed, Math .random () * 0xffffffff);
271
+ gl .uniform1i (program .geometryType, particleSystem .geometryType);
272
+ gl .uniform1i (program .createParticles, particleSystem .createParticles && this .on);
273
+ gl .uniform1f (program .particleLifetime, particleSystem .particleLifetime);
274
+ gl .uniform1f (program .lifetimeVariation, particleSystem .lifetimeVariation);
275
+ gl .uniform1f (program .deltaTime, deltaTime);
276
+ gl .uniform2f (program .particleSize, particleSystem ._particleSize .x, particleSystem ._particleSize .y);
277
+
278
+ // Forces
279
+
280
+ gl .uniform1i (program .numForces, particleSystem .numForces);
281
+
282
+ if (particleSystem .numForces)
283
+ {
284
+ gl .activeTexture (gl .TEXTURE0 + program .forcesTextureUnit);
285
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .forcesTexture);
286
+ }
287
+
288
+ // Bounded Physics
289
+
290
+ if (particleSystem .boundedHierarchyRoot < 0)
291
+ {
292
+ gl .uniform1i (program .boundedHierarchyRoot, -1);
293
+ }
294
+ else
295
+ {
296
+ gl .uniform1i (program .boundedVerticesIndex, particleSystem .boundedVerticesIndex);
297
+ gl .uniform1i (program .boundedNormalsIndex, particleSystem .boundedNormalsIndex);
298
+ gl .uniform1i (program .boundedHierarchyIndex, particleSystem .boundedHierarchyIndex);
299
+ gl .uniform1i (program .boundedHierarchyRoot, particleSystem .boundedHierarchyRoot);
300
+
301
+ gl .activeTexture (gl .TEXTURE0 + program .boundedVolumeTextureUnit);
302
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .boundedTexture);
303
+ }
304
+
305
+ // Colors
306
+
307
+ gl .uniform1i (program .numColors, particleSystem .numColors);
308
+
309
+ if (particleSystem .numColors)
310
+ {
311
+ gl .activeTexture (gl .TEXTURE0 + program .colorRampTextureUnit);
312
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .colorRampTexture);
313
+ }
314
+
315
+ // TexCoords
316
+
317
+ gl .uniform1i (program .numTexCoords, particleSystem .numTexCoords);
318
+
319
+ if (particleSystem .numTexCoords)
320
+ {
321
+ gl .uniform1i (program .texCoordCount, particleSystem .texCoordCount);
322
+
323
+ gl .activeTexture (gl .TEXTURE0 + program .texCoordRampTextureUnit);
324
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .texCoordRampTexture);
325
+ }
326
+
327
+ // Other textures
328
+
329
+ this .activateTextures (gl, program);
330
+
331
+ // Input attributes
332
+
333
+ if (inputParticles .emitterArrayObject .enable (gl, program))
334
+ {
335
+ for (const [i, attribute] of program .inputs)
336
+ {
337
+ gl .bindBuffer (gl .ARRAY_BUFFER, inputParticles);
338
+ gl .enableVertexAttribArray (attribute);
339
+ gl .vertexAttribPointer (attribute, 4, gl .FLOAT, false, particleStride, particleOffsets [i]);
340
+ }
341
+
342
+ gl .bindBuffer (gl .ARRAY_BUFFER, null);
343
+ }
344
+
345
+ // Transform particles.
346
+
347
+ gl .bindTransformFeedback (gl .TRANSFORM_FEEDBACK, this .transformFeedback);
348
+ gl .bindBufferBase (gl .TRANSFORM_FEEDBACK_BUFFER, 0, particleSystem .outputParticles);
349
+ gl .enable (gl .RASTERIZER_DISCARD);
350
+ gl .beginTransformFeedback (gl .POINTS);
351
+ gl .drawArrays (gl .POINTS, 0, particleSystem .numParticles);
352
+ gl .endTransformFeedback ();
353
+ gl .disable (gl .RASTERIZER_DISCARD);
354
+ gl .bindTransformFeedback (gl .TRANSFORM_FEEDBACK, null);
355
+
356
+ // DEBUG
357
+
358
+ // const data = new Float32Array (particleSystem .numParticles * (particleStride / 4));
359
+ // gl .bindBuffer (gl .ARRAY_BUFFER, particleSystem .outputParticles);
360
+ // gl .getBufferSubData (gl .ARRAY_BUFFER, 0, data);
361
+ // console .log (data .slice (0, particleStride / 4));
362
+ },
363
+ addSampler: function (name)
364
+ {
365
+ this .samplers .push (name);
366
+ },
367
+ addUniform: function (name, uniform)
368
+ {
369
+ this .uniforms [name] = uniform;
370
+ },
371
+ setUniform: function (func, name, value1, value2, value3)
372
+ {
373
+ const
374
+ gl = this .getBrowser () .getContext (),
375
+ program = this .program;
376
+
377
+ gl .useProgram (program);
378
+ gl [func] (program [name], value1, value2, value3);
379
+ },
380
+ addFunction: function (func)
381
+ {
382
+ this .functions .push (func);
383
+ },
384
+ createProgram: function ()
385
+ {
386
+ const
387
+ browser = this .getBrowser (),
388
+ gl = browser .getContext ();
389
+
390
+ const vertexShaderSource = /* glsl */ `#version 300 es
391
+
392
+ precision highp float;
393
+ precision highp int;
394
+ precision highp sampler2D;
395
+
396
+ uniform int randomSeed;
397
+ uniform int geometryType;
398
+ uniform bool createParticles;
399
+ uniform float particleLifetime;
400
+ uniform float lifetimeVariation;
401
+ uniform float deltaTime;
402
+ uniform vec2 particleSize;
403
+
404
+ uniform int numForces;
405
+ uniform sampler2D forces;
406
+
407
+ uniform int boundedVerticesIndex;
408
+ uniform int boundedNormalsIndex;
409
+ uniform int boundedHierarchyIndex;
410
+ uniform int boundedHierarchyRoot;
411
+ uniform sampler2D boundedVolume;
412
+
413
+ uniform int numColors;
414
+ uniform sampler2D colorRamp;
415
+
416
+ uniform int texCoordCount;
417
+ uniform int numTexCoords;
418
+ uniform sampler2D texCoordRamp;
419
+
420
+ ${Object .values (this .uniforms) .join ("\n")}
421
+
422
+ in vec4 input0;
423
+ in vec4 input2;
424
+ in vec4 input6;
425
+
426
+ out vec4 output0;
427
+ out vec4 output1;
428
+ out vec4 output2;
429
+
430
+ out vec4 output3;
431
+ out vec4 output4;
432
+ out vec4 output5;
433
+ out vec4 output6;
434
+
435
+ // Constants
436
+
437
+ ${Object .entries (GeometryTypes) .map (([k, v]) => `#define ${k} ${v}`) .join ("\n")}
438
+
439
+ const int ARRAY_SIZE = 32;
440
+ const float M_PI = 3.14159265359;
441
+
442
+ uniform float NaN;
443
+
444
+ // Texture
445
+
446
+ vec4
447
+ texelFetch (const in sampler2D sampler, const in int index, const in int lod)
448
+ {
449
+ int x = textureSize (sampler, lod) .x;
450
+ ivec2 p = ivec2 (index % x, index / x);
451
+ vec4 t = texelFetch (sampler, p, lod);
452
+
453
+ return t;
454
+ }
455
+
456
+ // Math
457
+
458
+ // Save normalize, that will not divide by zero.
459
+ vec3
460
+ save_normalize (const in vec3 vector)
461
+ {
462
+ float l = length (vector);
463
+
464
+ if (l == 0.0)
465
+ return vec3 (0.0);
466
+
467
+ return vector / l;
468
+ }
469
+
470
+ // Quaternion
471
+
472
+ vec4
473
+ Quaternion (const in vec3 fromVector, const in vec3 toVector)
474
+ {
475
+ vec3 from = save_normalize (fromVector);
476
+ vec3 to = save_normalize (toVector);
477
+
478
+ float cos_angle = dot (from, to);
479
+ vec3 cross_vec = cross (from, to);
480
+ float cross_len = length (cross_vec);
481
+
482
+ if (cross_len == 0.0)
483
+ {
484
+ if (cos_angle > 0.0)
485
+ {
486
+ return vec4 (0.0, 0.0, 0.0, 1.0);
487
+ }
488
+ else
489
+ {
490
+ vec3 t = cross (from, vec3 (1.0, 0.0, 0.0));
491
+
492
+ if (dot (t, t) == 0.0)
493
+ t = cross (from, vec3 (0.0, 1.0, 0.0));
494
+
495
+ t = save_normalize (t);
496
+
497
+ return vec4 (t, 0.0);
498
+ }
499
+ }
500
+ else
501
+ {
502
+ float s = sqrt (abs (1.0 - cos_angle) * 0.5);
503
+
504
+ cross_vec = save_normalize (cross_vec);
505
+
506
+ return vec4 (cross_vec * s, sqrt (abs (1.0 + cos_angle) * 0.5));
507
+ }
508
+ }
509
+
510
+ vec3
511
+ multVecQuat (const in vec3 v, const in vec4 q)
512
+ {
513
+ float a = q .w * q .w - q .x * q .x - q .y * q .y - q .z * q .z;
514
+ float b = 2.0 * (v .x * q .x + v .y * q .y + v .z * q .z);
515
+ float c = 2.0 * q .w;
516
+ vec3 r = a * v .xyz + b * q .xyz + c * (q .yzx * v .zxy - q .zxy * v .yzx);
517
+
518
+ return r;
519
+ }
520
+
521
+ mat3
522
+ Matrix3 (const in vec4 quaternion)
523
+ {
524
+ float x = quaternion .x;
525
+ float y = quaternion .y;
526
+ float z = quaternion .z;
527
+ float w = quaternion .w;
528
+ float A = y * y;
529
+ float B = z * z;
530
+ float C = x * y;
531
+ float D = z * w;
532
+ float E = z * x;
533
+ float F = y * w;
534
+ float G = x * x;
535
+ float H = y * z;
536
+ float I = x * w;
537
+
538
+ return mat3 (1.0 - 2.0 * (A + B),
539
+ 2.0 * (C + D),
540
+ 2.0 * (E - F),
541
+ 2.0 * (C - D),
542
+ 1.0 - 2.0 * (B + G),
543
+ 2.0 * (H + I),
544
+ 2.0 * (E + F),
545
+ 2.0 * (H - I),
546
+ 1.0 - 2.0 * (A + G));
547
+ }
548
+
549
+ /* Random number generation */
550
+
551
+ uint seed = 1u;
552
+
553
+ void
554
+ srand (const in int value)
555
+ {
556
+ seed = uint (value);
557
+ }
558
+
559
+ // Return a uniform distributed random floating point number in the interval [0, 1].
560
+ float
561
+ random ()
562
+ {
563
+ seed = seed * 1103515245u + 12345u;
564
+
565
+ return float (seed) / 4294967295.0;
566
+ }
567
+
568
+ float
569
+ getRandomValue (const in float min, const in float max)
570
+ {
571
+ return min + random () * (max - min);
572
+ }
573
+
574
+ float
575
+ getRandomLifetime ()
576
+ {
577
+ float v = particleLifetime * lifetimeVariation;
578
+ float min_ = max (0.0, particleLifetime - v);
579
+ float max_ = particleLifetime + v;
580
+
581
+ return getRandomValue (min_, max_);
582
+ }
583
+
584
+ float
585
+ getRandomSpeed ()
586
+ {
587
+ float v = speed * variation;
588
+ float min_ = max (0.0, speed - v);
589
+ float max_ = speed + v;
590
+
591
+ return getRandomValue (min_, max_);
592
+ }
593
+
594
+ vec3
595
+ getRandomNormal ()
596
+ {
597
+ float theta = getRandomValue (-M_PI, M_PI);
598
+ float cphi = getRandomValue (-1.0, 1.0);
599
+ float r = sqrt (1.0 - cphi * cphi); // sin (acos (cphi));
600
+
601
+ return vec3 (sin (theta) * r, cos (theta) * r, cphi);
602
+ }
603
+
604
+ vec3
605
+ getRandomNormalWithAngle (const in float angle)
606
+ {
607
+ float theta = getRandomValue (-M_PI, M_PI);
608
+ float cphi = getRandomValue (cos (angle), 1.0);
609
+ float r = sqrt (1.0 - cphi * cphi); // sin (acos (cphi));
610
+
611
+ return vec3 (sin (theta) * r, cos (theta) * r, cphi);
612
+ }
613
+
614
+ vec3
615
+ getRandomNormalWithDirectionAndAngle (const in vec3 direction, const in float angle)
616
+ {
617
+ vec4 rotation = Quaternion (vec3 (0.0, 0.0, 1.0), direction);
618
+ vec3 normal = getRandomNormalWithAngle (angle);
619
+
620
+ return multVecQuat (normal, rotation);
621
+ }
622
+
623
+ vec3
624
+ getRandomSurfaceNormal (const in vec3 direction)
625
+ {
626
+ float theta = getRandomValue (-M_PI, M_PI);
627
+ float cphi = pow (random (), 1.0 / 3.0);
628
+ float r = sqrt (1.0 - cphi * cphi); // sin (acos (cphi));
629
+ vec3 normal = vec3 (sin (theta) * r, cos (theta) * r, cphi);
630
+ vec4 rotation = Quaternion (vec3 (0.0, 0.0, 1.0), direction);
631
+
632
+ return multVecQuat (normal, rotation);
633
+ }
634
+
635
+ vec3
636
+ getRandomSphericalVelocity ()
637
+ {
638
+ vec3 normal = getRandomNormal ();
639
+ float speed = getRandomSpeed ();
640
+
641
+ return normal * speed;
642
+ }
643
+
644
+ // Algorithms
645
+
646
+ int
647
+ upperBound (const in sampler2D sampler, in int count, const in float value)
648
+ {
649
+ int first = 0;
650
+ int step = 0;
651
+
652
+ while (count > 0)
653
+ {
654
+ int index = first;
655
+
656
+ step = count >> 1;
657
+
658
+ index += step;
659
+
660
+ if (value < texelFetch (sampler, index, 0) .x)
661
+ {
662
+ count = step;
663
+ }
664
+ else
665
+ {
666
+ first = ++ index;
667
+ count -= step + 1;
668
+ }
669
+ }
670
+
671
+ return first;
672
+ }
673
+
674
+ void
675
+ interpolate (const in sampler2D sampler, const in int count, const in float fraction, out int index0, out int index1, out float weight)
676
+ {
677
+ // Determine index0, index1 and weight.
678
+
679
+ if (count == 1 || fraction <= texelFetch (sampler, 0, 0) .x)
680
+ {
681
+ index0 = 0;
682
+ index1 = 0;
683
+ weight = 0.0;
684
+ }
685
+ else if (fraction >= texelFetch (sampler, count - 1, 0) .x)
686
+ {
687
+ index0 = count - 2;
688
+ index1 = count - 1;
689
+ weight = 1.0;
690
+ }
691
+ else
692
+ {
693
+ int index = upperBound (sampler, count, fraction);
694
+
695
+ if (index < count)
696
+ {
697
+ index1 = index;
698
+ index0 = index - 1;
699
+
700
+ float key0 = texelFetch (sampler, index0, 0) .x;
701
+ float key1 = texelFetch (sampler, index1, 0) .x;
702
+
703
+ weight = clamp ((fraction - key0) / (key1 - key0), 0.0, 1.0);
704
+ }
705
+ else
706
+ {
707
+ index0 = 0;
708
+ index1 = 0;
709
+ weight = 0.0;
710
+ }
711
+ }
712
+ }
713
+
714
+ void
715
+ interpolate (const in sampler2D sampler, const in int count, const in float fraction, out int index0)
716
+ {
717
+ // Determine index0.
718
+
719
+ if (count == 1 || fraction <= texelFetch (sampler, 0, 0) .x)
720
+ {
721
+ index0 = 0;
722
+ }
723
+ else if (fraction >= texelFetch (sampler, count - 1, 0) .x)
724
+ {
725
+ index0 = count - 2;
726
+ }
727
+ else
728
+ {
729
+ int index = upperBound (sampler, count, fraction);
730
+
731
+ if (index < count)
732
+ index0 = index - 1;
733
+ else
734
+ index0 = 0;
735
+ }
736
+ }
737
+
738
+ vec3
739
+ getRandomBarycentricCoord ()
740
+ {
741
+ // Random barycentric coordinates.
742
+
743
+ float u = random ();
744
+ float v = random ();
745
+
746
+ if (u + v > 1.0)
747
+ {
748
+ u = 1.0 - u;
749
+ v = 1.0 - v;
750
+ }
751
+
752
+ float t = 1.0 - u - v;
753
+
754
+ return vec3 (t, u, v);
755
+ }
756
+
757
+ void
758
+ getRandomPointOnSurface (const in sampler2D surface, const in int verticesIndex, const in int normalsIndex, out vec4 position, out vec3 normal)
759
+ {
760
+ // Determine index0, index1 and weight.
761
+
762
+ float lastAreaSoFar = texelFetch (surface, verticesIndex - 1, 0) .x;
763
+ float fraction = random () * lastAreaSoFar;
764
+
765
+ int index0;
766
+ int index1;
767
+ int index2;
768
+ float weight;
769
+
770
+ interpolate (surface, verticesIndex, fraction, index0, index1, weight);
771
+
772
+ // Interpolate and return position.
773
+
774
+ index0 *= 3;
775
+ index1 = index0 + 1;
776
+ index2 = index0 + 2;
777
+
778
+ vec4 vertex0 = texelFetch (surface, verticesIndex + index0, 0);
779
+ vec4 vertex1 = texelFetch (surface, verticesIndex + index1, 0);
780
+ vec4 vertex2 = texelFetch (surface, verticesIndex + index2, 0);
781
+
782
+ vec3 normal0 = texelFetch (surface, normalsIndex + index0, 0) .xyz;
783
+ vec3 normal1 = texelFetch (surface, normalsIndex + index1, 0) .xyz;
784
+ vec3 normal2 = texelFetch (surface, normalsIndex + index2, 0) .xyz;
785
+
786
+ // Random barycentric coordinates.
787
+
788
+ vec3 r = getRandomBarycentricCoord ();
789
+
790
+ // Calculate position and direction.
791
+
792
+ position = r .z * vertex0 + r .x * vertex1 + r .y * vertex2;
793
+ normal = save_normalize (r .z * normal0 + r .x * normal1 + r .y * normal2);
794
+ }
795
+
796
+ // Functions
797
+
798
+ ${this .functions .join ("\n")}
799
+
800
+ // Current values
801
+
802
+ vec4
803
+ getColor (const in float lifetime, const in float elapsedTime)
804
+ {
805
+ if (numColors > 0)
806
+ {
807
+ // Determine index0, index1 and weight.
808
+
809
+ float fraction = elapsedTime / lifetime;
810
+
811
+ int index0;
812
+ int index1;
813
+ float weight;
814
+
815
+ interpolate (colorRamp, numColors, fraction, index0, index1, weight);
816
+
817
+ // Interpolate and return color.
818
+
819
+ vec4 color0 = texelFetch (colorRamp, numColors + index0, 0);
820
+ vec4 color1 = texelFetch (colorRamp, numColors + index1, 0);
821
+
822
+ return mix (color0, color1, weight);
823
+ }
824
+ else
825
+ {
826
+ return vec4 (1.0);
827
+ }
828
+ }
829
+
830
+ void
831
+ bounce (const in vec4 fromPosition, inout vec4 toPosition, inout vec3 velocity)
832
+ {
833
+ if (boundedHierarchyRoot < 0)
834
+ return;
835
+
836
+ Line3 line = Line3 (fromPosition .xyz, save_normalize (velocity));
837
+
838
+ vec4 points [ARRAY_SIZE];
839
+ vec3 normals [ARRAY_SIZE];
840
+
841
+ int numIntersections = getIntersections (boundedVolume, boundedVerticesIndex, boundedNormalsIndex, boundedHierarchyIndex, boundedHierarchyRoot, line, points, normals);
842
+
843
+ if (numIntersections == 0)
844
+ return;
845
+
846
+ Plane3 plane1 = plane3 (line .point, line .direction);
847
+
848
+ int index = min_index (points, numIntersections, 0.0, plane1);
849
+
850
+ if (index == -1)
851
+ return;
852
+
853
+ Plane3 plane2 = plane3 (points [index] .xyz, normals [index]);
854
+
855
+ if (sign (plane_distance (plane2, fromPosition .xyz)) == sign (plane_distance (plane2, toPosition .xyz)))
856
+ return;
857
+
858
+ velocity = reflect (velocity, normals [index]);
859
+ toPosition = vec4 (points [index] .xyz + reflect (points [index] .xyz - fromPosition .xyz, normals [index]), 1.0);
860
+ }
861
+
862
+ int
863
+ getTexCoordIndex0 (const in float lifetime, const in float elapsedTime)
864
+ {
865
+ if (numTexCoords == 0)
866
+ {
867
+ return -1;
868
+ }
869
+ else
870
+ {
871
+ float fraction = elapsedTime / lifetime;
872
+ int index0 = 0;
192
873
 
193
- return normal .set (Math .sin (theta) * r,
194
- Math .cos (theta) * r,
195
- cphi);
196
- },
197
- getRandomNormalWithDirectionAndAngle: function (direction, angle, normal)
198
- {
199
- rotation .setFromToVec (Vector3 .zAxis, direction);
874
+ interpolate (texCoordRamp, numTexCoords, fraction, index0);
200
875
 
201
- return rotation .multVecRot (this .getRandomNormalWithAngle (angle, normal));
202
- },
203
- getRandomSurfaceNormal: function (normal)
204
- {
205
- var
206
- theta = this .getRandomValue (-1, 1) * Math .PI,
207
- cphi = Math .pow (Math .random (), 1/3),
208
- phi = Math .acos (cphi),
209
- r = Math .sin (phi);
876
+ return numTexCoords + index0 * texCoordCount;
877
+ }
878
+ }
210
879
 
211
- return normal .set (Math .sin (theta) * r,
212
- Math .cos (theta) * r,
213
- cphi);
214
- },
215
- animate: function (particleSystem, deltaTime)
216
- {
217
- var
218
- particles = particleSystem .particles,
219
- numParticles = particleSystem .numParticles,
220
- createParticles = particleSystem .createParticles,
221
- particleLifetime = particleSystem .particleLifetime,
222
- lifetimeVariation = particleSystem .lifetimeVariation,
223
- speeds = particleSystem .speeds, // speed of velocities
224
- velocities = particleSystem .velocities, // resulting velocities from forces
225
- turbulences = particleSystem .turbulences, // turbulences
226
- rotations = this .rotations, // rotation to direction of force
227
- numForces = particleSystem .numForces, // number of forces
228
- boundedPhysics = particleSystem .boundedVertices .length,
229
- boundedVolume = particleSystem .boundedVolume;
230
-
231
- for (var i = rotations .length; i < numForces; ++ i)
232
- rotations [i] = new Rotation4 (0, 0, 1, 0);
233
-
234
- for (var i = 0; i < numForces; ++ i)
235
- rotations [i] .setFromToVec (Vector3 .zAxis, velocities [i]);
236
-
237
- for (var i = 0; i < numParticles; ++ i)
880
+ void
881
+ main ()
238
882
  {
239
- var
240
- particle = particles [i],
241
- elapsedTime = particle .elapsedTime + deltaTime;
883
+ int life = int (input0 [0]);
884
+ float lifetime = input0 [1];
885
+ float elapsedTime = input0 [2] + deltaTime;
886
+
887
+ srand ((gl_VertexID + randomSeed) * randomSeed);
242
888
 
243
- if (elapsedTime > particle .lifetime)
889
+ if (elapsedTime > lifetime)
244
890
  {
245
891
  // Create new particle or hide particle.
246
892
 
247
- particle .lifetime = this .getRandomLifetime (particleLifetime, lifetimeVariation);
248
- particle .elapsedTime = 0;
893
+ lifetime = getRandomLifetime ();
894
+ elapsedTime = 0.0;
895
+
896
+ output0 = vec4 (max (life + 1, 1), lifetime, elapsedTime, getTexCoordIndex0 (lifetime, elapsedTime));
249
897
 
250
898
  if (createParticles)
251
899
  {
252
- ++ particle .life;
253
- this .getRandomPosition (particle .position);
254
- this .getRandomVelocity (particle .velocity);
900
+ output1 = getColor (lifetime, elapsedTime);
901
+ output2 = vec4 (getRandomVelocity (), 0.0);
902
+ output6 = getRandomPosition ();
255
903
  }
256
904
  else
257
- particle .position .set (Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY);
905
+ {
906
+ output1 = vec4 (0.0);
907
+ output2 = vec4 (0.0);
908
+ output6 = vec4 (NaN);
909
+ }
258
910
  }
259
911
  else
260
912
  {
261
913
  // Animate particle.
262
914
 
263
- var
264
- position = particle .position,
265
- velocity = particle .velocity;
915
+ vec3 velocity = input2 .xyz;
916
+ vec4 position = input6;
266
917
 
267
- for (var f = 0; f < numForces; ++ f)
918
+ for (int i = 0; i < numForces; ++ i)
268
919
  {
269
- velocity .add (rotations [f] .multVecRot (this .getRandomNormalWithAngle (turbulences [f], normal)) .multiply (speeds [f]));
920
+ vec4 force = texelFetch (forces, i, 0);
921
+ float turbulence = force .w;
922
+ vec3 normal = getRandomNormalWithDirectionAndAngle (force .xyz, turbulence);
923
+ float speed = length (force .xyz);
924
+
925
+ velocity += normal * speed;
270
926
  }
271
927
 
272
- if (boundedPhysics)
273
- {
274
- fromPosition .x = position .x;
275
- fromPosition .y = position .y;
276
- fromPosition .z = position .z;
928
+ position .xyz += velocity * deltaTime;
277
929
 
278
- position .x += velocity .x * deltaTime;
279
- position .y += velocity .y * deltaTime;
280
- position .z += velocity .z * deltaTime;
930
+ bounce (input6, position, velocity);
281
931
 
282
- this .bounce (boundedVolume, fromPosition, position, velocity);
283
- }
284
- else
932
+ output0 = vec4 (life, lifetime, elapsedTime, getTexCoordIndex0 (lifetime, elapsedTime));
933
+ output1 = getColor (lifetime, elapsedTime);
934
+ output2 = vec4 (velocity, 0.0);
935
+ output6 = position;
936
+ }
937
+
938
+ switch (geometryType)
939
+ {
940
+ case POINT:
941
+ case SPRITE:
942
+ case GEOMETRY:
285
943
  {
286
- position .x += velocity .x * deltaTime;
287
- position .y += velocity .y * deltaTime;
288
- position .z += velocity .z * deltaTime;
944
+ output3 = vec4 (1.0, 0.0, 0.0, 0.0);
945
+ output4 = vec4 (0.0, 1.0, 0.0, 0.0);
946
+ output5 = vec4 (0.0, 0.0, 1.0, 0.0);
947
+ break;
289
948
  }
949
+ case LINE:
950
+ {
951
+ mat3 r = Matrix3 (Quaternion (vec3 (0.0, 0.0, 1.0), output2 .xyz));
952
+ mat3 s = mat3 (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, particleSize .y);
953
+ mat3 m = r * s;
290
954
 
291
- particle .elapsedTime = elapsedTime;
955
+ output3 = vec4 (m [0], 0.0);
956
+ output4 = vec4 (m [1], 0.0);
957
+ output5 = vec4 (m [2], 0.0);
958
+ break;
959
+ }
960
+ default: // QUAD, TRIANGLE
961
+ {
962
+ output3 = vec4 (particleSize .x, 0.0, 0.0, 0.0);
963
+ output4 = vec4 (0.0, particleSize .y, 0.0, 0.0);
964
+ output5 = vec4 (0.0, 0.0, 1.0, 0.0);
965
+ break;
966
+ }
292
967
  }
293
968
  }
969
+ `;
294
970
 
295
- // Animate color if needed.
971
+ const fragmentShaderSource = /* glsl */ `#version 300 es
296
972
 
297
- if (particleSystem .geometryContext .colorMaterial)
298
- this .getColors (particles, particleSystem .colorKeys, particleSystem .colorRamp, numParticles);
299
- },
300
- bounce: function (boundedVolume, fromPosition, toPosition, velocity)
301
- {
302
- normal .assign (velocity) .normalize ();
973
+ precision highp float;
303
974
 
304
- line .set (fromPosition, normal);
975
+ void
976
+ main () { }
977
+ `;
305
978
 
306
- var
307
- intersections = this .intersections,
308
- intersectionNormals = this .intersectionNormals,
309
- numIntersections = boundedVolume .intersectsLine (line, intersections, intersectionNormals);
979
+ // Vertex shader
310
980
 
311
- if (numIntersections)
312
- {
313
- for (var i = 0; i < numIntersections; ++ i)
314
- intersections [i] .index = i;
981
+ const vertexShader = gl .createShader (gl .VERTEX_SHADER);
315
982
 
316
- plane .set (fromPosition, normal);
983
+ gl .shaderSource (vertexShader, vertexShaderSource);
984
+ gl .compileShader (vertexShader);
317
985
 
318
- this .sorter .sort (0, numIntersections);
986
+ // Fragment shader
319
987
 
320
- var index = Algorithm .upperBound (intersections, 0, numIntersections, 0, PlaneCompareValue);
988
+ const fragmentShader = gl .createShader (gl .FRAGMENT_SHADER);
321
989
 
322
- if (index < numIntersections)
323
- {
324
- var
325
- intersection = intersections [index],
326
- intersectionNormal = intersectionNormals [intersection .index];
990
+ gl .shaderSource (fragmentShader, fragmentShaderSource);
991
+ gl .compileShader (fragmentShader);
327
992
 
328
- plane .set (intersection, intersectionNormal);
993
+ // Program
329
994
 
330
- if (plane .getDistanceToPoint (fromPosition) * plane .getDistanceToPoint (toPosition) < 0)
331
- {
332
- var dot2 = 2 * intersectionNormal .dot (velocity);
995
+ const program = gl .createProgram ();
333
996
 
334
- velocity .x -= intersectionNormal .x * dot2;
335
- velocity .y -= intersectionNormal .y * dot2;
336
- velocity .z -= intersectionNormal .z * dot2;
997
+ gl .attachShader (program, vertexShader);
998
+ gl .attachShader (program, fragmentShader);
999
+ gl .transformFeedbackVaryings (program, Array .from ({length: 7}, (_, i) => "output" + i), gl .INTERLEAVED_ATTRIBS);
1000
+ gl .linkProgram (program);
337
1001
 
338
- normal .assign (velocity) .normalize ();
1002
+ if (!gl .getProgramParameter (program, gl .LINK_STATUS))
1003
+ console .error ("Couldn't initialize particle shader: " + gl .getProgramInfoLog (program));
339
1004
 
340
- var distance = intersection .distance (fromPosition);
1005
+ program .inputs = [
1006
+ [0, gl .getAttribLocation (program, "input0")],
1007
+ [2, gl .getAttribLocation (program, "input2")],
1008
+ [6, gl .getAttribLocation (program, "input6")],
1009
+ ];
341
1010
 
342
- toPosition .x = intersection .x + normal .x * distance;
343
- toPosition .y = intersection .y + normal .y * distance;
344
- toPosition .z = intersection .z + normal .z * distance;
345
- }
346
- }
347
- }
348
- },
349
- getColors: function (particles, colorKeys, colorRamp, numParticles)
350
- {
351
- var
352
- length = colorKeys .length,
353
- index0 = 0,
354
- index1 = 0,
355
- weight = 0;
1011
+ program .randomSeed = gl .getUniformLocation (program, "randomSeed");
1012
+ program .geometryType = gl .getUniformLocation (program, "geometryType");
1013
+ program .createParticles = gl .getUniformLocation (program, "createParticles");
1014
+ program .particleLifetime = gl .getUniformLocation (program, "particleLifetime");
1015
+ program .lifetimeVariation = gl .getUniformLocation (program, "lifetimeVariation");
1016
+ program .deltaTime = gl .getUniformLocation (program, "deltaTime");
1017
+ program .particleSize = gl .getUniformLocation (program, "particleSize");
356
1018
 
357
- for (var i = 0; i < numParticles; ++ i)
358
- {
359
- // Determine index0, index1 and weight.
1019
+ program .numForces = gl .getUniformLocation (program, "numForces");
1020
+ program .forces = gl .getUniformLocation (program, "forces");
360
1021
 
361
- var
362
- particle = particles [i],
363
- fraction = particle .elapsedTime / particle .lifetime,
364
- color = particle .color;
1022
+ program .boundedVerticesIndex = gl .getUniformLocation (program, "boundedVerticesIndex");
1023
+ program .boundedNormalsIndex = gl .getUniformLocation (program, "boundedNormalsIndex");
1024
+ program .boundedHierarchyIndex = gl .getUniformLocation (program, "boundedHierarchyIndex");
1025
+ program .boundedHierarchyRoot = gl .getUniformLocation (program, "boundedHierarchyRoot");
1026
+ program .boundedVolume = gl .getUniformLocation (program, "boundedVolume");
365
1027
 
366
- if (length == 1 || fraction <= colorKeys [0])
367
- {
368
- index0 = 0;
369
- index1 = 0;
370
- weight = 0;
371
- }
372
- else if (fraction >= colorKeys [length - 1])
373
- {
374
- index0 = length - 2;
375
- index1 = length - 1;
376
- weight = 1;
377
- }
378
- else
379
- {
380
- var index = Algorithm .upperBound (colorKeys, 0, length, fraction, Algorithm .less);
1028
+ program .numColors = gl .getUniformLocation (program, "numColors");
1029
+ program .colorRamp = gl .getUniformLocation (program, "colorRamp");
381
1030
 
382
- if (index < length)
383
- {
384
- index1 = index;
385
- index0 = index - 1;
1031
+ program .texCoordCount = gl .getUniformLocation (program, "texCoordCount");
1032
+ program .numTexCoords = gl .getUniformLocation (program, "numTexCoords");
1033
+ program .texCoordRamp = gl .getUniformLocation (program, "texCoordRamp");
386
1034
 
387
- var
388
- key0 = colorKeys [index0],
389
- key1 = colorKeys [index1];
1035
+ for (const name of Object .keys (this .uniforms))
1036
+ program [name] = gl .getUniformLocation (program, name);
390
1037
 
391
- weight = Algorithm .clamp ((fraction - key0) / (key1 - key0), 0, 1);
392
- }
393
- else
394
- {
395
- index0 = 0;
396
- index1 = 0;
397
- weight = 0;
398
- }
399
- }
1038
+ program .NaN = gl .getUniformLocation (program, "NaN");
400
1039
 
401
- // Interpolate and set color.
1040
+ gl .useProgram (program);
402
1041
 
403
- var
404
- color0 = colorRamp [index0],
405
- color1 = colorRamp [index1];
1042
+ for (const name of this .samplers)
1043
+ {
1044
+ const location = gl .getUniformLocation (program, name);
406
1045
 
407
- // Algorithm .lerp (color0, color1, weight);
408
- color .x = color0 .x + weight * (color1 .x - color0 .x);
409
- color .y = color0 .y + weight * (color1 .y - color0 .y);
410
- color .z = color0 .z + weight * (color1 .z - color0 .z);
411
- color .w = color0 .w + weight * (color1 .w - color0 .w);
1046
+ gl .uniform1i (location, program [name + "TextureUnit"] = browser .getTexture2DUnit ());
412
1047
  }
1048
+
1049
+ gl .uniform1f (program .NaN, NaN);
1050
+
1051
+ browser .resetTextureUnits ();
1052
+
1053
+ return program;
1054
+ },
1055
+ activateTextures: function ()
1056
+ { },
1057
+ createTexture: function ()
1058
+ {
1059
+ const
1060
+ gl = this .getBrowser () .getContext (),
1061
+ texture = gl .createTexture ();
1062
+
1063
+ gl .bindTexture (gl .TEXTURE_2D, texture);
1064
+
1065
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_S, gl .CLAMP_TO_EDGE);
1066
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_T, gl .CLAMP_TO_EDGE);
1067
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MAG_FILTER, gl .NEAREST);
1068
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MIN_FILTER, gl .NEAREST);
1069
+
1070
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, 1, 1, 0, gl .RGBA, gl .FLOAT, new Float32Array (4));
1071
+
1072
+ return texture;
1073
+ },
1074
+ getTexture2DUnit: function (browser, object, property)
1075
+ {
1076
+ const textureUnit = object [property];
1077
+
1078
+ if (textureUnit === undefined)
1079
+ return object [property] = browser .getTexture2DUnit ();
1080
+
1081
+ return textureUnit;
413
1082
  },
414
1083
  });
415
1084
 
@@ -488,25 +1157,38 @@ function (Fields,
488
1157
 
489
1158
  this .addType (X3DConstants .PointEmitter);
490
1159
 
491
- this ._position .setUnit ("length");
492
- this ._speed .setUnit ("speed");
493
- this ._mass .setUnit ("mass");
494
- this ._surfaceArea .setUnit ("area");
1160
+ this ._position .setUnit ("length");
1161
+
1162
+ this .addUniform ("position", "uniform vec3 position;");
1163
+ this .addUniform ("direction", "uniform vec3 direction;");
1164
+
1165
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
1166
+ {
1167
+ if (direction == vec3 (0.0))
1168
+ return getRandomSphericalVelocity ();
495
1169
 
496
- this .direction = new Vector3 (0, 0, 0);
1170
+ else
1171
+ return direction * getRandomSpeed ();
1172
+ }`);
1173
+
1174
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
1175
+ {
1176
+ return vec4 (position, 1.0);
1177
+ }`);
497
1178
  }
498
1179
 
499
1180
  PointEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
500
1181
  {
501
1182
  constructor: PointEmitter,
502
1183
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
503
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
504
- new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
505
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
506
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
507
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
508
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
509
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
1184
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1185
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
1186
+ new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1187
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
1188
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1189
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1190
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
1191
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
510
1192
  ]),
511
1193
  getTypeName: function ()
512
1194
  {
@@ -524,7 +1206,10 @@ function (Fields,
524
1206
  {
525
1207
  X3DParticleEmitterNode .prototype .initialize .call (this);
526
1208
 
527
- this ._position .addInterest ("set_position__", this);
1209
+ if (this .getBrowser () .getContext () .getVersion () < 2)
1210
+ return;
1211
+
1212
+ this ._position .addInterest ("set_position__", this);
528
1213
  this ._direction .addInterest ("set_direction__", this);
529
1214
 
530
1215
  this .set_position__ ();
@@ -532,33 +1217,21 @@ function (Fields,
532
1217
  },
533
1218
  set_position__: function ()
534
1219
  {
535
- this .position = this ._position .getValue ()
536
- },
537
- set_direction__: function ()
538
- {
539
- this .direction .assign (this ._direction .getValue ()) .normalize ();
1220
+ const position = this ._position .getValue ();
540
1221
 
541
- if (this .direction .equals (Vector3 .Zero))
542
- this .getRandomVelocity = this .getSphericalRandomVelocity;
543
- else
544
- delete this .getRandomVelocity;
545
- },
546
- getRandomPosition: function (position)
547
- {
548
- return position .assign (this .position);
1222
+ this .setUniform ("uniform3f", "position", position .x, position .y, position .z);
549
1223
  },
550
- getRandomVelocity: function (velocity)
1224
+ set_direction__: (function ()
551
1225
  {
552
- var
553
- direction = this .direction,
554
- speed = this .getRandomSpeed ();
1226
+ const direction = new Vector3 (0, 0, 0);
555
1227
 
556
- velocity .x = direction .x * speed;
557
- velocity .y = direction .y * speed;
558
- velocity .z = direction .z * speed;
1228
+ return function ()
1229
+ {
1230
+ direction .assign (this ._direction .getValue ()) .normalize ();
559
1231
 
560
- return velocity;
561
- },
1232
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
1233
+ };
1234
+ })(),
562
1235
  });
563
1236
 
564
1237
  return PointEmitter;
@@ -830,17 +1503,17 @@ function (Fields,
830
1503
  },
831
1504
  addGeometry: function (boundedNormals, boundedVertices)
832
1505
  {
833
- if (this .geometryNode)
1506
+ if (this .geometryNode && this ._enabled .getValue ())
834
1507
  {
835
- var
1508
+ const
836
1509
  normals = this .geometryNode .getNormals () .getValue (),
837
1510
  vertices = this .geometryNode .getVertices () .getValue ();
838
1511
 
839
- for (var i = 0, length = normals .length; i < length; ++ i)
840
- boundedNormals .push (normals [i]);
1512
+ for (const value of normals)
1513
+ boundedNormals .push (value);
841
1514
 
842
- for (var i = 0, length = vertices .length; i < length; ++ i)
843
- boundedVertices .push (vertices [i]);
1515
+ for (const value of vertices)
1516
+ boundedVertices .push (value);
844
1517
  }
845
1518
  },
846
1519
  });
@@ -903,16 +1576,12 @@ define ('x_ite/Components/ParticleSystems/ConeEmitter',[
903
1576
  "x_ite/Base/FieldDefinitionArray",
904
1577
  "x_ite/Components/ParticleSystems/X3DParticleEmitterNode",
905
1578
  "x_ite/Base/X3DConstants",
906
- "standard/Math/Numbers/Vector3",
907
- "standard/Math/Numbers/Rotation4",
908
1579
  ],
909
1580
  function (Fields,
910
1581
  X3DFieldDefinition,
911
1582
  FieldDefinitionArray,
912
1583
  X3DParticleEmitterNode,
913
- X3DConstants,
914
- Vector3,
915
- Rotation4)
1584
+ X3DConstants)
916
1585
  {
917
1586
  "use strict";
918
1587
 
@@ -922,27 +1591,47 @@ function (Fields,
922
1591
 
923
1592
  this .addType (X3DConstants .ConeEmitter);
924
1593
 
925
- this ._position .setUnit ("length");
926
- this ._angle .setUnit ("angle");
927
- this ._speed .setUnit ("speed");
928
- this ._mass .setUnit ("mass");
929
- this ._surfaceArea .setUnit ("area");
1594
+ this ._position .setUnit ("length");
1595
+ this ._angle .setUnit ("angle");
1596
+
1597
+ this .addUniform ("position", "uniform vec3 position;");
1598
+ this .addUniform ("direction", "uniform vec3 direction;");
1599
+ this .addUniform ("angle", "uniform float angle;");
1600
+
1601
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
1602
+ {
1603
+ if (direction == vec3 (0.0))
1604
+ {
1605
+ return getRandomSphericalVelocity ();
1606
+ }
1607
+ else
1608
+ {
1609
+ vec3 normal = getRandomNormalWithDirectionAndAngle (direction, angle);
1610
+ float speed = getRandomSpeed ();
1611
+
1612
+ return normal * speed;
1613
+ }
1614
+ }`);
930
1615
 
931
- this .rotation = new Rotation4 (0, 0, 1, 0);
1616
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
1617
+ {
1618
+ return vec4 (position, 1.0);
1619
+ }`);
932
1620
  }
933
1621
 
934
1622
  ConeEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
935
1623
  {
936
1624
  constructor: ConeEmitter,
937
1625
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
938
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
939
- new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
940
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
941
- new X3DFieldDefinition (X3DConstants .inputOutput, "angle", new Fields .SFFloat (0.7854)),
942
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
943
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
944
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
945
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
1626
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1627
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
1628
+ new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1629
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
1630
+ new X3DFieldDefinition (X3DConstants .inputOutput, "angle", new Fields .SFFloat (0.7854)),
1631
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1632
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1633
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
1634
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
946
1635
  ]),
947
1636
  getTypeName: function ()
948
1637
  {
@@ -960,6 +1649,9 @@ function (Fields,
960
1649
  {
961
1650
  X3DParticleEmitterNode .prototype .initialize .call (this);
962
1651
 
1652
+ if (this .getBrowser () .getContext () .getVersion () < 2)
1653
+ return;
1654
+
963
1655
  this ._position .addInterest ("set_position__", this);
964
1656
  this ._direction .addInterest ("set_direction__", this);
965
1657
  this ._angle .addInterest ("set_angle__", this);
@@ -970,31 +1662,20 @@ function (Fields,
970
1662
  },
971
1663
  set_position__: function ()
972
1664
  {
973
- this .position = this ._position .getValue ()
1665
+ const position = this ._position .getValue ();
1666
+
1667
+ this .setUniform ("uniform3f", "position", position .x, position .y, position .z);
974
1668
  },
975
1669
  set_direction__: function ()
976
1670
  {
977
- var direction = this ._direction .getValue ();
978
-
979
- this .rotation .setFromToVec (Vector3 .zAxis, direction);
1671
+ const direction = this ._direction .getValue ();
980
1672
 
981
- if (direction .equals (Vector3 .Zero))
982
- this .getRandomVelocity = this .getSphericalRandomVelocity;
983
- else
984
- delete this .getRandomVelocity;
1673
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
985
1674
  },
986
1675
  set_angle__: function ()
987
1676
  {
988
- this .angle = this ._angle .getValue ()
989
- },
990
- getRandomPosition: function (position)
991
- {
992
- return position .assign (this .position);
1677
+ this .setUniform ("uniform1f", "angle", this ._angle .getValue ());
993
1678
  },
994
- getRandomVelocity: function (velocity)
995
- {
996
- return this .rotation .multVecRot (this .getRandomNormalWithAngle (this .angle, velocity) .multiply (this .getRandomSpeed ()));
997
- },
998
1679
  });
999
1680
 
1000
1681
  return ConeEmitter;
@@ -1070,24 +1751,32 @@ function (Fields,
1070
1751
 
1071
1752
  this .addType (X3DConstants .ExplosionEmitter);
1072
1753
 
1073
- this ._position .setUnit ("length");
1074
- this ._speed .setUnit ("speed");
1075
- this ._mass .setUnit ("mass");
1076
- this ._surfaceArea .setUnit ("area");
1754
+ this ._position .setUnit ("length");
1077
1755
 
1078
- this .getRandomVelocity = this .getSphericalRandomVelocity;
1756
+ this .addUniform ("position", "uniform vec3 position;");
1757
+
1758
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
1759
+ {
1760
+ return getRandomSphericalVelocity ();
1761
+ }`);
1762
+
1763
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
1764
+ {
1765
+ return vec4 (position, 1.0);
1766
+ }`);
1079
1767
  }
1080
1768
 
1081
1769
  ExplosionEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
1082
1770
  {
1083
1771
  constructor: ExplosionEmitter,
1084
1772
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
1085
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1086
- new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1087
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1088
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1089
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
1090
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
1773
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1774
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
1775
+ new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1776
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1777
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1778
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
1779
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
1091
1780
  ]),
1092
1781
  getTypeName: function ()
1093
1782
  {
@@ -1105,21 +1794,22 @@ function (Fields,
1105
1794
  {
1106
1795
  X3DParticleEmitterNode .prototype .initialize .call (this);
1107
1796
 
1797
+ if (this .getBrowser () .getContext () .getVersion () < 2)
1798
+ return;
1799
+
1108
1800
  this ._position .addInterest ("set_position__", this);
1109
1801
 
1110
1802
  this .set_position__ ();
1111
1803
  },
1112
- set_position__: function ()
1113
- {
1114
- this .position = this ._position .getValue ()
1115
- },
1116
1804
  isExplosive: function ()
1117
1805
  {
1118
1806
  return true;
1119
1807
  },
1120
- getRandomPosition: function (position)
1808
+ set_position__: function ()
1121
1809
  {
1122
- return position .assign (this .position);
1810
+ const position = this ._position .getValue ();
1811
+
1812
+ this .setUniform ("uniform3f", "position", position .x, position .y, position .z);
1123
1813
  },
1124
1814
  });
1125
1815
 
@@ -1181,12 +1871,14 @@ define ('x_ite/Components/ParticleSystems/ForcePhysicsModel',[
1181
1871
  "x_ite/Base/FieldDefinitionArray",
1182
1872
  "x_ite/Components/ParticleSystems/X3DParticlePhysicsModelNode",
1183
1873
  "x_ite/Base/X3DConstants",
1874
+ "standard/Math/Numbers/Vector3",
1184
1875
  ],
1185
1876
  function (Fields,
1186
1877
  X3DFieldDefinition,
1187
1878
  FieldDefinitionArray,
1188
1879
  X3DParticlePhysicsModelNode,
1189
- X3DConstants)
1880
+ X3DConstants,
1881
+ Vector3)
1190
1882
  {
1191
1883
  "use strict";
1192
1884
 
@@ -1219,14 +1911,25 @@ function (Fields,
1219
1911
  {
1220
1912
  return "physics";
1221
1913
  },
1222
- addForce: function (i, emitterNode, forces, turbulences)
1914
+ addForce: (function ()
1223
1915
  {
1224
- if (this ._enabled .getValue ())
1916
+ const force = new Vector3 (0, 0, 0);
1917
+
1918
+ return function (i, emitterNode, timeByMass, forces)
1225
1919
  {
1226
- forces [i] .assign (this ._force .getValue ());
1227
- turbulences [i] = 0;
1228
- }
1229
- },
1920
+ if (this ._enabled .getValue ())
1921
+ {
1922
+ forces .set (force .assign (this ._force .getValue ()) .multiply (timeByMass), i * 4);
1923
+ forces [i * 4 + 3] = 0;
1924
+
1925
+ return true;
1926
+ }
1927
+ else
1928
+ {
1929
+ return false;
1930
+ }
1931
+ };
1932
+ })(),
1230
1933
  });
1231
1934
 
1232
1935
  return ForcePhysicsModel;
@@ -1308,28 +2011,24 @@ function (Vector3,
1308
2011
  // left: We do not have to test for left.
1309
2012
  ];
1310
2013
 
2014
+ const
2015
+ NODE = 0,
2016
+ TRIANGLE = 1;
2017
+
1311
2018
  function SortComparator (vertices, axis)
1312
2019
  {
1313
- function compare (a, b)
2020
+ return function compare (a, b)
1314
2021
  {
1315
- const
1316
- vertices = compare .vertices;
1317
- axis = compare .axis;
1318
-
1319
- return Math .min (vertices [a + axis], vertices [a + 4 + axis], vertices [a + 8 + axis]) <
1320
- Math .min (vertices [b + axis], vertices [b + 4 + axis], vertices [b + 8 + axis]);
2022
+ return Math .min (vertices [a + axis], vertices [a + 4 + axis], vertices [a + 8 + axis]) <
2023
+ Math .min (vertices [b + axis], vertices [b + 4 + axis], vertices [b + 8 + axis]);
1321
2024
  }
1322
-
1323
- compare .vertices = vertices;
1324
- compare .axis = axis;
1325
-
1326
- return compare;
1327
2025
  }
1328
2026
 
1329
2027
  function Triangle (tree, triangle)
1330
2028
  {
1331
2029
  this .vertices = tree .vertices;
1332
2030
  this .normals = tree .normals;
2031
+ this .triangle = triangle;
1333
2032
  this .i4 = triangle * 12;
1334
2033
  this .i3 = triangle * 9;
1335
2034
  }
@@ -1379,6 +2078,14 @@ function (Vector3,
1379
2078
  }
1380
2079
  }
1381
2080
  },
2081
+ toArray: function (array)
2082
+ {
2083
+ const index = array .length / 4;
2084
+
2085
+ array .push (TRIANGLE, this .triangle * 3, 0, 0);
2086
+
2087
+ return index;
2088
+ },
1382
2089
  };
1383
2090
 
1384
2091
  function Node (tree, triangles, first, size)
@@ -1537,15 +2244,30 @@ function (Vector3,
1537
2244
  return 0;
1538
2245
  }
1539
2246
  },
2247
+ toArray: function (array)
2248
+ {
2249
+ const
2250
+ left = this .left .toArray (array),
2251
+ right = this .right .toArray (array),
2252
+ min = this .min,
2253
+ max = this .max,
2254
+ index = array .length / 4;
2255
+
2256
+ array .push (NODE, left, right, 0,
2257
+ min .x, min .y, min .z, 0,
2258
+ max .x, max .y, max .z, 0);
2259
+
2260
+ return index;
2261
+ },
1540
2262
  };
1541
2263
 
1542
2264
  function BVH (vertices, normals)
1543
2265
  {
2266
+ const numTriangles = vertices .length / 12;
2267
+
1544
2268
  this .vertices = vertices;
1545
2269
  this .normals = normals;
1546
2270
 
1547
- const numTriangles = vertices .length / 12;
1548
-
1549
2271
  switch (numTriangles)
1550
2272
  {
1551
2273
  case 0:
@@ -1566,8 +2288,7 @@ function (Vector3,
1566
2288
  triangles .push (i);
1567
2289
 
1568
2290
  this .sorter = new QuickSort (triangles, SortComparator (vertices, 0));
1569
-
1570
- this .root = new Node (this, triangles, 0, numTriangles);
2291
+ this .root = new Node (this, triangles, 0, numTriangles);
1571
2292
  break;
1572
2293
  }
1573
2294
  }
@@ -1576,7 +2297,6 @@ function (Vector3,
1576
2297
  BVH .prototype =
1577
2298
  {
1578
2299
  constructor: BVH,
1579
-
1580
2300
  intersectsLine: function (line, intersections, intersectionNormals)
1581
2301
  {
1582
2302
  intersections .size = 0;
@@ -1589,6 +2309,17 @@ function (Vector3,
1589
2309
 
1590
2310
  return 0;
1591
2311
  },
2312
+ toArray: function (array)
2313
+ {
2314
+ if (this .root)
2315
+ {
2316
+ const root = this .root .toArray (array);
2317
+
2318
+ array .push (root, 0, 0, 0);
2319
+ }
2320
+
2321
+ return array;
2322
+ },
1592
2323
  };
1593
2324
 
1594
2325
  return BVH;
@@ -1648,69 +2379,70 @@ define ('x_ite/Components/ParticleSystems/ParticleSystem',[
1648
2379
  "x_ite/Base/X3DFieldDefinition",
1649
2380
  "x_ite/Base/FieldDefinitionArray",
1650
2381
  "x_ite/Components/Shape/X3DShapeNode",
2382
+ "x_ite/Browser/ParticleSystems/GeometryTypes",
2383
+ "x_ite/Rendering/VertexArray",
1651
2384
  "x_ite/Rendering/TraverseType",
1652
2385
  "x_ite/Base/X3DConstants",
1653
2386
  "x_ite/Base/X3DCast",
1654
2387
  "x_ite/Browser/Shape/AlphaMode",
1655
2388
  "standard/Math/Numbers/Vector3",
1656
- "standard/Math/Numbers/Vector4",
1657
2389
  "standard/Math/Numbers/Matrix4",
1658
2390
  "standard/Math/Numbers/Matrix3",
1659
- "standard/Math/Algorithms/QuickSort",
1660
- "standard/Math/Algorithm",
1661
2391
  "standard/Math/Utility/BVH",
1662
2392
  ],
1663
2393
  function (Fields,
1664
2394
  X3DFieldDefinition,
1665
2395
  FieldDefinitionArray,
1666
2396
  X3DShapeNode,
2397
+ GeometryTypes,
2398
+ VertexArray,
1667
2399
  TraverseType,
1668
2400
  X3DConstants,
1669
2401
  X3DCast,
1670
2402
  AlphaMode,
1671
2403
  Vector3,
1672
- Vector4,
1673
2404
  Matrix4,
1674
2405
  Matrix3,
1675
- QuickSort,
1676
- Algorithm,
1677
2406
  BVH)
1678
2407
  {
1679
2408
  "use strict";
1680
2409
 
1681
- var i = 0;
1682
-
1683
- const
1684
- POINT = i ++,
1685
- LINE = i ++,
1686
- TRIANGLE = i ++,
1687
- QUAD = i ++,
1688
- GEOMETRY = i ++,
1689
- SPRITE = i ++;
1690
-
1691
- const GeometryTypes = {
1692
- POINT: POINT,
1693
- LINE: LINE,
1694
- TRIANGLE: TRIANGLE,
1695
- QUAD: QUAD,
1696
- GEOMETRY: GEOMETRY,
1697
- SPRITE: SPRITE,
1698
- };
1699
-
1700
- const
1701
- invModelViewMatrix = new Matrix4 (),
1702
- billboardToScreen = new Vector3 (0, 0, 0),
1703
- viewerYAxis = new Vector3 (0, 0, 0),
1704
- vector = new Vector3 (0, 0, 0),
1705
- normal = new Vector3 (0, 0, 0),
1706
- s1 = new Vector3 (0, 0, 0),
1707
- s2 = new Vector3 (0, 0, 0),
1708
- s3 = new Vector3 (0, 0, 0),
1709
- s4 = new Vector3 (0, 0, 0),
1710
- x = new Vector3 (0, 0, 0),
1711
- y = new Vector3 (0, 0, 0);
1712
-
1713
- function compareDistance (lhs, rhs) { return lhs .distance < rhs .distance; }
2410
+ const PointGeometry = new Float32Array ([0, 0, 0, 1]);
2411
+
2412
+ const LineGeometry = new Float32Array ([
2413
+ // TexCoords
2414
+ 0, 0, 0, 1,
2415
+ 1, 0, 0, 1,
2416
+ // Vertices
2417
+ 0, 0, -0.5, 1,
2418
+ 0, 0, 0.5, 1,
2419
+ ]);
2420
+
2421
+ // p4 ------ p3
2422
+ // | / |
2423
+ // | / |
2424
+ // | / |
2425
+ // | / |
2426
+ // p1 ------ p2
2427
+
2428
+ const QuadGeometry = new Float32Array ([
2429
+ // TexCoords
2430
+ 0, 0, 0, 1,
2431
+ 1, 0, 0, 1,
2432
+ 1, 1, 0, 1,
2433
+ 0, 0, 0, 1,
2434
+ 1, 1, 0, 1,
2435
+ 0, 1, 0, 1,
2436
+ // Normal
2437
+ 0, 0, 1,
2438
+ // Vertices
2439
+ -0.5, -0.5, 0, 1,
2440
+ 0.5, -0.5, 0, 1,
2441
+ 0.5, 0.5, 0, 1,
2442
+ -0.5, -0.5, 0, 1,
2443
+ 0.5, 0.5, 0, 1,
2444
+ -0.5, 0.5, 0, 1,
2445
+ ]);
1714
2446
 
1715
2447
  function ParticleSystem (executionContext)
1716
2448
  {
@@ -1720,39 +2452,25 @@ function (Fields,
1720
2452
 
1721
2453
  this ._particleSize .setUnit ("length");
1722
2454
 
1723
- this .createParticles = true;
1724
- this .particles = [ ];
1725
- this .velocities = [ ];
1726
- this .speeds = [ ];
1727
- this .turbulences = [ ];
1728
- this .geometryType = POINT;
1729
2455
  this .maxParticles = 0;
1730
2456
  this .numParticles = 0;
1731
- this .particleLifetime = 0;
1732
- this .lifetimeVariation = 0;
1733
- this .emitterNode = null;
1734
2457
  this .forcePhysicsModelNodes = [ ];
2458
+ this .forces = new Float32Array (4);
1735
2459
  this .boundedPhysicsModelNodes = [ ];
1736
2460
  this .boundedNormals = [ ];
1737
2461
  this .boundedVertices = [ ];
1738
- this .boundedVolume = null;
2462
+ this .colorRamp = new Float32Array ();
2463
+ this .texCoordRamp = new Float32Array ();
2464
+ this .geometryContext = { };
1739
2465
  this .creationTime = 0;
1740
2466
  this .pauseTime = 0;
1741
2467
  this .deltaTime = 0;
1742
- this .numForces = 0;
1743
- this .colorKeys = [ ];
1744
- this .colorRamppNode = null;
1745
- this .colorRamp = [ ];
1746
- this .texCoordKeys = [ ];
1747
- this .texCoordRampNode = null;
1748
- this .texCoordRamp = [ ];
1749
- this .texCoordAnim = false;
1750
- this .vertexCount = 0;
1751
- this .shaderNode = null;
1752
- this .rotation = new Matrix3 ();
1753
- this .particleSorter = new QuickSort (this .particles, compareDistance);
1754
- this .sortParticles = false;
1755
- this .geometryContext = { };
2468
+ this .particleStride = Float32Array .BYTES_PER_ELEMENT * 7 * 4; // 7 x vec4
2469
+ this .particleOffsets = Array .from ({length: 7}, (_, i) => Float32Array .BYTES_PER_ELEMENT * 4 * i); // i x vec4
2470
+ this .particleOffset = this .particleOffsets [0];
2471
+ this .colorOffset = this .particleOffsets [1];
2472
+ this .matrixOffset = this .particleOffsets [3];
2473
+ this .texCoordOffset = 0;
1756
2474
  }
1757
2475
 
1758
2476
  ParticleSystem .prototype = Object .assign (Object .create (X3DShapeNode .prototype),
@@ -1802,6 +2520,9 @@ function (Fields,
1802
2520
  browser = this .getBrowser (),
1803
2521
  gl = browser .getContext ();
1804
2522
 
2523
+ if (browser .getContext () .getVersion () < 2)
2524
+ return;
2525
+
1805
2526
  this .isLive () .addInterest ("set_live__", this);
1806
2527
 
1807
2528
  browser .getBrowserOptions () ._Shading .addInterest ("set_shader__", this);
@@ -1809,6 +2530,7 @@ function (Fields,
1809
2530
  this ._enabled .addInterest ("set_enabled__", this);
1810
2531
  this ._createParticles .addInterest ("set_createParticles__", this);
1811
2532
  this ._geometryType .addInterest ("set_geometryType__", this);
2533
+ this ._geometryType .addInterest ("set_texCoord__", this);
1812
2534
  this ._maxParticles .addInterest ("set_enabled__", this);
1813
2535
  this ._particleLifetime .addInterest ("set_particleLifetime__", this);
1814
2536
  this ._lifetimeVariation .addInterest ("set_lifetimeVariation__", this);
@@ -1819,38 +2541,42 @@ function (Fields,
1819
2541
  this ._texCoordKey .addInterest ("set_texCoord__", this);
1820
2542
  this ._texCoordRamp .addInterest ("set_texCoordRamp__", this);
1821
2543
 
1822
- this .idBuffer = gl .createBuffer ();
1823
- this .positionBuffer = gl .createBuffer ();
1824
- this .elapsedTimeBuffer = gl .createBuffer ();
1825
- this .lifeBuffer = gl .createBuffer ();
1826
- this .colorBuffer = gl .createBuffer ();
1827
- this .texCoordBuffers = [ gl .createBuffer () ];
1828
- this .normalBuffer = gl .createBuffer ();
1829
- this .vertexBuffer = gl .createBuffer ();
1830
-
1831
- for (var i = 1, channels = this .getBrowser () .getMaxTextures (); i < channels; ++ i)
1832
- this .texCoordBuffers .push (this .texCoordBuffers [0]);
1833
-
1834
- this .idArray = new Float32Array ();
1835
- this .positionArray = new Float32Array ();
1836
- this .elapsedTimeArray = new Float32Array ();
1837
- this .lifeArray = new Float32Array ();
1838
- this .colorArray = new Float32Array ();
1839
- this .texCoordArray = new Float32Array ();
1840
- this .normalArray = new Float32Array ();
1841
- this .vertexArray = new Float32Array ();
1842
-
1843
- this .primitiveMode = gl .TRIANGLES;
2544
+ // Create particles stuff.
2545
+
2546
+ this .inputParticles = this .createBuffer ();
2547
+ this .outputParticles = this .createBuffer ();
2548
+
2549
+ this .inputParticles . emitterArrayObject = new VertexArray ();
2550
+ this .inputParticles . vertexArrayObject = new VertexArray ();
2551
+ this .inputParticles .shadowArrayObject = new VertexArray ();
2552
+ this .outputParticles .emitterArrayObject = new VertexArray ();
2553
+ this .outputParticles .vertexArrayObject = new VertexArray ();
2554
+ this .outputParticles .shadowArrayObject = new VertexArray ();
2555
+
2556
+ // Create forces stuff.
2557
+
2558
+ this .forcesTexture = this .createTexture ();
2559
+ this .boundedTexture = this .createTexture ();
2560
+ this .colorRampTexture = this .createTexture ();
2561
+ this .texCoordRampTexture = this .createTexture ();
2562
+
2563
+ // Create GL stuff.
2564
+
2565
+ this .geometryBuffer = this .createBuffer ();
2566
+ this .texCoordBuffers = new Array (browser .getMaxTextures ()) .fill (this .geometryBuffer);
1844
2567
 
1845
2568
  // Geometry context
1846
2569
 
1847
- this .geometryContext .fogCoords = false;
2570
+ this .geometryContext .fogCoords = false;
1848
2571
  this .geometryContext .textureCoordinateNode = browser .getDefaultTextureCoordinate ();
1849
2572
  this .geometryContext .textureCoordinateMapping = new Map ();
1850
2573
 
1851
- // Call order is higly important at startup.
2574
+ // Init fields.
2575
+ // Call order is very important at startup.
2576
+
1852
2577
  this .set_emitter__ ();
1853
2578
  this .set_enabled__ ();
2579
+ this .set_geometryType__ ();
1854
2580
  this .set_createParticles__ ();
1855
2581
  this .set_particleLifetime__ ();
1856
2582
  this .set_lifetimeVariation__ ();
@@ -1874,7 +2600,7 @@ function (Fields,
1874
2600
  {
1875
2601
  switch (this .geometryType)
1876
2602
  {
1877
- case POINT:
2603
+ case GeometryTypes .POINT:
1878
2604
  {
1879
2605
  this .setTransparent (true);
1880
2606
  break;
@@ -1883,7 +2609,7 @@ function (Fields,
1883
2609
  {
1884
2610
  this .setTransparent (this .getAppearance () .getTransparent () ||
1885
2611
  (this .colorRampNode && this .colorRampNode .getTransparent ()) ||
1886
- (this .geometryType === GEOMETRY && this .geometryNode && this .geometryNode .getTransparent ()));
2612
+ (this .geometryType === GeometryTypes .GEOMETRY && this .geometryNode && this .geometryNode .getTransparent ()));
1887
2613
  break;
1888
2614
  }
1889
2615
  }
@@ -1923,7 +2649,7 @@ function (Fields,
1923
2649
  {
1924
2650
  if (this ._enabled .getValue () && this ._maxParticles .getValue ())
1925
2651
  {
1926
- if (! this ._isActive .getValue ())
2652
+ if (!this ._isActive .getValue ())
1927
2653
  {
1928
2654
  if (this .isLive () .getValue ())
1929
2655
  {
@@ -1935,6 +2661,8 @@ function (Fields,
1935
2661
  this .pauseTime = performance .now () / 1000;
1936
2662
 
1937
2663
  this ._isActive = true;
2664
+
2665
+ delete this .traverse;
1938
2666
  }
1939
2667
  }
1940
2668
  else
@@ -1949,6 +2677,7 @@ function (Fields,
1949
2677
  this ._isActive = false;
1950
2678
 
1951
2679
  this .numParticles = 0;
2680
+ this .traverse = Function .prototype;
1952
2681
  }
1953
2682
  }
1954
2683
 
@@ -1960,161 +2689,86 @@ function (Fields,
1960
2689
  },
1961
2690
  set_geometryType__: function ()
1962
2691
  {
1963
- var
1964
- gl = this .getBrowser () .getContext (),
1965
- maxParticles = this .maxParticles;
1966
-
1967
- // geometryType
2692
+ const
2693
+ browser = this .getBrowser (),
2694
+ gl = browser .getContext ();
1968
2695
 
1969
- this .geometryType = GeometryTypes [this ._geometryType .getValue ()];
2696
+ // Set geometryType.
1970
2697
 
1971
- if (! this .geometryType)
1972
- this .geometryType = POINT;
2698
+ this .geometryType = GeometryTypes .hasOwnProperty (this ._geometryType .getValue ())
2699
+ ? GeometryTypes [this ._geometryType .getValue ()]
2700
+ : GeometryTypes .QUAD;
1973
2701
 
1974
- // Create buffers
2702
+ // Create buffers.
1975
2703
 
1976
2704
  switch (this .geometryType)
1977
2705
  {
1978
- case POINT:
2706
+ case GeometryTypes .POINT:
1979
2707
  {
1980
- this .idArray = new Float32Array (maxParticles);
1981
- this .positionArray = new Float32Array (3 * maxParticles);
1982
- this .elapsedTimeArray = new Float32Array (maxParticles);
1983
- this .lifeArray = new Float32Array (maxParticles);
1984
- this .colorArray = new Float32Array (4 * maxParticles);
1985
- this .texCoordArray = new Float32Array ();
1986
- this .normalArray = new Float32Array ();
1987
- this .vertexArray = new Float32Array (4 * maxParticles);
1988
-
1989
- for (var i = 0, a = this .idArray, l = a .length; i < l; ++ i)
1990
- a [i] = i;
1991
-
1992
- this .colorArray .fill (1);
1993
- this .vertexArray .fill (1);
2708
+ this .geometryContext .geometryType = 0;
1994
2709
 
1995
- this .testWireframe = false;
1996
- this .primitiveMode = gl .POINTS;
1997
2710
  this .texCoordCount = 0;
1998
2711
  this .vertexCount = 1;
2712
+ this .hasNormals = false;
2713
+ this .testWireframe = false;
2714
+ this .primitiveMode = gl .POINTS;
2715
+
2716
+ this .verticesOffset = 0;
2717
+
2718
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
2719
+ gl .bufferData (gl .ARRAY_BUFFER, PointGeometry, gl .DYNAMIC_DRAW);
1999
2720
 
2000
- this .geometryContext .geometryType = 0;
2001
2721
  break;
2002
2722
  }
2003
- case LINE:
2723
+ case GeometryTypes .LINE:
2004
2724
  {
2005
- this .idArray = new Float32Array (2 * maxParticles);
2006
- this .positionArray = new Float32Array (2 * 3 * maxParticles);
2007
- this .elapsedTimeArray = new Float32Array (2 * maxParticles);
2008
- this .lifeArray = new Float32Array (2 * maxParticles);
2009
- this .colorArray = new Float32Array (2 * 4 * maxParticles);
2010
- this .texCoordArray = new Float32Array ();
2011
- this .normalArray = new Float32Array ();
2012
- this .vertexArray = new Float32Array (2 * 4 * maxParticles);
2013
-
2014
- for (var i = 0, a = this .idArray, l = a .length; i < l; ++ i)
2015
- a [i] = Math .floor (i / 2);
2016
-
2017
- this .colorArray .fill (1);
2018
- this .vertexArray .fill (1);
2725
+ this .geometryContext .geometryType = 1;
2019
2726
 
2020
- this .testWireframe = false;
2021
- this .primitiveMode = gl .LINES;
2022
2727
  this .texCoordCount = 2;
2023
2728
  this .vertexCount = 2;
2729
+ this .hasNormals = false;
2730
+ this .testWireframe = false;
2731
+ this .primitiveMode = gl .LINES;
2732
+
2733
+ this .texCoordsOffset = 0;
2734
+ this .verticesOffset = Float32Array .BYTES_PER_ELEMENT * 8;
2735
+
2736
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
2737
+ gl .bufferData (gl .ARRAY_BUFFER, LineGeometry, gl .DYNAMIC_DRAW);
2024
2738
 
2025
- this .geometryContext .geometryType = 1;
2026
2739
  break;
2027
2740
  }
2028
- case TRIANGLE:
2029
- case QUAD:
2030
- case SPRITE:
2741
+ case GeometryTypes .TRIANGLE:
2742
+ case GeometryTypes .QUAD:
2743
+ case GeometryTypes .SPRITE:
2031
2744
  {
2032
- this .idArray = new Float32Array (6 * maxParticles);
2033
- this .positionArray = new Float32Array (6 * 3 * maxParticles);
2034
- this .elapsedTimeArray = new Float32Array (6 * maxParticles);
2035
- this .lifeArray = new Float32Array (6 * maxParticles);
2036
- this .colorArray = new Float32Array (6 * 4 * maxParticles);
2037
- this .texCoordArray = new Float32Array (6 * 4 * maxParticles);
2038
- this .normalArray = new Float32Array (6 * 3 * maxParticles);
2039
- this .vertexArray = new Float32Array (6 * 4 * maxParticles);
2040
-
2041
- for (var i = 0, a = this .idArray, l = a .length; i < l; ++ i)
2042
- a [i] = Math .floor (i / 6);
2043
-
2044
- this .colorArray .fill (1);
2045
- this .vertexArray .fill (1);
2046
-
2047
- var
2048
- texCoordArray = this .texCoordArray,
2049
- normalArray = this .normalArray;
2050
-
2051
- for (var i = 0, length = 6 * 3 * maxParticles; i < length; i += 3)
2052
- {
2053
- normalArray [i] = 0;
2054
- normalArray [i + 1] = 0;
2055
- normalArray [i + 2] = 1;
2056
- }
2057
-
2058
- gl .bindBuffer (gl .ARRAY_BUFFER, this .normalBuffer);
2059
- gl .bufferData (gl .ARRAY_BUFFER, this .normalArray, gl .STATIC_DRAW);
2060
-
2061
- for (var i = 0; i < maxParticles; ++ i)
2062
- {
2063
- var i24 = i * 24;
2064
-
2065
- // p4 ------ p3
2066
- // | / |
2067
- // | / |
2068
- // | / |
2069
- // | / |
2070
- // p1 ------ p2
2071
-
2072
- // p1
2073
- texCoordArray [i24] = texCoordArray [i24 + 12] = 0;
2074
- texCoordArray [i24 + 1] = texCoordArray [i24 + 13] = 0;
2075
- texCoordArray [i24 + 2] = texCoordArray [i24 + 14] = 0;
2076
- texCoordArray [i24 + 3] = texCoordArray [i24 + 15] = 1;
2077
-
2078
- // p2
2079
- texCoordArray [i24 + 4] = 1;
2080
- texCoordArray [i24 + 5] = 0;
2081
- texCoordArray [i24 + 6] = 0;
2082
- texCoordArray [i24 + 7] = 1;
2083
-
2084
- // p3
2085
- texCoordArray [i24 + 8] = texCoordArray [i24 + 16] = 1;
2086
- texCoordArray [i24 + 9] = texCoordArray [i24 + 17] = 1;
2087
- texCoordArray [i24 + 10] = texCoordArray [i24 + 18] = 0;
2088
- texCoordArray [i24 + 11] = texCoordArray [i24 + 19] = 1;
2089
-
2090
- // p4
2091
- texCoordArray [i24 + 20] = 0;
2092
- texCoordArray [i24 + 21] = 1;
2093
- texCoordArray [i24 + 22] = 0;
2094
- texCoordArray [i24 + 23] = 1;
2095
- }
2096
-
2097
- gl .bindBuffer (gl .ARRAY_BUFFER, this .texCoordBuffers [0]);
2098
- gl .bufferData (gl .ARRAY_BUFFER, this .texCoordArray, gl .STATIC_DRAW);
2745
+ this .geometryContext .geometryType = 2;
2099
2746
 
2100
- this .testWireframe = true;
2101
- this .primitiveMode = gl .TRIANGLES;
2102
2747
  this .texCoordCount = 4;
2103
2748
  this .vertexCount = 6;
2749
+ this .hasNormals = true;
2750
+ this .testWireframe = true;
2751
+ this .primitiveMode = gl .TRIANGLES;
2752
+
2753
+ this .texCoordsOffset = 0;
2754
+ this .normalOffset = Float32Array .BYTES_PER_ELEMENT * 24;
2755
+ this .verticesOffset = Float32Array .BYTES_PER_ELEMENT * 27;
2756
+
2757
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
2758
+ gl .bufferData (gl .ARRAY_BUFFER, QuadGeometry, gl .DYNAMIC_DRAW);
2104
2759
 
2105
- this .geometryContext .geometryType = 2;
2106
2760
  break;
2107
2761
  }
2108
- case GEOMETRY:
2762
+ case GeometryTypes .GEOMETRY:
2109
2763
  {
2110
2764
  this .texCoordCount = 0;
2111
2765
  this .vertexCount = 0;
2766
+
2112
2767
  break;
2113
2768
  }
2114
2769
  }
2115
2770
 
2116
- gl .bindBuffer (gl .ARRAY_BUFFER, this .idBuffer);
2117
- gl .bufferData (gl .ARRAY_BUFFER, this .idArray, gl .STATIC_DRAW);
2771
+ this .updateVertexArrays ();
2118
2772
 
2119
2773
  this .set_shader__ ();
2120
2774
  this .set_transparent__ ();
@@ -2123,20 +2777,17 @@ function (Fields,
2123
2777
  {
2124
2778
  switch (this .geometryType)
2125
2779
  {
2126
- case POINT:
2780
+ case GeometryTypes .POINT:
2127
2781
  {
2128
2782
  this .shaderNode = this .getBrowser () .getPointShader ();
2129
2783
  break;
2130
2784
  }
2131
- case LINE:
2785
+ case GeometryTypes .LINE:
2132
2786
  {
2133
2787
  this .shaderNode = this .getBrowser () .getLineShader ();
2134
2788
  break;
2135
2789
  }
2136
- case TRIANGLE:
2137
- case QUAD:
2138
- case SPRITE:
2139
- case GEOMETRY:
2790
+ default:
2140
2791
  {
2141
2792
  this .shaderNode = null;
2142
2793
  break;
@@ -2145,37 +2796,18 @@ function (Fields,
2145
2796
  },
2146
2797
  set_maxParticles__: function ()
2147
2798
  {
2148
- var
2149
- particles = this .particles,
2150
- maxParticles = Math .max (0, this ._maxParticles .getValue ());
2151
-
2152
- for (var i = this .numParticles, length = Math .min (particles .length, maxParticles); i < length; ++ i)
2153
- {
2154
- particles [i] .life = 1;
2155
- particles [i] .lifetime = -1;
2156
- }
2157
-
2158
- for (var i = particles .length, length = maxParticles; i < length; ++ i)
2159
- {
2160
- particles [i] = {
2161
- id: i,
2162
- life: 1,
2163
- lifetime: -1,
2164
- elapsedTime: 0,
2165
- position: new Vector3 (0, 0, 0),
2166
- velocity: new Vector3 (0, 0, 0),
2167
- color: new Vector4 (1, 1, 1, 1),
2168
- distance: 0,
2169
- };
2170
- }
2799
+ const
2800
+ lastNumParticles = this .numParticles,
2801
+ maxParticles = Math .max (0, this ._maxParticles .getValue ());
2171
2802
 
2172
2803
  this .maxParticles = maxParticles;
2173
- this .numParticles = Math .min (this .numParticles, maxParticles);
2804
+ this .numParticles = Math .min (lastNumParticles, maxParticles);
2174
2805
 
2175
- if (! this .emitterNode .isExplosive ())
2806
+ if (!this .emitterNode .isExplosive ())
2176
2807
  this .creationTime = performance .now () / 1000;
2177
2808
 
2178
- this .set_geometryType__ ();
2809
+ this .resizeBuffers (lastNumParticles);
2810
+ this .updateVertexArrays ();
2179
2811
  },
2180
2812
  set_particleLifetime__: function ()
2181
2813
  {
@@ -2189,33 +2821,33 @@ function (Fields,
2189
2821
  {
2190
2822
  this .emitterNode = X3DCast (X3DConstants .X3DParticleEmitterNode, this ._emitter);
2191
2823
 
2192
- if (! this .emitterNode)
2824
+ if (!this .emitterNode)
2193
2825
  this .emitterNode = this .getBrowser () .getDefaultEmitter ();
2194
2826
 
2195
2827
  this .createParticles = this ._createParticles .getValue ();
2196
2828
  },
2197
2829
  set_physics__: function ()
2198
2830
  {
2199
- var
2831
+ const
2200
2832
  physics = this ._physics .getValue (),
2201
2833
  forcePhysicsModelNodes = this .forcePhysicsModelNodes,
2202
2834
  boundedPhysicsModelNodes = this .boundedPhysicsModelNodes;
2203
2835
 
2204
- for (var i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2836
+ for (let i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2205
2837
  boundedPhysicsModelNodes [i] .removeInterest ("set_boundedPhysics__", this);
2206
2838
 
2207
2839
  forcePhysicsModelNodes .length = 0;
2208
2840
  boundedPhysicsModelNodes .length = 0;
2209
2841
 
2210
- for (var i = 0, length = physics .length; i < length; ++ i)
2842
+ for (let i = 0, length = physics .length; i < length; ++ i)
2211
2843
  {
2212
2844
  try
2213
2845
  {
2214
- var
2846
+ const
2215
2847
  innerNode = physics [i] .getValue () .getInnerNode (),
2216
2848
  type = innerNode .getType ();
2217
2849
 
2218
- for (var t = type .length - 1; t >= 0; -- t)
2850
+ for (let t = type .length - 1; t >= 0; -- t)
2219
2851
  {
2220
2852
  switch (type [t])
2221
2853
  {
@@ -2246,7 +2878,8 @@ function (Fields,
2246
2878
  },
2247
2879
  set_boundedPhysics__: function ()
2248
2880
  {
2249
- var
2881
+ const
2882
+ gl = this .getBrowser () .getContext (),
2250
2883
  boundedPhysicsModelNodes = this .boundedPhysicsModelNodes,
2251
2884
  boundedNormals = this .boundedNormals,
2252
2885
  boundedVertices = this .boundedVertices;
@@ -2254,13 +2887,43 @@ function (Fields,
2254
2887
  boundedNormals .length = 0;
2255
2888
  boundedVertices .length = 0;
2256
2889
 
2257
- for (var i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2890
+ for (let i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2258
2891
  {
2259
2892
  boundedPhysicsModelNodes [i] .addGeometry (boundedNormals, boundedVertices);
2260
2893
  }
2261
2894
 
2262
- this .boundedVolume = new BVH (boundedVertices, boundedNormals);
2263
- },
2895
+ // Texture
2896
+
2897
+ const
2898
+ boundedHierarchy = new BVH (boundedVertices, boundedNormals) .toArray ([ ]),
2899
+ numBoundedVertices = boundedVertices .length / 4,
2900
+ numBoundedNormals = boundedNormals .length / 3,
2901
+ boundedHierarchyLength = boundedHierarchy .length / 4,
2902
+ boundedArraySize = Math .ceil (Math .sqrt (numBoundedVertices + numBoundedNormals + boundedHierarchyLength)),
2903
+ boundedArray = new Float32Array (boundedArraySize * boundedArraySize * 4);
2904
+
2905
+ this .boundedVerticesIndex = 0;
2906
+ this .boundedNormalsIndex = numBoundedVertices;
2907
+ this .boundedHierarchyIndex = this .boundedNormalsIndex + numBoundedNormals;
2908
+ this .boundedHierarchyRoot = this .boundedHierarchyIndex + boundedHierarchyLength - 1;
2909
+
2910
+ boundedArray .set (boundedVertices);
2911
+
2912
+ for (let s = this .boundedNormalsIndex * 4, n = 0, l = boundedNormals .length; n < l; s += 4, n += 3)
2913
+ {
2914
+ boundedArray [s + 0] = boundedNormals [n + 0];
2915
+ boundedArray [s + 1] = boundedNormals [n + 1];
2916
+ boundedArray [s + 2] = boundedNormals [n + 2];
2917
+ }
2918
+
2919
+ boundedArray .set (boundedHierarchy, this .boundedHierarchyIndex * 4);
2920
+
2921
+ if (boundedArraySize)
2922
+ {
2923
+ gl .bindTexture (gl .TEXTURE_2D, this .boundedTexture);
2924
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, boundedArraySize, boundedArraySize, 0, gl .RGBA, gl .FLOAT, boundedArray);
2925
+ }
2926
+ },
2264
2927
  set_colorRamp__: function ()
2265
2928
  {
2266
2929
  if (this .colorRampNode)
@@ -2276,25 +2939,35 @@ function (Fields,
2276
2939
  },
2277
2940
  set_color__: function ()
2278
2941
  {
2279
- var
2280
- colorKey = this ._colorKey,
2281
- colorKeys = this .colorKeys,
2282
- colorRamp = this .colorRamp;
2942
+ const
2943
+ gl = this .getBrowser () .getContext (),
2944
+ colorKey = this ._colorKey,
2945
+ numColors = colorKey .length,
2946
+ textureSize = Math .ceil (Math .sqrt (numColors * 2));
2283
2947
 
2284
- for (var i = 0, length = colorKey .length; i < length; ++ i)
2285
- colorKeys [i] = colorKey [i];
2948
+ let colorRamp = this .colorRamp;
2286
2949
 
2287
- colorKeys .length = length;
2950
+ if (textureSize * textureSize * 4 > colorRamp .length)
2951
+ colorRamp = this .colorRamp = new Float32Array (textureSize * textureSize * 4);
2952
+
2953
+ for (let i = 0; i < numColors; ++ i)
2954
+ colorRamp [i * 4] = colorKey [i];
2288
2955
 
2289
2956
  if (this .colorRampNode)
2290
- this .colorRampNode .getVectors (this .colorRamp);
2957
+ colorRamp .set (this .colorRampNode .addColors ([ ], numColors) .slice (0, numColors * 4), numColors * 4);
2958
+ else
2959
+ colorRamp .fill (1, numColors * 4);
2291
2960
 
2292
- for (var i = colorRamp .length, length = colorKey .length; i < length; ++ i)
2293
- colorRamp [i] = new Vector4 (1, 1, 1, 1);
2961
+ if (textureSize)
2962
+ {
2963
+ gl .bindTexture (gl .TEXTURE_2D, this .colorRampTexture);
2964
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, textureSize, textureSize, 0, gl .RGBA, gl .FLOAT, colorRamp);
2965
+ }
2294
2966
 
2295
- colorRamp .length = length;
2967
+ this .numColors = numColors;
2968
+ this .geometryContext .colorMaterial = !! (numColors && this .colorRampNode);
2296
2969
 
2297
- this .geometryContext .colorMaterial = !! (colorKeys .length && this .colorRampNode);
2970
+ this .updateVertexArrays ();
2298
2971
  },
2299
2972
  set_texCoordRamp__: function ()
2300
2973
  {
@@ -2310,48 +2983,117 @@ function (Fields,
2310
2983
  },
2311
2984
  set_texCoord__: function ()
2312
2985
  {
2313
- var
2986
+ const
2987
+ gl = this .getBrowser () .getContext (),
2314
2988
  texCoordKey = this ._texCoordKey,
2315
- texCoordKeys = this .texCoordKeys,
2316
- texCoordRamp = this .texCoordRamp;
2989
+ numTexCoords = texCoordKey .length,
2990
+ textureSize = Math .ceil (Math .sqrt (numTexCoords + numTexCoords * this .texCoordCount));
2991
+
2992
+ let texCoordRamp = this .texCoordRamp;
2317
2993
 
2318
- for (var i = 0, length = texCoordKey .length; i < length; ++ i)
2319
- texCoordKeys [i] = texCoordKey [i];
2994
+ if (textureSize * textureSize * 4 > texCoordRamp .length)
2995
+ texCoordRamp = this .texCoordRamp = new Float32Array (textureSize * textureSize * 4);
2996
+ else
2997
+ texCoordRamp .fill (0);
2320
2998
 
2321
- texCoordKeys .length = length;
2999
+ for (let i = 0; i < numTexCoords; ++ i)
3000
+ texCoordRamp [i * 4] = texCoordKey [i];
2322
3001
 
2323
3002
  if (this .texCoordRampNode)
2324
- this .texCoordRampNode .getTexCoord (texCoordRamp);
3003
+ texCoordRamp .set (this .texCoordRampNode .getTexCoord ([ ]) .slice (0, numTexCoords * this .texCoordCount * 4), numTexCoords * 4);
2325
3004
 
2326
- for (var i = texCoordRamp .length, length = texCoordKey .length * this .texCoordCount; i < length; ++ i)
2327
- texCoordRamp [i] = new Vector4 (0, 0, 0, 0);
3005
+ if (textureSize)
3006
+ {
3007
+ gl .bindTexture (gl .TEXTURE_2D, this .texCoordRampTexture);
3008
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, textureSize, textureSize, 0, gl .RGBA, gl .FLOAT, texCoordRamp);
3009
+ }
2328
3010
 
2329
- texCoordRamp .length = length;
3011
+ this .numTexCoords = this .texCoordRampNode ? numTexCoords : 0;
2330
3012
 
2331
- this .texCoordAnim = !! (texCoordKeys .length && this .texCoordRampNode);
3013
+ this .updateVertexArrays ();
2332
3014
  },
2333
- intersectsBox: function (box, clipPlanes)
3015
+ updateVertexArrays: function ()
3016
+ {
3017
+ this .inputParticles .vertexArrayObject .update ();
3018
+ this .inputParticles .shadowArrayObject .update ();
3019
+ this .inputParticles .emitterArrayObject .update ();
3020
+ this .outputParticles .vertexArrayObject .update ();
3021
+ this .outputParticles .shadowArrayObject .update ();
3022
+ this .outputParticles .emitterArrayObject .update ();
3023
+ },
3024
+ createTexture: function ()
3025
+ {
3026
+ const
3027
+ gl = this .getBrowser () .getContext (),
3028
+ texture = gl .createTexture ();
3029
+
3030
+ gl .bindTexture (gl .TEXTURE_2D, texture);
3031
+
3032
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_S, gl .CLAMP_TO_EDGE);
3033
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_T, gl .CLAMP_TO_EDGE);
3034
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MAG_FILTER, gl .NEAREST);
3035
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MIN_FILTER, gl .NEAREST);
3036
+
3037
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, 1, 1, 0, gl .RGBA, gl .FLOAT, new Float32Array (4));
3038
+
3039
+ return texture;
3040
+ },
3041
+ createBuffer: function ()
3042
+ {
3043
+ const
3044
+ gl = this .getBrowser () .getContext (),
3045
+ buffer = gl .createBuffer ();
3046
+
3047
+ gl .bindBuffer (gl .ARRAY_BUFFER, buffer);
3048
+ gl .bufferData (gl .ARRAY_BUFFER, new Uint32Array (), gl .DYNAMIC_DRAW);
3049
+
3050
+ return buffer;
3051
+ },
3052
+ resizeBuffers: function (lastNumParticles)
2334
3053
  {
2335
- // TODO: implement me.
3054
+ const
3055
+ gl = this .getBrowser () .getContext (),
3056
+ maxParticles = this .maxParticles,
3057
+ particleStride = this .particleStride,
3058
+ outputParticles = Object .assign (gl .createBuffer (), this .outputParticles),
3059
+ data = new Uint8Array (maxParticles * particleStride);
3060
+
3061
+ // Resize input buffer.
3062
+
3063
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .inputParticles);
3064
+ gl .bufferData (gl .ARRAY_BUFFER, data, gl .DYNAMIC_DRAW);
3065
+
3066
+ // Resize output buffer.
3067
+
3068
+ gl .bindBuffer (gl .COPY_READ_BUFFER, this .outputParticles);
3069
+ gl .bindBuffer (gl .ARRAY_BUFFER, outputParticles);
3070
+ gl .bufferData (gl .ARRAY_BUFFER, data, gl .DYNAMIC_DRAW);
3071
+ gl .copyBufferSubData (gl .COPY_READ_BUFFER, gl .ARRAY_BUFFER, 0, 0, Math .min (maxParticles * particleStride, lastNumParticles * particleStride));
3072
+ gl .deleteBuffer (this .outputParticles);
3073
+
3074
+ this .outputParticles = outputParticles;
2336
3075
  },
2337
3076
  animateParticles: function ()
2338
3077
  {
2339
- var emitterNode = this .emitterNode;
3078
+ const
3079
+ browser = this .getBrowser (),
3080
+ gl = browser .getContext (),
3081
+ emitterNode = this .emitterNode;
2340
3082
 
2341
3083
  // Determine delta time
2342
3084
 
2343
- var
2344
- DELAY = 15, // Delay in frames when dt full applys.
3085
+ const
3086
+ DELAY = 15, // Delay in frames when dt fully applies.
2345
3087
  dt = 1 / Math .max (10, this .getBrowser () .getCurrentFrameRate ());
2346
3088
 
2347
- // var deltaTime is only for the emitter, this.deltaTime is for the forces.
2348
- var deltaTime = this .deltaTime = ((DELAY - 1) * this .deltaTime + dt) / DELAY; // Moving average about DELAY frames.
3089
+ // let deltaTime is only for the emitter, this.deltaTime is for the forces.
3090
+ let deltaTime = this .deltaTime = ((DELAY - 1) * this .deltaTime + dt) / DELAY; // Moving average about DELAY frames.
2349
3091
 
2350
3092
  // Determine numParticles
2351
3093
 
2352
3094
  if (emitterNode .isExplosive ())
2353
3095
  {
2354
- var
3096
+ const
2355
3097
  now = performance .now () / 1000,
2356
3098
  particleLifetime = this .particleLifetime + this .particleLifetime * this .lifetimeVariation;
2357
3099
 
@@ -2370,7 +3112,7 @@ function (Fields,
2370
3112
  {
2371
3113
  if (this .numParticles < this .maxParticles)
2372
3114
  {
2373
- var
3115
+ const
2374
3116
  now = performance .now () / 1000,
2375
3117
  newParticles = Math .max (0, Math .floor ((now - this .creationTime) * this .maxParticles / this .particleLifetime));
2376
3118
 
@@ -2385,548 +3127,98 @@ function (Fields,
2385
3127
 
2386
3128
  if (emitterNode .getMass ())
2387
3129
  {
2388
- var
2389
- forcePhysicsModelNodes = this .forcePhysicsModelNodes,
2390
- velocities = this .velocities,
2391
- speeds = this .speeds,
2392
- turbulences = this .turbulences,
2393
- deltaMass = this .deltaTime / emitterNode .getMass ();
3130
+ const forcePhysicsModelNodes = this .forcePhysicsModelNodes;
2394
3131
 
2395
- // Collect forces in velocities and collect turbulences.
3132
+ let
3133
+ numForces = forcePhysicsModelNodes .length,
3134
+ forces = this .forces,
3135
+ timeByMass = deltaTime / emitterNode .getMass ();
2396
3136
 
2397
- for (var i = velocities .length, length = forcePhysicsModelNodes .length; i < length; ++ i)
2398
- velocities [i] = new Vector3 (0, 0, 0);
3137
+ // Collect forces in velocities and collect turbulences.
2399
3138
 
2400
- for (var i = 0, length = forcePhysicsModelNodes .length; i < length; ++ i)
2401
- forcePhysicsModelNodes [i] .addForce (i, emitterNode, velocities, turbulences);
3139
+ if (numForces * 4 > forces .length)
3140
+ forces = this .forces = new Float32Array (numForces * 4);
2402
3141
 
2403
- // Determine velocities from forces and determine speed.
3142
+ let disabledForces = 0;
2404
3143
 
2405
- for (var i = 0, length = velocities .length; i < length; ++ i)
3144
+ for (let i = 0; i < numForces; ++ i)
2406
3145
  {
2407
- velocities [i] .multiply (deltaMass);
2408
- speeds [i] = velocities [i] .abs ();
3146
+ disabledForces += !forcePhysicsModelNodes [i] .addForce (i - disabledForces, emitterNode, timeByMass, forces);
2409
3147
  }
2410
3148
 
2411
- this .numForces = length;
2412
- }
2413
- else
2414
- {
2415
- this .numForces = 0;
2416
- }
2417
-
2418
- // Determine particle position, velocity and colors
2419
-
2420
- emitterNode .animate (this, deltaTime);
2421
-
2422
- this .updateGeometry (null);
2423
-
2424
- this .getBrowser () .addBrowserEvent ();
2425
- },
2426
- updateGeometry: function (modelViewMatrix)
2427
- {
2428
- switch (this .geometryType)
2429
- {
2430
- case POINT:
2431
- if (! modelViewMatrix)
2432
- this .updatePoint ();
2433
- break;
2434
- case LINE:
2435
- if (! modelViewMatrix)
2436
- this .updateLine ();
2437
- break;
2438
- case TRIANGLE:
2439
- case QUAD:
2440
- case SPRITE:
2441
- this .updateQuad (modelViewMatrix);
2442
- break;
2443
- case GEOMETRY:
2444
- break;
2445
- }
2446
- },
2447
- updatePoint: function ()
2448
- {
2449
- var
2450
- gl = this .getBrowser () .getContext (),
2451
- particles = this .particles,
2452
- numParticles = this .numParticles,
2453
- positionArray = this .positionArray,
2454
- elapsedTimeArray = this .elapsedTimeArray,
2455
- lifeArray = this .lifeArray,
2456
- colorArray = this .colorArray,
2457
- vertexArray = this .vertexArray;
2458
-
2459
- // Colors
3149
+ this .numForces = numForces -= disabledForces;
2460
3150
 
2461
- if (this .geometryContext .colorMaterial)
2462
- {
2463
- for (var i = 0; i < numParticles; ++ i)
3151
+ if (numForces)
2464
3152
  {
2465
- var
2466
- color = particles [i] .color,
2467
- i4 = i * 4;
2468
-
2469
- colorArray [i4] = color .x;
2470
- colorArray [i4 + 1] = color .y;
2471
- colorArray [i4 + 2] = color .z;
2472
- colorArray [i4 + 3] = color .w;
3153
+ gl .bindTexture (gl .TEXTURE_2D, this .forcesTexture);
3154
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, numForces, 1, 0, gl .RGBA, gl .FLOAT, forces);
2473
3155
  }
2474
-
2475
- gl .bindBuffer (gl .ARRAY_BUFFER, this .colorBuffer);
2476
- gl .bufferData (gl .ARRAY_BUFFER, this .colorArray, gl .STATIC_DRAW);
2477
3156
  }
2478
-
2479
- // Vertices
2480
-
2481
- for (var i = 0; i < numParticles; ++ i)
3157
+ else
2482
3158
  {
2483
- var
2484
- position = particles [i] .position,
2485
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2486
- i3 = i * 3,
2487
- i4 = i * 4;
2488
-
2489
- positionArray [i3] = position .x;
2490
- positionArray [i3 + 1] = position .y;
2491
- positionArray [i3 + 2] = position .z;
2492
-
2493
- elapsedTimeArray [i] = elapsedTime;
2494
- lifeArray [i] = particles [i] .life;
2495
-
2496
- vertexArray [i4] = position .x;
2497
- vertexArray [i4 + 1] = position .y;
2498
- vertexArray [i4 + 2] = position .z;
3159
+ this .numForces = 0;
2499
3160
  }
2500
3161
 
2501
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2502
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2503
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2504
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2505
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2506
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2507
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2508
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
2509
- },
2510
- updateLine: function ()
2511
- {
2512
- var
2513
- gl = this .getBrowser () .getContext (),
2514
- particles = this .particles,
2515
- numParticles = this .numParticles,
2516
- positionArray = this .positionArray,
2517
- elapsedTimeArray = this .elapsedTimeArray,
2518
- lifeArray = this .lifeArray,
2519
- colorArray = this .colorArray,
2520
- vertexArray = this .vertexArray,
2521
- sy1_2 = this ._particleSize .y / 2;
2522
-
2523
- // Colors
2524
-
2525
- if (this .geometryContext .colorMaterial)
2526
- {
2527
- for (var i = 0; i < numParticles; ++ i)
2528
- {
2529
- var
2530
- color = particles [i] .color,
2531
- i8 = i * 8;
2532
-
2533
- colorArray [i8] = color .x;
2534
- colorArray [i8 + 1] = color .y;
2535
- colorArray [i8 + 2] = color .z;
2536
- colorArray [i8 + 3] = color .w;
2537
-
2538
- colorArray [i8 + 4] = color .x;
2539
- colorArray [i8 + 5] = color .y;
2540
- colorArray [i8 + 6] = color .z;
2541
- colorArray [i8 + 7] = color .w;
2542
- }
3162
+ // Swap buffers.
2543
3163
 
2544
- gl .bindBuffer (gl .ARRAY_BUFFER, this .colorBuffer);
2545
- gl .bufferData (gl .ARRAY_BUFFER, this .colorArray, gl .STATIC_DRAW);
2546
- }
3164
+ const inputParticles = this .outputParticles;
3165
+ this .outputParticles = this .inputParticles;
3166
+ this .inputParticles = inputParticles;
2547
3167
 
2548
- // Vertices
3168
+ // Determine particle position, velocity and colors.
2549
3169
 
2550
- for (var i = 0; i < numParticles; ++ i)
2551
- {
2552
- var
2553
- particle = particles [i],
2554
- position = particle .position,
2555
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2556
- life = particles [i] .life,
2557
- x = position .x,
2558
- y = position .y,
2559
- z = position .z,
2560
- i2 = i * 2,
2561
- i6 = i * 6,
2562
- i8 = i * 8;
2563
-
2564
- positionArray [i6] = x;
2565
- positionArray [i6 + 1] = y;
2566
- positionArray [i6 + 2] = z;
2567
- positionArray [i6 + 3] = x;
2568
- positionArray [i6 + 4] = y;
2569
- positionArray [i6 + 5] = z;
2570
-
2571
- elapsedTimeArray [i2] = elapsedTime;
2572
- elapsedTimeArray [i2 + 1] = elapsedTime;
2573
-
2574
- lifeArray [i2] = life;
2575
- lifeArray [i2 + 1] = life;
2576
-
2577
- // Length of line / 2.
2578
- normal .assign (particle .velocity) .normalize () .multiply (sy1_2);
2579
-
2580
- vertexArray [i8] = x - normal .x;
2581
- vertexArray [i8 + 1] = y - normal .y;
2582
- vertexArray [i8 + 2] = z - normal .z;
2583
-
2584
- vertexArray [i8 + 4] = x + normal .x;
2585
- vertexArray [i8 + 5] = y + normal .y;
2586
- vertexArray [i8 + 6] = z + normal .z;
2587
- }
3170
+ emitterNode .animate (this, deltaTime);
2588
3171
 
2589
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2590
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2591
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2592
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2593
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2594
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2595
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2596
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
3172
+ browser .addBrowserEvent ();
2597
3173
  },
2598
- updateQuad: function (modelViewMatrix)
3174
+ updateSprite: (function ()
2599
3175
  {
2600
- try
2601
- {
2602
- var
2603
- gl = this .getBrowser () .getContext (),
2604
- particles = this .particles,
2605
- maxParticles = this .maxParticles,
2606
- numParticles = this .numParticles,
2607
- positionArray = this .positionArray,
2608
- elapsedTimeArray = this .elapsedTimeArray,
2609
- lifeArray = this .lifeArray,
2610
- colorArray = this .colorArray,
2611
- texCoordArray = this .texCoordArray,
2612
- normalArray = this .normalArray,
2613
- vertexArray = this .vertexArray,
2614
- sx1_2 = this ._particleSize .x / 2,
2615
- sy1_2 = this ._particleSize .y / 2;
2616
-
2617
- // Sort particles
2618
-
2619
- // if (this .sortParticles) // always false
2620
- // {
2621
- // for (var i = 0; i < numParticles; ++ i)
2622
- // {
2623
- // var particle = particles [i];
2624
- // particle .distance = modelViewMatrix .getDepth (particle .position);
2625
- // }
2626
- //
2627
- // // Expensisive function!!!
2628
- // this .particleSorter .sort (0, numParticles);
2629
- // }
2630
-
2631
- // Colors
2632
-
2633
- if (! modelViewMatrix) // if called from animateParticles
2634
- {
2635
- if (this .geometryContext .colorMaterial)
2636
- {
2637
- for (var i = 0; i < maxParticles; ++ i)
2638
- {
2639
- var
2640
- color = particles [i] .color,
2641
- i24 = i * 24;
2642
-
2643
- // p4 ------ p3
2644
- // | / |
2645
- // | / |
2646
- // | / |
2647
- // | / |
2648
- // p1 ------ p2
2649
-
2650
- // p1, p2, p3; p1, p3, p4
2651
- colorArray [i24] = colorArray [i24 + 4] = colorArray [i24 + 8] = colorArray [i24 + 12] = colorArray [i24 + 16] = colorArray [i24 + 20] = color .x;
2652
- colorArray [i24 + 1] = colorArray [i24 + 5] = colorArray [i24 + 9] = colorArray [i24 + 13] = colorArray [i24 + 17] = colorArray [i24 + 21] = color .y;
2653
- colorArray [i24 + 2] = colorArray [i24 + 6] = colorArray [i24 + 10] = colorArray [i24 + 14] = colorArray [i24 + 18] = colorArray [i24 + 22] = color .z;
2654
- colorArray [i24 + 3] = colorArray [i24 + 7] = colorArray [i24 + 11] = colorArray [i24 + 15] = colorArray [i24 + 19] = colorArray [i24 + 23] = color .w;
2655
- }
2656
-
2657
- gl .bindBuffer (gl .ARRAY_BUFFER, this .colorBuffer);
2658
- gl .bufferData (gl .ARRAY_BUFFER, this .colorArray, gl .STATIC_DRAW);
2659
- }
3176
+ const data = new Float32Array (QuadGeometry);
2660
3177
 
2661
- if (this .texCoordAnim && this .texCoordArray .length)
2662
- {
2663
- var
2664
- texCoordKeys = this .texCoordKeys,
2665
- texCoordRamp = this .texCoordRamp;
2666
-
2667
- var
2668
- length = texCoordKeys .length,
2669
- index0 = 0;
2670
-
2671
- for (var i = 0; i < maxParticles; ++ i)
2672
- {
2673
- // Determine index0.
2674
-
2675
- var
2676
- particle = particles [i],
2677
- fraction = particle .elapsedTime / particle .lifetime;
2678
-
2679
- if (length == 1 || fraction <= texCoordKeys [0])
2680
- {
2681
- index0 = 0;
2682
- }
2683
- else if (fraction >= texCoordKeys .at (-1))
2684
- {
2685
- index0 = length - 2;
2686
- }
2687
- else
2688
- {
2689
- var index = Algorithm .upperBound (texCoordKeys, 0, length, fraction, Algorithm .less);
3178
+ const quad = [
3179
+ new Vector3 (-0.5, -0.5, 0),
3180
+ new Vector3 ( 0.5, -0.5, 0),
3181
+ new Vector3 ( 0.5, 0.5, 0),
3182
+ new Vector3 (-0.5, -0.5, 0),
3183
+ new Vector3 ( 0.5, 0.5, 0),
3184
+ new Vector3 (-0.5, 0.5, 0),
3185
+ ];
2690
3186
 
2691
- if (index < length)
2692
- index0 = index - 1;
2693
- else
2694
- index0 = 0;
2695
- }
3187
+ const
3188
+ vertex = new Vector3 (0, 0, 0),
3189
+ size = new Vector3 (0, 0, 0);
2696
3190
 
2697
- // Set texCoord.
2698
-
2699
- index0 *= this .texCoordCount;
2700
-
2701
- var
2702
- texCoord1 = texCoordRamp [index0],
2703
- texCoord2 = texCoordRamp [index0 + 1],
2704
- texCoord3 = texCoordRamp [index0 + 2],
2705
- texCoord4 = texCoordRamp [index0 + 3],
2706
- i24 = i * 24;
2707
-
2708
- // p4 ------ p3
2709
- // | / |
2710
- // | / |
2711
- // | / |
2712
- // | / |
2713
- // p1 ------ p2
2714
-
2715
- // p1
2716
- texCoordArray [i24] = texCoordArray [i24 + 12] = texCoord1 .x;
2717
- texCoordArray [i24 + 1] = texCoordArray [i24 + 13] = texCoord1 .y;
2718
- texCoordArray [i24 + 2] = texCoordArray [i24 + 14] = texCoord1 .z;
2719
- texCoordArray [i24 + 3] = texCoordArray [i24 + 15] = texCoord1 .w;
2720
-
2721
- // p2
2722
- texCoordArray [i24 + 4] = texCoord2 .x;
2723
- texCoordArray [i24 + 5] = texCoord2 .y;
2724
- texCoordArray [i24 + 6] = texCoord2 .z;
2725
- texCoordArray [i24 + 7] = texCoord2 .w;
2726
-
2727
- // p3
2728
- texCoordArray [i24 + 8] = texCoordArray [i24 + 16] = texCoord3 .x;
2729
- texCoordArray [i24 + 9] = texCoordArray [i24 + 17] = texCoord3 .y;
2730
- texCoordArray [i24 + 10] = texCoordArray [i24 + 18] = texCoord3 .z;
2731
- texCoordArray [i24 + 11] = texCoordArray [i24 + 19] = texCoord3 .w;
2732
-
2733
- // p4
2734
- texCoordArray [i24 + 20] = texCoord4 .x;
2735
- texCoordArray [i24 + 21] = texCoord4 .y;
2736
- texCoordArray [i24 + 22] = texCoord4 .z;
2737
- texCoordArray [i24 + 23] = texCoord4 .w;
2738
- }
3191
+ return function (gl, rotation)
3192
+ {
3193
+ // Normal
2739
3194
 
2740
- gl .bindBuffer (gl .ARRAY_BUFFER, this .texCoordBuffers [0]);
2741
- gl .bufferData (gl .ARRAY_BUFFER, this .texCoordArray, gl .STATIC_DRAW);
2742
- }
2743
- }
3195
+ for (let i = 0; i < 3; ++ i)
3196
+ data [24 + i] = rotation [i + 6];
2744
3197
 
2745
3198
  // Vertices
2746
3199
 
2747
- if (this .geometryType === SPRITE)
2748
- {
2749
- if (modelViewMatrix) // if called from depth or draw
2750
- {
2751
- // Normals
2752
-
2753
- var rotation = this .getScreenAlignedRotation (modelViewMatrix);
2754
-
2755
- normal
2756
- .set (rotation [0], rotation [1], rotation [2])
2757
- .cross (vector .set (rotation [3], rotation [4], rotation [5]))
2758
- .normalize ();
2759
-
2760
- var
2761
- nx = normal .x,
2762
- ny = normal .y,
2763
- nz = normal .z;
2764
-
2765
- for (var i = 0, length = 6 * 3 * maxParticles; i < length; i += 3)
2766
- {
2767
- normalArray [i] = nx;
2768
- normalArray [i + 1] = ny;
2769
- normalArray [i + 2] = nz;
2770
- }
2771
-
2772
- gl .bindBuffer (gl .ARRAY_BUFFER, this .normalBuffer);
2773
- gl .bufferData (gl .ARRAY_BUFFER, this .normalArray, gl .STATIC_DRAW);
2774
-
2775
- // Vertices
2776
-
2777
- s1 .set (-sx1_2, -sy1_2, 0);
2778
- s2 .set ( sx1_2, -sy1_2, 0);
2779
- s3 .set ( sx1_2, sy1_2, 0);
2780
- s4 .set (-sx1_2, sy1_2, 0);
2781
-
2782
- rotation .multVecMatrix (s1);
2783
- rotation .multVecMatrix (s2);
2784
- rotation .multVecMatrix (s3);
2785
- rotation .multVecMatrix (s4);
2786
-
2787
- for (var i = 0; i < numParticles; ++ i)
2788
- {
2789
- var
2790
- position = particles [i] .position,
2791
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2792
- x = position .x,
2793
- y = position .y,
2794
- z = position .z,
2795
- i6 = i * 6,
2796
- i18 = i * 18,
2797
- i24 = i * 24;
2798
-
2799
- // p4 ------ p3
2800
- // | / |
2801
- // | / |
2802
- // | / |
2803
- // | / |
2804
- // p1 ------ p2
2805
-
2806
-
2807
- positionArray [i18] = positionArray [i18 + 3] = positionArray [i18 + 6] = positionArray [i18 + 9] = positionArray [i18 + 12] = positionArray [i18 + 15] = x;
2808
- positionArray [i18 + 1] = positionArray [i18 + 4] = positionArray [i18 + 7] = positionArray [i18 + 10] = positionArray [i18 + 13] = positionArray [i18 + 16] = y;
2809
- positionArray [i18 + 2] = positionArray [i18 + 5] = positionArray [i18 + 8] = positionArray [i18 + 11] = positionArray [i18 + 14] = positionArray [i18 + 17] = z;
2810
-
2811
- elapsedTimeArray [i6] = elapsedTimeArray [i6 + 1] = elapsedTimeArray [i6 + 2] = elapsedTimeArray [i6 + 3] = elapsedTimeArray [i6 + 4] = elapsedTimeArray [i6 + 5] = elapsedTime;
2812
- lifeArray [i6] = lifeArray [i6 + 1] = lifeArray [i6 + 2] = lifeArray [i6 + 3] = lifeArray [i6 + 4] = lifeArray [i6 + 5] = particles [i] .life;
2813
-
2814
- // p1
2815
- vertexArray [i24] = vertexArray [i24 + 12] = x + s1 .x;
2816
- vertexArray [i24 + 1] = vertexArray [i24 + 13] = y + s1 .y;
2817
- vertexArray [i24 + 2] = vertexArray [i24 + 14] = z + s1 .z;
2818
-
2819
- // p2
2820
- vertexArray [i24 + 4] = x + s2 .x;
2821
- vertexArray [i24 + 5] = y + s2 .y;
2822
- vertexArray [i24 + 6] = z + s2 .z;
2823
-
2824
- // p3
2825
- vertexArray [i24 + 8] = vertexArray [i24 + 16] = x + s3 .x;
2826
- vertexArray [i24 + 9] = vertexArray [i24 + 17] = y + s3 .y;
2827
- vertexArray [i24 + 10] = vertexArray [i24 + 18] = z + s3 .z;
2828
-
2829
- // p4
2830
- vertexArray [i24 + 20] = x + s4 .x;
2831
- vertexArray [i24 + 21] = y + s4 .y;
2832
- vertexArray [i24 + 22] = z + s4 .z;
2833
- }
3200
+ size .set (this ._particleSize .x, this ._particleSize .y, 1);
2834
3201
 
2835
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2836
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2837
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2838
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2839
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2840
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2841
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2842
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
2843
- }
2844
- }
2845
- else
2846
- {
2847
- if (! modelViewMatrix) // if called from animateParticles
2848
- {
2849
- for (var i = 0; i < numParticles; ++ i)
2850
- {
2851
- var
2852
- position = particles [i] .position,
2853
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2854
- x = position .x,
2855
- y = position .y,
2856
- z = position .z,
2857
- i6 = i * 6,
2858
- i18 = i * 18,
2859
- i24 = i * 24;
2860
-
2861
- // p4 ------ p3
2862
- // | / |
2863
- // | / |
2864
- // | / |
2865
- // | / |
2866
- // p1 ------ p2
2867
-
2868
- positionArray [i18] = positionArray [i18 + 3] = positionArray [i18 + 6] = positionArray [i18 + 9] = positionArray [i18 + 12] = positionArray [i18 + 15] = x;
2869
- positionArray [i18 + 1] = positionArray [i18 + 4] = positionArray [i18 + 7] = positionArray [i18 + 10] = positionArray [i18 + 13] = positionArray [i18 + 16] = y;
2870
- positionArray [i18 + 2] = positionArray [i18 + 5] = positionArray [i18 + 8] = positionArray [i18 + 11] = positionArray [i18 + 14] = positionArray [i18 + 17] = z;
2871
-
2872
- elapsedTimeArray [i6] = elapsedTimeArray [i6 + 1] = elapsedTimeArray [i6 + 2] = elapsedTimeArray [i6 + 3] = elapsedTimeArray [i6 + 4] = elapsedTimeArray [i6 + 5] = elapsedTime;
2873
- lifeArray [i6] = lifeArray [i6 + 1] = lifeArray [i6 + 2] = lifeArray [i6 + 3] = lifeArray [i6 + 4] = lifeArray [i6 + 5] = particles [i] .life;
2874
-
2875
- // p1
2876
- vertexArray [i24] = vertexArray [i24 + 12] = x - sx1_2;
2877
- vertexArray [i24 + 1] = vertexArray [i24 + 13] = y - sy1_2;
2878
- vertexArray [i24 + 2] = vertexArray [i24 + 14] = z;
2879
-
2880
- // p2
2881
- vertexArray [i24 + 4] = x + sx1_2;
2882
- vertexArray [i24 + 5] = y - sy1_2;
2883
- vertexArray [i24 + 6] = z;
2884
-
2885
- // p3
2886
- vertexArray [i24 + 8] = vertexArray [i24 + 16] = x + sx1_2;
2887
- vertexArray [i24 + 9] = vertexArray [i24 + 17] = y + sy1_2;
2888
- vertexArray [i24 + 10] = vertexArray [i24 + 18] = z;
2889
-
2890
- // p4
2891
- vertexArray [i24 + 20] = x - sx1_2;
2892
- vertexArray [i24 + 21] = y + sy1_2;
2893
- vertexArray [i24 + 22] = z;
2894
- }
3202
+ for (let i = 0; i < 6; ++ i)
3203
+ data .set (rotation .multVecMatrix (vertex .assign (quad [i]) .multVec (size)), 27 + i * 4);
2895
3204
 
2896
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2897
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2898
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2899
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2900
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2901
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2902
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2903
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
2904
- }
2905
- }
2906
- }
2907
- catch (error)
2908
- {
2909
- console .error (error);
2910
- }
2911
- },
3205
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
3206
+ gl .bufferData (gl .ARRAY_BUFFER, data, gl .DYNAMIC_DRAW);
3207
+ };
3208
+ })(),
3209
+ intersectsBox: function (box, clipPlanes)
3210
+ { },
2912
3211
  traverse: function (type, renderObject)
2913
3212
  {
2914
- if (! this ._isActive .getValue ())
3213
+ if (this .numParticles === 0)
2915
3214
  return;
2916
3215
 
2917
3216
  switch (type)
2918
3217
  {
2919
3218
  case TraverseType .POINTER:
2920
- {
2921
- break;
2922
- }
2923
3219
  case TraverseType .PICKING:
2924
- {
2925
- break;
2926
- }
2927
3220
  case TraverseType .COLLISION:
2928
3221
  {
2929
- // TODO: to be implemented.
2930
3222
  break;
2931
3223
  }
2932
3224
  case TraverseType .SHADOW:
@@ -2945,7 +3237,7 @@ function (Fields,
2945
3237
  }
2946
3238
  }
2947
3239
 
2948
- if (this .geometryType === GEOMETRY)
3240
+ if (this .geometryType === GeometryTypes .GEOMETRY)
2949
3241
  {
2950
3242
  if (this .getGeometry ())
2951
3243
  this .getGeometry () .traverse (type, renderObject); // Currently used for ScreenText.
@@ -2953,64 +3245,75 @@ function (Fields,
2953
3245
  },
2954
3246
  depth: function (gl, context, shaderNode)
2955
3247
  {
2956
- // Update geometry if SPRITE.
2957
-
2958
- this .updateGeometry (context .modelViewMatrix);
2959
-
2960
3248
  // Display geometry.
2961
3249
 
2962
- if (this .geometryType === GEOMETRY)
3250
+ switch (this .geometryType)
2963
3251
  {
2964
- var geometryNode = this .getGeometry ();
3252
+ case GeometryTypes .GEOMETRY:
3253
+ {
3254
+ const geometryNode = this .getGeometry ();
2965
3255
 
2966
- if (geometryNode)
2967
- geometryNode .displayParticlesDepth (gl, context, shaderNode, this .particles, this .numParticles);
2968
- }
2969
- else
2970
- {
2971
- if (this .numParticles <= 0)
2972
- return;
3256
+ if (geometryNode)
3257
+ geometryNode .displayParticlesDepth (gl, context, shaderNode, this);
2973
3258
 
2974
- if (shaderNode .getValid ())
3259
+ break;
3260
+ }
3261
+ case GeometryTypes .SPRITE:
3262
+ {
3263
+ this .updateSprite (gl, this .getScreenAlignedRotation (context .modelViewMatrix));
3264
+ // [fall trough]
3265
+ }
3266
+ default:
2975
3267
  {
2976
- // Setup vertex attributes.
3268
+ const outputParticles = this .outputParticles;
3269
+
3270
+ if (outputParticles .shadowArrayObject .enable (gl, shaderNode))
3271
+ {
3272
+ const particleStride = this .particleStride;
2977
3273
 
2978
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleId", this .idBuffer, 1);
2979
- shaderNode .enableFloatAttrib (gl, "x3d_ParticlePosition", this .positionBuffer, 3);
2980
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleElapsedTime", this .elapsedTimeBuffer, 1);
2981
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleLife", this .lifeBuffer, 1);
2982
- shaderNode .enableVertexAttribute (gl, this .vertexBuffer);
3274
+ shaderNode .enableParticleAttribute (gl, outputParticles, particleStride, this .particleOffset, 1);
3275
+ shaderNode .enableParticleMatrixAttribute (gl, outputParticles, particleStride, this .matrixOffset, 1);
3276
+ shaderNode .enableVertexAttribute (gl, this .geometryBuffer, 0, this .verticesOffset);
3277
+ }
2983
3278
 
2984
- gl .drawArrays (this .primitiveMode, 0, this .numParticles * this .vertexCount);
3279
+ gl .drawArraysInstanced (this .primitiveMode, 0, this .vertexCount, this .numParticles);
2985
3280
 
2986
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleId");
2987
- shaderNode .disableFloatAttrib (gl, "x3d_ParticlePosition");
2988
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleElapsedTime");
2989
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleLife");
3281
+ break;
2990
3282
  }
2991
3283
  }
2992
3284
  },
2993
3285
  display: function (gl, context)
2994
3286
  {
2995
- try
2996
- {
2997
- if (this .numParticles <= 0)
2998
- return;
2999
-
3000
- // Update geometry if SPRITE.
3001
-
3002
- this .updateGeometry (context .modelViewMatrix);
3003
-
3004
- // Display geometry.
3287
+ // Display geometry.
3005
3288
 
3006
- if (this .geometryType === GEOMETRY)
3289
+ switch (this .geometryType)
3290
+ {
3291
+ case GeometryTypes .GEOMETRY:
3007
3292
  {
3008
3293
  const geometryNode = this .getGeometry ();
3009
3294
 
3010
3295
  if (geometryNode)
3011
- geometryNode .displayParticles (gl, context, this .particles, this .numParticles);
3296
+ geometryNode .displayParticles (gl, context, this);
3297
+
3298
+ break;
3012
3299
  }
3013
- else
3300
+ case GeometryTypes .SPRITE:
3301
+ {
3302
+ this .updateSprite (gl, this .getScreenAlignedRotation (context .modelViewMatrix));
3303
+ // [fall trough]
3304
+ }
3305
+ case GeometryTypes .QUAD:
3306
+ case GeometryTypes .TRIANGLE:
3307
+ {
3308
+ const positiveScale = Matrix4 .prototype .determinant3 .call (context .modelViewMatrix) > 0;
3309
+
3310
+ gl .frontFace (positiveScale ? gl .CCW : gl .CW);
3311
+ gl .enable (gl .CULL_FACE);
3312
+ gl .cullFace (gl .BACK);
3313
+
3314
+ // [fall trough]
3315
+ }
3316
+ default:
3014
3317
  {
3015
3318
  const
3016
3319
  appearanceNode = this .getAppearance (),
@@ -3018,7 +3321,7 @@ function (Fields,
3018
3321
 
3019
3322
  // Setup shader.
3020
3323
 
3021
- if (shaderNode .getValid ())
3324
+ if (shaderNode .isValid ())
3022
3325
  {
3023
3326
  context .geometryContext = this .geometryContext;
3024
3327
 
@@ -3030,85 +3333,98 @@ function (Fields,
3030
3333
  shaderNode .enable (gl);
3031
3334
  shaderNode .setLocalUniforms (gl, context);
3032
3335
 
3336
+ if (this .numTexCoords)
3337
+ {
3338
+ const textureUnit = context .browser .getTexture2DUnit ();
3339
+
3340
+ gl .activeTexture (gl .TEXTURE0 + textureUnit);
3341
+ gl .bindTexture (gl .TEXTURE_2D, this .texCoordRampTexture);
3342
+ gl .uniform1i (shaderNode .x3d_TexCoordRamp, textureUnit);
3343
+ }
3344
+
3033
3345
  // Setup vertex attributes.
3034
3346
 
3035
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleId", this .idBuffer, 1);
3036
- shaderNode .enableFloatAttrib (gl, "x3d_ParticlePosition", this .positionBuffer, 3);
3037
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleElapsedTime", this .elapsedTimeBuffer, 1);
3038
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleLife", this .lifeBuffer, 1);
3347
+ const outputParticles = this .outputParticles;
3348
+
3349
+ if (outputParticles .vertexArrayObject .enable (gl, shaderNode))
3350
+ {
3351
+ const particleStride = this .particleStride;
3352
+
3353
+ shaderNode .enableParticleAttribute (gl, outputParticles, particleStride, this .particleOffset, 1);
3354
+ shaderNode .enableParticleMatrixAttribute (gl, outputParticles, particleStride, this .matrixOffset, 1);
3039
3355
 
3040
- if (this .geometryContext .colorMaterial)
3041
- shaderNode .enableColorAttribute (gl, this .colorBuffer);
3356
+ if (this .geometryContext .colorMaterial)
3357
+ {
3358
+ shaderNode .enableColorAttribute (gl, outputParticles, particleStride, this .colorOffset);
3359
+ shaderNode .colorAttributeDivisor (gl, 1);
3360
+ }
3042
3361
 
3043
- if (this .texCoordArray .length)
3044
- shaderNode .enableTexCoordAttribute (gl, this .texCoordBuffers);
3362
+ if (this .texCoordCount)
3363
+ shaderNode .enableTexCoordAttribute (gl, this .texCoordBuffers, 0, this .texCoordOffset);
3045
3364
 
3046
- if (this .normalArray .length)
3047
- shaderNode .enableNormalAttribute (gl, this .normalBuffer);
3365
+ if (this .hasNormals)
3366
+ {
3367
+ shaderNode .enableNormalAttribute (gl, this .geometryBuffer, 0, this .normalOffset);
3368
+ shaderNode .normalAttributeDivisor (gl, this .maxParticles);
3369
+ }
3048
3370
 
3049
- shaderNode .enableVertexAttribute (gl, this .vertexBuffer);
3371
+ shaderNode .enableVertexAttribute (gl, this .geometryBuffer, 0, this .verticesOffset);
3372
+ }
3050
3373
 
3051
3374
  if (shaderNode .wireframe && this .testWireframe)
3052
3375
  {
3053
3376
  // Wireframes are always solid so only one drawing call is needed.
3054
3377
 
3055
- for (var i = 0, length = this .numParticles * this .vertexCount; i < length; i += 3)
3378
+ for (let i = 0, length = this .numParticles * this .vertexCount; i < length; i += 3)
3056
3379
  gl .drawArrays (shaderNode .primitiveMode, i, 3);
3057
3380
  }
3058
3381
  else
3059
3382
  {
3060
- const positiveScale = Matrix4 .prototype .determinant3 .call (context .modelViewMatrix) > 0;
3061
-
3062
- gl .frontFace (positiveScale ? gl .CCW : gl .CW);
3063
- gl .enable (gl .CULL_FACE);
3064
- gl .cullFace (gl .BACK);
3065
-
3066
- gl .drawArrays (this .primitiveMode, 0, this .numParticles * this .vertexCount);
3383
+ gl .drawArraysInstanced (this .primitiveMode, 0, this .vertexCount, this .numParticles);
3067
3384
  }
3068
3385
 
3069
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleId");
3070
- shaderNode .disableFloatAttrib (gl, "x3d_ParticlePosition");
3071
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleElapsedTime");
3072
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleLife");
3073
-
3074
- shaderNode .disableColorAttribute (gl);
3075
- shaderNode .disableTexCoordAttribute (gl);
3076
- shaderNode .disableNormalAttribute (gl);
3077
-
3078
3386
  if (blendModeNode)
3079
3387
  blendModeNode .disable (gl);
3080
3388
 
3081
- context .geometryContext = null;
3389
+ delete context .geometryContext;
3082
3390
  }
3391
+
3392
+ break;
3083
3393
  }
3084
3394
  }
3085
- catch (error)
3086
- {
3087
- // Catch error from setLocalUniforms.
3088
- console .error (error);
3089
- }
3090
3395
  },
3091
- getScreenAlignedRotation: function (modelViewMatrix)
3396
+ getScreenAlignedRotation: (function ()
3092
3397
  {
3093
- invModelViewMatrix .assign (modelViewMatrix) .inverse ();
3398
+ const
3399
+ invModelViewMatrix = new Matrix4 (),
3400
+ billboardToScreen = new Vector3 (0, 0, 0),
3401
+ viewerYAxis = new Vector3 (0, 0, 0),
3402
+ y = new Vector3 (0, 0, 0),
3403
+ rotation = new Matrix3 (9);
3404
+
3405
+ return function (modelViewMatrix)
3406
+ {
3407
+ invModelViewMatrix .assign (modelViewMatrix) .inverse ();
3408
+ invModelViewMatrix .multDirMatrix (billboardToScreen .assign (Vector3 .zAxis));
3409
+ invModelViewMatrix .multDirMatrix (viewerYAxis .assign (Vector3 .yAxis));
3094
3410
 
3095
- invModelViewMatrix .multDirMatrix (billboardToScreen .assign (Vector3 .zAxis));
3096
- invModelViewMatrix .multDirMatrix (viewerYAxis .assign (Vector3 .yAxis));
3411
+ const x = viewerYAxis .cross (billboardToScreen);
3412
+ y .assign (billboardToScreen) .cross (x);
3413
+ const z = billboardToScreen;
3097
3414
 
3098
- x .assign (viewerYAxis) .cross (billboardToScreen);
3099
- y .assign (billboardToScreen) .cross (x);
3100
- var z = billboardToScreen;
3415
+ // Compose rotation matrix.
3101
3416
 
3102
- // Compose rotation
3417
+ x .normalize ();
3418
+ y .normalize ();
3419
+ z .normalize ();
3103
3420
 
3104
- x .normalize ();
3105
- y .normalize ();
3106
- z .normalize ();
3421
+ rotation .set (x .x, x .y, x .z,
3422
+ y .x, y .y, y .z,
3423
+ z .x, z .y, z .z);
3107
3424
 
3108
- return this .rotation .set (x .x, x .y, x .z,
3109
- y .x, y .y, y .z,
3110
- z .x, z .y, z .z);
3111
- },
3425
+ return rotation;
3426
+ };
3427
+ })(),
3112
3428
  });
3113
3429
 
3114
3430
  return ParticleSystem;
@@ -3171,7 +3487,6 @@ define ('x_ite/Components/ParticleSystems/PolylineEmitter',[
3171
3487
  "x_ite/Components/Rendering/IndexedLineSet",
3172
3488
  "x_ite/Base/X3DConstants",
3173
3489
  "standard/Math/Numbers/Vector3",
3174
- "standard/Math/Algorithm",
3175
3490
  ],
3176
3491
  function (Fields,
3177
3492
  X3DFieldDefinition,
@@ -3179,8 +3494,7 @@ function (Fields,
3179
3494
  X3DParticleEmitterNode,
3180
3495
  IndexedLineSet,
3181
3496
  X3DConstants,
3182
- Vector3,
3183
- Algorithm)
3497
+ Vector3)
3184
3498
  {
3185
3499
  "use strict";
3186
3500
 
@@ -3190,28 +3504,69 @@ function (Fields,
3190
3504
 
3191
3505
  this .addType (X3DConstants .PolylineEmitter);
3192
3506
 
3193
- this ._speed .setUnit ("speed");
3194
- this ._mass .setUnit ("mass");
3195
- this ._surfaceArea .setUnit ("area");
3507
+ this .polylinesNode = new IndexedLineSet (executionContext);
3508
+ this .polylinesArray = new Float32Array ();
3509
+
3510
+ this .addSampler ("polylines");
3511
+
3512
+ this .addUniform ("direction", "uniform vec3 direction;");
3513
+ this .addUniform ("verticesIndex", "uniform int verticesIndex;");
3514
+ this .addUniform ("polylines", "uniform sampler2D polylines;");
3515
+
3516
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
3517
+ {
3518
+ if (direction == vec3 (0.0))
3519
+ return getRandomSphericalVelocity ();
3520
+
3521
+ else
3522
+ return direction * getRandomSpeed ();
3523
+ }`);
3524
+
3525
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
3526
+ {
3527
+ if (verticesIndex < 0)
3528
+ {
3529
+ return vec4 (NaN);
3530
+ }
3531
+ else
3532
+ {
3533
+ // Determine index0, index1 and weight.
3196
3534
 
3197
- this .direction = new Vector3 (0, 0, 0);
3198
- this .polylineNode = new IndexedLineSet (executionContext);
3199
- this .polylines = [ ];
3200
- this .lengthSoFarArray = [ 0 ];
3535
+ float lastLengthSoFar = texelFetch (polylines, verticesIndex - 1, 0) .x;
3536
+ float fraction = random () * lastLengthSoFar;
3537
+
3538
+ int index0 = 0;
3539
+ int index1 = 0;
3540
+ float weight = 0.0;
3541
+
3542
+ interpolate (polylines, verticesIndex, fraction, index0, index1, weight);
3543
+
3544
+ // Interpolate and return position.
3545
+
3546
+ index0 *= 2;
3547
+ index1 = index0 + 1;
3548
+
3549
+ vec4 vertex0 = texelFetch (polylines, verticesIndex + index0, 0);
3550
+ vec4 vertex1 = texelFetch (polylines, verticesIndex + index1, 0);
3551
+
3552
+ return mix (vertex0, vertex1, weight);
3553
+ }
3554
+ }`);
3201
3555
  }
3202
3556
 
3203
3557
  PolylineEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
3204
3558
  {
3205
3559
  constructor: PolylineEmitter,
3206
3560
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
3207
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3208
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
3209
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3210
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3211
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
3212
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
3213
- new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
3214
- new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
3561
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3562
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
3563
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
3564
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3565
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3566
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
3567
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
3568
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
3569
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
3215
3570
  ]),
3216
3571
  getTypeName: function ()
3217
3572
  {
@@ -3229,148 +3584,93 @@ function (Fields,
3229
3584
  {
3230
3585
  X3DParticleEmitterNode .prototype .initialize .call (this);
3231
3586
 
3587
+ const browser = this .getBrowser ();
3588
+
3589
+ if (browser .getContext () .getVersion () < 2)
3590
+ return;
3591
+
3592
+ // Create GL stuff.
3593
+
3594
+ this .polylinesTexture = this .createTexture ();
3595
+
3596
+ // Initialize fields.
3597
+
3232
3598
  this ._direction .addInterest ("set_direction__", this);
3233
3599
 
3234
- this ._coordIndex .addFieldInterest (this .polylineNode ._coordIndex);
3235
- this ._coord .addFieldInterest (this .polylineNode ._coord);
3600
+ this ._coordIndex .addFieldInterest (this .polylinesNode ._coordIndex);
3601
+ this ._coord .addFieldInterest (this .polylinesNode ._coord);
3236
3602
 
3237
- this .polylineNode ._coordIndex = this ._coordIndex;
3238
- this .polylineNode ._coord = this ._coord;
3603
+ this .polylinesNode ._coordIndex = this ._coordIndex;
3604
+ this .polylinesNode ._coord = this ._coord;
3239
3605
 
3240
- this .polylineNode ._rebuild .addInterest ("set_polyline", this);
3241
- this .polylineNode .setPrivate (true);
3242
- this .polylineNode .setup ();
3606
+ this .polylinesNode ._rebuild .addInterest ("set_polyline", this);
3607
+ this .polylinesNode .setPrivate (true);
3608
+ this .polylinesNode .setup ();
3243
3609
 
3244
3610
  this .set_direction__ ();
3245
3611
  this .set_polyline ();
3246
3612
  },
3247
- set_direction__: function ()
3613
+ set_direction__: (function ()
3248
3614
  {
3249
- this .direction .assign (this ._direction .getValue ()) .normalize ();
3615
+ const direction = new Vector3 (0, 0, 0);
3250
3616
 
3251
- if (this .direction .equals (Vector3 .Zero))
3252
- this .getRandomVelocity = this .getSphericalRandomVelocity;
3253
- else
3254
- delete this .getRandomVelocity;
3255
- },
3617
+ return function ()
3618
+ {
3619
+ direction .assign (this ._direction .getValue ()) .normalize ();
3620
+
3621
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
3622
+ };
3623
+ })(),
3256
3624
  set_polyline: (function ()
3257
3625
  {
3258
- var
3626
+ const
3259
3627
  vertex1 = new Vector3 (0, 0, 0),
3260
3628
  vertex2 = new Vector3 (0, 0, 0);
3261
3629
 
3262
3630
  return function ()
3263
3631
  {
3264
- var vertices = this .vertices = this .polylineNode .getVertices () .getValue ();
3632
+ const
3633
+ gl = this .getBrowser () .getContext (),
3634
+ vertices = this .polylinesNode .getVertices () .getValue (),
3635
+ numVertices = vertices .length / 4,
3636
+ numLengthSoFar = numVertices / 2 + 1,
3637
+ polylineArraySize = Math .ceil (Math .sqrt (numLengthSoFar + numVertices));
3265
3638
 
3266
- if (vertices .length)
3267
- {
3268
- delete this .getRandomPosition;
3639
+ const verticesIndex = numLengthSoFar;
3269
3640
 
3270
- var
3271
- lengthSoFar = 0,
3272
- lengthSoFarArray = this .lengthSoFarArray;
3641
+ let polylinesArray = this .polylinesArray;
3273
3642
 
3274
- lengthSoFarArray .length = 1;
3643
+ if (polylinesArray .length < polylineArraySize * polylineArraySize * 4)
3644
+ polylinesArray = this .polylinesArray = new Float32Array (polylineArraySize * polylineArraySize * 4);
3275
3645
 
3276
- for (var i = 0, length = vertices .length; i < length; i += 8)
3277
- {
3278
- vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3279
- vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3646
+ let lengthSoFar = 0;
3280
3647
 
3281
- lengthSoFar += vertex2 .subtract (vertex1) .abs ();
3282
- lengthSoFarArray .push (lengthSoFar);
3283
- }
3284
- }
3285
- else
3648
+ for (let i = 0, length = vertices .length; i < length; i += 8)
3286
3649
  {
3287
- this .getRandomPosition = getPosition;
3288
- }
3289
- };
3290
- })(),
3291
- getRandomPosition: function (position)
3292
- {
3293
- // Determine index0 and weight.
3294
-
3295
- var
3296
- lengthSoFarArray = this .lengthSoFarArray,
3297
- length = lengthSoFarArray .length,
3298
- fraction = Math .random () * lengthSoFarArray .at (-1),
3299
- index0 = 0,
3300
- index1 = 0,
3301
- weight = 0;
3650
+ vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3651
+ vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3302
3652
 
3303
- if (length == 1 || fraction <= lengthSoFarArray [0])
3304
- {
3305
- index0 = 0;
3306
- weight = 0;
3307
- }
3308
- else if (fraction >= lengthSoFarArray .at (-1))
3309
- {
3310
- index0 = length - 2;
3311
- weight = 1;
3312
- }
3313
- else
3314
- {
3315
- var index = Algorithm .upperBound (lengthSoFarArray, 0, length, fraction, Algorithm .less);
3653
+ polylinesArray [i / 2 + 4] = lengthSoFar += vertex2 .subtract (vertex1) .abs ();
3654
+ }
3316
3655
 
3317
- if (index < length)
3318
- {
3319
- index1 = index;
3320
- index0 = index - 1;
3656
+ polylinesArray .set (vertices, verticesIndex * 4);
3321
3657
 
3322
- var
3323
- key0 = lengthSoFarArray [index0],
3324
- key1 = lengthSoFarArray [index1];
3658
+ this .setUniform ("uniform1i", "verticesIndex", numVertices ? verticesIndex : -1);
3325
3659
 
3326
- weight = Algorithm .clamp ((fraction - key0) / (key1 - key0), 0, 1);
3327
- }
3328
- else
3660
+ if (polylineArraySize)
3329
3661
  {
3330
- index0 = 0;
3331
- weight = 0;
3662
+ gl .bindTexture (gl .TEXTURE_2D, this .polylinesTexture);
3663
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, polylineArraySize, polylineArraySize, 0, gl .RGBA, gl .FLOAT, polylinesArray);
3332
3664
  }
3333
- }
3334
-
3335
- // Interpolate and set position.
3336
-
3337
- index0 *= 8;
3338
- index1 = index0 + 4;
3339
-
3340
- var
3341
- vertices = this .vertices,
3342
- x1 = vertices [index0],
3343
- y1 = vertices [index0 + 1],
3344
- z1 = vertices [index0 + 2],
3345
- x2 = vertices [index1],
3346
- y2 = vertices [index1 + 1],
3347
- z2 = vertices [index1 + 2];
3348
-
3349
- position .x = x1 + weight * (x2 - x1);
3350
- position .y = y1 + weight * (y2 - y1);
3351
- position .z = z1 + weight * (z2 - z1);
3352
-
3353
- return position;
3354
- },
3355
- getRandomVelocity: function (velocity)
3665
+ };
3666
+ })(),
3667
+ activateTextures: function (gl, program)
3356
3668
  {
3357
- var
3358
- direction = this .direction,
3359
- speed = this .getRandomSpeed ();
3360
-
3361
- velocity .x = direction .x * speed;
3362
- velocity .y = direction .y * speed;
3363
- velocity .z = direction .z * speed;
3364
-
3365
- return velocity;
3366
- },
3669
+ gl .activeTexture (gl .TEXTURE0 + program .polylinesTextureUnit);
3670
+ gl .bindTexture (gl .TEXTURE_2D, this .polylinesTexture);
3671
+ },
3367
3672
  });
3368
3673
 
3369
- function getPosition (position)
3370
- {
3371
- return position .set (0, 0, 0);
3372
- }
3373
-
3374
3674
  return PolylineEmitter;
3375
3675
  });
3376
3676
 
@@ -3432,7 +3732,6 @@ define ('x_ite/Components/ParticleSystems/SurfaceEmitter',[
3432
3732
  "x_ite/Base/X3DCast",
3433
3733
  "standard/Math/Geometry/Triangle3",
3434
3734
  "standard/Math/Numbers/Vector3",
3435
- "standard/Math/Algorithm",
3436
3735
  ],
3437
3736
  function (Fields,
3438
3737
  X3DFieldDefinition,
@@ -3441,8 +3740,7 @@ function (Fields,
3441
3740
  X3DConstants,
3442
3741
  X3DCast,
3443
3742
  Triangle3,
3444
- Vector3,
3445
- Algorithm)
3743
+ Vector3)
3446
3744
  {
3447
3745
  "use strict";
3448
3746
 
@@ -3452,25 +3750,52 @@ function (Fields,
3452
3750
 
3453
3751
  this .addType (X3DConstants .SurfaceEmitter);
3454
3752
 
3455
- this ._speed .setUnit ("speed");
3456
- this ._mass .setUnit ("mass");
3457
- this ._surfaceArea .setUnit ("area");
3753
+ this .surfaceNode = null;
3754
+ this .surfaceArray = new Float32Array ();
3755
+
3756
+ this .addSampler ("surface");
3757
+
3758
+ this .addUniform ("solid", "uniform bool solid;");
3759
+ this .addUniform ("verticesIndex", "uniform int verticesIndex;");
3760
+ this .addUniform ("normalsIndex", "uniform int normalsIndex;");
3761
+ this .addUniform ("surface", "uniform sampler2D surface;");
3458
3762
 
3459
- this .surfaceNode = null;
3460
- this .areaSoFarArray = [ 0 ];
3461
- this .direction = new Vector3 (0, 0, 0);
3763
+ this .addFunction (/* glsl */ `vec4 position; vec3 getRandomVelocity ()
3764
+ {
3765
+ if (verticesIndex < 0)
3766
+ {
3767
+ return vec3 (0.0);
3768
+ }
3769
+ else
3770
+ {
3771
+ vec3 normal;
3772
+
3773
+ getRandomPointOnSurface (surface, verticesIndex, normalsIndex, position, normal);
3774
+
3775
+ if (solid == false && random () > 0.5)
3776
+ normal = -normal;
3777
+
3778
+ return normal * getRandomSpeed ();
3779
+ }
3780
+ }`);
3781
+
3782
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
3783
+ {
3784
+ return verticesIndex < 0 ? vec4 (NaN) : position;
3785
+ }`);
3462
3786
  }
3463
3787
 
3464
3788
  SurfaceEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
3465
3789
  {
3466
3790
  constructor: SurfaceEmitter,
3467
3791
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
3468
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3469
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3470
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3471
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
3472
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
3473
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surface", new Fields .SFNode ()),
3792
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3793
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
3794
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3795
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3796
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
3797
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
3798
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surface", new Fields .SFNode ()),
3474
3799
  ]),
3475
3800
  getTypeName: function ()
3476
3801
  {
@@ -3488,6 +3813,17 @@ function (Fields,
3488
3813
  {
3489
3814
  X3DParticleEmitterNode .prototype .initialize .call (this);
3490
3815
 
3816
+ const browser = this .getBrowser ();
3817
+
3818
+ if (browser .getContext () .getVersion () < 2)
3819
+ return;
3820
+
3821
+ // Create GL stuff.
3822
+
3823
+ this .surfaceTexture = this .createTexture ();
3824
+
3825
+ // Initialize fields.
3826
+
3491
3827
  this ._surface .addInterest ("set_surface__", this);
3492
3828
 
3493
3829
  this .set_surface__ ();
@@ -3495,142 +3831,99 @@ function (Fields,
3495
3831
  set_surface__: function ()
3496
3832
  {
3497
3833
  if (this .surfaceNode)
3834
+ {
3835
+ this .surfaceNode ._solid .removeInterest ("set_solid__", this);
3498
3836
  this .surfaceNode ._rebuild .removeInterest ("set_geometry__", this);
3837
+ }
3499
3838
 
3500
3839
  this .surfaceNode = X3DCast (X3DConstants .X3DGeometryNode, this ._surface);
3501
3840
 
3502
3841
  if (this .surfaceNode)
3842
+ {
3843
+ this .surfaceNode ._solid .addInterest ("set_solid__", this);
3503
3844
  this .surfaceNode ._rebuild .addInterest ("set_geometry__", this);
3845
+ }
3504
3846
 
3847
+ this .set_solid__ ();
3505
3848
  this .set_geometry__ ();
3506
3849
  },
3850
+ set_solid__: function ()
3851
+ {
3852
+ if (this .surfaceNode)
3853
+ this .setUniform ("uniform1i", "solid", this .surfaceNode ._solid .getValue ());
3854
+ },
3507
3855
  set_geometry__: (function ()
3508
3856
  {
3509
- var
3857
+ const
3510
3858
  vertex1 = new Vector3 (0, 0, 0),
3511
3859
  vertex2 = new Vector3 (0, 0, 0),
3512
3860
  vertex3 = new Vector3 (0, 0, 0);
3513
3861
 
3514
3862
  return function ()
3515
3863
  {
3864
+ const gl = this .getBrowser () .getContext ();
3865
+
3516
3866
  if (this .surfaceNode)
3517
3867
  {
3518
- delete this .getRandomPosition;
3519
- delete this .getRandomVelocity;
3868
+ const
3869
+ vertices = this .surfaceNode .getVertices () .getValue (),
3870
+ normals = this .surfaceNode .getNormals () .getValue (),
3871
+ numVertices = vertices .length / 4,
3872
+ numAreaSoFar = numVertices / 3 + 1,
3873
+ surfaceArraySize = Math .ceil (Math .sqrt (numAreaSoFar + numVertices + numVertices));
3874
+
3875
+ const
3876
+ verticesIndex = numAreaSoFar,
3877
+ normalsIndex = verticesIndex + numVertices;
3520
3878
 
3521
- var
3522
- areaSoFar = 0,
3523
- areaSoFarArray = this .areaSoFarArray,
3524
- vertices = this .surfaceNode .getVertices () .getValue ();
3879
+ let surfaceArray = this .surfaceArray;
3525
3880
 
3526
- this .normals = this .surfaceNode .getNormals () .getValue ();
3527
- this .vertices = vertices;
3881
+ if (surfaceArray .length < surfaceArraySize * surfaceArraySize * 4)
3882
+ surfaceArray = this .surfaceArray = new Float32Array (surfaceArraySize * surfaceArraySize * 4);
3528
3883
 
3529
- areaSoFarArray .length = 1;
3884
+ let areaSoFar = 0;
3530
3885
 
3531
- for (var i = 0, length = vertices .length; i < length; i += 12)
3886
+ for (let i = 0, length = vertices .length; i < length; i += 12)
3532
3887
  {
3533
3888
  vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3534
3889
  vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3535
3890
  vertex3 .set (vertices [i + 8], vertices [i + 9], vertices [i + 10]);
3536
3891
 
3537
- areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3538
- areaSoFarArray .push (areaSoFar);
3892
+ surfaceArray [i / 3 + 4] = areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3539
3893
  }
3540
- }
3541
- else
3542
- {
3543
- this .getRandomPosition = getPosition;
3544
- this .getRandomVelocity = this .getSphericalRandomVelocity;
3545
- }
3546
- };
3547
- })(),
3548
- getRandomPosition: function (position)
3549
- {
3550
- // Determine index0.
3551
3894
 
3552
- var
3553
- areaSoFarArray = this .areaSoFarArray,
3554
- length = areaSoFarArray .length,
3555
- fraction = Math .random () * areaSoFarArray .at (-1),
3556
- index0 = 0;
3895
+ surfaceArray .set (vertices, verticesIndex * 4);
3557
3896
 
3558
- if (length == 1 || fraction <= areaSoFarArray [0])
3559
- {
3560
- index0 = 0;
3561
- }
3562
- else if (fraction >= areaSoFarArray .at (-1))
3563
- {
3564
- index0 = length - 2;
3565
- }
3566
- else
3567
- {
3568
- var index = Algorithm .upperBound (areaSoFarArray, 0, length, fraction, Algorithm .less);
3897
+ for (let s = normalsIndex * 4, n = 0, l = normals .length; n < l; s += 4, n += 3)
3898
+ {
3899
+ surfaceArray [s + 0] = normals [n + 0];
3900
+ surfaceArray [s + 1] = normals [n + 1];
3901
+ surfaceArray [s + 2] = normals [n + 2];
3902
+ }
3569
3903
 
3570
- if (index < length)
3571
- {
3572
- index0 = index - 1;
3904
+ this .setUniform ("uniform1i", "verticesIndex", numVertices ? verticesIndex : -1);
3905
+ this .setUniform ("uniform1i", "normalsIndex", numVertices ? normalsIndex : -1);
3906
+
3907
+ if (surfaceArraySize)
3908
+ {
3909
+ gl .bindTexture (gl .TEXTURE_2D, this .surfaceTexture);
3910
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, surfaceArraySize, surfaceArraySize, 0, gl .RGBA, gl .FLOAT, surfaceArray);
3911
+ }
3573
3912
  }
3574
3913
  else
3575
3914
  {
3576
- index0 = 0;
3915
+ this .setUniform ("uniform1i", "verticesIndex", -1);
3916
+ this .setUniform ("uniform1i", "normalsIndex", -1);
3577
3917
  }
3578
- }
3579
-
3580
- // Random barycentric coordinates.
3581
-
3582
- var
3583
- u = Math .random (),
3584
- v = Math .random ();
3585
-
3586
- if (u + v > 1)
3587
- {
3588
- u = 1 - u;
3589
- v = 1 - v;
3590
- }
3591
-
3592
- var t = 1 - u - v;
3593
-
3594
- // Interpolate and set position.
3595
-
3596
- var
3597
- i = index0 * 12,
3598
- vertices = this .vertices;
3599
-
3600
- position .x = u * vertices [i] + v * vertices [i + 4] + t * vertices [i + 8];
3601
- position .y = u * vertices [i + 1] + v * vertices [i + 5] + t * vertices [i + 9];
3602
- position .z = u * vertices [i + 2] + v * vertices [i + 6] + t * vertices [i + 10];
3603
-
3604
- var
3605
- i = index0 * 9,
3606
- normals = this .normals,
3607
- direction = this .direction;
3608
-
3609
- direction .x = u * normals [i] + v * normals [i + 3] + t * normals [i + 6];
3610
- direction .y = u * normals [i + 1] + v * normals [i + 4] + t * normals [i + 7];
3611
- direction .z = u * normals [i + 2] + v * normals [i + 5] + t * normals [i + 8];
3612
-
3613
- return position;
3614
- },
3615
- getRandomVelocity: function (velocity)
3918
+ };
3919
+ })(),
3920
+ activateTextures: function (gl, program)
3616
3921
  {
3617
- var
3618
- speed = this .getRandomSpeed (),
3619
- direction = this .direction;
3620
-
3621
- velocity .x = direction .x * speed;
3622
- velocity .y = direction .y * speed;
3623
- velocity .z = direction .z * speed;
3624
-
3625
- return velocity;
3626
- },
3922
+ gl .activeTexture (gl .TEXTURE0 + program .surfaceTextureUnit);
3923
+ gl .bindTexture (gl .TEXTURE_2D, this .surfaceTexture);
3924
+ },
3627
3925
  });
3628
3926
 
3629
- function getPosition (position)
3630
- {
3631
- return position .set (0, 0, 0);
3632
- }
3633
-
3634
3927
  return SurfaceEmitter;
3635
3928
  });
3636
3929
 
@@ -3691,13 +3984,8 @@ define ('x_ite/Components/ParticleSystems/VolumeEmitter',[
3691
3984
  "x_ite/Components/Geometry3D/IndexedFaceSet",
3692
3985
  "x_ite/Base/X3DConstants",
3693
3986
  "standard/Math/Numbers/Vector3",
3694
- "standard/Math/Numbers/Rotation4",
3695
- "standard/Math/Geometry/Line3",
3696
- "standard/Math/Geometry/Plane3",
3697
3987
  "standard/Math/Geometry/Triangle3",
3698
- "standard/Math/Algorithm",
3699
3988
  "standard/Math/Utility/BVH",
3700
- "standard/Math/Algorithms/QuickSort",
3701
3989
  ],
3702
3990
  function (Fields,
3703
3991
  X3DFieldDefinition,
@@ -3706,13 +3994,8 @@ function (Fields,
3706
3994
  IndexedFaceSet,
3707
3995
  X3DConstants,
3708
3996
  Vector3,
3709
- Rotation4,
3710
- Line3,
3711
- Plane3,
3712
3997
  Triangle3,
3713
- Algorithm,
3714
- BVH,
3715
- QuickSort)
3998
+ BVH)
3716
3999
  {
3717
4000
  "use strict";
3718
4001
 
@@ -3722,28 +4005,87 @@ function (Fields,
3722
4005
 
3723
4006
  this .addType (X3DConstants .VolumeEmitter);
3724
4007
 
3725
- this ._speed .setUnit ("speed");
3726
- this ._mass .setUnit ("mass");
3727
- this ._surfaceArea .setUnit ("area");
4008
+ this .volumeNode = new IndexedFaceSet (executionContext);
4009
+ this .volumeArray = new Float32Array ();
4010
+
4011
+ this .addSampler ("volume");
4012
+
4013
+ this .addUniform ("direction", "uniform vec3 direction;");
4014
+ this .addUniform ("verticesIndex", "uniform int verticesIndex;");
4015
+ this .addUniform ("normalsIndex", "uniform int normalsIndex;");
4016
+ this .addUniform ("hierarchyIndex", "uniform int hierarchyIndex;");
4017
+ this .addUniform ("hierarchyRoot", "uniform int hierarchyRoot;");
4018
+ this .addUniform ("volume", "uniform sampler2D volume;");
4019
+
4020
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
4021
+ {
4022
+ if (hierarchyRoot < 0)
4023
+ {
4024
+ return vec3 (0.0);
4025
+ }
4026
+ else
4027
+ {
4028
+ if (direction == vec3 (0.0))
4029
+ return getRandomSphericalVelocity ();
4030
+
4031
+ else
4032
+ return direction * getRandomSpeed ();
4033
+ }
4034
+ }`);
4035
+
4036
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
4037
+ {
4038
+ if (hierarchyRoot < 0)
4039
+ {
4040
+ return vec4 (NaN);
4041
+ }
4042
+ else
4043
+ {
4044
+ vec4 point;
4045
+ vec3 normal;
4046
+
4047
+ getRandomPointOnSurface (volume, verticesIndex, normalsIndex, point, normal);
4048
+
4049
+ Line3 line = Line3 (point .xyz, getRandomSurfaceNormal (normal));
4050
+
4051
+ vec4 points [ARRAY_SIZE];
4052
+
4053
+ int numIntersections = getIntersections (volume, verticesIndex, hierarchyIndex, hierarchyRoot, line, points);
4054
+
4055
+ numIntersections -= numIntersections % 2; // We need an even count of intersections.
3728
4056
 
3729
- this .direction = new Vector3 (0, 0, 0);
3730
- this .volumeNode = new IndexedFaceSet (executionContext);
3731
- this .areaSoFarArray = [ 0 ];
4057
+ switch (numIntersections)
4058
+ {
4059
+ case 0:
4060
+ return vec4 (0.0);
4061
+ case 2:
4062
+ break;
4063
+ default:
4064
+ sort (points, numIntersections, plane3 (line .point, line .direction));
4065
+ break;
4066
+ }
4067
+
4068
+ int index = int (fract (random ()) * float (numIntersections / 2)) * 2; // Select random intersection.
4069
+
4070
+ return mix (points [index], points [index + 1], random ());
4071
+ }
4072
+ }`);
3732
4073
  }
3733
4074
 
3734
4075
  VolumeEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
3735
4076
  {
3736
4077
  constructor: VolumeEmitter,
3737
4078
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
3738
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3739
- new X3DFieldDefinition (X3DConstants .initializeOnly, "internal", new Fields .SFBool (true)),
3740
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
3741
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3742
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3743
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
3744
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
3745
- new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
3746
- new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
4079
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
4080
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
4081
+ new X3DFieldDefinition (X3DConstants .inputOutput, "internal", new Fields .SFBool (true)),
4082
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
4083
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
4084
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
4085
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
4086
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
4087
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
4088
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
3747
4089
  ]),
3748
4090
  getTypeName: function ()
3749
4091
  {
@@ -3761,6 +4103,17 @@ function (Fields,
3761
4103
  {
3762
4104
  X3DParticleEmitterNode .prototype .initialize .call (this);
3763
4105
 
4106
+ const browser = this .getBrowser ();
4107
+
4108
+ if (browser .getContext () .getVersion () < 2)
4109
+ return;
4110
+
4111
+ // Create GL stuff.
4112
+
4113
+ this .volumeTexture = this .createTexture ();
4114
+
4115
+ // Initialize fields.
4116
+
3764
4117
  this ._direction .addInterest ("set_direction__", this);
3765
4118
 
3766
4119
  this ._coordIndex .addFieldInterest (this .volumeNode ._coordIndex);
@@ -3778,184 +4131,86 @@ function (Fields,
3778
4131
  this .set_direction__ ();
3779
4132
  this .set_geometry__ ();
3780
4133
  },
3781
- set_direction__: function ()
4134
+ set_direction__: (function ()
3782
4135
  {
3783
- this .direction .assign (this ._direction .getValue ()) .normalize ();
4136
+ const direction = new Vector3 (0, 0, 0);
3784
4137
 
3785
- if (this .direction .equals (Vector3 .Zero))
3786
- this .getRandomVelocity = this .getSphericalRandomVelocity;
3787
- else
3788
- delete this .getRandomVelocity;
3789
- },
4138
+ return function ()
4139
+ {
4140
+ direction .assign (this ._direction .getValue ()) .normalize ();
4141
+
4142
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
4143
+ };
4144
+ })(),
3790
4145
  set_geometry__: (function ()
3791
4146
  {
3792
- var
4147
+ const
3793
4148
  vertex1 = new Vector3 (0, 0, 0),
3794
4149
  vertex2 = new Vector3 (0, 0, 0),
3795
4150
  vertex3 = new Vector3 (0, 0, 0);
3796
4151
 
3797
4152
  return function ()
3798
4153
  {
3799
- var
3800
- areaSoFar = 0,
3801
- areaSoFarArray = this .areaSoFarArray,
3802
- normals = this .volumeNode .getNormals () .getValue (),
3803
- vertices = this .volumeNode .getVertices () .getValue ();
4154
+ const
4155
+ gl = this .getBrowser () .getContext (),
4156
+ vertices = this .volumeNode .getVertices () .getValue (),
4157
+ normals = this .volumeNode .getNormals () .getValue (),
4158
+ hierarchy = new BVH (vertices, normals) .toArray ([ ]),
4159
+ numVertices = vertices .length / 4,
4160
+ numNormals = normals .length / 3,
4161
+ numAreaSoFar = numVertices / 3 + 1,
4162
+ hierarchyLength = hierarchy .length / 4,
4163
+ volumeArraySize = Math .ceil (Math .sqrt (numAreaSoFar + numVertices + numVertices + hierarchyLength));
3804
4164
 
3805
- this .normals = normals;
3806
- this .vertices = vertices;
4165
+ const
4166
+ verticesIndex = numAreaSoFar,
4167
+ normalsIndex = verticesIndex + numVertices,
4168
+ hierarchyIndex = normalsIndex + numNormals;
4169
+
4170
+ let volumeArray = this .volumeArray;
3807
4171
 
3808
- areaSoFarArray .length = 1;
4172
+ if (volumeArray .length < volumeArraySize * volumeArraySize * 4)
4173
+ volumeArray = this .volumeArray = new Float32Array (volumeArraySize * volumeArraySize * 4);
3809
4174
 
3810
- for (var i = 0, length = vertices .length; i < length; i += 12)
4175
+ let areaSoFar = 0;
4176
+
4177
+ for (let i = 0, length = vertices .length; i < length; i += 12)
3811
4178
  {
3812
4179
  vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3813
4180
  vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3814
4181
  vertex3 .set (vertices [i + 8], vertices [i + 9], vertices [i + 10]);
3815
4182
 
3816
- areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3817
- areaSoFarArray .push (areaSoFar);
3818
- }
3819
-
3820
- this .bvh = new BVH (vertices, normals);
3821
- };
3822
- })(),
3823
- getRandomPosition: (function ()
3824
- {
3825
- var
3826
- point = new Vector3 (0, 0, 0),
3827
- normal = new Vector3 (0, 0, 0),
3828
- rotation = new Rotation4 (0, 0, 1, 0),
3829
- line = new Line3 (Vector3 .Zero, Vector3 .zAxis),
3830
- plane = new Plane3 (Vector3 .Zero, Vector3 .zAxis),
3831
- intersections = [ ],
3832
- sorter = new QuickSort (intersections, PlaneCompare);
3833
-
3834
- function PlaneCompare (a, b)
3835
- {
3836
- return plane .getDistanceToPoint (a) < plane .getDistanceToPoint (b);
3837
- }
3838
-
3839
- return function (position)
3840
- {
3841
- // Get random point on surface
3842
-
3843
- // Determine index0.
3844
-
3845
- var
3846
- areaSoFarArray = this .areaSoFarArray,
3847
- length = areaSoFarArray .length,
3848
- fraction = Math .random () * areaSoFarArray .at (-1),
3849
- index0 = 0;
3850
-
3851
- if (length == 1 || fraction <= areaSoFarArray [0])
3852
- {
3853
- index0 = 0;
3854
- }
3855
- else if (fraction >= areaSoFarArray .at (-1))
3856
- {
3857
- index0 = length - 2;
3858
- }
3859
- else
3860
- {
3861
- var index = Algorithm .upperBound (areaSoFarArray, 0, length, fraction, Algorithm .less);
3862
-
3863
- if (index < length)
3864
- {
3865
- index0 = index - 1;
3866
- }
3867
- else
3868
- {
3869
- index0 = 0;
3870
- }
4183
+ volumeArray [i / 3 + 4] = areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3871
4184
  }
3872
4185
 
3873
- // Random barycentric coordinates.
3874
-
3875
- var
3876
- u = Math .random (),
3877
- v = Math .random ();
4186
+ volumeArray .set (vertices, verticesIndex * 4);
3878
4187
 
3879
- if (u + v > 1)
4188
+ for (let s = normalsIndex * 4, n = 0, l = normals .length; n < l; s += 4, n += 3)
3880
4189
  {
3881
- u = 1 - u;
3882
- v = 1 - v;
4190
+ volumeArray [s + 0] = normals [n + 0];
4191
+ volumeArray [s + 1] = normals [n + 1];
4192
+ volumeArray [s + 2] = normals [n + 2];
3883
4193
  }
3884
4194
 
3885
- var t = 1 - u - v;
4195
+ volumeArray .set (hierarchy, hierarchyIndex * 4);
3886
4196
 
3887
- // Interpolate and determine random point on surface and normal.
4197
+ this .setUniform ("uniform1i", "verticesIndex", verticesIndex);
4198
+ this .setUniform ("uniform1i", "normalsIndex", normalsIndex);
4199
+ this .setUniform ("uniform1i", "hierarchyIndex", hierarchyIndex);
4200
+ this .setUniform ("uniform1i", "hierarchyRoot", hierarchyIndex + hierarchyLength - 1);
3888
4201
 
3889
- var
3890
- i = index0 * 12,
3891
- vertices = this .vertices;
3892
-
3893
- point .x = u * vertices [i] + v * vertices [i + 4] + t * vertices [i + 8];
3894
- point .y = u * vertices [i + 1] + v * vertices [i + 5] + t * vertices [i + 9];
3895
- point .z = u * vertices [i + 2] + v * vertices [i + 6] + t * vertices [i + 10];
3896
-
3897
- var
3898
- i = index0 * 9,
3899
- normals = this .normals;
3900
-
3901
- normal .x = u * normals [i] + v * normals [i + 3] + t * normals [i + 6];
3902
- normal .y = u * normals [i + 1] + v * normals [i + 4] + t * normals [i + 7];
3903
- normal .z = u * normals [i + 2] + v * normals [i + 5] + t * normals [i + 8];
3904
-
3905
- rotation .setFromToVec (Vector3 .zAxis, normal);
3906
- rotation .multVecRot (this .getRandomSurfaceNormal (normal));
3907
-
3908
- // Setup random line throu volume for intersection text
3909
- // and a plane corresponding to the line for intersection sorting.
3910
-
3911
- line .set (point, normal);
3912
- plane .set (point, normal);
3913
-
3914
- // Find random point in volume.
3915
-
3916
- var numIntersections = this .bvh .intersectsLine (line, intersections);
3917
-
3918
- numIntersections -= numIntersections % 2; // We need an even count of intersections.
3919
-
3920
- if (numIntersections)
4202
+ if (volumeArraySize)
3921
4203
  {
3922
- // Sort intersections along line with a little help from the plane.
3923
-
3924
- sorter .sort (0, numIntersections);
3925
-
3926
- // Select random intersection pair.
3927
-
3928
- var
3929
- index = Math .round (this .getRandomValue (0, numIntersections / 2 - 1)) * 2,
3930
- point0 = intersections [index],
3931
- point1 = intersections [index + 1],
3932
- t = Math .random ();
3933
-
3934
- // lerp
3935
- position .x = point0 .x + (point1 .x - point0 .x) * t;
3936
- position .y = point0 .y + (point1 .y - point0 .y) * t;
3937
- position .z = point0 .z + (point1 .z - point0 .z) * t;
3938
-
3939
- return position;
4204
+ gl .bindTexture (gl .TEXTURE_2D, this .volumeTexture);
4205
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, volumeArraySize, volumeArraySize, 0, gl .RGBA, gl .FLOAT, volumeArray);
3940
4206
  }
3941
-
3942
- // Discard point.
3943
-
3944
- return position .set (Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY);
3945
4207
  };
3946
4208
  })(),
3947
- getRandomVelocity: function (velocity)
4209
+ activateTextures: function (gl, program)
3948
4210
  {
3949
- var
3950
- direction = this .direction,
3951
- speed = this .getRandomSpeed ();
3952
-
3953
- velocity .x = direction .x * speed;
3954
- velocity .y = direction .y * speed;
3955
- velocity .z = direction .z * speed;
3956
-
3957
- return velocity;
3958
- },
4211
+ gl .activeTexture (gl .TEXTURE0 + program .volumeTextureUnit);
4212
+ gl .bindTexture (gl .TEXTURE_2D, this .volumeTexture);
4213
+ },
3959
4214
  });
3960
4215
 
3961
4216
  return VolumeEmitter;
@@ -4063,7 +4318,7 @@ function (Fields,
4063
4318
  },
4064
4319
  getRandomSpeed: function (emitterNode)
4065
4320
  {
4066
- var
4321
+ const
4067
4322
  speed = Math .max (0, this ._speed .getValue ()),
4068
4323
  variation = speed * Math .max (0, this ._gustiness .getValue ());
4069
4324
 
@@ -4071,27 +4326,32 @@ function (Fields,
4071
4326
  },
4072
4327
  addForce: (function ()
4073
4328
  {
4074
- var force = new Vector3 (0, 0, 0);
4329
+ const force = new Vector3 (0, 0, 0);
4075
4330
 
4076
- return function (i, emitterNode, forces, turbulences)
4331
+ return function (i, emitterNode, timeByMass, forces)
4077
4332
  {
4078
- var surfaceArea = emitterNode ._surfaceArea .getValue ()
4079
-
4080
4333
  if (this ._enabled .getValue ())
4081
4334
  {
4082
- var
4083
- randomSpeed = this .getRandomSpeed (emitterNode),
4084
- pressure = Math .pow (10, 2 * Math .log (randomSpeed)) * 0.64615;
4335
+ const
4336
+ surfaceArea = emitterNode ._surfaceArea .getValue (),
4337
+ speed = this .getRandomSpeed (emitterNode),
4338
+ pressure = Math .pow (10, 2 * Math .log (speed)) * 0.64615;
4085
4339
 
4086
4340
  if (this ._direction .getValue () .equals (Vector3 .Zero))
4087
4341
  emitterNode .getRandomNormal (force);
4088
4342
  else
4089
4343
  force .assign (this ._direction .getValue ()) .normalize ();
4090
4344
 
4091
- forces [i] .assign (force .multiply (surfaceArea * pressure));
4092
- turbulences [i] = Math .PI * Algorithm .clamp (this ._turbulence .getValue (), 0, 1);
4345
+ forces .set (force .multiply (surfaceArea * pressure * timeByMass), i * 4);
4346
+ forces [i * 4 + 3] = Math .PI * Algorithm .clamp (this ._turbulence .getValue (), 0, 1);
4347
+
4348
+ return true;
4093
4349
  }
4094
- };
4350
+ else
4351
+ {
4352
+ return false;
4353
+ }
4354
+ }
4095
4355
  })(),
4096
4356
  });
4097
4357
 
@@ -4199,7 +4459,7 @@ function (Components,
4199
4459
  X3DParticleEmitterNode: X3DParticleEmitterNode,
4200
4460
  X3DParticlePhysicsModelNode: X3DParticlePhysicsModelNode,
4201
4461
  },
4202
- browser: X3DParticleSystemsContext,
4462
+ context: X3DParticleSystemsContext,
4203
4463
  });
4204
4464
  });
4205
4465