babylon.scene.ts 107 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806
  1. module BABYLON {
  2. export interface IDisposable {
  3. dispose(): void;
  4. }
  5. export class PointerEventTypes {
  6. static _POINTERDOWN = 0x01;
  7. static _POINTERUP = 0x02;
  8. static _POINTERMOVE = 0x04;
  9. static _POINTERWHEEL = 0x08;
  10. static _POINTERPICK = 0x10;
  11. public static get POINTERDOWN(): number {
  12. return PointerEventTypes._POINTERDOWN;
  13. }
  14. public static get POINTERUP(): number {
  15. return PointerEventTypes._POINTERUP;
  16. }
  17. public static get POINTERMOVE(): number {
  18. return PointerEventTypes._POINTERMOVE;
  19. }
  20. public static get POINTERWHEEL(): number {
  21. return PointerEventTypes._POINTERWHEEL;
  22. }
  23. public static get POINTERPICK(): number {
  24. return PointerEventTypes._POINTERPICK;
  25. }
  26. }
  27. /**
  28. * This type contains all the data related to a pointer event in Babylon.js.
  29. * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The differents event types can be found in the PointerEventTypes class.
  30. */
  31. export class PointerInfo {
  32. constructor(public type: number, public event: PointerEvent | MouseWheelEvent, public pickInfo: PickingInfo) {
  33. }
  34. }
  35. /**
  36. * Represents a scene to be rendered by the engine.
  37. * @see http://doc.babylonjs.com/page.php?p=21911
  38. */
  39. export class Scene implements IAnimatable {
  40. // Statics
  41. private static _FOGMODE_NONE = 0;
  42. private static _FOGMODE_EXP = 1;
  43. private static _FOGMODE_EXP2 = 2;
  44. private static _FOGMODE_LINEAR = 3;
  45. public static MinDeltaTime = 1.0;
  46. public static MaxDeltaTime = 1000.0;
  47. public static get FOGMODE_NONE(): number {
  48. return Scene._FOGMODE_NONE;
  49. }
  50. public static get FOGMODE_EXP(): number {
  51. return Scene._FOGMODE_EXP;
  52. }
  53. public static get FOGMODE_EXP2(): number {
  54. return Scene._FOGMODE_EXP2;
  55. }
  56. public static get FOGMODE_LINEAR(): number {
  57. return Scene._FOGMODE_LINEAR;
  58. }
  59. // Members
  60. public autoClear = true;
  61. public clearColor: any = new Color3(0.2, 0.2, 0.3);
  62. public ambientColor = new Color3(0, 0, 0);
  63. public forceWireframe = false;
  64. public forcePointsCloud = false;
  65. public forceShowBoundingBoxes = false;
  66. public clipPlane: Plane;
  67. public animationsEnabled = true;
  68. public constantlyUpdateMeshUnderPointer = false;
  69. // Events
  70. /**
  71. * An event triggered when the scene is disposed.
  72. * @type {BABYLON.Observable}
  73. */
  74. public onDisposeObservable = new Observable<Scene>();
  75. private _onDisposeObserver: Observer<Scene>;
  76. public set onDispose(callback: () => void) {
  77. if (this._onDisposeObserver) {
  78. this.onDisposeObservable.remove(this._onDisposeObserver);
  79. }
  80. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  81. }
  82. /**
  83. * An event triggered before rendering the scene
  84. * @type {BABYLON.Observable}
  85. */
  86. public onBeforeRenderObservable = new Observable<Scene>();
  87. private _onBeforeRenderObserver: Observer<Scene>;
  88. public set beforeRender(callback: () => void) {
  89. if (this._onBeforeRenderObserver) {
  90. this.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
  91. }
  92. this._onBeforeRenderObserver = this.onBeforeRenderObservable.add(callback);
  93. }
  94. /**
  95. * An event triggered after rendering the scene
  96. * @type {BABYLON.Observable}
  97. */
  98. public onAfterRenderObservable = new Observable<Scene>();
  99. private _onAfterRenderObserver: Observer<Scene>;
  100. public set afterRender(callback: () => void) {
  101. if (this._onAfterRenderObserver) {
  102. this.onAfterRenderObservable.remove(this._onAfterRenderObserver);
  103. }
  104. this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback);
  105. }
  106. /**
  107. * An event triggered when the scene is ready
  108. * @type {BABYLON.Observable}
  109. */
  110. public onReadyObservable = new Observable<Scene>();
  111. /**
  112. * An event triggered before rendering a camera
  113. * @type {BABYLON.Observable}
  114. */
  115. public onBeforeCameraRenderObservable = new Observable<Camera>();
  116. private _onBeforeCameraRenderObserver: Observer<Camera>;
  117. public set beforeCameraRender(callback: () => void) {
  118. if (this._onBeforeCameraRenderObserver) {
  119. this.onBeforeCameraRenderObservable.remove(this._onBeforeCameraRenderObserver);
  120. }
  121. this._onBeforeCameraRenderObserver = this.onBeforeCameraRenderObservable.add(callback);
  122. }
  123. /**
  124. * An event triggered after rendering a camera
  125. * @type {BABYLON.Observable}
  126. */
  127. public onAfterCameraRenderObservable = new Observable<Camera>();
  128. private _onAfterCameraRenderObserver: Observer<Camera>;
  129. public set afterCameraRender(callback: () => void) {
  130. if (this._onAfterCameraRenderObserver) {
  131. this.onAfterCameraRenderObservable.remove(this._onAfterCameraRenderObserver);
  132. }
  133. this._onAfterCameraRenderObserver = this.onAfterCameraRenderObservable.add(callback);
  134. }
  135. /**
  136. * An event triggered when a camera is created
  137. * @type {BABYLON.Observable}
  138. */
  139. public onNewCameraAddedObservable = new Observable<Camera>();
  140. /**
  141. * An event triggered when a camera is removed
  142. * @type {BABYLON.Observable}
  143. */
  144. public onCameraRemovedObservable = new Observable<Camera>();
  145. /**
  146. * An event triggered when a light is created
  147. * @type {BABYLON.Observable}
  148. */
  149. public onNewLightAddedObservable = new Observable<Light>();
  150. /**
  151. * An event triggered when a light is removed
  152. * @type {BABYLON.Observable}
  153. */
  154. public onLightRemovedObservable = new Observable<Light>();
  155. /**
  156. * An event triggered when a geometry is created
  157. * @type {BABYLON.Observable}
  158. */
  159. public onNewGeometryAddedObservable = new Observable<Geometry>();
  160. /**
  161. * An event triggered when a geometry is removed
  162. * @type {BABYLON.Observable}
  163. */
  164. public onGeometryRemovedObservable = new Observable<Geometry>();
  165. /**
  166. * An event triggered when a mesh is created
  167. * @type {BABYLON.Observable}
  168. */
  169. public onNewMeshAddedObservable = new Observable<AbstractMesh>();
  170. /**
  171. * An event triggered when a mesh is removed
  172. * @type {BABYLON.Observable}
  173. */
  174. public onMeshRemovedObservable = new Observable<AbstractMesh>();
  175. // Animations
  176. public animations: Animation[] = [];
  177. // Pointers
  178. public pointerDownPredicate: (Mesh: AbstractMesh) => boolean;
  179. public pointerUpPredicate: (Mesh: AbstractMesh) => boolean;
  180. public pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
  181. private _onPointerMove: (evt: PointerEvent) => void;
  182. private _onPointerDown: (evt: PointerEvent) => void;
  183. private _onPointerUp: (evt: PointerEvent) => void;
  184. /**
  185. * @deprecated Use onPointerObservable instead
  186. */
  187. public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  188. /**
  189. * @deprecated Use onPointerObservable instead
  190. */
  191. public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  192. /**
  193. * @deprecated Use onPointerObservable instead
  194. */
  195. public onPointerUp: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  196. /**
  197. * @deprecated Use onPointerObservable instead
  198. */
  199. public onPointerPick: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  200. /**
  201. * Observable event triggered each time an input event is received from the rendering canvas
  202. */
  203. public onPointerObservable = new Observable<PointerInfo>();
  204. public cameraToUseForPointers: Camera = null; // Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position
  205. private _pointerX: number;
  206. private _pointerY: number;
  207. private _unTranslatedPointerX: number;
  208. private _unTranslatedPointerY: number;
  209. private _startingPointerPosition = new Vector2(0, 0);
  210. private _startingPointerTime = 0;
  211. // Mirror
  212. public _mirroredCameraPosition: Vector3;
  213. // Keyboard
  214. private _onKeyDown: (evt: Event) => void;
  215. private _onKeyUp: (evt: Event) => void;
  216. // Fog
  217. /**
  218. * is fog enabled on this scene.
  219. * @type {boolean}
  220. */
  221. public fogEnabled = true;
  222. public fogMode = Scene.FOGMODE_NONE;
  223. public fogColor = new Color3(0.2, 0.2, 0.3);
  224. public fogDensity = 0.1;
  225. public fogStart = 0;
  226. public fogEnd = 1000.0;
  227. // Lights
  228. /**
  229. * is shadow enabled on this scene.
  230. * @type {boolean}
  231. */
  232. public shadowsEnabled = true;
  233. /**
  234. * is light enabled on this scene.
  235. * @type {boolean}
  236. */
  237. public lightsEnabled = true;
  238. /**
  239. * All of the lights added to this scene.
  240. * @see BABYLON.Light
  241. * @type {BABYLON.Light[]}
  242. */
  243. public lights = new Array<Light>();
  244. // Cameras
  245. /**
  246. * All of the cameras added to this scene.
  247. * @see BABYLON.Camera
  248. * @type {BABYLON.Camera[]}
  249. */
  250. public cameras = new Array<Camera>();
  251. public activeCameras = new Array<Camera>();
  252. public activeCamera: Camera;
  253. // Meshes
  254. /**
  255. * All of the (abstract) meshes added to this scene.
  256. * @see BABYLON.AbstractMesh
  257. * @type {BABYLON.AbstractMesh[]}
  258. */
  259. public meshes = new Array<AbstractMesh>();
  260. // Geometries
  261. private _geometries = new Array<Geometry>();
  262. public materials = new Array<Material>();
  263. public multiMaterials = new Array<MultiMaterial>();
  264. public defaultMaterial = new StandardMaterial("default material", this);
  265. // Textures
  266. public texturesEnabled = true;
  267. public textures = new Array<BaseTexture>();
  268. // Particles
  269. public particlesEnabled = true;
  270. public particleSystems = new Array<ParticleSystem>();
  271. // Sprites
  272. public spritesEnabled = true;
  273. public spriteManagers = new Array<SpriteManager>();
  274. // Layers
  275. public layers = new Array<Layer>();
  276. // Skeletons
  277. public skeletonsEnabled = true;
  278. public skeletons = new Array<Skeleton>();
  279. // Lens flares
  280. public lensFlaresEnabled = true;
  281. public lensFlareSystems = new Array<LensFlareSystem>();
  282. // Collisions
  283. public collisionsEnabled = true;
  284. private _workerCollisions;
  285. public collisionCoordinator: ICollisionCoordinator;
  286. public gravity = new Vector3(0, -9.807, 0);
  287. // Postprocesses
  288. public postProcessesEnabled = true;
  289. public postProcessManager: PostProcessManager;
  290. public postProcessRenderPipelineManager: PostProcessRenderPipelineManager;
  291. // Customs render targets
  292. public renderTargetsEnabled = true;
  293. public dumpNextRenderTargets = false;
  294. public customRenderTargets = new Array<RenderTargetTexture>();
  295. // Delay loading
  296. public useDelayedTextureLoading: boolean;
  297. // Imported meshes
  298. public importedMeshesFiles = new Array<String>();
  299. // Probes
  300. public probesEnabled = true;
  301. public reflectionProbes = new Array<ReflectionProbe>();
  302. // Database
  303. public database; //ANY
  304. // Actions
  305. /**
  306. * This scene's action manager
  307. * @type {BABYLON.ActionManager}
  308. */
  309. public actionManager: ActionManager;
  310. public _actionManagers = new Array<ActionManager>();
  311. private _meshesForIntersections = new SmartArray<AbstractMesh>(256);
  312. // Procedural textures
  313. public proceduralTexturesEnabled = true;
  314. public _proceduralTextures = new Array<ProceduralTexture>();
  315. // Sound Tracks
  316. public mainSoundTrack: SoundTrack;
  317. public soundTracks = new Array<SoundTrack>();
  318. private _audioEnabled = true;
  319. private _headphone = false;
  320. //Simplification Queue
  321. public simplificationQueue: SimplificationQueue;
  322. // Private
  323. private _engine: Engine;
  324. private _totalVertices = 0;
  325. public _activeIndices = 0;
  326. public _activeParticles = 0;
  327. private _lastFrameDuration = 0;
  328. private _evaluateActiveMeshesDuration = 0;
  329. private _renderTargetsDuration = 0;
  330. public _particlesDuration = 0;
  331. private _renderDuration = 0;
  332. public _spritesDuration = 0;
  333. private _animationRatio = 0;
  334. private _animationStartDate: number;
  335. public _cachedMaterial: Material;
  336. private _renderId = 0;
  337. private _executeWhenReadyTimeoutId = -1;
  338. private _intermediateRendering = false;
  339. public _toBeDisposed = new SmartArray<IDisposable>(256);
  340. private _pendingData = [];//ANY
  341. private _activeMeshes = new SmartArray<Mesh>(256);
  342. private _processedMaterials = new SmartArray<Material>(256);
  343. private _renderTargets = new SmartArray<RenderTargetTexture>(256);
  344. public _activeParticleSystems = new SmartArray<ParticleSystem>(256);
  345. private _activeSkeletons = new SmartArray<Skeleton>(32);
  346. private _softwareSkinnedMeshes = new SmartArray<Mesh>(32);
  347. public _activeBones = 0;
  348. private _renderingManager: RenderingManager;
  349. private _physicsEngine: PhysicsEngine;
  350. public _activeAnimatables = new Array<Animatable>();
  351. private _transformMatrix = Matrix.Zero();
  352. private _pickWithRayInverseMatrix: Matrix;
  353. private _edgesRenderers = new SmartArray<EdgesRenderer>(16);
  354. private _boundingBoxRenderer: BoundingBoxRenderer;
  355. private _outlineRenderer: OutlineRenderer;
  356. private _viewMatrix: Matrix;
  357. private _projectionMatrix: Matrix;
  358. private _frustumPlanes: Plane[];
  359. private _selectionOctree: Octree<AbstractMesh>;
  360. private _pointerOverMesh: AbstractMesh;
  361. private _pointerOverSprite: Sprite;
  362. private _debugLayer: DebugLayer;
  363. private _depthRenderer: DepthRenderer;
  364. private _uniqueIdCounter = 0;
  365. private _pickedDownMesh: AbstractMesh;
  366. private _pickedDownSprite: Sprite;
  367. /**
  368. * @constructor
  369. * @param {BABYLON.Engine} engine - the engine to be used to render this scene.
  370. */
  371. constructor(engine: Engine) {
  372. this._engine = engine;
  373. engine.scenes.push(this);
  374. this._renderingManager = new RenderingManager(this);
  375. this.postProcessManager = new PostProcessManager(this);
  376. this.postProcessRenderPipelineManager = new PostProcessRenderPipelineManager();
  377. this._boundingBoxRenderer = new BoundingBoxRenderer(this);
  378. if (OutlineRenderer) {
  379. this._outlineRenderer = new OutlineRenderer(this);
  380. }
  381. this.attachControl();
  382. this._debugLayer = new DebugLayer(this);
  383. if (SoundTrack) {
  384. this.mainSoundTrack = new SoundTrack(this, { mainTrack: true });
  385. }
  386. //simplification queue
  387. if (SimplificationQueue) {
  388. this.simplificationQueue = new SimplificationQueue();
  389. }
  390. //collision coordinator initialization. For now legacy per default.
  391. this.workerCollisions = false;//(!!Worker && (!!BABYLON.CollisionWorker || BABYLON.WorkerIncluded));
  392. }
  393. // Properties
  394. public get debugLayer(): DebugLayer {
  395. return this._debugLayer;
  396. }
  397. public set workerCollisions(enabled: boolean) {
  398. enabled = (enabled && !!Worker);
  399. this._workerCollisions = enabled;
  400. if (this.collisionCoordinator) {
  401. this.collisionCoordinator.destroy();
  402. }
  403. this.collisionCoordinator = enabled ? new CollisionCoordinatorWorker() : new CollisionCoordinatorLegacy();
  404. this.collisionCoordinator.init(this);
  405. }
  406. public get workerCollisions(): boolean {
  407. return this._workerCollisions;
  408. }
  409. public get SelectionOctree(): Octree<AbstractMesh> {
  410. return this._selectionOctree;
  411. }
  412. /**
  413. * The mesh that is currently under the pointer.
  414. * @return {BABYLON.AbstractMesh} mesh under the pointer/mouse cursor or null if none.
  415. */
  416. public get meshUnderPointer(): AbstractMesh {
  417. return this._pointerOverMesh;
  418. }
  419. /**
  420. * Current on-screen X position of the pointer
  421. * @return {number} X position of the pointer
  422. */
  423. public get pointerX(): number {
  424. return this._pointerX;
  425. }
  426. /**
  427. * Current on-screen Y position of the pointer
  428. * @return {number} Y position of the pointer
  429. */
  430. public get pointerY(): number {
  431. return this._pointerY;
  432. }
  433. public getCachedMaterial(): Material {
  434. return this._cachedMaterial;
  435. }
  436. public getBoundingBoxRenderer(): BoundingBoxRenderer {
  437. return this._boundingBoxRenderer;
  438. }
  439. public getOutlineRenderer(): OutlineRenderer {
  440. return this._outlineRenderer;
  441. }
  442. public getEngine(): Engine {
  443. return this._engine;
  444. }
  445. public getTotalVertices(): number {
  446. return this._totalVertices;
  447. }
  448. public getActiveIndices(): number {
  449. return this._activeIndices;
  450. }
  451. public getActiveParticles(): number {
  452. return this._activeParticles;
  453. }
  454. public getActiveBones(): number {
  455. return this._activeBones;
  456. }
  457. // Stats
  458. public getLastFrameDuration(): number {
  459. return this._lastFrameDuration;
  460. }
  461. public getEvaluateActiveMeshesDuration(): number {
  462. return this._evaluateActiveMeshesDuration;
  463. }
  464. public getActiveMeshes(): SmartArray<Mesh> {
  465. return this._activeMeshes;
  466. }
  467. public getRenderTargetsDuration(): number {
  468. return this._renderTargetsDuration;
  469. }
  470. public getRenderDuration(): number {
  471. return this._renderDuration;
  472. }
  473. public getParticlesDuration(): number {
  474. return this._particlesDuration;
  475. }
  476. public getSpritesDuration(): number {
  477. return this._spritesDuration;
  478. }
  479. public getAnimationRatio(): number {
  480. return this._animationRatio;
  481. }
  482. public getRenderId(): number {
  483. return this._renderId;
  484. }
  485. public incrementRenderId(): void {
  486. this._renderId++;
  487. }
  488. private _updatePointerPosition(evt: PointerEvent): void {
  489. var canvasRect = this._engine.getRenderingCanvasClientRect();
  490. this._pointerX = evt.clientX - canvasRect.left;
  491. this._pointerY = evt.clientY - canvasRect.top;
  492. this._unTranslatedPointerX = this._pointerX;
  493. this._unTranslatedPointerY = this._pointerY;
  494. if (this.cameraToUseForPointers) {
  495. this._pointerX = this._pointerX - this.cameraToUseForPointers.viewport.x * this._engine.getRenderWidth();
  496. this._pointerY = this._pointerY - this.cameraToUseForPointers.viewport.y * this._engine.getRenderHeight();
  497. }
  498. }
  499. // Pointers handling
  500. /**
  501. * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
  502. * @param attachUp defines if you want to attach events to pointerup
  503. * @param attachDown defines if you want to attach events to pointerdown
  504. * @param attachMove defines if you want to attach events to pointermove
  505. */
  506. public attachControl(attachUp = true, attachDown = true, attachMove = true) {
  507. var spritePredicate = (sprite: Sprite): boolean => {
  508. return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
  509. };
  510. this._onPointerMove = (evt: PointerEvent) => {
  511. if (!this.cameraToUseForPointers && !this.activeCamera) {
  512. return;
  513. }
  514. var canvas = this._engine.getRenderingCanvas();
  515. this._updatePointerPosition(evt);
  516. if (!this.pointerMovePredicate) {
  517. this.pointerMovePredicate = (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && (this.constantlyUpdateMeshUnderPointer || mesh.actionManager !== null && mesh.actionManager !== undefined);
  518. }
  519. // Meshes
  520. var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);
  521. if (pickResult.hit && pickResult.pickedMesh) {
  522. this.setPointerOverSprite(null);
  523. this.setPointerOverMesh(pickResult.pickedMesh);
  524. if (this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
  525. canvas.style.cursor = "pointer";
  526. } else {
  527. canvas.style.cursor = "";
  528. }
  529. } else {
  530. this.setPointerOverMesh(null);
  531. // Sprites
  532. pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
  533. if (pickResult.hit && pickResult.pickedSprite) {
  534. canvas.style.cursor = "pointer";
  535. this.setPointerOverSprite(pickResult.pickedSprite);
  536. } else {
  537. this.setPointerOverSprite(null);
  538. // Restore pointer
  539. canvas.style.cursor = "";
  540. }
  541. }
  542. if (this.onPointerMove) {
  543. this.onPointerMove(evt, pickResult);
  544. }
  545. if (this.onPointerObservable.hasObservers()) {
  546. let type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
  547. let pi = new PointerInfo(type, evt, pickResult);
  548. this.onPointerObservable.notifyObservers(pi, type);
  549. }
  550. };
  551. this._onPointerDown = (evt: PointerEvent) => {
  552. if (!this.cameraToUseForPointers && !this.activeCamera) {
  553. return;
  554. }
  555. this._updatePointerPosition(evt);
  556. this._startingPointerPosition.x = this._pointerX;
  557. this._startingPointerPosition.y = this._pointerY;
  558. this._startingPointerTime = new Date().getTime();
  559. if (!this.pointerDownPredicate) {
  560. this.pointerDownPredicate = (mesh: AbstractMesh): boolean => {
  561. return mesh.isPickable && mesh.isVisible && mesh.isReady() && (!mesh.actionManager || mesh.actionManager.hasPointerTriggers);
  562. };
  563. }
  564. // Meshes
  565. this._pickedDownMesh = null;
  566. var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
  567. if (pickResult.hit && pickResult.pickedMesh) {
  568. if (pickResult.pickedMesh.actionManager) {
  569. this._pickedDownMesh = pickResult.pickedMesh;
  570. if (pickResult.pickedMesh.actionManager.hasPickTriggers) {
  571. switch (evt.button) {
  572. case 0:
  573. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  574. break;
  575. case 1:
  576. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  577. break;
  578. case 2:
  579. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  580. break;
  581. }
  582. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  583. }
  584. if (pickResult.pickedMesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger)) {
  585. var that = this;
  586. window.setTimeout(function () {
  587. var pickResult = that.pick(that._unTranslatedPointerX, that._unTranslatedPointerY,
  588. (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger),
  589. false, that.cameraToUseForPointers);
  590. if (pickResult.hit && pickResult.pickedMesh) {
  591. if (pickResult.pickedMesh.actionManager) {
  592. if (that._startingPointerTime !== 0 && ((new Date().getTime() - that._startingPointerTime) > ActionManager.LongPressDelay) && (Math.abs(that._startingPointerPosition.x - that._pointerX) < ActionManager.DragMovementThreshold && Math.abs(that._startingPointerPosition.y - that._pointerY) < ActionManager.DragMovementThreshold)) {
  593. that._startingPointerTime = 0;
  594. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  595. }
  596. }
  597. }
  598. }, ActionManager.LongPressDelay);
  599. }
  600. }
  601. }
  602. if (this.onPointerDown) {
  603. this.onPointerDown(evt, pickResult);
  604. }
  605. if (this.onPointerObservable.hasObservers()) {
  606. let type = PointerEventTypes.POINTERDOWN;
  607. let pi = new PointerInfo(type, evt, pickResult);
  608. this.onPointerObservable.notifyObservers(pi, type);
  609. }
  610. // Sprites
  611. this._pickedDownSprite = null;
  612. if (this.spriteManagers.length > 0) {
  613. pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
  614. if (pickResult.hit && pickResult.pickedSprite) {
  615. if (pickResult.pickedSprite.actionManager) {
  616. this._pickedDownSprite = pickResult.pickedSprite;
  617. switch (evt.button) {
  618. case 0:
  619. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  620. break;
  621. case 1:
  622. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  623. break;
  624. case 2:
  625. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  626. break;
  627. }
  628. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  629. }
  630. }
  631. }
  632. };
  633. this._onPointerUp = (evt: PointerEvent) => {
  634. if (!this.cameraToUseForPointers && !this.activeCamera) {
  635. return;
  636. }
  637. this._updatePointerPosition(evt);
  638. if (!this.pointerUpPredicate) {
  639. this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
  640. return mesh.isPickable && mesh.isVisible && mesh.isReady() && (!mesh.actionManager || (mesh.actionManager.hasPickTriggers || mesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger)));
  641. };
  642. }
  643. // Meshes
  644. var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerUpPredicate, false, this.cameraToUseForPointers);
  645. if (pickResult.hit && pickResult.pickedMesh) {
  646. if (this._pickedDownMesh != null && pickResult.pickedMesh == this._pickedDownMesh) {
  647. if (this.onPointerPick) {
  648. this.onPointerPick(evt, pickResult);
  649. }
  650. if (this.onPointerObservable.hasObservers()) {
  651. let type = PointerEventTypes.POINTERPICK;
  652. let pi = new PointerInfo(type, evt, pickResult);
  653. this.onPointerObservable.notifyObservers(pi, type);
  654. }
  655. }
  656. if (pickResult.pickedMesh.actionManager) {
  657. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  658. if (Math.abs(this._startingPointerPosition.x - this._pointerX) < ActionManager.DragMovementThreshold && Math.abs(this._startingPointerPosition.y - this._pointerY) < ActionManager.DragMovementThreshold) {
  659. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  660. }
  661. }
  662. }
  663. if (this._pickedDownMesh && this._pickedDownMesh !== pickResult.pickedMesh) {
  664. this._pickedDownMesh.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
  665. }
  666. if (this.onPointerUp) {
  667. this.onPointerUp(evt, pickResult);
  668. }
  669. if (this.onPointerObservable.hasObservers()) {
  670. let type = PointerEventTypes.POINTERUP;
  671. let pi = new PointerInfo(type, evt, pickResult);
  672. this.onPointerObservable.notifyObservers(pi, type);
  673. }
  674. this._startingPointerTime = 0;
  675. // Sprites
  676. if (this.spriteManagers.length > 0) {
  677. pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
  678. if (pickResult.hit && pickResult.pickedSprite) {
  679. if (pickResult.pickedSprite.actionManager) {
  680. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  681. if (Math.abs(this._startingPointerPosition.x - this._pointerX) < ActionManager.DragMovementThreshold && Math.abs(this._startingPointerPosition.y - this._pointerY) < ActionManager.DragMovementThreshold) {
  682. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  683. }
  684. }
  685. }
  686. if (this._pickedDownSprite && this._pickedDownSprite !== pickResult.pickedSprite) {
  687. this._pickedDownSprite.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNewFromSprite(this._pickedDownSprite, this, evt));
  688. }
  689. }
  690. };
  691. this._onKeyDown = (evt: Event) => {
  692. if (this.actionManager) {
  693. this.actionManager.processTrigger(ActionManager.OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
  694. }
  695. };
  696. this._onKeyUp = (evt: Event) => {
  697. if (this.actionManager) {
  698. this.actionManager.processTrigger(ActionManager.OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
  699. }
  700. };
  701. var eventPrefix = Tools.GetPointerPrefix();
  702. if (attachMove) {
  703. this._engine.getRenderingCanvas().addEventListener(eventPrefix + "move", this._onPointerMove, false);
  704. // Wheel
  705. this._engine.getRenderingCanvas().addEventListener('mousewheel', this._onPointerMove, false);
  706. this._engine.getRenderingCanvas().addEventListener('DOMMouseScroll', this._onPointerMove, false);
  707. }
  708. if (attachDown) {
  709. this._engine.getRenderingCanvas().addEventListener(eventPrefix + "down", this._onPointerDown, false);
  710. }
  711. if (attachUp) {
  712. this._engine.getRenderingCanvas().addEventListener(eventPrefix + "up", this._onPointerUp, false);
  713. }
  714. Tools.RegisterTopRootEvents([
  715. { name: "keydown", handler: this._onKeyDown },
  716. { name: "keyup", handler: this._onKeyUp }
  717. ]);
  718. }
  719. public detachControl() {
  720. var eventPrefix = Tools.GetPointerPrefix();
  721. this._engine.getRenderingCanvas().removeEventListener(eventPrefix + "move", this._onPointerMove);
  722. this._engine.getRenderingCanvas().removeEventListener(eventPrefix + "down", this._onPointerDown);
  723. this._engine.getRenderingCanvas().removeEventListener(eventPrefix + "up", this._onPointerUp);
  724. // Wheel
  725. this._engine.getRenderingCanvas().removeEventListener('mousewheel', this._onPointerMove);
  726. this._engine.getRenderingCanvas().removeEventListener('DOMMouseScroll', this._onPointerMove);
  727. Tools.UnregisterTopRootEvents([
  728. { name: "keydown", handler: this._onKeyDown },
  729. { name: "keyup", handler: this._onKeyUp }
  730. ]);
  731. }
  732. // Ready
  733. public isReady(): boolean {
  734. if (this._pendingData.length > 0) {
  735. return false;
  736. }
  737. var index: number;
  738. for (index = 0; index < this._geometries.length; index++) {
  739. var geometry = this._geometries[index];
  740. if (geometry.delayLoadState === Engine.DELAYLOADSTATE_LOADING) {
  741. return false;
  742. }
  743. }
  744. for (index = 0; index < this.meshes.length; index++) {
  745. var mesh = this.meshes[index];
  746. if (!mesh.isReady()) {
  747. return false;
  748. }
  749. var mat = mesh.material;
  750. if (mat) {
  751. if (!mat.isReady(mesh)) {
  752. return false;
  753. }
  754. }
  755. }
  756. return true;
  757. }
  758. public resetCachedMaterial(): void {
  759. this._cachedMaterial = null;
  760. }
  761. public registerBeforeRender(func: () => void): void {
  762. this.onBeforeRenderObservable.add(func);
  763. }
  764. public unregisterBeforeRender(func: () => void): void {
  765. this.onBeforeRenderObservable.removeCallback(func);
  766. }
  767. public registerAfterRender(func: () => void): void {
  768. this.onAfterRenderObservable.add(func);
  769. }
  770. public unregisterAfterRender(func: () => void): void {
  771. this.onAfterRenderObservable.removeCallback(func);
  772. }
  773. public _addPendingData(data): void {
  774. this._pendingData.push(data);
  775. }
  776. public _removePendingData(data): void {
  777. var index = this._pendingData.indexOf(data);
  778. if (index !== -1) {
  779. this._pendingData.splice(index, 1);
  780. }
  781. }
  782. public getWaitingItemsCount(): number {
  783. return this._pendingData.length;
  784. }
  785. /**
  786. * Registers a function to be executed when the scene is ready.
  787. * @param {Function} func - the function to be executed.
  788. */
  789. public executeWhenReady(func: () => void): void {
  790. this.onReadyObservable.add(func);
  791. if (this._executeWhenReadyTimeoutId !== -1) {
  792. return;
  793. }
  794. this._executeWhenReadyTimeoutId = setTimeout(() => {
  795. this._checkIsReady();
  796. }, 150);
  797. }
  798. public _checkIsReady() {
  799. if (this.isReady()) {
  800. this.onReadyObservable.notifyObservers(this);
  801. this.onReadyObservable.clear();
  802. this._executeWhenReadyTimeoutId = -1;
  803. return;
  804. }
  805. this._executeWhenReadyTimeoutId = setTimeout(() => {
  806. this._checkIsReady();
  807. }, 150);
  808. }
  809. // Animations
  810. /**
  811. * Will start the animation sequence of a given target
  812. * @param target - the target
  813. * @param {number} from - from which frame should animation start
  814. * @param {number} to - till which frame should animation run.
  815. * @param {boolean} [loop] - should the animation loop
  816. * @param {number} [speedRatio] - the speed in which to run the animation
  817. * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
  818. * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
  819. * @return {BABYLON.Animatable} the animatable object created for this animation
  820. * @see BABYLON.Animatable
  821. * @see http://doc.babylonjs.com/page.php?p=22081
  822. */
  823. public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable): Animatable {
  824. this.stopAnimation(target);
  825. if (!animatable) {
  826. animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
  827. }
  828. // Local animations
  829. if (target.animations) {
  830. animatable.appendAnimations(target, target.animations);
  831. }
  832. // Children animations
  833. if (target.getAnimatables) {
  834. var animatables = target.getAnimatables();
  835. for (var index = 0; index < animatables.length; index++) {
  836. this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
  837. }
  838. }
  839. animatable.reset();
  840. return animatable;
  841. }
  842. public beginDirectAnimation(target: any, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): Animatable {
  843. if (speedRatio === undefined) {
  844. speedRatio = 1.0;
  845. }
  846. var animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations);
  847. return animatable;
  848. }
  849. public getAnimatableByTarget(target: any): Animatable {
  850. for (var index = 0; index < this._activeAnimatables.length; index++) {
  851. if (this._activeAnimatables[index].target === target) {
  852. return this._activeAnimatables[index];
  853. }
  854. }
  855. return null;
  856. }
  857. public get Animatables(): Animatable[] {
  858. return this._activeAnimatables;
  859. }
  860. /**
  861. * Will stop the animation of the given target
  862. * @param target - the target
  863. * @see beginAnimation
  864. */
  865. public stopAnimation(target: any): void {
  866. var animatable = this.getAnimatableByTarget(target);
  867. if (animatable) {
  868. animatable.stop();
  869. }
  870. }
  871. private _animate(): void {
  872. if (!this.animationsEnabled || this._activeAnimatables.length === 0) {
  873. return;
  874. }
  875. if (!this._animationStartDate) {
  876. if (this._pendingData.length > 0) {
  877. return;
  878. }
  879. this._animationStartDate = Tools.Now;
  880. }
  881. // Getting time
  882. var now = Tools.Now;
  883. var delay = now - this._animationStartDate;
  884. for (var index = 0; index < this._activeAnimatables.length; index++) {
  885. this._activeAnimatables[index]._animate(delay);
  886. }
  887. }
  888. // Matrix
  889. public getViewMatrix(): Matrix {
  890. return this._viewMatrix;
  891. }
  892. public getProjectionMatrix(): Matrix {
  893. return this._projectionMatrix;
  894. }
  895. public getTransformMatrix(): Matrix {
  896. return this._transformMatrix;
  897. }
  898. public setTransformMatrix(view: Matrix, projection: Matrix): void {
  899. this._viewMatrix = view;
  900. this._projectionMatrix = projection;
  901. this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
  902. }
  903. // Methods
  904. public addMesh(newMesh: AbstractMesh) {
  905. newMesh.uniqueId = this._uniqueIdCounter++;
  906. var position = this.meshes.push(newMesh);
  907. //notify the collision coordinator
  908. this.collisionCoordinator.onMeshAdded(newMesh);
  909. this.onNewMeshAddedObservable.notifyObservers(newMesh);
  910. }
  911. public removeMesh(toRemove: AbstractMesh): number {
  912. var index = this.meshes.indexOf(toRemove);
  913. if (index !== -1) {
  914. // Remove from the scene if mesh found
  915. this.meshes.splice(index, 1);
  916. }
  917. //notify the collision coordinator
  918. this.collisionCoordinator.onMeshRemoved(toRemove);
  919. this.onMeshRemovedObservable.notifyObservers(toRemove);
  920. return index;
  921. }
  922. public removeSkeleton(toRemove: Skeleton): number {
  923. var index = this.skeletons.indexOf(toRemove);
  924. if (index !== -1) {
  925. // Remove from the scene if mesh found
  926. this.skeletons.splice(index, 1);
  927. }
  928. return index;
  929. }
  930. public removeLight(toRemove: Light): number {
  931. var index = this.lights.indexOf(toRemove);
  932. if (index !== -1) {
  933. // Remove from the scene if mesh found
  934. this.lights.splice(index, 1);
  935. }
  936. this.onLightRemovedObservable.notifyObservers(toRemove);
  937. return index;
  938. }
  939. public removeCamera(toRemove: Camera): number {
  940. var index = this.cameras.indexOf(toRemove);
  941. if (index !== -1) {
  942. // Remove from the scene if mesh found
  943. this.cameras.splice(index, 1);
  944. }
  945. // Remove from activeCameras
  946. var index2 = this.activeCameras.indexOf(toRemove);
  947. if (index2 !== -1) {
  948. // Remove from the scene if mesh found
  949. this.activeCameras.splice(index2, 1);
  950. }
  951. // Reset the activeCamera
  952. if (this.activeCamera === toRemove) {
  953. if (this.cameras.length > 0) {
  954. this.activeCamera = this.cameras[0];
  955. } else {
  956. this.activeCamera = null;
  957. }
  958. }
  959. this.onCameraRemovedObservable.notifyObservers(toRemove);
  960. return index;
  961. }
  962. public addLight(newLight: Light) {
  963. newLight.uniqueId = this._uniqueIdCounter++;
  964. var position = this.lights.push(newLight);
  965. this.onNewLightAddedObservable.notifyObservers(newLight);
  966. }
  967. public addCamera(newCamera: Camera) {
  968. newCamera.uniqueId = this._uniqueIdCounter++;
  969. var position = this.cameras.push(newCamera);
  970. this.onNewCameraAddedObservable.notifyObservers(newCamera);
  971. }
  972. /**
  973. * Switch active camera
  974. * @param {Camera} newCamera - new active camera
  975. * @param {boolean} attachControl - call attachControl for the new active camera (default: true)
  976. */
  977. public swithActiveCamera(newCamera: Camera, attachControl = true) {
  978. var canvas = this._engine.getRenderingCanvas();
  979. this.activeCamera.detachControl(canvas);
  980. this.activeCamera = newCamera;
  981. if (attachControl) {
  982. newCamera.attachControl(canvas);
  983. }
  984. }
  985. /**
  986. * sets the active camera of the scene using its ID
  987. * @param {string} id - the camera's ID
  988. * @return {BABYLON.Camera|null} the new active camera or null if none found.
  989. * @see activeCamera
  990. */
  991. public setActiveCameraByID(id: string): Camera {
  992. var camera = this.getCameraByID(id);
  993. if (camera) {
  994. this.activeCamera = camera;
  995. return camera;
  996. }
  997. return null;
  998. }
  999. /**
  1000. * sets the active camera of the scene using its name
  1001. * @param {string} name - the camera's name
  1002. * @return {BABYLON.Camera|null} the new active camera or null if none found.
  1003. * @see activeCamera
  1004. */
  1005. public setActiveCameraByName(name: string): Camera {
  1006. var camera = this.getCameraByName(name);
  1007. if (camera) {
  1008. this.activeCamera = camera;
  1009. return camera;
  1010. }
  1011. return null;
  1012. }
  1013. /**
  1014. * get a material using its id
  1015. * @param {string} the material's ID
  1016. * @return {BABYLON.Material|null} the material or null if none found.
  1017. */
  1018. public getMaterialByID(id: string): Material {
  1019. for (var index = 0; index < this.materials.length; index++) {
  1020. if (this.materials[index].id === id) {
  1021. return this.materials[index];
  1022. }
  1023. }
  1024. return null;
  1025. }
  1026. /**
  1027. * get a material using its name
  1028. * @param {string} the material's name
  1029. * @return {BABYLON.Material|null} the material or null if none found.
  1030. */
  1031. public getMaterialByName(name: string): Material {
  1032. for (var index = 0; index < this.materials.length; index++) {
  1033. if (this.materials[index].name === name) {
  1034. return this.materials[index];
  1035. }
  1036. }
  1037. return null;
  1038. }
  1039. public getLensFlareSystemByName(name: string): LensFlareSystem {
  1040. for (var index = 0; index < this.lensFlareSystems.length; index++) {
  1041. if (this.lensFlareSystems[index].name === name) {
  1042. return this.lensFlareSystems[index];
  1043. }
  1044. }
  1045. return null;
  1046. }
  1047. public getLensFlareSystemByID(id: string): LensFlareSystem {
  1048. for (var index = 0; index < this.lensFlareSystems.length; index++) {
  1049. if (this.lensFlareSystems[index].id === id) {
  1050. return this.lensFlareSystems[index];
  1051. }
  1052. }
  1053. return null;
  1054. }
  1055. public getCameraByID(id: string): Camera {
  1056. for (var index = 0; index < this.cameras.length; index++) {
  1057. if (this.cameras[index].id === id) {
  1058. return this.cameras[index];
  1059. }
  1060. }
  1061. return null;
  1062. }
  1063. public getCameraByUniqueID(uniqueId: number): Camera {
  1064. for (var index = 0; index < this.cameras.length; index++) {
  1065. if (this.cameras[index].uniqueId === uniqueId) {
  1066. return this.cameras[index];
  1067. }
  1068. }
  1069. return null;
  1070. }
  1071. /**
  1072. * get a camera using its name
  1073. * @param {string} the camera's name
  1074. * @return {BABYLON.Camera|null} the camera or null if none found.
  1075. */
  1076. public getCameraByName(name: string): Camera {
  1077. for (var index = 0; index < this.cameras.length; index++) {
  1078. if (this.cameras[index].name === name) {
  1079. return this.cameras[index];
  1080. }
  1081. }
  1082. return null;
  1083. }
  1084. /**
  1085. * get a bone using its id
  1086. * @param {string} the bone's id
  1087. * @return {BABYLON.Bone|null} the bone or null if not found
  1088. */
  1089. public getBoneByID(id: string): Bone {
  1090. for (var skeletonIndex = 0; skeletonIndex < this.skeletons.length; skeletonIndex++) {
  1091. var skeleton = this.skeletons[skeletonIndex];
  1092. for (var boneIndex = 0; boneIndex < skeleton.bones.length; boneIndex++) {
  1093. if (skeleton.bones[boneIndex].id === id) {
  1094. return skeleton.bones[boneIndex];
  1095. }
  1096. }
  1097. }
  1098. return null;
  1099. }
  1100. /**
  1101. * get a bone using its id
  1102. * @param {string} the bone's name
  1103. * @return {BABYLON.Bone|null} the bone or null if not found
  1104. */
  1105. public getBoneByName(name: string): Bone {
  1106. for (var skeletonIndex = 0; skeletonIndex < this.skeletons.length; skeletonIndex++) {
  1107. var skeleton = this.skeletons[skeletonIndex];
  1108. for (var boneIndex = 0; boneIndex < skeleton.bones.length; boneIndex++) {
  1109. if (skeleton.bones[boneIndex].name === name) {
  1110. return skeleton.bones[boneIndex];
  1111. }
  1112. }
  1113. }
  1114. return null;
  1115. }
  1116. /**
  1117. * get a light node using its name
  1118. * @param {string} the light's name
  1119. * @return {BABYLON.Light|null} the light or null if none found.
  1120. */
  1121. public getLightByName(name: string): Light {
  1122. for (var index = 0; index < this.lights.length; index++) {
  1123. if (this.lights[index].name === name) {
  1124. return this.lights[index];
  1125. }
  1126. }
  1127. return null;
  1128. }
  1129. /**
  1130. * get a light node using its ID
  1131. * @param {string} the light's id
  1132. * @return {BABYLON.Light|null} the light or null if none found.
  1133. */
  1134. public getLightByID(id: string): Light {
  1135. for (var index = 0; index < this.lights.length; index++) {
  1136. if (this.lights[index].id === id) {
  1137. return this.lights[index];
  1138. }
  1139. }
  1140. return null;
  1141. }
  1142. /**
  1143. * get a light node using its scene-generated unique ID
  1144. * @param {number} the light's unique id
  1145. * @return {BABYLON.Light|null} the light or null if none found.
  1146. */
  1147. public getLightByUniqueID(uniqueId: number): Light {
  1148. for (var index = 0; index < this.lights.length; index++) {
  1149. if (this.lights[index].uniqueId === uniqueId) {
  1150. return this.lights[index];
  1151. }
  1152. }
  1153. return null;
  1154. }
  1155. /**
  1156. * get a particle system by id
  1157. * @param id {number} the particle system id
  1158. * @return {BABYLON.ParticleSystem|null} the corresponding system or null if none found.
  1159. */
  1160. public getParticleSystemByID(id: string): ParticleSystem {
  1161. for (var index = 0; index < this.particleSystems.length; index++) {
  1162. if (this.particleSystems[index].id === id) {
  1163. return this.particleSystems[index];
  1164. }
  1165. }
  1166. return null;
  1167. }
  1168. /**
  1169. * get a geometry using its ID
  1170. * @param {string} the geometry's id
  1171. * @return {BABYLON.Geometry|null} the geometry or null if none found.
  1172. */
  1173. public getGeometryByID(id: string): Geometry {
  1174. for (var index = 0; index < this._geometries.length; index++) {
  1175. if (this._geometries[index].id === id) {
  1176. return this._geometries[index];
  1177. }
  1178. }
  1179. return null;
  1180. }
  1181. /**
  1182. * add a new geometry to this scene.
  1183. * @param {BABYLON.Geometry} geometry - the geometry to be added to the scene.
  1184. * @param {boolean} [force] - force addition, even if a geometry with this ID already exists
  1185. * @return {boolean} was the geometry added or not
  1186. */
  1187. public pushGeometry(geometry: Geometry, force?: boolean): boolean {
  1188. if (!force && this.getGeometryByID(geometry.id)) {
  1189. return false;
  1190. }
  1191. this._geometries.push(geometry);
  1192. //notify the collision coordinator
  1193. this.collisionCoordinator.onGeometryAdded(geometry);
  1194. this.onNewGeometryAddedObservable.notifyObservers(geometry);
  1195. return true;
  1196. }
  1197. /**
  1198. * Removes an existing geometry
  1199. * @param {BABYLON.Geometry} geometry - the geometry to be removed from the scene.
  1200. * @return {boolean} was the geometry removed or not
  1201. */
  1202. public removeGeometry(geometry: Geometry): boolean {
  1203. var index = this._geometries.indexOf(geometry);
  1204. if (index > -1) {
  1205. this._geometries.splice(index, 1);
  1206. //notify the collision coordinator
  1207. this.collisionCoordinator.onGeometryDeleted(geometry);
  1208. this.onGeometryRemovedObservable.notifyObservers(geometry);
  1209. return true;
  1210. }
  1211. return false;
  1212. }
  1213. public getGeometries(): Geometry[] {
  1214. return this._geometries;
  1215. }
  1216. /**
  1217. * Get the first added mesh found of a given ID
  1218. * @param {string} id - the id to search for
  1219. * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all.
  1220. */
  1221. public getMeshByID(id: string): AbstractMesh {
  1222. for (var index = 0; index < this.meshes.length; index++) {
  1223. if (this.meshes[index].id === id) {
  1224. return this.meshes[index];
  1225. }
  1226. }
  1227. return null;
  1228. }
  1229. public getMeshesByID(id: string): Array<AbstractMesh> {
  1230. return this.meshes.filter(function (m) {
  1231. return m.id === id;
  1232. })
  1233. }
  1234. /**
  1235. * Get a mesh with its auto-generated unique id
  1236. * @param {number} uniqueId - the unique id to search for
  1237. * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all.
  1238. */
  1239. public getMeshByUniqueID(uniqueId: number): AbstractMesh {
  1240. for (var index = 0; index < this.meshes.length; index++) {
  1241. if (this.meshes[index].uniqueId === uniqueId) {
  1242. return this.meshes[index];
  1243. }
  1244. }
  1245. return null;
  1246. }
  1247. /**
  1248. * Get a the last added mesh found of a given ID
  1249. * @param {string} id - the id to search for
  1250. * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all.
  1251. */
  1252. public getLastMeshByID(id: string): AbstractMesh {
  1253. for (var index = this.meshes.length - 1; index >= 0; index--) {
  1254. if (this.meshes[index].id === id) {
  1255. return this.meshes[index];
  1256. }
  1257. }
  1258. return null;
  1259. }
  1260. /**
  1261. * Get a the last added node (Mesh, Camera, Light) found of a given ID
  1262. * @param {string} id - the id to search for
  1263. * @return {BABYLON.Node|null} the node found or null if not found at all.
  1264. */
  1265. public getLastEntryByID(id: string): Node {
  1266. var index: number;
  1267. for (index = this.meshes.length - 1; index >= 0; index--) {
  1268. if (this.meshes[index].id === id) {
  1269. return this.meshes[index];
  1270. }
  1271. }
  1272. for (index = this.cameras.length - 1; index >= 0; index--) {
  1273. if (this.cameras[index].id === id) {
  1274. return this.cameras[index];
  1275. }
  1276. }
  1277. for (index = this.lights.length - 1; index >= 0; index--) {
  1278. if (this.lights[index].id === id) {
  1279. return this.lights[index];
  1280. }
  1281. }
  1282. return null;
  1283. }
  1284. public getNodeByID(id: string): Node {
  1285. var mesh = this.getMeshByID(id);
  1286. if (mesh) {
  1287. return mesh;
  1288. }
  1289. var light = this.getLightByID(id);
  1290. if (light) {
  1291. return light;
  1292. }
  1293. var camera = this.getCameraByID(id);
  1294. if (camera) {
  1295. return camera;
  1296. }
  1297. var bone = this.getBoneByID(id);
  1298. return bone;
  1299. }
  1300. public getNodeByName(name: string): Node {
  1301. var mesh = this.getMeshByName(name);
  1302. if (mesh) {
  1303. return mesh;
  1304. }
  1305. var light = this.getLightByName(name);
  1306. if (light) {
  1307. return light;
  1308. }
  1309. var camera = this.getCameraByName(name);
  1310. if (camera) {
  1311. return camera;
  1312. }
  1313. var bone = this.getBoneByName(name);
  1314. return bone;
  1315. }
  1316. public getMeshByName(name: string): AbstractMesh {
  1317. for (var index = 0; index < this.meshes.length; index++) {
  1318. if (this.meshes[index].name === name) {
  1319. return this.meshes[index];
  1320. }
  1321. }
  1322. return null;
  1323. }
  1324. public getSoundByName(name: string): Sound {
  1325. var index: number;
  1326. if (AudioEngine) {
  1327. for (index = 0; index < this.mainSoundTrack.soundCollection.length; index++) {
  1328. if (this.mainSoundTrack.soundCollection[index].name === name) {
  1329. return this.mainSoundTrack.soundCollection[index];
  1330. }
  1331. }
  1332. for (var sdIndex = 0; sdIndex < this.soundTracks.length; sdIndex++) {
  1333. for (index = 0; index < this.soundTracks[sdIndex].soundCollection.length; index++) {
  1334. if (this.soundTracks[sdIndex].soundCollection[index].name === name) {
  1335. return this.soundTracks[sdIndex].soundCollection[index];
  1336. }
  1337. }
  1338. }
  1339. }
  1340. return null;
  1341. }
  1342. public getLastSkeletonByID(id: string): Skeleton {
  1343. for (var index = this.skeletons.length - 1; index >= 0; index--) {
  1344. if (this.skeletons[index].id === id) {
  1345. return this.skeletons[index];
  1346. }
  1347. }
  1348. return null;
  1349. }
  1350. public getSkeletonById(id: string): Skeleton {
  1351. for (var index = 0; index < this.skeletons.length; index++) {
  1352. if (this.skeletons[index].id === id) {
  1353. return this.skeletons[index];
  1354. }
  1355. }
  1356. return null;
  1357. }
  1358. public getSkeletonByName(name: string): Skeleton {
  1359. for (var index = 0; index < this.skeletons.length; index++) {
  1360. if (this.skeletons[index].name === name) {
  1361. return this.skeletons[index];
  1362. }
  1363. }
  1364. return null;
  1365. }
  1366. public isActiveMesh(mesh: Mesh): boolean {
  1367. return (this._activeMeshes.indexOf(mesh) !== -1);
  1368. }
  1369. private _evaluateSubMesh(subMesh: SubMesh, mesh: AbstractMesh): void {
  1370. if (mesh.alwaysSelectAsActiveMesh || mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
  1371. var material = subMesh.getMaterial();
  1372. if (mesh.showSubMeshesBoundingBox) {
  1373. this._boundingBoxRenderer.renderList.push(subMesh.getBoundingInfo().boundingBox);
  1374. }
  1375. if (material) {
  1376. // Render targets
  1377. if (material.getRenderTargetTextures) {
  1378. if (this._processedMaterials.indexOf(material) === -1) {
  1379. this._processedMaterials.push(material);
  1380. this._renderTargets.concatWithNoDuplicate(material.getRenderTargetTextures());
  1381. }
  1382. }
  1383. // Dispatch
  1384. this._activeIndices += subMesh.indexCount;
  1385. this._renderingManager.dispatch(subMesh);
  1386. }
  1387. }
  1388. }
  1389. public _isInIntermediateRendering(): boolean {
  1390. return this._intermediateRendering
  1391. }
  1392. private _evaluateActiveMeshes(): void {
  1393. this.activeCamera._activeMeshes.reset();
  1394. this._activeMeshes.reset();
  1395. this._renderingManager.reset();
  1396. this._processedMaterials.reset();
  1397. this._activeParticleSystems.reset();
  1398. this._activeSkeletons.reset();
  1399. this._softwareSkinnedMeshes.reset();
  1400. this._boundingBoxRenderer.reset();
  1401. this._edgesRenderers.reset();
  1402. if (!this._frustumPlanes) {
  1403. this._frustumPlanes = Frustum.GetPlanes(this._transformMatrix);
  1404. } else {
  1405. Frustum.GetPlanesToRef(this._transformMatrix, this._frustumPlanes);
  1406. }
  1407. // Meshes
  1408. var meshes: AbstractMesh[];
  1409. var len: number;
  1410. if (this._selectionOctree) { // Octree
  1411. var selection = this._selectionOctree.select(this._frustumPlanes);
  1412. meshes = selection.data;
  1413. len = selection.length;
  1414. } else { // Full scene traversal
  1415. len = this.meshes.length;
  1416. meshes = this.meshes;
  1417. }
  1418. for (var meshIndex = 0; meshIndex < len; meshIndex++) {
  1419. var mesh = meshes[meshIndex];
  1420. if (mesh.isBlocked) {
  1421. continue;
  1422. }
  1423. this._totalVertices += mesh.getTotalVertices();
  1424. if (!mesh.isReady() || !mesh.isEnabled()) {
  1425. continue;
  1426. }
  1427. mesh.computeWorldMatrix();
  1428. // Intersections
  1429. if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([ActionManager.OnIntersectionEnterTrigger, ActionManager.OnIntersectionExitTrigger])) {
  1430. this._meshesForIntersections.pushNoDuplicate(mesh);
  1431. }
  1432. // Switch to current LOD
  1433. var meshLOD = mesh.getLOD(this.activeCamera);
  1434. if (!meshLOD) {
  1435. continue;
  1436. }
  1437. mesh._preActivate();
  1438. if (mesh.alwaysSelectAsActiveMesh || mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && mesh.isInFrustum(this._frustumPlanes)) {
  1439. this._activeMeshes.push(mesh);
  1440. this.activeCamera._activeMeshes.push(mesh);
  1441. mesh._activate(this._renderId);
  1442. this._activeMesh(meshLOD);
  1443. }
  1444. }
  1445. // Particle systems
  1446. var beforeParticlesDate = Tools.Now;
  1447. if (this.particlesEnabled) {
  1448. Tools.StartPerformanceCounter("Particles", this.particleSystems.length > 0);
  1449. for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
  1450. var particleSystem = this.particleSystems[particleIndex];
  1451. if (!particleSystem.isStarted()) {
  1452. continue;
  1453. }
  1454. if (!particleSystem.emitter.position || (particleSystem.emitter && particleSystem.emitter.isEnabled())) {
  1455. this._activeParticleSystems.push(particleSystem);
  1456. particleSystem.animate();
  1457. }
  1458. }
  1459. Tools.EndPerformanceCounter("Particles", this.particleSystems.length > 0);
  1460. }
  1461. this._particlesDuration += Tools.Now - beforeParticlesDate;
  1462. }
  1463. private _activeMesh(mesh: AbstractMesh): void {
  1464. if (mesh.skeleton && this.skeletonsEnabled) {
  1465. this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
  1466. if (!mesh.computeBonesUsingShaders) {
  1467. this._softwareSkinnedMeshes.pushNoDuplicate(mesh);
  1468. }
  1469. }
  1470. if (mesh.showBoundingBox || this.forceShowBoundingBoxes) {
  1471. this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
  1472. }
  1473. if (mesh._edgesRenderer) {
  1474. this._edgesRenderers.push(mesh._edgesRenderer);
  1475. }
  1476. if (mesh && mesh.subMeshes) {
  1477. // Submeshes Octrees
  1478. var len: number;
  1479. var subMeshes: SubMesh[];
  1480. if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
  1481. var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
  1482. len = intersections.length;
  1483. subMeshes = intersections.data;
  1484. } else {
  1485. subMeshes = mesh.subMeshes;
  1486. len = subMeshes.length;
  1487. }
  1488. for (var subIndex = 0; subIndex < len; subIndex++) {
  1489. var subMesh = subMeshes[subIndex];
  1490. this._evaluateSubMesh(subMesh, mesh);
  1491. }
  1492. }
  1493. }
  1494. public updateTransformMatrix(force?: boolean): void {
  1495. this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(force));
  1496. }
  1497. private _renderForCamera(camera: Camera): void {
  1498. var engine = this._engine;
  1499. this.activeCamera = camera;
  1500. if (!this.activeCamera)
  1501. throw new Error("Active camera not set");
  1502. Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
  1503. // Viewport
  1504. engine.setViewport(this.activeCamera.viewport);
  1505. // Camera
  1506. this.resetCachedMaterial();
  1507. this._renderId++;
  1508. this.updateTransformMatrix();
  1509. this.onBeforeCameraRenderObservable.notifyObservers(this.activeCamera);
  1510. // Meshes
  1511. var beforeEvaluateActiveMeshesDate = Tools.Now;
  1512. Tools.StartPerformanceCounter("Active meshes evaluation");
  1513. this._evaluateActiveMeshes();
  1514. this._evaluateActiveMeshesDuration += Tools.Now - beforeEvaluateActiveMeshesDate;
  1515. Tools.EndPerformanceCounter("Active meshes evaluation");
  1516. // Skeletons
  1517. for (var skeletonIndex = 0; skeletonIndex < this._activeSkeletons.length; skeletonIndex++) {
  1518. var skeleton = this._activeSkeletons.data[skeletonIndex];
  1519. skeleton.prepare();
  1520. }
  1521. // Software skinning
  1522. for (var softwareSkinnedMeshIndex = 0; softwareSkinnedMeshIndex < this._softwareSkinnedMeshes.length; softwareSkinnedMeshIndex++) {
  1523. var mesh = this._softwareSkinnedMeshes.data[softwareSkinnedMeshIndex];
  1524. mesh.applySkeleton(mesh.skeleton);
  1525. }
  1526. // Render targets
  1527. var beforeRenderTargetDate = Tools.Now;
  1528. if (this.renderTargetsEnabled && this._renderTargets.length > 0) {
  1529. this._intermediateRendering = true;
  1530. Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
  1531. for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
  1532. var renderTarget = this._renderTargets.data[renderIndex];
  1533. if (renderTarget._shouldRender()) {
  1534. this._renderId++;
  1535. var hasSpecialRenderTargetCamera = renderTarget.activeCamera && renderTarget.activeCamera !== this.activeCamera;
  1536. renderTarget.render(hasSpecialRenderTargetCamera, this.dumpNextRenderTargets);
  1537. }
  1538. }
  1539. Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0);
  1540. this._intermediateRendering = false;
  1541. this._renderId++;
  1542. engine.restoreDefaultFramebuffer(); // Restore back buffer
  1543. }
  1544. this._renderTargetsDuration += Tools.Now - beforeRenderTargetDate;
  1545. // Prepare Frame
  1546. this.postProcessManager._prepareFrame();
  1547. var beforeRenderDate = Tools.Now;
  1548. // Backgrounds
  1549. var layerIndex;
  1550. var layer;
  1551. if (this.layers.length) {
  1552. engine.setDepthBuffer(false);
  1553. for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) {
  1554. layer = this.layers[layerIndex];
  1555. if (layer.isBackground) {
  1556. layer.render();
  1557. }
  1558. }
  1559. engine.setDepthBuffer(true);
  1560. }
  1561. // Render
  1562. Tools.StartPerformanceCounter("Main render");
  1563. this._renderingManager.render(null, null, true, true);
  1564. Tools.EndPerformanceCounter("Main render");
  1565. // Bounding boxes
  1566. this._boundingBoxRenderer.render();
  1567. // Edges
  1568. for (var edgesRendererIndex = 0; edgesRendererIndex < this._edgesRenderers.length; edgesRendererIndex++) {
  1569. this._edgesRenderers.data[edgesRendererIndex].render();
  1570. }
  1571. // Lens flares
  1572. if (this.lensFlaresEnabled) {
  1573. Tools.StartPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
  1574. for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
  1575. var lensFlareSystem = this.lensFlareSystems[lensFlareSystemIndex];
  1576. if ((camera.layerMask & lensFlareSystem.layerMask) !== 0) {
  1577. lensFlareSystem.render();
  1578. }
  1579. }
  1580. Tools.EndPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
  1581. }
  1582. // Foregrounds
  1583. if (this.layers.length) {
  1584. engine.setDepthBuffer(false);
  1585. for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) {
  1586. layer = this.layers[layerIndex];
  1587. if (!layer.isBackground) {
  1588. layer.render();
  1589. }
  1590. }
  1591. engine.setDepthBuffer(true);
  1592. }
  1593. this._renderDuration += Tools.Now - beforeRenderDate;
  1594. // Finalize frame
  1595. this.postProcessManager._finalizeFrame(camera.isIntermediate);
  1596. // Update camera
  1597. this.activeCamera._updateFromScene();
  1598. // Reset some special arrays
  1599. this._renderTargets.reset();
  1600. this.onAfterCameraRenderObservable.notifyObservers(this.activeCamera);
  1601. Tools.EndPerformanceCounter("Rendering camera " + this.activeCamera.name);
  1602. }
  1603. private _processSubCameras(camera: Camera): void {
  1604. if (camera.cameraRigMode === Camera.RIG_MODE_NONE) {
  1605. this._renderForCamera(camera);
  1606. return;
  1607. }
  1608. // rig cameras
  1609. for (var index = 0; index < camera._rigCameras.length; index++) {
  1610. this._renderForCamera(camera._rigCameras[index]);
  1611. }
  1612. this.activeCamera = camera;
  1613. this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
  1614. // Update camera
  1615. this.activeCamera._updateFromScene();
  1616. }
  1617. private _checkIntersections(): void {
  1618. for (var index = 0; index < this._meshesForIntersections.length; index++) {
  1619. var sourceMesh = this._meshesForIntersections.data[index];
  1620. for (var actionIndex = 0; actionIndex < sourceMesh.actionManager.actions.length; actionIndex++) {
  1621. var action = sourceMesh.actionManager.actions[actionIndex];
  1622. if (action.trigger === ActionManager.OnIntersectionEnterTrigger || action.trigger === ActionManager.OnIntersectionExitTrigger) {
  1623. var parameters = action.getTriggerParameter();
  1624. var otherMesh = parameters instanceof AbstractMesh ? parameters : parameters.mesh;
  1625. var areIntersecting = otherMesh.intersectsMesh(sourceMesh, parameters.usePreciseIntersection);
  1626. var currentIntersectionInProgress = sourceMesh._intersectionsInProgress.indexOf(otherMesh);
  1627. if (areIntersecting && currentIntersectionInProgress === -1) {
  1628. if (action.trigger === ActionManager.OnIntersectionEnterTrigger) {
  1629. action._executeCurrent(ActionEvent.CreateNew(sourceMesh, null, otherMesh));
  1630. sourceMesh._intersectionsInProgress.push(otherMesh);
  1631. } else if (action.trigger === ActionManager.OnIntersectionExitTrigger) {
  1632. sourceMesh._intersectionsInProgress.push(otherMesh);
  1633. }
  1634. } else if (!areIntersecting && currentIntersectionInProgress > -1) {
  1635. //They intersected, and now they don't.
  1636. //is this trigger an exit trigger? execute an event.
  1637. if (action.trigger === ActionManager.OnIntersectionExitTrigger) {
  1638. action._executeCurrent(ActionEvent.CreateNew(sourceMesh, null, otherMesh));
  1639. }
  1640. //if this is an exit trigger, or no exit trigger exists, remove the id from the intersection in progress array.
  1641. if (!sourceMesh.actionManager.hasSpecificTrigger(ActionManager.OnIntersectionExitTrigger) || action.trigger === ActionManager.OnIntersectionExitTrigger) {
  1642. sourceMesh._intersectionsInProgress.splice(currentIntersectionInProgress, 1);
  1643. }
  1644. }
  1645. }
  1646. }
  1647. }
  1648. }
  1649. public render(): void {
  1650. var startDate = Tools.Now;
  1651. this._particlesDuration = 0;
  1652. this._spritesDuration = 0;
  1653. this._activeParticles = 0;
  1654. this._renderDuration = 0;
  1655. this._renderTargetsDuration = 0;
  1656. this._evaluateActiveMeshesDuration = 0;
  1657. this._totalVertices = 0;
  1658. this._activeIndices = 0;
  1659. this._activeBones = 0;
  1660. this.getEngine().resetDrawCalls();
  1661. this._meshesForIntersections.reset();
  1662. this.resetCachedMaterial();
  1663. Tools.StartPerformanceCounter("Scene rendering");
  1664. // Actions
  1665. if (this.actionManager) {
  1666. this.actionManager.processTrigger(ActionManager.OnEveryFrameTrigger, null);
  1667. }
  1668. //Simplification Queue
  1669. if (this.simplificationQueue && !this.simplificationQueue.running) {
  1670. this.simplificationQueue.executeNext();
  1671. }
  1672. // Animations
  1673. var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
  1674. this._animationRatio = deltaTime * (60.0 / 1000.0);
  1675. this._animate();
  1676. // Physics
  1677. if (this._physicsEngine) {
  1678. Tools.StartPerformanceCounter("Physics");
  1679. this._physicsEngine._step(deltaTime / 1000.0);
  1680. Tools.EndPerformanceCounter("Physics");
  1681. }
  1682. // Before render
  1683. this.onBeforeRenderObservable.notifyObservers(this);
  1684. // Customs render targets
  1685. var beforeRenderTargetDate = Tools.Now;
  1686. var engine = this.getEngine();
  1687. var currentActiveCamera = this.activeCamera;
  1688. if (this.renderTargetsEnabled) {
  1689. Tools.StartPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
  1690. for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
  1691. var renderTarget = this.customRenderTargets[customIndex];
  1692. if (renderTarget._shouldRender()) {
  1693. this._renderId++;
  1694. this.activeCamera = renderTarget.activeCamera || this.activeCamera;
  1695. if (!this.activeCamera)
  1696. throw new Error("Active camera not set");
  1697. // Viewport
  1698. engine.setViewport(this.activeCamera.viewport);
  1699. // Camera
  1700. this.updateTransformMatrix();
  1701. renderTarget.render(currentActiveCamera !== this.activeCamera, this.dumpNextRenderTargets);
  1702. }
  1703. }
  1704. Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
  1705. this._renderId++;
  1706. }
  1707. if (this.customRenderTargets.length > 0) { // Restore back buffer
  1708. engine.restoreDefaultFramebuffer();
  1709. }
  1710. this._renderTargetsDuration += Tools.Now - beforeRenderTargetDate;
  1711. this.activeCamera = currentActiveCamera;
  1712. // Procedural textures
  1713. if (this.proceduralTexturesEnabled) {
  1714. Tools.StartPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
  1715. for (var proceduralIndex = 0; proceduralIndex < this._proceduralTextures.length; proceduralIndex++) {
  1716. var proceduralTexture = this._proceduralTextures[proceduralIndex];
  1717. if (proceduralTexture._shouldRender()) {
  1718. proceduralTexture.render();
  1719. }
  1720. }
  1721. Tools.EndPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
  1722. }
  1723. // Clear
  1724. this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe || this.forcePointsCloud, true);
  1725. // Shadows
  1726. if (this.shadowsEnabled) {
  1727. for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
  1728. var light = this.lights[lightIndex];
  1729. var shadowGenerator = light.getShadowGenerator();
  1730. if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
  1731. this._renderTargets.push(shadowGenerator.getShadowMap());
  1732. }
  1733. }
  1734. }
  1735. // Depth renderer
  1736. if (this._depthRenderer) {
  1737. this._renderTargets.push(this._depthRenderer.getDepthMap());
  1738. }
  1739. // RenderPipeline
  1740. this.postProcessRenderPipelineManager.update();
  1741. // Multi-cameras?
  1742. if (this.activeCameras.length > 0) {
  1743. var currentRenderId = this._renderId;
  1744. for (var cameraIndex = 0; cameraIndex < this.activeCameras.length; cameraIndex++) {
  1745. this._renderId = currentRenderId;
  1746. if (cameraIndex > 0) {
  1747. this._engine.clear(0, false, true);
  1748. }
  1749. this._processSubCameras(this.activeCameras[cameraIndex]);
  1750. }
  1751. } else {
  1752. if (!this.activeCamera) {
  1753. throw new Error("No camera defined");
  1754. }
  1755. this._processSubCameras(this.activeCamera);
  1756. }
  1757. // Intersection checks
  1758. this._checkIntersections();
  1759. // Update the audio listener attached to the camera
  1760. if (AudioEngine) {
  1761. this._updateAudioParameters();
  1762. }
  1763. // After render
  1764. if (this.afterRender) {
  1765. this.afterRender();
  1766. }
  1767. this.onAfterRenderObservable.notifyObservers(this);
  1768. // Cleaning
  1769. for (var index = 0; index < this._toBeDisposed.length; index++) {
  1770. this._toBeDisposed.data[index].dispose();
  1771. this._toBeDisposed[index] = null;
  1772. }
  1773. this._toBeDisposed.reset();
  1774. if (this.dumpNextRenderTargets) {
  1775. this.dumpNextRenderTargets = false;
  1776. }
  1777. Tools.EndPerformanceCounter("Scene rendering");
  1778. this._lastFrameDuration = Tools.Now - startDate;
  1779. }
  1780. private _updateAudioParameters() {
  1781. if (!this.audioEnabled || (this.mainSoundTrack.soundCollection.length === 0 && this.soundTracks.length === 1)) {
  1782. return;
  1783. }
  1784. var listeningCamera: Camera;
  1785. var audioEngine = Engine.audioEngine;
  1786. if (this.activeCameras.length > 0) {
  1787. listeningCamera = this.activeCameras[0];
  1788. } else {
  1789. listeningCamera = this.activeCamera;
  1790. }
  1791. if (listeningCamera && audioEngine.canUseWebAudio) {
  1792. audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z);
  1793. var mat = Matrix.Invert(listeningCamera.getViewMatrix());
  1794. var cameraDirection = Vector3.TransformNormal(new Vector3(0, 0, -1), mat);
  1795. cameraDirection.normalize();
  1796. audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
  1797. var i: number;
  1798. for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
  1799. var sound = this.mainSoundTrack.soundCollection[i];
  1800. if (sound.useCustomAttenuation) {
  1801. sound.updateDistanceFromListener();
  1802. }
  1803. }
  1804. for (i = 0; i < this.soundTracks.length; i++) {
  1805. for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
  1806. sound = this.soundTracks[i].soundCollection[j];
  1807. if (sound.useCustomAttenuation) {
  1808. sound.updateDistanceFromListener();
  1809. }
  1810. }
  1811. }
  1812. }
  1813. }
  1814. // Audio
  1815. public get audioEnabled(): boolean {
  1816. return this._audioEnabled;
  1817. }
  1818. public set audioEnabled(value: boolean) {
  1819. this._audioEnabled = value;
  1820. if (AudioEngine) {
  1821. if (this._audioEnabled) {
  1822. this._enableAudio();
  1823. }
  1824. else {
  1825. this._disableAudio();
  1826. }
  1827. }
  1828. }
  1829. private _disableAudio() {
  1830. var i: number;
  1831. for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
  1832. this.mainSoundTrack.soundCollection[i].pause();
  1833. }
  1834. for (i = 0; i < this.soundTracks.length; i++) {
  1835. for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
  1836. this.soundTracks[i].soundCollection[j].pause();
  1837. }
  1838. }
  1839. }
  1840. private _enableAudio() {
  1841. var i: number;
  1842. for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
  1843. if (this.mainSoundTrack.soundCollection[i].isPaused) {
  1844. this.mainSoundTrack.soundCollection[i].play();
  1845. }
  1846. }
  1847. for (i = 0; i < this.soundTracks.length; i++) {
  1848. for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
  1849. if (this.soundTracks[i].soundCollection[j].isPaused) {
  1850. this.soundTracks[i].soundCollection[j].play();
  1851. }
  1852. }
  1853. }
  1854. }
  1855. public get headphone(): boolean {
  1856. return this._headphone;
  1857. }
  1858. public set headphone(value: boolean) {
  1859. this._headphone = value;
  1860. if (AudioEngine) {
  1861. if (this._headphone) {
  1862. this._switchAudioModeForHeadphones();
  1863. }
  1864. else {
  1865. this._switchAudioModeForNormalSpeakers();
  1866. }
  1867. }
  1868. }
  1869. private _switchAudioModeForHeadphones() {
  1870. this.mainSoundTrack.switchPanningModelToHRTF();
  1871. for (var i = 0; i < this.soundTracks.length; i++) {
  1872. this.soundTracks[i].switchPanningModelToHRTF();
  1873. }
  1874. }
  1875. private _switchAudioModeForNormalSpeakers() {
  1876. this.mainSoundTrack.switchPanningModelToEqualPower();
  1877. for (var i = 0; i < this.soundTracks.length; i++) {
  1878. this.soundTracks[i].switchPanningModelToEqualPower();
  1879. }
  1880. }
  1881. public enableDepthRenderer(): DepthRenderer {
  1882. if (this._depthRenderer) {
  1883. return this._depthRenderer;
  1884. }
  1885. this._depthRenderer = new DepthRenderer(this);
  1886. return this._depthRenderer;
  1887. }
  1888. public disableDepthRenderer(): void {
  1889. if (!this._depthRenderer) {
  1890. return;
  1891. }
  1892. this._depthRenderer.dispose();
  1893. this._depthRenderer = null;
  1894. }
  1895. public freezeMaterials(): void {
  1896. for (var i = 0; i < this.materials.length; i++) {
  1897. this.materials[i].freeze();
  1898. }
  1899. }
  1900. public unfreezeMaterials(): void {
  1901. for (var i = 0; i < this.materials.length; i++) {
  1902. this.materials[i].unfreeze();
  1903. }
  1904. }
  1905. public dispose(): void {
  1906. this.beforeRender = null;
  1907. this.afterRender = null;
  1908. this.skeletons = [];
  1909. this._boundingBoxRenderer.dispose();
  1910. if (this._depthRenderer) {
  1911. this._depthRenderer.dispose();
  1912. }
  1913. // Debug layer
  1914. this.debugLayer.hide();
  1915. // Events
  1916. if (this.onDisposeObservable) {
  1917. this.onDisposeObservable.notifyObservers(this);
  1918. }
  1919. this.onBeforeRenderObservable.clear();
  1920. this.onAfterRenderObservable.clear();
  1921. this.detachControl();
  1922. // Release sounds & sounds tracks
  1923. if (AudioEngine) {
  1924. this.disposeSounds();
  1925. }
  1926. // Detach cameras
  1927. var canvas = this._engine.getRenderingCanvas();
  1928. var index;
  1929. for (index = 0; index < this.cameras.length; index++) {
  1930. this.cameras[index].detachControl(canvas);
  1931. }
  1932. // Release lights
  1933. while (this.lights.length) {
  1934. this.lights[0].dispose();
  1935. }
  1936. // Release meshes
  1937. while (this.meshes.length) {
  1938. this.meshes[0].dispose(true);
  1939. }
  1940. // Release cameras
  1941. while (this.cameras.length) {
  1942. this.cameras[0].dispose();
  1943. }
  1944. // Release materials
  1945. while (this.materials.length) {
  1946. this.materials[0].dispose();
  1947. }
  1948. // Release particles
  1949. while (this.particleSystems.length) {
  1950. this.particleSystems[0].dispose();
  1951. }
  1952. // Release sprites
  1953. while (this.spriteManagers.length) {
  1954. this.spriteManagers[0].dispose();
  1955. }
  1956. // Release layers
  1957. while (this.layers.length) {
  1958. this.layers[0].dispose();
  1959. }
  1960. // Release textures
  1961. while (this.textures.length) {
  1962. this.textures[0].dispose();
  1963. }
  1964. // Post-processes
  1965. this.postProcessManager.dispose();
  1966. // Physics
  1967. if (this._physicsEngine) {
  1968. this.disablePhysicsEngine();
  1969. }
  1970. // Remove from engine
  1971. index = this._engine.scenes.indexOf(this);
  1972. if (index > -1) {
  1973. this._engine.scenes.splice(index, 1);
  1974. }
  1975. this._engine.wipeCaches();
  1976. }
  1977. // Release sounds & sounds tracks
  1978. public disposeSounds() {
  1979. this.mainSoundTrack.dispose();
  1980. for (var scIndex = 0; scIndex < this.soundTracks.length; scIndex++) {
  1981. this.soundTracks[scIndex].dispose();
  1982. }
  1983. }
  1984. // Octrees
  1985. public getWorldExtends(): { min: Vector3; max: Vector3 } {
  1986. var min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  1987. var max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  1988. for (var index = 0; index < this.meshes.length; index++) {
  1989. var mesh = this.meshes[index];
  1990. mesh.computeWorldMatrix(true);
  1991. var minBox = mesh.getBoundingInfo().boundingBox.minimumWorld;
  1992. var maxBox = mesh.getBoundingInfo().boundingBox.maximumWorld;
  1993. Tools.CheckExtends(minBox, min, max);
  1994. Tools.CheckExtends(maxBox, min, max);
  1995. }
  1996. return {
  1997. min: min,
  1998. max: max
  1999. };
  2000. }
  2001. public createOrUpdateSelectionOctree(maxCapacity = 64, maxDepth = 2): Octree<AbstractMesh> {
  2002. if (!this._selectionOctree) {
  2003. this._selectionOctree = new Octree<AbstractMesh>(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
  2004. }
  2005. var worldExtends = this.getWorldExtends();
  2006. // Update octree
  2007. this._selectionOctree.update(worldExtends.min, worldExtends.max, this.meshes);
  2008. return this._selectionOctree;
  2009. }
  2010. // Picking
  2011. public createPickingRay(x: number, y: number, world: Matrix, camera: Camera, cameraViewSpace = false): Ray {
  2012. var engine = this._engine;
  2013. if (!camera) {
  2014. if (!this.activeCamera)
  2015. throw new Error("Active camera not set");
  2016. camera = this.activeCamera;
  2017. }
  2018. var cameraViewport = camera.viewport;
  2019. var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
  2020. // Moving coordinates to local viewport world
  2021. x = x / this._engine.getHardwareScalingLevel() - viewport.x;
  2022. y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
  2023. return Ray.CreateNew(x, y, viewport.width, viewport.height, world ? world : Matrix.Identity(), cameraViewSpace ? Matrix.Identity() : camera.getViewMatrix(), camera.getProjectionMatrix());
  2024. // return BABYLON.Ray.CreateNew(x / window.devicePixelRatio, y / window.devicePixelRatio, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix());
  2025. }
  2026. public createPickingRayInCameraSpace(x: number, y: number, camera: Camera): Ray {
  2027. var engine = this._engine;
  2028. if (!camera) {
  2029. if (!this.activeCamera)
  2030. throw new Error("Active camera not set");
  2031. camera = this.activeCamera;
  2032. }
  2033. var cameraViewport = camera.viewport;
  2034. var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
  2035. var identity = Matrix.Identity();
  2036. // Moving coordinates to local viewport world
  2037. x = x / this._engine.getHardwareScalingLevel() - viewport.x;
  2038. y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
  2039. return Ray.CreateNew(x, y, viewport.width, viewport.height, identity, identity, camera.getProjectionMatrix());
  2040. }
  2041. private _internalPick(rayFunction: (world: Matrix) => Ray, predicate: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): PickingInfo {
  2042. var pickingInfo = null;
  2043. for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) {
  2044. var mesh = this.meshes[meshIndex];
  2045. if (predicate) {
  2046. if (!predicate(mesh)) {
  2047. continue;
  2048. }
  2049. } else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) {
  2050. continue;
  2051. }
  2052. var world = mesh.getWorldMatrix();
  2053. var ray = rayFunction(world);
  2054. var result = mesh.intersects(ray, fastCheck);
  2055. if (!result || !result.hit)
  2056. continue;
  2057. if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
  2058. continue;
  2059. pickingInfo = result;
  2060. if (fastCheck) {
  2061. break;
  2062. }
  2063. }
  2064. return pickingInfo || new PickingInfo();
  2065. }
  2066. private _internalPickSprites(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
  2067. var pickingInfo = null;
  2068. camera = camera || this.activeCamera;
  2069. if (this.spriteManagers.length > 0) {
  2070. for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
  2071. var spriteManager = this.spriteManagers[spriteIndex];
  2072. if (!spriteManager.isPickable) {
  2073. continue;
  2074. }
  2075. var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
  2076. if (!result || !result.hit)
  2077. continue;
  2078. if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
  2079. continue;
  2080. pickingInfo = result;
  2081. if (fastCheck) {
  2082. break;
  2083. }
  2084. }
  2085. }
  2086. return pickingInfo || new PickingInfo();
  2087. }
  2088. public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
  2089. /// <summary>Launch a ray to try to pick a mesh in the scene</summary>
  2090. /// <param name="x">X position on screen</param>
  2091. /// <param name="y">Y position on screen</param>
  2092. /// <param name="predicate">Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true</param>
  2093. /// <param name="fastCheck">Launch a fast check only using the bounding boxes. Can be set to null.</param>
  2094. /// <param name="camera">camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used</param>
  2095. return this._internalPick(world => this.createPickingRay(x, y, world, camera), predicate, fastCheck);
  2096. }
  2097. public pickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
  2098. /// <summary>Launch a ray to try to pick a mesh in the scene</summary>
  2099. /// <param name="x">X position on screen</param>
  2100. /// <param name="y">Y position on screen</param>
  2101. /// <param name="predicate">Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true</param>
  2102. /// <param name="fastCheck">Launch a fast check only using the bounding boxes. Can be set to null.</param>
  2103. /// <param name="camera">camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used</param>
  2104. return this._internalPickSprites(this.createPickingRayInCameraSpace(x, y, camera), predicate, fastCheck, camera);
  2105. }
  2106. public pickWithRay(ray: Ray, predicate: (mesh: Mesh) => boolean, fastCheck?: boolean) {
  2107. return this._internalPick(world => {
  2108. if (!this._pickWithRayInverseMatrix) {
  2109. this._pickWithRayInverseMatrix = Matrix.Identity();
  2110. }
  2111. world.invertToRef(this._pickWithRayInverseMatrix);
  2112. return Ray.Transform(ray, this._pickWithRayInverseMatrix);
  2113. }, predicate, fastCheck);
  2114. }
  2115. public setPointerOverMesh(mesh: AbstractMesh): void {
  2116. if (this._pointerOverMesh === mesh) {
  2117. return;
  2118. }
  2119. if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
  2120. this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
  2121. }
  2122. this._pointerOverMesh = mesh;
  2123. if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
  2124. this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
  2125. }
  2126. }
  2127. public getPointerOverMesh(): AbstractMesh {
  2128. return this._pointerOverMesh;
  2129. }
  2130. public setPointerOverSprite(sprite: Sprite): void {
  2131. if (this._pointerOverSprite === sprite) {
  2132. return;
  2133. }
  2134. if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
  2135. this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
  2136. }
  2137. this._pointerOverSprite = sprite;
  2138. if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
  2139. this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
  2140. }
  2141. }
  2142. public getPointerOverSprite(): Sprite {
  2143. return this._pointerOverSprite;
  2144. }
  2145. // Physics
  2146. public getPhysicsEngine(): PhysicsEngine {
  2147. return this._physicsEngine;
  2148. }
  2149. /**
  2150. * Enables physics to the current scene
  2151. * @param {BABYLON.Vector3} [gravity] - the scene's gravity for the physics engine
  2152. * @param {BABYLON.IPhysicsEnginePlugin} [plugin] - The physics engine to be used. defaults to OimoJS.
  2153. * @return {boolean} was the physics engine initialized
  2154. */
  2155. public enablePhysics(gravity?: Vector3, plugin?: IPhysicsEnginePlugin): boolean {
  2156. if (this._physicsEngine) {
  2157. return true;
  2158. }
  2159. try {
  2160. this._physicsEngine = new PhysicsEngine(gravity, plugin);
  2161. return true;
  2162. } catch (e) {
  2163. Tools.Error(e.message);
  2164. return false;
  2165. }
  2166. }
  2167. public disablePhysicsEngine(): void {
  2168. if (!this._physicsEngine) {
  2169. return;
  2170. }
  2171. this._physicsEngine.dispose();
  2172. this._physicsEngine = undefined;
  2173. }
  2174. public isPhysicsEnabled(): boolean {
  2175. return this._physicsEngine !== undefined;
  2176. }
  2177. /**
  2178. *
  2179. * Sets the gravity of the physics engine (and NOT of the scene)
  2180. * @param {BABYLON.Vector3} [gravity] - the new gravity to be used
  2181. */
  2182. public setGravity(gravity: Vector3): void {
  2183. Tools.Warn("Deprecated, please use 'scene.getPhysicsEngine().setGravity()'")
  2184. if (!this._physicsEngine) {
  2185. return;
  2186. }
  2187. this._physicsEngine.setGravity(gravity);
  2188. }
  2189. /**
  2190. * Legacy support, using the new API
  2191. * @Deprecated
  2192. */
  2193. public createCompoundImpostor(parts: any, options: PhysicsImpostorParameters): any {
  2194. Tools.Warn("Scene.createCompoundImpostor is deprecated. Please use PhysicsImpostor parent/child")
  2195. if (parts.parts) { // Old API
  2196. options = parts;
  2197. parts = parts.parts;
  2198. }
  2199. var mainMesh: AbstractMesh = parts[0].mesh;
  2200. mainMesh.physicsImpostor = new PhysicsImpostor(mainMesh, parts[0].impostor, options, this)
  2201. for (var index = 1; index < parts.length; index++) {
  2202. var mesh: AbstractMesh = parts[index].mesh;
  2203. if (mesh.parent !== mainMesh) {
  2204. mesh.position = mesh.position.subtract(mainMesh.position);
  2205. mesh.parent = mainMesh;
  2206. }
  2207. mesh.physicsImpostor = new PhysicsImpostor(mesh, parts[index].impostor, options, this)
  2208. }
  2209. mainMesh.physicsImpostor.forceUpdate();
  2210. }
  2211. public deleteCompoundImpostor(compound: any): void {
  2212. var mesh: AbstractMesh = compound.parts[0].mesh;
  2213. mesh.physicsImpostor.dispose(/*true*/);
  2214. mesh.physicsImpostor = null;
  2215. }
  2216. // Misc.
  2217. public createDefaultCameraOrLight() {
  2218. // Light
  2219. if (this.lights.length === 0) {
  2220. new HemisphericLight("default light", Vector3.Up(), this);
  2221. }
  2222. // Camera
  2223. if (!this.activeCamera) {
  2224. var camera = new FreeCamera("default camera", Vector3.Zero(), this);
  2225. // Compute position
  2226. var worldExtends = this.getWorldExtends();
  2227. var worldCenter = worldExtends.min.add(worldExtends.max.subtract(worldExtends.min).scale(0.5));
  2228. camera.position = new Vector3(worldCenter.x, worldCenter.y, worldExtends.min.z - (worldExtends.max.z - worldExtends.min.z));
  2229. camera.setTarget(worldCenter);
  2230. this.activeCamera = camera;
  2231. }
  2232. }
  2233. // Tags
  2234. private _getByTags(list: any[], tagsQuery: string, forEach?: (item: any) => void): any[] {
  2235. if (tagsQuery === undefined) {
  2236. // returns the complete list (could be done with BABYLON.Tags.MatchesQuery but no need to have a for-loop here)
  2237. return list;
  2238. }
  2239. var listByTags = [];
  2240. forEach = forEach || ((item: any) => { return; });
  2241. for (var i in list) {
  2242. var item = list[i];
  2243. if (Tags.MatchesQuery(item, tagsQuery)) {
  2244. listByTags.push(item);
  2245. forEach(item);
  2246. }
  2247. }
  2248. return listByTags;
  2249. }
  2250. public getMeshesByTags(tagsQuery: string, forEach?: (mesh: AbstractMesh) => void): Mesh[] {
  2251. return this._getByTags(this.meshes, tagsQuery, forEach);
  2252. }
  2253. public getCamerasByTags(tagsQuery: string, forEach?: (camera: Camera) => void): Camera[] {
  2254. return this._getByTags(this.cameras, tagsQuery, forEach);
  2255. }
  2256. public getLightsByTags(tagsQuery: string, forEach?: (light: Light) => void): Light[] {
  2257. return this._getByTags(this.lights, tagsQuery, forEach);
  2258. }
  2259. public getMaterialByTags(tagsQuery: string, forEach?: (material: Material) => void): Material[] {
  2260. return this._getByTags(this.materials, tagsQuery, forEach).concat(this._getByTags(this.multiMaterials, tagsQuery, forEach));
  2261. }
  2262. }
  2263. }