babylon.scene.ts 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379
  1. module BABYLON {
  2. export interface IDisposable {
  3. dispose(): void;
  4. }
  5. export class Scene {
  6. // Statics
  7. public static FOGMODE_NONE = 0;
  8. public static FOGMODE_EXP = 1;
  9. public static FOGMODE_EXP2 = 2;
  10. public static FOGMODE_LINEAR = 3;
  11. public static MinDeltaTime = 1.0;
  12. public static MaxDeltaTime = 1000.0;
  13. // Members
  14. public autoClear = true;
  15. public clearColor = new BABYLON.Color3(0.2, 0.2, 0.3);
  16. public ambientColor = new BABYLON.Color3(0, 0, 0);
  17. public beforeRender: () => void;
  18. public afterRender: () => void;
  19. public beforeCameraRender: (camera: Camera) => void;
  20. public afterCameraRender: (camera: Camera) => void;
  21. public forceWireframe = false;
  22. public clipPlane: Plane;
  23. // Pointers
  24. private _onPointerMove: (evt: PointerEvent) => void;
  25. private _onPointerDown: (evt: PointerEvent) => void;
  26. public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
  27. private _pointerX: number;
  28. private _pointerY: number;
  29. private _meshUnderPointer: AbstractMesh;
  30. // Fog
  31. public fogMode = BABYLON.Scene.FOGMODE_NONE;
  32. public fogColor = new Color3(0.2, 0.2, 0.3);
  33. public fogDensity = 0.1;
  34. public fogStart = 0;
  35. public fogEnd = 1000.0;
  36. // Lights
  37. public lightsEnabled = true;
  38. public lights = new Array<Light>();
  39. // Cameras
  40. public cameras = new Array<Camera>();
  41. public activeCameras = new Array<Camera>();
  42. public activeCamera: Camera;
  43. // Meshes
  44. public meshes = new Array<AbstractMesh>();
  45. // Geometries
  46. private _geometries = new Array<Geometry>();
  47. public materials = new Array<Material>();
  48. public multiMaterials = new Array<MultiMaterial>();
  49. public defaultMaterial = new BABYLON.StandardMaterial("default material", this);
  50. // Textures
  51. public texturesEnabled = true;
  52. public textures = new Array<BaseTexture>();
  53. // Particles
  54. public particlesEnabled = true;
  55. public particleSystems = new Array<ParticleSystem>();
  56. // Sprites
  57. public spriteManagers = new Array<SpriteManager>();
  58. // Layers
  59. public layers = new Array<Layer>();
  60. // Skeletons
  61. public skeletons = new Array<Skeleton>();
  62. // Lens flares
  63. public lensFlareSystems = new Array<LensFlareSystem>();
  64. // Collisions
  65. public collisionsEnabled = true;
  66. public gravity = new BABYLON.Vector3(0, -9.0, 0);
  67. // Postprocesses
  68. public postProcessesEnabled = true;
  69. public postProcessManager: PostProcessManager;
  70. public postProcessRenderPipelineManager: PostProcessRenderPipelineManager;
  71. // Customs render targets
  72. public renderTargetsEnabled = true;
  73. public customRenderTargets = new Array<RenderTargetTexture>();
  74. // Delay loading
  75. public useDelayedTextureLoading: boolean;
  76. // Imported meshes
  77. public importedMeshesFiles = new Array<String>();
  78. // Database
  79. public database; //ANY
  80. // Actions
  81. public actionManager: ActionManager;
  82. // Private
  83. private _engine: Engine;
  84. private _totalVertices = 0;
  85. public _activeVertices = 0;
  86. public _activeParticles = 0;
  87. private _lastFrameDuration = 0;
  88. private _evaluateActiveMeshesDuration = 0;
  89. private _renderTargetsDuration = 0;
  90. public _particlesDuration = 0;
  91. private _renderDuration = 0;
  92. public _spritesDuration = 0;
  93. private _animationRatio = 0;
  94. private _animationStartDate: number;
  95. private _renderId = 0;
  96. private _executeWhenReadyTimeoutId = -1;
  97. public _toBeDisposed = new SmartArray<IDisposable>(256);
  98. private _onReadyCallbacks = new Array<() => void>();
  99. private _pendingData = [];//ANY
  100. private _onBeforeRenderCallbacks = new Array<() => void>();
  101. private _activeMeshes = new SmartArray<Mesh>(256);
  102. private _processedMaterials = new SmartArray<Material>(256);
  103. private _renderTargets = new SmartArray<RenderTargetTexture>(256);
  104. public _activeParticleSystems = new SmartArray<ParticleSystem>(256);
  105. private _activeSkeletons = new SmartArray<Skeleton>(32);
  106. private _renderingManager: RenderingManager;
  107. private _physicsEngine: PhysicsEngine;
  108. public _activeAnimatables = new Array<Animatable>();
  109. private _transformMatrix = Matrix.Zero();
  110. private _pickWithRayInverseMatrix: Matrix;
  111. private _scaledPosition = Vector3.Zero();
  112. private _scaledVelocity = Vector3.Zero();
  113. private _boundingBoxRenderer: BoundingBoxRenderer;
  114. private _viewMatrix: Matrix;
  115. private _projectionMatrix: Matrix;
  116. private _frustumPlanes: Plane[];
  117. private _selectionOctree: Octree<AbstractMesh>;
  118. private _pointerOverMesh: AbstractMesh;
  119. // Constructor
  120. constructor(engine: Engine) {
  121. this._engine = engine;
  122. engine.scenes.push(this);
  123. this._renderingManager = new RenderingManager(this);
  124. this.postProcessManager = new PostProcessManager(this);
  125. this.postProcessRenderPipelineManager = new PostProcessRenderPipelineManager();
  126. this._boundingBoxRenderer = new BoundingBoxRenderer(this);
  127. this.attachControl();
  128. }
  129. // Properties
  130. public get meshUnderPointer(): AbstractMesh {
  131. return this._meshUnderPointer;
  132. }
  133. public get pointerX(): number {
  134. return this._pointerX;
  135. }
  136. public get pointerY(): number {
  137. return this._pointerY;
  138. }
  139. public getBoundingBoxRenderer(): BoundingBoxRenderer {
  140. return this._boundingBoxRenderer;
  141. }
  142. public getEngine(): Engine {
  143. return this._engine;
  144. }
  145. public getTotalVertices(): number {
  146. return this._totalVertices;
  147. }
  148. public getActiveVertices(): number {
  149. return this._activeVertices;
  150. }
  151. public getActiveParticles(): number {
  152. return this._activeParticles;
  153. }
  154. // Stats
  155. public getLastFrameDuration(): number {
  156. return this._lastFrameDuration;
  157. }
  158. public getEvaluateActiveMeshesDuration(): number {
  159. return this._evaluateActiveMeshesDuration;
  160. }
  161. public getActiveMeshes(): SmartArray<Mesh> {
  162. return this._activeMeshes;
  163. }
  164. public getRenderTargetsDuration(): number {
  165. return this._renderTargetsDuration;
  166. }
  167. public getRenderDuration(): number {
  168. return this._renderDuration;
  169. }
  170. public getParticlesDuration(): number {
  171. return this._particlesDuration;
  172. }
  173. public getSpritesDuration(): number {
  174. return this._spritesDuration;
  175. }
  176. public getAnimationRatio(): number {
  177. return this._animationRatio;
  178. }
  179. public getRenderId(): number {
  180. return this._renderId;
  181. }
  182. private _updatePointerPosition(evt: PointerEvent): void {
  183. var canvasRect = this._engine.getRenderingCanvasClientRect();
  184. this._pointerX = evt.clientX - canvasRect.left;
  185. this._pointerY = evt.clientY - canvasRect.top;
  186. }
  187. // Pointers handling
  188. public attachControl() {
  189. this._onPointerMove = (evt: PointerEvent) => {
  190. var canvas = this._engine.getRenderingCanvas();
  191. this._updatePointerPosition(evt);
  192. var pickResult = this.pick(this._pointerX, this._pointerY, (mesh: AbstractMesh): boolean => mesh.actionManager && mesh.isPickable && mesh.isVisible && mesh.isReady());
  193. if (pickResult.hit) {
  194. this.setPointerOverMesh(pickResult.pickedMesh);
  195. canvas.style.cursor = "pointer";
  196. this._meshUnderPointer = pickResult.pickedMesh;
  197. } else {
  198. this.setPointerOverMesh(null);
  199. canvas.style.cursor = "";
  200. this._meshUnderPointer = null;
  201. }
  202. };
  203. this._onPointerDown = (evt: PointerEvent) => {
  204. var predicate = null;
  205. if (!this.onPointerDown) {
  206. predicate = (mesh: AbstractMesh): boolean => {
  207. return mesh.actionManager && mesh.isPickable && mesh.isVisible && mesh.isReady();
  208. };
  209. }
  210. this._updatePointerPosition(evt);
  211. var pickResult = this.pick(this._pointerX, this._pointerY, predicate);
  212. if (pickResult.hit) {
  213. if (pickResult.pickedMesh.actionManager) {
  214. switch (evt.buttons) {
  215. case 1:
  216. pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
  217. break;
  218. case 2:
  219. pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
  220. break;
  221. case 3:
  222. pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
  223. break;
  224. }
  225. pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh));
  226. }
  227. }
  228. if (this.onPointerDown) {
  229. this.onPointerDown(evt, pickResult);
  230. }
  231. };
  232. var eventPrefix = Tools.GetPointerPrefix();
  233. this._engine.getRenderingCanvas().addEventListener(eventPrefix + "move", this._onPointerMove, false);
  234. this._engine.getRenderingCanvas().addEventListener(eventPrefix + "down", this._onPointerDown, false);
  235. }
  236. public detachControl() {
  237. var eventPrefix = Tools.GetPointerPrefix();
  238. this._engine.getRenderingCanvas().removeEventListener(eventPrefix + "move", this._onPointerMove);
  239. this._engine.getRenderingCanvas().removeEventListener(eventPrefix + "down", this._onPointerDown);
  240. }
  241. // Ready
  242. public isReady(): boolean {
  243. if (this._pendingData.length > 0) {
  244. return false;
  245. }
  246. for (var index = 0; index < this._geometries.length; index++) {
  247. var geometry = this._geometries[index];
  248. if (geometry.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
  249. return false;
  250. }
  251. }
  252. for (index = 0; index < this.meshes.length; index++) {
  253. var mesh = this.meshes[index];
  254. if (!mesh.isReady()) {
  255. return false;
  256. }
  257. var mat = mesh.material;
  258. if (mat) {
  259. if (!mat.isReady(mesh)) {
  260. return false;
  261. }
  262. }
  263. }
  264. return true;
  265. }
  266. public registerBeforeRender(func: () => void): void {
  267. this._onBeforeRenderCallbacks.push(func);
  268. }
  269. public unregisterBeforeRender(func: () => void): void {
  270. var index = this._onBeforeRenderCallbacks.indexOf(func);
  271. if (index > -1) {
  272. this._onBeforeRenderCallbacks.splice(index, 1);
  273. }
  274. }
  275. public _addPendingData(data): void {
  276. this._pendingData.push(data);
  277. }
  278. public _removePendingData(data): void {
  279. var index = this._pendingData.indexOf(data);
  280. if (index !== -1) {
  281. this._pendingData.splice(index, 1);
  282. }
  283. }
  284. public getWaitingItemsCount(): number {
  285. return this._pendingData.length;
  286. }
  287. public executeWhenReady(func: () => void): void {
  288. this._onReadyCallbacks.push(func);
  289. if (this._executeWhenReadyTimeoutId !== -1) {
  290. return;
  291. }
  292. this._executeWhenReadyTimeoutId = setTimeout(() => {
  293. this._checkIsReady();
  294. }, 150);
  295. }
  296. public _checkIsReady() {
  297. if (this.isReady()) {
  298. this._onReadyCallbacks.forEach(func => {
  299. func();
  300. });
  301. this._onReadyCallbacks = [];
  302. this._executeWhenReadyTimeoutId = -1;
  303. return;
  304. }
  305. this._executeWhenReadyTimeoutId = setTimeout(() => {
  306. this._checkIsReady();
  307. }, 150);
  308. }
  309. // Animations
  310. public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void, animatable?: Animatable): Animatable {
  311. if (speedRatio === undefined) {
  312. speedRatio = 1.0;
  313. }
  314. this.stopAnimation(target);
  315. if (!animatable) {
  316. animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
  317. }
  318. // Local animations
  319. if (target.animations) {
  320. animatable.appendAnimations(target, target.animations);
  321. }
  322. // Children animations
  323. if (target.getAnimatables) {
  324. var animatables = target.getAnimatables();
  325. for (var index = 0; index < animatables.length; index++) {
  326. this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
  327. }
  328. }
  329. return animatable;
  330. }
  331. public beginDirectAnimation(target: any, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): Animatable {
  332. if (speedRatio === undefined) {
  333. speedRatio = 1.0;
  334. }
  335. var animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations);
  336. return animatable;
  337. }
  338. public getAnimatableByTarget(target: any): Animatable {
  339. for (var index = 0; index < this._activeAnimatables.length; index++) {
  340. if (this._activeAnimatables[index].target === target) {
  341. return this._activeAnimatables[index];
  342. }
  343. }
  344. return null;
  345. }
  346. public stopAnimation(target: any): void {
  347. var animatable = this.getAnimatableByTarget(target);
  348. if (animatable) {
  349. animatable.stop();
  350. }
  351. }
  352. private _animate(): void {
  353. if (!this._animationStartDate) {
  354. this._animationStartDate = new Date().getTime();
  355. }
  356. // Getting time
  357. var now = new Date().getTime();
  358. var delay = now - this._animationStartDate;
  359. for (var index = 0; index < this._activeAnimatables.length; index++) {
  360. if (!this._activeAnimatables[index]._animate(delay)) {
  361. this._activeAnimatables.splice(index, 1);
  362. index--;
  363. }
  364. }
  365. }
  366. // Matrix
  367. public getViewMatrix(): Matrix {
  368. return this._viewMatrix;
  369. }
  370. public getProjectionMatrix(): Matrix {
  371. return this._projectionMatrix;
  372. }
  373. public getTransformMatrix(): Matrix {
  374. return this._transformMatrix;
  375. }
  376. public setTransformMatrix(view: Matrix, projection: Matrix): void {
  377. this._viewMatrix = view;
  378. this._projectionMatrix = projection;
  379. this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
  380. }
  381. // Methods
  382. public setActiveCameraByID(id: string): Camera {
  383. var camera = this.getCameraByID(id);
  384. if (camera) {
  385. this.activeCamera = camera;
  386. return camera;
  387. }
  388. return null;
  389. }
  390. public setActiveCameraByName(name: string): Camera {
  391. var camera = this.getCameraByName(name);
  392. if (camera) {
  393. this.activeCamera = camera;
  394. return camera;
  395. }
  396. return null;
  397. }
  398. public getMaterialByID(id: string): Material {
  399. for (var index = 0; index < this.materials.length; index++) {
  400. if (this.materials[index].id === id) {
  401. return this.materials[index];
  402. }
  403. }
  404. return null;
  405. }
  406. public getMaterialByName(name: string): Material {
  407. for (var index = 0; index < this.materials.length; index++) {
  408. if (this.materials[index].name === name) {
  409. return this.materials[index];
  410. }
  411. }
  412. return null;
  413. }
  414. public getCameraByID(id: string): Camera {
  415. for (var index = 0; index < this.cameras.length; index++) {
  416. if (this.cameras[index].id === id) {
  417. return this.cameras[index];
  418. }
  419. }
  420. return null;
  421. }
  422. public getCameraByName(name: string): Camera {
  423. for (var index = 0; index < this.cameras.length; index++) {
  424. if (this.cameras[index].name === name) {
  425. return this.cameras[index];
  426. }
  427. }
  428. return null;
  429. }
  430. public getLightByName(name: string): Light {
  431. for (var index = 0; index < this.lights.length; index++) {
  432. if (this.lights[index].name === name) {
  433. return this.lights[index];
  434. }
  435. }
  436. return null;
  437. }
  438. public getLightByID(id: string): Light {
  439. for (var index = 0; index < this.lights.length; index++) {
  440. if (this.lights[index].id === id) {
  441. return this.lights[index];
  442. }
  443. }
  444. return null;
  445. }
  446. public getGeometryByID(id: string): Geometry {
  447. for (var index = 0; index < this._geometries.length; index++) {
  448. if (this._geometries[index].id === id) {
  449. return this._geometries[index];
  450. }
  451. }
  452. return null;
  453. }
  454. public pushGeometry(geometry: Geometry, force?: boolean): boolean {
  455. if (!force && this.getGeometryByID(geometry.id)) {
  456. return false;
  457. }
  458. this._geometries.push(geometry);
  459. return true;
  460. }
  461. public getGeometries(): Geometry[] {
  462. return this._geometries;
  463. }
  464. public getMeshByID(id: string): AbstractMesh {
  465. for (var index = 0; index < this.meshes.length; index++) {
  466. if (this.meshes[index].id === id) {
  467. return this.meshes[index];
  468. }
  469. }
  470. return null;
  471. }
  472. public getLastMeshByID(id: string): AbstractMesh {
  473. for (var index = this.meshes.length - 1; index >= 0; index--) {
  474. if (this.meshes[index].id === id) {
  475. return this.meshes[index];
  476. }
  477. }
  478. return null;
  479. }
  480. public getLastEntryByID(id: string): Node {
  481. for (var index = this.meshes.length - 1; index >= 0; index--) {
  482. if (this.meshes[index].id === id) {
  483. return this.meshes[index];
  484. }
  485. }
  486. for (index = this.cameras.length - 1; index >= 0; index--) {
  487. if (this.cameras[index].id === id) {
  488. return this.cameras[index];
  489. }
  490. }
  491. for (index = this.lights.length - 1; index >= 0; index--) {
  492. if (this.lights[index].id === id) {
  493. return this.lights[index];
  494. }
  495. }
  496. return null;
  497. }
  498. public getMeshByName(name: string): AbstractMesh {
  499. for (var index = 0; index < this.meshes.length; index++) {
  500. if (this.meshes[index].name === name) {
  501. return this.meshes[index];
  502. }
  503. }
  504. return null;
  505. }
  506. public getLastSkeletonByID(id: string): Skeleton {
  507. for (var index = this.skeletons.length - 1; index >= 0; index--) {
  508. if (this.skeletons[index].id === id) {
  509. return this.skeletons[index];
  510. }
  511. }
  512. return null;
  513. }
  514. public getSkeletonById(id: string): Skeleton {
  515. for (var index = 0; index < this.skeletons.length; index++) {
  516. if (this.skeletons[index].id === id) {
  517. return this.skeletons[index];
  518. }
  519. }
  520. return null;
  521. }
  522. public getSkeletonByName(name: string): Skeleton {
  523. for (var index = 0; index < this.skeletons.length; index++) {
  524. if (this.skeletons[index].name === name) {
  525. return this.skeletons[index];
  526. }
  527. }
  528. return null;
  529. }
  530. public isActiveMesh(mesh: Mesh): boolean {
  531. return (this._activeMeshes.indexOf(mesh) !== -1);
  532. }
  533. private _evaluateSubMesh(subMesh: SubMesh, mesh: AbstractMesh): void {
  534. if (mesh.subMeshes.length == 1 || subMesh.isInFrustum(this._frustumPlanes)) {
  535. var material = subMesh.getMaterial();
  536. if (mesh.showSubMeshesBoundingBox) {
  537. this._boundingBoxRenderer.renderList.push(subMesh.getBoundingInfo().boundingBox);
  538. }
  539. if (material) {
  540. // Render targets
  541. if (material.getRenderTargetTextures) {
  542. if (this._processedMaterials.indexOf(material) === -1) {
  543. this._processedMaterials.push(material);
  544. this._renderTargets.concat(material.getRenderTargetTextures());
  545. }
  546. }
  547. // Dispatch
  548. this._activeVertices += subMesh.verticesCount;
  549. this._renderingManager.dispatch(subMesh);
  550. }
  551. }
  552. }
  553. private _evaluateActiveMeshes(): void {
  554. this._activeMeshes.reset();
  555. this._renderingManager.reset();
  556. this._processedMaterials.reset();
  557. this._activeParticleSystems.reset();
  558. this._activeSkeletons.reset();
  559. this._boundingBoxRenderer.reset();
  560. if (!this._frustumPlanes) {
  561. this._frustumPlanes = BABYLON.Frustum.GetPlanes(this._transformMatrix);
  562. } else {
  563. BABYLON.Frustum.GetPlanesToRef(this._transformMatrix, this._frustumPlanes);
  564. }
  565. // Meshes
  566. var meshes: AbstractMesh[];
  567. var len: number;
  568. if (this._selectionOctree) { // Octree
  569. var selection = this._selectionOctree.select(this._frustumPlanes);
  570. meshes = selection.data;
  571. len = selection.length;
  572. } else { // Full scene traversal
  573. len = this.meshes.length;
  574. meshes = this.meshes;
  575. }
  576. for (var meshIndex = 0; meshIndex < len; meshIndex++) {
  577. var mesh = meshes[meshIndex];
  578. this._totalVertices += mesh.getTotalVertices();
  579. if (!mesh.isReady()) {
  580. continue;
  581. }
  582. mesh.computeWorldMatrix();
  583. mesh._preActivate();
  584. if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
  585. this._activeMeshes.push(mesh);
  586. mesh._activate(this._renderId);
  587. this._activeMesh(mesh);
  588. }
  589. }
  590. // Particle systems
  591. var beforeParticlesDate = new Date().getTime();
  592. if (this.particlesEnabled) {
  593. for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
  594. var particleSystem = this.particleSystems[particleIndex];
  595. if (!particleSystem.isStarted()) {
  596. continue;
  597. }
  598. if (!particleSystem.emitter.position || (particleSystem.emitter && particleSystem.emitter.isEnabled())) {
  599. this._activeParticleSystems.push(particleSystem);
  600. particleSystem.animate();
  601. }
  602. }
  603. }
  604. this._particlesDuration += new Date().getTime() - beforeParticlesDate;
  605. }
  606. private _activeMesh(mesh: AbstractMesh): void {
  607. if (mesh.skeleton) {
  608. this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
  609. }
  610. if (mesh.showBoundingBox) {
  611. this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
  612. }
  613. if (mesh.subMeshes) {
  614. // Submeshes Octrees
  615. var len: number;
  616. var subMeshes: SubMesh[];
  617. if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
  618. var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
  619. len = intersections.length;
  620. subMeshes = intersections.data;
  621. } else {
  622. subMeshes = mesh.subMeshes;
  623. len = subMeshes.length;
  624. }
  625. for (var subIndex = 0; subIndex < len; subIndex++) {
  626. var subMesh = subMeshes[subIndex];
  627. this._evaluateSubMesh(subMesh, mesh);
  628. }
  629. }
  630. }
  631. public updateTransformMatrix(force?: boolean): void {
  632. this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(force));
  633. }
  634. private _renderForCamera(camera: Camera): void {
  635. var engine = this._engine;
  636. this.activeCamera = camera;
  637. if (!this.activeCamera)
  638. throw new Error("Active camera not set");
  639. // Viewport
  640. engine.setViewport(this.activeCamera.viewport);
  641. // Camera
  642. this._renderId++;
  643. this.updateTransformMatrix();
  644. if (this.beforeCameraRender) {
  645. this.beforeCameraRender(this.activeCamera);
  646. }
  647. // Meshes
  648. var beforeEvaluateActiveMeshesDate = new Date().getTime();
  649. this._evaluateActiveMeshes();
  650. this._evaluateActiveMeshesDuration += new Date().getTime() - beforeEvaluateActiveMeshesDate;
  651. // Skeletons
  652. for (var skeletonIndex = 0; skeletonIndex < this._activeSkeletons.length; skeletonIndex++) {
  653. var skeleton = this._activeSkeletons.data[skeletonIndex];
  654. skeleton.prepare();
  655. }
  656. // Customs render targets registration
  657. for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
  658. var renderTarget = this.customRenderTargets[customIndex];
  659. this._renderTargets.push(renderTarget);
  660. }
  661. // Render targets
  662. var beforeRenderTargetDate = new Date().getTime();
  663. if (this.renderTargetsEnabled) {
  664. for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
  665. renderTarget = this._renderTargets.data[renderIndex];
  666. if (renderTarget._shouldRender()) {
  667. this._renderId++;
  668. renderTarget.render();
  669. }
  670. }
  671. this._renderId++;
  672. }
  673. if (this._renderTargets.length > 0) { // Restore back buffer
  674. engine.restoreDefaultFramebuffer();
  675. }
  676. this._renderTargetsDuration = new Date().getTime() - beforeRenderTargetDate;
  677. // Prepare Frame
  678. this.postProcessManager._prepareFrame();
  679. var beforeRenderDate = new Date().getTime();
  680. // Backgrounds
  681. if (this.layers.length) {
  682. engine.setDepthBuffer(false);
  683. var layerIndex;
  684. var layer;
  685. for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) {
  686. layer = this.layers[layerIndex];
  687. if (layer.isBackground) {
  688. layer.render();
  689. }
  690. }
  691. engine.setDepthBuffer(true);
  692. }
  693. // Render
  694. this._renderingManager.render(null, null, true, true);
  695. // Bounding boxes
  696. this._boundingBoxRenderer.render();
  697. // Lens flares
  698. for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
  699. this.lensFlareSystems[lensFlareSystemIndex].render();
  700. }
  701. // Foregrounds
  702. if (this.layers.length) {
  703. engine.setDepthBuffer(false);
  704. for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) {
  705. layer = this.layers[layerIndex];
  706. if (!layer.isBackground) {
  707. layer.render();
  708. }
  709. }
  710. engine.setDepthBuffer(true);
  711. }
  712. this._renderDuration += new Date().getTime() - beforeRenderDate;
  713. // Finalize frame
  714. this.postProcessManager._finalizeFrame(camera.isIntermediate);
  715. // Update camera
  716. this.activeCamera._updateFromScene();
  717. // Reset some special arrays
  718. this._renderTargets.reset();
  719. if (this.afterCameraRender) {
  720. this.afterCameraRender(this.activeCamera);
  721. }
  722. }
  723. private _processSubCameras(camera: Camera): void {
  724. if (camera.subCameras.length == 0) {
  725. this._renderForCamera(camera);
  726. return;
  727. }
  728. // Sub-cameras
  729. for (var index = 0; index < camera.subCameras.length; index++) {
  730. this._renderForCamera(camera.subCameras[index]);
  731. }
  732. this.activeCamera = camera;
  733. this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
  734. // Update camera
  735. this.activeCamera._updateFromScene();
  736. }
  737. public render(): void {
  738. var startDate = new Date().getTime();
  739. this._particlesDuration = 0;
  740. this._spritesDuration = 0;
  741. this._activeParticles = 0;
  742. this._renderDuration = 0;
  743. this._evaluateActiveMeshesDuration = 0;
  744. this._totalVertices = 0;
  745. this._activeVertices = 0;
  746. // Actions
  747. if (this.actionManager) {
  748. this.actionManager.processTrigger(ActionManager.OnEveryFrameTrigger, null);
  749. }
  750. // Before render
  751. if (this.beforeRender) {
  752. this.beforeRender();
  753. }
  754. for (var callbackIndex = 0; callbackIndex < this._onBeforeRenderCallbacks.length; callbackIndex++) {
  755. this._onBeforeRenderCallbacks[callbackIndex]();
  756. }
  757. // Animations
  758. var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(BABYLON.Tools.GetDeltaTime(), Scene.MaxDeltaTime));
  759. this._animationRatio = deltaTime * (60.0 / 1000.0);
  760. this._animate();
  761. // Physics
  762. if (this._physicsEngine) {
  763. this._physicsEngine._runOneStep(deltaTime / 1000.0);
  764. }
  765. // Clear
  766. this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe, true);
  767. // Shadows
  768. for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
  769. var light = this.lights[lightIndex];
  770. var shadowGenerator = light.getShadowGenerator();
  771. if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
  772. this._renderTargets.push(shadowGenerator.getShadowMap());
  773. }
  774. }
  775. // RenderPipeline
  776. this.postProcessRenderPipelineManager.update();
  777. // Multi-cameras?
  778. if (this.activeCameras.length > 0) {
  779. var currentRenderId = this._renderId;
  780. for (var cameraIndex = 0; cameraIndex < this.activeCameras.length; cameraIndex++) {
  781. this._renderId = currentRenderId;
  782. this._processSubCameras(this.activeCameras[cameraIndex]);
  783. }
  784. } else {
  785. this._processSubCameras(this.activeCamera);
  786. }
  787. // After render
  788. if (this.afterRender) {
  789. this.afterRender();
  790. }
  791. // Cleaning
  792. for (var index = 0; index < this._toBeDisposed.length; index++) {
  793. this._toBeDisposed.data[index].dispose();
  794. this._toBeDisposed[index] = null;
  795. }
  796. this._toBeDisposed.reset();
  797. this._lastFrameDuration = new Date().getTime() - startDate;
  798. }
  799. public dispose(): void {
  800. this.beforeRender = null;
  801. this.afterRender = null;
  802. this.skeletons = [];
  803. this._boundingBoxRenderer.dispose();
  804. // Events
  805. this.detachControl();
  806. // Detach cameras
  807. var canvas = this._engine.getRenderingCanvas();
  808. var index;
  809. for (index = 0; index < this.cameras.length; index++) {
  810. this.cameras[index].detachControl(canvas);
  811. }
  812. // Release lights
  813. while (this.lights.length) {
  814. this.lights[0].dispose();
  815. }
  816. // Release meshes
  817. while (this.meshes.length) {
  818. this.meshes[0].dispose(true);
  819. }
  820. // Release cameras
  821. while (this.cameras.length) {
  822. this.cameras[0].dispose();
  823. }
  824. // Release materials
  825. while (this.materials.length) {
  826. this.materials[0].dispose();
  827. }
  828. // Release particles
  829. while (this.particleSystems.length) {
  830. this.particleSystems[0].dispose();
  831. }
  832. // Release sprites
  833. while (this.spriteManagers.length) {
  834. this.spriteManagers[0].dispose();
  835. }
  836. // Release layers
  837. while (this.layers.length) {
  838. this.layers[0].dispose();
  839. }
  840. // Release textures
  841. while (this.textures.length) {
  842. this.textures[0].dispose();
  843. }
  844. // Post-processes
  845. this.postProcessManager.dispose();
  846. // Physics
  847. if (this._physicsEngine) {
  848. this.disablePhysicsEngine();
  849. }
  850. // Remove from engine
  851. index = this._engine.scenes.indexOf(this);
  852. this._engine.scenes.splice(index, 1);
  853. this._engine.wipeCaches();
  854. }
  855. // Collisions
  856. public _getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3): void {
  857. position.divideToRef(collider.radius, this._scaledPosition);
  858. velocity.divideToRef(collider.radius, this._scaledVelocity);
  859. collider.retry = 0;
  860. collider.initialVelocity = this._scaledVelocity;
  861. collider.initialPosition = this._scaledPosition;
  862. this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, finalPosition);
  863. finalPosition.multiplyInPlace(collider.radius);
  864. }
  865. private _collideWithWorld(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3): void {
  866. var closeDistance = BABYLON.Engine.CollisionsEpsilon * 10.0;
  867. if (collider.retry >= maximumRetry) {
  868. finalPosition.copyFrom(position);
  869. return;
  870. }
  871. collider._initialize(position, velocity, closeDistance);
  872. // Check all meshes
  873. for (var index = 0; index < this.meshes.length; index++) {
  874. var mesh = this.meshes[index];
  875. if (mesh.isEnabled() && mesh.checkCollisions) {
  876. mesh._checkCollision(collider);
  877. }
  878. }
  879. if (!collider.collisionFound) {
  880. position.addToRef(velocity, finalPosition);
  881. return;
  882. }
  883. if (velocity.x != 0 || velocity.y != 0 || velocity.z != 0) {
  884. collider._getResponse(position, velocity);
  885. }
  886. if (velocity.length() <= closeDistance) {
  887. finalPosition.copyFrom(position);
  888. return;
  889. }
  890. collider.retry++;
  891. this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition);
  892. }
  893. // Octrees
  894. public createOrUpdateSelectionOctree(maxCapacity = 64, maxDepth = 2): Octree<AbstractMesh> {
  895. if (!this._selectionOctree) {
  896. this._selectionOctree = new BABYLON.Octree<AbstractMesh>(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
  897. }
  898. var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  899. var max = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  900. for (var index = 0; index < this.meshes.length; index++) {
  901. var mesh = this.meshes[index];
  902. mesh.computeWorldMatrix(true);
  903. var minBox = mesh.getBoundingInfo().boundingBox.minimumWorld;
  904. var maxBox = mesh.getBoundingInfo().boundingBox.maximumWorld;
  905. Tools.CheckExtends(minBox, min, max);
  906. Tools.CheckExtends(maxBox, min, max);
  907. }
  908. // Update octree
  909. this._selectionOctree.update(min, max, this.meshes);
  910. return this._selectionOctree;
  911. }
  912. // Picking
  913. public createPickingRay(x: number, y: number, world: Matrix, camera: Camera): Ray {
  914. var engine = this._engine;
  915. if (!camera) {
  916. if (!this.activeCamera)
  917. throw new Error("Active camera not set");
  918. camera = this.activeCamera;
  919. }
  920. var cameraViewport = camera.viewport;
  921. var viewport = cameraViewport.toGlobal(engine);
  922. // Moving coordinates to local viewport world
  923. x = x / this._engine.getHardwareScalingLevel() - viewport.x;
  924. y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
  925. return BABYLON.Ray.CreateNew(x, y, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix());
  926. }
  927. private _internalPick(rayFunction: (world: Matrix) => Ray, predicate: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): PickingInfo {
  928. var pickingInfo = null;
  929. for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) {
  930. var mesh = this.meshes[meshIndex];
  931. if (predicate) {
  932. if (!predicate(mesh)) {
  933. continue;
  934. }
  935. } else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) {
  936. continue;
  937. }
  938. var world = mesh.getWorldMatrix();
  939. var ray = rayFunction(world);
  940. var result = mesh.intersects(ray, fastCheck);
  941. if (!result || !result.hit)
  942. continue;
  943. if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
  944. continue;
  945. pickingInfo = result;
  946. if (fastCheck) {
  947. break;
  948. }
  949. }
  950. return pickingInfo || new BABYLON.PickingInfo();
  951. }
  952. public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Camera): PickingInfo {
  953. /// <summary>Launch a ray to try to pick a mesh in the scene</summary>
  954. /// <param name="x">X position on screen</param>
  955. /// <param name="y">Y position on screen</param>
  956. /// <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>
  957. /// <param name="fastCheck">Launch a fast check only using the bounding boxes. Can be set to null.</param>
  958. /// <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>
  959. return this._internalPick(world => this.createPickingRay(x, y, world, camera), predicate, fastCheck);
  960. }
  961. public pickWithRay(ray: Ray, predicate: (mesh: Mesh) => boolean, fastCheck?: boolean) {
  962. return this._internalPick(world => {
  963. if (!this._pickWithRayInverseMatrix) {
  964. this._pickWithRayInverseMatrix = BABYLON.Matrix.Identity();
  965. }
  966. world.invertToRef(this._pickWithRayInverseMatrix);
  967. return BABYLON.Ray.Transform(ray, this._pickWithRayInverseMatrix);
  968. }, predicate, fastCheck);
  969. }
  970. public setPointerOverMesh(mesh: AbstractMesh): void {
  971. if (this._pointerOverMesh === mesh) {
  972. return;
  973. }
  974. if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
  975. this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
  976. }
  977. this._pointerOverMesh = mesh;
  978. if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
  979. this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
  980. }
  981. }
  982. public getPointerOverMesh(): AbstractMesh {
  983. return this._pointerOverMesh;
  984. }
  985. // Physics
  986. public getPhysicsEngine(): PhysicsEngine {
  987. return this._physicsEngine;
  988. }
  989. public enablePhysics(gravity: Vector3, plugin?: IPhysicsEnginePlugin): boolean {
  990. if (this._physicsEngine) {
  991. return true;
  992. }
  993. this._physicsEngine = new BABYLON.PhysicsEngine(plugin);
  994. if (!this._physicsEngine.isSupported()) {
  995. this._physicsEngine = null;
  996. return false;
  997. }
  998. this._physicsEngine._initialize(gravity);
  999. return true;
  1000. }
  1001. public disablePhysicsEngine(): void {
  1002. if (!this._physicsEngine) {
  1003. return;
  1004. }
  1005. this._physicsEngine.dispose();
  1006. this._physicsEngine = undefined;
  1007. }
  1008. public isPhysicsEnabled(): boolean {
  1009. return this._physicsEngine !== undefined;
  1010. }
  1011. public setGravity(gravity: Vector3): void {
  1012. if (!this._physicsEngine) {
  1013. return;
  1014. }
  1015. this._physicsEngine._setGravity(gravity);
  1016. }
  1017. public createCompoundImpostor(parts: any, options: PhysicsBodyCreationOptions): any {
  1018. if (parts.parts) { // Old API
  1019. options = parts;
  1020. parts = parts.parts;
  1021. }
  1022. if (!this._physicsEngine) {
  1023. return null;
  1024. }
  1025. for (var index = 0; index < parts.length; index++) {
  1026. var mesh = parts[index].mesh;
  1027. mesh._physicImpostor = parts[index].impostor;
  1028. mesh._physicsMass = options.mass / parts.length;
  1029. mesh._physicsFriction = options.friction;
  1030. mesh._physicRestitution = options.restitution;
  1031. }
  1032. return this._physicsEngine._registerMeshesAsCompound(parts, options);
  1033. }
  1034. //ANY
  1035. public deleteCompoundImpostor(compound: any): void {
  1036. for (var index = 0; index < compound.parts.length; index++) {
  1037. var mesh = compound.parts[index].mesh;
  1038. mesh._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
  1039. this._physicsEngine._unregisterMesh(mesh);
  1040. }
  1041. }
  1042. // Tags
  1043. private _getByTags(list: any[], tagsQuery: string): any[] {
  1044. if (tagsQuery === undefined) {
  1045. // returns the complete list (could be done with BABYLON.Tags.MatchesQuery but no need to have a for-loop here)
  1046. return list;
  1047. }
  1048. var listByTags = [];
  1049. for (var i in list) {
  1050. var item = list[i];
  1051. if (BABYLON.Tags.MatchesQuery(item, tagsQuery)) {
  1052. listByTags.push(item);
  1053. }
  1054. }
  1055. return listByTags;
  1056. }
  1057. public getMeshesByTags(tagsQuery: string): Mesh[] {
  1058. return this._getByTags(this.meshes, tagsQuery);
  1059. }
  1060. public getCamerasByTags(tagsQuery: string): Camera[] {
  1061. return this._getByTags(this.cameras, tagsQuery);
  1062. }
  1063. public getLightsByTags(tagsQuery: string): Light[] {
  1064. return this._getByTags(this.lights, tagsQuery);
  1065. }
  1066. public getMaterialByTags(tagsQuery: string): Material[] {
  1067. return this._getByTags(this.materials, tagsQuery).concat(this._getByTags(this.multiMaterials, tagsQuery));
  1068. }
  1069. }
  1070. }