123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533 |
- import BoundingRectangle from "../Core/BoundingRectangle.js";
- import BoundingSphere from "../Core/BoundingSphere.js";
- import BoxGeometry from "../Core/BoxGeometry.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import Cartographic from "../Core/Cartographic.js";
- import Check from "../Core/Check.js";
- import clone from "../Core/clone.js";
- import Color from "../Core/Color.js";
- import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
- import createGuid from "../Core/createGuid.js";
- import CullingVolume from "../Core/CullingVolume.js";
- import defaultValue from "../Core/defaultValue.js";
- import defined from "../Core/defined.js";
- import destroyObject from "../Core/destroyObject.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import EllipsoidGeometry from "../Core/EllipsoidGeometry.js";
- import Event from "../Core/Event.js";
- import GeographicProjection from "../Core/GeographicProjection.js";
- import GeometryInstance from "../Core/GeometryInstance.js";
- import GeometryPipeline from "../Core/GeometryPipeline.js";
- import Intersect from "../Core/Intersect.js";
- import JulianDate from "../Core/JulianDate.js";
- import CesiumMath from "../Core/Math.js";
- import Matrix4 from "../Core/Matrix4.js";
- import mergeSort from "../Core/mergeSort.js";
- import Occluder from "../Core/Occluder.js";
- import OrthographicFrustum from "../Core/OrthographicFrustum.js";
- import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js";
- import PerspectiveFrustum from "../Core/PerspectiveFrustum.js";
- import PerspectiveOffCenterFrustum from "../Core/PerspectiveOffCenterFrustum.js";
- import RequestScheduler from "../Core/RequestScheduler.js";
- import TaskProcessor from "../Core/TaskProcessor.js";
- import Transforms from "../Core/Transforms.js";
- import ClearCommand from "../Renderer/ClearCommand.js";
- import ComputeEngine from "../Renderer/ComputeEngine.js";
- import Context from "../Renderer/Context.js";
- import ContextLimits from "../Renderer/ContextLimits.js";
- import Pass from "../Renderer/Pass.js";
- import RenderState from "../Renderer/RenderState.js";
- import BrdfLutGenerator from "./BrdfLutGenerator.js";
- import Camera from "./Camera.js";
- import Cesium3DTilePass from "./Cesium3DTilePass.js";
- import Cesium3DTilePassState from "./Cesium3DTilePassState.js";
- import CreditDisplay from "./CreditDisplay.js";
- import DebugCameraPrimitive from "./DebugCameraPrimitive.js";
- import DepthPlane from "./DepthPlane.js";
- import DerivedCommand from "./DerivedCommand.js";
- import DeviceOrientationCameraController from "./DeviceOrientationCameraController.js";
- import Fog from "./Fog.js";
- import FrameState from "./FrameState.js";
- import GlobeTranslucencyState from "./GlobeTranslucencyState.js";
- import InvertClassification from "./InvertClassification.js";
- import JobScheduler from "./JobScheduler.js";
- import MapMode2D from "./MapMode2D.js";
- import OctahedralProjectedCubeMap from "./OctahedralProjectedCubeMap.js";
- import PerformanceDisplay from "./PerformanceDisplay.js";
- import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js";
- import Picking from "./Picking.js";
- import PostProcessStageCollection from "./PostProcessStageCollection.js";
- import Primitive from "./Primitive.js";
- import PrimitiveCollection from "./PrimitiveCollection.js";
- import SceneMode from "./SceneMode.js";
- import SceneTransforms from "./SceneTransforms.js";
- import SceneTransitioner from "./SceneTransitioner.js";
- import ScreenSpaceCameraController from "./ScreenSpaceCameraController.js";
- import ShadowMap from "./ShadowMap.js";
- import StencilConstants from "./StencilConstants.js";
- import SunLight from "./SunLight.js";
- import SunPostProcess from "./SunPostProcess.js";
- import TweenCollection from "./TweenCollection.js";
- import View from "./View.js";
- import DebugInspector from "./DebugInspector.js";
- const requestRenderAfterFrame = function (scene) {
- return function () {
- scene.frameState.afterRender.push(function () {
- scene.requestRender();
- });
- };
- };
- /**
- * The container for all 3D graphical objects and state in a Cesium virtual scene. Generally,
- * a scene is not created directly; instead, it is implicitly created by {@link CesiumWidget}.
- *
- * @alias Scene
- * @constructor
- *
- * @param {object} options Object with the following properties:
- * @param {HTMLCanvasElement} options.canvas The HTML canvas element to create the scene for.
- * @param {ContextOptions} [options.contextOptions] Context and WebGL creation properties.
- * @param {Element} [options.creditContainer] The HTML element in which the credits will be displayed.
- * @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.
- * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes.
- * @param {boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
- * @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.
- * @param {boolean} [options.shadows=false] Determines if shadows are cast by light sources.
- * @param {MapMode2D} [options.mapMode2D=MapMode2D.INFINITE_SCROLL] Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
- * @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}.
- * @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}.
- * @param {number} [options.depthPlaneEllipsoidOffset=0.0] Adjust the DepthPlane to address rendering artefacts below ellipsoid zero elevation.
- * @param {number} [options.msaaSamples=1] If provided, this value controls the rate of multisample antialiasing. Typical multisampling rates are 2, 4, and sometimes 8 samples per pixel. Higher sampling rates of MSAA may impact performance in exchange for improved visual quality. This value only applies to WebGL2 contexts that support multisample render targets.
- *
- * @see CesiumWidget
- * @see {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
- *
- * @exception {DeveloperError} options and options.canvas are required.
- *
- * @example
- * // Create scene without anisotropic texture filtering
- * const scene = new Cesium.Scene({
- * canvas : canvas,
- * contextOptions : {
- * allowTextureFilterAnisotropic : false
- * }
- * });
- */
- function Scene(options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- const canvas = options.canvas;
- let creditContainer = options.creditContainer;
- let creditViewport = options.creditViewport;
- const contextOptions = clone(options.contextOptions);
- //>>includeStart('debug', pragmas.debug);
- if (!defined(canvas)) {
- throw new DeveloperError("options and options.canvas are required.");
- }
- //>>includeEnd('debug');
- const hasCreditContainer = defined(creditContainer);
- const context = new Context(canvas, contextOptions);
- if (!hasCreditContainer) {
- creditContainer = document.createElement("div");
- creditContainer.style.position = "absolute";
- creditContainer.style.bottom = "0";
- creditContainer.style["text-shadow"] = "0 0 2px #000000";
- creditContainer.style.color = "#ffffff";
- creditContainer.style["font-size"] = "10px";
- creditContainer.style["padding-right"] = "5px";
- canvas.parentNode.appendChild(creditContainer);
- }
- if (!defined(creditViewport)) {
- creditViewport = canvas.parentNode;
- }
- this._id = createGuid();
- this._jobScheduler = new JobScheduler();
- this._frameState = new FrameState(
- context,
- new CreditDisplay(creditContainer, " • ", creditViewport),
- this._jobScheduler
- );
- this._frameState.scene3DOnly = defaultValue(options.scene3DOnly, false);
- this._removeCreditContainer = !hasCreditContainer;
- this._creditContainer = creditContainer;
- this._canvas = canvas;
- this._context = context;
- this._computeEngine = new ComputeEngine(context);
- this._globe = undefined;
- this._globeTranslucencyState = new GlobeTranslucencyState();
- this._primitives = new PrimitiveCollection();
- this._groundPrimitives = new PrimitiveCollection();
- this._globeHeight = undefined;
- this._cameraUnderground = false;
- this._logDepthBuffer = context.fragmentDepth;
- this._logDepthBufferDirty = true;
- this._tweens = new TweenCollection();
- this._shaderFrameCount = 0;
- this._sunPostProcess = undefined;
- this._computeCommandList = [];
- this._overlayCommandList = [];
- this._useOIT = defaultValue(options.orderIndependentTranslucency, true);
- this._executeOITFunction = undefined;
- this._depthPlane = new DepthPlane(options.depthPlaneEllipsoidOffset);
- this._clearColorCommand = new ClearCommand({
- color: new Color(),
- stencil: 0,
- owner: this,
- });
- this._depthClearCommand = new ClearCommand({
- depth: 1.0,
- owner: this,
- });
- this._stencilClearCommand = new ClearCommand({
- stencil: 0,
- });
- this._classificationStencilClearCommand = new ClearCommand({
- stencil: 0,
- renderState: RenderState.fromCache({
- stencilMask: StencilConstants.CLASSIFICATION_MASK,
- }),
- });
- this._depthOnlyRenderStateCache = {};
- this._transitioner = new SceneTransitioner(this);
- this._preUpdate = new Event();
- this._postUpdate = new Event();
- this._renderError = new Event();
- this._preRender = new Event();
- this._postRender = new Event();
- this._minimumDisableDepthTestDistance = 0.0;
- this._debugInspector = new DebugInspector();
- this._msaaSamples = defaultValue(options.msaaSamples, 1);
- /**
- * Exceptions occurring in <code>render</code> are always caught in order to raise the
- * <code>renderError</code> event. If this property is true, the error is rethrown
- * after the event is raised. If this property is false, the <code>render</code> function
- * returns normally after raising the event.
- *
- * @type {boolean}
- * @default false
- */
- this.rethrowRenderErrors = false;
- /**
- * Determines whether or not to instantly complete the
- * scene transition animation on user input.
- *
- * @type {boolean}
- * @default true
- */
- this.completeMorphOnUserInput = true;
- /**
- * The event fired at the beginning of a scene transition.
- * @type {Event}
- * @default Event()
- */
- this.morphStart = new Event();
- /**
- * The event fired at the completion of a scene transition.
- * @type {Event}
- * @default Event()
- */
- this.morphComplete = new Event();
- /**
- * The {@link SkyBox} used to draw the stars.
- *
- * @type {SkyBox}
- * @default undefined
- *
- * @see Scene#backgroundColor
- */
- this.skyBox = undefined;
- /**
- * The sky atmosphere drawn around the globe.
- *
- * @type {SkyAtmosphere}
- * @default undefined
- */
- this.skyAtmosphere = undefined;
- /**
- * The {@link Sun}.
- *
- * @type {Sun}
- * @default undefined
- */
- this.sun = undefined;
- /**
- * Uses a bloom filter on the sun when enabled.
- *
- * @type {boolean}
- * @default true
- */
- this.sunBloom = true;
- this._sunBloom = undefined;
- /**
- * The {@link Moon}
- *
- * @type Moon
- * @default undefined
- */
- this.moon = undefined;
- /**
- * The background color, which is only visible if there is no sky box, i.e., {@link Scene#skyBox} is undefined.
- *
- * @type {Color}
- * @default {@link Color.BLACK}
- *
- * @see Scene#skyBox
- */
- this.backgroundColor = Color.clone(Color.BLACK);
- this._mode = SceneMode.SCENE3D;
- this._mapProjection = defined(options.mapProjection)
- ? options.mapProjection
- : new GeographicProjection();
- /**
- * The current morph transition time between 2D/Columbus View and 3D,
- * with 0.0 being 2D or Columbus View and 1.0 being 3D.
- *
- * @type {number}
- * @default 1.0
- */
- this.morphTime = 1.0;
- /**
- * The far-to-near ratio of the multi-frustum when using a normal depth buffer.
- * <p>
- * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used
- * when {@link Scene#logarithmicDepthBuffer} is <code>false</code>. When <code>logarithmicDepthBuffer</code> is
- * <code>true</code>, use {@link Scene#logarithmicDepthFarToNearRatio}.
- * </p>
- *
- * @type {number}
- * @default 1000.0
- */
- this.farToNearRatio = 1000.0;
- /**
- * The far-to-near ratio of the multi-frustum when using a logarithmic depth buffer.
- * <p>
- * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used
- * when {@link Scene#logarithmicDepthBuffer} is <code>true</code>. When <code>logarithmicDepthBuffer</code> is
- * <code>false</code>, use {@link Scene#farToNearRatio}.
- * </p>
- *
- * @type {number}
- * @default 1e9
- */
- this.logarithmicDepthFarToNearRatio = 1e9;
- /**
- * Determines the uniform depth size in meters of each frustum of the multifrustum in 2D. If a primitive or model close
- * to the surface shows z-fighting, decreasing this will eliminate the artifact, but decrease performance. On the
- * other hand, increasing this will increase performance but may cause z-fighting among primitives close to the surface.
- *
- * @type {number}
- * @default 1.75e6
- */
- this.nearToFarDistance2D = 1.75e6;
- /**
- * This property is for debugging only; it is not for production use.
- * <p>
- * A function that determines what commands are executed. As shown in the examples below,
- * the function receives the command's <code>owner</code> as an argument, and returns a boolean indicating if the
- * command should be executed.
- * </p>
- * <p>
- * The default is <code>undefined</code>, indicating that all commands are executed.
- * </p>
- *
- * @type Function
- *
- * @default undefined
- *
- * @example
- * // Do not execute any commands.
- * scene.debugCommandFilter = function(command) {
- * return false;
- * };
- *
- * // Execute only the billboard's commands. That is, only draw the billboard.
- * const billboards = new Cesium.BillboardCollection();
- * scene.debugCommandFilter = function(command) {
- * return command.owner === billboards;
- * };
- */
- this.debugCommandFilter = undefined;
- /**
- * This property is for debugging only; it is not for production use.
- * <p>
- * When <code>true</code>, commands are randomly shaded. This is useful
- * for performance analysis to see what parts of a scene or model are
- * command-dense and could benefit from batching.
- * </p>
- *
- * @type {boolean}
- *
- * @default false
- */
- this.debugShowCommands = false;
- /**
- * This property is for debugging only; it is not for production use.
- * <p>
- * When <code>true</code>, commands are shaded based on the frustums they
- * overlap. Commands in the closest frustum are tinted red, commands in
- * the next closest are green, and commands in the farthest frustum are
- * blue. If a command overlaps more than one frustum, the color components
- * are combined, e.g., a command overlapping the first two frustums is tinted
- * yellow.
- * </p>
- *
- * @type {boolean}
- *
- * @default false
- */
- this.debugShowFrustums = false;
- /**
- * This property is for debugging only; it is not for production use.
- * <p>
- * Displays frames per second and time between frames.
- * </p>
- *
- * @type {boolean}
- *
- * @default false
- */
- this.debugShowFramesPerSecond = false;
- /**
- * This property is for debugging only; it is not for production use.
- * <p>
- * Indicates which frustum will have depth information displayed.
- * </p>
- *
- * @type {number}
- *
- * @default 1
- */
- this.debugShowDepthFrustum = 1;
- /**
- * This property is for debugging only; it is not for production use.
- * <p>
- * When <code>true</code>, draws outlines to show the boundaries of the camera frustums
- * </p>
- *
- * @type {boolean}
- *
- * @default false
- */
- this.debugShowFrustumPlanes = false;
- this._debugShowFrustumPlanes = false;
- this._debugFrustumPlanes = undefined;
- /**
- * When <code>true</code>, enables picking using the depth buffer.
- *
- * @type {boolean}
- * @default true
- */
- this.useDepthPicking = true;
- /**
- * 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.
- *
- * <p>
- * There is a decrease in performance when enabled. There are extra draw calls to write depth for
- * translucent geometry.
- * </p>
- *
- * @example
- * // picking the position of a translucent primitive
- * viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
- * const pickedFeature = viewer.scene.pick(movement.position);
- * if (!Cesium.defined(pickedFeature)) {
- * // nothing picked
- * return;
- * }
- * const worldPosition = viewer.scene.pickPosition(movement.position);
- * }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
- *
- * @type {boolean}
- * @default false
- */
- this.pickTranslucentDepth = false;
- /**
- * The time in milliseconds to wait before checking if the camera has not moved and fire the cameraMoveEnd event.
- * @type {number}
- * @default 500.0
- * @private
- */
- this.cameraEventWaitTime = 500.0;
- /**
- * Blends the atmosphere to geometry far from the camera for horizon views. Allows for additional
- * performance improvements by rendering less geometry and dispatching less terrain requests.
- * @type {Fog}
- */
- this.fog = new Fog();
- this._shadowMapCamera = new Camera(this);
- /**
- * The shadow map for the scene's light source. When enabled, models, primitives, and the globe may cast and receive shadows.
- * @type {ShadowMap}
- */
- this.shadowMap = new ShadowMap({
- context: context,
- lightCamera: this._shadowMapCamera,
- enabled: defaultValue(options.shadows, false),
- });
- /**
- * When <code>false</code>, 3D Tiles will render normally. When <code>true</code>, classified 3D Tile geometry will render normally and
- * unclassified 3D Tile geometry will render with the color multiplied by {@link Scene#invertClassificationColor}.
- * @type {boolean}
- * @default false
- */
- this.invertClassification = false;
- /**
- * The highlight color of unclassified 3D Tile geometry when {@link Scene#invertClassification} is <code>true</code>.
- * <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>
- * <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>
- * @type {Color}
- * @default Color.WHITE
- */
- this.invertClassificationColor = Color.clone(Color.WHITE);
- this._actualInvertClassificationColor = Color.clone(
- this._invertClassificationColor
- );
- this._invertClassification = new InvertClassification();
- /**
- * The focal length for use when with cardboard or WebVR.
- * @type {number}
- */
- this.focalLength = undefined;
- /**
- * The eye separation distance in meters for use with cardboard or WebVR.
- * @type {number}
- */
- this.eyeSeparation = undefined;
- /**
- * Post processing effects applied to the final render.
- * @type {PostProcessStageCollection}
- */
- this.postProcessStages = new PostProcessStageCollection();
- this._brdfLutGenerator = new BrdfLutGenerator();
- this._performanceDisplay = undefined;
- this._debugVolume = undefined;
- this._screenSpaceCameraController = new ScreenSpaceCameraController(this);
- this._cameraUnderground = false;
- this._mapMode2D = defaultValue(options.mapMode2D, MapMode2D.INFINITE_SCROLL);
- // Keeps track of the state of a frame. FrameState is the state across
- // the primitives of the scene. This state is for internally keeping track
- // of celestial and environment effects that need to be updated/rendered in
- // a certain order as well as updating/tracking framebuffer usage.
- this._environmentState = {
- skyBoxCommand: undefined,
- skyAtmosphereCommand: undefined,
- sunDrawCommand: undefined,
- sunComputeCommand: undefined,
- moonCommand: undefined,
- isSunVisible: false,
- isMoonVisible: false,
- isReadyForAtmosphere: false,
- isSkyAtmosphereVisible: false,
- clearGlobeDepth: false,
- useDepthPlane: false,
- renderTranslucentDepthForPick: false,
- originalFramebuffer: undefined,
- useGlobeDepthFramebuffer: false,
- useOIT: false,
- useInvertClassification: false,
- usePostProcess: false,
- usePostProcessSelected: false,
- useWebVR: false,
- };
- this._useWebVR = false;
- this._cameraVR = undefined;
- this._aspectRatioVR = undefined;
- /**
- * When <code>true</code>, 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}
- * @see Scene#maximumRenderTimeChange
- * @see Scene#requestRender
- *
- * @type {boolean}
- * @default false
- */
- this.requestRenderMode = defaultValue(options.requestRenderMode, false);
- this._renderRequested = true;
- /**
- * If {@link Scene#requestRenderMode} is <code>true</code>, this value defines the maximum change in
- * simulation time allowed before a render is requested. Lower values increase the number of frames rendered
- * and higher values decrease the number of frames rendered. If <code>undefined</code>, changes to
- * the simulation time will never request a render.
- * This value impacts the rate of rendering for changes in the scene like lighting, entity property updates,
- * and animations.
- *
- * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
- * @see Scene#requestRenderMode
- *
- * @type {number}
- * @default 0.0
- */
- this.maximumRenderTimeChange = defaultValue(
- options.maximumRenderTimeChange,
- 0.0
- );
- this._lastRenderTime = undefined;
- this._frameRateMonitor = undefined;
- this._removeRequestListenerCallback = RequestScheduler.requestCompletedEvent.addEventListener(
- requestRenderAfterFrame(this)
- );
- this._removeTaskProcessorListenerCallback = TaskProcessor.taskCompletedEvent.addEventListener(
- requestRenderAfterFrame(this)
- );
- this._removeGlobeCallbacks = [];
- this._removeTerrainProviderReadyListener = undefined;
- const viewport = new BoundingRectangle(
- 0,
- 0,
- context.drawingBufferWidth,
- context.drawingBufferHeight
- );
- const camera = new Camera(this);
- if (this._logDepthBuffer) {
- camera.frustum.near = 0.1;
- camera.frustum.far = 10000000000.0;
- }
- /**
- * The camera view for the scene camera flight destination. Used for preloading flight destination tiles.
- * @type {Camera}
- * @private
- */
- this.preloadFlightCamera = new Camera(this);
- /**
- * The culling volume for the scene camera flight destination. Used for preloading flight destination tiles.
- * @type {CullingVolume}
- * @private
- */
- this.preloadFlightCullingVolume = undefined;
- this._picking = new Picking(this);
- this._defaultView = new View(this, camera, viewport);
- this._view = this._defaultView;
- this._hdr = undefined;
- this._hdrDirty = undefined;
- this.highDynamicRange = false;
- this.gamma = 2.2;
- /**
- * The spherical harmonic coefficients for image-based lighting of PBR models.
- * @type {Cartesian3[]}
- */
- this.sphericalHarmonicCoefficients = undefined;
- /**
- * The url to the KTX2 file containing the specular environment map and convoluted mipmaps for image-based lighting of PBR models.
- * @type {string}
- */
- this.specularEnvironmentMaps = undefined;
- this._specularEnvironmentMapAtlas = undefined;
- /**
- * The light source for shading. Defaults to a directional light from the Sun.
- * @type {Light}
- */
- this.light = new SunLight();
- // Give frameState, camera, and screen space camera controller initial state before rendering
- updateFrameNumber(this, 0.0, JulianDate.now());
- this.updateFrameState();
- this.initializeFrame();
- }
- function updateGlobeListeners(scene, globe) {
- for (let i = 0; i < scene._removeGlobeCallbacks.length; ++i) {
- scene._removeGlobeCallbacks[i]();
- }
- scene._removeGlobeCallbacks.length = 0;
- const removeGlobeCallbacks = [];
- if (defined(globe)) {
- removeGlobeCallbacks.push(
- globe.imageryLayersUpdatedEvent.addEventListener(
- requestRenderAfterFrame(scene)
- )
- );
- removeGlobeCallbacks.push(
- globe.terrainProviderChanged.addEventListener(
- requestRenderAfterFrame(scene)
- )
- );
- }
- scene._removeGlobeCallbacks = removeGlobeCallbacks;
- }
- Object.defineProperties(Scene.prototype, {
- /**
- * Gets the canvas element to which this scene is bound.
- * @memberof Scene.prototype
- *
- * @type {HTMLCanvasElement}
- * @readonly
- */
- canvas: {
- get: function () {
- return this._canvas;
- },
- },
- /**
- * The drawingBufferHeight of the underlying GL context.
- * @memberof Scene.prototype
- *
- * @type {number}
- * @readonly
- *
- * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
- */
- drawingBufferHeight: {
- get: function () {
- return this._context.drawingBufferHeight;
- },
- },
- /**
- * The drawingBufferHeight of the underlying GL context.
- * @memberof Scene.prototype
- *
- * @type {number}
- * @readonly
- *
- * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
- */
- drawingBufferWidth: {
- get: function () {
- return this._context.drawingBufferWidth;
- },
- },
- /**
- * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one.
- * @memberof Scene.prototype
- *
- * @type {number}
- * @readonly
- *
- * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>.
- */
- maximumAliasedLineWidth: {
- get: function () {
- return ContextLimits.maximumAliasedLineWidth;
- },
- },
- /**
- * The maximum length in pixels of one edge of a cube map, supported by this WebGL implementation. It will be at least 16.
- * @memberof Scene.prototype
- *
- * @type {number}
- * @readonly
- *
- * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>GL_MAX_CUBE_MAP_TEXTURE_SIZE</code>.
- */
- maximumCubeMapSize: {
- get: function () {
- return ContextLimits.maximumCubeMapSize;
- },
- },
- /**
- * Returns <code>true</code> if the {@link Scene#pickPosition} function is supported.
- * @memberof Scene.prototype
- *
- * @type {boolean}
- * @readonly
- *
- * @see Scene#pickPosition
- */
- pickPositionSupported: {
- get: function () {
- return this._context.depthTexture;
- },
- },
- /**
- * Returns <code>true</code> if the {@link Scene#sampleHeight} and {@link Scene#sampleHeightMostDetailed} functions are supported.
- * @memberof Scene.prototype
- *
- * @type {boolean}
- * @readonly
- *
- * @see Scene#sampleHeight
- * @see Scene#sampleHeightMostDetailed
- */
- sampleHeightSupported: {
- get: function () {
- return this._context.depthTexture;
- },
- },
- /**
- * Returns <code>true</code> if the {@link Scene#clampToHeight} and {@link Scene#clampToHeightMostDetailed} functions are supported.
- * @memberof Scene.prototype
- *
- * @type {boolean}
- * @readonly
- *
- * @see Scene#clampToHeight
- * @see Scene#clampToHeightMostDetailed
- */
- clampToHeightSupported: {
- get: function () {
- return this._context.depthTexture;
- },
- },
- /**
- * Returns <code>true</code> if the {@link Scene#invertClassification} is supported.
- * @memberof Scene.prototype
- *
- * @type {boolean}
- * @readonly
- *
- * @see Scene#invertClassification
- */
- invertClassificationSupported: {
- get: function () {
- return this._context.depthTexture;
- },
- },
- /**
- * Returns <code>true</code> if specular environment maps are supported.
- * @memberof Scene.prototype
- *
- * @type {boolean}
- * @readonly
- *
- * @see Scene#specularEnvironmentMaps
- */
- specularEnvironmentMapsSupported: {
- get: function () {
- return OctahedralProjectedCubeMap.isSupported(this._context);
- },
- },
- /**
- * Gets or sets the depth-test ellipsoid.
- * @memberof Scene.prototype
- *
- * @type {Globe}
- */
- globe: {
- get: function () {
- return this._globe;
- },
- set: function (globe) {
- this._globe = this._globe && this._globe.destroy();
- this._globe = globe;
- updateGlobeListeners(this, globe);
- },
- },
- /**
- * Gets the collection of primitives.
- * @memberof Scene.prototype
- *
- * @type {PrimitiveCollection}
- * @readonly
- */
- primitives: {
- get: function () {
- return this._primitives;
- },
- },
- /**
- * Gets the collection of ground primitives.
- * @memberof Scene.prototype
- *
- * @type {PrimitiveCollection}
- * @readonly
- */
- groundPrimitives: {
- get: function () {
- return this._groundPrimitives;
- },
- },
- /**
- * Gets or sets the camera.
- * @memberof Scene.prototype
- *
- * @type {Camera}
- * @readonly
- */
- camera: {
- get: function () {
- return this._view.camera;
- },
- set: function (camera) {
- // For internal use only. Documentation is still @readonly.
- this._view.camera = camera;
- },
- },
- /**
- * Gets or sets the view.
- * @memberof Scene.prototype
- *
- * @type {View}
- * @readonly
- *
- * @private
- */
- view: {
- get: function () {
- return this._view;
- },
- set: function (view) {
- // For internal use only. Documentation is still @readonly.
- this._view = view;
- },
- },
- /**
- * Gets the default view.
- * @memberof Scene.prototype
- *
- * @type {View}
- * @readonly
- *
- * @private
- */
- defaultView: {
- get: function () {
- return this._defaultView;
- },
- },
- /**
- * Gets picking functions and state
- * @memberof Scene.prototype
- *
- * @type {Picking}
- * @readonly
- *
- * @private
- */
- picking: {
- get: function () {
- return this._picking;
- },
- },
- /**
- * Gets the controller for camera input handling.
- * @memberof Scene.prototype
- *
- * @type {ScreenSpaceCameraController}
- * @readonly
- */
- screenSpaceCameraController: {
- get: function () {
- return this._screenSpaceCameraController;
- },
- },
- /**
- * Get the map projection to use in 2D and Columbus View modes.
- * @memberof Scene.prototype
- *
- * @type {MapProjection}
- * @readonly
- *
- * @default new GeographicProjection()
- */
- mapProjection: {
- get: function () {
- return this._mapProjection;
- },
- },
- /**
- * Gets the job scheduler
- * @memberof Scene.prototype
- * @type {JobScheduler}
- * @readonly
- *
- * @private
- */
- jobScheduler: {
- get: function () {
- return this._jobScheduler;
- },
- },
- /**
- * Gets state information about the current scene. If called outside of a primitive's <code>update</code>
- * function, the previous frame's state is returned.
- * @memberof Scene.prototype
- *
- * @type {FrameState}
- * @readonly
- *
- * @private
- */
- frameState: {
- get: function () {
- return this._frameState;
- },
- },
- /**
- * Gets the environment state.
- * @memberof Scene.prototype
- *
- * @type {EnvironmentState}
- * @readonly
- *
- * @private
- */
- environmentState: {
- get: function () {
- return this._environmentState;
- },
- },
- /**
- * Gets the collection of tweens taking place in the scene.
- * @memberof Scene.prototype
- *
- * @type {TweenCollection}
- * @readonly
- *
- * @private
- */
- tweens: {
- get: function () {
- return this._tweens;
- },
- },
- /**
- * Gets the collection of image layers that will be rendered on the globe.
- * @memberof Scene.prototype
- *
- * @type {ImageryLayerCollection}
- * @readonly
- */
- imageryLayers: {
- get: function () {
- if (!defined(this.globe)) {
- return undefined;
- }
- return this.globe.imageryLayers;
- },
- },
- /**
- * The terrain provider providing surface geometry for the globe.
- * @memberof Scene.prototype
- *
- * @type {TerrainProvider}
- */
- terrainProvider: {
- get: function () {
- if (!defined(this.globe)) {
- return undefined;
- }
- return this.globe.terrainProvider;
- },
- set: function (terrainProvider) {
- // Cancel any in-progress terrain update
- this._removeTerrainProviderReadyListener =
- this._removeTerrainProviderReadyListener &&
- this._removeTerrainProviderReadyListener();
- if (defined(this.globe)) {
- this.globe.terrainProvider = terrainProvider;
- }
- },
- },
- /**
- * Gets an event that's raised when the terrain provider is changed
- * @memberof Scene.prototype
- *
- * @type {Event}
- * @readonly
- */
- terrainProviderChanged: {
- get: function () {
- if (!defined(this.globe)) {
- return undefined;
- }
- return this.globe.terrainProviderChanged;
- },
- },
- /**
- * Gets the event that will be raised before the scene is updated or rendered. Subscribers to the event
- * receive the Scene instance as the first parameter and the current time as the second parameter.
- * @memberof Scene.prototype
- *
- * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
- * @see Scene#postUpdate
- * @see Scene#preRender
- * @see Scene#postRender
- *
- * @type {Event}
- * @readonly
- */
- preUpdate: {
- get: function () {
- return this._preUpdate;
- },
- },
- /**
- * Gets the event that will be raised immediately after the scene is updated and before the scene is rendered.
- * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second
- * parameter.
- * @memberof Scene.prototype
- *
- * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
- * @see Scene#preUpdate
- * @see Scene#preRender
- * @see Scene#postRender
- *
- * @type {Event}
- * @readonly
- */
- postUpdate: {
- get: function () {
- return this._postUpdate;
- },
- },
- /**
- * Gets the event that will be raised when an error is thrown inside the <code>render</code> function.
- * The Scene instance and the thrown error are the only two parameters passed to the event handler.
- * By default, errors are not rethrown after this event is raised, but that can be changed by setting
- * the <code>rethrowRenderErrors</code> property.
- * @memberof Scene.prototype
- *
- * @type {Event}
- * @readonly
- */
- renderError: {
- get: function () {
- return this._renderError;
- },
- },
- /**
- * Gets the event that will be raised after the scene is updated and immediately before the scene is rendered.
- * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second
- * parameter.
- * @memberof Scene.prototype
- *
- * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
- * @see Scene#preUpdate
- * @see Scene#postUpdate
- * @see Scene#postRender
- *
- * @type {Event}
- * @readonly
- */
- preRender: {
- get: function () {
- return this._preRender;
- },
- },
- /**
- * Gets the event that will be raised immediately after the scene is rendered. Subscribers to the event
- * receive the Scene instance as the first parameter and the current time as the second parameter.
- * @memberof Scene.prototype
- *
- * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
- * @see Scene#preUpdate
- * @see Scene#postUpdate
- * @see Scene#postRender
- *
- * @type {Event}
- * @readonly
- */
- postRender: {
- get: function () {
- return this._postRender;
- },
- },
- /**
- * Gets the simulation time when the scene was last rendered. Returns undefined if the scene has not yet been
- * rendered.
- * @memberof Scene.prototype
- *
- * @type {JulianDate}
- * @readonly
- */
- lastRenderTime: {
- get: function () {
- return this._lastRenderTime;
- },
- },
- /**
- * @memberof Scene.prototype
- * @private
- * @readonly
- */
- context: {
- get: function () {
- return this._context;
- },
- },
- /**
- * This property is for debugging only; it is not for production use.
- * <p>
- * When {@link Scene.debugShowFrustums} is <code>true</code>, this contains
- * properties with statistics about the number of command execute per frustum.
- * <code>totalCommands</code> is the total number of commands executed, ignoring
- * overlap. <code>commandsInFrustums</code> is an array with the number of times
- * commands are executed redundantly, e.g., how many commands overlap two or
- * three frustums.
- * </p>
- *
- * @memberof Scene.prototype
- *
- * @type {object}
- * @readonly
- *
- * @default undefined
- */
- debugFrustumStatistics: {
- get: function () {
- return this._view.debugFrustumStatistics;
- },
- },
- /**
- * Gets whether or not the scene is optimized for 3D only viewing.
- * @memberof Scene.prototype
- * @type {boolean}
- * @readonly
- */
- scene3DOnly: {
- get: function () {
- return this._frameState.scene3DOnly;
- },
- },
- /**
- * Gets whether or not the scene has order independent translucency enabled.
- * Note that this only reflects the original construction option, and there are
- * other factors that could prevent OIT from functioning on a given system configuration.
- * @memberof Scene.prototype
- * @type {boolean}
- * @readonly
- */
- orderIndependentTranslucency: {
- get: function () {
- return this._useOIT;
- },
- },
- /**
- * Gets the unique identifier for this scene.
- * @memberof Scene.prototype
- * @type {string}
- * @readonly
- */
- id: {
- get: function () {
- return this._id;
- },
- },
- /**
- * Gets or sets the current mode of the scene.
- * @memberof Scene.prototype
- * @type {SceneMode}
- * @default {@link SceneMode.SCENE3D}
- */
- mode: {
- get: function () {
- return this._mode;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (this.scene3DOnly && value !== SceneMode.SCENE3D) {
- throw new DeveloperError(
- "Only SceneMode.SCENE3D is valid when scene3DOnly is true."
- );
- }
- //>>includeEnd('debug');
- if (value === SceneMode.SCENE2D) {
- this.morphTo2D(0);
- } else if (value === SceneMode.SCENE3D) {
- this.morphTo3D(0);
- } else if (value === SceneMode.COLUMBUS_VIEW) {
- this.morphToColumbusView(0);
- //>>includeStart('debug', pragmas.debug);
- } else {
- throw new DeveloperError(
- "value must be a valid SceneMode enumeration."
- );
- //>>includeEnd('debug');
- }
- this._mode = value;
- },
- },
- /**
- * Gets the number of frustums used in the last frame.
- * @memberof Scene.prototype
- * @type {FrustumCommands[]}
- *
- * @private
- */
- frustumCommandsList: {
- get: function () {
- return this._view.frustumCommandsList;
- },
- },
- /**
- * Gets the number of frustums used in the last frame.
- * @memberof Scene.prototype
- * @type {number}
- *
- * @private
- */
- numberOfFrustums: {
- get: function () {
- return this._view.frustumCommandsList.length;
- },
- },
- /**
- * When <code>true</code>, splits the scene into two viewports with steroscopic views for the left and right eyes.
- * Used for cardboard and WebVR.
- * @memberof Scene.prototype
- * @type {boolean}
- * @default false
- */
- useWebVR: {
- get: function () {
- return this._useWebVR;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (this.camera.frustum instanceof OrthographicFrustum) {
- throw new DeveloperError(
- "VR is unsupported with an orthographic projection."
- );
- }
- //>>includeEnd('debug');
- this._useWebVR = value;
- if (this._useWebVR) {
- this._frameState.creditDisplay.container.style.visibility = "hidden";
- this._cameraVR = new Camera(this);
- if (!defined(this._deviceOrientationCameraController)) {
- this._deviceOrientationCameraController = new DeviceOrientationCameraController(
- this
- );
- }
- this._aspectRatioVR = this.camera.frustum.aspectRatio;
- } else {
- this._frameState.creditDisplay.container.style.visibility = "visible";
- this._cameraVR = undefined;
- this._deviceOrientationCameraController =
- this._deviceOrientationCameraController &&
- !this._deviceOrientationCameraController.isDestroyed() &&
- this._deviceOrientationCameraController.destroy();
- this.camera.frustum.aspectRatio = this._aspectRatioVR;
- this.camera.frustum.xOffset = 0.0;
- }
- },
- },
- /**
- * Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
- * @memberof Scene.prototype
- * @type {MapMode2D}
- * @readonly
- */
- mapMode2D: {
- get: function () {
- return this._mapMode2D;
- },
- },
- /**
- * Gets or sets the position of the splitter within the viewport. Valid values are between 0.0 and 1.0.
- * @memberof Scene.prototype
- *
- * @type {number}
- */
- splitPosition: {
- get: function () {
- return this._frameState.splitPosition;
- },
- set: function (value) {
- this._frameState.splitPosition = value;
- },
- },
- /**
- * The distance from the camera at which to disable the depth test of billboards, labels and points
- * to, for example, prevent clipping against terrain. When set to zero, the depth test should always
- * be applied. When less than zero, the depth test should never be applied. Setting the disableDepthTestDistance
- * property of a billboard, label or point will override this value.
- * @memberof Scene.prototype
- * @type {number}
- * @default 0.0
- */
- minimumDisableDepthTestDistance: {
- get: function () {
- return this._minimumDisableDepthTestDistance;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value) || value < 0.0) {
- throw new DeveloperError(
- "minimumDisableDepthTestDistance must be greater than or equal to 0.0."
- );
- }
- //>>includeEnd('debug');
- this._minimumDisableDepthTestDistance = value;
- },
- },
- /**
- * Whether or not to use a logarithmic depth buffer. Enabling this option will allow for less frustums in the multi-frustum,
- * increasing performance. This property relies on fragmentDepth being supported.
- * @memberof Scene.prototype
- * @type {boolean}
- */
- logarithmicDepthBuffer: {
- get: function () {
- return this._logDepthBuffer;
- },
- set: function (value) {
- value = this._context.fragmentDepth && value;
- if (this._logDepthBuffer !== value) {
- this._logDepthBuffer = value;
- this._logDepthBufferDirty = true;
- }
- },
- },
- /**
- * The value used for gamma correction. This is only used when rendering with high dynamic range.
- * @memberof Scene.prototype
- * @type {number}
- * @default 2.2
- */
- gamma: {
- get: function () {
- return this._context.uniformState.gamma;
- },
- set: function (value) {
- this._context.uniformState.gamma = value;
- },
- },
- /**
- * Whether or not to use high dynamic range rendering.
- * @memberof Scene.prototype
- * @type {boolean}
- * @default false
- */
- highDynamicRange: {
- get: function () {
- return this._hdr;
- },
- set: function (value) {
- const context = this._context;
- const hdr =
- value &&
- context.depthTexture &&
- (context.colorBufferFloat || context.colorBufferHalfFloat);
- this._hdrDirty = hdr !== this._hdr;
- this._hdr = hdr;
- },
- },
- /**
- * Whether or not high dynamic range rendering is supported.
- * @memberof Scene.prototype
- * @type {boolean}
- * @readonly
- * @default true
- */
- highDynamicRangeSupported: {
- get: function () {
- const context = this._context;
- return (
- context.depthTexture &&
- (context.colorBufferFloat || context.colorBufferHalfFloat)
- );
- },
- },
- /**
- * Whether or not the camera is underneath the globe.
- * @memberof Scene.prototype
- * @type {boolean}
- * @readonly
- * @default false
- */
- cameraUnderground: {
- get: function () {
- return this._cameraUnderground;
- },
- },
- /**
- * The sample rate of multisample antialiasing (values greater than 1 enable MSAA).
- * @memberof Scene.prototype
- * @type {number}
- * @default 1
- */
- msaaSamples: {
- get: function () {
- return this._msaaSamples;
- },
- set: function (value) {
- value = Math.min(value, ContextLimits.maximumSamples);
- this._msaaSamples = value;
- },
- },
- /**
- * Returns <code>true</code> if the Scene's context supports MSAA.
- * @memberof Scene.prototype
- * @type {boolean}
- * @readonly
- */
- msaaSupported: {
- get: function () {
- return this._context.msaa;
- },
- },
- /**
- * Ratio between a pixel and a density-independent pixel. Provides a standard unit of
- * measure for real pixel measurements appropriate to a particular device.
- *
- * @memberof Scene.prototype
- * @type {number}
- * @default 1.0
- * @private
- */
- pixelRatio: {
- get: function () {
- return this._frameState.pixelRatio;
- },
- set: function (value) {
- this._frameState.pixelRatio = value;
- },
- },
- /**
- * @private
- */
- opaqueFrustumNearOffset: {
- get: function () {
- return 0.9999;
- },
- },
- /**
- * @private
- */
- globeHeight: {
- get: function () {
- return this._globeHeight;
- },
- },
- });
- /**
- * Determines if a compressed texture format is supported.
- * @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.
- * @return {boolean} Whether or not the format is supported.
- */
- Scene.prototype.getCompressedTextureFormatSupported = function (format) {
- const context = this.context;
- return (
- ((format === "WEBGL_compressed_texture_s3tc" || format === "s3tc") &&
- context.s3tc) ||
- ((format === "WEBGL_compressed_texture_pvrtc" || format === "pvrtc") &&
- context.pvrtc) ||
- ((format === "WEBGL_compressed_texture_etc" || format === "etc") &&
- context.etc) ||
- ((format === "WEBGL_compressed_texture_etc1" || format === "etc1") &&
- context.etc1) ||
- ((format === "WEBGL_compressed_texture_astc" || format === "astc") &&
- context.astc) ||
- ((format === "EXT_texture_compression_bptc" || format === "bc7") &&
- context.bc7)
- );
- };
- function updateDerivedCommands(scene, command, shadowsDirty) {
- const frameState = scene._frameState;
- const context = scene._context;
- const oit = scene._view.oit;
- const lightShadowMaps = frameState.shadowState.lightShadowMaps;
- const lightShadowsEnabled = frameState.shadowState.lightShadowsEnabled;
- let derivedCommands = command.derivedCommands;
- if (defined(command.pickId)) {
- derivedCommands.picking = DerivedCommand.createPickDerivedCommand(
- scene,
- command,
- context,
- derivedCommands.picking
- );
- }
- if (!command.pickOnly) {
- derivedCommands.depth = DerivedCommand.createDepthOnlyDerivedCommand(
- scene,
- command,
- context,
- derivedCommands.depth
- );
- }
- derivedCommands.originalCommand = command;
- if (scene._hdr) {
- derivedCommands.hdr = DerivedCommand.createHdrCommand(
- command,
- context,
- derivedCommands.hdr
- );
- command = derivedCommands.hdr.command;
- derivedCommands = command.derivedCommands;
- }
- if (lightShadowsEnabled && command.receiveShadows) {
- derivedCommands.shadows = ShadowMap.createReceiveDerivedCommand(
- lightShadowMaps,
- command,
- shadowsDirty,
- context,
- derivedCommands.shadows
- );
- }
- if (command.pass === Pass.TRANSLUCENT && defined(oit) && oit.isSupported()) {
- if (lightShadowsEnabled && command.receiveShadows) {
- derivedCommands.oit = defined(derivedCommands.oit)
- ? derivedCommands.oit
- : {};
- derivedCommands.oit.shadows = oit.createDerivedCommands(
- derivedCommands.shadows.receiveCommand,
- context,
- derivedCommands.oit.shadows
- );
- } else {
- derivedCommands.oit = oit.createDerivedCommands(
- command,
- context,
- derivedCommands.oit
- );
- }
- }
- }
- /**
- * @private
- */
- Scene.prototype.updateDerivedCommands = function (command) {
- if (!defined(command.derivedCommands)) {
- // Is not a DrawCommand
- return;
- }
- const frameState = this._frameState;
- const context = this._context;
- // Update derived commands when any shadow maps become dirty
- let shadowsDirty = false;
- const lastDirtyTime = frameState.shadowState.lastDirtyTime;
- if (command.lastDirtyTime !== lastDirtyTime) {
- command.lastDirtyTime = lastDirtyTime;
- command.dirty = true;
- shadowsDirty = true;
- }
- const useLogDepth = frameState.useLogDepth;
- const useHdr = this._hdr;
- const derivedCommands = command.derivedCommands;
- const hasLogDepthDerivedCommands = defined(derivedCommands.logDepth);
- const hasHdrCommands = defined(derivedCommands.hdr);
- const hasDerivedCommands = defined(derivedCommands.originalCommand);
- const needsLogDepthDerivedCommands =
- useLogDepth && !hasLogDepthDerivedCommands;
- const needsHdrCommands = useHdr && !hasHdrCommands;
- const needsDerivedCommands = (!useLogDepth || !useHdr) && !hasDerivedCommands;
- command.dirty =
- command.dirty ||
- needsLogDepthDerivedCommands ||
- needsHdrCommands ||
- needsDerivedCommands;
- if (command.dirty) {
- command.dirty = false;
- const shadowMaps = frameState.shadowState.shadowMaps;
- const shadowsEnabled = frameState.shadowState.shadowsEnabled;
- if (shadowsEnabled && command.castShadows) {
- derivedCommands.shadows = ShadowMap.createCastDerivedCommand(
- shadowMaps,
- command,
- shadowsDirty,
- context,
- derivedCommands.shadows
- );
- }
- if (hasLogDepthDerivedCommands || needsLogDepthDerivedCommands) {
- derivedCommands.logDepth = DerivedCommand.createLogDepthCommand(
- command,
- context,
- derivedCommands.logDepth
- );
- updateDerivedCommands(
- this,
- derivedCommands.logDepth.command,
- shadowsDirty
- );
- }
- if (hasDerivedCommands || needsDerivedCommands) {
- updateDerivedCommands(this, command, shadowsDirty);
- }
- }
- };
- const renderTilesetPassState = new Cesium3DTilePassState({
- pass: Cesium3DTilePass.RENDER,
- });
- const preloadTilesetPassState = new Cesium3DTilePassState({
- pass: Cesium3DTilePass.PRELOAD,
- });
- const preloadFlightTilesetPassState = new Cesium3DTilePassState({
- pass: Cesium3DTilePass.PRELOAD_FLIGHT,
- });
- const requestRenderModeDeferCheckPassState = new Cesium3DTilePassState({
- pass: Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK,
- });
- const scratchOccluderBoundingSphere = new BoundingSphere();
- let scratchOccluder;
- function getOccluder(scene) {
- // TODO: The occluder is the top-level globe. When we add
- // support for multiple central bodies, this should be the closest one.
- const globe = scene.globe;
- if (
- scene._mode === SceneMode.SCENE3D &&
- defined(globe) &&
- globe.show &&
- !scene._cameraUnderground &&
- !scene._globeTranslucencyState.translucent
- ) {
- const ellipsoid = globe.ellipsoid;
- const minimumTerrainHeight = scene.frameState.minimumTerrainHeight;
- scratchOccluderBoundingSphere.radius =
- ellipsoid.minimumRadius + minimumTerrainHeight;
- scratchOccluder = Occluder.fromBoundingSphere(
- scratchOccluderBoundingSphere,
- scene.camera.positionWC,
- scratchOccluder
- );
- return scratchOccluder;
- }
- return undefined;
- }
- /**
- * @private
- */
- Scene.prototype.clearPasses = function (passes) {
- passes.render = false;
- passes.pick = false;
- passes.depth = false;
- passes.postProcess = false;
- passes.offscreen = false;
- };
- function updateFrameNumber(scene, frameNumber, time) {
- const frameState = scene._frameState;
- frameState.frameNumber = frameNumber;
- frameState.time = JulianDate.clone(time, frameState.time);
- }
- /**
- * @private
- */
- Scene.prototype.updateFrameState = function () {
- const camera = this.camera;
- const frameState = this._frameState;
- frameState.commandList.length = 0;
- frameState.shadowMaps.length = 0;
- frameState.brdfLutGenerator = this._brdfLutGenerator;
- frameState.environmentMap = this.skyBox && this.skyBox._cubeMap;
- frameState.mode = this._mode;
- frameState.morphTime = this.morphTime;
- frameState.mapProjection = this.mapProjection;
- frameState.camera = camera;
- frameState.cullingVolume = camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC
- );
- frameState.occluder = getOccluder(this);
- frameState.minimumTerrainHeight = 0.0;
- frameState.minimumDisableDepthTestDistance = this._minimumDisableDepthTestDistance;
- frameState.invertClassification = this.invertClassification;
- frameState.useLogDepth =
- this._logDepthBuffer &&
- !(
- this.camera.frustum instanceof OrthographicFrustum ||
- this.camera.frustum instanceof OrthographicOffCenterFrustum
- );
- frameState.light = this.light;
- frameState.cameraUnderground = this._cameraUnderground;
- frameState.globeTranslucencyState = this._globeTranslucencyState;
- if (defined(this.globe)) {
- frameState.terrainExaggeration = this.globe.terrainExaggeration;
- frameState.terrainExaggerationRelativeHeight = this.globe.terrainExaggerationRelativeHeight;
- }
- if (
- defined(this._specularEnvironmentMapAtlas) &&
- this._specularEnvironmentMapAtlas.ready
- ) {
- frameState.specularEnvironmentMaps = this._specularEnvironmentMapAtlas.texture;
- frameState.specularEnvironmentMapsMaximumLOD = this._specularEnvironmentMapAtlas.maximumMipmapLevel;
- } else {
- frameState.specularEnvironmentMaps = undefined;
- frameState.specularEnvironmentMapsMaximumLOD = undefined;
- }
- frameState.sphericalHarmonicCoefficients = this.sphericalHarmonicCoefficients;
- this._actualInvertClassificationColor = Color.clone(
- this.invertClassificationColor,
- this._actualInvertClassificationColor
- );
- if (!InvertClassification.isTranslucencySupported(this._context)) {
- this._actualInvertClassificationColor.alpha = 1.0;
- }
- frameState.invertClassificationColor = this._actualInvertClassificationColor;
- if (defined(this.globe)) {
- frameState.maximumScreenSpaceError = this.globe.maximumScreenSpaceError;
- } else {
- frameState.maximumScreenSpaceError = 2;
- }
- this.clearPasses(frameState.passes);
- frameState.tilesetPassState = undefined;
- };
- /**
- * @private
- */
- Scene.prototype.isVisible = function (command, cullingVolume, occluder) {
- return (
- defined(command) &&
- (!defined(command.boundingVolume) ||
- !command.cull ||
- (cullingVolume.computeVisibility(command.boundingVolume) !==
- Intersect.OUTSIDE &&
- (!defined(occluder) ||
- !command.occlude ||
- !command.boundingVolume.isOccluded(occluder))))
- );
- };
- let transformFrom2D = new Matrix4(
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- 1.0
- );
- transformFrom2D = Matrix4.inverseTransformation(
- transformFrom2D,
- transformFrom2D
- );
- function debugShowBoundingVolume(command, scene, passState, debugFramebuffer) {
- // Debug code to draw bounding volume for command. Not optimized!
- // Assumes bounding volume is a bounding sphere or box
- const frameState = scene._frameState;
- const context = frameState.context;
- const boundingVolume = command.boundingVolume;
- if (defined(scene._debugVolume)) {
- scene._debugVolume.destroy();
- }
- let geometry;
- let center = Cartesian3.clone(boundingVolume.center);
- if (frameState.mode !== SceneMode.SCENE3D) {
- center = Matrix4.multiplyByPoint(transformFrom2D, center, center);
- const projection = frameState.mapProjection;
- const centerCartographic = projection.unproject(center);
- center = projection.ellipsoid.cartographicToCartesian(centerCartographic);
- }
- if (defined(boundingVolume.radius)) {
- const radius = boundingVolume.radius;
- geometry = GeometryPipeline.toWireframe(
- EllipsoidGeometry.createGeometry(
- new EllipsoidGeometry({
- radii: new Cartesian3(radius, radius, radius),
- vertexFormat: PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
- })
- )
- );
- scene._debugVolume = new Primitive({
- geometryInstances: new GeometryInstance({
- geometry: geometry,
- modelMatrix: Matrix4.fromTranslation(center),
- attributes: {
- color: new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0),
- },
- }),
- appearance: new PerInstanceColorAppearance({
- flat: true,
- translucent: false,
- }),
- asynchronous: false,
- });
- } else {
- const halfAxes = boundingVolume.halfAxes;
- geometry = GeometryPipeline.toWireframe(
- BoxGeometry.createGeometry(
- BoxGeometry.fromDimensions({
- dimensions: new Cartesian3(2.0, 2.0, 2.0),
- vertexFormat: PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
- })
- )
- );
- scene._debugVolume = new Primitive({
- geometryInstances: new GeometryInstance({
- geometry: geometry,
- modelMatrix: Matrix4.fromRotationTranslation(
- halfAxes,
- center,
- new Matrix4()
- ),
- attributes: {
- color: new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0),
- },
- }),
- appearance: new PerInstanceColorAppearance({
- flat: true,
- translucent: false,
- }),
- asynchronous: false,
- });
- }
- const savedCommandList = frameState.commandList;
- const commandList = (frameState.commandList = []);
- scene._debugVolume.update(frameState);
- command = commandList[0];
- if (frameState.useLogDepth) {
- const logDepth = DerivedCommand.createLogDepthCommand(command, context);
- command = logDepth.command;
- }
- let framebuffer;
- if (defined(debugFramebuffer)) {
- framebuffer = passState.framebuffer;
- passState.framebuffer = debugFramebuffer;
- }
- command.execute(context, passState);
- if (defined(framebuffer)) {
- passState.framebuffer = framebuffer;
- }
- frameState.commandList = savedCommandList;
- }
- function executeCommand(command, scene, context, passState, debugFramebuffer) {
- const frameState = scene._frameState;
- if (defined(scene.debugCommandFilter) && !scene.debugCommandFilter(command)) {
- return;
- }
- if (command instanceof ClearCommand) {
- command.execute(context, passState);
- return;
- }
- if (command.debugShowBoundingVolume && defined(command.boundingVolume)) {
- debugShowBoundingVolume(command, scene, passState, debugFramebuffer);
- }
- if (frameState.useLogDepth && defined(command.derivedCommands.logDepth)) {
- command = command.derivedCommands.logDepth.command;
- }
- const passes = frameState.passes;
- if (
- !passes.pick &&
- !passes.depth &&
- scene._hdr &&
- defined(command.derivedCommands) &&
- defined(command.derivedCommands.hdr)
- ) {
- command = command.derivedCommands.hdr.command;
- }
- if (passes.pick || passes.depth) {
- if (
- passes.pick &&
- !passes.depth &&
- defined(command.derivedCommands.picking)
- ) {
- command = command.derivedCommands.picking.pickCommand;
- command.execute(context, passState);
- return;
- } else if (defined(command.derivedCommands.depth)) {
- command = command.derivedCommands.depth.depthOnlyCommand;
- command.execute(context, passState);
- return;
- }
- }
- if (scene.debugShowCommands || scene.debugShowFrustums) {
- scene._debugInspector.executeDebugShowFrustumsCommand(
- scene,
- command,
- passState
- );
- return;
- }
- if (
- frameState.shadowState.lightShadowsEnabled &&
- command.receiveShadows &&
- defined(command.derivedCommands.shadows)
- ) {
- // If the command receives shadows, execute the derived shadows command.
- // Some commands, such as OIT derived commands, do not have derived shadow commands themselves
- // and instead shadowing is built-in. In this case execute the command regularly below.
- command.derivedCommands.shadows.receiveCommand.execute(context, passState);
- } else {
- command.execute(context, passState);
- }
- }
- function executeIdCommand(command, scene, context, passState) {
- const frameState = scene._frameState;
- let derivedCommands = command.derivedCommands;
- if (!defined(derivedCommands)) {
- return;
- }
- if (frameState.useLogDepth && defined(derivedCommands.logDepth)) {
- command = derivedCommands.logDepth.command;
- }
- derivedCommands = command.derivedCommands;
- if (defined(derivedCommands.picking)) {
- command = derivedCommands.picking.pickCommand;
- command.execute(context, passState);
- } else if (defined(derivedCommands.depth)) {
- command = derivedCommands.depth.depthOnlyCommand;
- command.execute(context, passState);
- }
- }
- function backToFront(a, b, position) {
- return (
- b.boundingVolume.distanceSquaredTo(position) -
- a.boundingVolume.distanceSquaredTo(position)
- );
- }
- function frontToBack(a, b, position) {
- // When distances are equal equal favor sorting b before a. This gives render priority to commands later in the list.
- return (
- a.boundingVolume.distanceSquaredTo(position) -
- b.boundingVolume.distanceSquaredTo(position) +
- CesiumMath.EPSILON12
- );
- }
- function executeTranslucentCommandsBackToFront(
- scene,
- executeFunction,
- passState,
- commands,
- invertClassification
- ) {
- const context = scene.context;
- mergeSort(commands, backToFront, scene.camera.positionWC);
- if (defined(invertClassification)) {
- executeFunction(
- invertClassification.unclassifiedCommand,
- scene,
- context,
- passState
- );
- }
- const length = commands.length;
- for (let i = 0; i < length; ++i) {
- executeFunction(commands[i], scene, context, passState);
- }
- }
- function executeTranslucentCommandsFrontToBack(
- scene,
- executeFunction,
- passState,
- commands,
- invertClassification
- ) {
- const context = scene.context;
- mergeSort(commands, frontToBack, scene.camera.positionWC);
- if (defined(invertClassification)) {
- executeFunction(
- invertClassification.unclassifiedCommand,
- scene,
- context,
- passState
- );
- }
- const length = commands.length;
- for (let i = 0; i < length; ++i) {
- executeFunction(commands[i], scene, context, passState);
- }
- }
- function executeVoxelCommands(scene, executeFunction, passState, commands) {
- const context = scene.context;
- mergeSort(commands, backToFront, scene.camera.positionWC);
- const length = commands.length;
- for (let i = 0; i < length; ++i) {
- executeFunction(commands[i], scene, context, passState);
- }
- }
- const scratchPerspectiveFrustum = new PerspectiveFrustum();
- const scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
- const scratchOrthographicFrustum = new OrthographicFrustum();
- const scratchOrthographicOffCenterFrustum = new OrthographicOffCenterFrustum();
- function executeCommands(scene, passState) {
- const camera = scene.camera;
- const context = scene.context;
- const frameState = scene.frameState;
- const us = context.uniformState;
- us.updateCamera(camera);
- // Create a working frustum from the original camera frustum.
- let frustum;
- if (defined(camera.frustum.fov)) {
- frustum = camera.frustum.clone(scratchPerspectiveFrustum);
- } else if (defined(camera.frustum.infiniteProjectionMatrix)) {
- frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
- } else if (defined(camera.frustum.width)) {
- frustum = camera.frustum.clone(scratchOrthographicFrustum);
- } else {
- frustum = camera.frustum.clone(scratchOrthographicOffCenterFrustum);
- }
- // Ideally, we would render the sky box and atmosphere last for
- // early-z, but we would have to draw it in each frustum
- frustum.near = camera.frustum.near;
- frustum.far = camera.frustum.far;
- us.updateFrustum(frustum);
- us.updatePass(Pass.ENVIRONMENT);
- const passes = frameState.passes;
- const picking = passes.pick;
- const environmentState = scene._environmentState;
- const view = scene._view;
- const renderTranslucentDepthForPick =
- environmentState.renderTranslucentDepthForPick;
- const useWebVR = environmentState.useWebVR;
- // Do not render environment primitives during a pick pass since they do not generate picking commands.
- if (!picking) {
- const skyBoxCommand = environmentState.skyBoxCommand;
- if (defined(skyBoxCommand)) {
- executeCommand(skyBoxCommand, scene, context, passState);
- }
- if (environmentState.isSkyAtmosphereVisible) {
- executeCommand(
- environmentState.skyAtmosphereCommand,
- scene,
- context,
- passState
- );
- }
- if (environmentState.isSunVisible) {
- environmentState.sunDrawCommand.execute(context, passState);
- if (scene.sunBloom && !useWebVR) {
- let framebuffer;
- if (environmentState.useGlobeDepthFramebuffer) {
- framebuffer = view.globeDepth.framebuffer;
- } else if (environmentState.usePostProcess) {
- framebuffer = view.sceneFramebuffer.framebuffer;
- } else {
- framebuffer = environmentState.originalFramebuffer;
- }
- scene._sunPostProcess.execute(context);
- scene._sunPostProcess.copy(context, framebuffer);
- passState.framebuffer = framebuffer;
- }
- }
- // Moon can be seen through the atmosphere, since the sun is rendered after the atmosphere.
- if (environmentState.isMoonVisible) {
- environmentState.moonCommand.execute(context, passState);
- }
- }
- // Determine how translucent surfaces will be handled.
- let executeTranslucentCommands;
- if (environmentState.useOIT) {
- if (!defined(scene._executeOITFunction)) {
- scene._executeOITFunction = function (
- scene,
- executeFunction,
- passState,
- commands,
- invertClassification
- ) {
- view.globeDepth.prepareColorTextures(context);
- view.oit.executeCommands(
- scene,
- executeFunction,
- passState,
- commands,
- invertClassification
- );
- };
- }
- executeTranslucentCommands = scene._executeOITFunction;
- } else if (passes.render) {
- executeTranslucentCommands = executeTranslucentCommandsBackToFront;
- } else {
- executeTranslucentCommands = executeTranslucentCommandsFrontToBack;
- }
- const frustumCommandsList = view.frustumCommandsList;
- const numFrustums = frustumCommandsList.length;
- const clearGlobeDepth = environmentState.clearGlobeDepth;
- const useDepthPlane = environmentState.useDepthPlane;
- const globeTranslucencyState = scene._globeTranslucencyState;
- const globeTranslucent = globeTranslucencyState.translucent;
- const globeTranslucencyFramebuffer = scene._view.globeTranslucencyFramebuffer;
- const clearDepth = scene._depthClearCommand;
- const clearStencil = scene._stencilClearCommand;
- const clearClassificationStencil = scene._classificationStencilClearCommand;
- const depthPlane = scene._depthPlane;
- const usePostProcessSelected = environmentState.usePostProcessSelected;
- const height2D = camera.position.z;
- // Execute commands in each frustum in back to front order
- let j;
- for (let i = 0; i < numFrustums; ++i) {
- const index = numFrustums - i - 1;
- const frustumCommands = frustumCommandsList[index];
- if (scene.mode === SceneMode.SCENE2D) {
- // To avoid z-fighting in 2D, move the camera to just before the frustum
- // and scale the frustum depth to be in [1.0, nearToFarDistance2D].
- camera.position.z = height2D - frustumCommands.near + 1.0;
- frustum.far = Math.max(1.0, frustumCommands.far - frustumCommands.near);
- frustum.near = 1.0;
- us.update(frameState);
- us.updateFrustum(frustum);
- } else {
- // Avoid tearing artifacts between adjacent frustums in the opaque passes
- frustum.near =
- index !== 0
- ? frustumCommands.near * scene.opaqueFrustumNearOffset
- : frustumCommands.near;
- frustum.far = frustumCommands.far;
- us.updateFrustum(frustum);
- }
- clearDepth.execute(context, passState);
- if (context.stencilBuffer) {
- clearStencil.execute(context, passState);
- }
- us.updatePass(Pass.GLOBE);
- let commands = frustumCommands.commands[Pass.GLOBE];
- let length = frustumCommands.indices[Pass.GLOBE];
- if (globeTranslucent) {
- globeTranslucencyState.executeGlobeCommands(
- frustumCommands,
- executeCommand,
- globeTranslucencyFramebuffer,
- scene,
- passState
- );
- } else {
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- }
- const globeDepth = view.globeDepth;
- if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
- globeDepth.executeCopyDepth(context, passState);
- }
- // Draw terrain classification
- if (!environmentState.renderTranslucentDepthForPick) {
- us.updatePass(Pass.TERRAIN_CLASSIFICATION);
- commands = frustumCommands.commands[Pass.TERRAIN_CLASSIFICATION];
- length = frustumCommands.indices[Pass.TERRAIN_CLASSIFICATION];
- if (globeTranslucent) {
- globeTranslucencyState.executeGlobeClassificationCommands(
- frustumCommands,
- executeCommand,
- globeTranslucencyFramebuffer,
- scene,
- passState
- );
- } else {
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- }
- }
- if (clearGlobeDepth) {
- clearDepth.execute(context, passState);
- if (useDepthPlane) {
- depthPlane.execute(context, passState);
- }
- }
- if (
- !environmentState.useInvertClassification ||
- picking ||
- environmentState.renderTranslucentDepthForPick
- ) {
- // Common/fastest path. Draw 3D Tiles and classification normally.
- // Draw 3D Tiles
- us.updatePass(Pass.CESIUM_3D_TILE);
- commands = frustumCommands.commands[Pass.CESIUM_3D_TILE];
- length = frustumCommands.indices[Pass.CESIUM_3D_TILE];
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- if (length > 0) {
- if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
- // When clearGlobeDepth is true, executeUpdateDepth needs
- // a globe depth texture with resolved stencil bits.
- globeDepth.prepareColorTextures(context, clearGlobeDepth);
- globeDepth.executeUpdateDepth(
- context,
- passState,
- clearGlobeDepth,
- globeDepth.depthStencilTexture
- );
- }
- // Draw classifications. Modifies 3D Tiles color.
- if (!environmentState.renderTranslucentDepthForPick) {
- us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION);
- commands =
- frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION];
- length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION];
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- }
- }
- } else {
- // When the invert classification color is opaque:
- // Main FBO (FBO1): Main_Color + Main_DepthStencil
- // Invert classification FBO (FBO2) : Invert_Color + Main_DepthStencil
- //
- // 1. Clear FBO2 color to vec4(0.0) for each frustum
- // 2. Draw 3D Tiles to FBO2
- // 3. Draw classification to FBO2
- // 4. Fullscreen pass to FBO1, draw Invert_Color when:
- // * Main_DepthStencil has the stencil bit set > 0 (classified)
- // 5. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when:
- // * Main_DepthStencil has stencil bit set to 0 (unclassified) and
- // * Invert_Color !== vec4(0.0)
- //
- // When the invert classification color is translucent:
- // Main FBO (FBO1): Main_Color + Main_DepthStencil
- // Invert classification FBO (FBO2): Invert_Color + Invert_DepthStencil
- // IsClassified FBO (FBO3): IsClassified_Color + Invert_DepthStencil
- //
- // 1. Clear FBO2 and FBO3 color to vec4(0.0), stencil to 0, and depth to 1.0
- // 2. Draw 3D Tiles to FBO2
- // 3. Draw classification to FBO2
- // 4. Fullscreen pass to FBO3, draw any color when
- // * Invert_DepthStencil has the stencil bit set > 0 (classified)
- // 5. Fullscreen pass to FBO1, draw Invert_Color when:
- // * Invert_Color !== vec4(0.0) and
- // * IsClassified_Color !== vec4(0.0)
- // 6. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when:
- // * Invert_Color !== vec4(0.0) and
- // * IsClassified_Color === vec4(0.0)
- //
- // NOTE: Step six when translucent invert color occurs after the TRANSLUCENT pass
- //
- scene._invertClassification.clear(context, passState);
- const opaqueClassificationFramebuffer = passState.framebuffer;
- passState.framebuffer = scene._invertClassification._fbo.framebuffer;
- // Draw normally
- us.updatePass(Pass.CESIUM_3D_TILE);
- commands = frustumCommands.commands[Pass.CESIUM_3D_TILE];
- length = frustumCommands.indices[Pass.CESIUM_3D_TILE];
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer) {
- scene._invertClassification.prepareTextures(context);
- globeDepth.executeUpdateDepth(
- context,
- passState,
- clearGlobeDepth,
- scene._invertClassification._fbo.getDepthStencilTexture()
- );
- }
- // Set stencil
- us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW);
- commands =
- frustumCommands.commands[
- Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW
- ];
- length =
- frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW];
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- passState.framebuffer = opaqueClassificationFramebuffer;
- // Fullscreen pass to copy classified fragments
- scene._invertClassification.executeClassified(context, passState);
- if (frameState.invertClassificationColor.alpha === 1.0) {
- // Fullscreen pass to copy unclassified fragments when alpha == 1.0
- scene._invertClassification.executeUnclassified(context, passState);
- }
- // Clear stencil set by the classification for the next classification pass
- if (length > 0 && context.stencilBuffer) {
- clearClassificationStencil.execute(context, passState);
- }
- // Draw style over classification.
- us.updatePass(Pass.CESIUM_3D_TILE_CLASSIFICATION);
- commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_CLASSIFICATION];
- length = frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION];
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- }
- if (length > 0 && context.stencilBuffer) {
- clearStencil.execute(context, passState);
- }
- us.updatePass(Pass.VOXELS);
- commands = frustumCommands.commands[Pass.VOXELS];
- length = frustumCommands.indices[Pass.VOXELS];
- commands.length = length;
- executeVoxelCommands(scene, executeCommand, passState, commands);
- us.updatePass(Pass.OPAQUE);
- commands = frustumCommands.commands[Pass.OPAQUE];
- length = frustumCommands.indices[Pass.OPAQUE];
- for (j = 0; j < length; ++j) {
- executeCommand(commands[j], scene, context, passState);
- }
- if (index !== 0 && scene.mode !== SceneMode.SCENE2D) {
- // Do not overlap frustums in the translucent pass to avoid blending artifacts
- frustum.near = frustumCommands.near;
- us.updateFrustum(frustum);
- }
- let invertClassification;
- if (
- !picking &&
- environmentState.useInvertClassification &&
- frameState.invertClassificationColor.alpha < 1.0
- ) {
- // Fullscreen pass to copy unclassified fragments when alpha < 1.0.
- // Not executed when undefined.
- invertClassification = scene._invertClassification;
- }
- us.updatePass(Pass.TRANSLUCENT);
- commands = frustumCommands.commands[Pass.TRANSLUCENT];
- commands.length = frustumCommands.indices[Pass.TRANSLUCENT];
- executeTranslucentCommands(
- scene,
- executeCommand,
- passState,
- commands,
- invertClassification
- );
- // Classification for translucent 3D Tiles
- const has3DTilesClassificationCommands =
- frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION] > 0;
- if (
- has3DTilesClassificationCommands &&
- view.translucentTileClassification.isSupported()
- ) {
- view.translucentTileClassification.executeTranslucentCommands(
- scene,
- executeCommand,
- passState,
- commands,
- globeDepth.depthStencilTexture
- );
- view.translucentTileClassification.executeClassificationCommands(
- scene,
- executeCommand,
- passState,
- frustumCommands
- );
- }
- if (
- context.depthTexture &&
- scene.useDepthPicking &&
- (environmentState.useGlobeDepthFramebuffer ||
- renderTranslucentDepthForPick)
- ) {
- // PERFORMANCE_IDEA: Use MRT to avoid the extra copy.
- const depthStencilTexture = globeDepth.depthStencilTexture;
- const pickDepth = scene._picking.getPickDepth(scene, index);
- pickDepth.update(context, depthStencilTexture);
- pickDepth.executeCopyDepth(context, passState);
- }
- if (picking || !usePostProcessSelected) {
- continue;
- }
- const originalFramebuffer = passState.framebuffer;
- passState.framebuffer = view.sceneFramebuffer.getIdFramebuffer();
- // reset frustum
- frustum.near =
- index !== 0
- ? frustumCommands.near * scene.opaqueFrustumNearOffset
- : frustumCommands.near;
- frustum.far = frustumCommands.far;
- us.updateFrustum(frustum);
- us.updatePass(Pass.GLOBE);
- commands = frustumCommands.commands[Pass.GLOBE];
- length = frustumCommands.indices[Pass.GLOBE];
- if (globeTranslucent) {
- globeTranslucencyState.executeGlobeCommands(
- frustumCommands,
- executeIdCommand,
- globeTranslucencyFramebuffer,
- scene,
- passState
- );
- } else {
- for (j = 0; j < length; ++j) {
- executeIdCommand(commands[j], scene, context, passState);
- }
- }
- if (clearGlobeDepth) {
- clearDepth.framebuffer = passState.framebuffer;
- clearDepth.execute(context, passState);
- clearDepth.framebuffer = undefined;
- }
- if (clearGlobeDepth && useDepthPlane) {
- depthPlane.execute(context, passState);
- }
- us.updatePass(Pass.CESIUM_3D_TILE);
- commands = frustumCommands.commands[Pass.CESIUM_3D_TILE];
- length = frustumCommands.indices[Pass.CESIUM_3D_TILE];
- for (j = 0; j < length; ++j) {
- executeIdCommand(commands[j], scene, context, passState);
- }
- us.updatePass(Pass.OPAQUE);
- commands = frustumCommands.commands[Pass.OPAQUE];
- length = frustumCommands.indices[Pass.OPAQUE];
- for (j = 0; j < length; ++j) {
- executeIdCommand(commands[j], scene, context, passState);
- }
- us.updatePass(Pass.TRANSLUCENT);
- commands = frustumCommands.commands[Pass.TRANSLUCENT];
- length = frustumCommands.indices[Pass.TRANSLUCENT];
- for (j = 0; j < length; ++j) {
- executeIdCommand(commands[j], scene, context, passState);
- }
- passState.framebuffer = originalFramebuffer;
- }
- }
- function executeComputeCommands(scene) {
- const us = scene.context.uniformState;
- us.updatePass(Pass.COMPUTE);
- const sunComputeCommand = scene._environmentState.sunComputeCommand;
- if (defined(sunComputeCommand)) {
- sunComputeCommand.execute(scene._computeEngine);
- }
- const commandList = scene._computeCommandList;
- const length = commandList.length;
- for (let i = 0; i < length; ++i) {
- commandList[i].execute(scene._computeEngine);
- }
- }
- function executeOverlayCommands(scene, passState) {
- const us = scene.context.uniformState;
- us.updatePass(Pass.OVERLAY);
- const context = scene.context;
- const commandList = scene._overlayCommandList;
- const length = commandList.length;
- for (let i = 0; i < length; ++i) {
- commandList[i].execute(context, passState);
- }
- }
- function insertShadowCastCommands(scene, commandList, shadowMap) {
- const shadowVolume = shadowMap.shadowMapCullingVolume;
- const isPointLight = shadowMap.isPointLight;
- const passes = shadowMap.passes;
- const numberOfPasses = passes.length;
- const length = commandList.length;
- for (let i = 0; i < length; ++i) {
- const command = commandList[i];
- scene.updateDerivedCommands(command);
- if (
- command.castShadows &&
- (command.pass === Pass.GLOBE ||
- command.pass === Pass.CESIUM_3D_TILE ||
- command.pass === Pass.OPAQUE ||
- command.pass === Pass.TRANSLUCENT)
- ) {
- if (scene.isVisible(command, shadowVolume)) {
- if (isPointLight) {
- for (let k = 0; k < numberOfPasses; ++k) {
- passes[k].commandList.push(command);
- }
- } else if (numberOfPasses === 1) {
- passes[0].commandList.push(command);
- } else {
- let wasVisible = false;
- // Loop over cascades from largest to smallest
- for (let j = numberOfPasses - 1; j >= 0; --j) {
- const cascadeVolume = passes[j].cullingVolume;
- if (scene.isVisible(command, cascadeVolume)) {
- passes[j].commandList.push(command);
- wasVisible = true;
- } else if (wasVisible) {
- // If it was visible in the previous cascade but now isn't
- // then there is no need to check any more cascades
- break;
- }
- }
- }
- }
- }
- }
- }
- function executeShadowMapCastCommands(scene) {
- const frameState = scene.frameState;
- const shadowMaps = frameState.shadowState.shadowMaps;
- const shadowMapLength = shadowMaps.length;
- if (!frameState.shadowState.shadowsEnabled) {
- return;
- }
- const context = scene.context;
- const uniformState = context.uniformState;
- for (let i = 0; i < shadowMapLength; ++i) {
- const shadowMap = shadowMaps[i];
- if (shadowMap.outOfView) {
- continue;
- }
- // Reset the command lists
- const passes = shadowMap.passes;
- const numberOfPasses = passes.length;
- for (let j = 0; j < numberOfPasses; ++j) {
- passes[j].commandList.length = 0;
- }
- // Insert the primitive/model commands into the command lists
- const sceneCommands = scene.frameState.commandList;
- insertShadowCastCommands(scene, sceneCommands, shadowMap);
- for (let j = 0; j < numberOfPasses; ++j) {
- const pass = shadowMap.passes[j];
- uniformState.updateCamera(pass.camera);
- shadowMap.updatePass(context, j);
- const numberOfCommands = pass.commandList.length;
- for (let k = 0; k < numberOfCommands; ++k) {
- const command = pass.commandList[k];
- // Set the correct pass before rendering into the shadow map because some shaders
- // conditionally render based on whether the pass is translucent or opaque.
- uniformState.updatePass(command.pass);
- executeCommand(
- command.derivedCommands.shadows.castCommands[i],
- scene,
- context,
- pass.passState
- );
- }
- }
- }
- }
- const scratchEyeTranslation = new Cartesian3();
- /**
- * @private
- */
- Scene.prototype.updateAndExecuteCommands = function (
- passState,
- backgroundColor
- ) {
- const frameState = this._frameState;
- const mode = frameState.mode;
- const useWebVR = this._environmentState.useWebVR;
- if (useWebVR) {
- executeWebVRCommands(this, passState, backgroundColor);
- } else if (
- mode !== SceneMode.SCENE2D ||
- this._mapMode2D === MapMode2D.ROTATE
- ) {
- executeCommandsInViewport(true, this, passState, backgroundColor);
- } else {
- updateAndClearFramebuffers(this, passState, backgroundColor);
- execute2DViewportCommands(this, passState);
- }
- };
- function executeWebVRCommands(scene, passState, backgroundColor) {
- const view = scene._view;
- const camera = view.camera;
- const environmentState = scene._environmentState;
- const renderTranslucentDepthForPick =
- environmentState.renderTranslucentDepthForPick;
- updateAndClearFramebuffers(scene, passState, backgroundColor);
- updateAndRenderPrimitives(scene);
- view.createPotentiallyVisibleSet(scene);
- executeComputeCommands(scene);
- if (!renderTranslucentDepthForPick) {
- executeShadowMapCastCommands(scene);
- }
- // Based on Calculating Stereo pairs by Paul Bourke
- // http://paulbourke.net/stereographics/stereorender/
- const viewport = passState.viewport;
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = viewport.width * 0.5;
- const savedCamera = Camera.clone(camera, scene._cameraVR);
- savedCamera.frustum = camera.frustum;
- const near = camera.frustum.near;
- const fo = near * defaultValue(scene.focalLength, 5.0);
- const eyeSeparation = defaultValue(scene.eyeSeparation, fo / 30.0);
- const eyeTranslation = Cartesian3.multiplyByScalar(
- savedCamera.right,
- eyeSeparation * 0.5,
- scratchEyeTranslation
- );
- camera.frustum.aspectRatio = viewport.width / viewport.height;
- const offset = (0.5 * eyeSeparation * near) / fo;
- Cartesian3.add(savedCamera.position, eyeTranslation, camera.position);
- camera.frustum.xOffset = offset;
- executeCommands(scene, passState);
- viewport.x = viewport.width;
- Cartesian3.subtract(savedCamera.position, eyeTranslation, camera.position);
- camera.frustum.xOffset = -offset;
- executeCommands(scene, passState);
- Camera.clone(savedCamera, camera);
- }
- const scratch2DViewportCartographic = new Cartographic(
- Math.PI,
- CesiumMath.PI_OVER_TWO
- );
- const scratch2DViewportMaxCoord = new Cartesian3();
- const scratch2DViewportSavedPosition = new Cartesian3();
- const scratch2DViewportTransform = new Matrix4();
- const scratch2DViewportCameraTransform = new Matrix4();
- const scratch2DViewportEyePoint = new Cartesian3();
- const scratch2DViewportWindowCoords = new Cartesian3();
- const scratch2DViewport = new BoundingRectangle();
- function execute2DViewportCommands(scene, passState) {
- const context = scene.context;
- const frameState = scene.frameState;
- const camera = scene.camera;
- const originalViewport = passState.viewport;
- const viewport = BoundingRectangle.clone(originalViewport, scratch2DViewport);
- passState.viewport = viewport;
- const maxCartographic = scratch2DViewportCartographic;
- const maxCoord = scratch2DViewportMaxCoord;
- const projection = scene.mapProjection;
- projection.project(maxCartographic, maxCoord);
- const position = Cartesian3.clone(
- camera.position,
- scratch2DViewportSavedPosition
- );
- const transform = Matrix4.clone(
- camera.transform,
- scratch2DViewportCameraTransform
- );
- const frustum = camera.frustum.clone();
- camera._setTransform(Matrix4.IDENTITY);
- const viewportTransformation = Matrix4.computeViewportTransformation(
- viewport,
- 0.0,
- 1.0,
- scratch2DViewportTransform
- );
- const projectionMatrix = camera.frustum.projectionMatrix;
- const x = camera.positionWC.y;
- const eyePoint = Cartesian3.fromElements(
- CesiumMath.sign(x) * maxCoord.x - x,
- 0.0,
- -camera.positionWC.x,
- scratch2DViewportEyePoint
- );
- const windowCoordinates = Transforms.pointToGLWindowCoordinates(
- projectionMatrix,
- viewportTransformation,
- eyePoint,
- scratch2DViewportWindowCoords
- );
- windowCoordinates.x = Math.floor(windowCoordinates.x);
- const viewportX = viewport.x;
- const viewportWidth = viewport.width;
- if (
- x === 0.0 ||
- windowCoordinates.x <= viewportX ||
- windowCoordinates.x >= viewportX + viewportWidth
- ) {
- executeCommandsInViewport(true, scene, passState);
- } else if (
- Math.abs(viewportX + viewportWidth * 0.5 - windowCoordinates.x) < 1.0
- ) {
- viewport.width = windowCoordinates.x - viewport.x;
- camera.position.x *= CesiumMath.sign(camera.position.x);
- camera.frustum.right = 0.0;
- frameState.cullingVolume = camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC
- );
- context.uniformState.update(frameState);
- executeCommandsInViewport(true, scene, passState);
- viewport.x = windowCoordinates.x;
- camera.position.x = -camera.position.x;
- camera.frustum.right = -camera.frustum.left;
- camera.frustum.left = 0.0;
- frameState.cullingVolume = camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC
- );
- context.uniformState.update(frameState);
- executeCommandsInViewport(false, scene, passState);
- } else if (windowCoordinates.x > viewportX + viewportWidth * 0.5) {
- viewport.width = windowCoordinates.x - viewportX;
- const right = camera.frustum.right;
- camera.frustum.right = maxCoord.x - x;
- frameState.cullingVolume = camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC
- );
- context.uniformState.update(frameState);
- executeCommandsInViewport(true, scene, passState);
- viewport.x = windowCoordinates.x;
- viewport.width = viewportX + viewportWidth - windowCoordinates.x;
- camera.position.x = -camera.position.x;
- camera.frustum.left = -camera.frustum.right;
- camera.frustum.right = right - camera.frustum.right * 2.0;
- frameState.cullingVolume = camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC
- );
- context.uniformState.update(frameState);
- executeCommandsInViewport(false, scene, passState);
- } else {
- viewport.x = windowCoordinates.x;
- viewport.width = viewportX + viewportWidth - windowCoordinates.x;
- const left = camera.frustum.left;
- camera.frustum.left = -maxCoord.x - x;
- frameState.cullingVolume = camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC
- );
- context.uniformState.update(frameState);
- executeCommandsInViewport(true, scene, passState);
- viewport.x = viewportX;
- viewport.width = windowCoordinates.x - viewportX;
- camera.position.x = -camera.position.x;
- camera.frustum.right = -camera.frustum.left;
- camera.frustum.left = left - camera.frustum.left * 2.0;
- frameState.cullingVolume = camera.frustum.computeCullingVolume(
- camera.positionWC,
- camera.directionWC,
- camera.upWC
- );
- context.uniformState.update(frameState);
- executeCommandsInViewport(false, scene, passState);
- }
- camera._setTransform(transform);
- Cartesian3.clone(position, camera.position);
- camera.frustum = frustum.clone();
- passState.viewport = originalViewport;
- }
- function executeCommandsInViewport(
- firstViewport,
- scene,
- passState,
- backgroundColor
- ) {
- const environmentState = scene._environmentState;
- const view = scene._view;
- const renderTranslucentDepthForPick =
- environmentState.renderTranslucentDepthForPick;
- if (!firstViewport) {
- scene.frameState.commandList.length = 0;
- }
- updateAndRenderPrimitives(scene);
- view.createPotentiallyVisibleSet(scene);
- if (firstViewport) {
- if (defined(backgroundColor)) {
- updateAndClearFramebuffers(scene, passState, backgroundColor);
- }
- executeComputeCommands(scene);
- if (!renderTranslucentDepthForPick) {
- executeShadowMapCastCommands(scene);
- }
- }
- executeCommands(scene, passState);
- }
- const scratchCullingVolume = new CullingVolume();
- /**
- * @private
- */
- Scene.prototype.updateEnvironment = function () {
- const frameState = this._frameState;
- const view = this._view;
- // Update celestial and terrestrial environment effects.
- const environmentState = this._environmentState;
- const renderPass = frameState.passes.render;
- const offscreenPass = frameState.passes.offscreen;
- const skyAtmosphere = this.skyAtmosphere;
- const globe = this.globe;
- const globeTranslucencyState = this._globeTranslucencyState;
- if (
- !renderPass ||
- (this._mode !== SceneMode.SCENE2D &&
- view.camera.frustum instanceof OrthographicFrustum) ||
- !globeTranslucencyState.environmentVisible
- ) {
- environmentState.skyAtmosphereCommand = undefined;
- environmentState.skyBoxCommand = undefined;
- environmentState.sunDrawCommand = undefined;
- environmentState.sunComputeCommand = undefined;
- environmentState.moonCommand = undefined;
- } else {
- if (defined(skyAtmosphere)) {
- if (defined(globe)) {
- skyAtmosphere.setDynamicAtmosphereColor(
- globe.enableLighting && globe.dynamicAtmosphereLighting,
- globe.dynamicAtmosphereLightingFromSun
- );
- environmentState.isReadyForAtmosphere =
- environmentState.isReadyForAtmosphere ||
- globe._surface._tilesToRender.length > 0;
- }
- environmentState.skyAtmosphereCommand = skyAtmosphere.update(
- frameState,
- globe
- );
- if (defined(environmentState.skyAtmosphereCommand)) {
- this.updateDerivedCommands(environmentState.skyAtmosphereCommand);
- }
- } else {
- environmentState.skyAtmosphereCommand = undefined;
- }
- environmentState.skyBoxCommand = defined(this.skyBox)
- ? this.skyBox.update(frameState, this._hdr)
- : undefined;
- const sunCommands = defined(this.sun)
- ? this.sun.update(frameState, view.passState, this._hdr)
- : undefined;
- environmentState.sunDrawCommand = defined(sunCommands)
- ? sunCommands.drawCommand
- : undefined;
- environmentState.sunComputeCommand = defined(sunCommands)
- ? sunCommands.computeCommand
- : undefined;
- environmentState.moonCommand = defined(this.moon)
- ? this.moon.update(frameState)
- : undefined;
- }
- const clearGlobeDepth = (environmentState.clearGlobeDepth =
- defined(globe) &&
- globe.show &&
- (!globe.depthTestAgainstTerrain || this.mode === SceneMode.SCENE2D));
- const useDepthPlane = (environmentState.useDepthPlane =
- clearGlobeDepth &&
- this.mode === SceneMode.SCENE3D &&
- globeTranslucencyState.useDepthPlane);
- if (useDepthPlane) {
- // Update the depth plane that is rendered in 3D when the primitives are
- // not depth tested against terrain so primitives on the backface
- // of the globe are not picked.
- this._depthPlane.update(frameState);
- }
- environmentState.renderTranslucentDepthForPick = false;
- environmentState.useWebVR =
- this._useWebVR && this.mode !== SceneMode.SCENE2D && !offscreenPass;
- const occluder =
- frameState.mode === SceneMode.SCENE3D &&
- !globeTranslucencyState.sunVisibleThroughGlobe
- ? frameState.occluder
- : undefined;
- let cullingVolume = frameState.cullingVolume;
- // get user culling volume minus the far plane.
- const planes = scratchCullingVolume.planes;
- for (let k = 0; k < 5; ++k) {
- planes[k] = cullingVolume.planes[k];
- }
- cullingVolume = scratchCullingVolume;
- // Determine visibility of celestial and terrestrial environment effects.
- environmentState.isSkyAtmosphereVisible =
- defined(environmentState.skyAtmosphereCommand) &&
- environmentState.isReadyForAtmosphere;
- environmentState.isSunVisible = this.isVisible(
- environmentState.sunDrawCommand,
- cullingVolume,
- occluder
- );
- environmentState.isMoonVisible = this.isVisible(
- environmentState.moonCommand,
- cullingVolume,
- occluder
- );
- const envMaps = this.specularEnvironmentMaps;
- let envMapAtlas = this._specularEnvironmentMapAtlas;
- if (
- defined(envMaps) &&
- (!defined(envMapAtlas) || envMapAtlas.url !== envMaps)
- ) {
- envMapAtlas = envMapAtlas && envMapAtlas.destroy();
- this._specularEnvironmentMapAtlas = new OctahedralProjectedCubeMap(envMaps);
- } else if (!defined(envMaps) && defined(envMapAtlas)) {
- envMapAtlas.destroy();
- this._specularEnvironmentMapAtlas = undefined;
- }
- if (defined(this._specularEnvironmentMapAtlas)) {
- this._specularEnvironmentMapAtlas.update(frameState);
- }
- };
- function updateDebugFrustumPlanes(scene) {
- const frameState = scene._frameState;
- if (scene.debugShowFrustumPlanes !== scene._debugShowFrustumPlanes) {
- if (scene.debugShowFrustumPlanes) {
- scene._debugFrustumPlanes = new DebugCameraPrimitive({
- camera: scene.camera,
- updateOnChange: false,
- frustumSplits: frameState.frustumSplits,
- });
- } else {
- scene._debugFrustumPlanes =
- scene._debugFrustumPlanes && scene._debugFrustumPlanes.destroy();
- }
- scene._debugShowFrustumPlanes = scene.debugShowFrustumPlanes;
- }
- if (defined(scene._debugFrustumPlanes)) {
- scene._debugFrustumPlanes.update(frameState);
- }
- }
- function updateShadowMaps(scene) {
- const frameState = scene._frameState;
- const shadowMaps = frameState.shadowMaps;
- const length = shadowMaps.length;
- const shadowsEnabled =
- length > 0 && !frameState.passes.pick && scene.mode === SceneMode.SCENE3D;
- if (shadowsEnabled !== frameState.shadowState.shadowsEnabled) {
- // Update derived commands when shadowsEnabled changes
- ++frameState.shadowState.lastDirtyTime;
- frameState.shadowState.shadowsEnabled = shadowsEnabled;
- }
- frameState.shadowState.lightShadowsEnabled = false;
- if (!shadowsEnabled) {
- return;
- }
- // Check if the shadow maps are different than the shadow maps last frame.
- // If so, the derived commands need to be updated.
- for (let j = 0; j < length; ++j) {
- if (shadowMaps[j] !== frameState.shadowState.shadowMaps[j]) {
- ++frameState.shadowState.lastDirtyTime;
- break;
- }
- }
- frameState.shadowState.shadowMaps.length = 0;
- frameState.shadowState.lightShadowMaps.length = 0;
- for (let i = 0; i < length; ++i) {
- const shadowMap = shadowMaps[i];
- shadowMap.update(frameState);
- frameState.shadowState.shadowMaps.push(shadowMap);
- if (shadowMap.fromLightSource) {
- frameState.shadowState.lightShadowMaps.push(shadowMap);
- frameState.shadowState.lightShadowsEnabled = true;
- }
- if (shadowMap.dirty) {
- ++frameState.shadowState.lastDirtyTime;
- shadowMap.dirty = false;
- }
- }
- }
- function updateAndRenderPrimitives(scene) {
- const frameState = scene._frameState;
- scene._groundPrimitives.update(frameState);
- scene._primitives.update(frameState);
- updateDebugFrustumPlanes(scene);
- updateShadowMaps(scene);
- if (scene._globe) {
- scene._globe.render(frameState);
- }
- }
- function updateAndClearFramebuffers(scene, passState, clearColor) {
- const context = scene._context;
- const frameState = scene._frameState;
- const environmentState = scene._environmentState;
- const view = scene._view;
- const passes = scene._frameState.passes;
- const picking = passes.pick;
- if (defined(view.globeDepth)) {
- view.globeDepth.picking = picking;
- }
- const useWebVR = environmentState.useWebVR;
- // Preserve the reference to the original framebuffer.
- environmentState.originalFramebuffer = passState.framebuffer;
- // Manage sun bloom post-processing effect.
- if (defined(scene.sun) && scene.sunBloom !== scene._sunBloom) {
- if (scene.sunBloom && !useWebVR) {
- scene._sunPostProcess = new SunPostProcess();
- } else if (defined(scene._sunPostProcess)) {
- scene._sunPostProcess = scene._sunPostProcess.destroy();
- }
- scene._sunBloom = scene.sunBloom;
- } else if (!defined(scene.sun) && defined(scene._sunPostProcess)) {
- scene._sunPostProcess = scene._sunPostProcess.destroy();
- scene._sunBloom = false;
- }
- // Clear the pass state framebuffer.
- const clear = scene._clearColorCommand;
- Color.clone(clearColor, clear.color);
- clear.execute(context, passState);
- // Update globe depth rendering based on the current context and clear the globe depth framebuffer.
- // Globe depth is copied for the pick pass to support picking batched geometries in GroundPrimitives.
- const useGlobeDepthFramebuffer = (environmentState.useGlobeDepthFramebuffer = defined(
- view.globeDepth
- ));
- if (useGlobeDepthFramebuffer) {
- view.globeDepth.update(
- context,
- passState,
- view.viewport,
- scene.msaaSamples,
- scene._hdr,
- environmentState.clearGlobeDepth
- );
- view.globeDepth.clear(context, passState, clearColor);
- }
- // If supported, configure OIT to use the globe depth framebuffer and clear the OIT framebuffer.
- const oit = view.oit;
- const useOIT = (environmentState.useOIT =
- !picking && defined(oit) && oit.isSupported());
- if (useOIT) {
- oit.update(
- context,
- passState,
- view.globeDepth.colorFramebufferManager,
- scene._hdr,
- scene.msaaSamples
- );
- oit.clear(context, passState, clearColor);
- environmentState.useOIT = oit.isSupported();
- }
- const postProcess = scene.postProcessStages;
- let usePostProcess = (environmentState.usePostProcess =
- !picking &&
- (scene._hdr ||
- postProcess.length > 0 ||
- postProcess.ambientOcclusion.enabled ||
- postProcess.fxaa.enabled ||
- postProcess.bloom.enabled));
- environmentState.usePostProcessSelected = false;
- if (usePostProcess) {
- view.sceneFramebuffer.update(
- context,
- view.viewport,
- scene._hdr,
- scene.msaaSamples
- );
- view.sceneFramebuffer.clear(context, passState, clearColor);
- postProcess.update(context, frameState.useLogDepth, scene._hdr);
- postProcess.clear(context);
- usePostProcess = environmentState.usePostProcess = postProcess.ready;
- environmentState.usePostProcessSelected =
- usePostProcess && postProcess.hasSelected;
- }
- if (environmentState.isSunVisible && scene.sunBloom && !useWebVR) {
- passState.framebuffer = scene._sunPostProcess.update(passState);
- scene._sunPostProcess.clear(context, passState, clearColor);
- } else if (useGlobeDepthFramebuffer) {
- passState.framebuffer = view.globeDepth.framebuffer;
- } else if (usePostProcess) {
- passState.framebuffer = view.sceneFramebuffer.framebuffer;
- }
- if (defined(passState.framebuffer)) {
- clear.execute(context, passState);
- }
- const useInvertClassification = (environmentState.useInvertClassification =
- !picking && defined(passState.framebuffer) && scene.invertClassification);
- if (useInvertClassification) {
- let depthFramebuffer;
- if (scene.frameState.invertClassificationColor.alpha === 1.0) {
- if (environmentState.useGlobeDepthFramebuffer) {
- depthFramebuffer = view.globeDepth.framebuffer;
- }
- }
- if (defined(depthFramebuffer) || context.depthTexture) {
- scene._invertClassification.previousFramebuffer = depthFramebuffer;
- scene._invertClassification.update(
- context,
- scene.msaaSamples,
- view.globeDepth.colorFramebufferManager
- );
- scene._invertClassification.clear(context, passState);
- if (scene.frameState.invertClassificationColor.alpha < 1.0 && useOIT) {
- const command = scene._invertClassification.unclassifiedCommand;
- const derivedCommands = command.derivedCommands;
- derivedCommands.oit = oit.createDerivedCommands(
- command,
- context,
- derivedCommands.oit
- );
- }
- } else {
- environmentState.useInvertClassification = false;
- }
- }
- if (scene._globeTranslucencyState.translucent) {
- view.globeTranslucencyFramebuffer.updateAndClear(
- scene._hdr,
- view.viewport,
- context,
- passState
- );
- }
- }
- /**
- * @private
- */
- Scene.prototype.resolveFramebuffers = function (passState) {
- const context = this._context;
- const environmentState = this._environmentState;
- const view = this._view;
- const globeDepth = view.globeDepth;
- if (defined(globeDepth)) {
- globeDepth.prepareColorTextures(context);
- }
- const useOIT = environmentState.useOIT;
- const useGlobeDepthFramebuffer = environmentState.useGlobeDepthFramebuffer;
- const usePostProcess = environmentState.usePostProcess;
- const defaultFramebuffer = environmentState.originalFramebuffer;
- const globeFramebuffer = useGlobeDepthFramebuffer
- ? globeDepth.colorFramebufferManager
- : undefined;
- const sceneFramebuffer = view.sceneFramebuffer._colorFramebuffer;
- const idFramebuffer = view.sceneFramebuffer.idFramebuffer;
- if (useOIT) {
- passState.framebuffer = usePostProcess
- ? sceneFramebuffer.framebuffer
- : defaultFramebuffer;
- view.oit.execute(context, passState);
- }
- const translucentTileClassification = view.translucentTileClassification;
- if (
- translucentTileClassification.hasTranslucentDepth &&
- translucentTileClassification.isSupported()
- ) {
- translucentTileClassification.execute(this, passState);
- }
- if (usePostProcess) {
- view.sceneFramebuffer.prepareColorTextures(context);
- let inputFramebuffer = sceneFramebuffer;
- if (useGlobeDepthFramebuffer && !useOIT) {
- inputFramebuffer = globeFramebuffer;
- }
- const postProcess = this.postProcessStages;
- const colorTexture = inputFramebuffer.getColorTexture(0);
- const idTexture = idFramebuffer.getColorTexture(0);
- const depthTexture = defaultValue(
- globeFramebuffer,
- sceneFramebuffer
- ).getDepthStencilTexture();
- postProcess.execute(context, colorTexture, depthTexture, idTexture);
- postProcess.copy(context, defaultFramebuffer);
- }
- if (!useOIT && !usePostProcess && useGlobeDepthFramebuffer) {
- passState.framebuffer = defaultFramebuffer;
- globeDepth.executeCopyColor(context, passState);
- }
- };
- function callAfterRenderFunctions(scene) {
- // Functions are queued up during primitive update and executed here in case
- // the function modifies scene state that should remain constant over the frame.
- const functions = scene._frameState.afterRender;
- for (let i = 0, length = functions.length; i < length; ++i) {
- const shouldRequestRender = functions[i]();
- if (shouldRequestRender) {
- scene.requestRender();
- }
- }
- functions.length = 0;
- }
- function getGlobeHeight(scene) {
- const globe = scene._globe;
- const camera = scene.camera;
- const cartographic = camera.positionCartographic;
- if (defined(globe) && globe.show && defined(cartographic)) {
- return globe.getHeight(cartographic);
- }
- return undefined;
- }
- function isCameraUnderground(scene) {
- const camera = scene.camera;
- const mode = scene._mode;
- const globe = scene.globe;
- const cameraController = scene._screenSpaceCameraController;
- const cartographic = camera.positionCartographic;
- if (!defined(cartographic)) {
- return false;
- }
- if (!cameraController.onMap() && cartographic.height < 0.0) {
- // The camera can go off the map while in Columbus View.
- // Make a best guess as to whether it's underground by checking if its height is less than zero.
- return true;
- }
- if (
- !defined(globe) ||
- !globe.show ||
- mode === SceneMode.SCENE2D ||
- mode === SceneMode.MORPHING
- ) {
- return false;
- }
- const globeHeight = scene._globeHeight;
- return defined(globeHeight) && cartographic.height < globeHeight;
- }
- /**
- * @private
- */
- Scene.prototype.initializeFrame = function () {
- // Destroy released shaders and textures once every 120 frames to avoid thrashing the cache
- if (this._shaderFrameCount++ === 120) {
- this._shaderFrameCount = 0;
- this._context.shaderCache.destroyReleasedShaderPrograms();
- this._context.textureCache.destroyReleasedTextures();
- }
- this._tweens.update();
- this._globeHeight = getGlobeHeight(this);
- this._cameraUnderground = isCameraUnderground(this);
- this._globeTranslucencyState.update(this);
- this._screenSpaceCameraController.update();
- if (defined(this._deviceOrientationCameraController)) {
- this._deviceOrientationCameraController.update();
- }
- this.camera.update(this._mode);
- this.camera._updateCameraChanged();
- };
- function updateDebugShowFramesPerSecond(scene, renderedThisFrame) {
- if (scene.debugShowFramesPerSecond) {
- if (!defined(scene._performanceDisplay)) {
- const performanceContainer = document.createElement("div");
- performanceContainer.className =
- "cesium-performanceDisplay-defaultContainer";
- const container = scene._canvas.parentNode;
- container.appendChild(performanceContainer);
- const performanceDisplay = new PerformanceDisplay({
- container: performanceContainer,
- });
- scene._performanceDisplay = performanceDisplay;
- scene._performanceContainer = performanceContainer;
- }
- scene._performanceDisplay.throttled = scene.requestRenderMode;
- scene._performanceDisplay.update(renderedThisFrame);
- } else if (defined(scene._performanceDisplay)) {
- scene._performanceDisplay =
- scene._performanceDisplay && scene._performanceDisplay.destroy();
- scene._performanceContainer.parentNode.removeChild(
- scene._performanceContainer
- );
- }
- }
- function prePassesUpdate(scene) {
- scene._jobScheduler.resetBudgets();
- const frameState = scene._frameState;
- const primitives = scene.primitives;
- primitives.prePassesUpdate(frameState);
- if (defined(scene.globe)) {
- scene.globe.update(frameState);
- }
- scene._picking.update();
- frameState.creditDisplay.update();
- }
- function postPassesUpdate(scene) {
- const frameState = scene._frameState;
- const primitives = scene.primitives;
- primitives.postPassesUpdate(frameState);
- RequestScheduler.update();
- }
- const scratchBackgroundColor = new Color();
- function render(scene) {
- const frameState = scene._frameState;
- const context = scene.context;
- const us = context.uniformState;
- const view = scene._defaultView;
- scene._view = view;
- scene.updateFrameState();
- frameState.passes.render = true;
- frameState.passes.postProcess = scene.postProcessStages.hasSelected;
- frameState.tilesetPassState = renderTilesetPassState;
- let backgroundColor = defaultValue(scene.backgroundColor, Color.BLACK);
- if (scene._hdr) {
- backgroundColor = Color.clone(backgroundColor, scratchBackgroundColor);
- backgroundColor.red = Math.pow(backgroundColor.red, scene.gamma);
- backgroundColor.green = Math.pow(backgroundColor.green, scene.gamma);
- backgroundColor.blue = Math.pow(backgroundColor.blue, scene.gamma);
- }
- frameState.backgroundColor = backgroundColor;
- scene.fog.update(frameState);
- us.update(frameState);
- const shadowMap = scene.shadowMap;
- if (defined(shadowMap) && shadowMap.enabled) {
- if (!defined(scene.light) || scene.light instanceof SunLight) {
- // Negate the sun direction so that it is from the Sun, not to the Sun
- Cartesian3.negate(us.sunDirectionWC, scene._shadowMapCamera.direction);
- } else {
- Cartesian3.clone(scene.light.direction, scene._shadowMapCamera.direction);
- }
- frameState.shadowMaps.push(shadowMap);
- }
- scene._computeCommandList.length = 0;
- scene._overlayCommandList.length = 0;
- const viewport = view.viewport;
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = context.drawingBufferWidth;
- viewport.height = context.drawingBufferHeight;
- const passState = view.passState;
- passState.framebuffer = undefined;
- passState.blendingEnabled = undefined;
- passState.scissorTest = undefined;
- passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
- if (defined(scene.globe)) {
- scene.globe.beginFrame(frameState);
- }
- scene.updateEnvironment();
- scene.updateAndExecuteCommands(passState, backgroundColor);
- scene.resolveFramebuffers(passState);
- passState.framebuffer = undefined;
- executeOverlayCommands(scene, passState);
- if (defined(scene.globe)) {
- scene.globe.endFrame(frameState);
- if (!scene.globe.tilesLoaded) {
- scene._renderRequested = true;
- }
- }
- context.endFrame();
- }
- function tryAndCatchError(scene, functionToExecute) {
- try {
- functionToExecute(scene);
- } catch (error) {
- scene._renderError.raiseEvent(scene, error);
- if (scene.rethrowRenderErrors) {
- throw error;
- }
- }
- }
- function updateMostDetailedRayPicks(scene) {
- return scene._picking.updateMostDetailedRayPicks(scene);
- }
- /**
- * Update and render the scene. It is usually not necessary to call this function
- * directly because {@link CesiumWidget} will do it automatically.
- * @param {JulianDate} [time] The simulation time at which to render.
- */
- Scene.prototype.render = function (time) {
- /**
- *
- * Pre passes update. Execute any pass invariant code that should run before the passes here.
- *
- */
- this._preUpdate.raiseEvent(this, time);
- const frameState = this._frameState;
- frameState.newFrame = false;
- if (!defined(time)) {
- time = JulianDate.now();
- }
- // Determine if shouldRender
- const cameraChanged = this._view.checkForCameraUpdates(this);
- let shouldRender =
- !this.requestRenderMode ||
- this._renderRequested ||
- cameraChanged ||
- this._logDepthBufferDirty ||
- this._hdrDirty ||
- this.mode === SceneMode.MORPHING;
- if (
- !shouldRender &&
- defined(this.maximumRenderTimeChange) &&
- defined(this._lastRenderTime)
- ) {
- const difference = Math.abs(
- JulianDate.secondsDifference(this._lastRenderTime, time)
- );
- shouldRender = shouldRender || difference > this.maximumRenderTimeChange;
- }
- if (shouldRender) {
- this._lastRenderTime = JulianDate.clone(time, this._lastRenderTime);
- this._renderRequested = false;
- this._logDepthBufferDirty = false;
- this._hdrDirty = false;
- const frameNumber = CesiumMath.incrementWrap(
- frameState.frameNumber,
- 15000000.0,
- 1.0
- );
- updateFrameNumber(this, frameNumber, time);
- frameState.newFrame = true;
- }
- tryAndCatchError(this, prePassesUpdate);
- /**
- *
- * Passes update. Add any passes here
- *
- */
- if (this.primitives.show) {
- tryAndCatchError(this, updateMostDetailedRayPicks);
- tryAndCatchError(this, updatePreloadPass);
- tryAndCatchError(this, updatePreloadFlightPass);
- if (!shouldRender) {
- tryAndCatchError(this, updateRequestRenderModeDeferCheckPass);
- }
- }
- this._postUpdate.raiseEvent(this, time);
- if (shouldRender) {
- this._preRender.raiseEvent(this, time);
- frameState.creditDisplay.beginFrame();
- tryAndCatchError(this, render);
- }
- /**
- *
- * Post passes update. Execute any pass invariant code that should run after the passes here.
- *
- */
- updateDebugShowFramesPerSecond(this, shouldRender);
- tryAndCatchError(this, postPassesUpdate);
- // 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.
- // We don't want those events to resolve during the render loop because the events might add new primitives
- callAfterRenderFunctions(this);
- if (shouldRender) {
- this._postRender.raiseEvent(this, time);
- frameState.creditDisplay.endFrame();
- }
- };
- /**
- * Update and render the scene. Always forces a new render frame regardless of whether a render was
- * previously requested.
- * @param {JulianDate} [time] The simulation time at which to render.
- *
- * @private
- */
- Scene.prototype.forceRender = function (time) {
- this._renderRequested = true;
- this.render(time);
- };
- /**
- * Requests a new rendered frame when {@link Scene#requestRenderMode} is set to <code>true</code>.
- * The render rate will not exceed the {@link CesiumWidget#targetFrameRate}.
- *
- * @see Scene#requestRenderMode
- */
- Scene.prototype.requestRender = function () {
- this._renderRequested = true;
- };
- /**
- * @private
- */
- Scene.prototype.clampLineWidth = function (width) {
- return Math.max(
- ContextLimits.minimumAliasedLineWidth,
- Math.min(width, ContextLimits.maximumAliasedLineWidth)
- );
- };
- /**
- * Returns an object with a `primitive` property that contains the first (top) primitive in the scene
- * at a particular window coordinate or undefined if nothing is at the location. Other properties may
- * potentially be set depending on the type of primitive and may be used to further identify the picked object.
- * <p>
- * When a feature of a 3D Tiles tileset is picked, <code>pick</code> returns a {@link Cesium3DTileFeature} object.
- * </p>
- *
- * @example
- * // On mouse over, color the feature yellow.
- * handler.setInputAction(function(movement) {
- * const feature = scene.pick(movement.endPosition);
- * if (feature instanceof Cesium.Cesium3DTileFeature) {
- * feature.color = Cesium.Color.YELLOW;
- * }
- * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
- *
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {number} [width=3] Width of the pick rectangle.
- * @param {number} [height=3] Height of the pick rectangle.
- * @returns {object} Object containing the picked primitive.
- */
- Scene.prototype.pick = function (windowPosition, width, height) {
- return this._picking.pick(this, windowPosition, width, height);
- };
- /**
- * Returns the cartesian position reconstructed from the depth buffer and window position.
- * The returned position is in world coordinates. Used internally by camera functions to
- * prevent conversion to projected 2D coordinates and then back.
- * <p>
- * Set {@link Scene#pickTranslucentDepth} to <code>true</code> to include the depth of
- * translucent primitives; otherwise, this essentially picks through translucent primitives.
- * </p>
- *
- * @private
- *
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {Cartesian3} [result] The object on which to restore the result.
- * @returns {Cartesian3} The cartesian position in world coordinates.
- *
- * @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
- */
- Scene.prototype.pickPositionWorldCoordinates = function (
- windowPosition,
- result
- ) {
- return this._picking.pickPositionWorldCoordinates(
- this,
- windowPosition,
- result
- );
- };
- /**
- * Returns the cartesian position reconstructed from the depth buffer and window position.
- * <p>
- * The position reconstructed from the depth buffer in 2D may be slightly different from those
- * reconstructed in 3D and Columbus view. This is caused by the difference in the distribution
- * of depth values of perspective and orthographic projection.
- * </p>
- * <p>
- * Set {@link Scene#pickTranslucentDepth} to <code>true</code> to include the depth of
- * translucent primitives; otherwise, this essentially picks through translucent primitives.
- * </p>
- *
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {Cartesian3} [result] The object on which to restore the result.
- * @returns {Cartesian3} The cartesian position.
- *
- * @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
- */
- Scene.prototype.pickPosition = function (windowPosition, result) {
- return this._picking.pickPosition(this, windowPosition, result);
- };
- /**
- * Returns a list of objects, each containing a `primitive` property, for all primitives at
- * a particular window coordinate position. Other properties may also be set depending on the
- * type of primitive and may be used to further identify the picked object. The primitives in
- * the list are ordered by their visual order in the scene (front to back).
- *
- * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
- * @param {number} [limit] If supplied, stop drilling after collecting this many picks.
- * @param {number} [width=3] Width of the pick rectangle.
- * @param {number} [height=3] Height of the pick rectangle.
- * @returns {any[]} Array of objects, each containing 1 picked primitives.
- *
- * @exception {DeveloperError} windowPosition is undefined.
- *
- * @example
- * const pickedObjects = scene.drillPick(new Cesium.Cartesian2(100.0, 200.0));
- *
- * @see Scene#pick
- */
- Scene.prototype.drillPick = function (windowPosition, limit, width, height) {
- return this._picking.drillPick(this, windowPosition, limit, width, height);
- };
- function updatePreloadPass(scene) {
- const frameState = scene._frameState;
- preloadTilesetPassState.camera = frameState.camera;
- preloadTilesetPassState.cullingVolume = frameState.cullingVolume;
- const primitives = scene.primitives;
- primitives.updateForPass(frameState, preloadTilesetPassState);
- }
- function updatePreloadFlightPass(scene) {
- const frameState = scene._frameState;
- const camera = frameState.camera;
- if (!camera.canPreloadFlight()) {
- return;
- }
- preloadFlightTilesetPassState.camera = scene.preloadFlightCamera;
- preloadFlightTilesetPassState.cullingVolume =
- scene.preloadFlightCullingVolume;
- const primitives = scene.primitives;
- primitives.updateForPass(frameState, preloadFlightTilesetPassState);
- }
- function updateRequestRenderModeDeferCheckPass(scene) {
- // Check if any ignored requests are ready to go (to wake rendering up again)
- scene.primitives.updateForPass(
- scene._frameState,
- requestRenderModeDeferCheckPassState
- );
- }
- /**
- * Returns an object containing the first object intersected by the ray and the position of intersection,
- * or <code>undefined</code> if there were no intersections. The intersected object has a <code>primitive</code>
- * property that contains the intersected primitive. Other properties may be set depending on the type of primitive
- * and may be used to further identify the picked object. The ray must be given in world coordinates.
- * <p>
- * This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
- * primitives regardless of their visibility.
- * </p>
- *
- * @private
- *
- * @param {Ray} ray The ray.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @returns {object} An object containing the object and position of the first intersection.
- *
- * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
- */
- Scene.prototype.pickFromRay = function (ray, objectsToExclude, width) {
- return this._picking.pickFromRay(this, ray, objectsToExclude, width);
- };
- /**
- * Returns a list of objects, each containing the object intersected by the ray and the position of intersection.
- * The intersected object has a <code>primitive</code> property that contains the intersected primitive. Other
- * properties may also be set depending on the type of primitive and may be used to further identify the picked object.
- * The primitives in the list are ordered by first intersection to last intersection. The ray must be given in
- * world coordinates.
- * <p>
- * This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
- * primitives regardless of their visibility.
- * </p>
- *
- * @private
- *
- * @param {Ray} ray The ray.
- * @param {number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @returns {Object[]} List of objects containing the object and position of each intersection.
- *
- * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
- */
- Scene.prototype.drillPickFromRay = function (
- ray,
- limit,
- objectsToExclude,
- width
- ) {
- return this._picking.drillPickFromRay(
- this,
- ray,
- limit,
- objectsToExclude,
- width
- );
- };
- /**
- * Initiates an asynchronous {@link Scene#pickFromRay} request using the maximum level of detail for 3D Tilesets
- * regardless of visibility.
- *
- * @private
- *
- * @param {Ray} ray The ray.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @returns {Promise<object>} A promise that resolves to an object containing the object and position of the first intersection.
- *
- * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
- */
- Scene.prototype.pickFromRayMostDetailed = function (
- ray,
- objectsToExclude,
- width
- ) {
- return this._picking.pickFromRayMostDetailed(
- this,
- ray,
- objectsToExclude,
- width
- );
- };
- /**
- * Initiates an asynchronous {@link Scene#drillPickFromRay} request using the maximum level of detail for 3D Tilesets
- * regardless of visibility.
- *
- * @private
- *
- * @param {Ray} ray The ray.
- * @param {number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @returns {Promise<Object[]>} A promise that resolves to a list of objects containing the object and position of each intersection.
- *
- * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
- */
- Scene.prototype.drillPickFromRayMostDetailed = function (
- ray,
- limit,
- objectsToExclude,
- width
- ) {
- return this._picking.drillPickFromRayMostDetailed(
- this,
- ray,
- limit,
- objectsToExclude,
- width
- );
- };
- /**
- * Returns the height of scene geometry at the given cartographic position or <code>undefined</code> if there was no
- * scene geometry to sample height from. The height of the input position is ignored. May be used to clamp objects to
- * the globe, 3D Tiles, or primitives in the scene.
- * <p>
- * This function only samples height from globe tiles and 3D Tiles that are rendered in the current view. Samples height
- * from all other primitives regardless of their visibility.
- * </p>
- *
- * @param {Cartographic} position The cartographic position to sample height from.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @returns {number} The height. This may be <code>undefined</code> if there was no scene geometry to sample height from.
- *
- * @example
- * const position = new Cesium.Cartographic(-1.31968, 0.698874);
- * const height = viewer.scene.sampleHeight(position);
- * console.log(height);
- *
- * @see Scene#clampToHeight
- * @see Scene#clampToHeightMostDetailed
- * @see Scene#sampleHeightMostDetailed
- *
- * @exception {DeveloperError} sampleHeight is only supported in 3D mode.
- * @exception {DeveloperError} sampleHeight requires depth texture support. Check sampleHeightSupported.
- */
- Scene.prototype.sampleHeight = function (position, objectsToExclude, width) {
- return this._picking.sampleHeight(this, position, objectsToExclude, width);
- };
- /**
- * Clamps the given cartesian position to the scene geometry along the geodetic surface normal. Returns the
- * clamped position or <code>undefined</code> if there was no scene geometry to clamp to. May be used to clamp
- * objects to the globe, 3D Tiles, or primitives in the scene.
- * <p>
- * This function only clamps to globe tiles and 3D Tiles that are rendered in the current view. Clamps to
- * all other primitives regardless of their visibility.
- * </p>
- *
- * @param {Cartesian3} cartesian The cartesian position.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @param {Cartesian3} [result] An optional object to return the clamped position.
- * @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.
- *
- * @example
- * // Clamp an entity to the underlying scene geometry
- * const position = entity.position.getValue(Cesium.JulianDate.now());
- * entity.position = viewer.scene.clampToHeight(position);
- *
- * @see Scene#sampleHeight
- * @see Scene#sampleHeightMostDetailed
- * @see Scene#clampToHeightMostDetailed
- *
- * @exception {DeveloperError} clampToHeight is only supported in 3D mode.
- * @exception {DeveloperError} clampToHeight requires depth texture support. Check clampToHeightSupported.
- */
- Scene.prototype.clampToHeight = function (
- cartesian,
- objectsToExclude,
- width,
- result
- ) {
- return this._picking.clampToHeight(
- this,
- cartesian,
- objectsToExclude,
- width,
- result
- );
- };
- /**
- * Initiates an asynchronous {@link Scene#sampleHeight} query for an array of {@link Cartographic} positions
- * using the maximum level of detail for 3D Tilesets in the scene. The height of the input positions is ignored.
- * Returns a promise that is resolved when the query completes. Each point height is modified in place.
- * If a height cannot be determined because no geometry can be sampled at that location, or another error occurs,
- * the height is set to undefined.
- *
- * @param {Cartographic[]} positions The cartographic positions to update with sampled heights.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @returns {Promise<Cartographic[]>} A promise that resolves to the provided list of positions when the query has completed.
- *
- * @example
- * const positions = [
- * new Cesium.Cartographic(-1.31968, 0.69887),
- * new Cesium.Cartographic(-1.10489, 0.83923)
- * ];
- * const promise = viewer.scene.sampleHeightMostDetailed(positions);
- * promise.then(function(updatedPosition) {
- * // positions[0].height and positions[1].height have been updated.
- * // updatedPositions is just a reference to positions.
- * }
- *
- * @see Scene#sampleHeight
- *
- * @exception {DeveloperError} sampleHeightMostDetailed is only supported in 3D mode.
- * @exception {DeveloperError} sampleHeightMostDetailed requires depth texture support. Check sampleHeightSupported.
- */
- Scene.prototype.sampleHeightMostDetailed = function (
- positions,
- objectsToExclude,
- width
- ) {
- return this._picking.sampleHeightMostDetailed(
- this,
- positions,
- objectsToExclude,
- width
- );
- };
- /**
- * Initiates an asynchronous {@link Scene#clampToHeight} query for an array of {@link Cartesian3} positions
- * using the maximum level of detail for 3D Tilesets in the scene. Returns a promise that is resolved when
- * the query completes. Each position is modified in place. If a position cannot be clamped because no geometry
- * can be sampled at that location, or another error occurs, the element in the array is set to undefined.
- *
- * @param {Cartesian3[]} cartesians The cartesian positions to update with clamped positions.
- * @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
- * @param {number} [width=0.1] Width of the intersection volume in meters.
- * @returns {Promise<Cartesian3[]>} A promise that resolves to the provided list of positions when the query has completed.
- *
- * @example
- * const cartesians = [
- * entities[0].position.getValue(Cesium.JulianDate.now()),
- * entities[1].position.getValue(Cesium.JulianDate.now())
- * ];
- * const promise = viewer.scene.clampToHeightMostDetailed(cartesians);
- * promise.then(function(updatedCartesians) {
- * entities[0].position = updatedCartesians[0];
- * entities[1].position = updatedCartesians[1];
- * }
- *
- * @see Scene#clampToHeight
- *
- * @exception {DeveloperError} clampToHeightMostDetailed is only supported in 3D mode.
- * @exception {DeveloperError} clampToHeightMostDetailed requires depth texture support. Check clampToHeightSupported.
- */
- Scene.prototype.clampToHeightMostDetailed = function (
- cartesians,
- objectsToExclude,
- width
- ) {
- return this._picking.clampToHeightMostDetailed(
- this,
- cartesians,
- objectsToExclude,
- width
- );
- };
- /**
- * Transforms a position in cartesian coordinates to canvas coordinates. This is commonly used to place an
- * HTML element at the same screen position as an object in the scene.
- *
- * @param {Cartesian3} position The position in cartesian coordinates.
- * @param {Cartesian2} [result] An optional object to return the input position transformed to canvas coordinates.
- * @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.
- *
- * @example
- * // Output the canvas position of longitude/latitude (0, 0) every time the mouse moves.
- * const scene = widget.scene;
- * const ellipsoid = scene.globe.ellipsoid;
- * const position = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
- * const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
- * handler.setInputAction(function(movement) {
- * console.log(scene.cartesianToCanvasCoordinates(position));
- * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
- */
- Scene.prototype.cartesianToCanvasCoordinates = function (position, result) {
- return SceneTransforms.wgs84ToWindowCoordinates(this, position, result);
- };
- /**
- * Instantly completes an active transition.
- */
- Scene.prototype.completeMorph = function () {
- this._transitioner.completeMorph();
- };
- /**
- * Asynchronously transitions the scene to 2D.
- * @param {number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
- */
- Scene.prototype.morphTo2D = function (duration) {
- let ellipsoid;
- const globe = this.globe;
- if (defined(globe)) {
- ellipsoid = globe.ellipsoid;
- } else {
- ellipsoid = this.mapProjection.ellipsoid;
- }
- duration = defaultValue(duration, 2.0);
- this._transitioner.morphTo2D(duration, ellipsoid);
- };
- /**
- * Asynchronously transitions the scene to Columbus View.
- * @param {number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
- */
- Scene.prototype.morphToColumbusView = function (duration) {
- let ellipsoid;
- const globe = this.globe;
- if (defined(globe)) {
- ellipsoid = globe.ellipsoid;
- } else {
- ellipsoid = this.mapProjection.ellipsoid;
- }
- duration = defaultValue(duration, 2.0);
- this._transitioner.morphToColumbusView(duration, ellipsoid);
- };
- /**
- * Asynchronously transitions the scene to 3D.
- * @param {number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
- */
- Scene.prototype.morphTo3D = function (duration) {
- let ellipsoid;
- const globe = this.globe;
- if (defined(globe)) {
- ellipsoid = globe.ellipsoid;
- } else {
- ellipsoid = this.mapProjection.ellipsoid;
- }
- duration = defaultValue(duration, 2.0);
- this._transitioner.morphTo3D(duration, ellipsoid);
- };
- function setTerrain(scene, terrain) {
- // Cancel any in-progress terrain update
- scene._removeTerrainProviderReadyListener =
- scene._removeTerrainProviderReadyListener &&
- scene._removeTerrainProviderReadyListener();
- // If the terrain is already loaded, set it immediately
- if (terrain.ready) {
- if (defined(scene.globe)) {
- scene.globe.terrainProvider = terrain.provider;
- }
- return;
- }
- // Otherwise, set a placeholder
- scene.globe.terrainProvider = undefined;
- scene._removeTerrainProviderReadyListener = terrain.readyEvent.addEventListener(
- (provider) => {
- if (defined(scene) && defined(scene.globe)) {
- scene.globe.terrainProvider = provider;
- }
- scene._removeTerrainProviderReadyListener();
- }
- );
- }
- /**
- * Update the terrain providing surface geometry for the globe.
- *
- * @param {Terrain} terrain The terrain provider async helper
- * @returns {Terrain} terrain The terrain provider async helper
- *
- * @example
- * // Use Cesium World Terrain
- * scene.setTerrain(Cesium.Terrain.fromWorldTerrain());
- *
- * @example
- * // Use a custom terrain provider
- * const terrain = new Cesium.Terrain(Cesium.CesiumTerrainProvider.fromUrl("https://myTestTerrain.com"));
- * scene.setTerrain(terrain);
- *
- * terrain.errorEvent.addEventListener(error => {
- * alert(`Encountered an error while creating terrain! ${error}`);
- * });
- */
- Scene.prototype.setTerrain = function (terrain) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("terrain", terrain);
- //>>includeEnd('debug');
- setTerrain(this, terrain);
- return terrain;
- };
- /**
- * Returns true if this object was destroyed; otherwise, false.
- * <br /><br />
- * If this object was destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
- *
- * @returns {boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
- *
- * @see Scene#destroy
- */
- Scene.prototype.isDestroyed = function () {
- return false;
- };
- /**
- * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
- * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
- * <br /><br />
- * Once an object is destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
- * assign the return value (<code>undefined</code>) to the object as done in the example.
- *
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
- *
- *
- * @example
- * scene = scene && scene.destroy();
- *
- * @see Scene#isDestroyed
- */
- Scene.prototype.destroy = function () {
- this._tweens.removeAll();
- this._computeEngine = this._computeEngine && this._computeEngine.destroy();
- this._screenSpaceCameraController =
- this._screenSpaceCameraController &&
- this._screenSpaceCameraController.destroy();
- this._deviceOrientationCameraController =
- this._deviceOrientationCameraController &&
- !this._deviceOrientationCameraController.isDestroyed() &&
- this._deviceOrientationCameraController.destroy();
- this._primitives = this._primitives && this._primitives.destroy();
- this._groundPrimitives =
- this._groundPrimitives && this._groundPrimitives.destroy();
- this._globe = this._globe && this._globe.destroy();
- this._removeTerrainProviderReadyListener =
- this._removeTerrainProviderReadyListener &&
- this._removeTerrainProviderReadyListener();
- this.skyBox = this.skyBox && this.skyBox.destroy();
- this.skyAtmosphere = this.skyAtmosphere && this.skyAtmosphere.destroy();
- this._debugSphere = this._debugSphere && this._debugSphere.destroy();
- this.sun = this.sun && this.sun.destroy();
- this._sunPostProcess = this._sunPostProcess && this._sunPostProcess.destroy();
- this._depthPlane = this._depthPlane && this._depthPlane.destroy();
- this._transitioner = this._transitioner && this._transitioner.destroy();
- this._debugFrustumPlanes =
- this._debugFrustumPlanes && this._debugFrustumPlanes.destroy();
- this._brdfLutGenerator =
- this._brdfLutGenerator && this._brdfLutGenerator.destroy();
- this._picking = this._picking && this._picking.destroy();
- this._defaultView = this._defaultView && this._defaultView.destroy();
- this._view = undefined;
- if (this._removeCreditContainer) {
- this._canvas.parentNode.removeChild(this._creditContainer);
- }
- this.postProcessStages =
- this.postProcessStages && this.postProcessStages.destroy();
- this._context = this._context && this._context.destroy();
- this._frameState.creditDisplay =
- this._frameState.creditDisplay && this._frameState.creditDisplay.destroy();
- if (defined(this._performanceDisplay)) {
- this._performanceDisplay =
- this._performanceDisplay && this._performanceDisplay.destroy();
- this._performanceContainer.parentNode.removeChild(
- this._performanceContainer
- );
- }
- this._removeRequestListenerCallback();
- this._removeTaskProcessorListenerCallback();
- for (let i = 0; i < this._removeGlobeCallbacks.length; ++i) {
- this._removeGlobeCallbacks[i]();
- }
- this._removeGlobeCallbacks.length = 0;
- return destroyObject(this);
- };
- export default Scene;
|