babylon.scene.ts 155 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860
  1. module BABYLON {
  2. export interface IDisposable {
  3. dispose(): void;
  4. }
  5. class ClickInfo {
  6. private _singleClick = false;
  7. private _doubleClick = false;
  8. private _hasSwiped = false;
  9. private _ignore = false;
  10. public get singleClick(): boolean {
  11. return this._singleClick;
  12. }
  13. public get doubleClick(): boolean {
  14. return this._doubleClick;
  15. }
  16. public get hasSwiped(): boolean{
  17. return this._hasSwiped;
  18. }
  19. public get ignore(): boolean{
  20. return this._ignore;
  21. }
  22. public set singleClick(b: boolean) {
  23. this._singleClick = b;
  24. }
  25. public set doubleClick(b: boolean) {
  26. this._doubleClick = b;
  27. }
  28. public set hasSwiped(b: boolean) {
  29. this._hasSwiped = b;
  30. }
  31. public set ignore(b: boolean) {
  32. this._ignore = b;
  33. }
  34. }
  35. export class PointerEventTypes {
  36. static _POINTERDOWN = 0x01;
  37. static _POINTERUP = 0x02;
  38. static _POINTERMOVE = 0x04;
  39. static _POINTERWHEEL = 0x08;
  40. static _POINTERPICK = 0x10;
  41. static _POINTERTAP = 0x20;
  42. static _POINTERDOUBLETAP = 0x40;
  43. public static get POINTERDOWN(): number {
  44. return PointerEventTypes._POINTERDOWN;
  45. }
  46. public static get POINTERUP(): number {
  47. return PointerEventTypes._POINTERUP;
  48. }
  49. public static get POINTERMOVE(): number {
  50. return PointerEventTypes._POINTERMOVE;
  51. }
  52. public static get POINTERWHEEL(): number {
  53. return PointerEventTypes._POINTERWHEEL;
  54. }
  55. public static get POINTERPICK(): number {
  56. return PointerEventTypes._POINTERPICK;
  57. }
  58. public static get POINTERTAP(): number {
  59. return PointerEventTypes._POINTERTAP;
  60. }
  61. public static get POINTERDOUBLETAP(): number {
  62. return PointerEventTypes._POINTERDOUBLETAP;
  63. }
  64. }
  65. export class PointerInfoBase {
  66. constructor(public type: number, public event: PointerEvent | MouseWheelEvent) {
  67. }
  68. }
  69. /**
  70. * This class is used to store pointer related info for the onPrePointerObservable event.
  71. * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
  72. */
  73. export class PointerInfoPre extends PointerInfoBase {
  74. constructor(type: number, event: PointerEvent | MouseWheelEvent, localX, localY) {
  75. super(type, event);
  76. this.skipOnPointerObservable = false;
  77. this.localPosition = new Vector2(localX, localY);
  78. }
  79. public localPosition: Vector2;
  80. public skipOnPointerObservable: boolean;
  81. }
  82. /**
  83. * This type contains all the data related to a pointer event in Babylon.js.
  84. * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
  85. */
  86. export class PointerInfo extends PointerInfoBase {
  87. constructor(type: number, event: PointerEvent | MouseWheelEvent, public pickInfo: PickingInfo) {
  88. super(type, event);
  89. }
  90. }
  91. /**
  92. * This class is used by the onRenderingGroupObservable
  93. */
  94. export class RenderingGroupInfo {
  95. /**
  96. * The Scene that being rendered
  97. */
  98. scene: Scene;
  99. /**
  100. * The camera currently used for the rendering pass
  101. */
  102. camera: Camera;
  103. /**
  104. * The ID of the renderingGroup being processed
  105. */
  106. renderingGroupId: number;
  107. /**
  108. * The rendering stage, can be either STAGE_PRECLEAR, STAGE_PREOPAQUE, STAGE_PRETRANSPARENT, STAGE_POSTTRANSPARENT
  109. */
  110. renderStage: number;
  111. /**
  112. * Stage corresponding to the very first hook in the renderingGroup phase: before the render buffer may be cleared
  113. * This stage will be fired no matter what
  114. */
  115. static STAGE_PRECLEAR = 1;
  116. /**
  117. * Called before opaque object are rendered.
  118. * This stage will be fired only if there's 3D Opaque content to render
  119. */
  120. static STAGE_PREOPAQUE = 2;
  121. /**
  122. * Called after the opaque objects are rendered and before the transparent ones
  123. * This stage will be fired only if there's 3D transparent content to render
  124. */
  125. static STAGE_PRETRANSPARENT = 3;
  126. /**
  127. * Called after the transparent object are rendered, last hook of the renderingGroup phase
  128. * This stage will be fired no matter what
  129. */
  130. static STAGE_POSTTRANSPARENT = 4;
  131. }
  132. /**
  133. * Represents a scene to be rendered by the engine.
  134. * @see http://doc.babylonjs.com/page.php?p=21911
  135. */
  136. export class Scene implements IAnimatable {
  137. // Statics
  138. private static _FOGMODE_NONE = 0;
  139. private static _FOGMODE_EXP = 1;
  140. private static _FOGMODE_EXP2 = 2;
  141. private static _FOGMODE_LINEAR = 3;
  142. public static MinDeltaTime = 1.0;
  143. public static MaxDeltaTime = 1000.0;
  144. public static get FOGMODE_NONE(): number {
  145. return Scene._FOGMODE_NONE;
  146. }
  147. public static get FOGMODE_EXP(): number {
  148. return Scene._FOGMODE_EXP;
  149. }
  150. public static get FOGMODE_EXP2(): number {
  151. return Scene._FOGMODE_EXP2;
  152. }
  153. public static get FOGMODE_LINEAR(): number {
  154. return Scene._FOGMODE_LINEAR;
  155. }
  156. // Members
  157. public autoClear = true;
  158. public autoClearDepthAndStencil = true;
  159. public clearColor: Color4 = new Color4(0.2, 0.2, 0.3, 1.0);
  160. public ambientColor = new Color3(0, 0, 0);
  161. public _environmentBRDFTexture: BaseTexture;
  162. protected _environmentTexture: BaseTexture;
  163. /**
  164. * Texture used in all pbr material as the reflection texture.
  165. * As in the majority of the scene they are the same (exception for multi room and so on),
  166. * this is easier to reference from here than from all the materials.
  167. */
  168. public get environmentTexture(): BaseTexture {
  169. return this._environmentTexture;
  170. }
  171. /**
  172. * Texture used in all pbr material as the reflection texture.
  173. * As in the majority of the scene they are the same (exception for multi room and so on),
  174. * this is easier to set here than in all the materials.
  175. */
  176. public set environmentTexture(value: BaseTexture) {
  177. this._environmentTexture = value;
  178. this.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
  179. }
  180. protected _imageProcessingConfiguration: ImageProcessingConfiguration;
  181. /**
  182. * Default image processing configuration used either in the rendering
  183. * Forward main pass or through the imageProcessingPostProcess if present.
  184. * As in the majority of the scene they are the same (exception for multi camera),
  185. * this is easier to reference from here than from all the materials and post process.
  186. *
  187. * No setter as we it is a shared configuration, you can set the values instead.
  188. */
  189. public get imageProcessingConfiguration(): ImageProcessingConfiguration {
  190. return this._imageProcessingConfiguration;
  191. }
  192. public forceWireframe = false;
  193. private _forcePointsCloud = false;
  194. public set forcePointsCloud(value : boolean) {
  195. if (this._forcePointsCloud === value) {
  196. return;
  197. }
  198. this._forcePointsCloud = value;
  199. this.markAllMaterialsAsDirty(Material.MiscDirtyFlag);
  200. }
  201. public get forcePointsCloud(): boolean {
  202. return this._forcePointsCloud;
  203. }
  204. public forceShowBoundingBoxes = false;
  205. public clipPlane: Plane;
  206. public animationsEnabled = true;
  207. public constantlyUpdateMeshUnderPointer = false;
  208. public hoverCursor = "pointer";
  209. // Metadata
  210. public metadata: any = null;
  211. // Events
  212. /**
  213. * An event triggered when the scene is disposed.
  214. * @type {BABYLON.Observable}
  215. */
  216. public onDisposeObservable = new Observable<Scene>();
  217. private _onDisposeObserver: Observer<Scene>;
  218. public set onDispose(callback: () => void) {
  219. if (this._onDisposeObserver) {
  220. this.onDisposeObservable.remove(this._onDisposeObserver);
  221. }
  222. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  223. }
  224. /**
  225. * An event triggered before rendering the scene
  226. * @type {BABYLON.Observable}
  227. */
  228. public onBeforeRenderObservable = new Observable<Scene>();
  229. private _onBeforeRenderObserver: Observer<Scene>;
  230. public set beforeRender(callback: () => void) {
  231. if (this._onBeforeRenderObserver) {
  232. this.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
  233. }
  234. this._onBeforeRenderObserver = this.onBeforeRenderObservable.add(callback);
  235. }
  236. /**
  237. * An event triggered after rendering the scene
  238. * @type {BABYLON.Observable}
  239. */
  240. public onAfterRenderObservable = new Observable<Scene>();
  241. private _onAfterRenderObserver: Observer<Scene>;
  242. public set afterRender(callback: () => void) {
  243. if (this._onAfterRenderObserver) {
  244. this.onAfterRenderObservable.remove(this._onAfterRenderObserver);
  245. }
  246. this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback);
  247. }
  248. /**
  249. * An event triggered when the scene is ready
  250. * @type {BABYLON.Observable}
  251. */
  252. public onReadyObservable = new Observable<Scene>();
  253. /**
  254. * An event triggered before rendering a camera
  255. * @type {BABYLON.Observable}
  256. */
  257. public onBeforeCameraRenderObservable = new Observable<Camera>();
  258. private _onBeforeCameraRenderObserver: Observer<Camera>;
  259. public set beforeCameraRender(callback: () => void) {
  260. if (this._onBeforeCameraRenderObserver) {
  261. this.onBeforeCameraRenderObservable.remove(this._onBeforeCameraRenderObserver);
  262. }
  263. this._onBeforeCameraRenderObserver = this.onBeforeCameraRenderObservable.add(callback);
  264. }
  265. /**
  266. * An event triggered after rendering a camera
  267. * @type {BABYLON.Observable}
  268. */
  269. public onAfterCameraRenderObservable = new Observable<Camera>();
  270. private _onAfterCameraRenderObserver: Observer<Camera>;
  271. public set afterCameraRender(callback: () => void) {
  272. if (this._onAfterCameraRenderObserver) {
  273. this.onAfterCameraRenderObservable.remove(this._onAfterCameraRenderObserver);
  274. }
  275. this._onAfterCameraRenderObserver = this.onAfterCameraRenderObservable.add(callback);
  276. }
  277. /**
  278. * An event triggered when a camera is created
  279. * @type {BABYLON.Observable}
  280. */
  281. public onNewCameraAddedObservable = new Observable<Camera>();
  282. /**
  283. * An event triggered when a camera is removed
  284. * @type {BABYLON.Observable}
  285. */
  286. public onCameraRemovedObservable = new Observable<Camera>();
  287. /**
  288. * An event triggered when a light is created
  289. * @type {BABYLON.Observable}
  290. */
  291. public onNewLightAddedObservable = new Observable<Light>();
  292. /**
  293. * An event triggered when a light is removed
  294. * @type {BABYLON.Observable}
  295. */
  296. public onLightRemovedObservable = new Observable<Light>();
  297. /**
  298. * An event triggered when a geometry is created
  299. * @type {BABYLON.Observable}
  300. */
  301. public onNewGeometryAddedObservable = new Observable<Geometry>();
  302. /**
  303. * An event triggered when a geometry is removed
  304. * @type {BABYLON.Observable}
  305. */
  306. public onGeometryRemovedObservable = new Observable<Geometry>();
  307. /**
  308. * An event triggered when a mesh is created
  309. * @type {BABYLON.Observable}
  310. */
  311. public onNewMeshAddedObservable = new Observable<AbstractMesh>();
  312. /**
  313. * An event triggered when a mesh is removed
  314. * @type {BABYLON.Observable}
  315. */
  316. public onMeshRemovedObservable = new Observable<AbstractMesh>();
  317. /**
  318. * This Observable will be triggered for each stage of each renderingGroup of each rendered camera.
  319. * The RenderinGroupInfo class contains all the information about the context in which the observable is called
  320. * If you wish to register an Observer only for a given set of renderingGroup, use the mask with a combination of the renderingGroup index elevated to the power of two (1 for renderingGroup 0, 2 for renderingrOup1, 4 for 2 and 8 for 3)
  321. */
  322. public onRenderingGroupObservable = new Observable<RenderingGroupInfo>();
  323. // Animations
  324. public animations: Animation[] = [];
  325. // Pointers
  326. public pointerDownPredicate: (Mesh: AbstractMesh) => boolean;
  327. public pointerUpPredicate: (Mesh: AbstractMesh) => boolean;
  328. public pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
  329. private _onPointerMove: (evt: PointerEvent) => void;
  330. private _onPointerDown: (evt: PointerEvent) => void;
  331. private _onPointerUp: (evt: PointerEvent) => void;
  332. public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  333. public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  334. public onPointerUp: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  335. public onPointerPick: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  336. /**
  337. * This observable event is triggered when any mouse event registered during Scene.attach() is called BEFORE the 3D engine to process anything (mesh/sprite picking for instance).
  338. * You have the possibility to skip the 3D Engine process and the call to onPointerObservable by setting PointerInfoBase.skipOnPointerObservable to true
  339. */
  340. public onPrePointerObservable = new Observable<PointerInfoPre>();
  341. /**
  342. * Observable event triggered each time an input event is received from the rendering canvas
  343. */
  344. public onPointerObservable = new Observable<PointerInfo>();
  345. public get unTranslatedPointer(): Vector2 {
  346. return new Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY);
  347. }
  348. public static DragMovementThreshold = 10; // in pixels
  349. public static LongPressDelay = 500; // in milliseconds
  350. public static DoubleClickDelay = 300; // in milliseconds
  351. public static ExclusiveDoubleClickMode = false; // If you need to check double click without raising a single click at first click, enable this flag
  352. private _initClickEvent: (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void) => void;
  353. private _initActionManager: (act: ActionManager, clickInfo: ClickInfo) => ActionManager;
  354. private _delayedSimpleClick: (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void) => void;
  355. private _delayedSimpleClickTimeout;
  356. private _previousDelayedSimpleClickTimeout;
  357. private _meshPickProceed = false;
  358. private _previousButtonPressed;
  359. private _previousHasSwiped = false;
  360. private _currentPickResult = null;
  361. private _previousPickResult = null;
  362. private _isButtonPressed = false;
  363. private _doubleClickOccured = false;
  364. 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
  365. private _pointerX: number;
  366. private _pointerY: number;
  367. private _unTranslatedPointerX: number;
  368. private _unTranslatedPointerY: number;
  369. private _startingPointerPosition = new Vector2(0, 0);
  370. private _previousStartingPointerPosition = new Vector2(0, 0);
  371. private _startingPointerTime = 0;
  372. private _previousStartingPointerTime = 0;
  373. // Mirror
  374. public _mirroredCameraPosition: Vector3;
  375. // Keyboard
  376. private _onKeyDown: (evt: Event) => void;
  377. private _onKeyUp: (evt: Event) => void;
  378. // Coordinate system
  379. /**
  380. * use right-handed coordinate system on this scene.
  381. * @type {boolean}
  382. */
  383. private _useRightHandedSystem = false;
  384. public set useRightHandedSystem(value: boolean) {
  385. if (this._useRightHandedSystem === value) {
  386. return;
  387. }
  388. this._useRightHandedSystem = value;
  389. this.markAllMaterialsAsDirty(Material.MiscDirtyFlag);
  390. }
  391. public get useRightHandedSystem(): boolean {
  392. return this._useRightHandedSystem;
  393. }
  394. // Fog
  395. /**
  396. * is fog enabled on this scene.
  397. * @type {boolean}
  398. */
  399. private _fogEnabled = true;
  400. public set fogEnabled(value : boolean) {
  401. if (this._fogEnabled === value) {
  402. return;
  403. }
  404. this._fogEnabled = value;
  405. this.markAllMaterialsAsDirty(Material.MiscDirtyFlag);
  406. }
  407. public get fogEnabled(): boolean {
  408. return this._fogEnabled;
  409. }
  410. private _fogMode = Scene.FOGMODE_NONE;
  411. public set fogMode(value : number) {
  412. if (this._fogMode === value) {
  413. return;
  414. }
  415. this._fogMode = value;
  416. this.markAllMaterialsAsDirty(Material.MiscDirtyFlag);
  417. }
  418. public get fogMode(): number {
  419. return this._fogMode;
  420. }
  421. public fogColor = new Color3(0.2, 0.2, 0.3);
  422. public fogDensity = 0.1;
  423. public fogStart = 0;
  424. public fogEnd = 1000.0;
  425. // Lights
  426. /**
  427. * is shadow enabled on this scene.
  428. * @type {boolean}
  429. */
  430. private _shadowsEnabled = true;
  431. public set shadowsEnabled(value : boolean) {
  432. if (this._shadowsEnabled === value) {
  433. return;
  434. }
  435. this._shadowsEnabled = value;
  436. this.markAllMaterialsAsDirty(Material.LightDirtyFlag);
  437. }
  438. public get shadowsEnabled(): boolean {
  439. return this._shadowsEnabled;
  440. }
  441. /**
  442. * is light enabled on this scene.
  443. * @type {boolean}
  444. */
  445. private _lightsEnabled = true;
  446. public set lightsEnabled(value : boolean) {
  447. if (this._lightsEnabled === value) {
  448. return;
  449. }
  450. this._lightsEnabled = value;
  451. this.markAllMaterialsAsDirty(Material.LightDirtyFlag);
  452. }
  453. public get lightsEnabled(): boolean {
  454. return this._lightsEnabled;
  455. }
  456. /**
  457. * All of the lights added to this scene.
  458. * @see BABYLON.Light
  459. * @type {BABYLON.Light[]}
  460. */
  461. public lights = new Array<Light>();
  462. // Cameras
  463. /**
  464. * All of the cameras added to this scene.
  465. * @see BABYLON.Camera
  466. * @type {BABYLON.Camera[]}
  467. */
  468. public cameras = new Array<Camera>();
  469. public activeCameras = new Array<Camera>();
  470. public activeCamera: Camera;
  471. // Meshes
  472. /**
  473. * All of the (abstract) meshes added to this scene.
  474. * @see BABYLON.AbstractMesh
  475. * @type {BABYLON.AbstractMesh[]}
  476. */
  477. public meshes = new Array<AbstractMesh>();
  478. // Geometries
  479. private _geometries = new Array<Geometry>();
  480. public materials = new Array<Material>();
  481. public multiMaterials = new Array<MultiMaterial>();
  482. private _defaultMaterial: Material;
  483. public get defaultMaterial(): Material {
  484. if (!this._defaultMaterial) {
  485. this._defaultMaterial = new StandardMaterial("default material", this);
  486. }
  487. return this._defaultMaterial;
  488. }
  489. public set defaultMaterial(value: Material) {
  490. this._defaultMaterial = value;
  491. }
  492. // Textures
  493. private _texturesEnabled = true;
  494. public set texturesEnabled(value : boolean) {
  495. if (this._texturesEnabled === value) {
  496. return;
  497. }
  498. this._texturesEnabled = value;
  499. this.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
  500. }
  501. public get texturesEnabled(): boolean {
  502. return this._texturesEnabled;
  503. }
  504. public textures = new Array<BaseTexture>();
  505. // Particles
  506. public particlesEnabled = true;
  507. public particleSystems = new Array<ParticleSystem>();
  508. // Sprites
  509. public spritesEnabled = true;
  510. public spriteManagers = new Array<SpriteManager>();
  511. // Layers
  512. public layers = new Array<Layer>();
  513. public highlightLayers = new Array<HighlightLayer>();
  514. // Skeletons
  515. private _skeletonsEnabled = true;
  516. public set skeletonsEnabled(value : boolean) {
  517. if (this._skeletonsEnabled === value) {
  518. return;
  519. }
  520. this._skeletonsEnabled = value;
  521. this.markAllMaterialsAsDirty(Material.AttributesDirtyFlag);
  522. }
  523. public get skeletonsEnabled(): boolean {
  524. return this._skeletonsEnabled;
  525. }
  526. public skeletons = new Array<Skeleton>();
  527. // Morph targets
  528. public morphTargetManagers = new Array<MorphTargetManager>();
  529. // Lens flares
  530. public lensFlaresEnabled = true;
  531. public lensFlareSystems = new Array<LensFlareSystem>();
  532. // Collisions
  533. public collisionsEnabled = true;
  534. private _workerCollisions;
  535. public collisionCoordinator: ICollisionCoordinator;
  536. public gravity = new Vector3(0, -9.807, 0);
  537. // Postprocesses
  538. public postProcessesEnabled = true;
  539. public postProcessManager: PostProcessManager;
  540. private _postProcessRenderPipelineManager: PostProcessRenderPipelineManager
  541. public get postProcessRenderPipelineManager(): PostProcessRenderPipelineManager {
  542. if (!this._postProcessRenderPipelineManager) {
  543. this._postProcessRenderPipelineManager = new PostProcessRenderPipelineManager();
  544. }
  545. return this._postProcessRenderPipelineManager;
  546. }
  547. // Customs render targets
  548. public renderTargetsEnabled = true;
  549. public dumpNextRenderTargets = false;
  550. public customRenderTargets = new Array<RenderTargetTexture>();
  551. // Delay loading
  552. public useDelayedTextureLoading: boolean;
  553. // Imported meshes
  554. public importedMeshesFiles = new Array<String>();
  555. // Probes
  556. public probesEnabled = true;
  557. public reflectionProbes = new Array<ReflectionProbe>();
  558. // Database
  559. public database; //ANY
  560. /**
  561. * This scene's action manager
  562. * @type {BABYLON.ActionManager}
  563. */
  564. public actionManager: ActionManager;
  565. public _actionManagers = new Array<ActionManager>();
  566. private _meshesForIntersections = new SmartArray<AbstractMesh>(256);
  567. // Procedural textures
  568. public proceduralTexturesEnabled = true;
  569. public _proceduralTextures = new Array<ProceduralTexture>();
  570. // Sound Tracks
  571. public mainSoundTrack: SoundTrack;
  572. public soundTracks = new Array<SoundTrack>();
  573. private _audioEnabled = true;
  574. private _headphone = false;
  575. //Simplification Queue
  576. public simplificationQueue: SimplificationQueue;
  577. // Private
  578. private _engine: Engine;
  579. // Performance counters
  580. private _totalMeshesCounter = new PerfCounter();
  581. private _totalLightsCounter = new PerfCounter();
  582. private _totalMaterialsCounter = new PerfCounter();
  583. private _totalTexturesCounter = new PerfCounter();
  584. private _totalVertices = new PerfCounter();
  585. public _activeIndices = new PerfCounter();
  586. public _activeParticles = new PerfCounter();
  587. private _lastFrameDuration = new PerfCounter();
  588. private _evaluateActiveMeshesDuration = new PerfCounter();
  589. private _renderTargetsDuration = new PerfCounter();
  590. public _particlesDuration = new PerfCounter();
  591. private _renderDuration = new PerfCounter();
  592. public _spritesDuration = new PerfCounter();
  593. public _activeBones = new PerfCounter();
  594. private _animationRatio: number;
  595. private _animationTimeLast: number;
  596. private _animationTime: number = 0;
  597. public animationTimeScale: number = 1;
  598. public _cachedMaterial: Material;
  599. public _cachedEffect: Effect;
  600. public _cachedVisibility: number;
  601. private _renderId = 0;
  602. private _executeWhenReadyTimeoutId = -1;
  603. private _intermediateRendering = false;
  604. private _viewUpdateFlag = -1;
  605. private _projectionUpdateFlag = -1;
  606. public _toBeDisposed = new SmartArray<IDisposable>(256);
  607. private _pendingData = [];//ANY
  608. private _activeMeshes = new SmartArray<Mesh>(256);
  609. private _processedMaterials = new SmartArray<Material>(256);
  610. private _renderTargets = new SmartArray<RenderTargetTexture>(256);
  611. public _activeParticleSystems = new SmartArray<ParticleSystem>(256);
  612. private _activeSkeletons = new SmartArray<Skeleton>(32);
  613. private _softwareSkinnedMeshes = new SmartArray<Mesh>(32);
  614. private _renderingManager: RenderingManager;
  615. private _physicsEngine: PhysicsEngine;
  616. public _activeAnimatables = new Array<Animatable>();
  617. private _transformMatrix = Matrix.Zero();
  618. private _sceneUbo: UniformBuffer;
  619. private _pickWithRayInverseMatrix: Matrix;
  620. private _boundingBoxRenderer: BoundingBoxRenderer;
  621. private _outlineRenderer: OutlineRenderer;
  622. private _viewMatrix: Matrix;
  623. private _projectionMatrix: Matrix;
  624. private _frustumPlanes: Plane[];
  625. public get frustumPlanes(): Plane[] {
  626. return this._frustumPlanes;
  627. }
  628. public requireLightSorting = false;
  629. private _selectionOctree: Octree<AbstractMesh>;
  630. private _pointerOverMesh: AbstractMesh;
  631. private _pointerOverSprite: Sprite;
  632. private _debugLayer: DebugLayer;
  633. private _depthRenderer: DepthRenderer;
  634. private _geometryBufferRenderer: GeometryBufferRenderer;
  635. private _uniqueIdCounter = 0;
  636. private _pickedDownMesh: AbstractMesh;
  637. private _pickedUpMesh: AbstractMesh;
  638. private _pickedDownSprite: Sprite;
  639. private _externalData: StringDictionary<Object>;
  640. private _uid: string;
  641. /**
  642. * @constructor
  643. * @param {BABYLON.Engine} engine - the engine to be used to render this scene.
  644. */
  645. constructor(engine: Engine) {
  646. this._engine = engine || Engine.LastCreatedEngine;
  647. this._engine.scenes.push(this);
  648. this._uid = null;
  649. this._renderingManager = new RenderingManager(this);
  650. this.postProcessManager = new PostProcessManager(this);
  651. if (OutlineRenderer) {
  652. this._outlineRenderer = new OutlineRenderer(this);
  653. }
  654. this.attachControl();
  655. if (SoundTrack) {
  656. this.mainSoundTrack = new SoundTrack(this, { mainTrack: true });
  657. }
  658. //simplification queue
  659. if (SimplificationQueue) {
  660. this.simplificationQueue = new SimplificationQueue();
  661. }
  662. //collision coordinator initialization. For now legacy per default.
  663. this.workerCollisions = false;//(!!Worker && (!!BABYLON.CollisionWorker || BABYLON.WorkerIncluded));
  664. // Uniform Buffer
  665. this._createUbo();
  666. // Default Image processing definition.
  667. this._imageProcessingConfiguration = new ImageProcessingConfiguration();
  668. }
  669. // Properties
  670. public get debugLayer(): DebugLayer {
  671. if (!this._debugLayer) {
  672. this._debugLayer = new DebugLayer(this);
  673. }
  674. return this._debugLayer;
  675. }
  676. public set workerCollisions(enabled: boolean) {
  677. if (!BABYLON.CollisionCoordinatorLegacy) {
  678. return;
  679. }
  680. enabled = (enabled && !!Worker);
  681. this._workerCollisions = enabled;
  682. if (this.collisionCoordinator) {
  683. this.collisionCoordinator.destroy();
  684. }
  685. this.collisionCoordinator = enabled ? new CollisionCoordinatorWorker() : new CollisionCoordinatorLegacy();
  686. this.collisionCoordinator.init(this);
  687. }
  688. public get workerCollisions(): boolean {
  689. return this._workerCollisions;
  690. }
  691. public get selectionOctree(): Octree<AbstractMesh> {
  692. return this._selectionOctree;
  693. }
  694. /**
  695. * The mesh that is currently under the pointer.
  696. * @return {BABYLON.AbstractMesh} mesh under the pointer/mouse cursor or null if none.
  697. */
  698. public get meshUnderPointer(): AbstractMesh {
  699. return this._pointerOverMesh;
  700. }
  701. /**
  702. * Current on-screen X position of the pointer
  703. * @return {number} X position of the pointer
  704. */
  705. public get pointerX(): number {
  706. return this._pointerX;
  707. }
  708. /**
  709. * Current on-screen Y position of the pointer
  710. * @return {number} Y position of the pointer
  711. */
  712. public get pointerY(): number {
  713. return this._pointerY;
  714. }
  715. public getCachedMaterial(): Material {
  716. return this._cachedMaterial;
  717. }
  718. public getCachedEffect(): Effect {
  719. return this._cachedEffect;
  720. }
  721. public getCachedVisibility(): number {
  722. return this._cachedVisibility;
  723. }
  724. public isCachedMaterialValid(material: Material, effect: Effect, visibility: number = 0) {
  725. return this._cachedEffect !== effect || this._cachedMaterial !== material || this._cachedVisibility !== visibility;
  726. }
  727. public getBoundingBoxRenderer(): BoundingBoxRenderer {
  728. if (!this._boundingBoxRenderer) {
  729. this._boundingBoxRenderer = new BoundingBoxRenderer(this);
  730. }
  731. return this._boundingBoxRenderer;
  732. }
  733. public getOutlineRenderer(): OutlineRenderer {
  734. return this._outlineRenderer;
  735. }
  736. public getEngine(): Engine {
  737. return this._engine;
  738. }
  739. public getTotalVertices(): number {
  740. return this._totalVertices.current;
  741. }
  742. public get totalVerticesPerfCounter(): PerfCounter {
  743. return this._totalVertices;
  744. }
  745. public getActiveIndices(): number {
  746. return this._activeIndices.current;
  747. }
  748. public get totalActiveIndicesPerfCounter(): PerfCounter {
  749. return this._activeIndices;
  750. }
  751. public getActiveParticles(): number {
  752. return this._activeParticles.current;
  753. }
  754. public get activeParticlesPerfCounter(): PerfCounter {
  755. return this._activeParticles;
  756. }
  757. public getActiveBones(): number {
  758. return this._activeBones.current;
  759. }
  760. public get activeBonesPerfCounter(): PerfCounter {
  761. return this._activeBones;
  762. }
  763. // Stats
  764. public getLastFrameDuration(): number {
  765. return this._lastFrameDuration.current;
  766. }
  767. public get lastFramePerfCounter(): PerfCounter {
  768. return this._lastFrameDuration;
  769. }
  770. public getEvaluateActiveMeshesDuration(): number {
  771. return this._evaluateActiveMeshesDuration.current;
  772. }
  773. public get evaluateActiveMeshesDurationPerfCounter(): PerfCounter {
  774. return this._evaluateActiveMeshesDuration;
  775. }
  776. public getActiveMeshes(): SmartArray<Mesh> {
  777. return this._activeMeshes;
  778. }
  779. public getRenderTargetsDuration(): number {
  780. return this._renderTargetsDuration.current;
  781. }
  782. public getRenderDuration(): number {
  783. return this._renderDuration.current;
  784. }
  785. public get renderDurationPerfCounter(): PerfCounter {
  786. return this._renderDuration;
  787. }
  788. public getParticlesDuration(): number {
  789. return this._particlesDuration.current;
  790. }
  791. public get particlesDurationPerfCounter(): PerfCounter {
  792. return this._particlesDuration;
  793. }
  794. public getSpritesDuration(): number {
  795. return this._spritesDuration.current;
  796. }
  797. public get spriteDuractionPerfCounter(): PerfCounter {
  798. return this._spritesDuration;
  799. }
  800. public getAnimationRatio(): number {
  801. return this._animationRatio;
  802. }
  803. public getRenderId(): number {
  804. return this._renderId;
  805. }
  806. public incrementRenderId(): void {
  807. this._renderId++;
  808. }
  809. private _updatePointerPosition(evt: PointerEvent): void {
  810. var canvasRect = this._engine.getRenderingCanvasClientRect();
  811. this._pointerX = evt.clientX - canvasRect.left;
  812. this._pointerY = evt.clientY - canvasRect.top;
  813. this._unTranslatedPointerX = this._pointerX;
  814. this._unTranslatedPointerY = this._pointerY;
  815. if (this.cameraToUseForPointers) {
  816. this._pointerX = this._pointerX - this.cameraToUseForPointers.viewport.x * this._engine.getRenderWidth();
  817. this._pointerY = this._pointerY - this.cameraToUseForPointers.viewport.y * this._engine.getRenderHeight();
  818. }
  819. }
  820. private _createUbo(): void {
  821. this._sceneUbo = new UniformBuffer(this._engine, null, true);
  822. this._sceneUbo.addUniform("viewProjection", 16);
  823. this._sceneUbo.addUniform("view", 16);
  824. }
  825. // Pointers handling
  826. /**
  827. * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
  828. * @param attachUp defines if you want to attach events to pointerup
  829. * @param attachDown defines if you want to attach events to pointerdown
  830. * @param attachMove defines if you want to attach events to pointermove
  831. */
  832. public attachControl(attachUp = true, attachDown = true, attachMove = true) {
  833. this._initActionManager = (act: ActionManager, clickInfo: ClickInfo): ActionManager => {
  834. if (!this._meshPickProceed) {
  835. let pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
  836. this._currentPickResult = pickResult;
  837. if (pickResult) {
  838. act = (pickResult.hit && pickResult.pickedMesh) ? pickResult.pickedMesh.actionManager : null;
  839. }
  840. this._meshPickProceed = true;
  841. }
  842. return act;
  843. };
  844. this._delayedSimpleClick = (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void) => {
  845. // double click delay is over and that no double click has been raised since, or the 2 consecutive keys pressed are different
  846. if ((new Date().getTime() - this._previousStartingPointerTime > Scene.DoubleClickDelay && !this._doubleClickOccured) ||
  847. btn !== this._previousButtonPressed ) {
  848. this._doubleClickOccured = false;
  849. clickInfo.singleClick = true;
  850. clickInfo.ignore = false;
  851. cb(clickInfo, this._currentPickResult);
  852. }
  853. }
  854. this._initClickEvent = (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void): void => {
  855. let clickInfo = new ClickInfo();
  856. this._currentPickResult = null;
  857. let act;
  858. let checkPicking = obs1.hasSpecificMask(PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(PointerEventTypes.POINTERPICK)
  859. || obs1.hasSpecificMask(PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERTAP)
  860. || obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
  861. if (!checkPicking && BABYLON.ActionManager && ActionManager.HasPickTriggers) {
  862. act = this._initActionManager(act, clickInfo);
  863. if (act)
  864. checkPicking = act.hasPickTriggers;
  865. }
  866. if (checkPicking) {
  867. let btn = evt.button;
  868. clickInfo.hasSwiped = Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
  869. Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
  870. if (!clickInfo.hasSwiped) {
  871. let checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
  872. if (!checkSingleClickImmediately) {
  873. checkSingleClickImmediately = !obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) &&
  874. !obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
  875. if (checkSingleClickImmediately && !ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
  876. act = this._initActionManager(act, clickInfo);
  877. if (act)
  878. checkSingleClickImmediately = !act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
  879. }
  880. }
  881. if (checkSingleClickImmediately) {
  882. // single click detected if double click delay is over or two different successive keys pressed without exclusive double click or no double click required
  883. if (new Date().getTime() - this._previousStartingPointerTime > Scene.DoubleClickDelay ||
  884. btn !== this._previousButtonPressed ) {
  885. clickInfo.singleClick = true;
  886. cb(clickInfo, this._currentPickResult);
  887. }
  888. }
  889. // at least one double click is required to be check and exclusive double click is enabled
  890. else {
  891. // wait that no double click has been raised during the double click delay
  892. this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
  893. this._delayedSimpleClickTimeout = window.setTimeout(this._delayedSimpleClick.bind(this, btn, clickInfo, cb), Scene.DoubleClickDelay);
  894. }
  895. let checkDoubleClick = obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) ||
  896. obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
  897. if (!checkDoubleClick && ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)){
  898. act = this._initActionManager(act, clickInfo);
  899. if (act)
  900. checkDoubleClick = act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
  901. }
  902. if (checkDoubleClick) {
  903. // two successive keys pressed are equal, double click delay is not over and double click has not just occurred
  904. if (btn === this._previousButtonPressed &&
  905. new Date().getTime() - this._previousStartingPointerTime < Scene.DoubleClickDelay &&
  906. !this._doubleClickOccured
  907. ) {
  908. // pointer has not moved for 2 clicks, it's a double click
  909. if (!clickInfo.hasSwiped &&
  910. Math.abs(this._previousStartingPointerPosition.x - this._startingPointerPosition.x) < Scene.DragMovementThreshold &&
  911. Math.abs(this._previousStartingPointerPosition.y - this._startingPointerPosition.y) < Scene.DragMovementThreshold) {
  912. this._previousStartingPointerTime = 0;
  913. this._doubleClickOccured = true;
  914. clickInfo.doubleClick = true;
  915. clickInfo.ignore = false;
  916. if (Scene.ExclusiveDoubleClickMode && this._previousDelayedSimpleClickTimeout && this._previousDelayedSimpleClickTimeout.clearTimeout)
  917. this._previousDelayedSimpleClickTimeout.clearTimeout();
  918. this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
  919. cb(clickInfo, this._currentPickResult);
  920. }
  921. // if the two successive clicks are too far, it's just two simple clicks
  922. else {
  923. this._doubleClickOccured = false;
  924. this._previousStartingPointerTime = this._startingPointerTime;
  925. this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
  926. this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
  927. this._previousButtonPressed = btn;
  928. this._previousHasSwiped = clickInfo.hasSwiped;
  929. if (Scene.ExclusiveDoubleClickMode){
  930. if (this._previousDelayedSimpleClickTimeout && this._previousDelayedSimpleClickTimeout.clearTimeout) {
  931. this._previousDelayedSimpleClickTimeout.clearTimeout();
  932. }
  933. this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
  934. cb(clickInfo, this._previousPickResult);
  935. }
  936. else {
  937. cb(clickInfo, this._currentPickResult);
  938. }
  939. }
  940. }
  941. // just the first click of the double has been raised
  942. else {
  943. this._doubleClickOccured = false;
  944. this._previousStartingPointerTime = this._startingPointerTime;
  945. this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
  946. this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
  947. this._previousButtonPressed = btn;
  948. this._previousHasSwiped = clickInfo.hasSwiped;
  949. }
  950. }
  951. }
  952. }
  953. clickInfo.ignore = true;
  954. cb(clickInfo, this._currentPickResult);
  955. };
  956. var spritePredicate = (sprite: Sprite): boolean => {
  957. return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
  958. };
  959. this._onPointerMove = (evt: PointerEvent) => {
  960. this._updatePointerPosition(evt);
  961. // PreObservable support
  962. if (this.onPrePointerObservable.hasObservers()) {
  963. let type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
  964. let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
  965. this.onPrePointerObservable.notifyObservers(pi, type);
  966. if (pi.skipOnPointerObservable) {
  967. return;
  968. }
  969. }
  970. if (!this.cameraToUseForPointers && !this.activeCamera) {
  971. return;
  972. }
  973. var canvas = this._engine.getRenderingCanvas();
  974. if (!this.pointerMovePredicate) {
  975. this.pointerMovePredicate = (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (this.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined));
  976. }
  977. // Meshes
  978. var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);
  979. if (pickResult && pickResult.hit && pickResult.pickedMesh) {
  980. this.setPointerOverSprite(null);
  981. this.setPointerOverMesh(pickResult.pickedMesh);
  982. if (this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
  983. if (this._pointerOverMesh.actionManager.hoverCursor) {
  984. canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
  985. } else {
  986. canvas.style.cursor = this.hoverCursor;
  987. }
  988. } else {
  989. canvas.style.cursor = "";
  990. }
  991. } else {
  992. this.setPointerOverMesh(null);
  993. // Sprites
  994. pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
  995. if (pickResult && pickResult.hit && pickResult.pickedSprite) {
  996. this.setPointerOverSprite(pickResult.pickedSprite);
  997. if (this._pointerOverSprite.actionManager && this._pointerOverSprite.actionManager.hoverCursor) {
  998. canvas.style.cursor = this._pointerOverSprite.actionManager.hoverCursor;
  999. } else {
  1000. canvas.style.cursor = this.hoverCursor;
  1001. }
  1002. } else {
  1003. this.setPointerOverSprite(null);
  1004. // Restore pointer
  1005. canvas.style.cursor = "";
  1006. }
  1007. }
  1008. if (this.onPointerMove) {
  1009. this.onPointerMove(evt, pickResult);
  1010. }
  1011. if (this.onPointerObservable.hasObservers()) {
  1012. let type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
  1013. let pi = new PointerInfo(type, evt, pickResult);
  1014. this.onPointerObservable.notifyObservers(pi, type);
  1015. }
  1016. };
  1017. this._onPointerDown = (evt: PointerEvent) => {
  1018. this._isButtonPressed = true;
  1019. this._pickedDownMesh = null;
  1020. this._meshPickProceed = false;
  1021. this._updatePointerPosition(evt);
  1022. // PreObservable support
  1023. if (this.onPrePointerObservable.hasObservers()) {
  1024. let type = PointerEventTypes.POINTERDOWN;
  1025. let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
  1026. this.onPrePointerObservable.notifyObservers(pi, type);
  1027. if (pi.skipOnPointerObservable) {
  1028. return;
  1029. }
  1030. }
  1031. if (!this.cameraToUseForPointers && !this.activeCamera) {
  1032. return;
  1033. }
  1034. this._startingPointerPosition.x = this._pointerX;
  1035. this._startingPointerPosition.y = this._pointerY;
  1036. this._startingPointerTime = new Date().getTime();
  1037. if (!this.pointerDownPredicate) {
  1038. this.pointerDownPredicate = (mesh: AbstractMesh): boolean => {
  1039. return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled();
  1040. };
  1041. }
  1042. // Meshes
  1043. this._pickedDownMesh = null;
  1044. var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
  1045. if (pickResult && pickResult.hit && pickResult.pickedMesh) {
  1046. this._pickedDownMesh = pickResult.pickedMesh;
  1047. var actionManager = pickResult.pickedMesh.actionManager;
  1048. if (actionManager) {
  1049. if (actionManager.hasPickTriggers) {
  1050. actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1051. switch (evt.button) {
  1052. case 0:
  1053. actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1054. break;
  1055. case 1:
  1056. actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1057. break;
  1058. case 2:
  1059. actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1060. break;
  1061. }
  1062. }
  1063. if (actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger)) {
  1064. window.setTimeout((function () {
  1065. var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY,
  1066. (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger) && mesh == this._pickedDownMesh,
  1067. false, this.cameraToUseForPointers);
  1068. if (pickResult && pickResult.hit && pickResult.pickedMesh) {
  1069. if (this._isButtonPressed &&
  1070. ((new Date().getTime() - this._startingPointerTime) > Scene.LongPressDelay) &&
  1071. (Math.abs(this._startingPointerPosition.x - this._pointerX) < Scene.DragMovementThreshold &&
  1072. Math.abs(this._startingPointerPosition.y - this._pointerY) < Scene.DragMovementThreshold)) {
  1073. this._startingPointerTime = 0;
  1074. actionManager.processTrigger(ActionManager.OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1075. }
  1076. }
  1077. }).bind(this), Scene.LongPressDelay);
  1078. }
  1079. }
  1080. }
  1081. if (this.onPointerDown) {
  1082. this.onPointerDown(evt, pickResult);
  1083. }
  1084. if (this.onPointerObservable.hasObservers()) {
  1085. let type = PointerEventTypes.POINTERDOWN;
  1086. let pi = new PointerInfo(type, evt, pickResult);
  1087. this.onPointerObservable.notifyObservers(pi, type);
  1088. }
  1089. // Sprites
  1090. this._pickedDownSprite = null;
  1091. if (this.spriteManagers.length > 0) {
  1092. pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
  1093. if (pickResult && pickResult.hit && pickResult.pickedSprite) {
  1094. if (pickResult.pickedSprite.actionManager) {
  1095. this._pickedDownSprite = pickResult.pickedSprite;
  1096. switch (evt.button) {
  1097. case 0:
  1098. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  1099. break;
  1100. case 1:
  1101. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  1102. break;
  1103. case 2:
  1104. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  1105. break;
  1106. }
  1107. if (pickResult.pickedSprite.actionManager) {
  1108. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  1109. }
  1110. }
  1111. }
  1112. }
  1113. };
  1114. this._onPointerUp = (evt: PointerEvent) => {
  1115. this._isButtonPressed = false;
  1116. this._pickedUpMesh = null;
  1117. this._meshPickProceed = false;
  1118. this._updatePointerPosition(evt);
  1119. this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (function(clickInfo, pickResult){
  1120. // PreObservable support
  1121. if (this.onPrePointerObservable.hasObservers()) {
  1122. if (!clickInfo.ignore) {
  1123. if (!clickInfo.hasSwiped) {
  1124. if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
  1125. let type = PointerEventTypes.POINTERTAP;
  1126. let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
  1127. this.onPrePointerObservable.notifyObservers(pi, type);
  1128. if (pi.skipOnPointerObservable) {
  1129. return;
  1130. }
  1131. }
  1132. if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
  1133. let type = PointerEventTypes.POINTERDOUBLETAP;
  1134. let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
  1135. this.onPrePointerObservable.notifyObservers(pi, type);
  1136. if (pi.skipOnPointerObservable) {
  1137. return;
  1138. }
  1139. }
  1140. }
  1141. }
  1142. else {
  1143. let type = PointerEventTypes.POINTERUP;
  1144. let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
  1145. this.onPrePointerObservable.notifyObservers(pi, type);
  1146. if (pi.skipOnPointerObservable) {
  1147. return;
  1148. }
  1149. }
  1150. }
  1151. if (!this.cameraToUseForPointers && !this.activeCamera) {
  1152. return;
  1153. }
  1154. if (!this.pointerUpPredicate) {
  1155. this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
  1156. return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled();
  1157. };
  1158. }
  1159. // Meshes
  1160. if (!this._meshPickProceed && (BABYLON.ActionManager && ActionManager.HasTriggers || this.onPointerObservable.hasObservers())) {
  1161. this._initActionManager(null, clickInfo);
  1162. }
  1163. if (!pickResult) {
  1164. pickResult = this._currentPickResult;
  1165. }
  1166. if (pickResult && pickResult && pickResult.pickedMesh) {
  1167. this._pickedUpMesh = pickResult.pickedMesh;
  1168. if (this._pickedDownMesh === this._pickedUpMesh) {
  1169. if (this.onPointerPick) {
  1170. this.onPointerPick(evt, pickResult);
  1171. }
  1172. if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
  1173. let type = PointerEventTypes.POINTERPICK;
  1174. let pi = new PointerInfo(type, evt, pickResult);
  1175. this.onPointerObservable.notifyObservers(pi, type);
  1176. }
  1177. }
  1178. if (pickResult.pickedMesh.actionManager) {
  1179. if (clickInfo.ignore) {
  1180. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1181. }
  1182. if (!clickInfo.hasSwiped && !clickInfo.ignore && clickInfo.singleClick) {
  1183. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1184. }
  1185. if (clickInfo.doubleClick && !clickInfo.ignore && pickResult.pickedMesh.actionManager.hasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
  1186. pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnDoublePickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
  1187. }
  1188. }
  1189. }
  1190. if (this._pickedDownMesh &&
  1191. this._pickedDownMesh.actionManager &&
  1192. this._pickedDownMesh.actionManager.hasSpecificTrigger(ActionManager.OnPickOutTrigger) &&
  1193. this._pickedDownMesh !== this._pickedUpMesh) {
  1194. this._pickedDownMesh.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
  1195. }
  1196. if (this.onPointerUp) {
  1197. this.onPointerUp(evt, pickResult);
  1198. }
  1199. if (this.onPointerObservable.hasObservers()) {
  1200. if (!clickInfo.ignore) {
  1201. if (!clickInfo.hasSwiped) {
  1202. if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
  1203. let type = PointerEventTypes.POINTERTAP;
  1204. let pi = new PointerInfo(type, evt, pickResult);
  1205. this.onPointerObservable.notifyObservers(pi, type);
  1206. }
  1207. if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
  1208. let type = PointerEventTypes.POINTERDOUBLETAP;
  1209. let pi = new PointerInfo(type, evt, pickResult);
  1210. this.onPointerObservable.notifyObservers(pi, type);
  1211. }
  1212. }
  1213. }
  1214. else {
  1215. let type = PointerEventTypes.POINTERUP;
  1216. let pi = new PointerInfo(type, evt, pickResult);
  1217. this.onPointerObservable.notifyObservers(pi, type);
  1218. }
  1219. }
  1220. // Sprites
  1221. if (this.spriteManagers.length > 0) {
  1222. pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
  1223. if (pickResult.hit && pickResult.pickedSprite) {
  1224. if (pickResult.pickedSprite.actionManager) {
  1225. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  1226. if (pickResult.pickedSprite.actionManager) {
  1227. if (Math.abs(this._startingPointerPosition.x - this._pointerX) < Scene.DragMovementThreshold && Math.abs(this._startingPointerPosition.y - this._pointerY) < Scene.DragMovementThreshold) {
  1228. pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
  1229. }
  1230. }
  1231. }
  1232. }
  1233. if (this._pickedDownSprite && this._pickedDownSprite.actionManager && this._pickedDownSprite !== pickResult.pickedSprite) {
  1234. this._pickedDownSprite.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNewFromSprite(this._pickedDownSprite, this, evt));
  1235. }
  1236. }
  1237. this._previousPickResult = this._currentPickResult;
  1238. }).bind(this));
  1239. };
  1240. this._onKeyDown = (evt: Event) => {
  1241. if (this.actionManager) {
  1242. this.actionManager.processTrigger(ActionManager.OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
  1243. }
  1244. };
  1245. this._onKeyUp = (evt: Event) => {
  1246. if (this.actionManager) {
  1247. this.actionManager.processTrigger(ActionManager.OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
  1248. }
  1249. };
  1250. var eventPrefix = Tools.GetPointerPrefix();
  1251. var canvas = this._engine.getRenderingCanvas();
  1252. if (attachMove) {
  1253. canvas.addEventListener(eventPrefix + "move", this._onPointerMove, false);
  1254. // Wheel
  1255. canvas.addEventListener('mousewheel', this._onPointerMove, false);
  1256. canvas.addEventListener('DOMMouseScroll', this._onPointerMove, false);
  1257. }
  1258. if (attachDown) {
  1259. canvas.addEventListener(eventPrefix + "down", this._onPointerDown, false);
  1260. }
  1261. if (attachUp) {
  1262. canvas.addEventListener(eventPrefix + "up", this._onPointerUp, false);
  1263. }
  1264. canvas.tabIndex = 1;
  1265. canvas.addEventListener("keydown", this._onKeyDown, false);
  1266. canvas.addEventListener("keyup", this._onKeyUp, false);
  1267. }
  1268. public detachControl() {
  1269. var eventPrefix = Tools.GetPointerPrefix();
  1270. var canvas = this._engine.getRenderingCanvas();
  1271. canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
  1272. canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
  1273. canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
  1274. // Wheel
  1275. canvas.removeEventListener('mousewheel', this._onPointerMove);
  1276. canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
  1277. canvas.removeEventListener("keydown", this._onKeyDown);
  1278. canvas.removeEventListener("keyup", this._onKeyUp);
  1279. }
  1280. // Ready
  1281. public isReady(): boolean {
  1282. if (this._pendingData.length > 0) {
  1283. return false;
  1284. }
  1285. var index: number;
  1286. // Geometries
  1287. for (index = 0; index < this._geometries.length; index++) {
  1288. var geometry = this._geometries[index];
  1289. if (geometry.delayLoadState === Engine.DELAYLOADSTATE_LOADING) {
  1290. return false;
  1291. }
  1292. }
  1293. // Meshes
  1294. for (index = 0; index < this.meshes.length; index++) {
  1295. var mesh = this.meshes[index];
  1296. if (!mesh.isEnabled()) {
  1297. continue;
  1298. }
  1299. if (!mesh.subMeshes || mesh.subMeshes.length === 0) {
  1300. continue;
  1301. }
  1302. if (!mesh.isReady()) {
  1303. return false;
  1304. }
  1305. var mat = mesh.material;
  1306. if (mat) {
  1307. if (!mat.isReady(mesh)) {
  1308. return false;
  1309. }
  1310. }
  1311. }
  1312. return true;
  1313. }
  1314. public resetCachedMaterial(): void {
  1315. this._cachedMaterial = null;
  1316. this._cachedEffect = null;
  1317. this._cachedVisibility = null;
  1318. }
  1319. public registerBeforeRender(func: () => void): void {
  1320. this.onBeforeRenderObservable.add(func);
  1321. }
  1322. public unregisterBeforeRender(func: () => void): void {
  1323. this.onBeforeRenderObservable.removeCallback(func);
  1324. }
  1325. public registerAfterRender(func: () => void): void {
  1326. this.onAfterRenderObservable.add(func);
  1327. }
  1328. public unregisterAfterRender(func: () => void): void {
  1329. this.onAfterRenderObservable.removeCallback(func);
  1330. }
  1331. public _addPendingData(data): void {
  1332. this._pendingData.push(data);
  1333. }
  1334. public _removePendingData(data): void {
  1335. var index = this._pendingData.indexOf(data);
  1336. if (index !== -1) {
  1337. this._pendingData.splice(index, 1);
  1338. }
  1339. }
  1340. public getWaitingItemsCount(): number {
  1341. return this._pendingData.length;
  1342. }
  1343. /**
  1344. * Registers a function to be executed when the scene is ready.
  1345. * @param {Function} func - the function to be executed.
  1346. */
  1347. public executeWhenReady(func: () => void): void {
  1348. this.onReadyObservable.add(func);
  1349. if (this._executeWhenReadyTimeoutId !== -1) {
  1350. return;
  1351. }
  1352. this._executeWhenReadyTimeoutId = setTimeout(() => {
  1353. this._checkIsReady();
  1354. }, 150);
  1355. }
  1356. public _checkIsReady() {
  1357. if (this.isReady()) {
  1358. this.onReadyObservable.notifyObservers(this);
  1359. this.onReadyObservable.clear();
  1360. this._executeWhenReadyTimeoutId = -1;
  1361. return;
  1362. }
  1363. this._executeWhenReadyTimeoutId = setTimeout(() => {
  1364. this._checkIsReady();
  1365. }, 150);
  1366. }
  1367. // Animations
  1368. /**
  1369. * Will start the animation sequence of a given target
  1370. * @param target - the target
  1371. * @param {number} from - from which frame should animation start
  1372. * @param {number} to - till which frame should animation run.
  1373. * @param {boolean} [loop] - should the animation loop
  1374. * @param {number} [speedRatio] - the speed in which to run the animation
  1375. * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
  1376. * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
  1377. * @return {BABYLON.Animatable} the animatable object created for this animation
  1378. * @see BABYLON.Animatable
  1379. * @see http://doc.babylonjs.com/page.php?p=22081
  1380. */
  1381. public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable): Animatable {
  1382. if(from > to && speedRatio > 0){
  1383. speedRatio *= -1;
  1384. }
  1385. this.stopAnimation(target);
  1386. if (!animatable) {
  1387. animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
  1388. }
  1389. // Local animations
  1390. if (target.animations) {
  1391. animatable.appendAnimations(target, target.animations);
  1392. }
  1393. // Children animations
  1394. if (target.getAnimatables) {
  1395. var animatables = target.getAnimatables();
  1396. for (var index = 0; index < animatables.length; index++) {
  1397. this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
  1398. }
  1399. }
  1400. animatable.reset();
  1401. return animatable;
  1402. }
  1403. public beginDirectAnimation(target: any, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): Animatable {
  1404. if (speedRatio === undefined) {
  1405. speedRatio = 1.0;
  1406. }
  1407. var animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations);
  1408. return animatable;
  1409. }
  1410. public getAnimatableByTarget(target: any): Animatable {
  1411. for (var index = 0; index < this._activeAnimatables.length; index++) {
  1412. if (this._activeAnimatables[index].target === target) {
  1413. return this._activeAnimatables[index];
  1414. }
  1415. }
  1416. return null;
  1417. }
  1418. public get Animatables(): Animatable[] {
  1419. return this._activeAnimatables;
  1420. }
  1421. /**
  1422. * Will stop the animation of the given target
  1423. * @param target - the target
  1424. * @param animationName - the name of the animation to stop (all animations will be stopped is empty)
  1425. * @see beginAnimation
  1426. */
  1427. public stopAnimation(target: any, animationName?: string): void {
  1428. var animatable = this.getAnimatableByTarget(target);
  1429. if (animatable) {
  1430. animatable.stop(animationName);
  1431. }
  1432. }
  1433. private _animate(): void {
  1434. if (!this.animationsEnabled || this._activeAnimatables.length === 0) {
  1435. return;
  1436. }
  1437. // Getting time
  1438. var now = Tools.Now;
  1439. if (!this._animationTimeLast) {
  1440. if (this._pendingData.length > 0) {
  1441. return;
  1442. }
  1443. this._animationTimeLast = now;
  1444. }
  1445. var deltaTime = (now - this._animationTimeLast) * this.animationTimeScale;
  1446. this._animationTime += deltaTime;
  1447. this._animationTimeLast = now;
  1448. for (var index = 0; index < this._activeAnimatables.length; index++) {
  1449. this._activeAnimatables[index]._animate(this._animationTime);
  1450. }
  1451. }
  1452. // Matrix
  1453. public getViewMatrix(): Matrix {
  1454. return this._viewMatrix;
  1455. }
  1456. public getProjectionMatrix(): Matrix {
  1457. return this._projectionMatrix;
  1458. }
  1459. public getTransformMatrix(): Matrix {
  1460. return this._transformMatrix;
  1461. }
  1462. public setTransformMatrix(view: Matrix, projection: Matrix): void {
  1463. if (this._viewUpdateFlag === view.updateFlag && this._projectionUpdateFlag === projection.updateFlag) {
  1464. return;
  1465. }
  1466. this._viewUpdateFlag = view.updateFlag;
  1467. this._projectionUpdateFlag = projection.updateFlag;
  1468. this._viewMatrix = view;
  1469. this._projectionMatrix = projection;
  1470. this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
  1471. // Update frustum
  1472. if (!this._frustumPlanes) {
  1473. this._frustumPlanes = Frustum.GetPlanes(this._transformMatrix);
  1474. } else {
  1475. Frustum.GetPlanesToRef(this._transformMatrix, this._frustumPlanes);
  1476. }
  1477. if (this._sceneUbo.useUbo) {
  1478. this._sceneUbo.updateMatrix("viewProjection", this._transformMatrix);
  1479. this._sceneUbo.updateMatrix("view", this._viewMatrix);
  1480. this._sceneUbo.update();
  1481. }
  1482. }
  1483. public getSceneUniformBuffer(): UniformBuffer {
  1484. return this._sceneUbo;
  1485. }
  1486. // Methods
  1487. public getUniqueId() {
  1488. var result = this._uniqueIdCounter;
  1489. this._uniqueIdCounter++;
  1490. return result;
  1491. }
  1492. public addMesh(newMesh: AbstractMesh) {
  1493. newMesh.uniqueId = this.getUniqueId();
  1494. var position = this.meshes.push(newMesh);
  1495. //notify the collision coordinator
  1496. if (this.collisionCoordinator) {
  1497. this.collisionCoordinator.onMeshAdded(newMesh);
  1498. }
  1499. this.onNewMeshAddedObservable.notifyObservers(newMesh);
  1500. }
  1501. public removeMesh(toRemove: AbstractMesh): number {
  1502. var index = this.meshes.indexOf(toRemove);
  1503. if (index !== -1) {
  1504. // Remove from the scene if mesh found
  1505. this.meshes.splice(index, 1);
  1506. }
  1507. //notify the collision coordinator
  1508. if (this.collisionCoordinator) {
  1509. this.collisionCoordinator.onMeshRemoved(toRemove);
  1510. }
  1511. this.onMeshRemovedObservable.notifyObservers(toRemove);
  1512. return index;
  1513. }
  1514. public removeSkeleton(toRemove: Skeleton): number {
  1515. var index = this.skeletons.indexOf(toRemove);
  1516. if (index !== -1) {
  1517. // Remove from the scene if found
  1518. this.skeletons.splice(index, 1);
  1519. }
  1520. return index;
  1521. }
  1522. public removeMorphTargetManager(toRemove: MorphTargetManager): number {
  1523. var index = this.morphTargetManagers.indexOf(toRemove);
  1524. if (index !== -1) {
  1525. // Remove from the scene if found
  1526. this.morphTargetManagers.splice(index, 1);
  1527. }
  1528. return index;
  1529. }
  1530. public removeLight(toRemove: Light): number {
  1531. var index = this.lights.indexOf(toRemove);
  1532. if (index !== -1) {
  1533. // Remove from the scene if mesh found
  1534. this.lights.splice(index, 1);
  1535. this.sortLightsByPriority();
  1536. }
  1537. this.onLightRemovedObservable.notifyObservers(toRemove);
  1538. return index;
  1539. }
  1540. public removeCamera(toRemove: Camera): number {
  1541. var index = this.cameras.indexOf(toRemove);
  1542. if (index !== -1) {
  1543. // Remove from the scene if mesh found
  1544. this.cameras.splice(index, 1);
  1545. }
  1546. // Remove from activeCameras
  1547. var index2 = this.activeCameras.indexOf(toRemove);
  1548. if (index2 !== -1) {
  1549. // Remove from the scene if mesh found
  1550. this.activeCameras.splice(index2, 1);
  1551. }
  1552. // Reset the activeCamera
  1553. if (this.activeCamera === toRemove) {
  1554. if (this.cameras.length > 0) {
  1555. this.activeCamera = this.cameras[0];
  1556. } else {
  1557. this.activeCamera = null;
  1558. }
  1559. }
  1560. this.onCameraRemovedObservable.notifyObservers(toRemove);
  1561. return index;
  1562. }
  1563. public addLight(newLight: Light) {
  1564. newLight.uniqueId = this.getUniqueId();
  1565. this.lights.push(newLight);
  1566. this.sortLightsByPriority();
  1567. this.onNewLightAddedObservable.notifyObservers(newLight);
  1568. }
  1569. public sortLightsByPriority(): void {
  1570. if(this.requireLightSorting) {
  1571. this.lights.sort(Light.compareLightsPriority);
  1572. }
  1573. }
  1574. public addCamera(newCamera: Camera) {
  1575. newCamera.uniqueId = this.getUniqueId();
  1576. var position = this.cameras.push(newCamera);
  1577. this.onNewCameraAddedObservable.notifyObservers(newCamera);
  1578. }
  1579. /**
  1580. * Switch active camera
  1581. * @param {Camera} newCamera - new active camera
  1582. * @param {boolean} attachControl - call attachControl for the new active camera (default: true)
  1583. */
  1584. public switchActiveCamera(newCamera: Camera, attachControl = true) {
  1585. var canvas = this._engine.getRenderingCanvas();
  1586. this.activeCamera.detachControl(canvas);
  1587. this.activeCamera = newCamera;
  1588. if (attachControl) {
  1589. newCamera.attachControl(canvas);
  1590. }
  1591. }
  1592. /**
  1593. * sets the active camera of the scene using its ID
  1594. * @param {string} id - the camera's ID
  1595. * @return {BABYLON.Camera|null} the new active camera or null if none found.
  1596. * @see activeCamera
  1597. */
  1598. public setActiveCameraByID(id: string): Camera {
  1599. var camera = this.getCameraByID(id);
  1600. if (camera) {
  1601. this.activeCamera = camera;
  1602. return camera;
  1603. }
  1604. return null;
  1605. }
  1606. /**
  1607. * sets the active camera of the scene using its name
  1608. * @param {string} name - the camera's name
  1609. * @return {BABYLON.Camera|null} the new active camera or null if none found.
  1610. * @see activeCamera
  1611. */
  1612. public setActiveCameraByName(name: string): Camera {
  1613. var camera = this.getCameraByName(name);
  1614. if (camera) {
  1615. this.activeCamera = camera;
  1616. return camera;
  1617. }
  1618. return null;
  1619. }
  1620. /**
  1621. * get a material using its id
  1622. * @param {string} the material's ID
  1623. * @return {BABYLON.Material|null} the material or null if none found.
  1624. */
  1625. public getMaterialByID(id: string): Material {
  1626. for (var index = 0; index < this.materials.length; index++) {
  1627. if (this.materials[index].id === id) {
  1628. return this.materials[index];
  1629. }
  1630. }
  1631. return null;
  1632. }
  1633. /**
  1634. * get a material using its name
  1635. * @param {string} the material's name
  1636. * @return {BABYLON.Material|null} the material or null if none found.
  1637. */
  1638. public getMaterialByName(name: string): Material {
  1639. for (var index = 0; index < this.materials.length; index++) {
  1640. if (this.materials[index].name === name) {
  1641. return this.materials[index];
  1642. }
  1643. }
  1644. return null;
  1645. }
  1646. public getLensFlareSystemByName(name: string): LensFlareSystem {
  1647. for (var index = 0; index < this.lensFlareSystems.length; index++) {
  1648. if (this.lensFlareSystems[index].name === name) {
  1649. return this.lensFlareSystems[index];
  1650. }
  1651. }
  1652. return null;
  1653. }
  1654. public getLensFlareSystemByID(id: string): LensFlareSystem {
  1655. for (var index = 0; index < this.lensFlareSystems.length; index++) {
  1656. if (this.lensFlareSystems[index].id === id) {
  1657. return this.lensFlareSystems[index];
  1658. }
  1659. }
  1660. return null;
  1661. }
  1662. public getCameraByID(id: string): Camera {
  1663. for (var index = 0; index < this.cameras.length; index++) {
  1664. if (this.cameras[index].id === id) {
  1665. return this.cameras[index];
  1666. }
  1667. }
  1668. return null;
  1669. }
  1670. public getCameraByUniqueID(uniqueId: number): Camera {
  1671. for (var index = 0; index < this.cameras.length; index++) {
  1672. if (this.cameras[index].uniqueId === uniqueId) {
  1673. return this.cameras[index];
  1674. }
  1675. }
  1676. return null;
  1677. }
  1678. /**
  1679. * get a camera using its name
  1680. * @param {string} the camera's name
  1681. * @return {BABYLON.Camera|null} the camera or null if none found.
  1682. */
  1683. public getCameraByName(name: string): Camera {
  1684. for (var index = 0; index < this.cameras.length; index++) {
  1685. if (this.cameras[index].name === name) {
  1686. return this.cameras[index];
  1687. }
  1688. }
  1689. return null;
  1690. }
  1691. /**
  1692. * get a bone using its id
  1693. * @param {string} the bone's id
  1694. * @return {BABYLON.Bone|null} the bone or null if not found
  1695. */
  1696. public getBoneByID(id: string): Bone {
  1697. for (var skeletonIndex = 0; skeletonIndex < this.skeletons.length; skeletonIndex++) {
  1698. var skeleton = this.skeletons[skeletonIndex];
  1699. for (var boneIndex = 0; boneIndex < skeleton.bones.length; boneIndex++) {
  1700. if (skeleton.bones[boneIndex].id === id) {
  1701. return skeleton.bones[boneIndex];
  1702. }
  1703. }
  1704. }
  1705. return null;
  1706. }
  1707. /**
  1708. * get a bone using its id
  1709. * @param {string} the bone's name
  1710. * @return {BABYLON.Bone|null} the bone or null if not found
  1711. */
  1712. public getBoneByName(name: string): Bone {
  1713. for (var skeletonIndex = 0; skeletonIndex < this.skeletons.length; skeletonIndex++) {
  1714. var skeleton = this.skeletons[skeletonIndex];
  1715. for (var boneIndex = 0; boneIndex < skeleton.bones.length; boneIndex++) {
  1716. if (skeleton.bones[boneIndex].name === name) {
  1717. return skeleton.bones[boneIndex];
  1718. }
  1719. }
  1720. }
  1721. return null;
  1722. }
  1723. /**
  1724. * get a light node using its name
  1725. * @param {string} the light's name
  1726. * @return {BABYLON.Light|null} the light or null if none found.
  1727. */
  1728. public getLightByName(name: string): Light {
  1729. for (var index = 0; index < this.lights.length; index++) {
  1730. if (this.lights[index].name === name) {
  1731. return this.lights[index];
  1732. }
  1733. }
  1734. return null;
  1735. }
  1736. /**
  1737. * get a light node using its ID
  1738. * @param {string} the light's id
  1739. * @return {BABYLON.Light|null} the light or null if none found.
  1740. */
  1741. public getLightByID(id: string): Light {
  1742. for (var index = 0; index < this.lights.length; index++) {
  1743. if (this.lights[index].id === id) {
  1744. return this.lights[index];
  1745. }
  1746. }
  1747. return null;
  1748. }
  1749. /**
  1750. * get a light node using its scene-generated unique ID
  1751. * @param {number} the light's unique id
  1752. * @return {BABYLON.Light|null} the light or null if none found.
  1753. */
  1754. public getLightByUniqueID(uniqueId: number): Light {
  1755. for (var index = 0; index < this.lights.length; index++) {
  1756. if (this.lights[index].uniqueId === uniqueId) {
  1757. return this.lights[index];
  1758. }
  1759. }
  1760. return null;
  1761. }
  1762. /**
  1763. * get a particle system by id
  1764. * @param id {number} the particle system id
  1765. * @return {BABYLON.ParticleSystem|null} the corresponding system or null if none found.
  1766. */
  1767. public getParticleSystemByID(id: string): ParticleSystem {
  1768. for (var index = 0; index < this.particleSystems.length; index++) {
  1769. if (this.particleSystems[index].id === id) {
  1770. return this.particleSystems[index];
  1771. }
  1772. }
  1773. return null;
  1774. }
  1775. /**
  1776. * get a geometry using its ID
  1777. * @param {string} the geometry's id
  1778. * @return {BABYLON.Geometry|null} the geometry or null if none found.
  1779. */
  1780. public getGeometryByID(id: string): Geometry {
  1781. for (var index = 0; index < this._geometries.length; index++) {
  1782. if (this._geometries[index].id === id) {
  1783. return this._geometries[index];
  1784. }
  1785. }
  1786. return null;
  1787. }
  1788. /**
  1789. * add a new geometry to this scene.
  1790. * @param {BABYLON.Geometry} geometry - the geometry to be added to the scene.
  1791. * @param {boolean} [force] - force addition, even if a geometry with this ID already exists
  1792. * @return {boolean} was the geometry added or not
  1793. */
  1794. public pushGeometry(geometry: Geometry, force?: boolean): boolean {
  1795. if (!force && this.getGeometryByID(geometry.id)) {
  1796. return false;
  1797. }
  1798. this._geometries.push(geometry);
  1799. //notify the collision coordinator
  1800. if (this.collisionCoordinator) {
  1801. this.collisionCoordinator.onGeometryAdded(geometry);
  1802. }
  1803. this.onNewGeometryAddedObservable.notifyObservers(geometry);
  1804. return true;
  1805. }
  1806. /**
  1807. * Removes an existing geometry
  1808. * @param {BABYLON.Geometry} geometry - the geometry to be removed from the scene.
  1809. * @return {boolean} was the geometry removed or not
  1810. */
  1811. public removeGeometry(geometry: Geometry): boolean {
  1812. var index = this._geometries.indexOf(geometry);
  1813. if (index > -1) {
  1814. this._geometries.splice(index, 1);
  1815. //notify the collision coordinator
  1816. if (this.collisionCoordinator) {
  1817. this.collisionCoordinator.onGeometryDeleted(geometry);
  1818. }
  1819. this.onGeometryRemovedObservable.notifyObservers(geometry);
  1820. return true;
  1821. }
  1822. return false;
  1823. }
  1824. public getGeometries(): Geometry[] {
  1825. return this._geometries;
  1826. }
  1827. /**
  1828. * Get the first added mesh found of a given ID
  1829. * @param {string} id - the id to search for
  1830. * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all.
  1831. */
  1832. public getMeshByID(id: string): AbstractMesh {
  1833. for (var index = 0; index < this.meshes.length; index++) {
  1834. if (this.meshes[index].id === id) {
  1835. return this.meshes[index];
  1836. }
  1837. }
  1838. return null;
  1839. }
  1840. public getMeshesByID(id: string): Array<AbstractMesh> {
  1841. return this.meshes.filter(function (m) {
  1842. return m.id === id;
  1843. })
  1844. }
  1845. /**
  1846. * Get a mesh with its auto-generated unique id
  1847. * @param {number} uniqueId - the unique id to search for
  1848. * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all.
  1849. */
  1850. public getMeshByUniqueID(uniqueId: number): AbstractMesh {
  1851. for (var index = 0; index < this.meshes.length; index++) {
  1852. if (this.meshes[index].uniqueId === uniqueId) {
  1853. return this.meshes[index];
  1854. }
  1855. }
  1856. return null;
  1857. }
  1858. /**
  1859. * Get a the last added mesh found of a given ID
  1860. * @param {string} id - the id to search for
  1861. * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all.
  1862. */
  1863. public getLastMeshByID(id: string): AbstractMesh {
  1864. for (var index = this.meshes.length - 1; index >= 0; index--) {
  1865. if (this.meshes[index].id === id) {
  1866. return this.meshes[index];
  1867. }
  1868. }
  1869. return null;
  1870. }
  1871. /**
  1872. * Get a the last added node (Mesh, Camera, Light) found of a given ID
  1873. * @param {string} id - the id to search for
  1874. * @return {BABYLON.Node|null} the node found or null if not found at all.
  1875. */
  1876. public getLastEntryByID(id: string): Node {
  1877. var index: number;
  1878. for (index = this.meshes.length - 1; index >= 0; index--) {
  1879. if (this.meshes[index].id === id) {
  1880. return this.meshes[index];
  1881. }
  1882. }
  1883. for (index = this.cameras.length - 1; index >= 0; index--) {
  1884. if (this.cameras[index].id === id) {
  1885. return this.cameras[index];
  1886. }
  1887. }
  1888. for (index = this.lights.length - 1; index >= 0; index--) {
  1889. if (this.lights[index].id === id) {
  1890. return this.lights[index];
  1891. }
  1892. }
  1893. return null;
  1894. }
  1895. public getNodeByID(id: string): Node {
  1896. var mesh = this.getMeshByID(id);
  1897. if (mesh) {
  1898. return mesh;
  1899. }
  1900. var light = this.getLightByID(id);
  1901. if (light) {
  1902. return light;
  1903. }
  1904. var camera = this.getCameraByID(id);
  1905. if (camera) {
  1906. return camera;
  1907. }
  1908. var bone = this.getBoneByID(id);
  1909. return bone;
  1910. }
  1911. public getNodeByName(name: string): Node {
  1912. var mesh = this.getMeshByName(name);
  1913. if (mesh) {
  1914. return mesh;
  1915. }
  1916. var light = this.getLightByName(name);
  1917. if (light) {
  1918. return light;
  1919. }
  1920. var camera = this.getCameraByName(name);
  1921. if (camera) {
  1922. return camera;
  1923. }
  1924. var bone = this.getBoneByName(name);
  1925. return bone;
  1926. }
  1927. public getMeshByName(name: string): AbstractMesh {
  1928. for (var index = 0; index < this.meshes.length; index++) {
  1929. if (this.meshes[index].name === name) {
  1930. return this.meshes[index];
  1931. }
  1932. }
  1933. return null;
  1934. }
  1935. public getSoundByName(name: string): Sound {
  1936. var index: number;
  1937. if (AudioEngine) {
  1938. for (index = 0; index < this.mainSoundTrack.soundCollection.length; index++) {
  1939. if (this.mainSoundTrack.soundCollection[index].name === name) {
  1940. return this.mainSoundTrack.soundCollection[index];
  1941. }
  1942. }
  1943. for (var sdIndex = 0; sdIndex < this.soundTracks.length; sdIndex++) {
  1944. for (index = 0; index < this.soundTracks[sdIndex].soundCollection.length; index++) {
  1945. if (this.soundTracks[sdIndex].soundCollection[index].name === name) {
  1946. return this.soundTracks[sdIndex].soundCollection[index];
  1947. }
  1948. }
  1949. }
  1950. }
  1951. return null;
  1952. }
  1953. public getLastSkeletonByID(id: string): Skeleton {
  1954. for (var index = this.skeletons.length - 1; index >= 0; index--) {
  1955. if (this.skeletons[index].id === id) {
  1956. return this.skeletons[index];
  1957. }
  1958. }
  1959. return null;
  1960. }
  1961. public getSkeletonById(id: string): Skeleton {
  1962. for (var index = 0; index < this.skeletons.length; index++) {
  1963. if (this.skeletons[index].id === id) {
  1964. return this.skeletons[index];
  1965. }
  1966. }
  1967. return null;
  1968. }
  1969. public getSkeletonByName(name: string): Skeleton {
  1970. for (var index = 0; index < this.skeletons.length; index++) {
  1971. if (this.skeletons[index].name === name) {
  1972. return this.skeletons[index];
  1973. }
  1974. }
  1975. return null;
  1976. }
  1977. public getMorphTargetManagerById(id: number): MorphTargetManager {
  1978. for (var index = 0; index < this.morphTargetManagers.length; index++) {
  1979. if (this.morphTargetManagers[index].uniqueId === id) {
  1980. return this.morphTargetManagers[index];
  1981. }
  1982. }
  1983. return null;
  1984. }
  1985. public isActiveMesh(mesh: Mesh): boolean {
  1986. return (this._activeMeshes.indexOf(mesh) !== -1);
  1987. }
  1988. /**
  1989. * Return a the first highlight layer of the scene with a given name.
  1990. * @param name The name of the highlight layer to look for.
  1991. * @return The highlight layer if found otherwise null.
  1992. */
  1993. public getHighlightLayerByName(name: string): HighlightLayer {
  1994. for (var index = 0; index < this.highlightLayers.length; index++) {
  1995. if (this.highlightLayers[index].name === name) {
  1996. return this.highlightLayers[index];
  1997. }
  1998. }
  1999. return null;
  2000. }
  2001. /**
  2002. * Return a unique id as a string which can serve as an identifier for the scene
  2003. */
  2004. public get uid(): string {
  2005. if (!this._uid) {
  2006. this._uid = Tools.RandomId();
  2007. }
  2008. return this._uid;
  2009. }
  2010. /**
  2011. * Add an externaly attached data from its key.
  2012. * This method call will fail and return false, if such key already exists.
  2013. * If you don't care and just want to get the data no matter what, use the more convenient getOrAddExternalDataWithFactory() method.
  2014. * @param key the unique key that identifies the data
  2015. * @param data the data object to associate to the key for this Engine instance
  2016. * @return true if no such key were already present and the data was added successfully, false otherwise
  2017. */
  2018. public addExternalData<T>(key: string, data: T): boolean {
  2019. if (!this._externalData) {
  2020. this._externalData = new StringDictionary<Object>();
  2021. }
  2022. return this._externalData.add(key, data);
  2023. }
  2024. /**
  2025. * Get an externaly attached data from its key
  2026. * @param key the unique key that identifies the data
  2027. * @return the associated data, if present (can be null), or undefined if not present
  2028. */
  2029. public getExternalData<T>(key: string): T {
  2030. if (!this._externalData) {
  2031. return null;
  2032. }
  2033. return <T>this._externalData.get(key);
  2034. }
  2035. /**
  2036. * Get an externaly attached data from its key, create it using a factory if it's not already present
  2037. * @param key the unique key that identifies the data
  2038. * @param factory the factory that will be called to create the instance if and only if it doesn't exists
  2039. * @return the associated data, can be null if the factory returned null.
  2040. */
  2041. public getOrAddExternalDataWithFactory<T>(key: string, factory: (k: string) => T): T {
  2042. if (!this._externalData) {
  2043. this._externalData = new StringDictionary<Object>();
  2044. }
  2045. return <T>this._externalData.getOrAddWithFactory(key, factory);
  2046. }
  2047. /**
  2048. * Remove an externaly attached data from the Engine instance
  2049. * @param key the unique key that identifies the data
  2050. * @return true if the data was successfully removed, false if it doesn't exist
  2051. */
  2052. public removeExternalData(key): boolean {
  2053. return this._externalData.remove(key);
  2054. }
  2055. private _evaluateSubMesh(subMesh: SubMesh, mesh: AbstractMesh): void {
  2056. if (mesh.alwaysSelectAsActiveMesh || mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
  2057. var material = subMesh.getMaterial();
  2058. if (mesh.showSubMeshesBoundingBox) {
  2059. this.getBoundingBoxRenderer().renderList.push(subMesh.getBoundingInfo().boundingBox);
  2060. }
  2061. if (material) {
  2062. // Render targets
  2063. if (material.getRenderTargetTextures) {
  2064. if (this._processedMaterials.indexOf(material) === -1) {
  2065. this._processedMaterials.push(material);
  2066. this._renderTargets.concatWithNoDuplicate(material.getRenderTargetTextures());
  2067. }
  2068. }
  2069. // Dispatch
  2070. this._activeIndices.addCount(subMesh.indexCount, false);
  2071. this._renderingManager.dispatch(subMesh);
  2072. }
  2073. }
  2074. }
  2075. public _isInIntermediateRendering(): boolean {
  2076. return this._intermediateRendering
  2077. }
  2078. private _evaluateActiveMeshes(): void {
  2079. this.activeCamera._activeMeshes.reset();
  2080. this._activeMeshes.reset();
  2081. this._renderingManager.reset();
  2082. this._processedMaterials.reset();
  2083. this._activeParticleSystems.reset();
  2084. this._activeSkeletons.reset();
  2085. this._softwareSkinnedMeshes.reset();
  2086. if (this._boundingBoxRenderer) {
  2087. this._boundingBoxRenderer.reset();
  2088. }
  2089. // Meshes
  2090. var meshes: AbstractMesh[];
  2091. var len: number;
  2092. if (this._selectionOctree) { // Octree
  2093. var selection = this._selectionOctree.select(this._frustumPlanes);
  2094. meshes = selection.data;
  2095. len = selection.length;
  2096. } else { // Full scene traversal
  2097. len = this.meshes.length;
  2098. meshes = this.meshes;
  2099. }
  2100. for (var meshIndex = 0; meshIndex < len; meshIndex++) {
  2101. var mesh = meshes[meshIndex];
  2102. if (mesh.isBlocked) {
  2103. continue;
  2104. }
  2105. this._totalVertices.addCount(mesh.getTotalVertices(), false);
  2106. if (!mesh.isReady() || !mesh.isEnabled()) {
  2107. continue;
  2108. }
  2109. mesh.computeWorldMatrix();
  2110. // Intersections
  2111. if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([ActionManager.OnIntersectionEnterTrigger, ActionManager.OnIntersectionExitTrigger])) {
  2112. this._meshesForIntersections.pushNoDuplicate(mesh);
  2113. }
  2114. // Switch to current LOD
  2115. var meshLOD = mesh.getLOD(this.activeCamera);
  2116. if (!meshLOD) {
  2117. continue;
  2118. }
  2119. mesh._preActivate();
  2120. if (mesh.alwaysSelectAsActiveMesh || mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && mesh.isInFrustum(this._frustumPlanes)) {
  2121. this._activeMeshes.push(mesh);
  2122. this.activeCamera._activeMeshes.push(mesh);
  2123. mesh._activate(this._renderId);
  2124. this._activeMesh(mesh, meshLOD);
  2125. }
  2126. }
  2127. // Particle systems
  2128. this._particlesDuration.beginMonitoring();
  2129. var beforeParticlesDate = Tools.Now;
  2130. if (this.particlesEnabled) {
  2131. Tools.StartPerformanceCounter("Particles", this.particleSystems.length > 0);
  2132. for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
  2133. var particleSystem = this.particleSystems[particleIndex];
  2134. if (!particleSystem.isStarted()) {
  2135. continue;
  2136. }
  2137. if (!particleSystem.emitter.position || (particleSystem.emitter && particleSystem.emitter.isEnabled())) {
  2138. this._activeParticleSystems.push(particleSystem);
  2139. particleSystem.animate();
  2140. this._renderingManager.dispatchParticles(particleSystem);
  2141. }
  2142. }
  2143. Tools.EndPerformanceCounter("Particles", this.particleSystems.length > 0);
  2144. }
  2145. this._particlesDuration.endMonitoring(false);
  2146. }
  2147. private _activeMesh(sourceMesh: AbstractMesh, mesh: AbstractMesh): void {
  2148. if (mesh.skeleton && this.skeletonsEnabled) {
  2149. if (this._activeSkeletons.pushNoDuplicate(mesh.skeleton)) {
  2150. mesh.skeleton.prepare();
  2151. }
  2152. if (!mesh.computeBonesUsingShaders) {
  2153. this._softwareSkinnedMeshes.pushNoDuplicate(mesh);
  2154. }
  2155. }
  2156. if (sourceMesh.showBoundingBox || this.forceShowBoundingBoxes) {
  2157. this.getBoundingBoxRenderer().renderList.push(sourceMesh.getBoundingInfo().boundingBox);
  2158. }
  2159. if (mesh && mesh.subMeshes) {
  2160. // Submeshes Octrees
  2161. var len: number;
  2162. var subMeshes: SubMesh[];
  2163. if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
  2164. var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
  2165. len = intersections.length;
  2166. subMeshes = intersections.data;
  2167. } else {
  2168. subMeshes = mesh.subMeshes;
  2169. len = subMeshes.length;
  2170. }
  2171. for (var subIndex = 0; subIndex < len; subIndex++) {
  2172. var subMesh = subMeshes[subIndex];
  2173. this._evaluateSubMesh(subMesh, mesh);
  2174. }
  2175. }
  2176. }
  2177. public updateTransformMatrix(force?: boolean): void {
  2178. this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(force));
  2179. }
  2180. private _renderForCamera(camera: Camera): void {
  2181. var engine = this._engine;
  2182. var startTime = Tools.Now;
  2183. this.activeCamera = camera;
  2184. if (!this.activeCamera)
  2185. throw new Error("Active camera not set");
  2186. Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
  2187. // Viewport
  2188. engine.setViewport(this.activeCamera.viewport);
  2189. // Camera
  2190. this.resetCachedMaterial();
  2191. this._renderId++;
  2192. this.updateTransformMatrix();
  2193. this.onBeforeCameraRenderObservable.notifyObservers(this.activeCamera);
  2194. // Meshes
  2195. this._evaluateActiveMeshesDuration.beginMonitoring();
  2196. Tools.StartPerformanceCounter("Active meshes evaluation");
  2197. this._evaluateActiveMeshes();
  2198. this._evaluateActiveMeshesDuration.endMonitoring(false);
  2199. Tools.EndPerformanceCounter("Active meshes evaluation");
  2200. // Software skinning
  2201. for (var softwareSkinnedMeshIndex = 0; softwareSkinnedMeshIndex < this._softwareSkinnedMeshes.length; softwareSkinnedMeshIndex++) {
  2202. var mesh = this._softwareSkinnedMeshes.data[softwareSkinnedMeshIndex];
  2203. mesh.applySkeleton(mesh.skeleton);
  2204. }
  2205. // Render targets
  2206. this._renderTargetsDuration.beginMonitoring();
  2207. var needsRestoreFrameBuffer = false;
  2208. var beforeRenderTargetDate = Tools.Now;
  2209. if (camera.customRenderTargets && camera.customRenderTargets.length > 0) {
  2210. this._renderTargets.concatWithNoDuplicate(camera.customRenderTargets);
  2211. }
  2212. if (this.renderTargetsEnabled && this._renderTargets.length > 0) {
  2213. this._intermediateRendering = true;
  2214. Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
  2215. for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
  2216. let renderTarget = this._renderTargets.data[renderIndex];
  2217. if (renderTarget._shouldRender()) {
  2218. this._renderId++;
  2219. var hasSpecialRenderTargetCamera = renderTarget.activeCamera && renderTarget.activeCamera !== this.activeCamera;
  2220. renderTarget.render(hasSpecialRenderTargetCamera, this.dumpNextRenderTargets);
  2221. }
  2222. }
  2223. Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0);
  2224. this._intermediateRendering = false;
  2225. this._renderId++;
  2226. needsRestoreFrameBuffer = true; // Restore back buffer
  2227. }
  2228. // Render HighlightLayer Texture
  2229. var stencilState = this._engine.getStencilBuffer();
  2230. var renderhighlights = false;
  2231. if (this.renderTargetsEnabled && this.highlightLayers && this.highlightLayers.length > 0) {
  2232. this._intermediateRendering = true;
  2233. for (let i = 0; i < this.highlightLayers.length; i++) {
  2234. let highlightLayer = this.highlightLayers[i];
  2235. if (highlightLayer.shouldRender() &&
  2236. (!highlightLayer.camera ||
  2237. (highlightLayer.camera.cameraRigMode === Camera.RIG_MODE_NONE && camera === highlightLayer.camera) ||
  2238. (highlightLayer.camera.cameraRigMode !== Camera.RIG_MODE_NONE && highlightLayer.camera._rigCameras.indexOf(camera) > -1))) {
  2239. renderhighlights = true;
  2240. let renderTarget = (<RenderTargetTexture>(<any>highlightLayer)._mainTexture);
  2241. if (renderTarget._shouldRender()) {
  2242. this._renderId++;
  2243. renderTarget.render(false, false);
  2244. needsRestoreFrameBuffer = true;
  2245. }
  2246. }
  2247. }
  2248. this._intermediateRendering = false;
  2249. this._renderId++;
  2250. }
  2251. if (needsRestoreFrameBuffer) {
  2252. engine.restoreDefaultFramebuffer(); // Restore back buffer
  2253. }
  2254. this._renderTargetsDuration.endMonitoring(false);
  2255. // Prepare Frame
  2256. this.postProcessManager._prepareFrame();
  2257. this._renderDuration.beginMonitoring();
  2258. // Backgrounds
  2259. var layerIndex;
  2260. var layer;
  2261. if (this.layers.length) {
  2262. engine.setDepthBuffer(false);
  2263. for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) {
  2264. layer = this.layers[layerIndex];
  2265. if (layer.isBackground && ((layer.layerMask & this.activeCamera.layerMask) !== 0)) {
  2266. layer.render();
  2267. }
  2268. }
  2269. engine.setDepthBuffer(true);
  2270. }
  2271. // Render
  2272. Tools.StartPerformanceCounter("Main render");
  2273. // Activate HighlightLayer stencil
  2274. if (renderhighlights) {
  2275. this._engine.setStencilBuffer(true);
  2276. }
  2277. this._renderingManager.render(null, null, true, true);
  2278. // Restore HighlightLayer stencil
  2279. if (renderhighlights) {
  2280. this._engine.setStencilBuffer(stencilState);
  2281. }
  2282. Tools.EndPerformanceCounter("Main render");
  2283. // Bounding boxes
  2284. if (this._boundingBoxRenderer) {
  2285. this._boundingBoxRenderer.render();
  2286. }
  2287. // Lens flares
  2288. if (this.lensFlaresEnabled) {
  2289. Tools.StartPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
  2290. for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
  2291. var lensFlareSystem = this.lensFlareSystems[lensFlareSystemIndex];
  2292. if ((camera.layerMask & lensFlareSystem.layerMask) !== 0) {
  2293. lensFlareSystem.render();
  2294. }
  2295. }
  2296. Tools.EndPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0);
  2297. }
  2298. // Foregrounds
  2299. if (this.layers.length) {
  2300. engine.setDepthBuffer(false);
  2301. for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) {
  2302. layer = this.layers[layerIndex];
  2303. if (!layer.isBackground && ((layer.layerMask & this.activeCamera.layerMask) !== 0)) {
  2304. layer.render();
  2305. }
  2306. }
  2307. engine.setDepthBuffer(true);
  2308. }
  2309. // Highlight Layer
  2310. if (renderhighlights) {
  2311. engine.setDepthBuffer(false);
  2312. for (let i = 0; i < this.highlightLayers.length; i++) {
  2313. if (this.highlightLayers[i].shouldRender()) {
  2314. this.highlightLayers[i].render();
  2315. }
  2316. }
  2317. engine.setDepthBuffer(true);
  2318. }
  2319. this._renderDuration.endMonitoring(false);
  2320. // Finalize frame
  2321. this.postProcessManager._finalizeFrame(camera.isIntermediate);
  2322. // Update camera
  2323. this.activeCamera._updateFromScene();
  2324. // Reset some special arrays
  2325. this._renderTargets.reset();
  2326. this.onAfterCameraRenderObservable.notifyObservers(this.activeCamera);
  2327. Tools.EndPerformanceCounter("Rendering camera " + this.activeCamera.name);
  2328. }
  2329. private _processSubCameras(camera: Camera): void {
  2330. if (camera.cameraRigMode === Camera.RIG_MODE_NONE) {
  2331. this._renderForCamera(camera);
  2332. return;
  2333. }
  2334. // rig cameras
  2335. for (var index = 0; index < camera._rigCameras.length; index++) {
  2336. this._renderForCamera(camera._rigCameras[index]);
  2337. }
  2338. this.activeCamera = camera;
  2339. this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
  2340. // Update camera
  2341. this.activeCamera._updateFromScene();
  2342. }
  2343. private _checkIntersections(): void {
  2344. for (var index = 0; index < this._meshesForIntersections.length; index++) {
  2345. var sourceMesh = this._meshesForIntersections.data[index];
  2346. for (var actionIndex = 0; actionIndex < sourceMesh.actionManager.actions.length; actionIndex++) {
  2347. var action = sourceMesh.actionManager.actions[actionIndex];
  2348. if (action.trigger === ActionManager.OnIntersectionEnterTrigger || action.trigger === ActionManager.OnIntersectionExitTrigger) {
  2349. var parameters = action.getTriggerParameter();
  2350. var otherMesh = parameters instanceof AbstractMesh ? parameters : parameters.mesh;
  2351. var areIntersecting = otherMesh.intersectsMesh(sourceMesh, parameters.usePreciseIntersection);
  2352. var currentIntersectionInProgress = sourceMesh._intersectionsInProgress.indexOf(otherMesh);
  2353. if (areIntersecting && currentIntersectionInProgress === -1) {
  2354. if (action.trigger === ActionManager.OnIntersectionEnterTrigger) {
  2355. action._executeCurrent(ActionEvent.CreateNew(sourceMesh, null, otherMesh));
  2356. sourceMesh._intersectionsInProgress.push(otherMesh);
  2357. } else if (action.trigger === ActionManager.OnIntersectionExitTrigger) {
  2358. sourceMesh._intersectionsInProgress.push(otherMesh);
  2359. }
  2360. } else if (!areIntersecting && currentIntersectionInProgress > -1) {
  2361. //They intersected, and now they don't.
  2362. //is this trigger an exit trigger? execute an event.
  2363. if (action.trigger === ActionManager.OnIntersectionExitTrigger) {
  2364. action._executeCurrent(ActionEvent.CreateNew(sourceMesh, null, otherMesh));
  2365. }
  2366. //if this is an exit trigger, or no exit trigger exists, remove the id from the intersection in progress array.
  2367. if (!sourceMesh.actionManager.hasSpecificTrigger(ActionManager.OnIntersectionExitTrigger) || action.trigger === ActionManager.OnIntersectionExitTrigger) {
  2368. sourceMesh._intersectionsInProgress.splice(currentIntersectionInProgress, 1);
  2369. }
  2370. }
  2371. }
  2372. }
  2373. }
  2374. }
  2375. public render(): void {
  2376. if (this.isDisposed) {
  2377. return;
  2378. }
  2379. this._lastFrameDuration.beginMonitoring();
  2380. this._particlesDuration.fetchNewFrame();
  2381. this._spritesDuration.fetchNewFrame();
  2382. this._activeParticles.fetchNewFrame();
  2383. this._renderDuration.fetchNewFrame();
  2384. this._renderTargetsDuration.fetchNewFrame();
  2385. this._evaluateActiveMeshesDuration.fetchNewFrame();
  2386. this._totalVertices.fetchNewFrame();
  2387. this._activeIndices.fetchNewFrame();
  2388. this._activeBones.fetchNewFrame();
  2389. this.getEngine().drawCallsPerfCounter.fetchNewFrame();
  2390. this._meshesForIntersections.reset();
  2391. this.resetCachedMaterial();
  2392. Tools.StartPerformanceCounter("Scene rendering");
  2393. // Actions
  2394. if (this.actionManager) {
  2395. this.actionManager.processTrigger(ActionManager.OnEveryFrameTrigger, null);
  2396. }
  2397. //Simplification Queue
  2398. if (this.simplificationQueue && !this.simplificationQueue.running) {
  2399. this.simplificationQueue.executeNext();
  2400. }
  2401. // Animations
  2402. var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
  2403. this._animationRatio = deltaTime * (60.0 / 1000.0);
  2404. this._animate();
  2405. // Physics
  2406. if (this._physicsEngine) {
  2407. Tools.StartPerformanceCounter("Physics");
  2408. this._physicsEngine._step(deltaTime / 1000.0);
  2409. Tools.EndPerformanceCounter("Physics");
  2410. }
  2411. // Before render
  2412. this.onBeforeRenderObservable.notifyObservers(this);
  2413. // Customs render targets
  2414. this._renderTargetsDuration.beginMonitoring();
  2415. var beforeRenderTargetDate = Tools.Now;
  2416. var engine = this.getEngine();
  2417. var currentActiveCamera = this.activeCamera;
  2418. if (this.renderTargetsEnabled) {
  2419. Tools.StartPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
  2420. for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
  2421. var renderTarget = this.customRenderTargets[customIndex];
  2422. if (renderTarget._shouldRender()) {
  2423. this._renderId++;
  2424. this.activeCamera = renderTarget.activeCamera || this.activeCamera;
  2425. if (!this.activeCamera)
  2426. throw new Error("Active camera not set");
  2427. // Viewport
  2428. engine.setViewport(this.activeCamera.viewport);
  2429. // Camera
  2430. this.updateTransformMatrix();
  2431. renderTarget.render(currentActiveCamera !== this.activeCamera, this.dumpNextRenderTargets);
  2432. }
  2433. }
  2434. Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0);
  2435. this._renderId++;
  2436. }
  2437. // Restore back buffer
  2438. if (this.customRenderTargets.length > 0) {
  2439. engine.restoreDefaultFramebuffer();
  2440. }
  2441. this._renderTargetsDuration.endMonitoring();
  2442. this.activeCamera = currentActiveCamera;
  2443. // Procedural textures
  2444. if (this.proceduralTexturesEnabled) {
  2445. Tools.StartPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
  2446. for (var proceduralIndex = 0; proceduralIndex < this._proceduralTextures.length; proceduralIndex++) {
  2447. var proceduralTexture = this._proceduralTextures[proceduralIndex];
  2448. if (proceduralTexture._shouldRender()) {
  2449. proceduralTexture.render();
  2450. }
  2451. }
  2452. Tools.EndPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0);
  2453. }
  2454. // Clear
  2455. if (this.autoClearDepthAndStencil || this.autoClear) {
  2456. this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe || this.forcePointsCloud, this.autoClearDepthAndStencil, this.autoClearDepthAndStencil);
  2457. }
  2458. // Shadows
  2459. if (this.shadowsEnabled) {
  2460. for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
  2461. var light = this.lights[lightIndex];
  2462. var shadowGenerator = light.getShadowGenerator();
  2463. if (light.isEnabled() && light.shadowEnabled && shadowGenerator) {
  2464. var shadowMap = shadowGenerator.getShadowMap();
  2465. if (shadowMap.getScene().textures.indexOf(shadowMap) !== -1) {
  2466. this._renderTargets.push(shadowMap);
  2467. }
  2468. }
  2469. }
  2470. }
  2471. // Depth renderer
  2472. if (this._depthRenderer) {
  2473. this._renderTargets.push(this._depthRenderer.getDepthMap());
  2474. }
  2475. // Geometry renderer
  2476. if (this._geometryBufferRenderer) {
  2477. this._renderTargets.push(this._geometryBufferRenderer.getGBuffer());
  2478. }
  2479. // RenderPipeline
  2480. if (this._postProcessRenderPipelineManager) {
  2481. this._postProcessRenderPipelineManager.update();
  2482. }
  2483. // Multi-cameras?
  2484. if (this.activeCameras.length > 0) {
  2485. for (var cameraIndex = 0; cameraIndex < this.activeCameras.length; cameraIndex++) {
  2486. if (cameraIndex > 0) {
  2487. this._engine.clear(null, false, true, true);
  2488. }
  2489. this._processSubCameras(this.activeCameras[cameraIndex]);
  2490. }
  2491. } else {
  2492. if (!this.activeCamera) {
  2493. throw new Error("No camera defined");
  2494. }
  2495. this._processSubCameras(this.activeCamera);
  2496. }
  2497. // Intersection checks
  2498. this._checkIntersections();
  2499. // Update the audio listener attached to the camera
  2500. if (AudioEngine) {
  2501. this._updateAudioParameters();
  2502. }
  2503. // After render
  2504. if (this.afterRender) {
  2505. this.afterRender();
  2506. }
  2507. this.onAfterRenderObservable.notifyObservers(this);
  2508. // Cleaning
  2509. for (var index = 0; index < this._toBeDisposed.length; index++) {
  2510. this._toBeDisposed.data[index].dispose();
  2511. this._toBeDisposed[index] = null;
  2512. }
  2513. this._toBeDisposed.reset();
  2514. if (this.dumpNextRenderTargets) {
  2515. this.dumpNextRenderTargets = false;
  2516. }
  2517. Tools.EndPerformanceCounter("Scene rendering");
  2518. this._lastFrameDuration.endMonitoring();
  2519. this._totalMeshesCounter.addCount(this.meshes.length, true);
  2520. this._totalLightsCounter.addCount(this.lights.length, true);
  2521. this._totalMaterialsCounter.addCount(this.materials.length, true);
  2522. this._totalTexturesCounter.addCount(this.textures.length, true);
  2523. this._activeBones.addCount(0, true);
  2524. this._activeIndices.addCount(0, true);
  2525. this._activeParticles.addCount(0, true);
  2526. }
  2527. private _updateAudioParameters() {
  2528. if (!this.audioEnabled || (this.mainSoundTrack.soundCollection.length === 0 && this.soundTracks.length === 1)) {
  2529. return;
  2530. }
  2531. var listeningCamera: Camera;
  2532. var audioEngine = Engine.audioEngine;
  2533. if (this.activeCameras.length > 0) {
  2534. listeningCamera = this.activeCameras[0];
  2535. } else {
  2536. listeningCamera = this.activeCamera;
  2537. }
  2538. if (listeningCamera && audioEngine.canUseWebAudio) {
  2539. audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z);
  2540. // for VR cameras
  2541. if (listeningCamera.rigCameras && listeningCamera.rigCameras.length > 0) {
  2542. listeningCamera = listeningCamera.rigCameras[0];
  2543. }
  2544. var mat = Matrix.Invert(listeningCamera.getViewMatrix());
  2545. var cameraDirection = Vector3.TransformNormal(new Vector3(0, 0, -1), mat);
  2546. cameraDirection.normalize();
  2547. audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
  2548. var i: number;
  2549. for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
  2550. var sound = this.mainSoundTrack.soundCollection[i];
  2551. if (sound.useCustomAttenuation) {
  2552. sound.updateDistanceFromListener();
  2553. }
  2554. }
  2555. for (i = 0; i < this.soundTracks.length; i++) {
  2556. for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
  2557. sound = this.soundTracks[i].soundCollection[j];
  2558. if (sound.useCustomAttenuation) {
  2559. sound.updateDistanceFromListener();
  2560. }
  2561. }
  2562. }
  2563. }
  2564. }
  2565. // Audio
  2566. public get audioEnabled(): boolean {
  2567. return this._audioEnabled;
  2568. }
  2569. public set audioEnabled(value: boolean) {
  2570. this._audioEnabled = value;
  2571. if (AudioEngine) {
  2572. if (this._audioEnabled) {
  2573. this._enableAudio();
  2574. }
  2575. else {
  2576. this._disableAudio();
  2577. }
  2578. }
  2579. }
  2580. private _disableAudio() {
  2581. var i: number;
  2582. for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
  2583. this.mainSoundTrack.soundCollection[i].pause();
  2584. }
  2585. for (i = 0; i < this.soundTracks.length; i++) {
  2586. for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
  2587. this.soundTracks[i].soundCollection[j].pause();
  2588. }
  2589. }
  2590. }
  2591. private _enableAudio() {
  2592. var i: number;
  2593. for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
  2594. if (this.mainSoundTrack.soundCollection[i].isPaused) {
  2595. this.mainSoundTrack.soundCollection[i].play();
  2596. }
  2597. }
  2598. for (i = 0; i < this.soundTracks.length; i++) {
  2599. for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
  2600. if (this.soundTracks[i].soundCollection[j].isPaused) {
  2601. this.soundTracks[i].soundCollection[j].play();
  2602. }
  2603. }
  2604. }
  2605. }
  2606. public get headphone(): boolean {
  2607. return this._headphone;
  2608. }
  2609. public set headphone(value: boolean) {
  2610. this._headphone = value;
  2611. if (AudioEngine) {
  2612. if (this._headphone) {
  2613. this._switchAudioModeForHeadphones();
  2614. }
  2615. else {
  2616. this._switchAudioModeForNormalSpeakers();
  2617. }
  2618. }
  2619. }
  2620. private _switchAudioModeForHeadphones() {
  2621. this.mainSoundTrack.switchPanningModelToHRTF();
  2622. for (var i = 0; i < this.soundTracks.length; i++) {
  2623. this.soundTracks[i].switchPanningModelToHRTF();
  2624. }
  2625. }
  2626. private _switchAudioModeForNormalSpeakers() {
  2627. this.mainSoundTrack.switchPanningModelToEqualPower();
  2628. for (var i = 0; i < this.soundTracks.length; i++) {
  2629. this.soundTracks[i].switchPanningModelToEqualPower();
  2630. }
  2631. }
  2632. public enableDepthRenderer(): DepthRenderer {
  2633. if (this._depthRenderer) {
  2634. return this._depthRenderer;
  2635. }
  2636. this._depthRenderer = new DepthRenderer(this);
  2637. return this._depthRenderer;
  2638. }
  2639. public disableDepthRenderer(): void {
  2640. if (!this._depthRenderer) {
  2641. return;
  2642. }
  2643. this._depthRenderer.dispose();
  2644. this._depthRenderer = null;
  2645. }
  2646. public enableGeometryBufferRenderer(ratio: number = 1): GeometryBufferRenderer {
  2647. if (this._geometryBufferRenderer) {
  2648. return this._geometryBufferRenderer;
  2649. }
  2650. this._geometryBufferRenderer = new GeometryBufferRenderer(this, ratio);
  2651. if (!this._geometryBufferRenderer.isSupported) {
  2652. this._geometryBufferRenderer = null;
  2653. }
  2654. return this._geometryBufferRenderer;
  2655. }
  2656. public disableGeometryBufferRenderer(): void {
  2657. if (!this._geometryBufferRenderer) {
  2658. return;
  2659. }
  2660. this._geometryBufferRenderer.dispose();
  2661. this._geometryBufferRenderer = null;
  2662. }
  2663. public freezeMaterials(): void {
  2664. for (var i = 0; i < this.materials.length; i++) {
  2665. this.materials[i].freeze();
  2666. }
  2667. }
  2668. public unfreezeMaterials(): void {
  2669. for (var i = 0; i < this.materials.length; i++) {
  2670. this.materials[i].unfreeze();
  2671. }
  2672. }
  2673. public dispose(): void {
  2674. this.beforeRender = null;
  2675. this.afterRender = null;
  2676. this.skeletons = [];
  2677. this.morphTargetManagers = [];
  2678. this.importedMeshesFiles = new Array<string>();
  2679. if (this._depthRenderer) {
  2680. this._depthRenderer.dispose();
  2681. }
  2682. // Smart arrays
  2683. if (this.activeCamera) {
  2684. this.activeCamera._activeMeshes.dispose();
  2685. this.activeCamera = null;
  2686. }
  2687. this._activeMeshes.dispose();
  2688. this._renderingManager.dispose();
  2689. this._processedMaterials.dispose();
  2690. this._activeParticleSystems.dispose();
  2691. this._activeSkeletons.dispose();
  2692. this._softwareSkinnedMeshes.dispose();
  2693. if (this._boundingBoxRenderer) {
  2694. this._boundingBoxRenderer.dispose();
  2695. }
  2696. this._meshesForIntersections.dispose();
  2697. this._toBeDisposed.dispose();
  2698. // Debug layer
  2699. if (this._debugLayer) {
  2700. this._debugLayer.hide();
  2701. }
  2702. // Events
  2703. this.onDisposeObservable.notifyObservers(this);
  2704. this.onDisposeObservable.clear();
  2705. this.onBeforeRenderObservable.clear();
  2706. this.onAfterRenderObservable.clear();
  2707. this.detachControl();
  2708. // Release sounds & sounds tracks
  2709. if (AudioEngine) {
  2710. this.disposeSounds();
  2711. }
  2712. // Detach cameras
  2713. var canvas = this._engine.getRenderingCanvas();
  2714. var index;
  2715. for (index = 0; index < this.cameras.length; index++) {
  2716. this.cameras[index].detachControl(canvas);
  2717. }
  2718. // Release lights
  2719. while (this.lights.length) {
  2720. this.lights[0].dispose();
  2721. }
  2722. // Release meshes
  2723. while (this.meshes.length) {
  2724. this.meshes[0].dispose(true);
  2725. }
  2726. // Release cameras
  2727. while (this.cameras.length) {
  2728. this.cameras[0].dispose();
  2729. }
  2730. // Release materials
  2731. while (this.materials.length) {
  2732. this.materials[0].dispose();
  2733. }
  2734. // Release particles
  2735. while (this.particleSystems.length) {
  2736. this.particleSystems[0].dispose();
  2737. }
  2738. // Release sprites
  2739. while (this.spriteManagers.length) {
  2740. this.spriteManagers[0].dispose();
  2741. }
  2742. // Release layers
  2743. while (this.layers.length) {
  2744. this.layers[0].dispose();
  2745. }
  2746. while (this.highlightLayers.length) {
  2747. this.highlightLayers[0].dispose();
  2748. }
  2749. // Release textures
  2750. while (this.textures.length) {
  2751. this.textures[0].dispose();
  2752. }
  2753. // Release UBO
  2754. this._sceneUbo.dispose();
  2755. // Post-processes
  2756. this.postProcessManager.dispose();
  2757. // Physics
  2758. if (this._physicsEngine) {
  2759. this.disablePhysicsEngine();
  2760. }
  2761. // Remove from engine
  2762. index = this._engine.scenes.indexOf(this);
  2763. if (index > -1) {
  2764. this._engine.scenes.splice(index, 1);
  2765. }
  2766. this._engine.wipeCaches();
  2767. this._engine = null;
  2768. }
  2769. public get isDisposed(): boolean {
  2770. return !this._engine;
  2771. }
  2772. // Release sounds & sounds tracks
  2773. public disposeSounds() {
  2774. this.mainSoundTrack.dispose();
  2775. for (var scIndex = 0; scIndex < this.soundTracks.length; scIndex++) {
  2776. this.soundTracks[scIndex].dispose();
  2777. }
  2778. }
  2779. // Octrees
  2780. public getWorldExtends(): { min: Vector3; max: Vector3 } {
  2781. var min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  2782. var max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  2783. for (var index = 0; index < this.meshes.length; index++) {
  2784. var mesh = this.meshes[index];
  2785. mesh.computeWorldMatrix(true);
  2786. var minBox = mesh.getBoundingInfo().boundingBox.minimumWorld;
  2787. var maxBox = mesh.getBoundingInfo().boundingBox.maximumWorld;
  2788. Tools.CheckExtends(minBox, min, max);
  2789. Tools.CheckExtends(maxBox, min, max);
  2790. }
  2791. return {
  2792. min: min,
  2793. max: max
  2794. };
  2795. }
  2796. public createOrUpdateSelectionOctree(maxCapacity = 64, maxDepth = 2): Octree<AbstractMesh> {
  2797. if (!this._selectionOctree) {
  2798. this._selectionOctree = new Octree<AbstractMesh>(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
  2799. }
  2800. var worldExtends = this.getWorldExtends();
  2801. // Update octree
  2802. this._selectionOctree.update(worldExtends.min, worldExtends.max, this.meshes);
  2803. return this._selectionOctree;
  2804. }
  2805. // Picking
  2806. public createPickingRay(x: number, y: number, world: Matrix, camera: Camera, cameraViewSpace = false): Ray {
  2807. var engine = this._engine;
  2808. if (!camera) {
  2809. if (!this.activeCamera)
  2810. throw new Error("Active camera not set");
  2811. camera = this.activeCamera;
  2812. }
  2813. var cameraViewport = camera.viewport;
  2814. var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
  2815. // Moving coordinates to local viewport world
  2816. x = x / this._engine.getHardwareScalingLevel() - viewport.x;
  2817. y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
  2818. return Ray.CreateNew(x, y, viewport.width, viewport.height, world ? world : Matrix.Identity(), cameraViewSpace ? Matrix.Identity() : camera.getViewMatrix(), camera.getProjectionMatrix());
  2819. // return BABYLON.Ray.CreateNew(x / window.devicePixelRatio, y / window.devicePixelRatio, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix());
  2820. }
  2821. public createPickingRayInCameraSpace(x: number, y: number, camera: Camera): Ray {
  2822. if (!BABYLON.PickingInfo) {
  2823. return null;
  2824. }
  2825. var engine = this._engine;
  2826. if (!camera) {
  2827. if (!this.activeCamera)
  2828. throw new Error("Active camera not set");
  2829. camera = this.activeCamera;
  2830. }
  2831. var cameraViewport = camera.viewport;
  2832. var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
  2833. var identity = Matrix.Identity();
  2834. // Moving coordinates to local viewport world
  2835. x = x / this._engine.getHardwareScalingLevel() - viewport.x;
  2836. y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
  2837. return Ray.CreateNew(x, y, viewport.width, viewport.height, identity, identity, camera.getProjectionMatrix());
  2838. }
  2839. private _internalPick(rayFunction: (world: Matrix) => Ray, predicate: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): PickingInfo {
  2840. if (!BABYLON.PickingInfo) {
  2841. return null;
  2842. }
  2843. var pickingInfo = null;
  2844. for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) {
  2845. var mesh = this.meshes[meshIndex];
  2846. if (predicate) {
  2847. if (!predicate(mesh)) {
  2848. continue;
  2849. }
  2850. } else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) {
  2851. continue;
  2852. }
  2853. var world = mesh.getWorldMatrix();
  2854. var ray = rayFunction(world);
  2855. var result = mesh.intersects(ray, fastCheck);
  2856. if (!result || !result.hit)
  2857. continue;
  2858. if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
  2859. continue;
  2860. pickingInfo = result;
  2861. if (fastCheck) {
  2862. break;
  2863. }
  2864. }
  2865. return pickingInfo || new PickingInfo();
  2866. }
  2867. private _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate: (mesh: AbstractMesh) => boolean): PickingInfo[] {
  2868. if (!BABYLON.PickingInfo) {
  2869. return null;
  2870. }
  2871. var pickingInfos = new Array<PickingInfo>();
  2872. for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) {
  2873. var mesh = this.meshes[meshIndex];
  2874. if (predicate) {
  2875. if (!predicate(mesh)) {
  2876. continue;
  2877. }
  2878. } else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) {
  2879. continue;
  2880. }
  2881. var world = mesh.getWorldMatrix();
  2882. var ray = rayFunction(world);
  2883. var result = mesh.intersects(ray, false);
  2884. if (!result || !result.hit)
  2885. continue;
  2886. pickingInfos.push(result);
  2887. }
  2888. return pickingInfos;
  2889. }
  2890. private _internalPickSprites(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
  2891. if (!BABYLON.PickingInfo) {
  2892. return null;
  2893. }
  2894. var pickingInfo = null;
  2895. camera = camera || this.activeCamera;
  2896. if (this.spriteManagers.length > 0) {
  2897. for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
  2898. var spriteManager = this.spriteManagers[spriteIndex];
  2899. if (!spriteManager.isPickable) {
  2900. continue;
  2901. }
  2902. var result = spriteManager.intersects(ray, camera, predicate, fastCheck);
  2903. if (!result || !result.hit)
  2904. continue;
  2905. if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
  2906. continue;
  2907. pickingInfo = result;
  2908. if (fastCheck) {
  2909. break;
  2910. }
  2911. }
  2912. }
  2913. return pickingInfo || new PickingInfo();
  2914. }
  2915. /// <summary>Launch a ray to try to pick a mesh in the scene</summary>
  2916. /// <param name="x">X position on screen</param>
  2917. /// <param name="y">Y position on screen</param>
  2918. /// <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>
  2919. /// <param name="fastCheck">Launch a fast check only using the bounding boxes. Can be set to null.</param>
  2920. /// <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>
  2921. public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
  2922. return this._internalPick(world => this.createPickingRay(x, y, world, camera), predicate, fastCheck);
  2923. }
  2924. /// <summary>Launch a ray to try to pick a mesh in the scene</summary>
  2925. /// <param name="x">X position on screen</param>
  2926. /// <param name="y">Y position on screen</param>
  2927. /// <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>
  2928. /// <param name="fastCheck">Launch a fast check only using the bounding boxes. Can be set to null.</param>
  2929. /// <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>
  2930. public pickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
  2931. return this._internalPickSprites(this.createPickingRayInCameraSpace(x, y, camera), predicate, fastCheck, camera);
  2932. }
  2933. public pickWithRay(ray: Ray, predicate: (mesh: Mesh) => boolean, fastCheck?: boolean): PickingInfo {
  2934. return this._internalPick(world => {
  2935. if (!this._pickWithRayInverseMatrix) {
  2936. this._pickWithRayInverseMatrix = Matrix.Identity();
  2937. }
  2938. world.invertToRef(this._pickWithRayInverseMatrix);
  2939. return Ray.Transform(ray, this._pickWithRayInverseMatrix);
  2940. }, predicate, fastCheck);
  2941. }
  2942. /// <summary>Launch a ray to try to pick a mesh in the scene</summary>
  2943. /// <param name="x">X position on screen</param>
  2944. /// <param name="y">Y position on screen</param>
  2945. /// <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>
  2946. /// <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>
  2947. public multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): PickingInfo[] {
  2948. return this._internalMultiPick(world => this.createPickingRay(x, y, world, camera), predicate);
  2949. }
  2950. /// <summary>Launch a ray to try to pick a mesh in the scene</summary>
  2951. /// <param name="ray">Ray to use</param>
  2952. /// <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>
  2953. public multiPickWithRay(ray: Ray, predicate: (mesh: Mesh) => boolean): PickingInfo[] {
  2954. return this._internalMultiPick(world => {
  2955. if (!this._pickWithRayInverseMatrix) {
  2956. this._pickWithRayInverseMatrix = Matrix.Identity();
  2957. }
  2958. world.invertToRef(this._pickWithRayInverseMatrix);
  2959. return Ray.Transform(ray, this._pickWithRayInverseMatrix);
  2960. }, predicate);
  2961. }
  2962. public setPointerOverMesh(mesh: AbstractMesh): void {
  2963. if (this._pointerOverMesh === mesh) {
  2964. return;
  2965. }
  2966. if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
  2967. this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
  2968. }
  2969. this._pointerOverMesh = mesh;
  2970. if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
  2971. this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
  2972. }
  2973. }
  2974. public getPointerOverMesh(): AbstractMesh {
  2975. return this._pointerOverMesh;
  2976. }
  2977. public setPointerOverSprite(sprite: Sprite): void {
  2978. if (this._pointerOverSprite === sprite) {
  2979. return;
  2980. }
  2981. if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
  2982. this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
  2983. }
  2984. this._pointerOverSprite = sprite;
  2985. if (this._pointerOverSprite && this._pointerOverSprite.actionManager) {
  2986. this._pointerOverSprite.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this));
  2987. }
  2988. }
  2989. public getPointerOverSprite(): Sprite {
  2990. return this._pointerOverSprite;
  2991. }
  2992. // Physics
  2993. public getPhysicsEngine(): PhysicsEngine {
  2994. return this._physicsEngine;
  2995. }
  2996. /**
  2997. * Enables physics to the current scene
  2998. * @param {BABYLON.Vector3} [gravity] - the scene's gravity for the physics engine
  2999. * @param {BABYLON.IPhysicsEnginePlugin} [plugin] - The physics engine to be used. defaults to OimoJS.
  3000. * @return {boolean} was the physics engine initialized
  3001. */
  3002. public enablePhysics(gravity?: Vector3, plugin?: IPhysicsEnginePlugin): boolean {
  3003. if (this._physicsEngine) {
  3004. return true;
  3005. }
  3006. try {
  3007. this._physicsEngine = new PhysicsEngine(gravity, plugin);
  3008. return true;
  3009. } catch (e) {
  3010. Tools.Error(e.message);
  3011. return false;
  3012. }
  3013. }
  3014. public disablePhysicsEngine(): void {
  3015. if (!this._physicsEngine) {
  3016. return;
  3017. }
  3018. this._physicsEngine.dispose();
  3019. this._physicsEngine = undefined;
  3020. }
  3021. public isPhysicsEnabled(): boolean {
  3022. return this._physicsEngine !== undefined;
  3023. }
  3024. public deleteCompoundImpostor(compound: any): void {
  3025. var mesh: AbstractMesh = compound.parts[0].mesh;
  3026. mesh.physicsImpostor.dispose(/*true*/);
  3027. mesh.physicsImpostor = null;
  3028. }
  3029. // Misc.
  3030. public createDefaultCameraOrLight(createArcRotateCamera = false, replace = false, attachCameraControls = false) {
  3031. // Dispose existing camera or light in replace mode.
  3032. if (replace) {
  3033. if (this.activeCamera) {
  3034. this.activeCamera.dispose();
  3035. this.activeCamera = null;
  3036. }
  3037. if (this.lights) {
  3038. for (var i = 0; i < this.lights.length; i++) {
  3039. this.lights[i].dispose();
  3040. }
  3041. }
  3042. }
  3043. // Light
  3044. if (this.lights.length === 0) {
  3045. new HemisphericLight("default light", Vector3.Up(), this);
  3046. }
  3047. // Camera
  3048. if (!this.activeCamera) {
  3049. var worldExtends = this.getWorldExtends();
  3050. var worldSize = worldExtends.max.subtract(worldExtends.min);
  3051. var worldCenter = worldExtends.min.add(worldSize.scale(0.5));
  3052. var camera: TargetCamera;
  3053. var radius = worldSize.length() * 1.5;
  3054. if (createArcRotateCamera) {
  3055. var arcRotateCamera = new ArcRotateCamera("default camera", 4.712, 1.571, radius, worldCenter, this);
  3056. arcRotateCamera.lowerRadiusLimit = radius * 0.01;
  3057. arcRotateCamera.wheelPrecision = 100 / radius;
  3058. camera = arcRotateCamera;
  3059. }
  3060. else {
  3061. var freeCamera = new FreeCamera("default camera", new Vector3(worldCenter.x, worldCenter.y, this.useRightHandedSystem ? -radius : radius), this);
  3062. freeCamera.setTarget(worldCenter);
  3063. camera = freeCamera;
  3064. }
  3065. camera.minZ = radius * 0.01;
  3066. camera.maxZ = radius * 100;
  3067. camera.speed = radius * 0.2;
  3068. this.activeCamera = camera;
  3069. if (attachCameraControls) {
  3070. camera.attachControl(this.getEngine().getRenderingCanvas());
  3071. }
  3072. }
  3073. }
  3074. public createDefaultSkybox(environmentTexture?: BaseTexture, pbr = false, scale = 1000, blur = 0): Mesh {
  3075. if (environmentTexture) {
  3076. this.environmentTexture = environmentTexture;
  3077. }
  3078. if (!this.environmentTexture) {
  3079. Tools.Warn("Can not create default skybox without environment texture.");
  3080. return;
  3081. }
  3082. // Skybox
  3083. var hdrSkybox = BABYLON.Mesh.CreateBox("hdrSkyBox", scale, this);
  3084. if (pbr) {
  3085. let hdrSkyboxMaterial = new BABYLON.PBRMaterial("skyBox", this);
  3086. hdrSkyboxMaterial.backFaceCulling = false;
  3087. hdrSkyboxMaterial.reflectionTexture = environmentTexture.clone();
  3088. hdrSkyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
  3089. hdrSkyboxMaterial.microSurface = 1.0 - blur;
  3090. hdrSkyboxMaterial.disableLighting = true;
  3091. hdrSkyboxMaterial.twoSidedLighting = true;
  3092. hdrSkybox.infiniteDistance = true;
  3093. hdrSkybox.material = hdrSkyboxMaterial;
  3094. }
  3095. else {
  3096. let skyboxMaterial = new BABYLON.StandardMaterial("skyBox", this);
  3097. skyboxMaterial.backFaceCulling = false;
  3098. skyboxMaterial.reflectionTexture = environmentTexture.clone();
  3099. skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
  3100. skyboxMaterial.disableLighting = true;
  3101. hdrSkybox.infiniteDistance = true;
  3102. hdrSkybox.material = skyboxMaterial;
  3103. }
  3104. return hdrSkybox;
  3105. }
  3106. // Tags
  3107. private _getByTags(list: any[], tagsQuery: string, forEach?: (item: any) => void): any[] {
  3108. if (tagsQuery === undefined) {
  3109. // returns the complete list (could be done with BABYLON.Tags.MatchesQuery but no need to have a for-loop here)
  3110. return list;
  3111. }
  3112. var listByTags = [];
  3113. forEach = forEach || ((item: any) => { return; });
  3114. for (var i in list) {
  3115. var item = list[i];
  3116. if (Tags.MatchesQuery(item, tagsQuery)) {
  3117. listByTags.push(item);
  3118. forEach(item);
  3119. }
  3120. }
  3121. return listByTags;
  3122. }
  3123. public getMeshesByTags(tagsQuery: string, forEach?: (mesh: AbstractMesh) => void): Mesh[] {
  3124. return this._getByTags(this.meshes, tagsQuery, forEach);
  3125. }
  3126. public getCamerasByTags(tagsQuery: string, forEach?: (camera: Camera) => void): Camera[] {
  3127. return this._getByTags(this.cameras, tagsQuery, forEach);
  3128. }
  3129. public getLightsByTags(tagsQuery: string, forEach?: (light: Light) => void): Light[] {
  3130. return this._getByTags(this.lights, tagsQuery, forEach);
  3131. }
  3132. public getMaterialByTags(tagsQuery: string, forEach?: (material: Material) => void): Material[] {
  3133. return this._getByTags(this.materials, tagsQuery, forEach).concat(this._getByTags(this.multiMaterials, tagsQuery, forEach));
  3134. }
  3135. /**
  3136. * Overrides the default sort function applied in the renderging group to prepare the meshes.
  3137. * This allowed control for front to back rendering or reversly depending of the special needs.
  3138. *
  3139. * @param renderingGroupId The rendering group id corresponding to its index
  3140. * @param opaqueSortCompareFn The opaque queue comparison function use to sort.
  3141. * @param alphaTestSortCompareFn The alpha test queue comparison function use to sort.
  3142. * @param transparentSortCompareFn The transparent queue comparison function use to sort.
  3143. */
  3144. public setRenderingOrder(renderingGroupId: number,
  3145. opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
  3146. alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
  3147. transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number = null): void {
  3148. this._renderingManager.setRenderingOrder(renderingGroupId,
  3149. opaqueSortCompareFn,
  3150. alphaTestSortCompareFn,
  3151. transparentSortCompareFn);
  3152. }
  3153. /**
  3154. * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
  3155. *
  3156. * @param renderingGroupId The rendering group id corresponding to its index
  3157. * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
  3158. * @param depth Automatically clears depth between groups if true and autoClear is true.
  3159. * @param stencil Automatically clears stencil between groups if true and autoClear is true.
  3160. */
  3161. public setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean,
  3162. depth = true,
  3163. stencil = true): void {
  3164. this._renderingManager.setRenderingAutoClearDepthStencil(renderingGroupId, autoClearDepthStencil, depth, stencil);
  3165. }
  3166. /**
  3167. * Will flag all materials as dirty to trigger new shader compilation
  3168. * @param predicate If not null, it will be used to specifiy if a material has to be marked as dirty
  3169. */
  3170. public markAllMaterialsAsDirty(flag: number, predicate?: (mat: Material) => boolean): void {
  3171. for (var material of this.materials) {
  3172. if (predicate && !predicate(material)) {
  3173. continue;
  3174. }
  3175. material.markAsDirty(flag);
  3176. }
  3177. }
  3178. }
  3179. }