Scene.js 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750
  1. /*global define*/
  2. define([
  3. '../Core/BoundingRectangle',
  4. '../Core/BoundingSphere',
  5. '../Core/Cartesian2',
  6. '../Core/Cartesian3',
  7. '../Core/Color',
  8. '../Core/ColorGeometryInstanceAttribute',
  9. '../Core/createGuid',
  10. '../Core/defaultValue',
  11. '../Core/defined',
  12. '../Core/defineProperties',
  13. '../Core/destroyObject',
  14. '../Core/DeveloperError',
  15. '../Core/EllipsoidGeometry',
  16. '../Core/Event',
  17. '../Core/GeographicProjection',
  18. '../Core/GeometryInstance',
  19. '../Core/GeometryPipeline',
  20. '../Core/Intersect',
  21. '../Core/Interval',
  22. '../Core/JulianDate',
  23. '../Core/Math',
  24. '../Core/Matrix4',
  25. '../Core/mergeSort',
  26. '../Core/Occluder',
  27. '../Core/ShowGeometryInstanceAttribute',
  28. '../Renderer/ClearCommand',
  29. '../Renderer/Context',
  30. '../Renderer/PassState',
  31. './Camera',
  32. './CreditDisplay',
  33. './CullingVolume',
  34. './FrameState',
  35. './FrustumCommands',
  36. './FXAA',
  37. './OIT',
  38. './OrthographicFrustum',
  39. './Pass',
  40. './PerformanceDisplay',
  41. './PerInstanceColorAppearance',
  42. './PerspectiveFrustum',
  43. './PerspectiveOffCenterFrustum',
  44. './Primitive',
  45. './PrimitiveCollection',
  46. './SceneMode',
  47. './SceneTransforms',
  48. './SceneTransitioner',
  49. './ScreenSpaceCameraController',
  50. './SunPostProcess',
  51. './TweenCollection'
  52. ], function(
  53. BoundingRectangle,
  54. BoundingSphere,
  55. Cartesian2,
  56. Cartesian3,
  57. Color,
  58. ColorGeometryInstanceAttribute,
  59. createGuid,
  60. defaultValue,
  61. defined,
  62. defineProperties,
  63. destroyObject,
  64. DeveloperError,
  65. EllipsoidGeometry,
  66. Event,
  67. GeographicProjection,
  68. GeometryInstance,
  69. GeometryPipeline,
  70. Intersect,
  71. Interval,
  72. JulianDate,
  73. CesiumMath,
  74. Matrix4,
  75. mergeSort,
  76. Occluder,
  77. ShowGeometryInstanceAttribute,
  78. ClearCommand,
  79. Context,
  80. PassState,
  81. Camera,
  82. CreditDisplay,
  83. CullingVolume,
  84. FrameState,
  85. FrustumCommands,
  86. FXAA,
  87. OIT,
  88. OrthographicFrustum,
  89. Pass,
  90. PerformanceDisplay,
  91. PerInstanceColorAppearance,
  92. PerspectiveFrustum,
  93. PerspectiveOffCenterFrustum,
  94. Primitive,
  95. PrimitiveCollection,
  96. SceneMode,
  97. SceneTransforms,
  98. SceneTransitioner,
  99. ScreenSpaceCameraController,
  100. SunPostProcess,
  101. TweenCollection) {
  102. "use strict";
  103. /**
  104. * The container for all 3D graphical objects and state in a Cesium virtual scene. Generally,
  105. * a scene is not created directly; instead, it is implicitly created by {@link CesiumWidget}.
  106. * <p>
  107. * <em><code>contextOptions</code> parameter details:</em>
  108. * </p>
  109. * <p>
  110. * The default values are:
  111. * <code>
  112. * {
  113. * webgl : {
  114. * alpha : false,
  115. * depth : true,
  116. * stencil : false,
  117. * antialias : true,
  118. * premultipliedAlpha : true,
  119. * preserveDrawingBuffer : false
  120. * failIfMajorPerformanceCaveat : true
  121. * },
  122. * allowTextureFilterAnisotropic : true
  123. * }
  124. * </code>
  125. * </p>
  126. * <p>
  127. * The <code>webgl</code> property corresponds to the {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
  128. * object used to create the WebGL context.
  129. * </p>
  130. * <p>
  131. * <code>webgl.alpha</code> defaults to false, which can improve performance compared to the standard WebGL default
  132. * of true. If an application needs to composite Cesium above other HTML elements using alpha-blending, set
  133. * <code>webgl.alpha</code> to true.
  134. * </p>
  135. * <p>
  136. * <code>webgl.failIfMajorPerformanceCaveat</code> defaults to true, which ensures a context is not successfully created
  137. * if the system has a major performance issue such as only supporting software rendering. The standard WebGL default is false,
  138. * which is not appropriate for almost any Cesium app.
  139. * </p>
  140. * <p>
  141. * The other <code>webgl</code> properties match the WebGL defaults for {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}.
  142. * </p>
  143. * <p>
  144. * <code>allowTextureFilterAnisotropic</code> defaults to true, which enables anisotropic texture filtering when the
  145. * WebGL extension is supported. Setting this to false will improve performance, but hurt visual quality, especially for horizon views.
  146. * </p>
  147. *
  148. * @alias Scene
  149. * @constructor
  150. *
  151. * @param {Object} [options] Object with the following properties:
  152. * @param {Canvas} options.canvas The HTML canvas element to create the scene for.
  153. * @param {Object} [options.contextOptions] Context and WebGL creation properties. See details above.
  154. * @param {Element} [options.creditContainer] The HTML element in which the credits will be displayed.
  155. * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes.
  156. * @param {Boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
  157. * @param {Boolean} [options.scene3DOnly=false] If true, optimizes memory use and performance for 3D mode but disables the ability to use 2D or Columbus View. *
  158. * @see CesiumWidget
  159. * @see {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
  160. *
  161. * @exception {DeveloperError} options and options.canvas are required.
  162. *
  163. * @example
  164. * // Create scene without anisotropic texture filtering
  165. * var scene = new Cesium.Scene({
  166. * canvas : canvas,
  167. * contextOptions : {
  168. * allowTextureFilterAnisotropic : false
  169. * }
  170. * });
  171. */
  172. var Scene = function(options) {
  173. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  174. var canvas = options.canvas;
  175. var contextOptions = options.contextOptions;
  176. var creditContainer = options.creditContainer;
  177. //>>includeStart('debug', pragmas.debug);
  178. if (!defined(canvas)) {
  179. throw new DeveloperError('options and options.canvas are required.');
  180. }
  181. //>>includeEnd('debug');
  182. var context = new Context(canvas, contextOptions);
  183. if (!defined(creditContainer)) {
  184. creditContainer = document.createElement('div');
  185. creditContainer.style.position = 'absolute';
  186. creditContainer.style.bottom = '0';
  187. creditContainer.style['text-shadow'] = '0px 0px 2px #000000';
  188. creditContainer.style.color = '#ffffff';
  189. creditContainer.style['font-size'] = '10px';
  190. creditContainer.style['padding-right'] = '5px';
  191. canvas.parentNode.appendChild(creditContainer);
  192. }
  193. this._id = createGuid();
  194. this._frameState = new FrameState(new CreditDisplay(creditContainer));
  195. this._frameState.scene3DOnly = defaultValue(options.scene3DOnly, false);
  196. this._passState = new PassState(context);
  197. this._canvas = canvas;
  198. this._context = context;
  199. this._globe = undefined;
  200. this._primitives = new PrimitiveCollection();
  201. this._pickFramebuffer = undefined;
  202. this._tweens = new TweenCollection();
  203. this._shaderFrameCount = 0;
  204. this._sunPostProcess = undefined;
  205. this._commandList = [];
  206. this._frustumCommandsList = [];
  207. this._overlayCommandList = [];
  208. this._oit = defaultValue(options.orderIndependentTranslucency, true) ? new OIT(context) : undefined;
  209. this._executeOITFunction = undefined;
  210. this._fxaa = new FXAA();
  211. this._clearColorCommand = new ClearCommand({
  212. color : new Color(),
  213. owner : this
  214. });
  215. this._depthClearCommand = new ClearCommand({
  216. depth : 1.0,
  217. owner : this
  218. });
  219. this._transitioner = new SceneTransitioner(this);
  220. this._renderError = new Event();
  221. this._preRender = new Event();
  222. this._postRender = new Event();
  223. /**
  224. * Exceptions occurring in <code>render</code> are always caught in order to raise the
  225. * <code>renderError</code> event. If this property is true, the error is rethrown
  226. * after the event is raised. If this property is false, the <code>render</code> function
  227. * returns normally after raising the event.
  228. *
  229. * @type {Boolean}
  230. * @default false
  231. */
  232. this.rethrowRenderErrors = false;
  233. /**
  234. * Determines whether or not to instantly complete the
  235. * scene transition animation on user input.
  236. *
  237. * @type {Boolean}
  238. * @default true
  239. */
  240. this.completeMorphOnUserInput = true;
  241. /**
  242. * The event fired at the beginning of a scene transition.
  243. * @type {Event}
  244. * @default Event()
  245. */
  246. this.morphStart = new Event();
  247. /**
  248. * The event fired at the completion of a scene transition.
  249. * @type {Event}
  250. * @default Event()
  251. */
  252. this.morphComplete = new Event();
  253. /**
  254. * The {@link SkyBox} used to draw the stars.
  255. *
  256. * @type {SkyBox}
  257. * @default undefined
  258. *
  259. * @see Scene#backgroundColor
  260. */
  261. this.skyBox = undefined;
  262. /**
  263. * The sky atmosphere drawn around the globe.
  264. *
  265. * @type {SkyAtmosphere}
  266. * @default undefined
  267. */
  268. this.skyAtmosphere = undefined;
  269. /**
  270. * The {@link Sun}.
  271. *
  272. * @type {Sun}
  273. * @default undefined
  274. */
  275. this.sun = undefined;
  276. /**
  277. * Uses a bloom filter on the sun when enabled.
  278. *
  279. * @type {Boolean}
  280. * @default true
  281. */
  282. this.sunBloom = true;
  283. this._sunBloom = undefined;
  284. /**
  285. * The {@link Moon}
  286. *
  287. * @type Moon
  288. * @default undefined
  289. */
  290. this.moon = undefined;
  291. /**
  292. * The background color, which is only visible if there is no sky box, i.e., {@link Scene#skyBox} is undefined.
  293. *
  294. * @type {Color}
  295. * @default {@link Color.BLACK}
  296. *
  297. * @see Scene#skyBox
  298. */
  299. this.backgroundColor = Color.clone(Color.BLACK);
  300. this._mode = SceneMode.SCENE3D;
  301. this._mapProjection = defined(options.mapProjection) ? options.mapProjection : new GeographicProjection();
  302. /**
  303. * The current morph transition time between 2D/Columbus View and 3D,
  304. * with 0.0 being 2D or Columbus View and 1.0 being 3D.
  305. *
  306. * @type {Number}
  307. * @default 1.0
  308. */
  309. this.morphTime = 1.0;
  310. /**
  311. * The far-to-near ratio of the multi-frustum. The default is 1,000.0.
  312. *
  313. * @type {Number}
  314. * @default 1000.0
  315. */
  316. this.farToNearRatio = 1000.0;
  317. /**
  318. * This property is for debugging only; it is not for production use.
  319. * <p>
  320. * A function that determines what commands are executed. As shown in the examples below,
  321. * the function receives the command's <code>owner</code> as an argument, and returns a boolean indicating if the
  322. * command should be executed.
  323. * </p>
  324. * <p>
  325. * The default is <code>undefined</code>, indicating that all commands are executed.
  326. * </p>
  327. *
  328. * @type Function
  329. *
  330. * @default undefined
  331. *
  332. * @example
  333. * // Do not execute any commands.
  334. * scene.debugCommandFilter = function(command) {
  335. * return false;
  336. * };
  337. *
  338. * // Execute only the billboard's commands. That is, only draw the billboard.
  339. * var billboards = new Cesium.BillboardCollection();
  340. * scene.debugCommandFilter = function(command) {
  341. * return command.owner === billboards;
  342. * };
  343. */
  344. this.debugCommandFilter = undefined;
  345. /**
  346. * This property is for debugging only; it is not for production use.
  347. * <p>
  348. * When <code>true</code>, commands are randomly shaded. This is useful
  349. * for performance analysis to see what parts of a scene or model are
  350. * command-dense and could benefit from batching.
  351. * </p>
  352. *
  353. * @type Boolean
  354. *
  355. * @default false
  356. */
  357. this.debugShowCommands = false;
  358. /**
  359. * This property is for debugging only; it is not for production use.
  360. * <p>
  361. * When <code>true</code>, commands are shaded based on the frustums they
  362. * overlap. Commands in the closest frustum are tinted red, commands in
  363. * the next closest are green, and commands in the farthest frustum are
  364. * blue. If a command overlaps more than one frustum, the color components
  365. * are combined, e.g., a command overlapping the first two frustums is tinted
  366. * yellow.
  367. * </p>
  368. *
  369. * @type Boolean
  370. *
  371. * @default false
  372. */
  373. this.debugShowFrustums = false;
  374. this._debugFrustumStatistics = undefined;
  375. /**
  376. * This property is for debugging only; it is not for production use.
  377. * <p>
  378. * Displays frames per second and time between frames.
  379. * </p>
  380. *
  381. * @type Boolean
  382. *
  383. * @default false
  384. */
  385. this.debugShowFramesPerSecond = false;
  386. /**
  387. * If <code>true</code>, enables Fast Aproximate Anti-aliasing only if order independent translucency
  388. * is supported.
  389. *
  390. * @type Boolean
  391. * @default true
  392. */
  393. this.fxaaOrderIndependentTranslucency = true;
  394. /**
  395. * When <code>true</code>, enables Fast Approximate Anti-aliasing even when order independent translucency
  396. * is unsupported.
  397. *
  398. * @type Boolean
  399. * @default false
  400. */
  401. this.fxaa = false;
  402. this._performanceDisplay = undefined;
  403. this._debugSphere = undefined;
  404. var camera = new Camera(this);
  405. this._camera = camera;
  406. this._screenSpaceCameraController = new ScreenSpaceCameraController(this);
  407. // initial guess at frustums.
  408. var near = camera.frustum.near;
  409. var far = camera.frustum.far;
  410. var numFrustums = Math.ceil(Math.log(far / near) / Math.log(this.farToNearRatio));
  411. updateFrustums(near, far, this.farToNearRatio, numFrustums, this._frustumCommandsList);
  412. // give frameState, camera, and screen space camera controller initial state before rendering
  413. updateFrameState(this, 0.0, JulianDate.now());
  414. this.initializeFrame();
  415. };
  416. defineProperties(Scene.prototype, {
  417. /**
  418. * Gets the canvas element to which this scene is bound.
  419. * @memberof Scene.prototype
  420. *
  421. * @type {Element}
  422. * @readonly
  423. */
  424. canvas : {
  425. get : function() {
  426. return this._canvas;
  427. }
  428. },
  429. /**
  430. * The drawingBufferWidth of the underlying GL context.
  431. * @memberof Scene.prototype
  432. *
  433. * @type {Number}
  434. * @readonly
  435. *
  436. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferWidth|drawingBufferWidth}
  437. */
  438. drawingBufferHeight : {
  439. get : function() {
  440. return this._context.drawingBufferHeight;
  441. }
  442. },
  443. /**
  444. * The drawingBufferHeight of the underlying GL context.
  445. * @memberof Scene.prototype
  446. *
  447. * @type {Number}
  448. * @readonly
  449. *
  450. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
  451. */
  452. drawingBufferWidth : {
  453. get : function() {
  454. return this._context.drawingBufferWidth;
  455. }
  456. },
  457. /**
  458. * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one.
  459. * @memberof Scene.prototype
  460. *
  461. * @type {Number}
  462. * @readonly
  463. *
  464. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>.
  465. */
  466. maximumAliasedLineWidth : {
  467. get : function() {
  468. return this._context.maximumAliasedLineWidth;
  469. }
  470. },
  471. /**
  472. * Gets or sets the depth-test ellipsoid.
  473. * @memberof Scene.prototype
  474. *
  475. * @type {Globe}
  476. */
  477. globe : {
  478. get: function() {
  479. return this._globe;
  480. },
  481. set: function(globe) {
  482. this._globe = this._globe && this._globe.destroy();
  483. this._globe = globe;
  484. }
  485. },
  486. /**
  487. * Gets the collection of primitives.
  488. * @memberof Scene.prototype
  489. *
  490. * @type {PrimitiveCollection}
  491. * @readonly
  492. */
  493. primitives : {
  494. get : function() {
  495. return this._primitives;
  496. }
  497. },
  498. /**
  499. * Gets the camera.
  500. * @memberof Scene.prototype
  501. *
  502. * @type {Camera}
  503. * @readonly
  504. */
  505. camera : {
  506. get : function() {
  507. return this._camera;
  508. }
  509. },
  510. // TODO: setCamera
  511. /**
  512. * Gets the controller for camera input handling.
  513. * @memberof Scene.prototype
  514. *
  515. * @type {ScreenSpaceCameraController}
  516. * @readonly
  517. */
  518. screenSpaceCameraController : {
  519. get : function() {
  520. return this._screenSpaceCameraController;
  521. }
  522. },
  523. /**
  524. * Get the map projection to use in 2D and Columbus View modes.
  525. * @memberof Scene.prototype
  526. *
  527. * @type {MapProjection}
  528. * @readonly
  529. *
  530. * @default new GeographicProjection()
  531. */
  532. mapProjection : {
  533. get: function() {
  534. return this._mapProjection;
  535. }
  536. },
  537. /**
  538. * Gets state information about the current scene. If called outside of a primitive's <code>update</code>
  539. * function, the previous frame's state is returned.
  540. * @memberof Scene.prototype
  541. *
  542. * @type {FrameState}
  543. * @readonly
  544. *
  545. * @private
  546. */
  547. frameState : {
  548. get: function() {
  549. return this._frameState;
  550. }
  551. },
  552. /**
  553. * Gets the collection of tweens taking place in the scene.
  554. * @memberof Scene.prototype
  555. *
  556. * @type {TweenCollection}
  557. * @readonly
  558. *
  559. * @private
  560. */
  561. tweens : {
  562. get : function() {
  563. return this._tweens;
  564. }
  565. },
  566. /**
  567. * Gets the collection of image layers that will be rendered on the globe.
  568. * @memberof Scene.prototype
  569. *
  570. * @type {ImageryLayerCollection}
  571. * @readonly
  572. */
  573. imageryLayers : {
  574. get : function() {
  575. return this.globe.imageryLayers;
  576. }
  577. },
  578. /**
  579. * The terrain provider providing surface geometry for the globe.
  580. * @memberof Scene.prototype
  581. *
  582. * @type {TerrainProvider}
  583. */
  584. terrainProvider : {
  585. get : function() {
  586. return this.globe.terrainProvider;
  587. },
  588. set : function(terrainProvider) {
  589. this.globe.terrainProvider = terrainProvider;
  590. }
  591. },
  592. /**
  593. * Gets the event that will be raised when an error is thrown inside the <code>render</code> function.
  594. * The Scene instance and the thrown error are the only two parameters passed to the event handler.
  595. * By default, errors are not rethrown after this event is raised, but that can be changed by setting
  596. * the <code>rethrowRenderErrors</code> property.
  597. * @memberof Scene.prototype
  598. *
  599. * @type {Event}
  600. * @readonly
  601. */
  602. renderError : {
  603. get : function() {
  604. return this._renderError;
  605. }
  606. },
  607. /**
  608. * Gets the event that will be raised at the start of each call to <code>render</code>. Subscribers to the event
  609. * receive the Scene instance as the first parameter and the current time as the second parameter.
  610. * @memberof Scene.prototype
  611. *
  612. * @type {Event}
  613. * @readonly
  614. */
  615. preRender : {
  616. get : function() {
  617. return this._preRender;
  618. }
  619. },
  620. /**
  621. * Gets the event that will be raised at the end of each call to <code>render</code>. Subscribers to the event
  622. * receive the Scene instance as the first parameter and the current time as the second parameter.
  623. * @memberof Scene.prototype
  624. *
  625. * @type {Event}
  626. * @readonly
  627. */
  628. postRender : {
  629. get : function() {
  630. return this._postRender;
  631. }
  632. },
  633. /**
  634. * @memberof Scene.prototype
  635. * @private
  636. * @readonly
  637. */
  638. context : {
  639. get : function() {
  640. return this._context;
  641. }
  642. },
  643. /**
  644. * This property is for debugging only; it is not for production use.
  645. * <p>
  646. * When {@link Scene.debugShowFrustums} is <code>true</code>, this contains
  647. * properties with statistics about the number of command execute per frustum.
  648. * <code>totalCommands</code> is the total number of commands executed, ignoring
  649. * overlap. <code>commandsInFrustums</code> is an array with the number of times
  650. * commands are executed redundantly, e.g., how many commands overlap two or
  651. * three frustums.
  652. * </p>
  653. *
  654. * @memberof Scene.prototype
  655. *
  656. * @type {Object}
  657. * @readonly
  658. *
  659. * @default undefined
  660. */
  661. debugFrustumStatistics : {
  662. get : function() {
  663. return this._debugFrustumStatistics;
  664. }
  665. },
  666. /**
  667. * Gets whether or not the scene is optimized for 3D only viewing.
  668. * @memberof Scene.prototype
  669. * @type {Boolean}
  670. * @readonly
  671. */
  672. scene3DOnly : {
  673. get : function() {
  674. return this._frameState.scene3DOnly;
  675. }
  676. },
  677. /**
  678. * Gets whether or not the scene has order independent translucency enabled.
  679. * Note that this only reflects the original construction option, and there are
  680. * other factors that could prevent OIT from functioning on a given system configuration.
  681. * @memberof Scene.prototype
  682. * @type {Boolean}
  683. * @readonly
  684. */
  685. orderIndependentTranslucency : {
  686. get : function() {
  687. return defined(this._oit);
  688. }
  689. },
  690. /**
  691. * Gets the unique identifier for this scene.
  692. * @memberof Scene.prototype
  693. * @type {String}
  694. * @readonly
  695. */
  696. id : {
  697. get : function() {
  698. return this._id;
  699. }
  700. },
  701. /**
  702. * Gets or sets the current mode of the scene.
  703. * @memberof Scene.prototype
  704. * @type {SceneMode}
  705. * @default {@link SceneMode.SCENE3D}
  706. */
  707. mode : {
  708. get : function() {
  709. return this._mode;
  710. },
  711. set : function(value) {
  712. if (this.scene3DOnly && value !== SceneMode.SCENE3D) {
  713. throw new DeveloperError('Only SceneMode.SCENE3D is valid when scene3DOnly is true.');
  714. }
  715. this._mode = value;
  716. }
  717. }
  718. });
  719. var scratchOccluderBoundingSphere = new BoundingSphere();
  720. var scratchOccluder;
  721. function getOccluder(scene) {
  722. // TODO: The occluder is the top-level globe. When we add
  723. // support for multiple central bodies, this should be the closest one.
  724. var globe = scene.globe;
  725. if (scene._mode === SceneMode.SCENE3D && defined(globe)) {
  726. var ellipsoid = globe.ellipsoid;
  727. scratchOccluderBoundingSphere.radius = ellipsoid.minimumRadius;
  728. scratchOccluder = Occluder.fromBoundingSphere(scratchOccluderBoundingSphere, scene._camera.positionWC, scratchOccluder);
  729. return scratchOccluder;
  730. }
  731. return undefined;
  732. }
  733. function clearPasses(passes) {
  734. passes.render = false;
  735. passes.pick = false;
  736. }
  737. function updateFrameState(scene, frameNumber, time) {
  738. var camera = scene._camera;
  739. var frameState = scene._frameState;
  740. frameState.mode = scene._mode;
  741. frameState.morphTime = scene.morphTime;
  742. frameState.mapProjection = scene.mapProjection;
  743. frameState.frameNumber = frameNumber;
  744. frameState.time = JulianDate.clone(time, frameState.time);
  745. frameState.camera = camera;
  746. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  747. frameState.occluder = getOccluder(scene);
  748. frameState.afterRender.length = 0;
  749. clearPasses(frameState.passes);
  750. }
  751. function updateFrustums(near, far, farToNearRatio, numFrustums, frustumCommandsList) {
  752. frustumCommandsList.length = numFrustums;
  753. for (var m = 0; m < numFrustums; ++m) {
  754. var curNear = Math.max(near, Math.pow(farToNearRatio, m) * near);
  755. var curFar = Math.min(far, farToNearRatio * curNear);
  756. var frustumCommands = frustumCommandsList[m];
  757. if (!defined(frustumCommands)) {
  758. frustumCommands = frustumCommandsList[m] = new FrustumCommands(curNear, curFar);
  759. } else {
  760. frustumCommands.near = curNear;
  761. frustumCommands.far = curFar;
  762. }
  763. }
  764. }
  765. function insertIntoBin(scene, command, distance) {
  766. if (scene.debugShowFrustums) {
  767. command.debugOverlappingFrustums = 0;
  768. }
  769. var frustumCommandsList = scene._frustumCommandsList;
  770. var length = frustumCommandsList.length;
  771. for (var i = 0; i < length; ++i) {
  772. var frustumCommands = frustumCommandsList[i];
  773. var curNear = frustumCommands.near;
  774. var curFar = frustumCommands.far;
  775. if (distance.start > curFar) {
  776. continue;
  777. }
  778. if (distance.stop < curNear) {
  779. break;
  780. }
  781. if (command.pass === Pass.OPAQUE || command instanceof ClearCommand) {
  782. frustumCommands.opaqueCommands[frustumCommands.opaqueIndex++] = command;
  783. } else if (command.pass === Pass.TRANSLUCENT){
  784. frustumCommands.translucentCommands[frustumCommands.translucentIndex++] = command;
  785. }
  786. if (scene.debugShowFrustums) {
  787. command.debugOverlappingFrustums |= (1 << i);
  788. }
  789. if (command.executeInClosestFrustum) {
  790. break;
  791. }
  792. }
  793. if (scene.debugShowFrustums) {
  794. var cf = scene._debugFrustumStatistics.commandsInFrustums;
  795. cf[command.debugOverlappingFrustums] = defined(cf[command.debugOverlappingFrustums]) ? cf[command.debugOverlappingFrustums] + 1 : 1;
  796. ++scene._debugFrustumStatistics.totalCommands;
  797. }
  798. }
  799. var scratchCullingVolume = new CullingVolume();
  800. var distances = new Interval();
  801. function createPotentiallyVisibleSet(scene) {
  802. var commandList = scene._commandList;
  803. var overlayList = scene._overlayCommandList;
  804. var cullingVolume = scene._frameState.cullingVolume;
  805. var camera = scene._camera;
  806. var direction = camera.directionWC;
  807. var position = camera.positionWC;
  808. if (scene.debugShowFrustums) {
  809. scene._debugFrustumStatistics = {
  810. totalCommands : 0,
  811. commandsInFrustums : {}
  812. };
  813. }
  814. var frustumCommandsList = scene._frustumCommandsList;
  815. var numberOfFrustums = frustumCommandsList.length;
  816. for (var n = 0; n < numberOfFrustums; ++n) {
  817. frustumCommandsList[n].opaqueIndex = 0;
  818. frustumCommandsList[n].translucentIndex = 0;
  819. }
  820. var near = Number.MAX_VALUE;
  821. var far = Number.MIN_VALUE;
  822. var undefBV = false;
  823. var occluder;
  824. if (scene._frameState.mode === SceneMode.SCENE3D) {
  825. occluder = scene._frameState.occluder;
  826. }
  827. // get user culling volume minus the far plane.
  828. var planes = scratchCullingVolume.planes;
  829. for (var m = 0; m < 5; ++m) {
  830. planes[m] = cullingVolume.planes[m];
  831. }
  832. cullingVolume = scratchCullingVolume;
  833. var length = commandList.length;
  834. for (var i = 0; i < length; ++i) {
  835. var command = commandList[i];
  836. var pass = command.pass;
  837. if (pass === Pass.OVERLAY) {
  838. overlayList.push(command);
  839. } else {
  840. var boundingVolume = command.boundingVolume;
  841. if (defined(boundingVolume)) {
  842. if (command.cull &&
  843. ((cullingVolume.computeVisibility(boundingVolume) === Intersect.OUTSIDE) ||
  844. (defined(occluder) && !occluder.isBoundingSphereVisible(boundingVolume)))) {
  845. continue;
  846. }
  847. distances = BoundingSphere.computePlaneDistances(boundingVolume, position, direction, distances);
  848. near = Math.min(near, distances.start);
  849. far = Math.max(far, distances.stop);
  850. } else {
  851. // Clear commands don't need a bounding volume - just add the clear to all frustums.
  852. // If another command has no bounding volume, though, we need to use the camera's
  853. // worst-case near and far planes to avoid clipping something important.
  854. distances.start = camera.frustum.near;
  855. distances.stop = camera.frustum.far;
  856. undefBV = !(command instanceof ClearCommand);
  857. }
  858. insertIntoBin(scene, command, distances);
  859. }
  860. }
  861. if (undefBV) {
  862. near = camera.frustum.near;
  863. far = camera.frustum.far;
  864. } else {
  865. // The computed near plane must be between the user defined near and far planes.
  866. // The computed far plane must between the user defined far and computed near.
  867. // This will handle the case where the computed near plane is further than the user defined far plane.
  868. near = Math.min(Math.max(near, camera.frustum.near), camera.frustum.far);
  869. far = Math.max(Math.min(far, camera.frustum.far), near);
  870. }
  871. // Exploit temporal coherence. If the frustums haven't changed much, use the frustums computed
  872. // last frame, else compute the new frustums and sort them by frustum again.
  873. var farToNearRatio = scene.farToNearRatio;
  874. var numFrustums = Math.ceil(Math.log(far / near) / Math.log(farToNearRatio));
  875. if (near !== Number.MAX_VALUE && (numFrustums !== numberOfFrustums || (frustumCommandsList.length !== 0 &&
  876. (near < frustumCommandsList[0].near || far > frustumCommandsList[numberOfFrustums - 1].far)))) {
  877. updateFrustums(near, far, farToNearRatio, numFrustums, frustumCommandsList);
  878. createPotentiallyVisibleSet(scene);
  879. }
  880. }
  881. function getAttributeLocations(shaderProgram) {
  882. var attributeLocations = {};
  883. var attributes = shaderProgram.vertexAttributes;
  884. for (var a in attributes) {
  885. if (attributes.hasOwnProperty(a)) {
  886. attributeLocations[a] = attributes[a].index;
  887. }
  888. }
  889. return attributeLocations;
  890. }
  891. function createDebugFragmentShaderProgram(command, scene, shaderProgram) {
  892. var context = scene.context;
  893. var sp = defaultValue(shaderProgram, command.shaderProgram);
  894. var fs = sp.fragmentShaderSource.clone();
  895. fs.sources = fs.sources.map(function(source) {
  896. source = source.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, 'void czm_Debug_main()');
  897. return source;
  898. });
  899. var newMain =
  900. 'void main() \n' +
  901. '{ \n' +
  902. ' czm_Debug_main(); \n';
  903. if (scene.debugShowCommands) {
  904. if (!defined(command._debugColor)) {
  905. command._debugColor = Color.fromRandom();
  906. }
  907. var c = command._debugColor;
  908. newMain += ' gl_FragColor.rgb *= vec3(' + c.red + ', ' + c.green + ', ' + c.blue + '); \n';
  909. }
  910. if (scene.debugShowFrustums) {
  911. // Support up to three frustums. If a command overlaps all
  912. // three, it's code is not changed.
  913. var r = (command.debugOverlappingFrustums & (1 << 0)) ? '1.0' : '0.0';
  914. var g = (command.debugOverlappingFrustums & (1 << 1)) ? '1.0' : '0.0';
  915. var b = (command.debugOverlappingFrustums & (1 << 2)) ? '1.0' : '0.0';
  916. newMain += ' gl_FragColor.rgb *= vec3(' + r + ', ' + g + ', ' + b + '); \n';
  917. }
  918. newMain += '}';
  919. fs.sources.push(newMain);
  920. var attributeLocations = getAttributeLocations(sp);
  921. return context.createShaderProgram(sp.vertexShaderSource, fs, attributeLocations);
  922. }
  923. function executeDebugCommand(command, scene, passState, renderState, shaderProgram) {
  924. if (defined(command.shaderProgram) || defined(shaderProgram)) {
  925. // Replace shader for frustum visualization
  926. var sp = createDebugFragmentShaderProgram(command, scene, shaderProgram);
  927. command.execute(scene.context, passState, renderState, sp);
  928. sp.destroy();
  929. }
  930. }
  931. var transformFrom2D = new Matrix4(0.0, 0.0, 1.0, 0.0,
  932. 1.0, 0.0, 0.0, 0.0,
  933. 0.0, 1.0, 0.0, 0.0,
  934. 0.0, 0.0, 0.0, 1.0);
  935. transformFrom2D = Matrix4.inverseTransformation(transformFrom2D, transformFrom2D);
  936. function executeCommand(command, scene, context, passState, renderState, shaderProgram, debugFramebuffer) {
  937. if ((defined(scene.debugCommandFilter)) && !scene.debugCommandFilter(command)) {
  938. return;
  939. }
  940. if (scene.debugShowCommands || scene.debugShowFrustums) {
  941. executeDebugCommand(command, scene, passState, renderState, shaderProgram);
  942. } else {
  943. command.execute(context, passState, renderState, shaderProgram);
  944. }
  945. if (command.debugShowBoundingVolume && (defined(command.boundingVolume))) {
  946. // Debug code to draw bounding volume for command. Not optimized!
  947. // Assumes bounding volume is a bounding sphere.
  948. if (defined(scene._debugSphere)) {
  949. scene._debugSphere.destroy();
  950. }
  951. var frameState = scene._frameState;
  952. var boundingVolume = command.boundingVolume;
  953. var radius = boundingVolume.radius;
  954. var center = boundingVolume.center;
  955. var geometry = GeometryPipeline.toWireframe(EllipsoidGeometry.createGeometry(new EllipsoidGeometry({
  956. radii : new Cartesian3(radius, radius, radius),
  957. vertexFormat : PerInstanceColorAppearance.FLAT_VERTEX_FORMAT
  958. })));
  959. if (frameState.mode !== SceneMode.SCENE3D) {
  960. center = Matrix4.multiplyByPoint(transformFrom2D, center, center);
  961. var projection = frameState.mapProjection;
  962. var centerCartographic = projection.unproject(center);
  963. center = projection.ellipsoid.cartographicToCartesian(centerCartographic);
  964. }
  965. scene._debugSphere = new Primitive({
  966. geometryInstances : new GeometryInstance({
  967. geometry : geometry,
  968. modelMatrix : Matrix4.multiplyByTranslation(Matrix4.IDENTITY, center, new Matrix4()),
  969. attributes : {
  970. color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0)
  971. }
  972. }),
  973. appearance : new PerInstanceColorAppearance({
  974. flat : true,
  975. translucent : false
  976. }),
  977. asynchronous : false
  978. });
  979. var commandList = [];
  980. scene._debugSphere.update(context, frameState, commandList);
  981. var framebuffer;
  982. if (defined(debugFramebuffer)) {
  983. framebuffer = passState.framebuffer;
  984. passState.framebuffer = debugFramebuffer;
  985. }
  986. commandList[0].execute(context, passState);
  987. if (defined(framebuffer)) {
  988. passState.framebuffer = framebuffer;
  989. }
  990. }
  991. }
  992. function isVisible(command, frameState) {
  993. if (!defined(command)) {
  994. return;
  995. }
  996. var occluder = (frameState.mode === SceneMode.SCENE3D) ? frameState.occluder: undefined;
  997. var cullingVolume = frameState.cullingVolume;
  998. // get user culling volume minus the far plane.
  999. var planes = scratchCullingVolume.planes;
  1000. for (var k = 0; k < 5; ++k) {
  1001. planes[k] = cullingVolume.planes[k];
  1002. }
  1003. cullingVolume = scratchCullingVolume;
  1004. var boundingVolume = command.boundingVolume;
  1005. return ((defined(command)) &&
  1006. ((!defined(command.boundingVolume)) ||
  1007. !command.cull ||
  1008. ((cullingVolume.computeVisibility(boundingVolume) !== Intersect.OUTSIDE) &&
  1009. (!defined(occluder) || occluder.isBoundingSphereVisible(boundingVolume)))));
  1010. }
  1011. function translucentCompare(a, b, position) {
  1012. return BoundingSphere.distanceSquaredTo(b.boundingVolume, position) - BoundingSphere.distanceSquaredTo(a.boundingVolume, position);
  1013. }
  1014. function executeTranslucentCommandsSorted(scene, executeFunction, passState, commands) {
  1015. var context = scene.context;
  1016. mergeSort(commands, translucentCompare, scene._camera.positionWC);
  1017. var length = commands.length;
  1018. for (var j = 0; j < length; ++j) {
  1019. executeFunction(commands[j], scene, context, passState);
  1020. }
  1021. }
  1022. var scratchPerspectiveFrustum = new PerspectiveFrustum();
  1023. var scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
  1024. var scratchOrthographicFrustum = new OrthographicFrustum();
  1025. function executeCommands(scene, passState, clearColor, picking) {
  1026. var frameState = scene._frameState;
  1027. var camera = scene._camera;
  1028. var context = scene.context;
  1029. var us = context.uniformState;
  1030. var frustum;
  1031. if (defined(camera.frustum.fov)) {
  1032. frustum = camera.frustum.clone(scratchPerspectiveFrustum);
  1033. } else if (defined(camera.frustum.infiniteProjectionMatrix)){
  1034. frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
  1035. } else {
  1036. frustum = camera.frustum.clone(scratchOrthographicFrustum);
  1037. }
  1038. if (defined(scene.sun) && scene.sunBloom !== scene._sunBloom) {
  1039. if (scene.sunBloom) {
  1040. scene._sunPostProcess = new SunPostProcess();
  1041. } else if(defined(scene._sunPostProcess)){
  1042. scene._sunPostProcess = scene._sunPostProcess.destroy();
  1043. }
  1044. scene._sunBloom = scene.sunBloom;
  1045. } else if (!defined(scene.sun) && defined(scene._sunPostProcess)) {
  1046. scene._sunPostProcess = scene._sunPostProcess.destroy();
  1047. scene._sunBloom = false;
  1048. }
  1049. var skyBoxCommand = (frameState.passes.render && defined(scene.skyBox)) ? scene.skyBox.update(context, frameState) : undefined;
  1050. var skyAtmosphereCommand = (frameState.passes.render && defined(scene.skyAtmosphere)) ? scene.skyAtmosphere.update(context, frameState) : undefined;
  1051. var sunCommand = (frameState.passes.render && defined(scene.sun)) ? scene.sun.update(scene) : undefined;
  1052. var sunVisible = isVisible(sunCommand, frameState);
  1053. var clear = scene._clearColorCommand;
  1054. Color.clone(clearColor, clear.color);
  1055. clear.execute(context, passState);
  1056. var renderTranslucentCommands = false;
  1057. var i;
  1058. var frustumCommandsList = scene._frustumCommandsList;
  1059. var numFrustums = frustumCommandsList.length;
  1060. for (i = 0; i < numFrustums; ++i) {
  1061. if (frustumCommandsList[i].translucentIndex > 0) {
  1062. renderTranslucentCommands = true;
  1063. break;
  1064. }
  1065. }
  1066. var useOIT = !picking && renderTranslucentCommands && defined(scene._oit) && scene._oit.isSupported();
  1067. if (useOIT) {
  1068. scene._oit.update(context);
  1069. scene._oit.clear(context, passState, clearColor);
  1070. useOIT = useOIT && scene._oit.isSupported();
  1071. }
  1072. var useFXAA = !picking && (scene.fxaa || (useOIT && scene.fxaaOrderIndependentTranslucency));
  1073. if (useFXAA) {
  1074. scene._fxaa.update(context);
  1075. scene._fxaa.clear(context, passState, clearColor);
  1076. }
  1077. var opaqueFramebuffer = passState.framebuffer;
  1078. if (useOIT) {
  1079. opaqueFramebuffer = scene._oit.getColorFramebuffer();
  1080. } else if (useFXAA) {
  1081. opaqueFramebuffer = scene._fxaa.getColorFramebuffer();
  1082. }
  1083. if (sunVisible && scene.sunBloom) {
  1084. passState.framebuffer = scene._sunPostProcess.update(context);
  1085. } else {
  1086. passState.framebuffer = opaqueFramebuffer;
  1087. }
  1088. // Ideally, we would render the sky box and atmosphere last for
  1089. // early-z, but we would have to draw it in each frustum
  1090. frustum.near = camera.frustum.near;
  1091. frustum.far = camera.frustum.far;
  1092. us.updateFrustum(frustum);
  1093. if (defined(skyBoxCommand)) {
  1094. executeCommand(skyBoxCommand, scene, context, passState);
  1095. }
  1096. if (defined(skyAtmosphereCommand)) {
  1097. executeCommand(skyAtmosphereCommand, scene, context, passState);
  1098. }
  1099. if (defined(sunCommand) && sunVisible) {
  1100. sunCommand.execute(context, passState);
  1101. if (scene.sunBloom) {
  1102. scene._sunPostProcess.execute(context, opaqueFramebuffer);
  1103. passState.framebuffer = opaqueFramebuffer;
  1104. }
  1105. }
  1106. var clearDepth = scene._depthClearCommand;
  1107. var executeTranslucentCommands;
  1108. if (useOIT) {
  1109. if (!defined(scene._executeOITFunction)) {
  1110. scene._executeOITFunction = function(scene, executeFunction, passState, commands) {
  1111. scene._oit.executeCommands(scene, executeFunction, passState, commands);
  1112. };
  1113. }
  1114. executeTranslucentCommands = scene._executeOITFunction;
  1115. } else {
  1116. executeTranslucentCommands = executeTranslucentCommandsSorted;
  1117. }
  1118. for (i = 0; i < numFrustums; ++i) {
  1119. var index = numFrustums - i - 1;
  1120. var frustumCommands = frustumCommandsList[index];
  1121. frustum.near = frustumCommands.near;
  1122. frustum.far = frustumCommands.far;
  1123. if (index !== 0) {
  1124. // Avoid tearing artifacts between adjacent frustums
  1125. frustum.near *= 0.99;
  1126. }
  1127. us.updateFrustum(frustum);
  1128. clearDepth.execute(context, passState);
  1129. var commands = frustumCommands.opaqueCommands;
  1130. var length = frustumCommands.opaqueIndex;
  1131. for (var j = 0; j < length; ++j) {
  1132. executeCommand(commands[j], scene, context, passState);
  1133. }
  1134. frustum.near = frustumCommands.near;
  1135. us.updateFrustum(frustum);
  1136. commands = frustumCommands.translucentCommands;
  1137. commands.length = frustumCommands.translucentIndex;
  1138. executeTranslucentCommands(scene, executeCommand, passState, commands);
  1139. }
  1140. if (useOIT) {
  1141. passState.framebuffer = useFXAA ? scene._fxaa.getColorFramebuffer() : undefined;
  1142. scene._oit.execute(context, passState);
  1143. }
  1144. if (useFXAA) {
  1145. passState.framebuffer = undefined;
  1146. scene._fxaa.execute(context, passState);
  1147. }
  1148. }
  1149. function executeOverlayCommands(scene, passState) {
  1150. var context = scene.context;
  1151. var commandList = scene._overlayCommandList;
  1152. var length = commandList.length;
  1153. for (var i = 0; i < length; ++i) {
  1154. commandList[i].execute(context, passState);
  1155. }
  1156. }
  1157. function updatePrimitives(scene) {
  1158. var context = scene.context;
  1159. var frameState = scene._frameState;
  1160. var commandList = scene._commandList;
  1161. if (scene._globe) {
  1162. scene._globe.update(context, frameState, commandList);
  1163. }
  1164. scene._primitives.update(context, frameState, commandList);
  1165. if (defined(scene.moon)) {
  1166. scene.moon.update(context, frameState, commandList);
  1167. }
  1168. }
  1169. function callAfterRenderFunctions(frameState) {
  1170. // Functions are queued up during primitive update and executed here in case
  1171. // the function modifies scene state that should remain constant over the frame.
  1172. var functions = frameState.afterRender;
  1173. for (var i = 0, length = functions.length; i < length; ++i) {
  1174. functions[i]();
  1175. }
  1176. functions.length = 0;
  1177. }
  1178. /**
  1179. * @private
  1180. */
  1181. Scene.prototype.initializeFrame = function() {
  1182. // Destroy released shaders once every 120 frames to avoid thrashing the cache
  1183. if (this._shaderFrameCount++ === 120) {
  1184. this._shaderFrameCount = 0;
  1185. this._context.shaderCache.destroyReleasedShaderPrograms();
  1186. }
  1187. this._tweens.update();
  1188. this._camera.update(this._mode);
  1189. this._screenSpaceCameraController.update();
  1190. };
  1191. function render(scene, time) {
  1192. if (!defined(time)) {
  1193. time = JulianDate.now();
  1194. }
  1195. scene._preRender.raiseEvent(scene, time);
  1196. var us = scene.context.uniformState;
  1197. var frameState = scene._frameState;
  1198. var frameNumber = CesiumMath.incrementWrap(frameState.frameNumber, 15000000.0, 1.0);
  1199. updateFrameState(scene, frameNumber, time);
  1200. frameState.passes.render = true;
  1201. frameState.creditDisplay.beginFrame();
  1202. var context = scene.context;
  1203. us.update(context, frameState);
  1204. scene._commandList.length = 0;
  1205. scene._overlayCommandList.length = 0;
  1206. updatePrimitives(scene);
  1207. createPotentiallyVisibleSet(scene);
  1208. var passState = scene._passState;
  1209. executeCommands(scene, passState, defaultValue(scene.backgroundColor, Color.BLACK));
  1210. executeOverlayCommands(scene, passState);
  1211. frameState.creditDisplay.endFrame();
  1212. if (scene.debugShowFramesPerSecond) {
  1213. if (!defined(scene._performanceDisplay)) {
  1214. var performanceContainer = document.createElement('div');
  1215. performanceContainer.className = 'cesium-performanceDisplay';
  1216. performanceContainer.style.position = 'absolute';
  1217. performanceContainer.style.top = '50px';
  1218. performanceContainer.style.right = '10px';
  1219. var container = scene._canvas.parentNode;
  1220. container.appendChild(performanceContainer);
  1221. var performanceDisplay = new PerformanceDisplay({container: performanceContainer});
  1222. scene._performanceDisplay = performanceDisplay;
  1223. scene._performanceContainer = performanceContainer;
  1224. }
  1225. scene._performanceDisplay.update();
  1226. } else if (defined(scene._performanceDisplay)) {
  1227. scene._performanceDisplay = scene._performanceDisplay && scene._performanceDisplay.destroy();
  1228. scene._performanceContainer.parentNode.removeChild(scene._performanceContainer);
  1229. }
  1230. context.endFrame();
  1231. callAfterRenderFunctions(frameState);
  1232. scene._postRender.raiseEvent(scene, time);
  1233. }
  1234. /**
  1235. * @private
  1236. */
  1237. Scene.prototype.render = function(time) {
  1238. try {
  1239. render(this, time);
  1240. } catch (error) {
  1241. this._renderError.raiseEvent(this, error);
  1242. if (this.rethrowRenderErrors) {
  1243. throw error;
  1244. }
  1245. }
  1246. };
  1247. /**
  1248. * @private
  1249. */
  1250. Scene.prototype.clampLineWidth = function(width) {
  1251. var context = this._context;
  1252. return Math.max(context.minimumAliasedLineWidth, Math.min(width, context.maximumAliasedLineWidth));
  1253. };
  1254. var orthoPickingFrustum = new OrthographicFrustum();
  1255. var scratchOrigin = new Cartesian3();
  1256. var scratchDirection = new Cartesian3();
  1257. var scratchBufferDimensions = new Cartesian2();
  1258. var scratchPixelSize = new Cartesian2();
  1259. function getPickOrthographicCullingVolume(scene, drawingBufferPosition, width, height) {
  1260. var camera = scene._camera;
  1261. var frustum = camera.frustum;
  1262. var drawingBufferWidth = scene.drawingBufferWidth;
  1263. var drawingBufferHeight = scene.drawingBufferHeight;
  1264. var x = (2.0 / drawingBufferWidth) * drawingBufferPosition.x - 1.0;
  1265. x *= (frustum.right - frustum.left) * 0.5;
  1266. var y = (2.0 / drawingBufferHeight) * (drawingBufferHeight - drawingBufferPosition.y) - 1.0;
  1267. y *= (frustum.top - frustum.bottom) * 0.5;
  1268. var origin = Cartesian3.clone(camera.position, scratchOrigin);
  1269. Cartesian3.multiplyByScalar(camera.right, x, scratchDirection);
  1270. Cartesian3.add(scratchDirection, origin, origin);
  1271. Cartesian3.multiplyByScalar(camera.up, y, scratchDirection);
  1272. Cartesian3.add(scratchDirection, origin, origin);
  1273. Cartesian3.fromElements(origin.z, origin.x, origin.y, origin);
  1274. scratchBufferDimensions.x = drawingBufferWidth;
  1275. scratchBufferDimensions.y = drawingBufferHeight;
  1276. var pixelSize = frustum.getPixelSize(scratchBufferDimensions, undefined, scratchPixelSize);
  1277. var ortho = orthoPickingFrustum;
  1278. ortho.right = pixelSize.x * 0.5;
  1279. ortho.left = -ortho.right;
  1280. ortho.top = pixelSize.y * 0.5;
  1281. ortho.bottom = -ortho.top;
  1282. ortho.near = frustum.near;
  1283. ortho.far = frustum.far;
  1284. return ortho.computeCullingVolume(origin, camera.directionWC, camera.upWC);
  1285. }
  1286. var perspPickingFrustum = new PerspectiveOffCenterFrustum();
  1287. function getPickPerspectiveCullingVolume(scene, drawingBufferPosition, width, height) {
  1288. var camera = scene._camera;
  1289. var frustum = camera.frustum;
  1290. var near = frustum.near;
  1291. var drawingBufferWidth = scene.drawingBufferWidth;
  1292. var drawingBufferHeight = scene.drawingBufferHeight;
  1293. var tanPhi = Math.tan(frustum.fovy * 0.5);
  1294. var tanTheta = frustum.aspectRatio * tanPhi;
  1295. var x = (2.0 / drawingBufferWidth) * drawingBufferPosition.x - 1.0;
  1296. var y = (2.0 / drawingBufferHeight) * (drawingBufferHeight - drawingBufferPosition.y) - 1.0;
  1297. var xDir = x * near * tanTheta;
  1298. var yDir = y * near * tanPhi;
  1299. scratchBufferDimensions.x = drawingBufferWidth;
  1300. scratchBufferDimensions.y = drawingBufferHeight;
  1301. var pixelSize = frustum.getPixelSize(scratchBufferDimensions, undefined, scratchPixelSize);
  1302. var pickWidth = pixelSize.x * width * 0.5;
  1303. var pickHeight = pixelSize.y * height * 0.5;
  1304. var offCenter = perspPickingFrustum;
  1305. offCenter.top = yDir + pickHeight;
  1306. offCenter.bottom = yDir - pickHeight;
  1307. offCenter.right = xDir + pickWidth;
  1308. offCenter.left = xDir - pickWidth;
  1309. offCenter.near = near;
  1310. offCenter.far = frustum.far;
  1311. return offCenter.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  1312. }
  1313. function getPickCullingVolume(scene, drawingBufferPosition, width, height) {
  1314. if (scene._mode === SceneMode.SCENE2D) {
  1315. return getPickOrthographicCullingVolume(scene, drawingBufferPosition, width, height);
  1316. }
  1317. return getPickPerspectiveCullingVolume(scene, drawingBufferPosition, width, height);
  1318. }
  1319. // pick rectangle width and height, assumed odd
  1320. var rectangleWidth = 3.0;
  1321. var rectangleHeight = 3.0;
  1322. var scratchRectangle = new BoundingRectangle(0.0, 0.0, rectangleWidth, rectangleHeight);
  1323. var scratchColorZero = new Color(0.0, 0.0, 0.0, 0.0);
  1324. var scratchPosition = new Cartesian2();
  1325. /**
  1326. * Returns an object with a `primitive` property that contains the first (top) primitive in the scene
  1327. * at a particular window coordinate or undefined if nothing is at the location. Other properties may
  1328. * potentially be set depending on the type of primitive.
  1329. *
  1330. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  1331. * @returns {Object} Object containing the picked primitive.
  1332. *
  1333. * @exception {DeveloperError} windowPosition is undefined.
  1334. */
  1335. Scene.prototype.pick = function(windowPosition) {
  1336. //>>includeStart('debug', pragmas.debug);
  1337. if(!defined(windowPosition)) {
  1338. throw new DeveloperError('windowPosition is undefined.');
  1339. }
  1340. //>>includeEnd('debug');
  1341. var context = this._context;
  1342. var us = context.uniformState;
  1343. var frameState = this._frameState;
  1344. var drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(this, windowPosition, scratchPosition);
  1345. if (!defined(this._pickFramebuffer)) {
  1346. this._pickFramebuffer = context.createPickFramebuffer();
  1347. }
  1348. // Update with previous frame's number and time, assuming that render is called before picking.
  1349. updateFrameState(this, frameState.frameNumber, frameState.time);
  1350. frameState.cullingVolume = getPickCullingVolume(this, drawingBufferPosition, rectangleWidth, rectangleHeight);
  1351. frameState.passes.pick = true;
  1352. us.update(context, frameState);
  1353. this._commandList.length = 0;
  1354. updatePrimitives(this);
  1355. createPotentiallyVisibleSet(this);
  1356. scratchRectangle.x = drawingBufferPosition.x - ((rectangleWidth - 1.0) * 0.5);
  1357. scratchRectangle.y = (this.drawingBufferHeight - drawingBufferPosition.y) - ((rectangleHeight - 1.0) * 0.5);
  1358. executeCommands(this, this._pickFramebuffer.begin(scratchRectangle), scratchColorZero, true);
  1359. var object = this._pickFramebuffer.end(scratchRectangle);
  1360. context.endFrame();
  1361. callAfterRenderFunctions(frameState);
  1362. return object;
  1363. };
  1364. /**
  1365. * Returns a list of objects, each containing a `primitive` property, for all primitives at
  1366. * a particular window coordinate position. Other properties may also be set depending on the
  1367. * type of primitive. The primitives in the list are ordered by their visual order in the
  1368. * scene (front to back).
  1369. *
  1370. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  1371. * @returns {Object[]} Array of objects, each containing 1 picked primitives.
  1372. *
  1373. * @exception {DeveloperError} windowPosition is undefined.
  1374. *
  1375. * @example
  1376. * var pickedObjects = Cesium.Scene.drillPick(new Cesium.Cartesian2(100.0, 200.0));
  1377. */
  1378. Scene.prototype.drillPick = function(windowPosition) {
  1379. // PERFORMANCE_IDEA: This function calls each primitive's update for each pass. Instead
  1380. // we could update the primitive once, and then just execute their commands for each pass,
  1381. // and cull commands for picked primitives. e.g., base on the command's owner.
  1382. //>>includeStart('debug', pragmas.debug);
  1383. if (!defined(windowPosition)) {
  1384. throw new DeveloperError('windowPosition is undefined.');
  1385. }
  1386. //>>includeEnd('debug');
  1387. var pickedObjects = [];
  1388. var pickedResult = this.pick(windowPosition);
  1389. while (defined(pickedResult) && defined(pickedResult.primitive)) {
  1390. var primitive = pickedResult.primitive;
  1391. pickedObjects.push(pickedResult);
  1392. // hide the picked primitive and call picking again to get the next primitive
  1393. if (defined(primitive.show)) {
  1394. primitive.show = false;
  1395. } else if (typeof primitive.getGeometryInstanceAttributes === 'function') {
  1396. var attributes = primitive.getGeometryInstanceAttributes(pickedResult.id);
  1397. if (defined(attributes) && defined(attributes.show)) {
  1398. attributes.show = ShowGeometryInstanceAttribute.toValue(false);
  1399. }
  1400. }
  1401. pickedResult = this.pick(windowPosition);
  1402. }
  1403. // unhide the picked primitives
  1404. for (var i = 0; i < pickedObjects.length; ++i) {
  1405. var p = pickedObjects[i].primitive;
  1406. if (defined(p.show)) {
  1407. p.show = true;
  1408. } else if (typeof p.getGeometryInstanceAttributes === 'function') {
  1409. var attr = p.getGeometryInstanceAttributes(pickedObjects[i].id);
  1410. if (defined(attr) && defined(attr.show)) {
  1411. attr.show = ShowGeometryInstanceAttribute.toValue(true);
  1412. }
  1413. }
  1414. }
  1415. return pickedObjects;
  1416. };
  1417. /**
  1418. * Instantly completes an active transition.
  1419. */
  1420. Scene.prototype.completeMorph = function(){
  1421. this._transitioner.completeMorph();
  1422. };
  1423. /**
  1424. * Asynchronously transitions the scene to 2D.
  1425. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  1426. */
  1427. Scene.prototype.morphTo2D = function(duration) {
  1428. var ellipsoid;
  1429. var globe = this.globe;
  1430. if (defined(globe)) {
  1431. ellipsoid = globe.ellipsoid;
  1432. } else {
  1433. ellipsoid = this.mapProjection.ellipsoid;
  1434. }
  1435. duration = defaultValue(duration, 2.0);
  1436. this._transitioner.morphTo2D(duration, ellipsoid);
  1437. };
  1438. /**
  1439. * Asynchronously transitions the scene to Columbus View.
  1440. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  1441. */
  1442. Scene.prototype.morphToColumbusView = function(duration) {
  1443. var ellipsoid;
  1444. var globe = this.globe;
  1445. if (defined(globe)) {
  1446. ellipsoid = globe.ellipsoid;
  1447. } else {
  1448. ellipsoid = this.mapProjection.ellipsoid;
  1449. }
  1450. duration = defaultValue(duration, 2.0);
  1451. this._transitioner.morphToColumbusView(duration, ellipsoid);
  1452. };
  1453. /**
  1454. * Asynchronously transitions the scene to 3D.
  1455. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  1456. */
  1457. Scene.prototype.morphTo3D = function(duration) {
  1458. var ellipsoid;
  1459. var globe = this.globe;
  1460. if (defined(globe)) {
  1461. ellipsoid = globe.ellipsoid;
  1462. } else {
  1463. ellipsoid = this.mapProjection.ellipsoid;
  1464. }
  1465. duration = defaultValue(duration, 2.0);
  1466. this._transitioner.morphTo3D(duration, ellipsoid);
  1467. };
  1468. /**
  1469. * Returns true if this object was destroyed; otherwise, false.
  1470. * <br /><br />
  1471. * If this object was destroyed, it should not be used; calling any function other than
  1472. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  1473. *
  1474. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  1475. *
  1476. * @see Scene#destroy
  1477. */
  1478. Scene.prototype.isDestroyed = function() {
  1479. return false;
  1480. };
  1481. /**
  1482. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  1483. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  1484. * <br /><br />
  1485. * Once an object is destroyed, it should not be used; calling any function other than
  1486. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  1487. * assign the return value (<code>undefined</code>) to the object as done in the example.
  1488. *
  1489. * @returns {undefined}
  1490. *
  1491. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  1492. *
  1493. * @see Scene#isDestroyed
  1494. *
  1495. * @example
  1496. * scene = scene && scene.destroy();
  1497. */
  1498. Scene.prototype.destroy = function() {
  1499. this._tweens.removeAll();
  1500. this._screenSpaceCameraController = this._screenSpaceCameraController && this._screenSpaceCameraController.destroy();
  1501. this._pickFramebuffer = this._pickFramebuffer && this._pickFramebuffer.destroy();
  1502. this._primitives = this._primitives && this._primitives.destroy();
  1503. this._globe = this._globe && this._globe.destroy();
  1504. this.skyBox = this.skyBox && this.skyBox.destroy();
  1505. this.skyAtmosphere = this.skyAtmosphere && this.skyAtmosphere.destroy();
  1506. this._debugSphere = this._debugSphere && this._debugSphere.destroy();
  1507. this.sun = this.sun && this.sun.destroy();
  1508. this._sunPostProcess = this._sunPostProcess && this._sunPostProcess.destroy();
  1509. this._transitioner.destroy();
  1510. if (defined(this._oit)) {
  1511. this._oit.destroy();
  1512. }
  1513. this._fxaa.destroy();
  1514. this._context = this._context && this._context.destroy();
  1515. this._frameState.creditDisplay.destroy();
  1516. if (defined(this._performanceDisplay)){
  1517. this._performanceDisplay = this._performanceDisplay && this._performanceDisplay.destroy();
  1518. this._performanceContainer.parentNode.removeChild(this._performanceContainer);
  1519. }
  1520. return destroyObject(this);
  1521. };
  1522. return Scene;
  1523. });