Scene.js 155 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900
  1. import BoundingRectangle from '../Core/BoundingRectangle.js';
  2. import BoundingSphere from '../Core/BoundingSphere.js';
  3. import BoxGeometry from '../Core/BoxGeometry.js';
  4. import Cartesian3 from '../Core/Cartesian3.js';
  5. import Cartographic from '../Core/Cartographic.js';
  6. import Color from '../Core/Color.js';
  7. import ColorGeometryInstanceAttribute from '../Core/ColorGeometryInstanceAttribute.js';
  8. import createGuid from '../Core/createGuid.js';
  9. import CullingVolume from '../Core/CullingVolume.js';
  10. import defaultValue from '../Core/defaultValue.js';
  11. import defined from '../Core/defined.js';
  12. import defineProperties from '../Core/defineProperties.js';
  13. import destroyObject from '../Core/destroyObject.js';
  14. import DeveloperError from '../Core/DeveloperError.js';
  15. import EllipsoidGeometry from '../Core/EllipsoidGeometry.js';
  16. import Event from '../Core/Event.js';
  17. import GeographicProjection from '../Core/GeographicProjection.js';
  18. import GeometryInstance from '../Core/GeometryInstance.js';
  19. import GeometryPipeline from '../Core/GeometryPipeline.js';
  20. import Intersect from '../Core/Intersect.js';
  21. import JulianDate from '../Core/JulianDate.js';
  22. import CesiumMath from '../Core/Math.js';
  23. import Matrix4 from '../Core/Matrix4.js';
  24. import mergeSort from '../Core/mergeSort.js';
  25. import Occluder from '../Core/Occluder.js';
  26. import OrthographicFrustum from '../Core/OrthographicFrustum.js';
  27. import OrthographicOffCenterFrustum from '../Core/OrthographicOffCenterFrustum.js';
  28. import PerspectiveFrustum from '../Core/PerspectiveFrustum.js';
  29. import PerspectiveOffCenterFrustum from '../Core/PerspectiveOffCenterFrustum.js';
  30. import RequestScheduler from '../Core/RequestScheduler.js';
  31. import TaskProcessor from '../Core/TaskProcessor.js';
  32. import Transforms from '../Core/Transforms.js';
  33. import ClearCommand from '../Renderer/ClearCommand.js';
  34. import ComputeEngine from '../Renderer/ComputeEngine.js';
  35. import Context from '../Renderer/Context.js';
  36. import ContextLimits from '../Renderer/ContextLimits.js';
  37. import DrawCommand from '../Renderer/DrawCommand.js';
  38. import Pass from '../Renderer/Pass.js';
  39. import RenderState from '../Renderer/RenderState.js';
  40. import ShaderProgram from '../Renderer/ShaderProgram.js';
  41. import ShaderSource from '../Renderer/ShaderSource.js';
  42. import BrdfLutGenerator from './BrdfLutGenerator.js';
  43. import Camera from './Camera.js';
  44. import Cesium3DTilePass from './Cesium3DTilePass.js';
  45. import Cesium3DTilePassState from './Cesium3DTilePassState.js';
  46. import CreditDisplay from './CreditDisplay.js';
  47. import DebugCameraPrimitive from './DebugCameraPrimitive.js';
  48. import DepthPlane from './DepthPlane.js';
  49. import DerivedCommand from './DerivedCommand.js';
  50. import DeviceOrientationCameraController from './DeviceOrientationCameraController.js';
  51. import Fog from './Fog.js';
  52. import FrameState from './FrameState.js';
  53. import GlobeDepth from './GlobeDepth.js';
  54. import InvertClassification from './InvertClassification.js';
  55. import JobScheduler from './JobScheduler.js';
  56. import MapMode2D from './MapMode2D.js';
  57. import OctahedralProjectedCubeMap from './OctahedralProjectedCubeMap.js';
  58. import PerformanceDisplay from './PerformanceDisplay.js';
  59. import PerInstanceColorAppearance from './PerInstanceColorAppearance.js';
  60. import Picking from './Picking.js';
  61. import PostProcessStageCollection from './PostProcessStageCollection.js';
  62. import Primitive from './Primitive.js';
  63. import PrimitiveCollection from './PrimitiveCollection.js';
  64. import SceneMode from './SceneMode.js';
  65. import SceneTransforms from './SceneTransforms.js';
  66. import SceneTransitioner from './SceneTransitioner.js';
  67. import ScreenSpaceCameraController from './ScreenSpaceCameraController.js';
  68. import ShadowMap from './ShadowMap.js';
  69. import StencilConstants from './StencilConstants.js';
  70. import SunPostProcess from './SunPostProcess.js';
  71. import TweenCollection from './TweenCollection.js';
  72. import View from './View.js';
  73. var requestRenderAfterFrame = function (scene) {
  74. return function () {
  75. scene.frameState.afterRender.push(function() {
  76. scene.requestRender();
  77. });
  78. };
  79. };
  80. /**
  81. * The container for all 3D graphical objects and state in a Cesium virtual scene. Generally,
  82. * a scene is not created directly; instead, it is implicitly created by {@link CesiumWidget}.
  83. * <p>
  84. * <em><code>contextOptions</code> parameter details:</em>
  85. * </p>
  86. * <p>
  87. * The default values are:
  88. * <code>
  89. * {
  90. * webgl : {
  91. * alpha : false,
  92. * depth : true,
  93. * stencil : false,
  94. * antialias : true,
  95. * premultipliedAlpha : true,
  96. * preserveDrawingBuffer : false,
  97. * failIfMajorPerformanceCaveat : false
  98. * },
  99. * allowTextureFilterAnisotropic : true
  100. * }
  101. * </code>
  102. * </p>
  103. * <p>
  104. * The <code>webgl</code> property corresponds to the {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
  105. * object used to create the WebGL context.
  106. * </p>
  107. * <p>
  108. * <code>webgl.alpha</code> defaults to false, which can improve performance compared to the standard WebGL default
  109. * of true. If an application needs to composite Cesium above other HTML elements using alpha-blending, set
  110. * <code>webgl.alpha</code> to true.
  111. * </p>
  112. * <p>
  113. * The other <code>webgl</code> properties match the WebGL defaults for {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}.
  114. * </p>
  115. * <p>
  116. * <code>allowTextureFilterAnisotropic</code> defaults to true, which enables anisotropic texture filtering when the
  117. * WebGL extension is supported. Setting this to false will improve performance, but hurt visual quality, especially for horizon views.
  118. * </p>
  119. *
  120. * @alias Scene
  121. * @constructor
  122. *
  123. * @param {Object} [options] Object with the following properties:
  124. * @param {Canvas} options.canvas The HTML canvas element to create the scene for.
  125. * @param {Object} [options.contextOptions] Context and WebGL creation properties. See details above.
  126. * @param {Element} [options.creditContainer] The HTML element in which the credits will be displayed.
  127. * @param {Element} [options.creditViewport] The HTML element in which to display the credit popup. If not specified, the viewport will be a added as a sibling of the canvas.
  128. * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes.
  129. * @param {Boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
  130. * @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.
  131. * @param {Number} [options.terrainExaggeration=1.0] A scalar used to exaggerate the terrain. Note that terrain exaggeration will not modify any other primitive as they are positioned relative to the ellipsoid.
  132. * @param {Boolean} [options.shadows=false] Determines if shadows are cast by the sun.
  133. * @param {MapMode2D} [options.mapMode2D=MapMode2D.INFINITE_SCROLL] Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  134. * @param {Boolean} [options.requestRenderMode=false] If true, rendering a frame will only occur when needed as determined by changes within the scene. Enabling improves performance of the application, but requires using {@link Scene#requestRender} to render a new frame explicitly in this mode. This will be necessary in many cases after making changes to the scene in other parts of the API. See {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}.
  135. * @param {Number} [options.maximumRenderTimeChange=0.0] If requestRenderMode is true, this value defines the maximum change in simulation time allowed before a render is requested. See {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}.
  136. *
  137. * @see CesiumWidget
  138. * @see {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
  139. *
  140. * @exception {DeveloperError} options and options.canvas are required.
  141. *
  142. * @example
  143. * // Create scene without anisotropic texture filtering
  144. * var scene = new Cesium.Scene({
  145. * canvas : canvas,
  146. * contextOptions : {
  147. * allowTextureFilterAnisotropic : false
  148. * }
  149. * });
  150. */
  151. function Scene(options) {
  152. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  153. var canvas = options.canvas;
  154. var contextOptions = options.contextOptions;
  155. var creditContainer = options.creditContainer;
  156. var creditViewport = options.creditViewport;
  157. //>>includeStart('debug', pragmas.debug);
  158. if (!defined(canvas)) {
  159. throw new DeveloperError('options and options.canvas are required.');
  160. }
  161. //>>includeEnd('debug');
  162. var hasCreditContainer = defined(creditContainer);
  163. var context = new Context(canvas, contextOptions);
  164. if (!hasCreditContainer) {
  165. creditContainer = document.createElement('div');
  166. creditContainer.style.position = 'absolute';
  167. creditContainer.style.bottom = '0';
  168. creditContainer.style['text-shadow'] = '0 0 2px #000000';
  169. creditContainer.style.color = '#ffffff';
  170. creditContainer.style['font-size'] = '10px';
  171. creditContainer.style['padding-right'] = '5px';
  172. canvas.parentNode.appendChild(creditContainer);
  173. }
  174. if (!defined(creditViewport)) {
  175. creditViewport = canvas.parentNode;
  176. }
  177. this._id = createGuid();
  178. this._jobScheduler = new JobScheduler();
  179. this._frameState = new FrameState(context, new CreditDisplay(creditContainer, ' • ', creditViewport), this._jobScheduler);
  180. this._frameState.scene3DOnly = defaultValue(options.scene3DOnly, false);
  181. this._removeCreditContainer = !hasCreditContainer;
  182. this._creditContainer = creditContainer;
  183. this._canvas = canvas;
  184. this._context = context;
  185. this._computeEngine = new ComputeEngine(context);
  186. this._globe = undefined;
  187. this._primitives = new PrimitiveCollection();
  188. this._groundPrimitives = new PrimitiveCollection();
  189. this._logDepthBuffer = context.fragmentDepth;
  190. this._logDepthBufferDirty = true;
  191. this._tweens = new TweenCollection();
  192. this._shaderFrameCount = 0;
  193. this._sunPostProcess = undefined;
  194. this._computeCommandList = [];
  195. this._overlayCommandList = [];
  196. this._useOIT = defaultValue(options.orderIndependentTranslucency, true);
  197. this._executeOITFunction = undefined;
  198. this._depthPlane = new DepthPlane();
  199. this._clearColorCommand = new ClearCommand({
  200. color : new Color(),
  201. stencil : 0,
  202. owner : this
  203. });
  204. this._depthClearCommand = new ClearCommand({
  205. depth : 1.0,
  206. owner : this
  207. });
  208. this._stencilClearCommand = new ClearCommand({
  209. stencil : 0
  210. });
  211. this._classificationStencilClearCommand = new ClearCommand({
  212. stencil : 0,
  213. renderState : RenderState.fromCache({
  214. stencilMask : StencilConstants.CLASSIFICATION_MASK
  215. })
  216. });
  217. this._depthOnlyRenderStateCache = {};
  218. this._transitioner = new SceneTransitioner(this);
  219. this._preUpdate = new Event();
  220. this._postUpdate = new Event();
  221. this._renderError = new Event();
  222. this._preRender = new Event();
  223. this._postRender = new Event();
  224. this._minimumDisableDepthTestDistance = 0.0;
  225. /**
  226. * Exceptions occurring in <code>render</code> are always caught in order to raise the
  227. * <code>renderError</code> event. If this property is true, the error is rethrown
  228. * after the event is raised. If this property is false, the <code>render</code> function
  229. * returns normally after raising the event.
  230. *
  231. * @type {Boolean}
  232. * @default false
  233. */
  234. this.rethrowRenderErrors = false;
  235. /**
  236. * Determines whether or not to instantly complete the
  237. * scene transition animation on user input.
  238. *
  239. * @type {Boolean}
  240. * @default true
  241. */
  242. this.completeMorphOnUserInput = true;
  243. /**
  244. * The event fired at the beginning of a scene transition.
  245. * @type {Event}
  246. * @default Event()
  247. */
  248. this.morphStart = new Event();
  249. /**
  250. * The event fired at the completion of a scene transition.
  251. * @type {Event}
  252. * @default Event()
  253. */
  254. this.morphComplete = new Event();
  255. /**
  256. * The {@link SkyBox} used to draw the stars.
  257. *
  258. * @type {SkyBox}
  259. * @default undefined
  260. *
  261. * @see Scene#backgroundColor
  262. */
  263. this.skyBox = undefined;
  264. /**
  265. * The sky atmosphere drawn around the globe.
  266. *
  267. * @type {SkyAtmosphere}
  268. * @default undefined
  269. */
  270. this.skyAtmosphere = undefined;
  271. /**
  272. * The {@link Sun}.
  273. *
  274. * @type {Sun}
  275. * @default undefined
  276. */
  277. this.sun = undefined;
  278. /**
  279. * Uses a bloom filter on the sun when enabled.
  280. *
  281. * @type {Boolean}
  282. * @default true
  283. */
  284. this.sunBloom = true;
  285. this._sunBloom = undefined;
  286. /**
  287. * The {@link Moon}
  288. *
  289. * @type Moon
  290. * @default undefined
  291. */
  292. this.moon = undefined;
  293. /**
  294. * The background color, which is only visible if there is no sky box, i.e., {@link Scene#skyBox} is undefined.
  295. *
  296. * @type {Color}
  297. * @default {@link Color.BLACK}
  298. *
  299. * @see Scene#skyBox
  300. */
  301. this.backgroundColor = Color.clone(Color.BLACK);
  302. this._mode = SceneMode.SCENE3D;
  303. this._mapProjection = defined(options.mapProjection) ? options.mapProjection : new GeographicProjection();
  304. /**
  305. * The current morph transition time between 2D/Columbus View and 3D,
  306. * with 0.0 being 2D or Columbus View and 1.0 being 3D.
  307. *
  308. * @type {Number}
  309. * @default 1.0
  310. */
  311. this.morphTime = 1.0;
  312. /**
  313. * The far-to-near ratio of the multi-frustum when using a normal depth buffer.
  314. * <p>
  315. * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used
  316. * when {@link Scene#logarithmicDepthBuffer} is <code>false</code>. When <code>logarithmicDepthBuffer</code> is
  317. * <code>true</code>, use {@link Scene#logarithmicDepthFarToNearRatio}.
  318. * </p>
  319. *
  320. * @type {Number}
  321. * @default 1000.0
  322. */
  323. this.farToNearRatio = 1000.0;
  324. /**
  325. * The far-to-near ratio of the multi-frustum when using a logarithmic depth buffer.
  326. * <p>
  327. * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used
  328. * when {@link Scene#logarithmicDepthBuffer} is <code>true</code>. When <code>logarithmicDepthBuffer</code> is
  329. * <code>false</code>, use {@link Scene#farToNearRatio}.
  330. * </p>
  331. *
  332. * @type {Number}
  333. * @default 1e9
  334. */
  335. this.logarithmicDepthFarToNearRatio = 1e9;
  336. /**
  337. * Determines the uniform depth size in meters of each frustum of the multifrustum in 2D. If a primitive or model close
  338. * to the surface shows z-fighting, decreasing this will eliminate the artifact, but decrease performance. On the
  339. * other hand, increasing this will increase performance but may cause z-fighting among primitives close to the surface.
  340. *
  341. * @type {Number}
  342. * @default 1.75e6
  343. */
  344. this.nearToFarDistance2D = 1.75e6;
  345. /**
  346. * This property is for debugging only; it is not for production use.
  347. * <p>
  348. * A function that determines what commands are executed. As shown in the examples below,
  349. * the function receives the command's <code>owner</code> as an argument, and returns a boolean indicating if the
  350. * command should be executed.
  351. * </p>
  352. * <p>
  353. * The default is <code>undefined</code>, indicating that all commands are executed.
  354. * </p>
  355. *
  356. * @type Function
  357. *
  358. * @default undefined
  359. *
  360. * @example
  361. * // Do not execute any commands.
  362. * scene.debugCommandFilter = function(command) {
  363. * return false;
  364. * };
  365. *
  366. * // Execute only the billboard's commands. That is, only draw the billboard.
  367. * var billboards = new Cesium.BillboardCollection();
  368. * scene.debugCommandFilter = function(command) {
  369. * return command.owner === billboards;
  370. * };
  371. */
  372. this.debugCommandFilter = undefined;
  373. /**
  374. * This property is for debugging only; it is not for production use.
  375. * <p>
  376. * When <code>true</code>, commands are randomly shaded. This is useful
  377. * for performance analysis to see what parts of a scene or model are
  378. * command-dense and could benefit from batching.
  379. * </p>
  380. *
  381. * @type Boolean
  382. *
  383. * @default false
  384. */
  385. this.debugShowCommands = false;
  386. /**
  387. * This property is for debugging only; it is not for production use.
  388. * <p>
  389. * When <code>true</code>, commands are shaded based on the frustums they
  390. * overlap. Commands in the closest frustum are tinted red, commands in
  391. * the next closest are green, and commands in the farthest frustum are
  392. * blue. If a command overlaps more than one frustum, the color components
  393. * are combined, e.g., a command overlapping the first two frustums is tinted
  394. * yellow.
  395. * </p>
  396. *
  397. * @type Boolean
  398. *
  399. * @default false
  400. */
  401. this.debugShowFrustums = false;
  402. /**
  403. * This property is for debugging only; it is not for production use.
  404. * <p>
  405. * Displays frames per second and time between frames.
  406. * </p>
  407. *
  408. * @type Boolean
  409. *
  410. * @default false
  411. */
  412. this.debugShowFramesPerSecond = false;
  413. /**
  414. * This property is for debugging only; it is not for production use.
  415. * <p>
  416. * Displays depth information for the indicated frustum.
  417. * </p>
  418. *
  419. * @type Boolean
  420. *
  421. * @default false
  422. */
  423. this.debugShowGlobeDepth = false;
  424. /**
  425. * This property is for debugging only; it is not for production use.
  426. * <p>
  427. * Indicates which frustum will have depth information displayed.
  428. * </p>
  429. *
  430. * @type Number
  431. *
  432. * @default 1
  433. */
  434. this.debugShowDepthFrustum = 1;
  435. /**
  436. * This property is for debugging only; it is not for production use.
  437. * <p>
  438. * When <code>true</code>, draws outlines to show the boundaries of the camera frustums
  439. * </p>
  440. *
  441. * @type Boolean
  442. *
  443. * @default false
  444. */
  445. this.debugShowFrustumPlanes = false;
  446. this._debugShowFrustumPlanes = false;
  447. this._debugFrustumPlanes = undefined;
  448. /**
  449. * When <code>true</code>, enables picking using the depth buffer.
  450. *
  451. * @type Boolean
  452. * @default true
  453. */
  454. this.useDepthPicking = true;
  455. /**
  456. * When <code>true</code>, enables picking translucent geometry using the depth buffer. Note that {@link Scene#useDepthPicking} must also be true for enabling this to work.
  457. *
  458. * <p>
  459. * Render must be called between picks.
  460. * <br>There is a decrease in performance when enabled. There are extra draw calls to write depth for
  461. * translucent geometry.
  462. * </p>
  463. *
  464. * @example
  465. * // picking the position of a translucent primitive
  466. * viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
  467. * var pickedFeature = viewer.scene.pick(movement.position);
  468. * if (!Cesium.defined(pickedFeature)) {
  469. * // nothing picked
  470. * return;
  471. * }
  472. * viewer.scene.render();
  473. * var worldPosition = viewer.scene.pickPosition(movement.position);
  474. * }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  475. *
  476. * @type {Boolean}
  477. * @default false
  478. */
  479. this.pickTranslucentDepth = false;
  480. /**
  481. * The time in milliseconds to wait before checking if the camera has not moved and fire the cameraMoveEnd event.
  482. * @type {Number}
  483. * @default 500.0
  484. * @private
  485. */
  486. this.cameraEventWaitTime = 500.0;
  487. /**
  488. * Blends the atmosphere to geometry far from the camera for horizon views. Allows for additional
  489. * performance improvements by rendering less geometry and dispatching less terrain requests.
  490. * @type {Fog}
  491. */
  492. this.fog = new Fog();
  493. this._sunCamera = new Camera(this);
  494. /**
  495. * The shadow map in the scene. When enabled, models, primitives, and the globe may cast and receive shadows.
  496. * By default the light source of the shadow map is the sun.
  497. * @type {ShadowMap}
  498. */
  499. this.shadowMap = new ShadowMap({
  500. context : context,
  501. lightCamera : this._sunCamera,
  502. enabled : defaultValue(options.shadows, false)
  503. });
  504. /**
  505. * When <code>false</code>, 3D Tiles will render normally. When <code>true</code>, classified 3D Tile geometry will render normally and
  506. * unclassified 3D Tile geometry will render with the color multiplied by {@link Scene#invertClassificationColor}.
  507. * @type {Boolean}
  508. * @default false
  509. */
  510. this.invertClassification = false;
  511. /**
  512. * The highlight color of unclassified 3D Tile geometry when {@link Scene#invertClassification} is <code>true</code>.
  513. * <p>When the color's alpha is less than 1.0, the unclassified portions of the 3D Tiles will not blend correctly with the classified positions of the 3D Tiles.</p>
  514. * <p>Also, when the color's alpha is less than 1.0, the WEBGL_depth_texture and EXT_frag_depth WebGL extensions must be supported.</p>
  515. * @type {Color}
  516. * @default Color.WHITE
  517. */
  518. this.invertClassificationColor = Color.clone(Color.WHITE);
  519. this._actualInvertClassificationColor = Color.clone(this._invertClassificationColor);
  520. this._invertClassification = new InvertClassification();
  521. /**
  522. * The focal length for use when with cardboard or WebVR.
  523. * @type {Number}
  524. */
  525. this.focalLength = undefined;
  526. /**
  527. * The eye separation distance in meters for use with cardboard or WebVR.
  528. * @type {Number}
  529. */
  530. this.eyeSeparation = undefined;
  531. /**
  532. * Post processing effects applied to the final render.
  533. * @type {PostProcessStageCollection}
  534. */
  535. this.postProcessStages = new PostProcessStageCollection();
  536. this._brdfLutGenerator = new BrdfLutGenerator();
  537. this._terrainExaggeration = defaultValue(options.terrainExaggeration, 1.0);
  538. this._performanceDisplay = undefined;
  539. this._debugVolume = undefined;
  540. this._screenSpaceCameraController = new ScreenSpaceCameraController(this);
  541. this._mapMode2D = defaultValue(options.mapMode2D, MapMode2D.INFINITE_SCROLL);
  542. // Keeps track of the state of a frame. FrameState is the state across
  543. // the primitives of the scene. This state is for internally keeping track
  544. // of celestial and environment effects that need to be updated/rendered in
  545. // a certain order as well as updating/tracking framebuffer usage.
  546. this._environmentState = {
  547. skyBoxCommand : undefined,
  548. skyAtmosphereCommand : undefined,
  549. sunDrawCommand : undefined,
  550. sunComputeCommand : undefined,
  551. moonCommand : undefined,
  552. isSunVisible : false,
  553. isMoonVisible : false,
  554. isReadyForAtmosphere : false,
  555. isSkyAtmosphereVisible : false,
  556. clearGlobeDepth : false,
  557. useDepthPlane : false,
  558. renderTranslucentDepthForPick : false,
  559. originalFramebuffer : undefined,
  560. useGlobeDepthFramebuffer : false,
  561. separatePrimitiveFramebuffer : false,
  562. useOIT : false,
  563. useInvertClassification : false,
  564. usePostProcess : false,
  565. usePostProcessSelected : false,
  566. useWebVR : false
  567. };
  568. this._useWebVR = false;
  569. this._cameraVR = undefined;
  570. this._aspectRatioVR = undefined;
  571. /**
  572. * When <code>true</code>, rendering a frame will only occur when needed as determined by changes within the scene.
  573. * Enabling improves performance of the application, but requires using {@link Scene#requestRender}
  574. * to render a new frame explicitly in this mode. This will be necessary in many cases after making changes
  575. * to the scene in other parts of the API.
  576. *
  577. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  578. * @see Scene#maximumRenderTimeChange
  579. * @see Scene#requestRender
  580. *
  581. * @type {Boolean}
  582. * @default false
  583. */
  584. this.requestRenderMode = defaultValue(options.requestRenderMode, false);
  585. this._renderRequested = true;
  586. /**
  587. * If {@link Scene#requestRenderMode} is <code>true</code>, this value defines the maximum change in
  588. * simulation time allowed before a render is requested. Lower values increase the number of frames rendered
  589. * and higher values decrease the number of frames rendered. If <code>undefined</code>, changes to
  590. * the simulation time will never request a render.
  591. * This value impacts the rate of rendering for changes in the scene like lighting, entity property updates,
  592. * and animations.
  593. *
  594. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  595. * @see Scene#requestRenderMode
  596. *
  597. * @type {Number}
  598. * @default 0.5
  599. */
  600. this.maximumRenderTimeChange = defaultValue(options.maximumRenderTimeChange, 0.0);
  601. this._lastRenderTime = undefined;
  602. this._frameRateMonitor = undefined;
  603. this._removeRequestListenerCallback = RequestScheduler.requestCompletedEvent.addEventListener(requestRenderAfterFrame(this));
  604. this._removeTaskProcessorListenerCallback = TaskProcessor.taskCompletedEvent.addEventListener(requestRenderAfterFrame(this));
  605. this._removeGlobeCallbacks = [];
  606. var viewport = new BoundingRectangle(0, 0, context.drawingBufferWidth, context.drawingBufferHeight);
  607. var camera = new Camera(this);
  608. if (this._logDepthBuffer) {
  609. camera.frustum.near = 0.1;
  610. camera.frustum.far = 10000000000.0;
  611. }
  612. /**
  613. * The camera view for the scene camera flight destination. Used for preloading flight destination tiles.
  614. * @type {Camera}
  615. * @private
  616. */
  617. this.preloadFlightCamera = new Camera(this);
  618. /**
  619. * The culling volume for the scene camera flight destination. Used for preloading flight destination tiles.
  620. * @type {CullingVolume}
  621. * @private
  622. */
  623. this.preloadFlightCullingVolume = undefined;
  624. this._picking = new Picking(this);
  625. this._defaultView = new View(this, camera, viewport);
  626. this._view = this._defaultView;
  627. this._hdr = undefined;
  628. this._hdrDirty = undefined;
  629. this.highDynamicRange = false;
  630. this.gamma = 2.2;
  631. this._sunColor = new Cartesian3(1.8, 1.85, 2.0);
  632. /**
  633. * The spherical harmonic coefficients for image-based lighting of PBR models.
  634. * @type {Cartesian3[]}
  635. */
  636. this.sphericalHarmonicCoefficients = undefined;
  637. /**
  638. * The url to the KTX file containing the specular environment map and convoluted mipmaps for image-based lighting of PBR models.
  639. * @type {String}
  640. */
  641. this.specularEnvironmentMaps = undefined;
  642. this._specularEnvironmentMapAtlas = undefined;
  643. // Give frameState, camera, and screen space camera controller initial state before rendering
  644. updateFrameNumber(this, 0.0, JulianDate.now());
  645. this.updateFrameState();
  646. this.initializeFrame();
  647. }
  648. function updateGlobeListeners(scene, globe) {
  649. for (var i = 0; i < scene._removeGlobeCallbacks.length; ++i) {
  650. scene._removeGlobeCallbacks[i]();
  651. }
  652. scene._removeGlobeCallbacks.length = 0;
  653. var removeGlobeCallbacks = [];
  654. if (defined(globe)) {
  655. removeGlobeCallbacks.push(globe.imageryLayersUpdatedEvent.addEventListener(requestRenderAfterFrame(scene)));
  656. removeGlobeCallbacks.push(globe.terrainProviderChanged.addEventListener(requestRenderAfterFrame(scene)));
  657. }
  658. scene._removeGlobeCallbacks = removeGlobeCallbacks;
  659. }
  660. defineProperties(Scene.prototype, {
  661. /**
  662. * Gets the canvas element to which this scene is bound.
  663. * @memberof Scene.prototype
  664. *
  665. * @type {Canvas}
  666. * @readonly
  667. */
  668. canvas : {
  669. get : function() {
  670. return this._canvas;
  671. }
  672. },
  673. /**
  674. * The drawingBufferHeight of the underlying GL context.
  675. * @memberof Scene.prototype
  676. *
  677. * @type {Number}
  678. * @readonly
  679. *
  680. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
  681. */
  682. drawingBufferHeight : {
  683. get : function() {
  684. return this._context.drawingBufferHeight;
  685. }
  686. },
  687. /**
  688. * The drawingBufferHeight of the underlying GL context.
  689. * @memberof Scene.prototype
  690. *
  691. * @type {Number}
  692. * @readonly
  693. *
  694. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
  695. */
  696. drawingBufferWidth : {
  697. get : function() {
  698. return this._context.drawingBufferWidth;
  699. }
  700. },
  701. /**
  702. * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one.
  703. * @memberof Scene.prototype
  704. *
  705. * @type {Number}
  706. * @readonly
  707. *
  708. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>.
  709. */
  710. maximumAliasedLineWidth : {
  711. get : function() {
  712. return ContextLimits.maximumAliasedLineWidth;
  713. }
  714. },
  715. /**
  716. * The maximum length in pixels of one edge of a cube map, supported by this WebGL implementation. It will be at least 16.
  717. * @memberof Scene.prototype
  718. *
  719. * @type {Number}
  720. * @readonly
  721. *
  722. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>GL_MAX_CUBE_MAP_TEXTURE_SIZE</code>.
  723. */
  724. maximumCubeMapSize : {
  725. get : function() {
  726. return ContextLimits.maximumCubeMapSize;
  727. }
  728. },
  729. /**
  730. * Returns <code>true</code> if the {@link Scene#pickPosition} function is supported.
  731. * @memberof Scene.prototype
  732. *
  733. * @type {Boolean}
  734. * @readonly
  735. *
  736. * @see Scene#pickPosition
  737. */
  738. pickPositionSupported : {
  739. get : function() {
  740. return this._context.depthTexture;
  741. }
  742. },
  743. /**
  744. * Returns <code>true</code> if the {@link Scene#sampleHeight} and {@link Scene#sampleHeightMostDetailed} functions are supported.
  745. * @memberof Scene.prototype
  746. *
  747. * @type {Boolean}
  748. * @readonly
  749. *
  750. * @see Scene#sampleHeight
  751. * @see Scene#sampleHeightMostDetailed
  752. */
  753. sampleHeightSupported : {
  754. get : function() {
  755. return this._context.depthTexture;
  756. }
  757. },
  758. /**
  759. * Returns <code>true</code> if the {@link Scene#clampToHeight} and {@link Scene#clampToHeightMostDetailed} functions are supported.
  760. * @memberof Scene.prototype
  761. *
  762. * @type {Boolean}
  763. * @readonly
  764. *
  765. * @see Scene#clampToHeight
  766. * @see Scene#clampToHeightMostDetailed
  767. */
  768. clampToHeightSupported : {
  769. get : function() {
  770. return this._context.depthTexture;
  771. }
  772. },
  773. /**
  774. * Returns <code>true</code> if the {@link Scene#invertClassification} is supported.
  775. * @memberof Scene.prototype
  776. *
  777. * @type {Boolean}
  778. * @readonly
  779. *
  780. * @see Scene#invertClassification
  781. */
  782. invertClassificationSupported : {
  783. get : function() {
  784. return this._context.depthTexture;
  785. }
  786. },
  787. /**
  788. * Returns <code>true</code> if specular environment maps are supported.
  789. * @memberof Scene.prototype
  790. *
  791. * @type {Boolean}
  792. * @readonly
  793. *
  794. * @see Scene#specularEnvironmentMaps
  795. */
  796. specularEnvironmentMapsSupported : {
  797. get : function() {
  798. return OctahedralProjectedCubeMap.isSupported(this._context);
  799. }
  800. },
  801. /**
  802. * Gets or sets the depth-test ellipsoid.
  803. * @memberof Scene.prototype
  804. *
  805. * @type {Globe}
  806. */
  807. globe : {
  808. get: function() {
  809. return this._globe;
  810. },
  811. set: function(globe) {
  812. this._globe = this._globe && this._globe.destroy();
  813. this._globe = globe;
  814. updateGlobeListeners(this, globe);
  815. }
  816. },
  817. /**
  818. * Gets the collection of primitives.
  819. * @memberof Scene.prototype
  820. *
  821. * @type {PrimitiveCollection}
  822. * @readonly
  823. */
  824. primitives : {
  825. get : function() {
  826. return this._primitives;
  827. }
  828. },
  829. /**
  830. * Gets the collection of ground primitives.
  831. * @memberof Scene.prototype
  832. *
  833. * @type {PrimitiveCollection}
  834. * @readonly
  835. */
  836. groundPrimitives : {
  837. get : function() {
  838. return this._groundPrimitives;
  839. }
  840. },
  841. /**
  842. * Gets or sets the camera.
  843. * @memberof Scene.prototype
  844. *
  845. * @type {Camera}
  846. * @readonly
  847. */
  848. camera : {
  849. get : function() {
  850. return this._view.camera;
  851. },
  852. set : function(camera) {
  853. // For internal use only. Documentation is still @readonly.
  854. this._view.camera = camera;
  855. }
  856. },
  857. /**
  858. * Gets or sets the view.
  859. * @memberof Scene.prototype
  860. *
  861. * @type {View}
  862. * @readonly
  863. *
  864. * @private
  865. */
  866. view : {
  867. get : function() {
  868. return this._view;
  869. },
  870. set : function(view) {
  871. // For internal use only. Documentation is still @readonly.
  872. this._view = view;
  873. }
  874. },
  875. /**
  876. * Gets the default view.
  877. * @memberof Scene.prototype
  878. *
  879. * @type {View}
  880. * @readonly
  881. *
  882. * @private
  883. */
  884. defaultView : {
  885. get : function() {
  886. return this._defaultView;
  887. }
  888. },
  889. /**
  890. * Gets picking functions and state
  891. * @memberof Scene.prototype
  892. *
  893. * @type {Picking}
  894. * @readonly
  895. *
  896. * @private
  897. */
  898. picking : {
  899. get : function() {
  900. return this._picking;
  901. }
  902. },
  903. /**
  904. * Gets the controller for camera input handling.
  905. * @memberof Scene.prototype
  906. *
  907. * @type {ScreenSpaceCameraController}
  908. * @readonly
  909. */
  910. screenSpaceCameraController : {
  911. get : function() {
  912. return this._screenSpaceCameraController;
  913. }
  914. },
  915. /**
  916. * Get the map projection to use in 2D and Columbus View modes.
  917. * @memberof Scene.prototype
  918. *
  919. * @type {MapProjection}
  920. * @readonly
  921. *
  922. * @default new GeographicProjection()
  923. */
  924. mapProjection : {
  925. get: function() {
  926. return this._mapProjection;
  927. }
  928. },
  929. /**
  930. * Gets the job scheduler
  931. * @memberof Scene.prototype
  932. * @type {JobScheduler}
  933. * @readonly
  934. *
  935. * @private
  936. */
  937. jobScheduler : {
  938. get: function() {
  939. return this._jobScheduler;
  940. }
  941. },
  942. /**
  943. * Gets state information about the current scene. If called outside of a primitive's <code>update</code>
  944. * function, the previous frame's state is returned.
  945. * @memberof Scene.prototype
  946. *
  947. * @type {FrameState}
  948. * @readonly
  949. *
  950. * @private
  951. */
  952. frameState : {
  953. get: function() {
  954. return this._frameState;
  955. }
  956. },
  957. /**
  958. * Gets the environment state.
  959. * @memberof Scene.prototype
  960. *
  961. * @type {EnvironmentState}
  962. * @readonly
  963. *
  964. * @private
  965. */
  966. environmentState : {
  967. get: function() {
  968. return this._environmentState;
  969. }
  970. },
  971. /**
  972. * Gets the collection of tweens taking place in the scene.
  973. * @memberof Scene.prototype
  974. *
  975. * @type {TweenCollection}
  976. * @readonly
  977. *
  978. * @private
  979. */
  980. tweens : {
  981. get : function() {
  982. return this._tweens;
  983. }
  984. },
  985. /**
  986. * Gets the collection of image layers that will be rendered on the globe.
  987. * @memberof Scene.prototype
  988. *
  989. * @type {ImageryLayerCollection}
  990. * @readonly
  991. */
  992. imageryLayers : {
  993. get : function() {
  994. if (!defined(this.globe)) {
  995. return undefined;
  996. }
  997. return this.globe.imageryLayers;
  998. }
  999. },
  1000. /**
  1001. * The terrain provider providing surface geometry for the globe.
  1002. * @memberof Scene.prototype
  1003. *
  1004. * @type {TerrainProvider}
  1005. */
  1006. terrainProvider : {
  1007. get : function() {
  1008. if (!defined(this.globe)) {
  1009. return undefined;
  1010. }
  1011. return this.globe.terrainProvider;
  1012. },
  1013. set : function(terrainProvider) {
  1014. if (defined(this.globe)) {
  1015. this.globe.terrainProvider = terrainProvider;
  1016. }
  1017. }
  1018. },
  1019. /**
  1020. * Gets an event that's raised when the terrain provider is changed
  1021. * @memberof Scene.prototype
  1022. *
  1023. * @type {Event}
  1024. * @readonly
  1025. */
  1026. terrainProviderChanged : {
  1027. get : function() {
  1028. if (!defined(this.globe)) {
  1029. return undefined;
  1030. }
  1031. return this.globe.terrainProviderChanged;
  1032. }
  1033. },
  1034. /**
  1035. * Gets the event that will be raised before the scene is updated or rendered. Subscribers to the event
  1036. * receive the Scene instance as the first parameter and the current time as the second parameter.
  1037. * @memberof Scene.prototype
  1038. *
  1039. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1040. * @see Scene#postUpdate
  1041. * @see Scene#preRender
  1042. * @see Scene#postRender
  1043. *
  1044. * @type {Event}
  1045. * @readonly
  1046. */
  1047. preUpdate : {
  1048. get : function() {
  1049. return this._preUpdate;
  1050. }
  1051. },
  1052. /**
  1053. * Gets the event that will be raised immediately after the scene is updated and before the scene is rendered.
  1054. * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second
  1055. * parameter.
  1056. * @memberof Scene.prototype
  1057. *
  1058. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1059. * @see Scene#preUpdate
  1060. * @see Scene#preRender
  1061. * @see Scene#postRender
  1062. *
  1063. * @type {Event}
  1064. * @readonly
  1065. */
  1066. postUpdate : {
  1067. get : function() {
  1068. return this._postUpdate;
  1069. }
  1070. },
  1071. /**
  1072. * Gets the event that will be raised when an error is thrown inside the <code>render</code> function.
  1073. * The Scene instance and the thrown error are the only two parameters passed to the event handler.
  1074. * By default, errors are not rethrown after this event is raised, but that can be changed by setting
  1075. * the <code>rethrowRenderErrors</code> property.
  1076. * @memberof Scene.prototype
  1077. *
  1078. * @type {Event}
  1079. * @readonly
  1080. */
  1081. renderError : {
  1082. get : function() {
  1083. return this._renderError;
  1084. }
  1085. },
  1086. /**
  1087. * Gets the event that will be raised after the scene is updated and immediately before the scene is rendered.
  1088. * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second
  1089. * parameter.
  1090. * @memberof Scene.prototype
  1091. *
  1092. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1093. * @see Scene#preUpdate
  1094. * @see Scene#postUpdate
  1095. * @see Scene#postRender
  1096. *
  1097. * @type {Event}
  1098. * @readonly
  1099. */
  1100. preRender : {
  1101. get : function() {
  1102. return this._preRender;
  1103. }
  1104. },
  1105. /**
  1106. * Gets the event that will be raised immediately after the scene is rendered. Subscribers to the event
  1107. * receive the Scene instance as the first parameter and the current time as the second parameter.
  1108. * @memberof Scene.prototype
  1109. *
  1110. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1111. * @see Scene#preUpdate
  1112. * @see Scene#postUpdate
  1113. * @see Scene#postRender
  1114. *
  1115. * @type {Event}
  1116. * @readonly
  1117. */
  1118. postRender : {
  1119. get : function() {
  1120. return this._postRender;
  1121. }
  1122. },
  1123. /**
  1124. * Gets the simulation time when the scene was last rendered. Returns undefined if the scene has not yet been
  1125. * rendered.
  1126. * @memberof Scene.prototype
  1127. *
  1128. * @type {JulianDate}
  1129. * @readonly
  1130. */
  1131. lastRenderTime : {
  1132. get : function() {
  1133. return this._lastRenderTime;
  1134. }
  1135. },
  1136. /**
  1137. * @memberof Scene.prototype
  1138. * @private
  1139. * @readonly
  1140. */
  1141. context : {
  1142. get : function() {
  1143. return this._context;
  1144. }
  1145. },
  1146. /**
  1147. * This property is for debugging only; it is not for production use.
  1148. * <p>
  1149. * When {@link Scene.debugShowFrustums} is <code>true</code>, this contains
  1150. * properties with statistics about the number of command execute per frustum.
  1151. * <code>totalCommands</code> is the total number of commands executed, ignoring
  1152. * overlap. <code>commandsInFrustums</code> is an array with the number of times
  1153. * commands are executed redundantly, e.g., how many commands overlap two or
  1154. * three frustums.
  1155. * </p>
  1156. *
  1157. * @memberof Scene.prototype
  1158. *
  1159. * @type {Object}
  1160. * @readonly
  1161. *
  1162. * @default undefined
  1163. */
  1164. debugFrustumStatistics : {
  1165. get : function() {
  1166. return this._view.debugFrustumStatistics;
  1167. }
  1168. },
  1169. /**
  1170. * Gets whether or not the scene is optimized for 3D only viewing.
  1171. * @memberof Scene.prototype
  1172. * @type {Boolean}
  1173. * @readonly
  1174. */
  1175. scene3DOnly : {
  1176. get : function() {
  1177. return this._frameState.scene3DOnly;
  1178. }
  1179. },
  1180. /**
  1181. * Gets whether or not the scene has order independent translucency enabled.
  1182. * Note that this only reflects the original construction option, and there are
  1183. * other factors that could prevent OIT from functioning on a given system configuration.
  1184. * @memberof Scene.prototype
  1185. * @type {Boolean}
  1186. * @readonly
  1187. */
  1188. orderIndependentTranslucency : {
  1189. get : function() {
  1190. return this._useOIT;
  1191. }
  1192. },
  1193. /**
  1194. * Gets the unique identifier for this scene.
  1195. * @memberof Scene.prototype
  1196. * @type {String}
  1197. * @readonly
  1198. */
  1199. id : {
  1200. get : function() {
  1201. return this._id;
  1202. }
  1203. },
  1204. /**
  1205. * Gets or sets the current mode of the scene.
  1206. * @memberof Scene.prototype
  1207. * @type {SceneMode}
  1208. * @default {@link SceneMode.SCENE3D}
  1209. */
  1210. mode : {
  1211. get : function() {
  1212. return this._mode;
  1213. },
  1214. set : function(value) {
  1215. //>>includeStart('debug', pragmas.debug);
  1216. if (this.scene3DOnly && value !== SceneMode.SCENE3D) {
  1217. throw new DeveloperError('Only SceneMode.SCENE3D is valid when scene3DOnly is true.');
  1218. }
  1219. //>>includeEnd('debug');
  1220. if (value === SceneMode.SCENE2D) {
  1221. this.morphTo2D(0);
  1222. } else if (value === SceneMode.SCENE3D) {
  1223. this.morphTo3D(0);
  1224. } else if (value === SceneMode.COLUMBUS_VIEW) {
  1225. this.morphToColumbusView(0);
  1226. //>>includeStart('debug', pragmas.debug);
  1227. } else {
  1228. throw new DeveloperError('value must be a valid SceneMode enumeration.');
  1229. //>>includeEnd('debug');
  1230. }
  1231. this._mode = value;
  1232. }
  1233. },
  1234. /**
  1235. * Gets the number of frustums used in the last frame.
  1236. * @memberof Scene.prototype
  1237. * @type {FrustumCommands[]}
  1238. *
  1239. * @private
  1240. */
  1241. frustumCommandsList : {
  1242. get : function() {
  1243. return this._view.frustumCommandsList;
  1244. }
  1245. },
  1246. /**
  1247. * Gets the number of frustums used in the last frame.
  1248. * @memberof Scene.prototype
  1249. * @type {Number}
  1250. *
  1251. * @private
  1252. */
  1253. numberOfFrustums : {
  1254. get : function() {
  1255. return this._view.frustumCommandsList.length;
  1256. }
  1257. },
  1258. /**
  1259. * Gets the scalar used to exaggerate the terrain.
  1260. * @memberof Scene.prototype
  1261. * @type {Number}
  1262. */
  1263. terrainExaggeration : {
  1264. get : function() {
  1265. return this._terrainExaggeration;
  1266. }
  1267. },
  1268. /**
  1269. * When <code>true</code>, splits the scene into two viewports with steroscopic views for the left and right eyes.
  1270. * Used for cardboard and WebVR.
  1271. * @memberof Scene.prototype
  1272. * @type {Boolean}
  1273. * @default false
  1274. */
  1275. useWebVR : {
  1276. get : function() {
  1277. return this._useWebVR;
  1278. },
  1279. set : function(value) {
  1280. //>>includeStart('debug', pragmas.debug);
  1281. if (this.camera.frustum instanceof OrthographicFrustum) {
  1282. throw new DeveloperError('VR is unsupported with an orthographic projection.');
  1283. }
  1284. //>>includeEnd('debug');
  1285. this._useWebVR = value;
  1286. if (this._useWebVR) {
  1287. this._frameState.creditDisplay.container.style.visibility = 'hidden';
  1288. this._cameraVR = new Camera(this);
  1289. if (!defined(this._deviceOrientationCameraController)) {
  1290. this._deviceOrientationCameraController = new DeviceOrientationCameraController(this);
  1291. }
  1292. this._aspectRatioVR = this.camera.frustum.aspectRatio;
  1293. } else {
  1294. this._frameState.creditDisplay.container.style.visibility = 'visible';
  1295. this._cameraVR = undefined;
  1296. this._deviceOrientationCameraController = this._deviceOrientationCameraController && !this._deviceOrientationCameraController.isDestroyed() && this._deviceOrientationCameraController.destroy();
  1297. this.camera.frustum.aspectRatio = this._aspectRatioVR;
  1298. this.camera.frustum.xOffset = 0.0;
  1299. }
  1300. }
  1301. },
  1302. /**
  1303. * Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  1304. * @memberof Scene.prototype
  1305. * @type {MapMode2D}
  1306. */
  1307. mapMode2D : {
  1308. get : function() {
  1309. return this._mapMode2D;
  1310. }
  1311. },
  1312. /**
  1313. * Gets or sets the position of the Imagery splitter within the viewport. Valid values are between 0.0 and 1.0.
  1314. * @memberof Scene.prototype
  1315. *
  1316. * @type {Number}
  1317. */
  1318. imagerySplitPosition : {
  1319. get: function() {
  1320. return this._frameState.imagerySplitPosition;
  1321. },
  1322. set: function(value) {
  1323. this._frameState.imagerySplitPosition = value;
  1324. }
  1325. },
  1326. /**
  1327. * The distance from the camera at which to disable the depth test of billboards, labels and points
  1328. * to, for example, prevent clipping against terrain. When set to zero, the depth test should always
  1329. * be applied. When less than zero, the depth test should never be applied. Setting the disableDepthTestDistance
  1330. * property of a billboard, label or point will override this value.
  1331. * @memberof Scene.prototype
  1332. * @type {Number}
  1333. * @default 0.0
  1334. */
  1335. minimumDisableDepthTestDistance : {
  1336. get : function() {
  1337. return this._minimumDisableDepthTestDistance;
  1338. },
  1339. set : function(value) {
  1340. //>>includeStart('debug', pragmas.debug);
  1341. if (!defined(value) || value < 0.0) {
  1342. throw new DeveloperError('minimumDisableDepthTestDistance must be greater than or equal to 0.0.');
  1343. }
  1344. //>>includeEnd('debug');
  1345. this._minimumDisableDepthTestDistance = value;
  1346. }
  1347. },
  1348. /**
  1349. * Whether or not to use a logarithmic depth buffer. Enabling this option will allow for less frustums in the multi-frustum,
  1350. * increasing performance. This property relies on fragmentDepth being supported.
  1351. * @memberof Scene.prototype
  1352. * @type {Boolean}
  1353. */
  1354. logarithmicDepthBuffer : {
  1355. get : function() {
  1356. return this._logDepthBuffer;
  1357. },
  1358. set : function(value) {
  1359. value = this._context.fragmentDepth && value;
  1360. if (this._logDepthBuffer !== value) {
  1361. this._logDepthBuffer = value;
  1362. this._logDepthBufferDirty = true;
  1363. this._defaultView.updateFrustums = true;
  1364. }
  1365. }
  1366. },
  1367. /**
  1368. * The value used for gamma correction. This is only used when rendering with high dynamic range.
  1369. * @memberof Scene.prototype
  1370. * @type {Number}
  1371. * @default 2.2
  1372. */
  1373. gamma : {
  1374. get : function() {
  1375. return this._context.uniformState.gamma;
  1376. },
  1377. set : function(value) {
  1378. this._context.uniformState.gamma = value;
  1379. }
  1380. },
  1381. /**
  1382. * Whether or not to use high dynamic range rendering.
  1383. * @memberof Scene.prototype
  1384. * @type {Boolean}
  1385. * @default true
  1386. */
  1387. highDynamicRange : {
  1388. get : function() {
  1389. return this._hdr;
  1390. },
  1391. set : function(value) {
  1392. var context = this._context;
  1393. var hdr = value && context.depthTexture && (context.colorBufferFloat || context.colorBufferHalfFloat);
  1394. this._hdrDirty = hdr !== this._hdr;
  1395. this._hdr = hdr;
  1396. }
  1397. },
  1398. /**
  1399. * Whether or not high dynamic range rendering is supported.
  1400. * @memberof Scene.prototype
  1401. * @type {Boolean}
  1402. * @default true
  1403. */
  1404. highDynamicRangeSupported : {
  1405. get : function() {
  1406. var context = this._context;
  1407. return context.depthTexture && (context.colorBufferFloat || context.colorBufferHalfFloat);
  1408. }
  1409. },
  1410. /**
  1411. * Gets or sets the color of the light emitted by the sun.
  1412. *
  1413. * @memberof Scene.prototype
  1414. * @type {Cartesian3}
  1415. * @default Cartesian3(1.8, 1.85, 2.0)
  1416. */
  1417. sunColor: {
  1418. get: function() {
  1419. return this._sunColor;
  1420. },
  1421. set: function(value) {
  1422. this._sunColor = value;
  1423. }
  1424. },
  1425. /**
  1426. * Ratio between a pixel and a density-independent pixel. Provides a standard unit of
  1427. * measure for real pixel measurements appropriate to a particular device.
  1428. *
  1429. * @memberof Scene.prototype
  1430. * @type {Number}
  1431. * @default 1.0
  1432. * @private
  1433. */
  1434. pixelRatio: {
  1435. get: function() {
  1436. return this._frameState.pixelRatio;
  1437. },
  1438. set: function(value) {
  1439. this._frameState.pixelRatio = value;
  1440. }
  1441. },
  1442. /**
  1443. * @private
  1444. */
  1445. opaqueFrustumNearOffset : {
  1446. get : function() {
  1447. return this._frameState.useLogDepth ? 0.9 : 0.9999;
  1448. }
  1449. }
  1450. });
  1451. /**
  1452. * Determines if a compressed texture format is supported.
  1453. * @param {String} format The texture format. May be the name of the format or the WebGL extension name, e.g. s3tc or WEBGL_compressed_texture_s3tc.
  1454. * @return {boolean} Whether or not the format is supported.
  1455. */
  1456. Scene.prototype.getCompressedTextureFormatSupported = function(format) {
  1457. var context = this.context;
  1458. return ((format === 'WEBGL_compressed_texture_s3tc' || format === 's3tc') && context.s3tc) ||
  1459. ((format === 'WEBGL_compressed_texture_pvrtc' || format === 'pvrtc') && context.pvrtc) ||
  1460. ((format === 'WEBGL_compressed_texture_etc1' || format === 'etc1') && context.etc1);
  1461. };
  1462. function updateDerivedCommands(scene, command, shadowsDirty) {
  1463. var frameState = scene._frameState;
  1464. var context = scene._context;
  1465. var oit = scene._view.oit;
  1466. var lightShadowMaps = frameState.shadowState.lightShadowMaps;
  1467. var lightShadowsEnabled = frameState.shadowState.lightShadowsEnabled;
  1468. var derivedCommands = command.derivedCommands;
  1469. if (defined(command.pickId)) {
  1470. derivedCommands.picking = DerivedCommand.createPickDerivedCommand(scene, command, context, derivedCommands.picking);
  1471. }
  1472. if (!command.pickOnly) {
  1473. derivedCommands.depth = DerivedCommand.createDepthOnlyDerivedCommand(scene, command, context, derivedCommands.depth);
  1474. }
  1475. derivedCommands.originalCommand = command;
  1476. if (scene._hdr) {
  1477. derivedCommands.hdr = DerivedCommand.createHdrCommand(command, context, derivedCommands.hdr);
  1478. command = derivedCommands.hdr.command;
  1479. derivedCommands = command.derivedCommands;
  1480. }
  1481. if (lightShadowsEnabled && command.receiveShadows) {
  1482. derivedCommands.shadows = ShadowMap.createReceiveDerivedCommand(lightShadowMaps, command, shadowsDirty, context, derivedCommands.shadows);
  1483. }
  1484. if (command.pass === Pass.TRANSLUCENT && defined(oit) && oit.isSupported()) {
  1485. if (lightShadowsEnabled && command.receiveShadows) {
  1486. derivedCommands.oit = defined(derivedCommands.oit) ? derivedCommands.oit : {};
  1487. derivedCommands.oit.shadows = oit.createDerivedCommands(derivedCommands.shadows.receiveCommand, context, derivedCommands.oit.shadows);
  1488. } else {
  1489. derivedCommands.oit = oit.createDerivedCommands(command, context, derivedCommands.oit);
  1490. }
  1491. }
  1492. }
  1493. /**
  1494. * @private
  1495. */
  1496. Scene.prototype.updateDerivedCommands = function(command) {
  1497. if (!defined(command.derivedCommands)) {
  1498. // Is not a DrawCommand
  1499. return;
  1500. }
  1501. var frameState = this._frameState;
  1502. var context = this._context;
  1503. // Update derived commands when any shadow maps become dirty
  1504. var shadowsDirty = false;
  1505. var lastDirtyTime = frameState.shadowState.lastDirtyTime;
  1506. if (command.lastDirtyTime !== lastDirtyTime) {
  1507. command.lastDirtyTime = lastDirtyTime;
  1508. command.dirty = true;
  1509. shadowsDirty = true;
  1510. }
  1511. var useLogDepth = frameState.useLogDepth;
  1512. var useHdr = this._hdr;
  1513. var derivedCommands = command.derivedCommands;
  1514. var hasLogDepthDerivedCommands = defined(derivedCommands.logDepth);
  1515. var hasHdrCommands = defined(derivedCommands.hdr);
  1516. var hasDerivedCommands = defined(derivedCommands.originalCommand);
  1517. var needsLogDepthDerivedCommands = useLogDepth && !hasLogDepthDerivedCommands;
  1518. var needsHdrCommands = useHdr && !hasHdrCommands;
  1519. var needsDerivedCommands = (!useLogDepth || !useHdr) && !hasDerivedCommands;
  1520. command.dirty = command.dirty || needsLogDepthDerivedCommands || needsHdrCommands || needsDerivedCommands;
  1521. if (command.dirty) {
  1522. command.dirty = false;
  1523. var shadowMaps = frameState.shadowState.shadowMaps;
  1524. var shadowsEnabled = frameState.shadowState.shadowsEnabled;
  1525. if (shadowsEnabled && command.castShadows) {
  1526. derivedCommands.shadows = ShadowMap.createCastDerivedCommand(shadowMaps, command, shadowsDirty, context, derivedCommands.shadows);
  1527. }
  1528. if (hasLogDepthDerivedCommands || needsLogDepthDerivedCommands) {
  1529. derivedCommands.logDepth = DerivedCommand.createLogDepthCommand(command, context, derivedCommands.logDepth);
  1530. updateDerivedCommands(this, derivedCommands.logDepth.command, shadowsDirty);
  1531. }
  1532. if (hasDerivedCommands || needsDerivedCommands) {
  1533. updateDerivedCommands(this, command, shadowsDirty);
  1534. }
  1535. }
  1536. };
  1537. var renderTilesetPassState = new Cesium3DTilePassState({
  1538. pass : Cesium3DTilePass.RENDER
  1539. });
  1540. var preloadTilesetPassState = new Cesium3DTilePassState({
  1541. pass : Cesium3DTilePass.PRELOAD
  1542. });
  1543. var preloadFlightTilesetPassState = new Cesium3DTilePassState({
  1544. pass : Cesium3DTilePass.PRELOAD_FLIGHT
  1545. });
  1546. var requestRenderModeDeferCheckPassState = new Cesium3DTilePassState({
  1547. pass : Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK
  1548. });
  1549. var scratchOccluderBoundingSphere = new BoundingSphere();
  1550. var scratchOccluder;
  1551. function getOccluder(scene) {
  1552. // TODO: The occluder is the top-level globe. When we add
  1553. // support for multiple central bodies, this should be the closest one.
  1554. var globe = scene.globe;
  1555. if (scene._mode === SceneMode.SCENE3D && defined(globe) && globe.show) {
  1556. var ellipsoid = globe.ellipsoid;
  1557. scratchOccluderBoundingSphere.radius = ellipsoid.minimumRadius;
  1558. scratchOccluder = Occluder.fromBoundingSphere(scratchOccluderBoundingSphere, scene.camera.positionWC, scratchOccluder);
  1559. return scratchOccluder;
  1560. }
  1561. return undefined;
  1562. }
  1563. /**
  1564. * @private
  1565. */
  1566. Scene.prototype.clearPasses = function(passes) {
  1567. passes.render = false;
  1568. passes.pick = false;
  1569. passes.depth = false;
  1570. passes.postProcess = false;
  1571. passes.offscreen = false;
  1572. };
  1573. function updateFrameNumber(scene, frameNumber, time) {
  1574. var frameState = scene._frameState;
  1575. frameState.frameNumber = frameNumber;
  1576. frameState.time = JulianDate.clone(time, frameState.time);
  1577. }
  1578. /**
  1579. * @private
  1580. */
  1581. Scene.prototype.updateFrameState = function() {
  1582. var camera = this.camera;
  1583. var frameState = this._frameState;
  1584. frameState.commandList.length = 0;
  1585. frameState.shadowMaps.length = 0;
  1586. frameState.brdfLutGenerator = this._brdfLutGenerator;
  1587. frameState.environmentMap = this.skyBox && this.skyBox._cubeMap;
  1588. frameState.mode = this._mode;
  1589. frameState.morphTime = this.morphTime;
  1590. frameState.mapProjection = this.mapProjection;
  1591. frameState.camera = camera;
  1592. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  1593. frameState.occluder = getOccluder(this);
  1594. frameState.terrainExaggeration = this._terrainExaggeration;
  1595. frameState.minimumDisableDepthTestDistance = this._minimumDisableDepthTestDistance;
  1596. frameState.invertClassification = this.invertClassification;
  1597. frameState.useLogDepth = this._logDepthBuffer && !(this.camera.frustum instanceof OrthographicFrustum || this.camera.frustum instanceof OrthographicOffCenterFrustum);
  1598. frameState.sunColor = this._sunColor;
  1599. if (defined(this._specularEnvironmentMapAtlas) && this._specularEnvironmentMapAtlas.ready) {
  1600. frameState.specularEnvironmentMaps = this._specularEnvironmentMapAtlas.texture;
  1601. frameState.specularEnvironmentMapsMaximumLOD = this._specularEnvironmentMapAtlas.maximumMipmapLevel;
  1602. } else {
  1603. frameState.specularEnvironmentMaps = undefined;
  1604. frameState.specularEnvironmentMapsMaximumLOD = undefined;
  1605. }
  1606. frameState.sphericalHarmonicCoefficients = this.sphericalHarmonicCoefficients;
  1607. this._actualInvertClassificationColor = Color.clone(this.invertClassificationColor, this._actualInvertClassificationColor);
  1608. if (!InvertClassification.isTranslucencySupported(this._context)) {
  1609. this._actualInvertClassificationColor.alpha = 1.0;
  1610. }
  1611. frameState.invertClassificationColor = this._actualInvertClassificationColor;
  1612. if (defined(this.globe)) {
  1613. frameState.maximumScreenSpaceError = this.globe.maximumScreenSpaceError;
  1614. } else {
  1615. frameState.maximumScreenSpaceError = 2;
  1616. }
  1617. this.clearPasses(frameState.passes);
  1618. frameState.tilesetPassState = undefined;
  1619. };
  1620. /**
  1621. * @private
  1622. */
  1623. Scene.prototype.isVisible = function(command, cullingVolume, occluder) {
  1624. return ((defined(command)) &&
  1625. ((!defined(command.boundingVolume)) ||
  1626. !command.cull ||
  1627. ((cullingVolume.computeVisibility(command.boundingVolume) !== Intersect.OUTSIDE) &&
  1628. (!defined(occluder) || !command.occlude || !command.boundingVolume.isOccluded(occluder)))));
  1629. };
  1630. function getAttributeLocations(shaderProgram) {
  1631. var attributeLocations = {};
  1632. var attributes = shaderProgram.vertexAttributes;
  1633. for (var a in attributes) {
  1634. if (attributes.hasOwnProperty(a)) {
  1635. attributeLocations[a] = attributes[a].index;
  1636. }
  1637. }
  1638. return attributeLocations;
  1639. }
  1640. function createDebugFragmentShaderProgram(command, scene, shaderProgram) {
  1641. var context = scene.context;
  1642. var sp = defaultValue(shaderProgram, command.shaderProgram);
  1643. var fs = sp.fragmentShaderSource.clone();
  1644. var targets = [];
  1645. fs.sources = fs.sources.map(function(source) {
  1646. source = ShaderSource.replaceMain(source, 'czm_Debug_main');
  1647. var re = /gl_FragData\[(\d+)\]/g;
  1648. var match;
  1649. while ((match = re.exec(source)) !== null) {
  1650. if (targets.indexOf(match[1]) === -1) {
  1651. targets.push(match[1]);
  1652. }
  1653. }
  1654. return source;
  1655. });
  1656. var length = targets.length;
  1657. var newMain =
  1658. 'void main() \n' +
  1659. '{ \n' +
  1660. ' czm_Debug_main(); \n';
  1661. var i;
  1662. if (scene.debugShowCommands) {
  1663. if (!defined(command._debugColor)) {
  1664. command._debugColor = Color.fromRandom();
  1665. }
  1666. var c = command._debugColor;
  1667. if (length > 0) {
  1668. for (i = 0; i < length; ++i) {
  1669. newMain += ' gl_FragData[' + targets[i] + '].rgb *= vec3(' + c.red + ', ' + c.green + ', ' + c.blue + '); \n';
  1670. }
  1671. } else {
  1672. newMain += ' ' + 'gl_FragColor' + '.rgb *= vec3(' + c.red + ', ' + c.green + ', ' + c.blue + '); \n';
  1673. }
  1674. }
  1675. if (scene.debugShowFrustums) {
  1676. // Support up to three frustums. If a command overlaps all
  1677. // three, it's code is not changed.
  1678. var r = (command.debugOverlappingFrustums & (1 << 0)) ? '1.0' : '0.0';
  1679. var g = (command.debugOverlappingFrustums & (1 << 1)) ? '1.0' : '0.0';
  1680. var b = (command.debugOverlappingFrustums & (1 << 2)) ? '1.0' : '0.0';
  1681. if (length > 0) {
  1682. for (i = 0; i < length; ++i) {
  1683. newMain += ' gl_FragData[' + targets[i] + '].rgb *= vec3(' + r + ', ' + g + ', ' + b + '); \n';
  1684. }
  1685. } else {
  1686. newMain += ' ' + 'gl_FragColor' + '.rgb *= vec3(' + r + ', ' + g + ', ' + b + '); \n';
  1687. }
  1688. }
  1689. newMain += '}';
  1690. fs.sources.push(newMain);
  1691. var attributeLocations = getAttributeLocations(sp);
  1692. return ShaderProgram.fromCache({
  1693. context : context,
  1694. vertexShaderSource : sp.vertexShaderSource,
  1695. fragmentShaderSource : fs,
  1696. attributeLocations : attributeLocations
  1697. });
  1698. }
  1699. function executeDebugCommand(command, scene, passState) {
  1700. var debugCommand = DrawCommand.shallowClone(command);
  1701. debugCommand.shaderProgram = createDebugFragmentShaderProgram(command, scene);
  1702. debugCommand.execute(scene.context, passState);
  1703. debugCommand.shaderProgram.destroy();
  1704. }
  1705. var transformFrom2D = new Matrix4(0.0, 0.0, 1.0, 0.0,
  1706. 1.0, 0.0, 0.0, 0.0,
  1707. 0.0, 1.0, 0.0, 0.0,
  1708. 0.0, 0.0, 0.0, 1.0);
  1709. transformFrom2D = Matrix4.inverseTransformation(transformFrom2D, transformFrom2D);
  1710. function debugShowBoundingVolume(command, scene, passState, debugFramebuffer) {
  1711. // Debug code to draw bounding volume for command. Not optimized!
  1712. // Assumes bounding volume is a bounding sphere or box
  1713. var frameState = scene._frameState;
  1714. var context = frameState.context;
  1715. var boundingVolume = command.boundingVolume;
  1716. if (defined(scene._debugVolume)) {
  1717. scene._debugVolume.destroy();
  1718. }
  1719. var geometry;
  1720. var center = Cartesian3.clone(boundingVolume.center);
  1721. if (frameState.mode !== SceneMode.SCENE3D) {
  1722. center = Matrix4.multiplyByPoint(transformFrom2D, center, center);
  1723. var projection = frameState.mapProjection;
  1724. var centerCartographic = projection.unproject(center);
  1725. center = projection.ellipsoid.cartographicToCartesian(centerCartographic);
  1726. }
  1727. if (defined(boundingVolume.radius)) {
  1728. var radius = boundingVolume.radius;
  1729. geometry = GeometryPipeline.toWireframe(EllipsoidGeometry.createGeometry(new EllipsoidGeometry({
  1730. radii : new Cartesian3(radius, radius, radius),
  1731. vertexFormat : PerInstanceColorAppearance.FLAT_VERTEX_FORMAT
  1732. })));
  1733. scene._debugVolume = new Primitive({
  1734. geometryInstances : new GeometryInstance({
  1735. geometry : geometry,
  1736. modelMatrix : Matrix4.fromTranslation(center),
  1737. attributes : {
  1738. color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0)
  1739. }
  1740. }),
  1741. appearance : new PerInstanceColorAppearance({
  1742. flat : true,
  1743. translucent : false
  1744. }),
  1745. asynchronous : false
  1746. });
  1747. } else {
  1748. var halfAxes = boundingVolume.halfAxes;
  1749. geometry = GeometryPipeline.toWireframe(BoxGeometry.createGeometry(BoxGeometry.fromDimensions({
  1750. dimensions : new Cartesian3(2.0, 2.0, 2.0),
  1751. vertexFormat : PerInstanceColorAppearance.FLAT_VERTEX_FORMAT
  1752. })));
  1753. scene._debugVolume = new Primitive({
  1754. geometryInstances : new GeometryInstance({
  1755. geometry : geometry,
  1756. modelMatrix : Matrix4.fromRotationTranslation(halfAxes, center, new Matrix4()),
  1757. attributes : {
  1758. color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0)
  1759. }
  1760. }),
  1761. appearance : new PerInstanceColorAppearance({
  1762. flat : true,
  1763. translucent : false
  1764. }),
  1765. asynchronous : false
  1766. });
  1767. }
  1768. var savedCommandList = frameState.commandList;
  1769. var commandList = frameState.commandList = [];
  1770. scene._debugVolume.update(frameState);
  1771. command = commandList[0];
  1772. if (frameState.useLogDepth) {
  1773. var logDepth = DerivedCommand.createLogDepthCommand(command, context);
  1774. command = logDepth.command;
  1775. }
  1776. var framebuffer;
  1777. if (defined(debugFramebuffer)) {
  1778. framebuffer = passState.framebuffer;
  1779. passState.framebuffer = debugFramebuffer;
  1780. }
  1781. command.execute(context, passState);
  1782. if (defined(framebuffer)) {
  1783. passState.framebuffer = framebuffer;
  1784. }
  1785. frameState.commandList = savedCommandList;
  1786. }
  1787. function executeCommand(command, scene, context, passState, debugFramebuffer) {
  1788. var frameState = scene._frameState;
  1789. if ((defined(scene.debugCommandFilter)) && !scene.debugCommandFilter(command)) {
  1790. return;
  1791. }
  1792. if (command instanceof ClearCommand) {
  1793. command.execute(context, passState);
  1794. return;
  1795. }
  1796. if (command.debugShowBoundingVolume && (defined(command.boundingVolume))) {
  1797. debugShowBoundingVolume(command, scene, passState, debugFramebuffer);
  1798. }
  1799. if (frameState.useLogDepth && defined(command.derivedCommands.logDepth)) {
  1800. command = command.derivedCommands.logDepth.command;
  1801. }
  1802. var passes = frameState.passes;
  1803. if (!passes.pick && scene._hdr && defined(command.derivedCommands) && defined(command.derivedCommands.hdr)) {
  1804. command = command.derivedCommands.hdr.command;
  1805. }
  1806. if (passes.pick || passes.depth) {
  1807. if (passes.pick && !passes.depth && defined(command.derivedCommands.picking)) {
  1808. command = command.derivedCommands.picking.pickCommand;
  1809. command.execute(context, passState);
  1810. return;
  1811. } else if (defined(command.derivedCommands.depth)) {
  1812. command = command.derivedCommands.depth.depthOnlyCommand;
  1813. command.execute(context, passState);
  1814. return;
  1815. }
  1816. }
  1817. if (scene.debugShowCommands || scene.debugShowFrustums) {
  1818. executeDebugCommand(command, scene, passState);
  1819. return;
  1820. }
  1821. if (frameState.shadowState.lightShadowsEnabled && command.receiveShadows && defined(command.derivedCommands.shadows)) {
  1822. // If the command receives shadows, execute the derived shadows command.
  1823. // Some commands, such as OIT derived commands, do not have derived shadow commands themselves
  1824. // and instead shadowing is built-in. In this case execute the command regularly below.
  1825. command.derivedCommands.shadows.receiveCommand.execute(context, passState);
  1826. } else {
  1827. command.execute(context, passState);
  1828. }
  1829. }
  1830. function executeIdCommand(command, scene, context, passState) {
  1831. var frameState = scene._frameState;
  1832. var derivedCommands = command.derivedCommands;
  1833. if (!defined(derivedCommands)) {
  1834. return;
  1835. }
  1836. if (frameState.useLogDepth && defined(derivedCommands.logDepth)) {
  1837. command = derivedCommands.logDepth.command;
  1838. }
  1839. derivedCommands = command.derivedCommands;
  1840. if (defined(derivedCommands.picking)) {
  1841. command = derivedCommands.picking.pickCommand;
  1842. command.execute(context, passState);
  1843. } else if (defined(derivedCommands.depth)) {
  1844. command = derivedCommands.depth.depthOnlyCommand;
  1845. command.execute(context, passState);
  1846. }
  1847. }
  1848. function backToFront(a, b, position) {
  1849. return b.boundingVolume.distanceSquaredTo(position) - a.boundingVolume.distanceSquaredTo(position);
  1850. }
  1851. function frontToBack(a, b, position) {
  1852. // When distances are equal equal favor sorting b before a. This gives render priority to commands later in the list.
  1853. return a.boundingVolume.distanceSquaredTo(position) - b.boundingVolume.distanceSquaredTo(position) + CesiumMath.EPSILON12;
  1854. }
  1855. function executeTranslucentCommandsBackToFront(scene, executeFunction, passState, commands, invertClassification) {
  1856. var context = scene.context;
  1857. mergeSort(commands, backToFront, scene.camera.positionWC);
  1858. if (defined(invertClassification)) {
  1859. executeFunction(invertClassification.unclassifiedCommand, scene, context, passState);
  1860. }
  1861. var length = commands.length;
  1862. for (var i = 0; i < length; ++i) {
  1863. executeFunction(commands[i], scene, context, passState);
  1864. }
  1865. }
  1866. function executeTranslucentCommandsFrontToBack(scene, executeFunction, passState, commands, invertClassification) {
  1867. var context = scene.context;
  1868. mergeSort(commands, frontToBack, scene.camera.positionWC);
  1869. if (defined(invertClassification)) {
  1870. executeFunction(invertClassification.unclassifiedCommand, scene, context, passState);
  1871. }
  1872. var length = commands.length;
  1873. for (var i = 0; i < length; ++i) {
  1874. executeFunction(commands[i], scene, context, passState);
  1875. }
  1876. }
  1877. function getDebugGlobeDepth(scene, index) {
  1878. var globeDepths = scene._view.debugGlobeDepths;
  1879. var globeDepth = globeDepths[index];
  1880. if (!defined(globeDepth) && scene.context.depthTexture) {
  1881. globeDepth = new GlobeDepth();
  1882. globeDepths[index] = globeDepth;
  1883. }
  1884. return globeDepth;
  1885. }
  1886. var scratchPerspectiveFrustum = new PerspectiveFrustum();
  1887. var scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
  1888. var scratchOrthographicFrustum = new OrthographicFrustum();
  1889. var scratchOrthographicOffCenterFrustum = new OrthographicOffCenterFrustum();
  1890. function executeCommands(scene, passState) {
  1891. var camera = scene.camera;
  1892. var context = scene.context;
  1893. var us = context.uniformState;
  1894. us.updateCamera(camera);
  1895. // Create a working frustum from the original camera frustum.
  1896. var frustum;
  1897. if (defined(camera.frustum.fov)) {
  1898. frustum = camera.frustum.clone(scratchPerspectiveFrustum);
  1899. } else if (defined(camera.frustum.infiniteProjectionMatrix)){
  1900. frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
  1901. } else if (defined(camera.frustum.width)) {
  1902. frustum = camera.frustum.clone(scratchOrthographicFrustum);
  1903. } else {
  1904. frustum = camera.frustum.clone(scratchOrthographicOffCenterFrustum);
  1905. }
  1906. // Ideally, we would render the sky box and atmosphere last for
  1907. // early-z, but we would have to draw it in each frustum
  1908. frustum.near = camera.frustum.near;
  1909. frustum.far = camera.frustum.far;
  1910. us.updateFrustum(frustum);
  1911. us.updatePass(Pass.ENVIRONMENT);
  1912. var passes = scene._frameState.passes;
  1913. var picking = passes.pick;
  1914. var environmentState = scene._environmentState;
  1915. var view = scene._view;
  1916. var renderTranslucentDepthForPick = environmentState.renderTranslucentDepthForPick;
  1917. var useWebVR = environmentState.useWebVR;
  1918. // Do not render environment primitives during a pick pass since they do not generate picking commands.
  1919. if (!picking) {
  1920. var skyBoxCommand = environmentState.skyBoxCommand;
  1921. if (defined(skyBoxCommand)) {
  1922. executeCommand(skyBoxCommand, scene, context, passState);
  1923. }
  1924. if (environmentState.isSkyAtmosphereVisible) {
  1925. executeCommand(environmentState.skyAtmosphereCommand, scene, context, passState);
  1926. }
  1927. if (environmentState.isSunVisible) {
  1928. environmentState.sunDrawCommand.execute(context, passState);
  1929. if (scene.sunBloom && !useWebVR) {
  1930. var framebuffer;
  1931. if (environmentState.useGlobeDepthFramebuffer) {
  1932. framebuffer = view.globeDepth.framebuffer;
  1933. } else if (environmentState.usePostProcess) {
  1934. framebuffer = view.sceneFramebuffer.getFramebuffer();
  1935. } else {
  1936. framebuffer = environmentState.originalFramebuffer;
  1937. }
  1938. scene._sunPostProcess.execute(context);
  1939. scene._sunPostProcess.copy(context, framebuffer);
  1940. passState.framebuffer = framebuffer;
  1941. }
  1942. }
  1943. // Moon can be seen through the atmosphere, since the sun is rendered after the atmosphere.
  1944. if (environmentState.isMoonVisible) {
  1945. environmentState.moonCommand.execute(context, passState);
  1946. }
  1947. }
  1948. // Determine how translucent surfaces will be handled.
  1949. var executeTranslucentCommands;
  1950. if (environmentState.useOIT) {
  1951. if (!defined(scene._executeOITFunction)) {
  1952. scene._executeOITFunction = function(scene, executeFunction, passState, commands, invertClassification) {
  1953. view.oit.executeCommands(scene, executeFunction, passState, commands, invertClassification);
  1954. };
  1955. }
  1956. executeTranslucentCommands = scene._executeOITFunction;
  1957. } else if (passes.render) {
  1958. executeTranslucentCommands = executeTranslucentCommandsBackToFront;
  1959. } else {
  1960. executeTranslucentCommands = executeTranslucentCommandsFrontToBack;
  1961. }
  1962. var frustumCommandsList = view.frustumCommandsList;
  1963. var numFrustums = frustumCommandsList.length;
  1964. var clearGlobeDepth = environmentState.clearGlobeDepth;
  1965. var useDepthPlane = environmentState.useDepthPlane;
  1966. var separatePrimitiveFramebuffer = environmentState.separatePrimitiveFramebuffer = false;
  1967. var clearDepth = scene._depthClearCommand;
  1968. var clearStencil = scene._stencilClearCommand;
  1969. var clearClassificationStencil = scene._classificationStencilClearCommand;
  1970. var depthPlane = scene._depthPlane;
  1971. var usePostProcessSelected = environmentState.usePostProcessSelected;
  1972. var height2D = camera.position.z;
  1973. // Execute commands in each frustum in back to front order
  1974. var j;
  1975. for (var i = 0; i < numFrustums; ++i) {
  1976. var index = numFrustums - i - 1;
  1977. var frustumCommands = frustumCommandsList[index];
  1978. if (scene.mode === SceneMode.SCENE2D) {
  1979. // To avoid z-fighting in 2D, move the camera to just before the frustum
  1980. // and scale the frustum depth to be in [1.0, nearToFarDistance2D].
  1981. camera.position.z = height2D - frustumCommands.near + 1.0;
  1982. frustum.far = Math.max(1.0, frustumCommands.far - frustumCommands.near);
  1983. frustum.near = 1.0;
  1984. us.update(scene.frameState);
  1985. us.updateFrustum(frustum);
  1986. } else {
  1987. // Avoid tearing artifacts between adjacent frustums in the opaque passes
  1988. frustum.near = index !== 0 ? frustumCommands.near * scene.opaqueFrustumNearOffset : frustumCommands.near;
  1989. frustum.far = frustumCommands.far;
  1990. us.updateFrustum(frustum);
  1991. }
  1992. var globeDepth = scene.debugShowGlobeDepth ? getDebugGlobeDepth(scene, index) : view.globeDepth;
  1993. if (separatePrimitiveFramebuffer) {
  1994. // Render to globe framebuffer in GLOBE pass
  1995. passState.framebuffer = globeDepth.framebuffer;
  1996. }
  1997. var fb;
  1998. if (scene.debugShowGlobeDepth && defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
  1999. globeDepth.update(context, passState, view.viewport, scene._hdr, clearGlobeDepth);
  2000. globeDepth.clear(context, passState, scene._clearColorCommand.color);
  2001. fb = passState.framebuffer;
  2002. passState.framebuffer = globeDepth.framebuffer;
  2003. }
  2004. clearDepth.execute(context, passState);
  2005. if (context.stencilBuffer) {
  2006. clearStencil.execute(context, passState);
  2007. }
  2008. us.updatePass(Pass.GLOBE);
  2009. var commands = frustumCommands.commands[Pass.GLOBE];
  2010. var length = frustumCommands.indices[Pass.GLOBE];
  2011. for (j = 0; j < length; ++j) {
  2012. executeCommand(commands[j], scene, context, passState);
  2013. }
  2014. if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
  2015. globeDepth.executeCopyDepth(context, passState);
  2016. }
  2017. if (scene.debugShowGlobeDepth && defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
  2018. passState.framebuffer = fb;
  2019. }
  2020. // Draw terrain classification
  2021. us.updatePass(Pass.TERRAIN_CLASSIFICATION);
  2022. commands = frustumCommands.commands[Pass.TERRAIN_CLASSIFICATION];
  2023. length = frustumCommands.indices[Pass.TERRAIN_CLASSIFICATION];
  2024. for (j = 0; j < length; ++j) {
  2025. executeCommand(commands[j], scene, context, passState);
  2026. }
  2027. if (clearGlobeDepth) {
  2028. clearDepth.execute(context, passState);
  2029. if (useDepthPlane) {
  2030. depthPlane.execute(context, passState);
  2031. }
  2032. }
  2033. if (separatePrimitiveFramebuffer) {
  2034. // Render to primitive framebuffer in all other passes
  2035. passState.framebuffer = globeDepth.primitiveFramebuffer;
  2036. }
  2037. if (!environmentState.useInvertClassification || picking) {
  2038. // Common/fastest path. Draw 3D Tiles and classification normally.
  2039. // Draw 3D Tiles
  2040. us.updatePass(Pass.CESIUM_3D_TILE);
  2041. commands = frustumCommands.commands[Pass.CESIUM_3D_TILE];
  2042. length = frustumCommands.indices[Pass.CESIUM_3D_TILE];
  2043. for (j = 0; j < length; ++j) {
  2044. executeCommand(commands[j], scene, context, passState);
  2045. }
  2046. if (length > 0) {
  2047. if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
  2048. globeDepth.executeUpdateDepth(context, passState, clearGlobeDepth);
  2049. }
  2050. // Draw classifications. Modifies 3D Tiles color.
  2051. us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION);
  2052. commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION];
  2053. length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION];
  2054. for (j = 0; j < length; ++j) {
  2055. executeCommand(commands[j], scene, context, passState);
  2056. }
  2057. }
  2058. } else {
  2059. // When the invert classification color is opaque:
  2060. // Main FBO (FBO1): Main_Color + Main_DepthStencil
  2061. // Invert classification FBO (FBO2) : Invert_Color + Main_DepthStencil
  2062. //
  2063. // 1. Clear FBO2 color to vec4(0.0) for each frustum
  2064. // 2. Draw 3D Tiles to FBO2
  2065. // 3. Draw classification to FBO2
  2066. // 4. Fullscreen pass to FBO1, draw Invert_Color when:
  2067. // * Main_DepthStencil has the stencil bit set > 0 (classified)
  2068. // 5. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when:
  2069. // * Main_DepthStencil has stencil bit set to 0 (unclassified) and
  2070. // * Invert_Color !== vec4(0.0)
  2071. //
  2072. // When the invert classification color is translucent:
  2073. // Main FBO (FBO1): Main_Color + Main_DepthStencil
  2074. // Invert classification FBO (FBO2): Invert_Color + Invert_DepthStencil
  2075. // IsClassified FBO (FBO3): IsClassified_Color + Invert_DepthStencil
  2076. //
  2077. // 1. Clear FBO2 and FBO3 color to vec4(0.0), stencil to 0, and depth to 1.0
  2078. // 2. Draw 3D Tiles to FBO2
  2079. // 3. Draw classification to FBO2
  2080. // 4. Fullscreen pass to FBO3, draw any color when
  2081. // * Invert_DepthStencil has the stencil bit set > 0 (classified)
  2082. // 5. Fullscreen pass to FBO1, draw Invert_Color when:
  2083. // * Invert_Color !== vec4(0.0) and
  2084. // * IsClassified_Color !== vec4(0.0)
  2085. // 6. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when:
  2086. // * Invert_Color !== vec4(0.0) and
  2087. // * IsClassified_Color === vec4(0.0)
  2088. //
  2089. // NOTE: Step six when translucent invert color occurs after the TRANSLUCENT pass
  2090. //
  2091. scene._invertClassification.clear(context, passState);
  2092. var opaqueClassificationFramebuffer = passState.framebuffer;
  2093. passState.framebuffer = scene._invertClassification._fbo;
  2094. // Draw normally
  2095. us.updatePass(Pass.CESIUM_3D_TILE);
  2096. commands = frustumCommands.commands[Pass.CESIUM_3D_TILE];
  2097. length = frustumCommands.indices[Pass.CESIUM_3D_TILE];
  2098. for (j = 0; j < length; ++j) {
  2099. executeCommand(commands[j], scene, context, passState);
  2100. }
  2101. if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
  2102. globeDepth.executeUpdateDepth(context, passState, clearGlobeDepth);
  2103. }
  2104. // Set stencil
  2105. us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW);
  2106. commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW];
  2107. length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW];
  2108. for (j = 0; j < length; ++j) {
  2109. executeCommand(commands[j], scene, context, passState);
  2110. }
  2111. passState.framebuffer = opaqueClassificationFramebuffer;
  2112. // Fullscreen pass to copy classified fragments
  2113. scene._invertClassification.executeClassified(context, passState);
  2114. if (scene.frameState.invertClassificationColor.alpha === 1.0) {
  2115. // Fullscreen pass to copy unclassified fragments when alpha == 1.0
  2116. scene._invertClassification.executeUnclassified(context, passState);
  2117. }
  2118. // Clear stencil set by the classification for the next classification pass
  2119. if (length > 0 && context.stencilBuffer) {
  2120. clearClassificationStencil.execute(context, passState);
  2121. }
  2122. // Draw style over classification.
  2123. us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION);
  2124. commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION];
  2125. length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION];
  2126. for (j = 0; j < length; ++j) {
  2127. executeCommand(commands[j], scene, context, passState);
  2128. }
  2129. }
  2130. if (length > 0 && context.stencilBuffer) {
  2131. clearStencil.execute(context, passState);
  2132. }
  2133. us.updatePass(Pass.OPAQUE);
  2134. commands = frustumCommands.commands[Pass.OPAQUE];
  2135. length = frustumCommands.indices[Pass.OPAQUE];
  2136. for (j = 0; j < length; ++j) {
  2137. executeCommand(commands[j], scene, context, passState);
  2138. }
  2139. if (index !== 0 && scene.mode !== SceneMode.SCENE2D) {
  2140. // Do not overlap frustums in the translucent pass to avoid blending artifacts
  2141. frustum.near = frustumCommands.near;
  2142. us.updateFrustum(frustum);
  2143. }
  2144. var invertClassification;
  2145. if (!picking && environmentState.useInvertClassification && scene.frameState.invertClassificationColor.alpha < 1.0) {
  2146. // Fullscreen pass to copy unclassified fragments when alpha < 1.0.
  2147. // Not executed when undefined.
  2148. invertClassification = scene._invertClassification;
  2149. }
  2150. us.updatePass(Pass.TRANSLUCENT);
  2151. commands = frustumCommands.commands[Pass.TRANSLUCENT];
  2152. commands.length = frustumCommands.indices[Pass.TRANSLUCENT];
  2153. executeTranslucentCommands(scene, executeCommand, passState, commands, invertClassification);
  2154. if (context.depthTexture && scene.useDepthPicking && (environmentState.useGlobeDepthFramebuffer || renderTranslucentDepthForPick)) {
  2155. // PERFORMANCE_IDEA: Use MRT to avoid the extra copy.
  2156. var depthStencilTexture = renderTranslucentDepthForPick ? passState.framebuffer.depthStencilTexture : globeDepth.framebuffer.depthStencilTexture;
  2157. var pickDepth = scene._picking.getPickDepth(scene, index);
  2158. pickDepth.update(context, depthStencilTexture);
  2159. pickDepth.executeCopyDepth(context, passState);
  2160. }
  2161. if (separatePrimitiveFramebuffer) {
  2162. // Reset framebuffer
  2163. passState.framebuffer = globeDepth.framebuffer;
  2164. }
  2165. if (picking || !usePostProcessSelected) {
  2166. continue;
  2167. }
  2168. var originalFramebuffer = passState.framebuffer;
  2169. passState.framebuffer = view.sceneFramebuffer.getIdFramebuffer();
  2170. // reset frustum
  2171. frustum.near = index !== 0 ? frustumCommands.near * scene.opaqueFrustumNearOffset : frustumCommands.near;
  2172. frustum.far = frustumCommands.far;
  2173. us.updateFrustum(frustum);
  2174. us.updatePass(Pass.GLOBE);
  2175. commands = frustumCommands.commands[Pass.GLOBE];
  2176. length = frustumCommands.indices[Pass.GLOBE];
  2177. for (j = 0; j < length; ++j) {
  2178. executeIdCommand(commands[j], scene, context, passState);
  2179. }
  2180. if (clearGlobeDepth) {
  2181. clearDepth.framebuffer = passState.framebuffer;
  2182. clearDepth.execute(context, passState);
  2183. clearDepth.framebuffer = undefined;
  2184. }
  2185. if (clearGlobeDepth && useDepthPlane) {
  2186. depthPlane.execute(context, passState);
  2187. }
  2188. us.updatePass(Pass.CESIUM_3D_TILE);
  2189. commands = frustumCommands.commands[Pass.CESIUM_3D_TILE];
  2190. length = frustumCommands.indices[Pass.CESIUM_3D_TILE];
  2191. for (j = 0; j < length; ++j) {
  2192. executeIdCommand(commands[j], scene, context, passState);
  2193. }
  2194. us.updatePass(Pass.OPAQUE);
  2195. commands = frustumCommands.commands[Pass.OPAQUE];
  2196. length = frustumCommands.indices[Pass.OPAQUE];
  2197. for (j = 0; j < length; ++j) {
  2198. executeIdCommand(commands[j], scene, context, passState);
  2199. }
  2200. us.updatePass(Pass.TRANSLUCENT);
  2201. commands = frustumCommands.commands[Pass.TRANSLUCENT];
  2202. length = frustumCommands.indices[Pass.TRANSLUCENT];
  2203. for (j = 0; j < length; ++j) {
  2204. executeIdCommand(commands[j], scene, context, passState);
  2205. }
  2206. passState.framebuffer = originalFramebuffer;
  2207. }
  2208. }
  2209. function executeComputeCommands(scene) {
  2210. var us = scene.context.uniformState;
  2211. us.updatePass(Pass.COMPUTE);
  2212. var sunComputeCommand = scene._environmentState.sunComputeCommand;
  2213. if (defined(sunComputeCommand)) {
  2214. sunComputeCommand.execute(scene._computeEngine);
  2215. }
  2216. var commandList = scene._computeCommandList;
  2217. var length = commandList.length;
  2218. for (var i = 0; i < length; ++i) {
  2219. commandList[i].execute(scene._computeEngine);
  2220. }
  2221. }
  2222. function executeOverlayCommands(scene, passState) {
  2223. var us = scene.context.uniformState;
  2224. us.updatePass(Pass.OVERLAY);
  2225. var context = scene.context;
  2226. var commandList = scene._overlayCommandList;
  2227. var length = commandList.length;
  2228. for (var i = 0; i < length; ++i) {
  2229. commandList[i].execute(context, passState);
  2230. }
  2231. }
  2232. function insertShadowCastCommands(scene, commandList, shadowMap) {
  2233. var shadowVolume = shadowMap.shadowMapCullingVolume;
  2234. var isPointLight = shadowMap.isPointLight;
  2235. var passes = shadowMap.passes;
  2236. var numberOfPasses = passes.length;
  2237. var length = commandList.length;
  2238. for (var i = 0; i < length; ++i) {
  2239. var command = commandList[i];
  2240. scene.updateDerivedCommands(command);
  2241. if (command.castShadows && (command.pass === Pass.GLOBE || command.pass === Pass.CESIUM_3D_TILE || command.pass === Pass.OPAQUE || command.pass === Pass.TRANSLUCENT)) {
  2242. if (scene.isVisible(command, shadowVolume)) {
  2243. if (isPointLight) {
  2244. for (var k = 0; k < numberOfPasses; ++k) {
  2245. passes[k].commandList.push(command);
  2246. }
  2247. } else if (numberOfPasses === 1) {
  2248. passes[0].commandList.push(command);
  2249. } else {
  2250. var wasVisible = false;
  2251. // Loop over cascades from largest to smallest
  2252. for (var j = numberOfPasses - 1; j >= 0; --j) {
  2253. var cascadeVolume = passes[j].cullingVolume;
  2254. if (scene.isVisible(command, cascadeVolume)) {
  2255. passes[j].commandList.push(command);
  2256. wasVisible = true;
  2257. } else if (wasVisible) {
  2258. // If it was visible in the previous cascade but now isn't
  2259. // then there is no need to check any more cascades
  2260. break;
  2261. }
  2262. }
  2263. }
  2264. }
  2265. }
  2266. }
  2267. }
  2268. function executeShadowMapCastCommands(scene) {
  2269. var frameState = scene.frameState;
  2270. var shadowMaps = frameState.shadowState.shadowMaps;
  2271. var shadowMapLength = shadowMaps.length;
  2272. if (!frameState.shadowState.shadowsEnabled) {
  2273. return;
  2274. }
  2275. var context = scene.context;
  2276. var uniformState = context.uniformState;
  2277. for (var i = 0; i < shadowMapLength; ++i) {
  2278. var shadowMap = shadowMaps[i];
  2279. if (shadowMap.outOfView) {
  2280. continue;
  2281. }
  2282. // Reset the command lists
  2283. var j;
  2284. var passes = shadowMap.passes;
  2285. var numberOfPasses = passes.length;
  2286. for (j = 0; j < numberOfPasses; ++j) {
  2287. passes[j].commandList.length = 0;
  2288. }
  2289. // Insert the primitive/model commands into the command lists
  2290. var sceneCommands = scene.frameState.commandList;
  2291. insertShadowCastCommands(scene, sceneCommands, shadowMap);
  2292. for (j = 0; j < numberOfPasses; ++j) {
  2293. var pass = shadowMap.passes[j];
  2294. uniformState.updateCamera(pass.camera);
  2295. shadowMap.updatePass(context, j);
  2296. var numberOfCommands = pass.commandList.length;
  2297. for (var k = 0; k < numberOfCommands; ++k) {
  2298. var command = pass.commandList[k];
  2299. // Set the correct pass before rendering into the shadow map because some shaders
  2300. // conditionally render based on whether the pass is translucent or opaque.
  2301. uniformState.updatePass(command.pass);
  2302. executeCommand(command.derivedCommands.shadows.castCommands[i], scene, context, pass.passState);
  2303. }
  2304. }
  2305. }
  2306. }
  2307. var scratchEyeTranslation = new Cartesian3();
  2308. /**
  2309. * @private
  2310. */
  2311. Scene.prototype.updateAndExecuteCommands = function(passState, backgroundColor) {
  2312. var frameState = this._frameState;
  2313. var mode = frameState.mode;
  2314. var useWebVR = this._environmentState.useWebVR;
  2315. if (useWebVR) {
  2316. executeWebVRCommands(this, passState, backgroundColor);
  2317. } else if (mode !== SceneMode.SCENE2D || this._mapMode2D === MapMode2D.ROTATE) {
  2318. executeCommandsInViewport(true, this, passState, backgroundColor);
  2319. } else {
  2320. updateAndClearFramebuffers(this, passState, backgroundColor);
  2321. execute2DViewportCommands(this, passState);
  2322. }
  2323. };
  2324. function executeWebVRCommands(scene, passState, backgroundColor) {
  2325. var view = scene._view;
  2326. var camera = view.camera;
  2327. var environmentState = scene._environmentState;
  2328. var renderTranslucentDepthForPick = environmentState.renderTranslucentDepthForPick;
  2329. updateAndClearFramebuffers(scene, passState, backgroundColor);
  2330. if (!renderTranslucentDepthForPick) {
  2331. updateAndRenderPrimitives(scene);
  2332. }
  2333. view.createPotentiallyVisibleSet(scene);
  2334. if (!renderTranslucentDepthForPick) {
  2335. executeComputeCommands(scene);
  2336. executeShadowMapCastCommands(scene);
  2337. }
  2338. // Based on Calculating Stereo pairs by Paul Bourke
  2339. // http://paulbourke.net/stereographics/stereorender/
  2340. var viewport = passState.viewport;
  2341. viewport.x = 0;
  2342. viewport.y = 0;
  2343. viewport.width = viewport.width * 0.5;
  2344. var savedCamera = Camera.clone(camera, scene._cameraVR);
  2345. savedCamera.frustum = camera.frustum;
  2346. var near = camera.frustum.near;
  2347. var fo = near * defaultValue(scene.focalLength, 5.0);
  2348. var eyeSeparation = defaultValue(scene.eyeSeparation, fo / 30.0);
  2349. var eyeTranslation = Cartesian3.multiplyByScalar(savedCamera.right, eyeSeparation * 0.5, scratchEyeTranslation);
  2350. camera.frustum.aspectRatio = viewport.width / viewport.height;
  2351. var offset = 0.5 * eyeSeparation * near / fo;
  2352. Cartesian3.add(savedCamera.position, eyeTranslation, camera.position);
  2353. camera.frustum.xOffset = offset;
  2354. executeCommands(scene, passState);
  2355. viewport.x = viewport.width;
  2356. Cartesian3.subtract(savedCamera.position, eyeTranslation, camera.position);
  2357. camera.frustum.xOffset = -offset;
  2358. executeCommands(scene, passState);
  2359. Camera.clone(savedCamera, camera);
  2360. }
  2361. var scratch2DViewportCartographic = new Cartographic(Math.PI, CesiumMath.PI_OVER_TWO);
  2362. var scratch2DViewportMaxCoord = new Cartesian3();
  2363. var scratch2DViewportSavedPosition = new Cartesian3();
  2364. var scratch2DViewportTransform = new Matrix4();
  2365. var scratch2DViewportCameraTransform = new Matrix4();
  2366. var scratch2DViewportEyePoint = new Cartesian3();
  2367. var scratch2DViewportWindowCoords = new Cartesian3();
  2368. var scratch2DViewport = new BoundingRectangle();
  2369. function execute2DViewportCommands(scene, passState) {
  2370. var context = scene.context;
  2371. var frameState = scene.frameState;
  2372. var camera = scene.camera;
  2373. var originalViewport = passState.viewport;
  2374. var viewport = BoundingRectangle.clone(originalViewport, scratch2DViewport);
  2375. passState.viewport = viewport;
  2376. var maxCartographic = scratch2DViewportCartographic;
  2377. var maxCoord = scratch2DViewportMaxCoord;
  2378. var projection = scene.mapProjection;
  2379. projection.project(maxCartographic, maxCoord);
  2380. var position = Cartesian3.clone(camera.position, scratch2DViewportSavedPosition);
  2381. var transform = Matrix4.clone(camera.transform, scratch2DViewportCameraTransform);
  2382. var frustum = camera.frustum.clone();
  2383. camera._setTransform(Matrix4.IDENTITY);
  2384. var viewportTransformation = Matrix4.computeViewportTransformation(viewport, 0.0, 1.0, scratch2DViewportTransform);
  2385. var projectionMatrix = camera.frustum.projectionMatrix;
  2386. var x = camera.positionWC.y;
  2387. var eyePoint = Cartesian3.fromElements(CesiumMath.sign(x) * maxCoord.x - x, 0.0, -camera.positionWC.x, scratch2DViewportEyePoint);
  2388. var windowCoordinates = Transforms.pointToGLWindowCoordinates(projectionMatrix, viewportTransformation, eyePoint, scratch2DViewportWindowCoords);
  2389. windowCoordinates.x = Math.floor(windowCoordinates.x);
  2390. var viewportX = viewport.x;
  2391. var viewportWidth = viewport.width;
  2392. if (x === 0.0 || windowCoordinates.x <= viewportX || windowCoordinates.x >= viewportX + viewportWidth) {
  2393. executeCommandsInViewport(true, scene, passState);
  2394. } else if (Math.abs(viewportX + viewportWidth * 0.5 - windowCoordinates.x) < 1.0) {
  2395. viewport.width = windowCoordinates.x - viewport.x;
  2396. camera.position.x *= CesiumMath.sign(camera.position.x);
  2397. camera.frustum.right = 0.0;
  2398. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  2399. context.uniformState.update(frameState);
  2400. executeCommandsInViewport(true, scene, passState);
  2401. viewport.x = windowCoordinates.x;
  2402. camera.position.x = -camera.position.x;
  2403. camera.frustum.right = -camera.frustum.left;
  2404. camera.frustum.left = 0.0;
  2405. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  2406. context.uniformState.update(frameState);
  2407. executeCommandsInViewport(false, scene, passState);
  2408. } else if (windowCoordinates.x > viewportX + viewportWidth * 0.5) {
  2409. viewport.width = windowCoordinates.x - viewportX;
  2410. var right = camera.frustum.right;
  2411. camera.frustum.right = maxCoord.x - x;
  2412. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  2413. context.uniformState.update(frameState);
  2414. executeCommandsInViewport(true, scene, passState);
  2415. viewport.x = windowCoordinates.x;
  2416. viewport.width = viewportX + viewportWidth - windowCoordinates.x;
  2417. camera.position.x = -camera.position.x;
  2418. camera.frustum.left = -camera.frustum.right;
  2419. camera.frustum.right = right - camera.frustum.right * 2.0;
  2420. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  2421. context.uniformState.update(frameState);
  2422. executeCommandsInViewport(false, scene, passState);
  2423. } else {
  2424. viewport.x = windowCoordinates.x;
  2425. viewport.width = viewportX + viewportWidth - windowCoordinates.x;
  2426. var left = camera.frustum.left;
  2427. camera.frustum.left = -maxCoord.x - x;
  2428. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  2429. context.uniformState.update(frameState);
  2430. executeCommandsInViewport(true, scene, passState);
  2431. viewport.x = viewportX;
  2432. viewport.width = windowCoordinates.x - viewportX;
  2433. camera.position.x = -camera.position.x;
  2434. camera.frustum.right = -camera.frustum.left;
  2435. camera.frustum.left = left - camera.frustum.left * 2.0;
  2436. frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
  2437. context.uniformState.update(frameState);
  2438. executeCommandsInViewport(false, scene, passState);
  2439. }
  2440. camera._setTransform(transform);
  2441. Cartesian3.clone(position, camera.position);
  2442. camera.frustum = frustum.clone();
  2443. passState.viewport = originalViewport;
  2444. }
  2445. function executeCommandsInViewport(firstViewport, scene, passState, backgroundColor) {
  2446. var environmentState = scene._environmentState;
  2447. var view = scene._view;
  2448. var renderTranslucentDepthForPick = environmentState.renderTranslucentDepthForPick;
  2449. if (!firstViewport && !renderTranslucentDepthForPick) {
  2450. scene.frameState.commandList.length = 0;
  2451. }
  2452. if (!renderTranslucentDepthForPick) {
  2453. updateAndRenderPrimitives(scene);
  2454. }
  2455. view.createPotentiallyVisibleSet(scene);
  2456. if (firstViewport) {
  2457. if (defined(backgroundColor)) {
  2458. updateAndClearFramebuffers(scene, passState, backgroundColor);
  2459. }
  2460. if (!renderTranslucentDepthForPick) {
  2461. executeComputeCommands(scene);
  2462. executeShadowMapCastCommands(scene);
  2463. }
  2464. }
  2465. executeCommands(scene, passState);
  2466. }
  2467. var scratchCullingVolume = new CullingVolume();
  2468. /**
  2469. * @private
  2470. */
  2471. Scene.prototype.updateEnvironment = function() {
  2472. var frameState = this._frameState;
  2473. var view = this._view;
  2474. // Update celestial and terrestrial environment effects.
  2475. var environmentState = this._environmentState;
  2476. var renderPass = frameState.passes.render;
  2477. var offscreenPass = frameState.passes.offscreen;
  2478. var skyAtmosphere = this.skyAtmosphere;
  2479. var globe = this.globe;
  2480. if (!renderPass || (this._mode !== SceneMode.SCENE2D && view.camera.frustum instanceof OrthographicFrustum)) {
  2481. environmentState.skyAtmosphereCommand = undefined;
  2482. environmentState.skyBoxCommand = undefined;
  2483. environmentState.sunDrawCommand = undefined;
  2484. environmentState.sunComputeCommand = undefined;
  2485. environmentState.moonCommand = undefined;
  2486. } else {
  2487. if (defined(skyAtmosphere) && defined(globe)) {
  2488. skyAtmosphere.setDynamicAtmosphereColor(globe.enableLighting);
  2489. environmentState.isReadyForAtmosphere = environmentState.isReadyForAtmosphere || globe._surface._tilesToRender.length > 0;
  2490. }
  2491. environmentState.skyAtmosphereCommand = defined(skyAtmosphere) ? skyAtmosphere.update(frameState) : undefined;
  2492. environmentState.skyBoxCommand = defined(this.skyBox) ? this.skyBox.update(frameState, this._hdr) : undefined;
  2493. var sunCommands = defined(this.sun) ? this.sun.update(frameState, view.passState, this._hdr) : undefined;
  2494. environmentState.sunDrawCommand = defined(sunCommands) ? sunCommands.drawCommand : undefined;
  2495. environmentState.sunComputeCommand = defined(sunCommands) ? sunCommands.computeCommand : undefined;
  2496. environmentState.moonCommand = defined(this.moon) ? this.moon.update(frameState) : undefined;
  2497. }
  2498. var clearGlobeDepth = environmentState.clearGlobeDepth = defined(globe) && (!globe.depthTestAgainstTerrain || this.mode === SceneMode.SCENE2D);
  2499. var useDepthPlane = environmentState.useDepthPlane = clearGlobeDepth && this.mode === SceneMode.SCENE3D;
  2500. if (useDepthPlane) {
  2501. // Update the depth plane that is rendered in 3D when the primitives are
  2502. // not depth tested against terrain so primitives on the backface
  2503. // of the globe are not picked.
  2504. this._depthPlane.update(frameState);
  2505. }
  2506. environmentState.renderTranslucentDepthForPick = false;
  2507. environmentState.useWebVR = this._useWebVR && this.mode !== SceneMode.SCENE2D && !offscreenPass;
  2508. var occluder = (frameState.mode === SceneMode.SCENE3D) ? frameState.occluder: undefined;
  2509. var cullingVolume = frameState.cullingVolume;
  2510. // get user culling volume minus the far plane.
  2511. var planes = scratchCullingVolume.planes;
  2512. for (var k = 0; k < 5; ++k) {
  2513. planes[k] = cullingVolume.planes[k];
  2514. }
  2515. cullingVolume = scratchCullingVolume;
  2516. // Determine visibility of celestial and terrestrial environment effects.
  2517. environmentState.isSkyAtmosphereVisible = defined(environmentState.skyAtmosphereCommand) && environmentState.isReadyForAtmosphere;
  2518. environmentState.isSunVisible = this.isVisible(environmentState.sunDrawCommand, cullingVolume, occluder);
  2519. environmentState.isMoonVisible = this.isVisible(environmentState.moonCommand, cullingVolume, occluder);
  2520. var envMaps = this.specularEnvironmentMaps;
  2521. var envMapAtlas = this._specularEnvironmentMapAtlas;
  2522. if (defined(envMaps) && (!defined(envMapAtlas) || envMapAtlas.url !== envMaps)) {
  2523. envMapAtlas = envMapAtlas && envMapAtlas.destroy();
  2524. this._specularEnvironmentMapAtlas = new OctahedralProjectedCubeMap(envMaps);
  2525. } else if (!defined(envMaps) && defined(envMapAtlas)) {
  2526. envMapAtlas.destroy();
  2527. this._specularEnvironmentMapAtlas = undefined;
  2528. }
  2529. if (defined(this._specularEnvironmentMapAtlas)) {
  2530. this._specularEnvironmentMapAtlas.update(frameState);
  2531. }
  2532. };
  2533. function updateDebugFrustumPlanes(scene) {
  2534. var frameState = scene._frameState;
  2535. if (scene.debugShowFrustumPlanes !== scene._debugShowFrustumPlanes) {
  2536. if (scene.debugShowFrustumPlanes) {
  2537. scene._debugFrustumPlanes = new DebugCameraPrimitive({
  2538. camera: scene.camera,
  2539. updateOnChange: false
  2540. });
  2541. } else {
  2542. scene._debugFrustumPlanes = scene._debugFrustumPlanes && scene._debugFrustumPlanes.destroy();
  2543. }
  2544. scene._debugShowFrustumPlanes = scene.debugShowFrustumPlanes;
  2545. }
  2546. if (defined(scene._debugFrustumPlanes)) {
  2547. scene._debugFrustumPlanes.update(frameState);
  2548. }
  2549. }
  2550. function updateShadowMaps(scene) {
  2551. var frameState = scene._frameState;
  2552. var shadowMaps = frameState.shadowMaps;
  2553. var length = shadowMaps.length;
  2554. var shadowsEnabled = (length > 0) && !frameState.passes.pick && (scene.mode === SceneMode.SCENE3D);
  2555. if (shadowsEnabled !== frameState.shadowState.shadowsEnabled) {
  2556. // Update derived commands when shadowsEnabled changes
  2557. ++frameState.shadowState.lastDirtyTime;
  2558. frameState.shadowState.shadowsEnabled = shadowsEnabled;
  2559. }
  2560. frameState.shadowState.lightShadowsEnabled = false;
  2561. if (!shadowsEnabled) {
  2562. return;
  2563. }
  2564. // Check if the shadow maps are different than the shadow maps last frame.
  2565. // If so, the derived commands need to be updated.
  2566. for (var j = 0; j < length; ++j) {
  2567. if (shadowMaps[j] !== frameState.shadowState.shadowMaps[j]) {
  2568. ++frameState.shadowState.lastDirtyTime;
  2569. break;
  2570. }
  2571. }
  2572. frameState.shadowState.shadowMaps.length = 0;
  2573. frameState.shadowState.lightShadowMaps.length = 0;
  2574. for (var i = 0; i < length; ++i) {
  2575. var shadowMap = shadowMaps[i];
  2576. shadowMap.update(frameState);
  2577. frameState.shadowState.shadowMaps.push(shadowMap);
  2578. if (shadowMap.fromLightSource) {
  2579. frameState.shadowState.lightShadowMaps.push(shadowMap);
  2580. frameState.shadowState.lightShadowsEnabled = true;
  2581. }
  2582. if (shadowMap.dirty) {
  2583. ++frameState.shadowState.lastDirtyTime;
  2584. shadowMap.dirty = false;
  2585. }
  2586. }
  2587. }
  2588. function updateAndRenderPrimitives(scene) {
  2589. var frameState = scene._frameState;
  2590. scene._groundPrimitives.update(frameState);
  2591. scene._primitives.update(frameState);
  2592. updateDebugFrustumPlanes(scene);
  2593. updateShadowMaps(scene);
  2594. if (scene._globe) {
  2595. scene._globe.render(frameState);
  2596. }
  2597. }
  2598. function updateAndClearFramebuffers(scene, passState, clearColor) {
  2599. var context = scene._context;
  2600. var frameState = scene._frameState;
  2601. var environmentState = scene._environmentState;
  2602. var view = scene._view;
  2603. var passes = scene._frameState.passes;
  2604. var picking = passes.pick;
  2605. var useWebVR = environmentState.useWebVR;
  2606. // Preserve the reference to the original framebuffer.
  2607. environmentState.originalFramebuffer = passState.framebuffer;
  2608. // Manage sun bloom post-processing effect.
  2609. if (defined(scene.sun) && scene.sunBloom !== scene._sunBloom) {
  2610. if (scene.sunBloom && !useWebVR) {
  2611. scene._sunPostProcess = new SunPostProcess();
  2612. } else if(defined(scene._sunPostProcess)){
  2613. scene._sunPostProcess = scene._sunPostProcess.destroy();
  2614. }
  2615. scene._sunBloom = scene.sunBloom;
  2616. } else if (!defined(scene.sun) && defined(scene._sunPostProcess)) {
  2617. scene._sunPostProcess = scene._sunPostProcess.destroy();
  2618. scene._sunBloom = false;
  2619. }
  2620. // Clear the pass state framebuffer.
  2621. var clear = scene._clearColorCommand;
  2622. Color.clone(clearColor, clear.color);
  2623. clear.execute(context, passState);
  2624. // Update globe depth rendering based on the current context and clear the globe depth framebuffer.
  2625. // Globe depth is copied for the pick pass to support picking batched geometries in GroundPrimitives.
  2626. var useGlobeDepthFramebuffer = environmentState.useGlobeDepthFramebuffer = defined(view.globeDepth);
  2627. if (useGlobeDepthFramebuffer) {
  2628. view.globeDepth.update(context, passState, view.viewport, scene._hdr, environmentState.clearGlobeDepth);
  2629. view.globeDepth.clear(context, passState, clearColor);
  2630. }
  2631. // If supported, configure OIT to use the globe depth framebuffer and clear the OIT framebuffer.
  2632. var oit = view.oit;
  2633. var useOIT = environmentState.useOIT = !picking && defined(oit) && oit.isSupported();
  2634. if (useOIT) {
  2635. oit.update(context, passState, view.globeDepth.framebuffer, scene._hdr);
  2636. oit.clear(context, passState, clearColor);
  2637. environmentState.useOIT = oit.isSupported();
  2638. }
  2639. var postProcess = scene.postProcessStages;
  2640. var usePostProcess = environmentState.usePostProcess = !picking && (scene._hdr || postProcess.length > 0 || postProcess.ambientOcclusion.enabled || postProcess.fxaa.enabled || postProcess.bloom.enabled);
  2641. environmentState.usePostProcessSelected = false;
  2642. if (usePostProcess) {
  2643. view.sceneFramebuffer.update(context, view.viewport, scene._hdr);
  2644. view.sceneFramebuffer.clear(context, passState, clearColor);
  2645. postProcess.update(context, frameState.useLogDepth, scene._hdr);
  2646. postProcess.clear(context);
  2647. usePostProcess = environmentState.usePostProcess = postProcess.ready;
  2648. environmentState.usePostProcessSelected = usePostProcess && postProcess.hasSelected;
  2649. }
  2650. if (environmentState.isSunVisible && scene.sunBloom && !useWebVR) {
  2651. passState.framebuffer = scene._sunPostProcess.update(passState);
  2652. scene._sunPostProcess.clear(context, passState, clearColor);
  2653. } else if (useGlobeDepthFramebuffer) {
  2654. passState.framebuffer = view.globeDepth.framebuffer;
  2655. } else if (usePostProcess) {
  2656. passState.framebuffer = view.sceneFramebuffer.getFramebuffer();
  2657. }
  2658. if (defined(passState.framebuffer)) {
  2659. clear.execute(context, passState);
  2660. }
  2661. var useInvertClassification = environmentState.useInvertClassification = !picking && defined(passState.framebuffer) && scene.invertClassification;
  2662. if (useInvertClassification) {
  2663. var depthFramebuffer;
  2664. if (scene.frameState.invertClassificationColor.alpha === 1.0) {
  2665. if (environmentState.useGlobeDepthFramebuffer) {
  2666. depthFramebuffer = view.globeDepth.framebuffer;
  2667. }
  2668. }
  2669. if (defined(depthFramebuffer) || context.depthTexture) {
  2670. scene._invertClassification.previousFramebuffer = depthFramebuffer;
  2671. scene._invertClassification.update(context);
  2672. scene._invertClassification.clear(context, passState);
  2673. if (scene.frameState.invertClassificationColor.alpha < 1.0 && useOIT) {
  2674. var command = scene._invertClassification.unclassifiedCommand;
  2675. var derivedCommands = command.derivedCommands;
  2676. derivedCommands.oit = oit.createDerivedCommands(command, context, derivedCommands.oit);
  2677. }
  2678. } else {
  2679. environmentState.useInvertClassification = false;
  2680. }
  2681. }
  2682. }
  2683. /**
  2684. * @private
  2685. */
  2686. Scene.prototype.resolveFramebuffers = function(passState) {
  2687. var context = this._context;
  2688. var frameState = this._frameState;
  2689. var environmentState = this._environmentState;
  2690. var view = this._view;
  2691. var globeDepth = view.globeDepth;
  2692. var useOIT = environmentState.useOIT;
  2693. var useGlobeDepthFramebuffer = environmentState.useGlobeDepthFramebuffer;
  2694. var usePostProcess = environmentState.usePostProcess;
  2695. var defaultFramebuffer = environmentState.originalFramebuffer;
  2696. var globeFramebuffer = useGlobeDepthFramebuffer ? globeDepth.framebuffer : undefined;
  2697. var sceneFramebuffer = view.sceneFramebuffer.getFramebuffer();
  2698. var idFramebuffer = view.sceneFramebuffer.getIdFramebuffer();
  2699. if (environmentState.separatePrimitiveFramebuffer) {
  2700. // Merge primitive framebuffer into globe framebuffer
  2701. globeDepth.executeMergeColor(context, passState);
  2702. }
  2703. if (useOIT) {
  2704. passState.framebuffer = usePostProcess ? sceneFramebuffer : defaultFramebuffer;
  2705. view.oit.execute(context, passState);
  2706. }
  2707. if (usePostProcess) {
  2708. var inputFramebuffer = sceneFramebuffer;
  2709. if (useGlobeDepthFramebuffer && !useOIT) {
  2710. inputFramebuffer = globeFramebuffer;
  2711. }
  2712. var postProcess = this.postProcessStages;
  2713. var colorTexture = inputFramebuffer.getColorTexture(0);
  2714. var idTexture = idFramebuffer.getColorTexture(0);
  2715. var depthTexture = defaultValue(globeFramebuffer, sceneFramebuffer).depthStencilTexture;
  2716. postProcess.execute(context, colorTexture, depthTexture, idTexture);
  2717. postProcess.copy(context, defaultFramebuffer);
  2718. }
  2719. if (!useOIT && !usePostProcess && useGlobeDepthFramebuffer) {
  2720. passState.framebuffer = defaultFramebuffer;
  2721. globeDepth.executeCopyColor(context, passState);
  2722. }
  2723. var useLogDepth = frameState.useLogDepth;
  2724. if (this.debugShowGlobeDepth && useGlobeDepthFramebuffer) {
  2725. var gd = getDebugGlobeDepth(this, this.debugShowDepthFrustum - 1);
  2726. gd.executeDebugGlobeDepth(context, passState, useLogDepth);
  2727. }
  2728. if (this.debugShowPickDepth && useGlobeDepthFramebuffer) {
  2729. var pd = this._picking.getPickDepth(this, this.debugShowDepthFrustum - 1);
  2730. pd.executeDebugPickDepth(context, passState, useLogDepth);
  2731. }
  2732. };
  2733. function callAfterRenderFunctions(scene) {
  2734. // Functions are queued up during primitive update and executed here in case
  2735. // the function modifies scene state that should remain constant over the frame.
  2736. var functions = scene._frameState.afterRender;
  2737. for (var i = 0, length = functions.length; i < length; ++i) {
  2738. functions[i]();
  2739. scene.requestRender();
  2740. }
  2741. functions.length = 0;
  2742. }
  2743. /**
  2744. * @private
  2745. */
  2746. Scene.prototype.initializeFrame = function() {
  2747. // Destroy released shaders and textures once every 120 frames to avoid thrashing the cache
  2748. if (this._shaderFrameCount++ === 120) {
  2749. this._shaderFrameCount = 0;
  2750. this._context.shaderCache.destroyReleasedShaderPrograms();
  2751. this._context.textureCache.destroyReleasedTextures();
  2752. }
  2753. this._tweens.update();
  2754. this._screenSpaceCameraController.update();
  2755. if (defined(this._deviceOrientationCameraController)) {
  2756. this._deviceOrientationCameraController.update();
  2757. }
  2758. this.camera.update(this._mode);
  2759. this.camera._updateCameraChanged();
  2760. };
  2761. function updateDebugShowFramesPerSecond(scene, renderedThisFrame) {
  2762. if (scene.debugShowFramesPerSecond) {
  2763. if (!defined(scene._performanceDisplay)) {
  2764. var performanceContainer = document.createElement('div');
  2765. performanceContainer.className = 'cesium-performanceDisplay-defaultContainer';
  2766. var container = scene._canvas.parentNode;
  2767. container.appendChild(performanceContainer);
  2768. var performanceDisplay = new PerformanceDisplay({container: performanceContainer});
  2769. scene._performanceDisplay = performanceDisplay;
  2770. scene._performanceContainer = performanceContainer;
  2771. }
  2772. scene._performanceDisplay.throttled = scene.requestRenderMode;
  2773. scene._performanceDisplay.update(renderedThisFrame);
  2774. } else if (defined(scene._performanceDisplay)) {
  2775. scene._performanceDisplay = scene._performanceDisplay && scene._performanceDisplay.destroy();
  2776. scene._performanceContainer.parentNode.removeChild(scene._performanceContainer);
  2777. }
  2778. }
  2779. function prePassesUpdate(scene) {
  2780. scene._jobScheduler.resetBudgets();
  2781. var frameState = scene._frameState;
  2782. var primitives = scene.primitives;
  2783. primitives.prePassesUpdate(frameState);
  2784. if (defined(scene.globe)) {
  2785. scene.globe.update(frameState);
  2786. }
  2787. scene._picking.update();
  2788. frameState.creditDisplay.update();
  2789. }
  2790. function postPassesUpdate(scene) {
  2791. var frameState = scene._frameState;
  2792. var primitives = scene.primitives;
  2793. primitives.postPassesUpdate(frameState);
  2794. RequestScheduler.update();
  2795. }
  2796. var scratchBackgroundColor = new Color();
  2797. function render(scene) {
  2798. var frameState = scene._frameState;
  2799. var context = scene.context;
  2800. var us = context.uniformState;
  2801. var view = scene._defaultView;
  2802. scene._view = view;
  2803. scene.updateFrameState();
  2804. frameState.passes.render = true;
  2805. frameState.passes.postProcess = scene.postProcessStages.hasSelected;
  2806. frameState.tilesetPassState = renderTilesetPassState;
  2807. var backgroundColor = defaultValue(scene.backgroundColor, Color.BLACK);
  2808. if (scene._hdr) {
  2809. backgroundColor = Color.clone(backgroundColor, scratchBackgroundColor);
  2810. backgroundColor.red = Math.pow(backgroundColor.red, scene.gamma);
  2811. backgroundColor.green = Math.pow(backgroundColor.green, scene.gamma);
  2812. backgroundColor.blue = Math.pow(backgroundColor.blue, scene.gamma);
  2813. }
  2814. frameState.backgroundColor = backgroundColor;
  2815. scene.fog.update(frameState);
  2816. us.update(frameState);
  2817. var shadowMap = scene.shadowMap;
  2818. if (defined(shadowMap) && shadowMap.enabled) {
  2819. // Update the sun's direction
  2820. Cartesian3.negate(us.sunDirectionWC, scene._sunCamera.direction);
  2821. frameState.shadowMaps.push(shadowMap);
  2822. }
  2823. scene._computeCommandList.length = 0;
  2824. scene._overlayCommandList.length = 0;
  2825. var viewport = view.viewport;
  2826. viewport.x = 0;
  2827. viewport.y = 0;
  2828. viewport.width = context.drawingBufferWidth;
  2829. viewport.height = context.drawingBufferHeight;
  2830. var passState = view.passState;
  2831. passState.framebuffer = undefined;
  2832. passState.blendingEnabled = undefined;
  2833. passState.scissorTest = undefined;
  2834. passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
  2835. if (defined(scene.globe)) {
  2836. scene.globe.beginFrame(frameState);
  2837. }
  2838. scene.updateEnvironment();
  2839. scene.updateAndExecuteCommands(passState, backgroundColor);
  2840. scene.resolveFramebuffers(passState);
  2841. passState.framebuffer = undefined;
  2842. executeOverlayCommands(scene, passState);
  2843. if (defined(scene.globe)) {
  2844. scene.globe.endFrame(frameState);
  2845. if (!scene.globe.tilesLoaded) {
  2846. scene._renderRequested = true;
  2847. }
  2848. }
  2849. context.endFrame();
  2850. }
  2851. function tryAndCatchError(scene, functionToExecute) {
  2852. try {
  2853. functionToExecute(scene);
  2854. } catch (error) {
  2855. scene._renderError.raiseEvent(scene, error);
  2856. if (scene.rethrowRenderErrors) {
  2857. throw error;
  2858. }
  2859. }
  2860. }
  2861. function updateMostDetailedRayPicks(scene) {
  2862. return scene._picking.updateMostDetailedRayPicks(scene);
  2863. }
  2864. /**
  2865. * Update and render the scene.
  2866. * @param {JulianDate} [time] The simulation time at which to render.
  2867. *
  2868. * @private
  2869. */
  2870. Scene.prototype.render = function(time) {
  2871. /**
  2872. *
  2873. * Pre passes update. Execute any pass invariant code that should run before the passes here.
  2874. *
  2875. */
  2876. this._preUpdate.raiseEvent(this, time);
  2877. var frameState = this._frameState;
  2878. frameState.newFrame = false;
  2879. if (!defined(time)) {
  2880. time = JulianDate.now();
  2881. }
  2882. // Determine if shouldRender
  2883. var cameraChanged = this._view.checkForCameraUpdates(this);
  2884. var shouldRender = !this.requestRenderMode || this._renderRequested || cameraChanged || this._logDepthBufferDirty || this._hdrDirty || (this.mode === SceneMode.MORPHING);
  2885. if (!shouldRender && defined(this.maximumRenderTimeChange) && defined(this._lastRenderTime)) {
  2886. var difference = Math.abs(JulianDate.secondsDifference(this._lastRenderTime, time));
  2887. shouldRender = shouldRender || difference > this.maximumRenderTimeChange;
  2888. }
  2889. if (shouldRender) {
  2890. this._lastRenderTime = JulianDate.clone(time, this._lastRenderTime);
  2891. this._renderRequested = false;
  2892. this._logDepthBufferDirty = false;
  2893. this._hdrDirty = false;
  2894. var frameNumber = CesiumMath.incrementWrap(frameState.frameNumber, 15000000.0, 1.0);
  2895. updateFrameNumber(this, frameNumber, time);
  2896. frameState.newFrame = true;
  2897. }
  2898. tryAndCatchError(this, prePassesUpdate);
  2899. /**
  2900. *
  2901. * Passes update. Add any passes here
  2902. *
  2903. */
  2904. if (this.primitives.show) {
  2905. tryAndCatchError(this, updateMostDetailedRayPicks);
  2906. tryAndCatchError(this, updatePreloadPass);
  2907. tryAndCatchError(this, updatePreloadFlightPass);
  2908. if (!shouldRender) {
  2909. tryAndCatchError(this, updateRequestRenderModeDeferCheckPass);
  2910. }
  2911. }
  2912. this._postUpdate.raiseEvent(this, time);
  2913. if (shouldRender) {
  2914. this._preRender.raiseEvent(this, time);
  2915. frameState.creditDisplay.beginFrame();
  2916. tryAndCatchError(this, render);
  2917. }
  2918. /**
  2919. *
  2920. * Post passes update. Execute any pass invariant code that should run after the passes here.
  2921. *
  2922. */
  2923. updateDebugShowFramesPerSecond(this, shouldRender);
  2924. tryAndCatchError(this, postPassesUpdate);
  2925. // Often used to trigger events (so don't want in trycatch) that the user might be subscribed to. Things like the tile load events, ready promises, etc.
  2926. // We don't want those events to resolve during the render loop because the events might add new primitives
  2927. callAfterRenderFunctions(this);
  2928. if (shouldRender) {
  2929. this._postRender.raiseEvent(this, time);
  2930. frameState.creditDisplay.endFrame();
  2931. }
  2932. };
  2933. /**
  2934. * Update and render the scene. Always forces a new render frame regardless of whether a render was
  2935. * previously requested.
  2936. * @param {JulianDate} [time] The simulation time at which to render.
  2937. *
  2938. * @private
  2939. */
  2940. Scene.prototype.forceRender = function(time) {
  2941. this._renderRequested = true;
  2942. this.render(time);
  2943. };
  2944. /**
  2945. * Requests a new rendered frame when {@link Scene#requestRenderMode} is set to <code>true</code>.
  2946. * The render rate will not exceed the {@link CesiumWidget#targetFrameRate}.
  2947. *
  2948. * @see Scene#requestRenderMode
  2949. */
  2950. Scene.prototype.requestRender = function() {
  2951. this._renderRequested = true;
  2952. };
  2953. /**
  2954. * @private
  2955. */
  2956. Scene.prototype.clampLineWidth = function(width) {
  2957. return Math.max(ContextLimits.minimumAliasedLineWidth, Math.min(width, ContextLimits.maximumAliasedLineWidth));
  2958. };
  2959. /**
  2960. * Returns an object with a `primitive` property that contains the first (top) primitive in the scene
  2961. * at a particular window coordinate or undefined if nothing is at the location. Other properties may
  2962. * potentially be set depending on the type of primitive and may be used to further identify the picked object.
  2963. * <p>
  2964. * When a feature of a 3D Tiles tileset is picked, <code>pick</code> returns a {@link Cesium3DTileFeature} object.
  2965. * </p>
  2966. *
  2967. * @example
  2968. * // On mouse over, color the feature yellow.
  2969. * handler.setInputAction(function(movement) {
  2970. * var feature = scene.pick(movement.endPosition);
  2971. * if (feature instanceof Cesium.Cesium3DTileFeature) {
  2972. * feature.color = Cesium.Color.YELLOW;
  2973. * }
  2974. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  2975. *
  2976. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  2977. * @param {Number} [width=3] Width of the pick rectangle.
  2978. * @param {Number} [height=3] Height of the pick rectangle.
  2979. * @returns {Object} Object containing the picked primitive.
  2980. */
  2981. Scene.prototype.pick = function(windowPosition, width, height) {
  2982. return this._picking.pick(this, windowPosition, width, height);
  2983. };
  2984. /**
  2985. * Returns the cartesian position reconstructed from the depth buffer and window position.
  2986. * The returned position is in world coordinates. Used internally by camera functions to
  2987. * prevent conversion to projected 2D coordinates and then back.
  2988. * <p>
  2989. * Set {@link Scene#pickTranslucentDepth} to <code>true</code> to include the depth of
  2990. * translucent primitives; otherwise, this essentially picks through translucent primitives.
  2991. * </p>
  2992. *
  2993. * @private
  2994. *
  2995. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  2996. * @param {Cartesian3} [result] The object on which to restore the result.
  2997. * @returns {Cartesian3} The cartesian position in world coordinates.
  2998. *
  2999. * @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
  3000. */
  3001. Scene.prototype.pickPositionWorldCoordinates = function(windowPosition, result) {
  3002. return this._picking.pickPositionWorldCoordinates(this, windowPosition, result);
  3003. };
  3004. /**
  3005. * Returns the cartesian position reconstructed from the depth buffer and window position.
  3006. * <p>
  3007. * The position reconstructed from the depth buffer in 2D may be slightly different from those
  3008. * reconstructed in 3D and Columbus view. This is caused by the difference in the distribution
  3009. * of depth values of perspective and orthographic projection.
  3010. * </p>
  3011. * <p>
  3012. * Set {@link Scene#pickTranslucentDepth} to <code>true</code> to include the depth of
  3013. * translucent primitives; otherwise, this essentially picks through translucent primitives.
  3014. * </p>
  3015. *
  3016. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  3017. * @param {Cartesian3} [result] The object on which to restore the result.
  3018. * @returns {Cartesian3} The cartesian position.
  3019. *
  3020. * @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
  3021. */
  3022. Scene.prototype.pickPosition = function(windowPosition, result) {
  3023. return this._picking.pickPosition(this, windowPosition, result);
  3024. };
  3025. /**
  3026. * Returns a list of objects, each containing a `primitive` property, for all primitives at
  3027. * a particular window coordinate position. Other properties may also be set depending on the
  3028. * type of primitive and may be used to further identify the picked object. The primitives in
  3029. * the list are ordered by their visual order in the scene (front to back).
  3030. *
  3031. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  3032. * @param {Number} [limit] If supplied, stop drilling after collecting this many picks.
  3033. * @param {Number} [width=3] Width of the pick rectangle.
  3034. * @param {Number} [height=3] Height of the pick rectangle.
  3035. * @returns {Object[]} Array of objects, each containing 1 picked primitives.
  3036. *
  3037. * @exception {DeveloperError} windowPosition is undefined.
  3038. *
  3039. * @example
  3040. * var pickedObjects = scene.drillPick(new Cesium.Cartesian2(100.0, 200.0));
  3041. *
  3042. * @see Scene#pick
  3043. */
  3044. Scene.prototype.drillPick = function(windowPosition, limit, width, height) {
  3045. return this._picking.drillPick(this, windowPosition, limit, width, height);
  3046. };
  3047. function updatePreloadPass(scene) {
  3048. var frameState = scene._frameState;
  3049. preloadTilesetPassState.camera = frameState.camera;
  3050. preloadTilesetPassState.cullingVolume = frameState.cullingVolume;
  3051. var primitives = scene.primitives;
  3052. primitives.updateForPass(frameState, preloadTilesetPassState);
  3053. }
  3054. function updatePreloadFlightPass(scene) {
  3055. var frameState = scene._frameState;
  3056. var camera = frameState.camera;
  3057. if (!camera.hasCurrentFlight()) {
  3058. return;
  3059. }
  3060. preloadFlightTilesetPassState.camera = scene.preloadFlightCamera;
  3061. preloadFlightTilesetPassState.cullingVolume = scene.preloadFlightCullingVolume;
  3062. var primitives = scene.primitives;
  3063. primitives.updateForPass(frameState, preloadFlightTilesetPassState);
  3064. }
  3065. function updateRequestRenderModeDeferCheckPass(scene) {
  3066. // Check if any ignored requests are ready to go (to wake rendering up again)
  3067. scene.primitives.updateForPass(scene._frameState, requestRenderModeDeferCheckPassState);
  3068. }
  3069. /**
  3070. * Returns an object containing the first object intersected by the ray and the position of intersection,
  3071. * or <code>undefined</code> if there were no intersections. The intersected object has a <code>primitive</code>
  3072. * property that contains the intersected primitive. Other properties may be set depending on the type of primitive
  3073. * and may be used to further identify the picked object. The ray must be given in world coordinates.
  3074. * <p>
  3075. * This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
  3076. * primitives regardless of their visibility.
  3077. * </p>
  3078. *
  3079. * @private
  3080. *
  3081. * @param {Ray} ray The ray.
  3082. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  3083. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3084. * @returns {Object} An object containing the object and position of the first intersection.
  3085. *
  3086. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  3087. */
  3088. Scene.prototype.pickFromRay = function(ray, objectsToExclude, width) {
  3089. return this._picking.pickFromRay(this, ray, objectsToExclude, width);
  3090. };
  3091. /**
  3092. * Returns a list of objects, each containing the object intersected by the ray and the position of intersection.
  3093. * The intersected object has a <code>primitive</code> property that contains the intersected primitive. Other
  3094. * properties may also be set depending on the type of primitive and may be used to further identify the picked object.
  3095. * The primitives in the list are ordered by first intersection to last intersection. The ray must be given in
  3096. * world coordinates.
  3097. * <p>
  3098. * This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
  3099. * primitives regardless of their visibility.
  3100. * </p>
  3101. *
  3102. * @private
  3103. *
  3104. * @param {Ray} ray The ray.
  3105. * @param {Number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
  3106. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  3107. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3108. * @returns {Object[]} List of objects containing the object and position of each intersection.
  3109. *
  3110. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  3111. */
  3112. Scene.prototype.drillPickFromRay = function(ray, limit, objectsToExclude, width) {
  3113. return this._picking.drillPickFromRay(this, ray, limit, objectsToExclude, width);
  3114. };
  3115. /**
  3116. * Initiates an asynchronous {@link Scene#pickFromRay} request using the maximum level of detail for 3D Tilesets
  3117. * regardless of visibility.
  3118. *
  3119. * @private
  3120. *
  3121. * @param {Ray} ray The ray.
  3122. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  3123. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3124. * @returns {Promise.<Object>} A promise that resolves to an object containing the object and position of the first intersection.
  3125. *
  3126. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  3127. */
  3128. Scene.prototype.pickFromRayMostDetailed = function(ray, objectsToExclude, width) {
  3129. return this._picking.pickFromRayMostDetailed(this, ray, objectsToExclude, width);
  3130. };
  3131. /**
  3132. * Initiates an asynchronous {@link Scene#drillPickFromRay} request using the maximum level of detail for 3D Tilesets
  3133. * regardless of visibility.
  3134. *
  3135. * @private
  3136. *
  3137. * @param {Ray} ray The ray.
  3138. * @param {Number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
  3139. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  3140. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3141. * @returns {Promise.<Object[]>} A promise that resolves to a list of objects containing the object and position of each intersection.
  3142. *
  3143. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  3144. */
  3145. Scene.prototype.drillPickFromRayMostDetailed = function(ray, limit, objectsToExclude, width) {
  3146. return this._picking.drillPickFromRayMostDetailed(this, ray, limit, objectsToExclude, width);
  3147. };
  3148. /**
  3149. * Returns the height of scene geometry at the given cartographic position or <code>undefined</code> if there was no
  3150. * scene geometry to sample height from. The height of the input position is ignored. May be used to clamp objects to
  3151. * the globe, 3D Tiles, or primitives in the scene.
  3152. * <p>
  3153. * This function only samples height from globe tiles and 3D Tiles that are rendered in the current view. Samples height
  3154. * from all other primitives regardless of their visibility.
  3155. * </p>
  3156. *
  3157. * @param {Cartographic} position The cartographic position to sample height from.
  3158. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
  3159. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3160. * @returns {Number} The height. This may be <code>undefined</code> if there was no scene geometry to sample height from.
  3161. *
  3162. * @example
  3163. * var position = new Cesium.Cartographic(-1.31968, 0.698874);
  3164. * var height = viewer.scene.sampleHeight(position);
  3165. * console.log(height);
  3166. *
  3167. * @see Scene#clampToHeight
  3168. * @see Scene#clampToHeightMostDetailed
  3169. * @see Scene#sampleHeightMostDetailed
  3170. *
  3171. * @exception {DeveloperError} sampleHeight is only supported in 3D mode.
  3172. * @exception {DeveloperError} sampleHeight requires depth texture support. Check sampleHeightSupported.
  3173. */
  3174. Scene.prototype.sampleHeight = function(position, objectsToExclude, width) {
  3175. return this._picking.sampleHeight(this, position, objectsToExclude, width);
  3176. };
  3177. /**
  3178. * Clamps the given cartesian position to the scene geometry along the geodetic surface normal. Returns the
  3179. * clamped position or <code>undefined</code> if there was no scene geometry to clamp to. May be used to clamp
  3180. * objects to the globe, 3D Tiles, or primitives in the scene.
  3181. * <p>
  3182. * This function only clamps to globe tiles and 3D Tiles that are rendered in the current view. Clamps to
  3183. * all other primitives regardless of their visibility.
  3184. * </p>
  3185. *
  3186. * @param {Cartesian3} cartesian The cartesian position.
  3187. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
  3188. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3189. * @param {Cartesian3} [result] An optional object to return the clamped position.
  3190. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. This may be <code>undefined</code> if there was no scene geometry to clamp to.
  3191. *
  3192. * @example
  3193. * // Clamp an entity to the underlying scene geometry
  3194. * var position = entity.position.getValue(Cesium.JulianDate.now());
  3195. * entity.position = viewer.scene.clampToHeight(position);
  3196. *
  3197. * @see Scene#sampleHeight
  3198. * @see Scene#sampleHeightMostDetailed
  3199. * @see Scene#clampToHeightMostDetailed
  3200. *
  3201. * @exception {DeveloperError} clampToHeight is only supported in 3D mode.
  3202. * @exception {DeveloperError} clampToHeight requires depth texture support. Check clampToHeightSupported.
  3203. */
  3204. Scene.prototype.clampToHeight = function(cartesian, objectsToExclude, width, result) {
  3205. return this._picking.clampToHeight(this, cartesian, objectsToExclude, width, result);
  3206. };
  3207. /**
  3208. * Initiates an asynchronous {@link Scene#sampleHeight} query for an array of {@link Cartographic} positions
  3209. * using the maximum level of detail for 3D Tilesets in the scene. The height of the input positions is ignored.
  3210. * Returns a promise that is resolved when the query completes. Each point height is modified in place.
  3211. * If a height cannot be determined because no geometry can be sampled at that location, or another error occurs,
  3212. * the height is set to undefined.
  3213. *
  3214. * @param {Cartographic[]} positions The cartographic positions to update with sampled heights.
  3215. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
  3216. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3217. * @returns {Promise.<Number[]>} A promise that resolves to the provided list of positions when the query has completed.
  3218. *
  3219. * @example
  3220. * var positions = [
  3221. * new Cesium.Cartographic(-1.31968, 0.69887),
  3222. * new Cesium.Cartographic(-1.10489, 0.83923)
  3223. * ];
  3224. * var promise = viewer.scene.sampleHeightMostDetailed(positions);
  3225. * promise.then(function(updatedPosition) {
  3226. * // positions[0].height and positions[1].height have been updated.
  3227. * // updatedPositions is just a reference to positions.
  3228. * }
  3229. *
  3230. * @see Scene#sampleHeight
  3231. *
  3232. * @exception {DeveloperError} sampleHeightMostDetailed is only supported in 3D mode.
  3233. * @exception {DeveloperError} sampleHeightMostDetailed requires depth texture support. Check sampleHeightSupported.
  3234. */
  3235. Scene.prototype.sampleHeightMostDetailed = function(positions, objectsToExclude, width) {
  3236. return this._picking.sampleHeightMostDetailed(this, positions, objectsToExclude, width);
  3237. };
  3238. /**
  3239. * Initiates an asynchronous {@link Scene#clampToHeight} query for an array of {@link Cartesian3} positions
  3240. * using the maximum level of detail for 3D Tilesets in the scene. Returns a promise that is resolved when
  3241. * the query completes. Each position is modified in place. If a position cannot be clamped because no geometry
  3242. * can be sampled at that location, or another error occurs, the element in the array is set to undefined.
  3243. *
  3244. * @param {Cartesian3[]} cartesians The cartesian positions to update with clamped positions.
  3245. * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
  3246. * @param {Number} [width=0.1] Width of the intersection volume in meters.
  3247. * @returns {Promise.<Cartesian3[]>} A promise that resolves to the provided list of positions when the query has completed.
  3248. *
  3249. * @example
  3250. * var cartesians = [
  3251. * entities[0].position.getValue(Cesium.JulianDate.now()),
  3252. * entities[1].position.getValue(Cesium.JulianDate.now())
  3253. * ];
  3254. * var promise = viewer.scene.clampToHeightMostDetailed(cartesians);
  3255. * promise.then(function(updatedCartesians) {
  3256. * entities[0].position = updatedCartesians[0];
  3257. * entities[1].position = updatedCartesians[1];
  3258. * }
  3259. *
  3260. * @see Scene#clampToHeight
  3261. *
  3262. * @exception {DeveloperError} clampToHeightMostDetailed is only supported in 3D mode.
  3263. * @exception {DeveloperError} clampToHeightMostDetailed requires depth texture support. Check clampToHeightSupported.
  3264. */
  3265. Scene.prototype.clampToHeightMostDetailed = function(cartesians, objectsToExclude, width) {
  3266. return this._picking.clampToHeightMostDetailed(this, cartesians, objectsToExclude, width);
  3267. };
  3268. /**
  3269. * Transforms a position in cartesian coordinates to canvas coordinates. This is commonly used to place an
  3270. * HTML element at the same screen position as an object in the scene.
  3271. *
  3272. * @param {Cartesian3} position The position in cartesian coordinates.
  3273. * @param {Cartesian2} [result] An optional object to return the input position transformed to canvas coordinates.
  3274. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. This may be <code>undefined</code> if the input position is near the center of the ellipsoid.
  3275. *
  3276. * @example
  3277. * // Output the canvas position of longitude/latitude (0, 0) every time the mouse moves.
  3278. * var scene = widget.scene;
  3279. * var ellipsoid = scene.globe.ellipsoid;
  3280. * var position = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  3281. * var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
  3282. * handler.setInputAction(function(movement) {
  3283. * console.log(scene.cartesianToCanvasCoordinates(position));
  3284. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  3285. */
  3286. Scene.prototype.cartesianToCanvasCoordinates = function(position, result) {
  3287. return SceneTransforms.wgs84ToWindowCoordinates(this, position, result);
  3288. };
  3289. /**
  3290. * Instantly completes an active transition.
  3291. */
  3292. Scene.prototype.completeMorph = function(){
  3293. this._transitioner.completeMorph();
  3294. };
  3295. /**
  3296. * Asynchronously transitions the scene to 2D.
  3297. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  3298. */
  3299. Scene.prototype.morphTo2D = function(duration) {
  3300. var ellipsoid;
  3301. var globe = this.globe;
  3302. if (defined(globe)) {
  3303. ellipsoid = globe.ellipsoid;
  3304. } else {
  3305. ellipsoid = this.mapProjection.ellipsoid;
  3306. }
  3307. duration = defaultValue(duration, 2.0);
  3308. this._transitioner.morphTo2D(duration, ellipsoid);
  3309. };
  3310. /**
  3311. * Asynchronously transitions the scene to Columbus View.
  3312. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  3313. */
  3314. Scene.prototype.morphToColumbusView = function(duration) {
  3315. var ellipsoid;
  3316. var globe = this.globe;
  3317. if (defined(globe)) {
  3318. ellipsoid = globe.ellipsoid;
  3319. } else {
  3320. ellipsoid = this.mapProjection.ellipsoid;
  3321. }
  3322. duration = defaultValue(duration, 2.0);
  3323. this._transitioner.morphToColumbusView(duration, ellipsoid);
  3324. };
  3325. /**
  3326. * Asynchronously transitions the scene to 3D.
  3327. * @param {Number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  3328. */
  3329. Scene.prototype.morphTo3D = function(duration) {
  3330. var ellipsoid;
  3331. var globe = this.globe;
  3332. if (defined(globe)) {
  3333. ellipsoid = globe.ellipsoid;
  3334. } else {
  3335. ellipsoid = this.mapProjection.ellipsoid;
  3336. }
  3337. duration = defaultValue(duration, 2.0);
  3338. this._transitioner.morphTo3D(duration, ellipsoid);
  3339. };
  3340. /**
  3341. * Returns true if this object was destroyed; otherwise, false.
  3342. * <br /><br />
  3343. * If this object was destroyed, it should not be used; calling any function other than
  3344. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  3345. *
  3346. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  3347. *
  3348. * @see Scene#destroy
  3349. */
  3350. Scene.prototype.isDestroyed = function() {
  3351. return false;
  3352. };
  3353. /**
  3354. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  3355. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  3356. * <br /><br />
  3357. * Once an object is destroyed, it should not be used; calling any function other than
  3358. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  3359. * assign the return value (<code>undefined</code>) to the object as done in the example.
  3360. *
  3361. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  3362. *
  3363. *
  3364. * @example
  3365. * scene = scene && scene.destroy();
  3366. *
  3367. * @see Scene#isDestroyed
  3368. */
  3369. Scene.prototype.destroy = function() {
  3370. this._tweens.removeAll();
  3371. this._computeEngine = this._computeEngine && this._computeEngine.destroy();
  3372. this._screenSpaceCameraController = this._screenSpaceCameraController && this._screenSpaceCameraController.destroy();
  3373. this._deviceOrientationCameraController = this._deviceOrientationCameraController && !this._deviceOrientationCameraController.isDestroyed() && this._deviceOrientationCameraController.destroy();
  3374. this._primitives = this._primitives && this._primitives.destroy();
  3375. this._groundPrimitives = this._groundPrimitives && this._groundPrimitives.destroy();
  3376. this._globe = this._globe && this._globe.destroy();
  3377. this.skyBox = this.skyBox && this.skyBox.destroy();
  3378. this.skyAtmosphere = this.skyAtmosphere && this.skyAtmosphere.destroy();
  3379. this._debugSphere = this._debugSphere && this._debugSphere.destroy();
  3380. this.sun = this.sun && this.sun.destroy();
  3381. this._sunPostProcess = this._sunPostProcess && this._sunPostProcess.destroy();
  3382. this._depthPlane = this._depthPlane && this._depthPlane.destroy();
  3383. this._transitioner = this._transitioner && this._transitioner.destroy();
  3384. this._debugFrustumPlanes = this._debugFrustumPlanes && this._debugFrustumPlanes.destroy();
  3385. this._brdfLutGenerator = this._brdfLutGenerator && this._brdfLutGenerator.destroy();
  3386. this._picking = this._picking && this._picking.destroy();
  3387. this._defaultView = this._defaultView && this._defaultView.destroy();
  3388. this._view = undefined;
  3389. if (this._removeCreditContainer) {
  3390. this._canvas.parentNode.removeChild(this._creditContainer);
  3391. }
  3392. this.postProcessStages = this.postProcessStages && this.postProcessStages.destroy();
  3393. this._context = this._context && this._context.destroy();
  3394. this._frameState.creditDisplay = this._frameState.creditDisplay && this._frameState.creditDisplay.destroy();
  3395. if (defined(this._performanceDisplay)){
  3396. this._performanceDisplay = this._performanceDisplay && this._performanceDisplay.destroy();
  3397. this._performanceContainer.parentNode.removeChild(this._performanceContainer);
  3398. }
  3399. this._removeRequestListenerCallback();
  3400. this._removeTaskProcessorListenerCallback();
  3401. for (var i = 0; i < this._removeGlobeCallbacks.length; ++i) {
  3402. this._removeGlobeCallbacks[i]();
  3403. }
  3404. this._removeGlobeCallbacks.length = 0;
  3405. return destroyObject(this);
  3406. };
  3407. export default Scene;