智慧水务管理系统 - 精河县供水工程综合管理平台

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318
  1. import BoundingRectangle from "../Core/BoundingRectangle.js";
  2. import BoundingSphere from "../Core/BoundingSphere.js";
  3. import BoxGeometry from "../Core/BoxGeometry.js";
  4. import Cartesian3 from "../Core/Cartesian3.js";
  5. import Cartographic from "../Core/Cartographic.js";
  6. import Check from "../Core/Check.js";
  7. import clone from "../Core/clone.js";
  8. import Color from "../Core/Color.js";
  9. import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
  10. import createGuid from "../Core/createGuid.js";
  11. import CullingVolume from "../Core/CullingVolume.js";
  12. import Frozen from "../Core/Frozen.js";
  13. import defined from "../Core/defined.js";
  14. import destroyObject from "../Core/destroyObject.js";
  15. import DeveloperError from "../Core/DeveloperError.js";
  16. import Ellipsoid from "../Core/Ellipsoid.js";
  17. import EllipsoidGeometry from "../Core/EllipsoidGeometry.js";
  18. import Event from "../Core/Event.js";
  19. import GeographicProjection from "../Core/GeographicProjection.js";
  20. import GeometryInstance from "../Core/GeometryInstance.js";
  21. import GeometryPipeline from "../Core/GeometryPipeline.js";
  22. import HeightReference from "./HeightReference.js";
  23. import Intersect from "../Core/Intersect.js";
  24. import JulianDate from "../Core/JulianDate.js";
  25. import CesiumMath from "../Core/Math.js";
  26. import Matrix4 from "../Core/Matrix4.js";
  27. import mergeSort from "../Core/mergeSort.js";
  28. import Occluder from "../Core/Occluder.js";
  29. import OrthographicFrustum from "../Core/OrthographicFrustum.js";
  30. import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js";
  31. import PerspectiveFrustum from "../Core/PerspectiveFrustum.js";
  32. import PerspectiveOffCenterFrustum from "../Core/PerspectiveOffCenterFrustum.js";
  33. import Rectangle from "../Core/Rectangle.js";
  34. import RequestScheduler from "../Core/RequestScheduler.js";
  35. import TaskProcessor from "../Core/TaskProcessor.js";
  36. import Transforms from "../Core/Transforms.js";
  37. import ClearCommand from "../Renderer/ClearCommand.js";
  38. import ComputeEngine from "../Renderer/ComputeEngine.js";
  39. import Context from "../Renderer/Context.js";
  40. import ContextLimits from "../Renderer/ContextLimits.js";
  41. import Pass from "../Renderer/Pass.js";
  42. import RenderState from "../Renderer/RenderState.js";
  43. import Atmosphere from "./Atmosphere.js";
  44. import BrdfLutGenerator from "./BrdfLutGenerator.js";
  45. import Camera from "./Camera.js";
  46. import Cesium3DTilePass from "./Cesium3DTilePass.js";
  47. import Cesium3DTilePassState from "./Cesium3DTilePassState.js";
  48. import CreditDisplay from "./CreditDisplay.js";
  49. import DebugCameraPrimitive from "./DebugCameraPrimitive.js";
  50. import DepthPlane from "./DepthPlane.js";
  51. import DerivedCommand from "./DerivedCommand.js";
  52. import DeviceOrientationCameraController from "./DeviceOrientationCameraController.js";
  53. import DynamicAtmosphereLightingType from "./DynamicAtmosphereLightingType.js";
  54. import Fog from "./Fog.js";
  55. import FrameState from "./FrameState.js";
  56. import GlobeTranslucencyState from "./GlobeTranslucencyState.js";
  57. import InvertClassification from "./InvertClassification.js";
  58. import JobScheduler from "./JobScheduler.js";
  59. import MapMode2D from "./MapMode2D.js";
  60. import PerformanceDisplay from "./PerformanceDisplay.js";
  61. import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js";
  62. import Picking from "./Picking.js";
  63. import PostProcessStageCollection from "./PostProcessStageCollection.js";
  64. import Primitive from "./Primitive.js";
  65. import PrimitiveCollection from "./PrimitiveCollection.js";
  66. import SceneMode from "./SceneMode.js";
  67. import SceneTransforms from "./SceneTransforms.js";
  68. import SceneTransitioner from "./SceneTransitioner.js";
  69. import ScreenSpaceCameraController from "./ScreenSpaceCameraController.js";
  70. import ShadowMap from "./ShadowMap.js";
  71. import SharedContext from "../Renderer/SharedContext.js";
  72. import SpecularEnvironmentCubeMap from "./SpecularEnvironmentCubeMap.js";
  73. import StencilConstants from "./StencilConstants.js";
  74. import SunLight from "./SunLight.js";
  75. import SunPostProcess from "./SunPostProcess.js";
  76. import TweenCollection from "./TweenCollection.js";
  77. import View from "./View.js";
  78. import DebugInspector from "./DebugInspector.js";
  79. import VoxelCell from "./VoxelCell.js";
  80. import VoxelPrimitive from "./VoxelPrimitive.js";
  81. import getMetadataClassProperty from "./getMetadataClassProperty.js";
  82. import PickedMetadataInfo from "./PickedMetadataInfo.js";
  83. import getMetadataProperty from "./getMetadataProperty.js";
  84. const requestRenderAfterFrame = function (scene) {
  85. return function () {
  86. scene.frameState.afterRender.push(function () {
  87. scene.requestRender();
  88. });
  89. };
  90. };
  91. /**
  92. * The container for all 3D graphical objects and state in a Cesium virtual scene. Generally,
  93. * a scene is not created directly; instead, it is implicitly created by {@link CesiumWidget}.
  94. *
  95. * @alias Scene
  96. * @constructor
  97. *
  98. * @param {object} options Object with the following properties:
  99. * @param {HTMLCanvasElement} options.canvas The HTML canvas element to create the scene for.
  100. * @param {ContextOptions} [options.contextOptions] Context and WebGL creation properties.
  101. * @param {Element} [options.creditContainer] The HTML element in which the credits will be displayed. If not specified, a credit container will be created and added as a sibling of the canvas.
  102. * @param {Element} [options.creditViewport] The HTML element in which to display the credit popup. If not specified, the viewport will be added as a sibling of the canvas.
  103. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.default] The default ellipsoid. If not specified, the default ellipsoid is used.
  104. * @param {MapProjection} [options.mapProjection=new GeographicProjection(options.ellipsoid)] The map projection to use in 2D and Columbus View modes.
  105. * @param {boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
  106. * @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.
  107. * @param {boolean} [options.shadows=false] Determines if shadows are cast by light sources.
  108. * @param {MapMode2D} [options.mapMode2D=MapMode2D.INFINITE_SCROLL] Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  109. * @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}.
  110. * @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}.
  111. * @param {number} [options.depthPlaneEllipsoidOffset=0.0] Adjust the DepthPlane to address rendering artefacts below ellipsoid zero elevation.
  112. * @param {number} [options.msaaSamples=4] 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. Set to 1 to disable MSAA.
  113. *
  114. * @see CesiumWidget
  115. * @see {@link http://www.khronos.org/registry/webgl/specs/latest/#5.2|WebGLContextAttributes}
  116. *
  117. * @exception {DeveloperError} options and options.canvas are required.
  118. *
  119. * @example
  120. * // Create scene without anisotropic texture filtering
  121. * const scene = new Cesium.Scene({
  122. * canvas : canvas,
  123. * contextOptions : {
  124. * allowTextureFilterAnisotropic : false
  125. * }
  126. * });
  127. */
  128. function Scene(options) {
  129. options = options ?? Frozen.EMPTY_OBJECT;
  130. const canvas = options.canvas;
  131. let creditContainer = options.creditContainer;
  132. let creditViewport = options.creditViewport;
  133. //>>includeStart('debug', pragmas.debug);
  134. if (!defined(canvas)) {
  135. throw new DeveloperError("options and options.canvas are required.");
  136. }
  137. //>>includeEnd('debug');
  138. const countReferences = options.contextOptions instanceof SharedContext;
  139. if (countReferences) {
  140. this._context = options.contextOptions.createSceneContext(canvas);
  141. } else {
  142. const contextOptions = clone(options.contextOptions);
  143. this._context = new Context(canvas, contextOptions);
  144. }
  145. const context = this._context;
  146. const hasCreditContainer = defined(creditContainer);
  147. if (!hasCreditContainer) {
  148. creditContainer = document.createElement("div");
  149. creditContainer.style.position = "absolute";
  150. creditContainer.style.bottom = "0";
  151. creditContainer.style["text-shadow"] = "0 0 2px #000000";
  152. creditContainer.style.color = "#ffffff";
  153. creditContainer.style["font-size"] = "10px";
  154. creditContainer.style["padding-right"] = "5px";
  155. canvas.parentNode.appendChild(creditContainer);
  156. }
  157. if (!defined(creditViewport)) {
  158. creditViewport = canvas.parentNode;
  159. }
  160. this._id = createGuid();
  161. this._jobScheduler = new JobScheduler();
  162. this._frameState = new FrameState(
  163. context,
  164. new CreditDisplay(creditContainer, "•", creditViewport),
  165. this._jobScheduler,
  166. );
  167. this._frameState.scene3DOnly = options.scene3DOnly ?? false;
  168. this._removeCreditContainer = !hasCreditContainer;
  169. this._creditContainer = creditContainer;
  170. this._canvas = canvas;
  171. this._computeEngine = new ComputeEngine(context);
  172. this._ellipsoid = options.ellipsoid ?? Ellipsoid.default;
  173. this._globe = undefined;
  174. this._globeTranslucencyState = new GlobeTranslucencyState();
  175. this._primitives = new PrimitiveCollection({ countReferences });
  176. this._groundPrimitives = new PrimitiveCollection({ countReferences });
  177. this._globeHeight = undefined;
  178. this._globeHeightDirty = true;
  179. this._cameraUnderground = false;
  180. this._removeUpdateHeightCallback = undefined;
  181. this._logDepthBuffer = Scene.defaultLogDepthBuffer && context.fragmentDepth;
  182. this._logDepthBufferDirty = true;
  183. this._tweens = new TweenCollection();
  184. this._shaderFrameCount = 0;
  185. this._sunPostProcess = undefined;
  186. this._computeCommandList = [];
  187. this._overlayCommandList = [];
  188. this._useOIT = options.orderIndependentTranslucency ?? true;
  189. /**
  190. * The function that will be used for executing translucent commands when
  191. * useOIT is true. This is created once in
  192. * obtainTranslucentCommandExecutionFunction, then cached here.
  193. * @private
  194. */
  195. this._executeOITFunction = undefined;
  196. this._depthPlane = new DepthPlane(options.depthPlaneEllipsoidOffset);
  197. this._clearColorCommand = new ClearCommand({
  198. color: new Color(),
  199. stencil: 0,
  200. owner: this,
  201. });
  202. this._depthClearCommand = new ClearCommand({
  203. depth: 1.0,
  204. owner: this,
  205. });
  206. this._stencilClearCommand = new ClearCommand({
  207. stencil: 0,
  208. });
  209. this._classificationStencilClearCommand = new ClearCommand({
  210. stencil: 0,
  211. renderState: RenderState.fromCache({
  212. stencilMask: StencilConstants.CLASSIFICATION_MASK,
  213. }),
  214. });
  215. this._depthOnlyRenderStateCache = {};
  216. this._transitioner = new SceneTransitioner(this);
  217. this._preUpdate = new Event();
  218. this._postUpdate = new Event();
  219. this._renderError = new Event();
  220. this._preRender = new Event();
  221. this._postRender = new Event();
  222. this._minimumDisableDepthTestDistance = 0.0;
  223. this._debugInspector = new DebugInspector();
  224. this._msaaSamples = options.msaaSamples ?? 4;
  225. /**
  226. * Exceptions occurring in <code>render</code> are always caught in order to raise the
  227. * <code>renderError</code> event. If this property is true, the error is rethrown
  228. * after the event is raised. If this property is false, the <code>render</code> function
  229. * returns normally after raising the event.
  230. *
  231. * @type {boolean}
  232. * @default false
  233. */
  234. this.rethrowRenderErrors = false;
  235. /**
  236. * Determines whether or not to instantly complete the
  237. * scene transition animation on user input.
  238. *
  239. * @type {boolean}
  240. * @default true
  241. */
  242. this.completeMorphOnUserInput = true;
  243. /**
  244. * The event fired at the beginning of a scene transition.
  245. * @type {Event}
  246. * @default Event()
  247. */
  248. this.morphStart = new Event();
  249. /**
  250. * The event fired at the completion of a scene transition.
  251. * @type {Event}
  252. * @default Event()
  253. */
  254. this.morphComplete = new Event();
  255. /**
  256. * The {@link SkyBox} used to draw the stars.
  257. *
  258. * @type {SkyBox | undefined}
  259. * @default undefined
  260. *
  261. * @see Scene#backgroundColor
  262. */
  263. this.skyBox = undefined;
  264. /**
  265. * The sky atmosphere drawn around the globe.
  266. *
  267. * @type {SkyAtmosphere | undefined}
  268. * @default undefined
  269. */
  270. this.skyAtmosphere = undefined;
  271. /**
  272. * The {@link Sun}.
  273. *
  274. * @type {Sun | undefined}
  275. * @default undefined
  276. */
  277. this.sun = undefined;
  278. /**
  279. * Uses a bloom filter on the sun when enabled.
  280. *
  281. * @type {boolean}
  282. * @default true
  283. */
  284. this.sunBloom = true;
  285. this._sunBloom = undefined;
  286. /**
  287. * The {@link Moon}
  288. *
  289. * @type {Moon | undefined}
  290. * @default undefined
  291. */
  292. this.moon = undefined;
  293. /**
  294. * The background color, which is only visible if there is no sky box, i.e., {@link Scene#skyBox} is <code>undefined</code>.
  295. *
  296. * @type {Color}
  297. * @default {@link Color.BLACK}
  298. *
  299. * @see Scene#skyBox
  300. */
  301. this.backgroundColor = Color.clone(Color.BLACK);
  302. this._mode = SceneMode.SCENE3D;
  303. this._mapProjection = defined(options.mapProjection)
  304. ? options.mapProjection
  305. : new GeographicProjection(this._ellipsoid);
  306. /**
  307. * The current morph transition time between 2D/Columbus View and 3D,
  308. * with 0.0 being 2D or Columbus View and 1.0 being 3D.
  309. *
  310. * @type {number}
  311. * @default 1.0
  312. */
  313. this.morphTime = 1.0;
  314. /**
  315. * The far-to-near ratio of the multi-frustum when using a normal depth buffer.
  316. * <p>
  317. * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used
  318. * when {@link Scene#logarithmicDepthBuffer} is <code>false</code>. When <code>logarithmicDepthBuffer</code> is
  319. * <code>true</code>, use {@link Scene#logarithmicDepthFarToNearRatio}.
  320. * </p>
  321. *
  322. * @type {number}
  323. * @default 1000.0
  324. */
  325. this.farToNearRatio = 1000.0;
  326. /**
  327. * The far-to-near ratio of the multi-frustum when using a logarithmic depth buffer.
  328. * <p>
  329. * This value is used to create the near and far values for each frustum of the multi-frustum. It is only used
  330. * when {@link Scene#logarithmicDepthBuffer} is <code>true</code>. When <code>logarithmicDepthBuffer</code> is
  331. * <code>false</code>, use {@link Scene#farToNearRatio}.
  332. * </p>
  333. *
  334. * @type {number}
  335. * @default 1e9
  336. */
  337. this.logarithmicDepthFarToNearRatio = 1e9;
  338. /**
  339. * Determines the uniform depth size in meters of each frustum of the multifrustum in 2D. If a primitive or model close
  340. * to the surface shows z-fighting, decreasing this will eliminate the artifact, but decrease performance. On the
  341. * other hand, increasing this will increase performance but may cause z-fighting among primitives close to the surface.
  342. *
  343. * @type {number}
  344. * @default 1.75e6
  345. */
  346. this.nearToFarDistance2D = 1.75e6;
  347. /**
  348. * The vertical exaggeration of the scene.
  349. * When set to 1.0, no exaggeration is applied.
  350. *
  351. * @type {number}
  352. * @default 1.0
  353. */
  354. this.verticalExaggeration = 1.0;
  355. /**
  356. * The reference height for vertical exaggeration of the scene.
  357. * When set to 0.0, the exaggeration is applied relative to the ellipsoid surface.
  358. *
  359. * @type {number}
  360. * @default 0.0
  361. */
  362. this.verticalExaggerationRelativeHeight = 0.0;
  363. /**
  364. * This property is for debugging only; it is not for production use.
  365. * <p>
  366. * A function that determines what commands are executed. As shown in the examples below,
  367. * the function receives the command's <code>owner</code> as an argument, and returns a boolean indicating if the
  368. * command should be executed.
  369. * </p>
  370. * <p>
  371. * The default is <code>undefined</code>, indicating that all commands are executed.
  372. * </p>
  373. *
  374. * @type {Function | undefined}
  375. *
  376. * @default undefined
  377. *
  378. * @example
  379. * // Do not execute any commands.
  380. * scene.debugCommandFilter = function(command) {
  381. * return false;
  382. * };
  383. *
  384. * // Execute only the billboard's commands. That is, only draw the billboard.
  385. * const billboards = new Cesium.BillboardCollection();
  386. * scene.debugCommandFilter = function(command) {
  387. * return command.owner === billboards;
  388. * };
  389. */
  390. this.debugCommandFilter = undefined;
  391. /**
  392. * This property is for debugging only; it is not for production use.
  393. * <p>
  394. * When <code>true</code>, commands are randomly shaded. This is useful
  395. * for performance analysis to see what parts of a scene or model are
  396. * command-dense and could benefit from batching.
  397. * </p>
  398. *
  399. * @type {boolean}
  400. *
  401. * @default false
  402. */
  403. this.debugShowCommands = false;
  404. /**
  405. * This property is for debugging only; it is not for production use.
  406. * <p>
  407. * When <code>true</code>, commands are shaded based on the frustums they
  408. * overlap. Commands in the closest frustum are tinted red, commands in
  409. * the next closest are green, and commands in the farthest frustum are
  410. * blue. If a command overlaps more than one frustum, the color components
  411. * are combined, e.g., a command overlapping the first two frustums is tinted
  412. * yellow.
  413. * </p>
  414. *
  415. * @type {boolean}
  416. *
  417. * @default false
  418. */
  419. this.debugShowFrustums = false;
  420. /**
  421. * This property is for debugging only; it is not for production use.
  422. * <p>
  423. * Displays frames per second and time between frames.
  424. * </p>
  425. *
  426. * @type {boolean}
  427. *
  428. * @default false
  429. */
  430. this.debugShowFramesPerSecond = false;
  431. /**
  432. * This property is for debugging only; it is not for production use.
  433. * <p>
  434. * Indicates which frustum will have depth information displayed.
  435. * </p>
  436. *
  437. * @type {number}
  438. *
  439. * @default 1
  440. */
  441. this.debugShowDepthFrustum = 1;
  442. /**
  443. * This property is for debugging only; it is not for production use.
  444. * <p>
  445. * When <code>true</code>, draws outlines to show the boundaries of the camera frustums
  446. * </p>
  447. *
  448. * @type {boolean}
  449. *
  450. * @default false
  451. */
  452. this.debugShowFrustumPlanes = false;
  453. this._debugShowFrustumPlanes = false;
  454. this._debugFrustumPlanes = undefined;
  455. /**
  456. * When <code>true</code>, enables picking using the depth buffer.
  457. *
  458. * @type {boolean}
  459. * @default true
  460. */
  461. this.useDepthPicking = true;
  462. /**
  463. * 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.
  464. *
  465. * <p>
  466. * There is a decrease in performance when enabled. There are extra draw calls to write depth for
  467. * translucent geometry.
  468. * </p>
  469. *
  470. * @example
  471. * // picking the position of a translucent primitive
  472. * viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
  473. * const pickedFeature = viewer.scene.pick(movement.position);
  474. * if (!Cesium.defined(pickedFeature)) {
  475. * // nothing picked
  476. * return;
  477. * }
  478. * const worldPosition = viewer.scene.pickPosition(movement.position);
  479. * }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  480. *
  481. * @type {boolean}
  482. * @default false
  483. */
  484. this.pickTranslucentDepth = false;
  485. /**
  486. * The time in milliseconds to wait before checking if the camera has not moved and fire the cameraMoveEnd event.
  487. * @type {number}
  488. * @default 500.0
  489. * @private
  490. */
  491. this.cameraEventWaitTime = 500.0;
  492. /**
  493. * Settings for atmosphere lighting effects affecting 3D Tiles and model rendering. This is not to be confused with
  494. * {@link Scene#skyAtmosphere} which is responsible for rendering the sky.
  495. *
  496. * @type {Atmosphere}
  497. */
  498. this.atmosphere = new Atmosphere();
  499. /**
  500. * Blends the atmosphere to geometry far from the camera for horizon views. Allows for additional
  501. * performance improvements by rendering less geometry and dispatching less terrain requests.
  502. *
  503. * Disbaled by default if an ellipsoid other than WGS84 is used.
  504. * @type {Fog}
  505. */
  506. this.fog = new Fog();
  507. this.fog.enabled = Ellipsoid.WGS84.equals(this._ellipsoid);
  508. if (!Ellipsoid.WGS84.equals(this._ellipsoid)) {
  509. Camera.DEFAULT_VIEW_RECTANGLE = Rectangle.fromDegrees(
  510. -45.0,
  511. -45.0,
  512. 45.0,
  513. 45.0,
  514. );
  515. }
  516. this._shadowMapCamera = new Camera(this);
  517. /**
  518. * The shadow map for the scene's light source. When enabled, models, primitives, and the globe may cast and receive shadows.
  519. * @type {ShadowMap}
  520. */
  521. this.shadowMap = new ShadowMap({
  522. context: context,
  523. lightCamera: this._shadowMapCamera,
  524. enabled: options.shadows ?? false,
  525. });
  526. /**
  527. * When <code>false</code>, 3D Tiles will render normally. When <code>true</code>, classified 3D Tile geometry will render normally and
  528. * unclassified 3D Tile geometry will render with the color multiplied by {@link Scene#invertClassificationColor}.
  529. * @type {boolean}
  530. * @default false
  531. */
  532. this.invertClassification = false;
  533. /**
  534. * The highlight color of unclassified 3D Tile geometry when {@link Scene#invertClassification} is <code>true</code>.
  535. * <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>
  536. * <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>
  537. * @type {Color}
  538. * @default Color.WHITE
  539. */
  540. this.invertClassificationColor = Color.clone(Color.WHITE);
  541. this._actualInvertClassificationColor = Color.clone(
  542. this._invertClassificationColor,
  543. );
  544. this._invertClassification = new InvertClassification();
  545. /**
  546. * The focal length for use when with cardboard or WebVR.
  547. * @type {number}
  548. */
  549. this.focalLength = undefined;
  550. /**
  551. * The eye separation distance in meters for use with cardboard or WebVR.
  552. * @type {number}
  553. */
  554. this.eyeSeparation = undefined;
  555. /**
  556. * Post processing effects applied to the final render.
  557. * @type {PostProcessStageCollection}
  558. */
  559. this.postProcessStages = new PostProcessStageCollection();
  560. this._brdfLutGenerator = new BrdfLutGenerator();
  561. this._performanceDisplay = undefined;
  562. this._debugVolume = undefined;
  563. this._screenSpaceCameraController = new ScreenSpaceCameraController(this);
  564. this._cameraUnderground = false;
  565. this._mapMode2D = options.mapMode2D ?? MapMode2D.INFINITE_SCROLL;
  566. // Keeps track of the state of a frame. FrameState is the state across
  567. // the primitives of the scene. This state is for internally keeping track
  568. // of celestial and environment effects that need to be updated/rendered in
  569. // a certain order as well as updating/tracking framebuffer usage.
  570. this._environmentState = {
  571. skyBoxCommand: undefined,
  572. skyAtmosphereCommand: undefined,
  573. sunDrawCommand: undefined,
  574. sunComputeCommand: undefined,
  575. moonCommand: undefined,
  576. isSunVisible: false,
  577. isMoonVisible: false,
  578. isReadyForAtmosphere: false,
  579. isSkyAtmosphereVisible: false,
  580. clearGlobeDepth: false,
  581. useDepthPlane: false,
  582. renderTranslucentDepthForPick: false,
  583. originalFramebuffer: undefined,
  584. useGlobeDepthFramebuffer: false,
  585. useOIT: false,
  586. useInvertClassification: false,
  587. usePostProcess: false,
  588. usePostProcessSelected: false,
  589. useWebVR: false,
  590. };
  591. this._useWebVR = false;
  592. this._cameraVR = undefined;
  593. this._aspectRatioVR = undefined;
  594. /**
  595. * When <code>true</code>, rendering a frame will only occur when needed as determined by changes within the scene.
  596. * Enabling improves performance of the application, but requires using {@link Scene#requestRender}
  597. * to render a new frame explicitly in this mode. This will be necessary in many cases after making changes
  598. * to the scene in other parts of the API.
  599. *
  600. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  601. * @see Scene#maximumRenderTimeChange
  602. * @see Scene#requestRender
  603. *
  604. * @type {boolean}
  605. * @default false
  606. */
  607. this.requestRenderMode = options.requestRenderMode ?? false;
  608. this._renderRequested = true;
  609. /**
  610. * If {@link Scene#requestRenderMode} is <code>true</code>, this value defines the maximum change in
  611. * simulation time allowed before a render is requested. Lower values increase the number of frames rendered
  612. * and higher values decrease the number of frames rendered. If <code>undefined</code>, changes to
  613. * the simulation time will never request a render.
  614. * This value impacts the rate of rendering for changes in the scene like lighting, entity property updates,
  615. * and animations.
  616. *
  617. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  618. * @see Scene#requestRenderMode
  619. *
  620. * @type {number}
  621. * @default 0.0
  622. */
  623. this.maximumRenderTimeChange = options.maximumRenderTimeChange ?? 0.0;
  624. this._lastRenderTime = undefined;
  625. this._frameRateMonitor = undefined;
  626. this._removeRequestListenerCallback =
  627. RequestScheduler.requestCompletedEvent.addEventListener(
  628. requestRenderAfterFrame(this),
  629. );
  630. this._removeTaskProcessorListenerCallback =
  631. TaskProcessor.taskCompletedEvent.addEventListener(
  632. requestRenderAfterFrame(this),
  633. );
  634. this._removeGlobeCallbacks = [];
  635. this._removeTerrainProviderReadyListener = undefined;
  636. const viewport = new BoundingRectangle(
  637. 0,
  638. 0,
  639. context.drawingBufferWidth,
  640. context.drawingBufferHeight,
  641. );
  642. const camera = new Camera(this);
  643. if (this._logDepthBuffer) {
  644. camera.frustum.near = 0.1;
  645. camera.frustum.far = 10000000000.0;
  646. }
  647. /**
  648. * The camera view for the scene camera flight destination. Used for preloading flight destination tiles.
  649. * @type {Camera}
  650. * @private
  651. */
  652. this.preloadFlightCamera = new Camera(this);
  653. /**
  654. * The culling volume for the scene camera flight destination. Used for preloading flight destination tiles.
  655. * @type {CullingVolume}
  656. * @private
  657. */
  658. this.preloadFlightCullingVolume = undefined;
  659. this._picking = new Picking(this);
  660. this._defaultView = new View(this, camera, viewport);
  661. this._view = this._defaultView;
  662. this._hdr = undefined;
  663. this._hdrDirty = undefined;
  664. this.highDynamicRange = false;
  665. this.gamma = 2.2;
  666. /**
  667. * The spherical harmonic coefficients for image-based lighting of PBR models.
  668. * @type {Cartesian3[]}
  669. */
  670. this.sphericalHarmonicCoefficients = undefined;
  671. /**
  672. * The url to the KTX2 file containing the specular environment map and convoluted mipmaps for image-based lighting of PBR models.
  673. * @type {string}
  674. */
  675. this.specularEnvironmentMaps = undefined;
  676. this._specularEnvironmentCubeMap = undefined;
  677. /**
  678. * The light source for shading. Defaults to a directional light from the Sun.
  679. * @type {Light}
  680. */
  681. this.light = new SunLight();
  682. /**
  683. * Whether or not to enable edge visibility rendering for 3D tiles.
  684. * When enabled, creates a framebuffer with multiple render targets
  685. * for advanced edge detection and visibility techniques.
  686. * @type {boolean}
  687. * @default false
  688. */
  689. this._enableEdgeVisibility = false;
  690. // Give frameState, camera, and screen space camera controller initial state before rendering
  691. updateFrameNumber(this, 0.0, JulianDate.now());
  692. this.updateFrameState();
  693. this.initializeFrame();
  694. }
  695. /**
  696. * Use this to set the default value for {@link Scene#logarithmicDepthBuffer} in newly constructed Scenes
  697. * This property relies on fragmentDepth being supported.
  698. */
  699. Scene.defaultLogDepthBuffer = true;
  700. function updateGlobeListeners(scene, globe) {
  701. for (let i = 0; i < scene._removeGlobeCallbacks.length; ++i) {
  702. scene._removeGlobeCallbacks[i]();
  703. }
  704. scene._removeGlobeCallbacks.length = 0;
  705. const removeGlobeCallbacks = [];
  706. if (defined(globe)) {
  707. removeGlobeCallbacks.push(
  708. globe.imageryLayersUpdatedEvent.addEventListener(
  709. requestRenderAfterFrame(scene),
  710. ),
  711. );
  712. removeGlobeCallbacks.push(
  713. globe.terrainProviderChanged.addEventListener(
  714. requestRenderAfterFrame(scene),
  715. ),
  716. );
  717. }
  718. scene._removeGlobeCallbacks = removeGlobeCallbacks;
  719. }
  720. Object.defineProperties(Scene.prototype, {
  721. /**
  722. * Gets the canvas element to which this scene is bound.
  723. * @memberof Scene.prototype
  724. *
  725. * @type {HTMLCanvasElement}
  726. * @readonly
  727. */
  728. canvas: {
  729. get: function () {
  730. return this._canvas;
  731. },
  732. },
  733. /**
  734. * The drawingBufferHeight of the underlying GL context.
  735. * @memberof Scene.prototype
  736. *
  737. * @type {number}
  738. * @readonly
  739. *
  740. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
  741. */
  742. drawingBufferHeight: {
  743. get: function () {
  744. return this._context.drawingBufferHeight;
  745. },
  746. },
  747. /**
  748. * The drawingBufferWidth of the underlying GL context.
  749. * @memberof Scene.prototype
  750. *
  751. * @type {number}
  752. * @readonly
  753. *
  754. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferWidth|drawingBufferWidth}
  755. */
  756. drawingBufferWidth: {
  757. get: function () {
  758. return this._context.drawingBufferWidth;
  759. },
  760. },
  761. /**
  762. * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one.
  763. * @memberof Scene.prototype
  764. *
  765. * @type {number}
  766. * @readonly
  767. *
  768. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>ALIASED_LINE_WIDTH_RANGE</code>.
  769. */
  770. maximumAliasedLineWidth: {
  771. get: function () {
  772. return ContextLimits.maximumAliasedLineWidth;
  773. },
  774. },
  775. /**
  776. * The maximum length in pixels of one edge of a cube map, supported by this WebGL implementation. It will be at least 16.
  777. * @memberof Scene.prototype
  778. *
  779. * @type {number}
  780. * @readonly
  781. *
  782. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>GL_MAX_CUBE_MAP_TEXTURE_SIZE</code>.
  783. */
  784. maximumCubeMapSize: {
  785. get: function () {
  786. return ContextLimits.maximumCubeMapSize;
  787. },
  788. },
  789. /**
  790. * Returns <code>true</code> if the {@link Scene#pickPosition} function is supported.
  791. * @memberof Scene.prototype
  792. *
  793. * @type {boolean}
  794. * @readonly
  795. *
  796. * @see Scene#pickPosition
  797. */
  798. pickPositionSupported: {
  799. get: function () {
  800. return this._context.depthTexture;
  801. },
  802. },
  803. /**
  804. * Returns <code>true</code> if the {@link Scene#sampleHeight} and {@link Scene#sampleHeightMostDetailed} functions are supported.
  805. * @memberof Scene.prototype
  806. *
  807. * @type {boolean}
  808. * @readonly
  809. *
  810. * @see Scene#sampleHeight
  811. * @see Scene#sampleHeightMostDetailed
  812. */
  813. sampleHeightSupported: {
  814. get: function () {
  815. return this._context.depthTexture;
  816. },
  817. },
  818. /**
  819. * Returns <code>true</code> if the {@link Scene#clampToHeight} and {@link Scene#clampToHeightMostDetailed} functions are supported.
  820. * @memberof Scene.prototype
  821. *
  822. * @type {boolean}
  823. * @readonly
  824. *
  825. * @see Scene#clampToHeight
  826. * @see Scene#clampToHeightMostDetailed
  827. */
  828. clampToHeightSupported: {
  829. get: function () {
  830. return this._context.depthTexture;
  831. },
  832. },
  833. /**
  834. * Returns <code>true</code> if the {@link Scene#invertClassification} is supported.
  835. * @memberof Scene.prototype
  836. *
  837. * @type {boolean}
  838. * @readonly
  839. *
  840. * @see Scene#invertClassification
  841. */
  842. invertClassificationSupported: {
  843. get: function () {
  844. return this._context.depthTexture;
  845. },
  846. },
  847. /**
  848. * Returns <code>true</code> if specular environment maps are supported.
  849. * @memberof Scene.prototype
  850. *
  851. * @type {boolean}
  852. * @readonly
  853. *
  854. * @see Scene#specularEnvironmentMaps
  855. */
  856. specularEnvironmentMapsSupported: {
  857. get: function () {
  858. return SpecularEnvironmentCubeMap.isSupported(this._context);
  859. },
  860. },
  861. /**
  862. * The ellipsoid. If not specified, the default ellipsoid is used.
  863. * @memberof Scene.prototype
  864. *
  865. * @type {Ellipsoid}
  866. * @readonly
  867. */
  868. ellipsoid: {
  869. get: function () {
  870. return this._ellipsoid;
  871. },
  872. },
  873. /**
  874. * Gets or sets the depth-test ellipsoid.
  875. * @memberof Scene.prototype
  876. *
  877. * @type {Globe}
  878. */
  879. globe: {
  880. get: function () {
  881. return this._globe;
  882. },
  883. set: function (globe) {
  884. this._globe = this._globe && this._globe.destroy();
  885. this._globe = globe;
  886. updateGlobeListeners(this, globe);
  887. },
  888. },
  889. /**
  890. * Gets the collection of primitives.
  891. * @memberof Scene.prototype
  892. *
  893. * @type {PrimitiveCollection}
  894. * @readonly
  895. */
  896. primitives: {
  897. get: function () {
  898. return this._primitives;
  899. },
  900. },
  901. /**
  902. * Gets the collection of ground primitives.
  903. * @memberof Scene.prototype
  904. *
  905. * @type {PrimitiveCollection}
  906. * @readonly
  907. */
  908. groundPrimitives: {
  909. get: function () {
  910. return this._groundPrimitives;
  911. },
  912. },
  913. /**
  914. * Gets or sets the camera.
  915. * @memberof Scene.prototype
  916. *
  917. * @type {Camera}
  918. * @readonly
  919. */
  920. camera: {
  921. get: function () {
  922. return this._view.camera;
  923. },
  924. set: function (camera) {
  925. // For internal use only. Documentation is still @readonly.
  926. this._view.camera = camera;
  927. },
  928. },
  929. /**
  930. * Gets or sets the view.
  931. * @memberof Scene.prototype
  932. *
  933. * @type {View}
  934. * @readonly
  935. *
  936. * @private
  937. */
  938. view: {
  939. get: function () {
  940. return this._view;
  941. },
  942. set: function (view) {
  943. // For internal use only. Documentation is still @readonly.
  944. this._view = view;
  945. },
  946. },
  947. /**
  948. * Gets the default view.
  949. * @memberof Scene.prototype
  950. *
  951. * @type {View}
  952. * @readonly
  953. *
  954. * @private
  955. */
  956. defaultView: {
  957. get: function () {
  958. return this._defaultView;
  959. },
  960. },
  961. /**
  962. * Gets picking functions and state
  963. * @memberof Scene.prototype
  964. *
  965. * @type {Picking}
  966. * @readonly
  967. *
  968. * @private
  969. */
  970. picking: {
  971. get: function () {
  972. return this._picking;
  973. },
  974. },
  975. /**
  976. * Gets the controller for camera input handling.
  977. * @memberof Scene.prototype
  978. *
  979. * @type {ScreenSpaceCameraController}
  980. * @readonly
  981. */
  982. screenSpaceCameraController: {
  983. get: function () {
  984. return this._screenSpaceCameraController;
  985. },
  986. },
  987. /**
  988. * Get the map projection to use in 2D and Columbus View modes.
  989. * @memberof Scene.prototype
  990. *
  991. * @type {MapProjection}
  992. * @readonly
  993. *
  994. * @default new GeographicProjection()
  995. */
  996. mapProjection: {
  997. get: function () {
  998. return this._mapProjection;
  999. },
  1000. },
  1001. /**
  1002. * Gets the job scheduler
  1003. * @memberof Scene.prototype
  1004. * @type {JobScheduler}
  1005. * @readonly
  1006. *
  1007. * @private
  1008. */
  1009. jobScheduler: {
  1010. get: function () {
  1011. return this._jobScheduler;
  1012. },
  1013. },
  1014. /**
  1015. * Gets state information about the current scene. If called outside of a primitive's <code>update</code>
  1016. * function, the previous frame's state is returned.
  1017. * @memberof Scene.prototype
  1018. *
  1019. * @type {FrameState}
  1020. * @readonly
  1021. *
  1022. * @private
  1023. */
  1024. frameState: {
  1025. get: function () {
  1026. return this._frameState;
  1027. },
  1028. },
  1029. /**
  1030. * Gets the environment state.
  1031. * @memberof Scene.prototype
  1032. *
  1033. * @type {EnvironmentState}
  1034. * @readonly
  1035. *
  1036. * @private
  1037. */
  1038. environmentState: {
  1039. get: function () {
  1040. return this._environmentState;
  1041. },
  1042. },
  1043. /**
  1044. * Gets the collection of tweens taking place in the scene.
  1045. * @memberof Scene.prototype
  1046. *
  1047. * @type {TweenCollection}
  1048. * @readonly
  1049. *
  1050. * @private
  1051. */
  1052. tweens: {
  1053. get: function () {
  1054. return this._tweens;
  1055. },
  1056. },
  1057. /**
  1058. * Gets the collection of image layers that will be rendered on the globe.
  1059. * @memberof Scene.prototype
  1060. *
  1061. * @type {ImageryLayerCollection}
  1062. * @readonly
  1063. */
  1064. imageryLayers: {
  1065. get: function () {
  1066. if (!defined(this.globe)) {
  1067. return undefined;
  1068. }
  1069. return this.globe.imageryLayers;
  1070. },
  1071. },
  1072. /**
  1073. * The terrain provider providing surface geometry for the globe.
  1074. * @memberof Scene.prototype
  1075. *
  1076. * @type {TerrainProvider}
  1077. */
  1078. terrainProvider: {
  1079. get: function () {
  1080. if (!defined(this.globe)) {
  1081. return undefined;
  1082. }
  1083. return this.globe.terrainProvider;
  1084. },
  1085. set: function (terrainProvider) {
  1086. // Cancel any in-progress terrain update
  1087. this._removeTerrainProviderReadyListener =
  1088. this._removeTerrainProviderReadyListener &&
  1089. this._removeTerrainProviderReadyListener();
  1090. if (defined(this.globe)) {
  1091. this.globe.terrainProvider = terrainProvider;
  1092. }
  1093. },
  1094. },
  1095. /**
  1096. * Gets an event that's raised when the terrain provider is changed
  1097. * @memberof Scene.prototype
  1098. *
  1099. * @type {Event}
  1100. * @readonly
  1101. */
  1102. terrainProviderChanged: {
  1103. get: function () {
  1104. if (!defined(this.globe)) {
  1105. return undefined;
  1106. }
  1107. return this.globe.terrainProviderChanged;
  1108. },
  1109. },
  1110. /**
  1111. * Gets the event that will be raised before the scene is updated or rendered. Subscribers to the event
  1112. * receive the Scene instance as the first parameter and the current time as the second parameter.
  1113. * @memberof Scene.prototype
  1114. *
  1115. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1116. * @see Scene#postUpdate
  1117. * @see Scene#preRender
  1118. * @see Scene#postRender
  1119. *
  1120. * @type {Event}
  1121. * @readonly
  1122. */
  1123. preUpdate: {
  1124. get: function () {
  1125. return this._preUpdate;
  1126. },
  1127. },
  1128. /**
  1129. * Gets the event that will be raised immediately after the scene is updated and before the scene is rendered.
  1130. * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second
  1131. * parameter.
  1132. * @memberof Scene.prototype
  1133. *
  1134. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1135. * @see Scene#preUpdate
  1136. * @see Scene#preRender
  1137. * @see Scene#postRender
  1138. *
  1139. * @type {Event}
  1140. * @readonly
  1141. */
  1142. postUpdate: {
  1143. get: function () {
  1144. return this._postUpdate;
  1145. },
  1146. },
  1147. /**
  1148. * Gets the event that will be raised when an error is thrown inside the <code>render</code> function.
  1149. * The Scene instance and the thrown error are the only two parameters passed to the event handler.
  1150. * By default, errors are not rethrown after this event is raised, but that can be changed by setting
  1151. * the <code>rethrowRenderErrors</code> property.
  1152. * @memberof Scene.prototype
  1153. *
  1154. * @type {Event}
  1155. * @readonly
  1156. */
  1157. renderError: {
  1158. get: function () {
  1159. return this._renderError;
  1160. },
  1161. },
  1162. /**
  1163. * Gets the event that will be raised after the scene is updated and immediately before the scene is rendered.
  1164. * Subscribers to the event receive the Scene instance as the first parameter and the current time as the second
  1165. * parameter.
  1166. * @memberof Scene.prototype
  1167. *
  1168. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1169. * @see Scene#preUpdate
  1170. * @see Scene#postUpdate
  1171. * @see Scene#postRender
  1172. *
  1173. * @type {Event}
  1174. * @readonly
  1175. */
  1176. preRender: {
  1177. get: function () {
  1178. return this._preRender;
  1179. },
  1180. },
  1181. /**
  1182. * Gets the event that will be raised immediately after the scene is rendered. Subscribers to the event
  1183. * receive the Scene instance as the first parameter and the current time as the second parameter.
  1184. * @memberof Scene.prototype
  1185. *
  1186. * @see {@link https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/|Improving Performance with Explicit Rendering}
  1187. * @see Scene#preUpdate
  1188. * @see Scene#postUpdate
  1189. * @see Scene#postRender
  1190. *
  1191. * @type {Event}
  1192. * @readonly
  1193. */
  1194. postRender: {
  1195. get: function () {
  1196. return this._postRender;
  1197. },
  1198. },
  1199. /**
  1200. * Gets the simulation time when the scene was last rendered. Returns <code>undefined</code>
  1201. * if the scene has not yet been rendered.
  1202. * @memberof Scene.prototype
  1203. *
  1204. * @type {JulianDate | undefined}
  1205. * @readonly
  1206. */
  1207. lastRenderTime: {
  1208. get: function () {
  1209. return this._lastRenderTime;
  1210. },
  1211. },
  1212. /**
  1213. * @memberof Scene.prototype
  1214. * @private
  1215. * @readonly
  1216. */
  1217. context: {
  1218. get: function () {
  1219. return this._context;
  1220. },
  1221. },
  1222. /**
  1223. * This property is for debugging only; it is not for production use.
  1224. * <p>
  1225. * When {@link Scene.debugShowFrustums} is <code>true</code>, this contains
  1226. * properties with statistics about the number of command execute per frustum.
  1227. * <code>totalCommands</code> is the total number of commands executed, ignoring
  1228. * overlap. <code>commandsInFrustums</code> is an array with the number of times
  1229. * commands are executed redundantly, e.g., how many commands overlap two or
  1230. * three frustums.
  1231. * </p>
  1232. *
  1233. * @memberof Scene.prototype
  1234. *
  1235. * @type {object | undefined}
  1236. * @readonly
  1237. *
  1238. * @default undefined
  1239. */
  1240. debugFrustumStatistics: {
  1241. get: function () {
  1242. return this._view.debugFrustumStatistics;
  1243. },
  1244. },
  1245. /**
  1246. * Gets whether or not the scene is optimized for 3D only viewing.
  1247. * @memberof Scene.prototype
  1248. * @type {boolean}
  1249. * @readonly
  1250. */
  1251. scene3DOnly: {
  1252. get: function () {
  1253. return this._frameState.scene3DOnly;
  1254. },
  1255. },
  1256. /**
  1257. * Gets whether or not the scene has order independent translucency enabled.
  1258. * Note that this only reflects the original construction option, and there are
  1259. * other factors that could prevent OIT from functioning on a given system configuration.
  1260. * @memberof Scene.prototype
  1261. * @type {boolean}
  1262. * @readonly
  1263. */
  1264. orderIndependentTranslucency: {
  1265. get: function () {
  1266. return this._useOIT;
  1267. },
  1268. },
  1269. /**
  1270. * Gets the unique identifier for this scene.
  1271. * @memberof Scene.prototype
  1272. * @type {string}
  1273. * @readonly
  1274. */
  1275. id: {
  1276. get: function () {
  1277. return this._id;
  1278. },
  1279. },
  1280. /**
  1281. * Gets or sets the current mode of the scene.
  1282. * @memberof Scene.prototype
  1283. * @type {SceneMode}
  1284. * @default {@link SceneMode.SCENE3D}
  1285. */
  1286. mode: {
  1287. get: function () {
  1288. return this._mode;
  1289. },
  1290. set: function (value) {
  1291. //>>includeStart('debug', pragmas.debug);
  1292. if (this.scene3DOnly && value !== SceneMode.SCENE3D) {
  1293. throw new DeveloperError(
  1294. "Only SceneMode.SCENE3D is valid when scene3DOnly is true.",
  1295. );
  1296. }
  1297. //>>includeEnd('debug');
  1298. if (value === SceneMode.SCENE2D) {
  1299. this.morphTo2D(0);
  1300. } else if (value === SceneMode.SCENE3D) {
  1301. this.morphTo3D(0);
  1302. } else if (value === SceneMode.COLUMBUS_VIEW) {
  1303. this.morphToColumbusView(0);
  1304. //>>includeStart('debug', pragmas.debug);
  1305. } else {
  1306. throw new DeveloperError(
  1307. "value must be a valid SceneMode enumeration.",
  1308. );
  1309. //>>includeEnd('debug');
  1310. }
  1311. this._mode = value;
  1312. },
  1313. },
  1314. /**
  1315. * Gets the number of frustums used in the last frame.
  1316. * @memberof Scene.prototype
  1317. * @type {FrustumCommands[]}
  1318. *
  1319. * @private
  1320. */
  1321. frustumCommandsList: {
  1322. get: function () {
  1323. return this._view.frustumCommandsList;
  1324. },
  1325. },
  1326. /**
  1327. * Gets the number of frustums used in the last frame.
  1328. * @memberof Scene.prototype
  1329. * @type {number}
  1330. *
  1331. * @private
  1332. */
  1333. numberOfFrustums: {
  1334. get: function () {
  1335. return this._view.frustumCommandsList.length;
  1336. },
  1337. },
  1338. /**
  1339. * When <code>true</code>, splits the scene into two viewports with steroscopic views for the left and right eyes.
  1340. * Used for cardboard and WebVR.
  1341. * @memberof Scene.prototype
  1342. * @type {boolean}
  1343. * @default false
  1344. */
  1345. useWebVR: {
  1346. get: function () {
  1347. return this._useWebVR;
  1348. },
  1349. set: function (value) {
  1350. //>>includeStart('debug', pragmas.debug);
  1351. if (this.camera.frustum instanceof OrthographicFrustum) {
  1352. throw new DeveloperError(
  1353. "VR is unsupported with an orthographic projection.",
  1354. );
  1355. }
  1356. //>>includeEnd('debug');
  1357. this._useWebVR = value;
  1358. if (this._useWebVR) {
  1359. this._frameState.creditDisplay.container.style.visibility = "hidden";
  1360. this._cameraVR = new Camera(this);
  1361. if (!defined(this._deviceOrientationCameraController)) {
  1362. this._deviceOrientationCameraController =
  1363. new DeviceOrientationCameraController(this);
  1364. }
  1365. this._aspectRatioVR = this.camera.frustum.aspectRatio;
  1366. } else {
  1367. this._frameState.creditDisplay.container.style.visibility = "visible";
  1368. this._cameraVR = undefined;
  1369. this._deviceOrientationCameraController =
  1370. this._deviceOrientationCameraController &&
  1371. !this._deviceOrientationCameraController.isDestroyed() &&
  1372. this._deviceOrientationCameraController.destroy();
  1373. this.camera.frustum.aspectRatio = this._aspectRatioVR;
  1374. this.camera.frustum.xOffset = 0.0;
  1375. }
  1376. },
  1377. },
  1378. /**
  1379. * Determines if the 2D map is rotatable or can be scrolled infinitely in the horizontal direction.
  1380. * @memberof Scene.prototype
  1381. * @type {MapMode2D}
  1382. * @readonly
  1383. */
  1384. mapMode2D: {
  1385. get: function () {
  1386. return this._mapMode2D;
  1387. },
  1388. },
  1389. /**
  1390. * Gets or sets the position of the splitter within the viewport. Valid values are between 0.0 and 1.0.
  1391. * @memberof Scene.prototype
  1392. *
  1393. * @type {number}
  1394. */
  1395. splitPosition: {
  1396. get: function () {
  1397. return this._frameState.splitPosition;
  1398. },
  1399. set: function (value) {
  1400. this._frameState.splitPosition = value;
  1401. },
  1402. },
  1403. /**
  1404. * The distance from the camera at which to disable the depth test of billboards, labels and points
  1405. * to, for example, prevent clipping against terrain. When set to zero, the depth test should always
  1406. * be applied. When less than zero, the depth test should never be applied. Setting the disableDepthTestDistance
  1407. * property of a billboard, label or point will override this value.
  1408. * @memberof Scene.prototype
  1409. * @type {number}
  1410. * @default 0.0
  1411. */
  1412. minimumDisableDepthTestDistance: {
  1413. get: function () {
  1414. return this._minimumDisableDepthTestDistance;
  1415. },
  1416. set: function (value) {
  1417. //>>includeStart('debug', pragmas.debug);
  1418. if (!defined(value) || value < 0.0) {
  1419. throw new DeveloperError(
  1420. "minimumDisableDepthTestDistance must be greater than or equal to 0.0.",
  1421. );
  1422. }
  1423. //>>includeEnd('debug');
  1424. this._minimumDisableDepthTestDistance = value;
  1425. },
  1426. },
  1427. /**
  1428. * Whether or not to use a logarithmic depth buffer. Enabling this option will allow for less frustums in the multi-frustum,
  1429. * increasing performance. This property relies on fragmentDepth being supported.
  1430. * @memberof Scene.prototype
  1431. * @type {boolean}
  1432. */
  1433. logarithmicDepthBuffer: {
  1434. get: function () {
  1435. return this._logDepthBuffer;
  1436. },
  1437. set: function (value) {
  1438. value = this._context.fragmentDepth && value;
  1439. if (this._logDepthBuffer !== value) {
  1440. this._logDepthBuffer = value;
  1441. this._logDepthBufferDirty = true;
  1442. }
  1443. },
  1444. },
  1445. /**
  1446. * The value used for gamma correction. This is only used when rendering with high dynamic range.
  1447. * @memberof Scene.prototype
  1448. * @type {number}
  1449. * @default 2.2
  1450. */
  1451. gamma: {
  1452. get: function () {
  1453. return this._context.uniformState.gamma;
  1454. },
  1455. set: function (value) {
  1456. this._context.uniformState.gamma = value;
  1457. },
  1458. },
  1459. /**
  1460. * Whether or not to use high dynamic range rendering.
  1461. * @memberof Scene.prototype
  1462. * @type {boolean}
  1463. * @default false
  1464. */
  1465. highDynamicRange: {
  1466. get: function () {
  1467. return this._hdr;
  1468. },
  1469. set: function (value) {
  1470. const context = this._context;
  1471. const hdr =
  1472. value &&
  1473. context.depthTexture &&
  1474. (context.colorBufferFloat || context.colorBufferHalfFloat);
  1475. this._hdrDirty = hdr !== this._hdr;
  1476. this._hdr = hdr;
  1477. },
  1478. },
  1479. /**
  1480. * Whether or not high dynamic range rendering is supported.
  1481. * @memberof Scene.prototype
  1482. * @type {boolean}
  1483. * @readonly
  1484. * @default true
  1485. */
  1486. highDynamicRangeSupported: {
  1487. get: function () {
  1488. const context = this._context;
  1489. return (
  1490. context.depthTexture &&
  1491. (context.colorBufferFloat || context.colorBufferHalfFloat)
  1492. );
  1493. },
  1494. },
  1495. /**
  1496. * Whether or not the camera is underneath the globe.
  1497. * @memberof Scene.prototype
  1498. * @type {boolean}
  1499. * @readonly
  1500. * @default false
  1501. */
  1502. cameraUnderground: {
  1503. get: function () {
  1504. return this._cameraUnderground;
  1505. },
  1506. },
  1507. /**
  1508. * The sample rate of multisample antialiasing (values greater than 1 enable MSAA).
  1509. * @memberof Scene.prototype
  1510. * @type {number}
  1511. * @default 4
  1512. */
  1513. msaaSamples: {
  1514. get: function () {
  1515. return this._msaaSamples;
  1516. },
  1517. set: function (value) {
  1518. value = Math.min(value, ContextLimits.maximumSamples);
  1519. this._msaaSamples = value;
  1520. },
  1521. },
  1522. /**
  1523. * Returns <code>true</code> if the Scene's context supports MSAA.
  1524. * @memberof Scene.prototype
  1525. * @type {boolean}
  1526. * @readonly
  1527. */
  1528. msaaSupported: {
  1529. get: function () {
  1530. return this._context.msaa;
  1531. },
  1532. },
  1533. /**
  1534. * Ratio between a pixel and a density-independent pixel. Provides a standard unit of
  1535. * measure for real pixel measurements appropriate to a particular device.
  1536. *
  1537. * @memberof Scene.prototype
  1538. * @type {number}
  1539. * @default 1.0
  1540. * @private
  1541. */
  1542. pixelRatio: {
  1543. get: function () {
  1544. return this._frameState.pixelRatio;
  1545. },
  1546. set: function (value) {
  1547. this._frameState.pixelRatio = value;
  1548. },
  1549. },
  1550. /**
  1551. * @private
  1552. */
  1553. opaqueFrustumNearOffset: {
  1554. get: function () {
  1555. return 0.9999;
  1556. },
  1557. },
  1558. /**
  1559. * @private
  1560. */
  1561. globeHeight: {
  1562. get: function () {
  1563. return this._globeHeight;
  1564. },
  1565. },
  1566. });
  1567. /**
  1568. * Determines if a compressed texture format is supported.
  1569. * @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.
  1570. * @return {boolean} Whether or not the format is supported.
  1571. */
  1572. Scene.prototype.getCompressedTextureFormatSupported = function (format) {
  1573. const context = this.context;
  1574. return (
  1575. ((format === "WEBGL_compressed_texture_s3tc" || format === "s3tc") &&
  1576. context.s3tc) ||
  1577. ((format === "WEBGL_compressed_texture_pvrtc" || format === "pvrtc") &&
  1578. context.pvrtc) ||
  1579. ((format === "WEBGL_compressed_texture_etc" || format === "etc") &&
  1580. context.etc) ||
  1581. ((format === "WEBGL_compressed_texture_etc1" || format === "etc1") &&
  1582. context.etc1) ||
  1583. ((format === "WEBGL_compressed_texture_astc" || format === "astc") &&
  1584. context.astc) ||
  1585. ((format === "EXT_texture_compression_bptc" || format === "bc7") &&
  1586. context.bc7)
  1587. );
  1588. };
  1589. function pickedMetadataInfoChanged(command, frameState) {
  1590. const oldPickedMetadataInfo = command.pickedMetadataInfo;
  1591. const newPickedMetadataInfo = frameState.pickedMetadataInfo;
  1592. if (oldPickedMetadataInfo?.schemaId !== newPickedMetadataInfo?.schemaId) {
  1593. return true;
  1594. }
  1595. if (oldPickedMetadataInfo?.className !== newPickedMetadataInfo?.className) {
  1596. return true;
  1597. }
  1598. if (
  1599. oldPickedMetadataInfo?.propertyName !== newPickedMetadataInfo?.propertyName
  1600. ) {
  1601. return true;
  1602. }
  1603. return false;
  1604. }
  1605. function updateDerivedCommands(scene, command, shadowsDirty) {
  1606. const frameState = scene._frameState;
  1607. const context = scene._context;
  1608. const oit = scene._view.oit;
  1609. const { lightShadowMaps, lightShadowsEnabled } = frameState.shadowState;
  1610. let derivedCommands = command.derivedCommands;
  1611. if (defined(command.pickId)) {
  1612. derivedCommands.picking = DerivedCommand.createPickDerivedCommand(
  1613. scene,
  1614. command,
  1615. context,
  1616. derivedCommands.picking,
  1617. );
  1618. }
  1619. if (frameState.pickingMetadata && command.pickMetadataAllowed) {
  1620. command.pickedMetadataInfo = frameState.pickedMetadataInfo;
  1621. if (defined(command.pickedMetadataInfo)) {
  1622. derivedCommands.pickingMetadata =
  1623. DerivedCommand.createPickMetadataDerivedCommand(
  1624. scene,
  1625. command,
  1626. context,
  1627. derivedCommands.pickingMetadata,
  1628. );
  1629. }
  1630. }
  1631. if (!command.pickOnly) {
  1632. derivedCommands.depth = DerivedCommand.createDepthOnlyDerivedCommand(
  1633. scene,
  1634. command,
  1635. context,
  1636. derivedCommands.depth,
  1637. );
  1638. }
  1639. derivedCommands.originalCommand = command;
  1640. if (scene._hdr) {
  1641. derivedCommands.hdr = DerivedCommand.createHdrCommand(
  1642. command,
  1643. context,
  1644. derivedCommands.hdr,
  1645. );
  1646. command = derivedCommands.hdr.command;
  1647. derivedCommands = command.derivedCommands;
  1648. }
  1649. if (lightShadowsEnabled && command.receiveShadows) {
  1650. derivedCommands.shadows = ShadowMap.createReceiveDerivedCommand(
  1651. lightShadowMaps,
  1652. command,
  1653. shadowsDirty,
  1654. context,
  1655. derivedCommands.shadows,
  1656. );
  1657. }
  1658. if (command.pass === Pass.TRANSLUCENT && defined(oit) && oit.isSupported()) {
  1659. if (lightShadowsEnabled && command.receiveShadows) {
  1660. derivedCommands.oit = defined(derivedCommands.oit)
  1661. ? derivedCommands.oit
  1662. : {};
  1663. derivedCommands.oit.shadows = oit.createDerivedCommands(
  1664. derivedCommands.shadows.receiveCommand,
  1665. context,
  1666. derivedCommands.oit.shadows,
  1667. );
  1668. } else {
  1669. derivedCommands.oit = oit.createDerivedCommands(
  1670. command,
  1671. context,
  1672. derivedCommands.oit,
  1673. );
  1674. }
  1675. }
  1676. }
  1677. /**
  1678. * @private
  1679. */
  1680. Scene.prototype.updateDerivedCommands = function (command) {
  1681. const { derivedCommands } = command;
  1682. if (!defined(derivedCommands)) {
  1683. // Is not a DrawCommand
  1684. return;
  1685. }
  1686. const frameState = this._frameState;
  1687. const { shadowState, useLogDepth } = this._frameState;
  1688. const context = this._context;
  1689. // Update derived commands when any shadow maps become dirty
  1690. let shadowsDirty = false;
  1691. const lastDirtyTime = shadowState.lastDirtyTime;
  1692. if (command.lastDirtyTime !== lastDirtyTime) {
  1693. command.lastDirtyTime = lastDirtyTime;
  1694. command.dirty = true;
  1695. shadowsDirty = true;
  1696. }
  1697. const useHdr = this._hdr;
  1698. const hasLogDepthDerivedCommands = defined(derivedCommands.logDepth);
  1699. const hasHdrCommands = defined(derivedCommands.hdr);
  1700. const hasDerivedCommands = defined(derivedCommands.originalCommand);
  1701. const needsLogDepthDerivedCommands =
  1702. useLogDepth && !hasLogDepthDerivedCommands;
  1703. const needsHdrCommands = useHdr && !hasHdrCommands;
  1704. const needsDerivedCommands = (!useLogDepth || !useHdr) && !hasDerivedCommands;
  1705. const needsUpdateForMetadataPicking =
  1706. frameState.pickingMetadata &&
  1707. pickedMetadataInfoChanged(command, frameState);
  1708. command.dirty =
  1709. command.dirty ||
  1710. needsLogDepthDerivedCommands ||
  1711. needsHdrCommands ||
  1712. needsDerivedCommands ||
  1713. needsUpdateForMetadataPicking;
  1714. if (!command.dirty) {
  1715. return;
  1716. }
  1717. command.dirty = false;
  1718. const { shadowsEnabled, shadowMaps } = shadowState;
  1719. if (shadowsEnabled && command.castShadows) {
  1720. derivedCommands.shadows = ShadowMap.createCastDerivedCommand(
  1721. shadowMaps,
  1722. command,
  1723. shadowsDirty,
  1724. context,
  1725. derivedCommands.shadows,
  1726. );
  1727. }
  1728. if (hasLogDepthDerivedCommands || needsLogDepthDerivedCommands) {
  1729. derivedCommands.logDepth = DerivedCommand.createLogDepthCommand(
  1730. command,
  1731. context,
  1732. derivedCommands.logDepth,
  1733. );
  1734. updateDerivedCommands(this, derivedCommands.logDepth.command, shadowsDirty);
  1735. }
  1736. if (hasDerivedCommands || needsDerivedCommands) {
  1737. updateDerivedCommands(this, command, shadowsDirty);
  1738. }
  1739. };
  1740. const renderTilesetPassState = new Cesium3DTilePassState({
  1741. pass: Cesium3DTilePass.RENDER,
  1742. });
  1743. const preloadTilesetPassState = new Cesium3DTilePassState({
  1744. pass: Cesium3DTilePass.PRELOAD,
  1745. });
  1746. const preloadFlightTilesetPassState = new Cesium3DTilePassState({
  1747. pass: Cesium3DTilePass.PRELOAD_FLIGHT,
  1748. });
  1749. const requestRenderModeDeferCheckPassState = new Cesium3DTilePassState({
  1750. pass: Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK,
  1751. });
  1752. const scratchOccluderBoundingSphere = new BoundingSphere();
  1753. let scratchOccluder;
  1754. /**
  1755. * Get the central body occluder for the scene.
  1756. * Assumes only one central body occluder, the top-level globe.
  1757. *
  1758. * @param {Scene} scene
  1759. * @returns {Occluder|undefined}
  1760. *
  1761. * @private
  1762. */
  1763. function getOccluder(scene) {
  1764. if (
  1765. scene._mode !== SceneMode.SCENE3D ||
  1766. !scene.globe?.show ||
  1767. scene._cameraUnderground ||
  1768. scene._globeTranslucencyState.translucent
  1769. ) {
  1770. return undefined;
  1771. }
  1772. scratchOccluderBoundingSphere.radius =
  1773. scene.ellipsoid.minimumRadius + scene.frameState.minimumTerrainHeight;
  1774. scratchOccluder = Occluder.fromBoundingSphere(
  1775. scratchOccluderBoundingSphere,
  1776. scene.camera.positionWC,
  1777. scratchOccluder,
  1778. );
  1779. return scratchOccluder;
  1780. }
  1781. /**
  1782. * @private
  1783. * @param {FrameState.Passes} passes
  1784. */
  1785. Scene.prototype.clearPasses = function (passes) {
  1786. passes.render = false;
  1787. passes.pick = false;
  1788. passes.pickVoxel = false;
  1789. passes.depth = false;
  1790. passes.postProcess = false;
  1791. passes.offscreen = false;
  1792. };
  1793. function updateFrameNumber(scene, frameNumber, time) {
  1794. const frameState = scene._frameState;
  1795. frameState.frameNumber = frameNumber;
  1796. frameState.time = JulianDate.clone(time, frameState.time);
  1797. }
  1798. /**
  1799. * @private
  1800. */
  1801. Scene.prototype.updateFrameState = function () {
  1802. const camera = this.camera;
  1803. const frameState = this._frameState;
  1804. frameState.commandList.length = 0;
  1805. frameState.shadowMaps.length = 0;
  1806. frameState.brdfLutGenerator = this._brdfLutGenerator;
  1807. frameState.environmentMap = this.skyBox && this.skyBox._cubeMap;
  1808. frameState.mode = this._mode;
  1809. frameState.morphTime = this.morphTime;
  1810. frameState.mapProjection = this.mapProjection;
  1811. frameState.camera = camera;
  1812. frameState.cullingVolume = camera.frustum.computeCullingVolume(
  1813. camera.positionWC,
  1814. camera.directionWC,
  1815. camera.upWC,
  1816. );
  1817. frameState.occluder = getOccluder(this);
  1818. frameState.minimumTerrainHeight = 0.0;
  1819. frameState.minimumDisableDepthTestDistance =
  1820. this._minimumDisableDepthTestDistance;
  1821. frameState.invertClassification = this.invertClassification;
  1822. frameState.useLogDepth =
  1823. this._logDepthBuffer &&
  1824. !(
  1825. this.camera.frustum instanceof OrthographicFrustum ||
  1826. this.camera.frustum instanceof OrthographicOffCenterFrustum
  1827. );
  1828. frameState.light = this.light;
  1829. frameState.cameraUnderground = this._cameraUnderground;
  1830. frameState.globeTranslucencyState = this._globeTranslucencyState;
  1831. const { globe } = this;
  1832. if (defined(globe) && globe._terrainExaggerationChanged) {
  1833. // Honor a user-set value for the old deprecated globe.terrainExaggeration.
  1834. // This can be removed when Globe.terrainExaggeration is removed.
  1835. this.verticalExaggeration = globe._terrainExaggeration;
  1836. this.verticalExaggerationRelativeHeight =
  1837. globe._terrainExaggerationRelativeHeight;
  1838. globe._terrainExaggerationChanged = false;
  1839. }
  1840. frameState.verticalExaggeration = this.verticalExaggeration;
  1841. frameState.verticalExaggerationRelativeHeight =
  1842. this.verticalExaggerationRelativeHeight;
  1843. if (
  1844. defined(this._specularEnvironmentCubeMap) &&
  1845. this._specularEnvironmentCubeMap.ready
  1846. ) {
  1847. frameState.specularEnvironmentMaps =
  1848. this._specularEnvironmentCubeMap.texture;
  1849. frameState.specularEnvironmentMapsMaximumLOD =
  1850. this._specularEnvironmentCubeMap.maximumMipmapLevel;
  1851. } else {
  1852. frameState.specularEnvironmentMaps = undefined;
  1853. frameState.specularEnvironmentMapsMaximumLOD = undefined;
  1854. }
  1855. frameState.sphericalHarmonicCoefficients = this.sphericalHarmonicCoefficients;
  1856. this._actualInvertClassificationColor = Color.clone(
  1857. this.invertClassificationColor,
  1858. this._actualInvertClassificationColor,
  1859. );
  1860. if (!InvertClassification.isTranslucencySupported(this._context)) {
  1861. this._actualInvertClassificationColor.alpha = 1.0;
  1862. }
  1863. frameState.invertClassificationColor = this._actualInvertClassificationColor;
  1864. if (defined(this.globe)) {
  1865. frameState.maximumScreenSpaceError = this.globe.maximumScreenSpaceError;
  1866. } else {
  1867. frameState.maximumScreenSpaceError = 2;
  1868. }
  1869. this.clearPasses(frameState.passes);
  1870. frameState.tilesetPassState = undefined;
  1871. };
  1872. /**
  1873. * Check whether a draw command will render anything visible in the current Scene,
  1874. * based on its bounding volume.
  1875. *
  1876. * @param {CullingVolume} cullingVolume The culling volume of the current Scene.
  1877. * @param {DrawCommand} [command] The draw command
  1878. * @param {Occluder} [occluder] An occluder that may be in front of the command's bounding volume.
  1879. * @returns {boolean} <code>true</code> if the command's bounding volume is visible in the scene.
  1880. *
  1881. * @private
  1882. */
  1883. Scene.prototype.isVisible = function (cullingVolume, command, occluder) {
  1884. if (!defined(command)) {
  1885. return false;
  1886. }
  1887. const { boundingVolume } = command;
  1888. if (!defined(boundingVolume) || !command.cull) {
  1889. return true;
  1890. }
  1891. if (cullingVolume.computeVisibility(boundingVolume) === Intersect.OUTSIDE) {
  1892. return false;
  1893. }
  1894. return (
  1895. !defined(occluder) ||
  1896. !command.occlude ||
  1897. !boundingVolume.isOccluded(occluder)
  1898. );
  1899. };
  1900. let transformFrom2D = new Matrix4(
  1901. 0.0,
  1902. 0.0,
  1903. 1.0,
  1904. 0.0,
  1905. 1.0,
  1906. 0.0,
  1907. 0.0,
  1908. 0.0,
  1909. 0.0,
  1910. 1.0,
  1911. 0.0,
  1912. 0.0,
  1913. 0.0,
  1914. 0.0,
  1915. 0.0,
  1916. 1.0,
  1917. );
  1918. transformFrom2D = Matrix4.inverseTransformation(
  1919. transformFrom2D,
  1920. transformFrom2D,
  1921. );
  1922. /**
  1923. * Debug code to draw bounding volume for command. Not optimized!
  1924. * Assumes bounding volume is a bounding sphere or box.
  1925. *
  1926. * @param {DrawCommand} command The draw command for which to render the bounding volume.
  1927. * @param {Scene} scene The scene.
  1928. * @param {PassState} passState The state for the current render pass.
  1929. * @param {Framebuffer} debugFramebuffer The framebuffer where the bounding volume will be rendered.
  1930. *
  1931. * @private
  1932. */
  1933. function debugShowBoundingVolume(command, scene, passState, debugFramebuffer) {
  1934. const frameState = scene._frameState;
  1935. const context = frameState.context;
  1936. const boundingVolume = command.boundingVolume;
  1937. if (defined(scene._debugVolume)) {
  1938. scene._debugVolume.destroy();
  1939. }
  1940. let center = Cartesian3.clone(boundingVolume.center);
  1941. if (frameState.mode !== SceneMode.SCENE3D) {
  1942. center = Matrix4.multiplyByPoint(transformFrom2D, center, center);
  1943. const projection = frameState.mapProjection;
  1944. const centerCartographic = projection.unproject(center);
  1945. center = projection.ellipsoid.cartographicToCartesian(centerCartographic);
  1946. }
  1947. let geometry;
  1948. let modelMatrix;
  1949. const { radius } = boundingVolume;
  1950. if (defined(radius)) {
  1951. geometry = EllipsoidGeometry.createGeometry(
  1952. new EllipsoidGeometry({
  1953. radii: new Cartesian3(radius, radius, radius),
  1954. vertexFormat: PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
  1955. }),
  1956. );
  1957. modelMatrix = Matrix4.fromTranslation(center);
  1958. } else {
  1959. geometry = BoxGeometry.createGeometry(
  1960. BoxGeometry.fromDimensions({
  1961. dimensions: new Cartesian3(2.0, 2.0, 2.0),
  1962. vertexFormat: PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
  1963. }),
  1964. );
  1965. modelMatrix = Matrix4.fromRotationTranslation(
  1966. boundingVolume.halfAxes,
  1967. center,
  1968. new Matrix4(),
  1969. );
  1970. }
  1971. scene._debugVolume = new Primitive({
  1972. geometryInstances: new GeometryInstance({
  1973. geometry: GeometryPipeline.toWireframe(geometry),
  1974. modelMatrix: modelMatrix,
  1975. attributes: {
  1976. color: new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0),
  1977. },
  1978. }),
  1979. appearance: new PerInstanceColorAppearance({
  1980. flat: true,
  1981. translucent: false,
  1982. }),
  1983. asynchronous: false,
  1984. });
  1985. const savedCommandList = frameState.commandList;
  1986. const commandList = (frameState.commandList = []);
  1987. scene._debugVolume.update(frameState);
  1988. command = commandList[0];
  1989. if (frameState.useLogDepth) {
  1990. const logDepth = DerivedCommand.createLogDepthCommand(command, context);
  1991. command = logDepth.command;
  1992. }
  1993. let framebuffer;
  1994. if (defined(debugFramebuffer)) {
  1995. framebuffer = passState.framebuffer;
  1996. passState.framebuffer = debugFramebuffer;
  1997. }
  1998. command.execute(context, passState);
  1999. if (defined(framebuffer)) {
  2000. passState.framebuffer = framebuffer;
  2001. }
  2002. frameState.commandList = savedCommandList;
  2003. }
  2004. /**
  2005. * Execute a single draw command, or one of its derived commands if appropriate for the current render state.
  2006. *
  2007. * @param {DrawCommand} command The command to execute.
  2008. * @param {Scene} scene The scene.
  2009. * @param {PassState} passState The state for the current render pass.
  2010. * @param {Framebuffer} debugFramebuffer The framebuffer where debug QCs will be rendered.
  2011. *
  2012. * @private
  2013. */
  2014. function executeCommand(command, scene, passState, debugFramebuffer) {
  2015. const frameState = scene._frameState;
  2016. const context = scene._context;
  2017. if (defined(scene.debugCommandFilter) && !scene.debugCommandFilter(command)) {
  2018. return;
  2019. }
  2020. if (command instanceof ClearCommand) {
  2021. command.execute(context, passState);
  2022. return;
  2023. }
  2024. if (command.debugShowBoundingVolume && defined(command.boundingVolume)) {
  2025. debugShowBoundingVolume(command, scene, passState, debugFramebuffer);
  2026. }
  2027. if (frameState.useLogDepth && defined(command.derivedCommands.logDepth)) {
  2028. command = command.derivedCommands.logDepth.command;
  2029. }
  2030. const passes = frameState.passes;
  2031. if (
  2032. !passes.pick &&
  2033. !passes.pickVoxel &&
  2034. !passes.depth &&
  2035. scene._hdr &&
  2036. defined(command.derivedCommands) &&
  2037. defined(command.derivedCommands.hdr)
  2038. ) {
  2039. command = command.derivedCommands.hdr.command;
  2040. }
  2041. if (passes.pick || passes.depth) {
  2042. if (passes.pick && !passes.depth) {
  2043. if (
  2044. frameState.pickingMetadata &&
  2045. defined(command.derivedCommands.pickingMetadata)
  2046. ) {
  2047. command = command.derivedCommands.pickingMetadata.pickMetadataCommand;
  2048. command.execute(context, passState);
  2049. return;
  2050. }
  2051. if (
  2052. !frameState.pickingMetadata &&
  2053. defined(command.derivedCommands.picking)
  2054. ) {
  2055. command = command.derivedCommands.picking.pickCommand;
  2056. command.execute(context, passState);
  2057. return;
  2058. }
  2059. } else if (defined(command.derivedCommands.depth)) {
  2060. command = command.derivedCommands.depth.depthOnlyCommand;
  2061. command.execute(context, passState);
  2062. return;
  2063. }
  2064. }
  2065. if (scene.debugShowCommands || scene.debugShowFrustums) {
  2066. scene._debugInspector.executeDebugShowFrustumsCommand(
  2067. scene,
  2068. command,
  2069. passState,
  2070. );
  2071. return;
  2072. }
  2073. if (
  2074. frameState.shadowState.lightShadowsEnabled &&
  2075. command.receiveShadows &&
  2076. defined(command.derivedCommands.shadows)
  2077. ) {
  2078. // If the command receives shadows, execute the derived shadows command.
  2079. // Some commands, such as OIT derived commands, do not have derived shadow commands themselves
  2080. // and instead shadowing is built-in. In this case execute the command regularly below.
  2081. command.derivedCommands.shadows.receiveCommand.execute(context, passState);
  2082. } else {
  2083. command.execute(context, passState);
  2084. }
  2085. }
  2086. /**
  2087. * Execute a single ID draw command, used to render information for picking.
  2088. *
  2089. * @param {DrawCommand} command The command to execute.
  2090. * @param {Scene} scene The scene.
  2091. * @param {PassState} passState The state for the current render pass.
  2092. *
  2093. * @private
  2094. */
  2095. function executeIdCommand(command, scene, passState) {
  2096. const { derivedCommands } = command;
  2097. if (!defined(derivedCommands)) {
  2098. return;
  2099. }
  2100. const frameState = scene._frameState;
  2101. const context = scene._context;
  2102. if (frameState.useLogDepth && defined(derivedCommands.logDepth)) {
  2103. command = derivedCommands.logDepth.command;
  2104. }
  2105. const { picking, pickingMetadata, depth } = command.derivedCommands;
  2106. if (defined(pickingMetadata)) {
  2107. command = derivedCommands.pickingMetadata.pickMetadataCommand;
  2108. command.execute(context, passState);
  2109. }
  2110. if (defined(picking)) {
  2111. command = picking.pickCommand;
  2112. command.execute(context, passState);
  2113. } else if (defined(depth)) {
  2114. command = depth.depthOnlyCommand;
  2115. command.execute(context, passState);
  2116. }
  2117. }
  2118. function backToFront(a, b, position) {
  2119. return (
  2120. b.boundingVolume.distanceSquaredTo(position) -
  2121. a.boundingVolume.distanceSquaredTo(position)
  2122. );
  2123. }
  2124. const scratchCart3 = new Cartesian3();
  2125. function distanceSquaredToCenter(center, position) {
  2126. const diff = Cartesian3.subtract(center, position, scratchCart3);
  2127. const distance = Math.max(0.0, Cartesian3.magnitude(diff));
  2128. return distance * distance;
  2129. }
  2130. function backToFrontSplats(a, b, position) {
  2131. const boxA = a.boundingVolume;
  2132. const boxB = b.boundingVolume;
  2133. return (
  2134. distanceSquaredToCenter(boxB.center, position) -
  2135. distanceSquaredToCenter(boxA.center, position)
  2136. );
  2137. }
  2138. function frontToBack(a, b, position) {
  2139. // When distances are equal equal favor sorting b before a. This gives render priority to commands later in the list.
  2140. return (
  2141. a.boundingVolume.distanceSquaredTo(position) -
  2142. b.boundingVolume.distanceSquaredTo(position) +
  2143. CesiumMath.EPSILON12
  2144. );
  2145. }
  2146. function executeTranslucentCommandsBackToFront(
  2147. scene,
  2148. executeFunction,
  2149. passState,
  2150. commands,
  2151. invertClassification,
  2152. ) {
  2153. mergeSort(commands, backToFront, scene.camera.positionWC);
  2154. if (defined(invertClassification)) {
  2155. executeFunction(invertClassification.unclassifiedCommand, scene, passState);
  2156. }
  2157. for (let i = 0; i < commands.length; ++i) {
  2158. executeFunction(commands[i], scene, passState);
  2159. }
  2160. }
  2161. function executeTranslucentCommandsFrontToBack(
  2162. scene,
  2163. executeFunction,
  2164. passState,
  2165. commands,
  2166. invertClassification,
  2167. ) {
  2168. mergeSort(commands, frontToBack, scene.camera.positionWC);
  2169. if (defined(invertClassification)) {
  2170. executeFunction(invertClassification.unclassifiedCommand, scene, passState);
  2171. }
  2172. for (let i = 0; i < commands.length; ++i) {
  2173. executeFunction(commands[i], scene, passState);
  2174. }
  2175. }
  2176. /**
  2177. * Execute commands to render voxels in the scene.
  2178. *
  2179. * @param {Scene} scene The scene.
  2180. * @param {PassState} passState The state for the current render pass.
  2181. * @param {FrustumCommands} frustumCommands The draw commands for the current frustum.
  2182. *
  2183. * @private
  2184. */
  2185. function performVoxelsPass(scene, passState, frustumCommands) {
  2186. scene.context.uniformState.updatePass(Pass.VOXELS);
  2187. const commands = frustumCommands.commands[Pass.VOXELS];
  2188. commands.length = frustumCommands.indices[Pass.VOXELS];
  2189. mergeSort(commands, backToFront, scene.camera.positionWC);
  2190. for (let i = 0; i < commands.length; ++i) {
  2191. executeCommand(commands[i], scene, passState);
  2192. }
  2193. }
  2194. function performGaussianSplatPass(scene, passState, frustumCommands) {
  2195. scene.context.uniformState.updatePass(Pass.GAUSSIAN_SPLATS);
  2196. const commands = frustumCommands.commands[Pass.GAUSSIAN_SPLATS];
  2197. commands.length = frustumCommands.indices[Pass.GAUSSIAN_SPLATS];
  2198. mergeSort(commands, backToFrontSplats, scene.camera.positionWC);
  2199. for (let i = 0; i < commands.length; ++i) {
  2200. executeCommand(commands[i], scene, passState);
  2201. }
  2202. }
  2203. const scratchPerspectiveFrustum = new PerspectiveFrustum();
  2204. const scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
  2205. const scratchOrthographicFrustum = new OrthographicFrustum();
  2206. const scratchOrthographicOffCenterFrustum = new OrthographicOffCenterFrustum();
  2207. /**
  2208. * Create a working frustum from the original camera frustum.
  2209. *
  2210. * @param {Camera} camera The camera
  2211. * @returns {PerspectiveFrustum|PerspectiveOffCenterFrustum|OrthographicFrustum|OrthographicOffCenterFrustum} The working frustum
  2212. *
  2213. * @private
  2214. */
  2215. function createWorkingFrustum(camera) {
  2216. const { frustum } = camera;
  2217. if (defined(frustum.fov)) {
  2218. return frustum.clone(scratchPerspectiveFrustum);
  2219. }
  2220. if (defined(frustum.infiniteProjectionMatrix)) {
  2221. return frustum.clone(scratchPerspectiveOffCenterFrustum);
  2222. }
  2223. if (defined(frustum.width)) {
  2224. return frustum.clone(scratchOrthographicFrustum);
  2225. }
  2226. return frustum.clone(scratchOrthographicOffCenterFrustum);
  2227. }
  2228. /**
  2229. * Determine how translucent surfaces will be handled.
  2230. *
  2231. * When OIT is enabled, then this will delegate to OIT.executeCommands.
  2232. * Otherwise, it will just be executeTranslucentCommandsBackToFront
  2233. * for render passes, or executeTranslucentCommandsFrontToBack for
  2234. * other passes.
  2235. *
  2236. * @param {Scene} scene The scene.
  2237. * @returns {Function} A function to execute translucent commands.
  2238. */
  2239. function obtainTranslucentCommandExecutionFunction(scene) {
  2240. if (scene._environmentState.useOIT) {
  2241. if (!defined(scene._executeOITFunction)) {
  2242. const { view, context } = scene;
  2243. scene._executeOITFunction = function (
  2244. scene,
  2245. executeFunction,
  2246. passState,
  2247. commands,
  2248. invertClassification,
  2249. ) {
  2250. view.globeDepth.prepareColorTextures(context);
  2251. view.oit.executeCommands(
  2252. scene,
  2253. executeFunction,
  2254. passState,
  2255. commands,
  2256. invertClassification,
  2257. );
  2258. };
  2259. }
  2260. return scene._executeOITFunction;
  2261. }
  2262. if (scene.frameState.passes.render) {
  2263. return executeTranslucentCommandsBackToFront;
  2264. }
  2265. return executeTranslucentCommandsFrontToBack;
  2266. }
  2267. /**
  2268. * Execute draw commands to render translucent objects in the scene.
  2269. *
  2270. * @param {Scene} scene The scene.
  2271. * @param {PassState} passState The state for the current render pass.
  2272. * @param {FrustumCommands} frustumCommands The draw commands for the current frustum.
  2273. *
  2274. * @private
  2275. */
  2276. function performTranslucentPass(scene, passState, frustumCommands) {
  2277. const { frameState, context } = scene;
  2278. const { pick, pickVoxel } = frameState.passes;
  2279. const picking = pick || pickVoxel;
  2280. let invertClassification;
  2281. if (
  2282. !picking &&
  2283. scene._environmentState.useInvertClassification &&
  2284. frameState.invertClassificationColor.alpha < 1.0
  2285. ) {
  2286. // Fullscreen pass to copy unclassified fragments when alpha < 1.0.
  2287. // Not executed when undefined.
  2288. invertClassification = scene._invertClassification;
  2289. }
  2290. const executeTranslucentCommands =
  2291. obtainTranslucentCommandExecutionFunction(scene);
  2292. context.uniformState.updatePass(Pass.TRANSLUCENT);
  2293. const commands = frustumCommands.commands[Pass.TRANSLUCENT];
  2294. commands.length = frustumCommands.indices[Pass.TRANSLUCENT];
  2295. executeTranslucentCommands(
  2296. scene,
  2297. executeCommand,
  2298. passState,
  2299. commands,
  2300. invertClassification,
  2301. );
  2302. }
  2303. /**
  2304. * Execute commands for classification of translucent 3D Tiles.
  2305. *
  2306. * @param {Scene} scene The scene.
  2307. * @param {PassState} passState The state for the current render pass.
  2308. * @param {FrustumCommands} frustumCommands The draw commands for the current frustum.
  2309. *
  2310. * @private
  2311. */
  2312. function performTranslucent3DTilesClassification(
  2313. scene,
  2314. passState,
  2315. frustumCommands,
  2316. ) {
  2317. const { translucentTileClassification, globeDepth } = scene._view;
  2318. const has3DTilesClassificationCommands =
  2319. frustumCommands.indices[Pass.CESIUM_3D_TILE_CLASSIFICATION] > 0;
  2320. if (
  2321. !has3DTilesClassificationCommands ||
  2322. !translucentTileClassification.isSupported()
  2323. ) {
  2324. return;
  2325. }
  2326. const commands = frustumCommands.commands[Pass.TRANSLUCENT];
  2327. translucentTileClassification.executeTranslucentCommands(
  2328. scene,
  2329. executeCommand,
  2330. passState,
  2331. commands,
  2332. globeDepth.depthStencilTexture,
  2333. );
  2334. translucentTileClassification.executeClassificationCommands(
  2335. scene,
  2336. executeCommand,
  2337. passState,
  2338. frustumCommands,
  2339. );
  2340. }
  2341. function performCesium3DTileEdgesPass(scene, passState, frustumCommands) {
  2342. scene.context.uniformState.updatePass(Pass.CESIUM_3D_TILE_EDGES);
  2343. const originalFramebuffer = passState.framebuffer;
  2344. scene.context.uniformState.edgeColorTexture = scene.context.defaultTexture;
  2345. scene.context.uniformState.edgeIdTexture = scene.context.defaultTexture;
  2346. scene.context.uniformState.edgeDepthTexture = scene.context.defaultTexture;
  2347. // Set edge framebuffer for rendering
  2348. if (
  2349. scene._enableEdgeVisibility &&
  2350. defined(scene._view) &&
  2351. defined(scene._view.edgeFramebuffer)
  2352. ) {
  2353. passState.framebuffer = scene._view.edgeFramebuffer.framebuffer;
  2354. }
  2355. // performPass
  2356. const commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_EDGES];
  2357. const commandCount = frustumCommands.indices[Pass.CESIUM_3D_TILE_EDGES];
  2358. // clear edge framebuffer
  2359. if (
  2360. scene._enableEdgeVisibility &&
  2361. defined(scene._view) &&
  2362. defined(scene._view.edgeFramebuffer)
  2363. ) {
  2364. const clearCommand = scene._view.edgeFramebuffer.getClearCommand(
  2365. new Color(0.0, 0.0, 0.0, 0.0),
  2366. );
  2367. clearCommand.execute(scene.context, passState);
  2368. }
  2369. // Then execute edge rendering commands
  2370. for (let j = 0; j < commandCount; ++j) {
  2371. executeCommand(commands[j], scene, passState);
  2372. }
  2373. passState.framebuffer = originalFramebuffer;
  2374. }
  2375. /**
  2376. * Execute edge commands that should render directly to the main framebuffer
  2377. * (EDGES_ONLY mode). These edges bypass the MRT edge framebuffer and render
  2378. * on top of surface geometry.
  2379. *
  2380. * @param {Scene} scene
  2381. * @param {PassState} passState
  2382. * @param {FrustumCommands} frustumCommands
  2383. *
  2384. * @private
  2385. */
  2386. function performCesium3DTileEdgesDirectPass(scene, passState, frustumCommands) {
  2387. scene.context.uniformState.updatePass(Pass.CESIUM_3D_TILE_EDGES_DIRECT);
  2388. const commands = frustumCommands.commands[Pass.CESIUM_3D_TILE_EDGES_DIRECT];
  2389. const commandCount =
  2390. frustumCommands.indices[Pass.CESIUM_3D_TILE_EDGES_DIRECT];
  2391. for (let j = 0; j < commandCount; ++j) {
  2392. executeCommand(commands[j], scene, passState);
  2393. }
  2394. }
  2395. /**
  2396. * Execute the draw commands for all the render passes.
  2397. *
  2398. * @param {Scene} scene
  2399. * @param {PassState} passState
  2400. *
  2401. * @private
  2402. */
  2403. function executeCommands(scene, passState) {
  2404. const { camera, context, frameState } = scene;
  2405. const { uniformState } = context;
  2406. uniformState.updateCamera(camera);
  2407. const frustum = createWorkingFrustum(camera);
  2408. frustum.near = camera.frustum.near;
  2409. frustum.far = camera.frustum.far;
  2410. const passes = frameState.passes;
  2411. const picking = passes.pick || passes.pickVoxel;
  2412. // Ideally, we would render the sky box and atmosphere last for
  2413. // early-z, but we would have to draw it in each frustum.
  2414. // Do not render environment primitives during a pick pass since they do not generate picking commands.
  2415. if (!picking) {
  2416. renderEnvironment(scene, passState);
  2417. }
  2418. const {
  2419. clearGlobeDepth,
  2420. renderTranslucentDepthForPick,
  2421. useDepthPlane,
  2422. useGlobeDepthFramebuffer,
  2423. useInvertClassification,
  2424. usePostProcessSelected,
  2425. } = scene._environmentState;
  2426. const {
  2427. globeDepth,
  2428. globeTranslucencyFramebuffer,
  2429. sceneFramebuffer,
  2430. frustumCommandsList,
  2431. } = scene._view;
  2432. const numFrustums = frustumCommandsList.length;
  2433. const globeTranslucencyState = scene._globeTranslucencyState;
  2434. const clearDepth = scene._depthClearCommand;
  2435. const clearStencil = scene._stencilClearCommand;
  2436. const clearClassificationStencil = scene._classificationStencilClearCommand;
  2437. const depthPlane = scene._depthPlane;
  2438. const height2D = camera.position.z;
  2439. function performPass(frustumCommands, passId) {
  2440. uniformState.updatePass(passId);
  2441. const commands = frustumCommands.commands[passId];
  2442. const commandCount = frustumCommands.indices[passId];
  2443. for (let j = 0; j < commandCount; ++j) {
  2444. executeCommand(commands[j], scene, passState);
  2445. }
  2446. return commandCount;
  2447. }
  2448. function performIdPass(frustumCommands, passId) {
  2449. uniformState.updatePass(passId);
  2450. const commands = frustumCommands.commands[passId];
  2451. const commandCount = frustumCommands.indices[passId];
  2452. for (let j = 0; j < commandCount; ++j) {
  2453. executeIdCommand(commands[j], scene, passState);
  2454. }
  2455. }
  2456. // Execute commands in each frustum in back to front order
  2457. for (let i = 0; i < numFrustums; ++i) {
  2458. const index = numFrustums - i - 1;
  2459. const frustumCommands = frustumCommandsList[index];
  2460. if (scene.mode === SceneMode.SCENE2D) {
  2461. // To avoid z-fighting in 2D, move the camera to just before the frustum
  2462. // and scale the frustum depth to be in [1.0, nearToFarDistance2D].
  2463. camera.position.z = height2D - frustumCommands.near + 1.0;
  2464. frustum.far = Math.max(1.0, frustumCommands.far - frustumCommands.near);
  2465. frustum.near = 1.0;
  2466. uniformState.update(frameState);
  2467. uniformState.updateFrustum(frustum);
  2468. } else {
  2469. // Avoid tearing artifacts between adjacent frustums in the opaque passes
  2470. frustum.near =
  2471. index !== 0
  2472. ? frustumCommands.near * scene.opaqueFrustumNearOffset
  2473. : frustumCommands.near;
  2474. frustum.far = frustumCommands.far;
  2475. uniformState.updateFrustum(frustum);
  2476. }
  2477. clearDepth.execute(context, passState);
  2478. if (context.stencilBuffer) {
  2479. clearStencil.execute(context, passState);
  2480. }
  2481. if (globeTranslucencyState.translucent) {
  2482. uniformState.updatePass(Pass.GLOBE);
  2483. globeTranslucencyState.executeGlobeCommands(
  2484. frustumCommands,
  2485. executeCommand,
  2486. globeTranslucencyFramebuffer,
  2487. scene,
  2488. passState,
  2489. );
  2490. } else {
  2491. performPass(frustumCommands, Pass.GLOBE);
  2492. }
  2493. if (useGlobeDepthFramebuffer) {
  2494. globeDepth.executeCopyDepth(context, passState);
  2495. }
  2496. // Draw terrain classification
  2497. if (!renderTranslucentDepthForPick) {
  2498. if (globeTranslucencyState.translucent) {
  2499. uniformState.updatePass(Pass.TERRAIN_CLASSIFICATION);
  2500. globeTranslucencyState.executeGlobeClassificationCommands(
  2501. frustumCommands,
  2502. executeCommand,
  2503. globeTranslucencyFramebuffer,
  2504. scene,
  2505. passState,
  2506. );
  2507. } else {
  2508. performPass(frustumCommands, Pass.TERRAIN_CLASSIFICATION);
  2509. }
  2510. }
  2511. if (clearGlobeDepth) {
  2512. clearDepth.execute(context, passState);
  2513. if (useDepthPlane) {
  2514. depthPlane.execute(context, passState);
  2515. }
  2516. }
  2517. let commandCount;
  2518. // Draw edges FIRST - before binding textures to avoid feedback loop
  2519. performCesium3DTileEdgesPass(scene, passState, frustumCommands);
  2520. if (
  2521. scene._enableEdgeVisibility &&
  2522. defined(scene._view) &&
  2523. defined(scene._view.edgeFramebuffer)
  2524. ) {
  2525. // Get edge color texture (attachment 0)
  2526. const colorTexture = scene._view.edgeFramebuffer.colorTexture;
  2527. if (defined(colorTexture)) {
  2528. scene.context.uniformState.edgeColorTexture = colorTexture;
  2529. } else {
  2530. scene.context.uniformState.edgeColorTexture =
  2531. scene.context.defaultTexture;
  2532. }
  2533. // Get edge ID texture (attachment 1)
  2534. const idTexture = scene._view.edgeFramebuffer.idTexture;
  2535. if (defined(idTexture)) {
  2536. scene.context.uniformState.edgeIdTexture = idTexture;
  2537. } else {
  2538. scene.context.uniformState.edgeIdTexture = scene.context.defaultTexture;
  2539. }
  2540. // Get edge depth texture (attachment 2)
  2541. const edgeDepthTexture = scene._view.edgeFramebuffer.depthTexture;
  2542. if (defined(edgeDepthTexture)) {
  2543. scene.context.uniformState.edgeDepthTexture = edgeDepthTexture;
  2544. } else {
  2545. scene.context.uniformState.edgeDepthTexture =
  2546. scene.context.defaultTexture;
  2547. }
  2548. } else {
  2549. scene.context.uniformState.edgeColorTexture =
  2550. scene.context.defaultTexture;
  2551. scene.context.uniformState.edgeIdTexture = scene.context.defaultTexture;
  2552. scene.context.uniformState.edgeDepthTexture =
  2553. scene.context.defaultTexture;
  2554. }
  2555. if (!useInvertClassification || picking || renderTranslucentDepthForPick) {
  2556. // Common/fastest path. Draw 3D Tiles and classification normally.
  2557. // Draw 3D Tiles
  2558. commandCount = performPass(frustumCommands, Pass.CESIUM_3D_TILE);
  2559. if (commandCount > 0) {
  2560. if (useGlobeDepthFramebuffer) {
  2561. globeDepth.prepareColorTextures(context, clearGlobeDepth);
  2562. globeDepth.executeUpdateDepth(
  2563. context,
  2564. passState,
  2565. globeDepth.depthStencilTexture,
  2566. );
  2567. }
  2568. // Draw classifications. Modifies 3D Tiles color.
  2569. if (!renderTranslucentDepthForPick) {
  2570. commandCount = performPass(
  2571. frustumCommands,
  2572. Pass.CESIUM_3D_TILE_CLASSIFICATION,
  2573. );
  2574. }
  2575. }
  2576. } else {
  2577. // When the invert classification color is opaque:
  2578. // Main FBO (FBO1): Main_Color + Main_DepthStencil
  2579. // Invert classification FBO (FBO2) : Invert_Color + Main_DepthStencil
  2580. //
  2581. // 1. Clear FBO2 color to vec4(0.0) for each frustum
  2582. // 2. Draw 3D Tiles to FBO2
  2583. // 3. Draw classification to FBO2
  2584. // 4. Fullscreen pass to FBO1, draw Invert_Color when:
  2585. // * Main_DepthStencil has the stencil bit set > 0 (classified)
  2586. // 5. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when:
  2587. // * Main_DepthStencil has stencil bit set to 0 (unclassified) and
  2588. // * Invert_Color !== vec4(0.0)
  2589. //
  2590. // When the invert classification color is translucent:
  2591. // Main FBO (FBO1): Main_Color + Main_DepthStencil
  2592. // Invert classification FBO (FBO2): Invert_Color + Invert_DepthStencil
  2593. // IsClassified FBO (FBO3): IsClassified_Color + Invert_DepthStencil
  2594. //
  2595. // 1. Clear FBO2 and FBO3 color to vec4(0.0), stencil to 0, and depth to 1.0
  2596. // 2. Draw 3D Tiles to FBO2
  2597. // 3. Draw classification to FBO2
  2598. // 4. Fullscreen pass to FBO3, draw any color when
  2599. // * Invert_DepthStencil has the stencil bit set > 0 (classified)
  2600. // 5. Fullscreen pass to FBO1, draw Invert_Color when:
  2601. // * Invert_Color !== vec4(0.0) and
  2602. // * IsClassified_Color !== vec4(0.0)
  2603. // 6. Fullscreen pass to FBO1, draw Invert_Color * czm_invertClassificationColor when:
  2604. // * Invert_Color !== vec4(0.0) and
  2605. // * IsClassified_Color === vec4(0.0)
  2606. //
  2607. // NOTE: Step six when translucent invert color occurs after the TRANSLUCENT pass
  2608. //
  2609. scene._invertClassification.clear(context, passState);
  2610. const opaqueClassificationFramebuffer = passState.framebuffer;
  2611. passState.framebuffer = scene._invertClassification._fbo.framebuffer;
  2612. // Draw normally
  2613. commandCount = performPass(frustumCommands, Pass.CESIUM_3D_TILE);
  2614. if (useGlobeDepthFramebuffer) {
  2615. scene._invertClassification.prepareTextures(context);
  2616. globeDepth.executeUpdateDepth(
  2617. context,
  2618. passState,
  2619. scene._invertClassification._fbo.getDepthStencilTexture(),
  2620. );
  2621. }
  2622. // Set stencil
  2623. commandCount = performPass(
  2624. frustumCommands,
  2625. Pass.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW,
  2626. );
  2627. passState.framebuffer = opaqueClassificationFramebuffer;
  2628. // Fullscreen pass to copy classified fragments
  2629. scene._invertClassification.executeClassified(context, passState);
  2630. if (frameState.invertClassificationColor.alpha === 1.0) {
  2631. // Fullscreen pass to copy unclassified fragments when alpha == 1.0
  2632. scene._invertClassification.executeUnclassified(context, passState);
  2633. }
  2634. // Clear stencil set by the classification for the next classification pass
  2635. if (commandCount > 0 && context.stencilBuffer) {
  2636. clearClassificationStencil.execute(context, passState);
  2637. }
  2638. // Draw style over classification.
  2639. commandCount = performPass(
  2640. frustumCommands,
  2641. Pass.CESIUM_3D_TILE_CLASSIFICATION,
  2642. );
  2643. }
  2644. if (commandCount > 0 && context.stencilBuffer) {
  2645. clearStencil.execute(context, passState);
  2646. }
  2647. performVoxelsPass(scene, passState, frustumCommands);
  2648. performPass(frustumCommands, Pass.OPAQUE);
  2649. // Draw direct edges (EDGES_ONLY mode) after opaque surfaces
  2650. performCesium3DTileEdgesDirectPass(scene, passState, frustumCommands);
  2651. performGaussianSplatPass(scene, passState, frustumCommands);
  2652. if (index !== 0 && scene.mode !== SceneMode.SCENE2D) {
  2653. // Do not overlap frustums in the translucent pass to avoid blending artifacts
  2654. frustum.near = frustumCommands.near;
  2655. uniformState.updateFrustum(frustum);
  2656. }
  2657. performTranslucentPass(scene, passState, frustumCommands);
  2658. performTranslucent3DTilesClassification(scene, passState, frustumCommands);
  2659. if (
  2660. context.depthTexture &&
  2661. scene.useDepthPicking &&
  2662. (useGlobeDepthFramebuffer || renderTranslucentDepthForPick)
  2663. ) {
  2664. // PERFORMANCE_IDEA: Use MRT to avoid the extra copy.
  2665. const pickDepth = scene._picking.getPickDepth(scene, index);
  2666. pickDepth.update(context, globeDepth.depthStencilTexture);
  2667. pickDepth.executeCopyDepth(context, passState);
  2668. }
  2669. if (picking || !usePostProcessSelected) {
  2670. continue;
  2671. }
  2672. const originalFramebuffer = passState.framebuffer;
  2673. passState.framebuffer = sceneFramebuffer.getIdFramebuffer();
  2674. // reset frustum
  2675. frustum.near =
  2676. index !== 0
  2677. ? frustumCommands.near * scene.opaqueFrustumNearOffset
  2678. : frustumCommands.near;
  2679. frustum.far = frustumCommands.far;
  2680. uniformState.updateFrustum(frustum);
  2681. if (globeTranslucencyState.translucent) {
  2682. uniformState.updatePass(Pass.GLOBE);
  2683. globeTranslucencyState.executeGlobeCommands(
  2684. frustumCommands,
  2685. executeIdCommand,
  2686. globeTranslucencyFramebuffer,
  2687. scene,
  2688. passState,
  2689. );
  2690. } else {
  2691. performIdPass(frustumCommands, Pass.GLOBE);
  2692. }
  2693. if (clearGlobeDepth) {
  2694. clearDepth.framebuffer = passState.framebuffer;
  2695. clearDepth.execute(context, passState);
  2696. clearDepth.framebuffer = undefined;
  2697. }
  2698. if (clearGlobeDepth && useDepthPlane) {
  2699. depthPlane.execute(context, passState);
  2700. }
  2701. performIdPass(frustumCommands, Pass.CESIUM_3D_TILE);
  2702. performIdPass(frustumCommands, Pass.OPAQUE);
  2703. performIdPass(frustumCommands, Pass.TRANSLUCENT);
  2704. passState.framebuffer = originalFramebuffer;
  2705. }
  2706. }
  2707. /**
  2708. * Render the sky, atmosphere, sun, and moon
  2709. *
  2710. * @param {Scene} scene The scene.
  2711. * @param {PassState} passState The render state for the pass.
  2712. *
  2713. * @private
  2714. */
  2715. function renderEnvironment(scene, passState) {
  2716. const { context, environmentState, view } = scene;
  2717. context.uniformState.updatePass(Pass.ENVIRONMENT);
  2718. if (defined(environmentState.skyBoxCommand)) {
  2719. executeCommand(environmentState.skyBoxCommand, scene, passState);
  2720. }
  2721. if (environmentState.isSkyAtmosphereVisible) {
  2722. executeCommand(environmentState.skyAtmosphereCommand, scene, passState);
  2723. }
  2724. if (environmentState.isSunVisible) {
  2725. environmentState.sunDrawCommand.execute(context, passState);
  2726. if (scene.sunBloom && !environmentState.useWebVR) {
  2727. let framebuffer;
  2728. if (environmentState.useGlobeDepthFramebuffer) {
  2729. framebuffer = view.globeDepth.framebuffer;
  2730. } else if (environmentState.usePostProcess) {
  2731. framebuffer = view.sceneFramebuffer.framebuffer;
  2732. } else {
  2733. framebuffer = environmentState.originalFramebuffer;
  2734. }
  2735. scene._sunPostProcess.execute(context);
  2736. scene._sunPostProcess.copy(context, framebuffer);
  2737. passState.framebuffer = framebuffer;
  2738. }
  2739. }
  2740. // Moon can be seen through the atmosphere, since the sun is rendered after the atmosphere.
  2741. if (environmentState.isMoonVisible) {
  2742. environmentState.moonCommand.execute(context, passState);
  2743. }
  2744. // execute panorama commands, drop removed primitives
  2745. const panoramaCommandList = scene.frameState.panoramaCommandList;
  2746. for (let i = panoramaCommandList.length - 1; i >= 0; i--) {
  2747. const panoramaCommand = panoramaCommandList[i];
  2748. if (defined(panoramaCommand.shaderProgram)) {
  2749. executeCommand(panoramaCommandList[i], scene, passState);
  2750. } else {
  2751. //primitive was removed
  2752. panoramaCommandList.splice(i, 1);
  2753. }
  2754. }
  2755. }
  2756. /**
  2757. * Execute compute commands from the scene's environment state and computeCommandList
  2758. *
  2759. * @param {Scene} scene
  2760. *
  2761. * @private
  2762. */
  2763. function executeComputeCommands(scene) {
  2764. scene.context.uniformState.updatePass(Pass.COMPUTE);
  2765. const sunComputeCommand = scene._environmentState.sunComputeCommand;
  2766. if (defined(sunComputeCommand)) {
  2767. sunComputeCommand.execute(scene._computeEngine);
  2768. }
  2769. const commandList = scene._computeCommandList;
  2770. for (let i = 0; i < commandList.length; ++i) {
  2771. commandList[i].execute(scene._computeEngine);
  2772. }
  2773. }
  2774. /**
  2775. * Execute the draw commands for overlays
  2776. *
  2777. * @param {Scene} scene
  2778. * @param {PassState} passState
  2779. *
  2780. * @private
  2781. */
  2782. function executeOverlayCommands(scene, passState) {
  2783. scene.context.uniformState.updatePass(Pass.OVERLAY);
  2784. const context = scene.context;
  2785. const commandList = scene._overlayCommandList;
  2786. for (let i = 0; i < commandList.length; ++i) {
  2787. commandList[i].execute(context, passState);
  2788. }
  2789. }
  2790. /**
  2791. * Add the scene's draw commands into the shadow map passes.
  2792. *
  2793. * @param {Scene} scene
  2794. * @param {DrawCommand[]} commandList
  2795. * @param {ShadowMap} shadowMap
  2796. *
  2797. * @private
  2798. */
  2799. function insertShadowCastCommands(scene, commandList, shadowMap) {
  2800. const { shadowMapCullingVolume, isPointLight, passes } = shadowMap;
  2801. const numberOfPasses = passes.length;
  2802. const shadowedPasses = [
  2803. Pass.GLOBE,
  2804. Pass.CESIUM_3D_TILE,
  2805. Pass.OPAQUE,
  2806. Pass.TRANSLUCENT,
  2807. ];
  2808. for (let i = 0; i < commandList.length; ++i) {
  2809. const command = commandList[i];
  2810. scene.updateDerivedCommands(command);
  2811. if (
  2812. !command.castShadows ||
  2813. shadowedPasses.indexOf(command.pass) < 0 ||
  2814. !scene.isVisible(shadowMapCullingVolume, command)
  2815. ) {
  2816. continue;
  2817. }
  2818. if (isPointLight) {
  2819. for (let k = 0; k < numberOfPasses; ++k) {
  2820. passes[k].commandList.push(command);
  2821. }
  2822. } else if (numberOfPasses === 1) {
  2823. passes[0].commandList.push(command);
  2824. } else {
  2825. let wasVisible = false;
  2826. // Loop over cascades from largest to smallest
  2827. for (let j = numberOfPasses - 1; j >= 0; --j) {
  2828. const cascadeVolume = passes[j].cullingVolume;
  2829. if (scene.isVisible(cascadeVolume, command)) {
  2830. passes[j].commandList.push(command);
  2831. wasVisible = true;
  2832. } else if (wasVisible) {
  2833. // If it was visible in the previous cascade but now isn't
  2834. // then there is no need to check any more cascades
  2835. break;
  2836. }
  2837. }
  2838. }
  2839. }
  2840. }
  2841. /**
  2842. * Execute the draw commands to cast shadows into the shadow maps.
  2843. *
  2844. * @param {Scene} scene
  2845. *
  2846. * @private
  2847. */
  2848. function executeShadowMapCastCommands(scene) {
  2849. const { shadowState, commandList } = scene.frameState;
  2850. const { shadowsEnabled, shadowMaps } = shadowState;
  2851. if (!shadowsEnabled) {
  2852. return;
  2853. }
  2854. const { context } = scene;
  2855. const { uniformState } = context;
  2856. for (let i = 0; i < shadowMaps.length; ++i) {
  2857. const shadowMap = shadowMaps[i];
  2858. if (shadowMap.outOfView) {
  2859. continue;
  2860. }
  2861. // Reset the command lists
  2862. const { passes } = shadowMap;
  2863. for (let j = 0; j < passes.length; ++j) {
  2864. passes[j].commandList.length = 0;
  2865. }
  2866. // Insert the primitive/model commands into the shadow map command lists
  2867. insertShadowCastCommands(scene, commandList, shadowMap);
  2868. for (let j = 0; j < passes.length; ++j) {
  2869. const pass = shadowMap.passes[j];
  2870. const { camera, commandList } = pass;
  2871. uniformState.updateCamera(camera);
  2872. shadowMap.updatePass(context, j);
  2873. for (let k = 0; k < commandList.length; ++k) {
  2874. const command = commandList[k];
  2875. // Set the correct pass before rendering into the shadow map because some shaders
  2876. // conditionally render based on whether the pass is translucent or opaque.
  2877. uniformState.updatePass(command.pass);
  2878. const castCommand = command.derivedCommands.shadows.castCommands[i];
  2879. executeCommand(castCommand, scene, pass.passState);
  2880. }
  2881. }
  2882. }
  2883. }
  2884. const scratchEyeTranslation = new Cartesian3();
  2885. /**
  2886. * Update and clear framebuffers, and execute draw commands.
  2887. *
  2888. * @param {PassState} passState State specific to each render pass.
  2889. * @param {Color} backgroundColor
  2890. *
  2891. * @private
  2892. */
  2893. Scene.prototype.updateAndExecuteCommands = function (
  2894. passState,
  2895. backgroundColor,
  2896. ) {
  2897. updateAndClearFramebuffers(this, passState, backgroundColor);
  2898. if (this._environmentState.useWebVR) {
  2899. executeWebVRCommands(this, passState, backgroundColor);
  2900. } else if (
  2901. this._frameState.mode !== SceneMode.SCENE2D ||
  2902. this._mapMode2D === MapMode2D.ROTATE
  2903. ) {
  2904. executeCommandsInViewport(true, this, passState);
  2905. } else {
  2906. execute2DViewportCommands(this, passState);
  2907. }
  2908. };
  2909. /**
  2910. * Execute the draw commands to render the scene into the stereo viewports of a WebVR application.
  2911. *
  2912. * @param {Scene} scene
  2913. * @param {PassState} passState
  2914. *
  2915. * @private
  2916. */
  2917. function executeWebVRCommands(scene, passState) {
  2918. const view = scene._view;
  2919. const camera = view.camera;
  2920. const environmentState = scene._environmentState;
  2921. const renderTranslucentDepthForPick =
  2922. environmentState.renderTranslucentDepthForPick;
  2923. updateAndRenderPrimitives(scene);
  2924. view.createPotentiallyVisibleSet(scene);
  2925. executeComputeCommands(scene);
  2926. if (!renderTranslucentDepthForPick) {
  2927. executeShadowMapCastCommands(scene);
  2928. }
  2929. // Based on Calculating Stereo pairs by Paul Bourke
  2930. // http://paulbourke.net/stereographics/stereorender/
  2931. const viewport = passState.viewport;
  2932. viewport.x = 0;
  2933. viewport.y = 0;
  2934. viewport.width = viewport.width * 0.5;
  2935. const savedCamera = Camera.clone(camera, scene._cameraVR);
  2936. savedCamera.frustum = camera.frustum;
  2937. const near = camera.frustum.near;
  2938. const fo = near * (scene.focalLength ?? 5.0);
  2939. const eyeSeparation = scene.eyeSeparation ?? fo / 30.0;
  2940. const eyeTranslation = Cartesian3.multiplyByScalar(
  2941. savedCamera.right,
  2942. eyeSeparation * 0.5,
  2943. scratchEyeTranslation,
  2944. );
  2945. camera.frustum.aspectRatio = viewport.width / viewport.height;
  2946. const offset = (0.5 * eyeSeparation * near) / fo;
  2947. Cartesian3.add(savedCamera.position, eyeTranslation, camera.position);
  2948. camera.frustum.xOffset = offset;
  2949. executeCommands(scene, passState);
  2950. viewport.x = viewport.width;
  2951. Cartesian3.subtract(savedCamera.position, eyeTranslation, camera.position);
  2952. camera.frustum.xOffset = -offset;
  2953. executeCommands(scene, passState);
  2954. Camera.clone(savedCamera, camera);
  2955. }
  2956. const scratch2DViewportCartographic = new Cartographic(
  2957. Math.PI,
  2958. CesiumMath.PI_OVER_TWO,
  2959. );
  2960. const scratch2DViewportMaxCoord = new Cartesian3();
  2961. const scratch2DViewportSavedPosition = new Cartesian3();
  2962. const scratch2DViewportTransform = new Matrix4();
  2963. const scratch2DViewportCameraTransform = new Matrix4();
  2964. const scratch2DViewportEyePoint = new Cartesian3();
  2965. const scratch2DViewportWindowCoords = new Cartesian3();
  2966. const scratch2DViewport = new BoundingRectangle();
  2967. /**
  2968. * Execute the draw commands to render into a 2D viewport.
  2969. *
  2970. * @param {Scene} scene
  2971. * @param {PassState} passState
  2972. *
  2973. * @private
  2974. */
  2975. function execute2DViewportCommands(scene, passState) {
  2976. const { frameState, camera } = scene;
  2977. const { uniformState } = scene.context;
  2978. const originalViewport = passState.viewport;
  2979. const viewport = BoundingRectangle.clone(originalViewport, scratch2DViewport);
  2980. passState.viewport = viewport;
  2981. const maxCartographic = scratch2DViewportCartographic;
  2982. const maxCoord = scratch2DViewportMaxCoord;
  2983. const projection = scene.mapProjection;
  2984. projection.project(maxCartographic, maxCoord);
  2985. const position = Cartesian3.clone(
  2986. camera.position,
  2987. scratch2DViewportSavedPosition,
  2988. );
  2989. const transform = Matrix4.clone(
  2990. camera.transform,
  2991. scratch2DViewportCameraTransform,
  2992. );
  2993. const frustum = camera.frustum.clone();
  2994. camera._setTransform(Matrix4.IDENTITY);
  2995. const viewportTransformation = Matrix4.computeViewportTransformation(
  2996. viewport,
  2997. 0.0,
  2998. 1.0,
  2999. scratch2DViewportTransform,
  3000. );
  3001. const projectionMatrix = camera.frustum.projectionMatrix;
  3002. const x = camera.positionWC.y;
  3003. const eyePoint = Cartesian3.fromElements(
  3004. CesiumMath.sign(x) * maxCoord.x - x,
  3005. 0.0,
  3006. -camera.positionWC.x,
  3007. scratch2DViewportEyePoint,
  3008. );
  3009. const windowCoordinates = Transforms.pointToGLWindowCoordinates(
  3010. projectionMatrix,
  3011. viewportTransformation,
  3012. eyePoint,
  3013. scratch2DViewportWindowCoords,
  3014. );
  3015. windowCoordinates.x = Math.floor(windowCoordinates.x);
  3016. const viewportX = viewport.x;
  3017. const viewportWidth = viewport.width;
  3018. if (
  3019. x === 0.0 ||
  3020. windowCoordinates.x <= viewportX ||
  3021. windowCoordinates.x >= viewportX + viewportWidth
  3022. ) {
  3023. executeCommandsInViewport(true, scene, passState);
  3024. } else if (
  3025. Math.abs(viewportX + viewportWidth * 0.5 - windowCoordinates.x) < 1.0
  3026. ) {
  3027. viewport.width = windowCoordinates.x - viewport.x;
  3028. camera.position.x *= CesiumMath.sign(camera.position.x);
  3029. camera.frustum.right = 0.0;
  3030. frameState.cullingVolume = camera.frustum.computeCullingVolume(
  3031. camera.positionWC,
  3032. camera.directionWC,
  3033. camera.upWC,
  3034. );
  3035. uniformState.update(frameState);
  3036. executeCommandsInViewport(true, scene, passState);
  3037. viewport.x = windowCoordinates.x;
  3038. camera.position.x = -camera.position.x;
  3039. camera.frustum.right = -camera.frustum.left;
  3040. camera.frustum.left = 0.0;
  3041. frameState.cullingVolume = camera.frustum.computeCullingVolume(
  3042. camera.positionWC,
  3043. camera.directionWC,
  3044. camera.upWC,
  3045. );
  3046. uniformState.update(frameState);
  3047. executeCommandsInViewport(false, scene, passState);
  3048. } else if (windowCoordinates.x > viewportX + viewportWidth * 0.5) {
  3049. viewport.width = windowCoordinates.x - viewportX;
  3050. const right = camera.frustum.right;
  3051. camera.frustum.right = maxCoord.x - x;
  3052. frameState.cullingVolume = camera.frustum.computeCullingVolume(
  3053. camera.positionWC,
  3054. camera.directionWC,
  3055. camera.upWC,
  3056. );
  3057. uniformState.update(frameState);
  3058. executeCommandsInViewport(true, scene, passState);
  3059. viewport.x = windowCoordinates.x;
  3060. viewport.width = viewportX + viewportWidth - windowCoordinates.x;
  3061. camera.position.x = -camera.position.x;
  3062. camera.frustum.left = -camera.frustum.right;
  3063. camera.frustum.right = right - camera.frustum.right * 2.0;
  3064. frameState.cullingVolume = camera.frustum.computeCullingVolume(
  3065. camera.positionWC,
  3066. camera.directionWC,
  3067. camera.upWC,
  3068. );
  3069. uniformState.update(frameState);
  3070. executeCommandsInViewport(false, scene, passState);
  3071. } else {
  3072. viewport.x = windowCoordinates.x;
  3073. viewport.width = viewportX + viewportWidth - windowCoordinates.x;
  3074. const left = camera.frustum.left;
  3075. camera.frustum.left = -maxCoord.x - x;
  3076. frameState.cullingVolume = camera.frustum.computeCullingVolume(
  3077. camera.positionWC,
  3078. camera.directionWC,
  3079. camera.upWC,
  3080. );
  3081. uniformState.update(frameState);
  3082. executeCommandsInViewport(true, scene, passState);
  3083. viewport.x = viewportX;
  3084. viewport.width = windowCoordinates.x - viewportX;
  3085. camera.position.x = -camera.position.x;
  3086. camera.frustum.right = -camera.frustum.left;
  3087. camera.frustum.left = left - camera.frustum.left * 2.0;
  3088. frameState.cullingVolume = camera.frustum.computeCullingVolume(
  3089. camera.positionWC,
  3090. camera.directionWC,
  3091. camera.upWC,
  3092. );
  3093. uniformState.update(frameState);
  3094. executeCommandsInViewport(false, scene, passState);
  3095. }
  3096. camera._setTransform(transform);
  3097. Cartesian3.clone(position, camera.position);
  3098. camera.frustum = frustum.clone();
  3099. passState.viewport = originalViewport;
  3100. }
  3101. /**
  3102. * Execute the draw commands to render the scene into the viewport.
  3103. * If this is the first viewport rendered, the framebuffers will be cleared to the background color.
  3104. *
  3105. * @param {boolean} firstViewport <code>true</code> if this is the first viewport rendered.
  3106. * @param {Scene} scene
  3107. * @param {PassState} passState
  3108. *
  3109. * @private
  3110. */
  3111. function executeCommandsInViewport(firstViewport, scene, passState) {
  3112. const view = scene._view;
  3113. const { renderTranslucentDepthForPick } = scene._environmentState;
  3114. if (!firstViewport) {
  3115. scene.frameState.commandList.length = 0;
  3116. }
  3117. updateAndRenderPrimitives(scene);
  3118. view.createPotentiallyVisibleSet(scene);
  3119. if (firstViewport) {
  3120. executeComputeCommands(scene);
  3121. if (!renderTranslucentDepthForPick) {
  3122. executeShadowMapCastCommands(scene);
  3123. }
  3124. }
  3125. executeCommands(scene, passState);
  3126. }
  3127. const scratchCullingVolume = new CullingVolume();
  3128. /**
  3129. * @private
  3130. */
  3131. Scene.prototype.updateEnvironment = function () {
  3132. const frameState = this._frameState;
  3133. const view = this._view;
  3134. // Update celestial and terrestrial environment effects.
  3135. const environmentState = this._environmentState;
  3136. const renderPass = frameState.passes.render;
  3137. const offscreenPass = frameState.passes.offscreen;
  3138. const atmosphere = this.atmosphere;
  3139. const skyAtmosphere = this.skyAtmosphere;
  3140. const globe = this.globe;
  3141. const globeTranslucencyState = this._globeTranslucencyState;
  3142. if (
  3143. !renderPass ||
  3144. (this._mode !== SceneMode.SCENE2D &&
  3145. view.camera.frustum instanceof OrthographicFrustum) ||
  3146. !globeTranslucencyState.environmentVisible
  3147. ) {
  3148. environmentState.skyAtmosphereCommand = undefined;
  3149. environmentState.skyBoxCommand = undefined;
  3150. environmentState.sunDrawCommand = undefined;
  3151. environmentState.sunComputeCommand = undefined;
  3152. environmentState.moonCommand = undefined;
  3153. } else {
  3154. if (defined(skyAtmosphere)) {
  3155. if (defined(globe)) {
  3156. skyAtmosphere.setDynamicLighting(
  3157. DynamicAtmosphereLightingType.fromGlobeFlags(globe),
  3158. );
  3159. environmentState.isReadyForAtmosphere =
  3160. environmentState.isReadyForAtmosphere ||
  3161. !globe.show ||
  3162. globe._surface._tilesToRender.length > 0;
  3163. } else {
  3164. const dynamicLighting = atmosphere.dynamicLighting;
  3165. skyAtmosphere.setDynamicLighting(dynamicLighting);
  3166. environmentState.isReadyForAtmosphere = true;
  3167. }
  3168. environmentState.skyAtmosphereCommand = skyAtmosphere.update(
  3169. frameState,
  3170. globe,
  3171. );
  3172. if (defined(environmentState.skyAtmosphereCommand)) {
  3173. this.updateDerivedCommands(environmentState.skyAtmosphereCommand);
  3174. }
  3175. } else {
  3176. environmentState.skyAtmosphereCommand = undefined;
  3177. }
  3178. environmentState.skyBoxCommand = defined(this.skyBox)
  3179. ? this.skyBox.update(frameState, this._hdr)
  3180. : undefined;
  3181. const sunCommands = defined(this.sun)
  3182. ? this.sun.update(frameState, view.passState, this._hdr)
  3183. : undefined;
  3184. environmentState.sunDrawCommand = defined(sunCommands)
  3185. ? sunCommands.drawCommand
  3186. : undefined;
  3187. environmentState.sunComputeCommand = defined(sunCommands)
  3188. ? sunCommands.computeCommand
  3189. : undefined;
  3190. environmentState.moonCommand = defined(this.moon)
  3191. ? this.moon.update(frameState)
  3192. : undefined;
  3193. }
  3194. const clearGlobeDepth = (environmentState.clearGlobeDepth =
  3195. defined(globe) &&
  3196. globe.show &&
  3197. (!globe.depthTestAgainstTerrain || this.mode === SceneMode.SCENE2D));
  3198. const useDepthPlane = (environmentState.useDepthPlane =
  3199. clearGlobeDepth &&
  3200. this.mode === SceneMode.SCENE3D &&
  3201. globeTranslucencyState.useDepthPlane);
  3202. if (useDepthPlane) {
  3203. // Update the depth plane that is rendered in 3D when the primitives are
  3204. // not depth tested against terrain so primitives on the backface
  3205. // of the globe are not picked.
  3206. this._depthPlane.update(frameState);
  3207. }
  3208. environmentState.renderTranslucentDepthForPick = false;
  3209. environmentState.useWebVR =
  3210. this._useWebVR && this.mode !== SceneMode.SCENE2D && !offscreenPass;
  3211. const occluder =
  3212. frameState.mode === SceneMode.SCENE3D &&
  3213. !globeTranslucencyState.sunVisibleThroughGlobe
  3214. ? frameState.occluder
  3215. : undefined;
  3216. let cullingVolume = frameState.cullingVolume;
  3217. // get user culling volume minus the far plane.
  3218. const planes = scratchCullingVolume.planes;
  3219. for (let k = 0; k < 5; ++k) {
  3220. planes[k] = cullingVolume.planes[k];
  3221. }
  3222. cullingVolume = scratchCullingVolume;
  3223. // Determine visibility of celestial and terrestrial environment effects.
  3224. environmentState.isSkyAtmosphereVisible =
  3225. defined(environmentState.skyAtmosphereCommand) &&
  3226. environmentState.isReadyForAtmosphere;
  3227. environmentState.isSunVisible = this.isVisible(
  3228. cullingVolume,
  3229. environmentState.sunDrawCommand,
  3230. occluder,
  3231. );
  3232. environmentState.isMoonVisible = this.isVisible(
  3233. cullingVolume,
  3234. environmentState.moonCommand,
  3235. occluder,
  3236. );
  3237. const envMaps = this.specularEnvironmentMaps;
  3238. let specularEnvironmentCubeMap = this._specularEnvironmentCubeMap;
  3239. if (defined(envMaps) && specularEnvironmentCubeMap?.url !== envMaps) {
  3240. specularEnvironmentCubeMap =
  3241. specularEnvironmentCubeMap && specularEnvironmentCubeMap.destroy();
  3242. this._specularEnvironmentCubeMap = new SpecularEnvironmentCubeMap(envMaps);
  3243. } else if (!defined(envMaps) && defined(specularEnvironmentCubeMap)) {
  3244. specularEnvironmentCubeMap.destroy();
  3245. this._specularEnvironmentCubeMap = undefined;
  3246. }
  3247. if (defined(this._specularEnvironmentCubeMap)) {
  3248. this._specularEnvironmentCubeMap.update(frameState);
  3249. }
  3250. };
  3251. function updateDebugFrustumPlanes(scene) {
  3252. const frameState = scene._frameState;
  3253. if (scene.debugShowFrustumPlanes !== scene._debugShowFrustumPlanes) {
  3254. if (scene.debugShowFrustumPlanes) {
  3255. scene._debugFrustumPlanes = new DebugCameraPrimitive({
  3256. camera: scene.camera,
  3257. updateOnChange: false,
  3258. frustumSplits: frameState.frustumSplits,
  3259. });
  3260. } else {
  3261. scene._debugFrustumPlanes =
  3262. scene._debugFrustumPlanes && scene._debugFrustumPlanes.destroy();
  3263. }
  3264. scene._debugShowFrustumPlanes = scene.debugShowFrustumPlanes;
  3265. }
  3266. if (defined(scene._debugFrustumPlanes)) {
  3267. scene._debugFrustumPlanes.update(frameState);
  3268. }
  3269. }
  3270. function updateShadowMaps(scene) {
  3271. const frameState = scene._frameState;
  3272. const { passes, shadowState, shadowMaps } = frameState;
  3273. const length = shadowMaps.length;
  3274. const shadowsEnabled =
  3275. length > 0 &&
  3276. !passes.pick &&
  3277. !passes.pickVoxel &&
  3278. scene.mode === SceneMode.SCENE3D;
  3279. if (shadowsEnabled !== shadowState.shadowsEnabled) {
  3280. // Update derived commands when shadowsEnabled changes
  3281. ++shadowState.lastDirtyTime;
  3282. shadowState.shadowsEnabled = shadowsEnabled;
  3283. }
  3284. shadowState.lightShadowsEnabled = false;
  3285. if (!shadowsEnabled) {
  3286. return;
  3287. }
  3288. // Check if the shadow maps are different than the shadow maps last frame.
  3289. // If so, the derived commands need to be updated.
  3290. for (let j = 0; j < length; ++j) {
  3291. if (shadowMaps[j] !== shadowState.shadowMaps[j]) {
  3292. ++shadowState.lastDirtyTime;
  3293. break;
  3294. }
  3295. }
  3296. shadowState.shadowMaps.length = 0;
  3297. shadowState.lightShadowMaps.length = 0;
  3298. for (let i = 0; i < length; ++i) {
  3299. const shadowMap = shadowMaps[i];
  3300. shadowMap.update(frameState);
  3301. shadowState.shadowMaps.push(shadowMap);
  3302. if (shadowMap.fromLightSource) {
  3303. shadowState.lightShadowMaps.push(shadowMap);
  3304. shadowState.lightShadowsEnabled = true;
  3305. }
  3306. if (shadowMap.dirty) {
  3307. ++shadowState.lastDirtyTime;
  3308. shadowMap.dirty = false;
  3309. }
  3310. }
  3311. }
  3312. function updateAndRenderPrimitives(scene) {
  3313. const frameState = scene._frameState;
  3314. // Reset per-frame edge visibility request flag before primitives update
  3315. frameState.edgeVisibilityRequested = false;
  3316. scene._groundPrimitives.update(frameState);
  3317. scene._primitives.update(frameState);
  3318. // If any primitive requested edge visibility this frame, flip the scene flag lazily.
  3319. if (
  3320. frameState.edgeVisibilityRequested &&
  3321. scene._enableEdgeVisibility === false
  3322. ) {
  3323. scene._enableEdgeVisibility = true;
  3324. }
  3325. updateDebugFrustumPlanes(scene);
  3326. updateShadowMaps(scene);
  3327. if (scene._globe) {
  3328. scene._globe.render(frameState);
  3329. }
  3330. }
  3331. function updateAndClearFramebuffers(scene, passState, clearColor) {
  3332. const context = scene._context;
  3333. const frameState = scene._frameState;
  3334. const environmentState = scene._environmentState;
  3335. const view = scene._view;
  3336. const passes = frameState.passes;
  3337. const picking = passes.pick || passes.pickVoxel;
  3338. if (defined(view.globeDepth)) {
  3339. view.globeDepth.picking = picking;
  3340. }
  3341. const useWebVR = environmentState.useWebVR;
  3342. // Preserve the reference to the original framebuffer.
  3343. environmentState.originalFramebuffer = passState.framebuffer;
  3344. // Manage sun bloom post-processing effect.
  3345. if (defined(scene.sun) && scene.sunBloom !== scene._sunBloom) {
  3346. if (scene.sunBloom && !useWebVR) {
  3347. scene._sunPostProcess = new SunPostProcess();
  3348. } else if (defined(scene._sunPostProcess)) {
  3349. scene._sunPostProcess = scene._sunPostProcess.destroy();
  3350. }
  3351. scene._sunBloom = scene.sunBloom;
  3352. } else if (!defined(scene.sun) && defined(scene._sunPostProcess)) {
  3353. scene._sunPostProcess = scene._sunPostProcess.destroy();
  3354. scene._sunBloom = false;
  3355. }
  3356. // Clear the pass state framebuffer.
  3357. const clear = scene._clearColorCommand;
  3358. Color.clone(clearColor, clear.color);
  3359. clear.execute(context, passState);
  3360. // Update globe depth rendering based on the current context and clear the globe depth framebuffer.
  3361. // Globe depth is copied for the pick pass to support picking batched geometries in GroundPrimitives.
  3362. const useGlobeDepthFramebuffer = (environmentState.useGlobeDepthFramebuffer =
  3363. defined(view.globeDepth));
  3364. if (useGlobeDepthFramebuffer) {
  3365. view.globeDepth.update(
  3366. context,
  3367. passState,
  3368. view.viewport,
  3369. scene.msaaSamples,
  3370. scene._hdr,
  3371. environmentState.clearGlobeDepth,
  3372. );
  3373. view.globeDepth.clear(context, passState, clearColor);
  3374. }
  3375. // If supported, configure OIT to use the globe depth framebuffer and clear the OIT framebuffer.
  3376. const oit = view.oit;
  3377. const useOIT = (environmentState.useOIT =
  3378. !picking && defined(oit) && oit.isSupported());
  3379. if (useOIT) {
  3380. oit.update(
  3381. context,
  3382. passState,
  3383. view.globeDepth.colorFramebufferManager,
  3384. scene._hdr,
  3385. scene.msaaSamples,
  3386. );
  3387. oit.clear(context, passState, clearColor);
  3388. environmentState.useOIT = oit.isSupported();
  3389. }
  3390. const postProcess = scene.postProcessStages;
  3391. let usePostProcess = (environmentState.usePostProcess =
  3392. !picking &&
  3393. (scene._hdr ||
  3394. postProcess.length > 0 ||
  3395. postProcess.ambientOcclusion.enabled ||
  3396. postProcess.fxaa.enabled ||
  3397. postProcess.bloom.enabled));
  3398. environmentState.usePostProcessSelected = false;
  3399. if (usePostProcess) {
  3400. view.sceneFramebuffer.update(
  3401. context,
  3402. view.viewport,
  3403. scene._hdr,
  3404. scene.msaaSamples,
  3405. );
  3406. view.sceneFramebuffer.clear(context, passState, clearColor);
  3407. postProcess.update(context, frameState.useLogDepth, scene._hdr);
  3408. postProcess.clear(context);
  3409. usePostProcess = environmentState.usePostProcess = postProcess.ready;
  3410. environmentState.usePostProcessSelected =
  3411. usePostProcess && postProcess.hasSelected;
  3412. }
  3413. if (environmentState.isSunVisible && scene.sunBloom && !useWebVR) {
  3414. passState.framebuffer = scene._sunPostProcess.update(passState);
  3415. scene._sunPostProcess.clear(context, passState, clearColor);
  3416. } else if (useGlobeDepthFramebuffer) {
  3417. passState.framebuffer = view.globeDepth.framebuffer;
  3418. } else if (usePostProcess) {
  3419. passState.framebuffer = view.sceneFramebuffer.framebuffer;
  3420. }
  3421. if (defined(passState.framebuffer)) {
  3422. clear.execute(context, passState);
  3423. }
  3424. const useInvertClassification = (environmentState.useInvertClassification =
  3425. !picking && defined(passState.framebuffer) && scene.invertClassification);
  3426. // Update edge framebuffer for 3D tile edge rendering
  3427. const useEdgeFramebuffer = !picking && scene._enableEdgeVisibility;
  3428. if (useEdgeFramebuffer) {
  3429. view.edgeFramebuffer.update(context, view.viewport, scene._hdr);
  3430. }
  3431. if (useInvertClassification) {
  3432. let depthFramebuffer;
  3433. if (frameState.invertClassificationColor.alpha === 1.0) {
  3434. if (useGlobeDepthFramebuffer) {
  3435. depthFramebuffer = view.globeDepth.framebuffer;
  3436. }
  3437. }
  3438. if (defined(depthFramebuffer) || context.depthTexture) {
  3439. scene._invertClassification.previousFramebuffer = depthFramebuffer;
  3440. scene._invertClassification.update(
  3441. context,
  3442. scene.msaaSamples,
  3443. view.globeDepth.colorFramebufferManager,
  3444. );
  3445. scene._invertClassification.clear(context, passState);
  3446. if (frameState.invertClassificationColor.alpha < 1.0 && useOIT) {
  3447. const command = scene._invertClassification.unclassifiedCommand;
  3448. const derivedCommands = command.derivedCommands;
  3449. derivedCommands.oit = oit.createDerivedCommands(
  3450. command,
  3451. context,
  3452. derivedCommands.oit,
  3453. );
  3454. }
  3455. } else {
  3456. environmentState.useInvertClassification = false;
  3457. }
  3458. }
  3459. if (scene._globeTranslucencyState.translucent) {
  3460. view.globeTranslucencyFramebuffer.updateAndClear(
  3461. scene._hdr,
  3462. view.viewport,
  3463. context,
  3464. passState,
  3465. );
  3466. }
  3467. }
  3468. /**
  3469. * @private
  3470. */
  3471. Scene.prototype.resolveFramebuffers = function (passState) {
  3472. const context = this._context;
  3473. const environmentState = this._environmentState;
  3474. const view = this._view;
  3475. const { globeDepth, translucentTileClassification } = view;
  3476. if (defined(globeDepth)) {
  3477. globeDepth.prepareColorTextures(context);
  3478. }
  3479. const {
  3480. useOIT,
  3481. useGlobeDepthFramebuffer,
  3482. usePostProcess,
  3483. originalFramebuffer,
  3484. } = environmentState;
  3485. const globeFramebuffer = useGlobeDepthFramebuffer
  3486. ? globeDepth.colorFramebufferManager
  3487. : undefined;
  3488. const sceneFramebuffer = view.sceneFramebuffer._colorFramebuffer;
  3489. const idFramebuffer = view.sceneFramebuffer.idFramebuffer;
  3490. if (useOIT) {
  3491. passState.framebuffer = usePostProcess
  3492. ? sceneFramebuffer.framebuffer
  3493. : originalFramebuffer;
  3494. view.oit.execute(context, passState);
  3495. }
  3496. if (
  3497. translucentTileClassification.hasTranslucentDepth &&
  3498. translucentTileClassification.isSupported()
  3499. ) {
  3500. translucentTileClassification.execute(this, passState);
  3501. }
  3502. if (usePostProcess) {
  3503. view.sceneFramebuffer.prepareColorTextures(context);
  3504. let inputFramebuffer = sceneFramebuffer;
  3505. if (useGlobeDepthFramebuffer && !useOIT) {
  3506. inputFramebuffer = globeFramebuffer;
  3507. }
  3508. const postProcess = this.postProcessStages;
  3509. const colorTexture = inputFramebuffer.getColorTexture(0);
  3510. const idTexture = idFramebuffer.getColorTexture(0);
  3511. const depthTexture = (
  3512. globeFramebuffer ?? sceneFramebuffer
  3513. ).getDepthStencilTexture();
  3514. postProcess.execute(context, colorTexture, depthTexture, idTexture);
  3515. postProcess.copy(context, originalFramebuffer);
  3516. }
  3517. if (!useOIT && !usePostProcess && useGlobeDepthFramebuffer) {
  3518. passState.framebuffer = originalFramebuffer;
  3519. globeDepth.executeCopyColor(context, passState);
  3520. }
  3521. };
  3522. function callAfterRenderFunctions(scene) {
  3523. // Functions are queued up during primitive update and executed here in case
  3524. // the function modifies scene state that should remain constant over the frame.
  3525. const functions = scene._frameState.afterRender;
  3526. const functionsCpy = functions.slice(); // Snapshot before iterate allows callbacks to add functions for next frame
  3527. functions.length = 0;
  3528. for (let i = 0; i < functionsCpy.length; ++i) {
  3529. const shouldRequestRender = functionsCpy[i]();
  3530. if (shouldRequestRender) {
  3531. scene.requestRender();
  3532. }
  3533. }
  3534. }
  3535. function getGlobeHeight(scene) {
  3536. if (scene.mode === SceneMode.MORPHING) {
  3537. return;
  3538. }
  3539. const cartographic = scene.camera.positionCartographic;
  3540. return scene.getHeight(cartographic);
  3541. }
  3542. function getMaxPrimitiveHeight(primitive, cartographic, scene) {
  3543. let maxHeight = Number.NEGATIVE_INFINITY;
  3544. if (primitive instanceof PrimitiveCollection) {
  3545. // If it's a PrimitiveCollection, iterate through its children
  3546. const length = primitive.length;
  3547. for (let i = 0; i < length; ++i) {
  3548. const subPrimitive = primitive.get(i);
  3549. const subHeight = getMaxPrimitiveHeight(
  3550. subPrimitive,
  3551. cartographic,
  3552. scene,
  3553. );
  3554. if (defined(subHeight) && subHeight > maxHeight) {
  3555. maxHeight = subHeight;
  3556. }
  3557. }
  3558. } else if (
  3559. primitive.isCesium3DTileset &&
  3560. primitive.show &&
  3561. primitive.enableCollision
  3562. ) {
  3563. // If it's an individual primitive, check its height
  3564. const result = primitive.getHeight(cartographic, scene);
  3565. if (defined(result) && result > maxHeight) {
  3566. return result;
  3567. }
  3568. }
  3569. return maxHeight;
  3570. }
  3571. /**
  3572. * Gets the height of the loaded surface at the cartographic position.
  3573. * @param {Cartographic} cartographic The cartographic position.
  3574. * @param {HeightReference} [heightReference=CLAMP_TO_GROUND] Based on the height reference value, determines whether to ignore heights from 3D Tiles or terrain.
  3575. * @private
  3576. */
  3577. Scene.prototype.getHeight = function (cartographic, heightReference) {
  3578. if (!defined(cartographic)) {
  3579. return undefined;
  3580. }
  3581. const ignore3dTiles =
  3582. heightReference === HeightReference.CLAMP_TO_TERRAIN ||
  3583. heightReference === HeightReference.RELATIVE_TO_TERRAIN;
  3584. const ignoreTerrain =
  3585. heightReference === HeightReference.CLAMP_TO_3D_TILE ||
  3586. heightReference === HeightReference.RELATIVE_TO_3D_TILE;
  3587. if (!defined(cartographic)) {
  3588. return;
  3589. }
  3590. let maxHeight = Number.NEGATIVE_INFINITY;
  3591. if (!ignore3dTiles) {
  3592. const maxPrimitiveHeight = getMaxPrimitiveHeight(
  3593. this.primitives,
  3594. cartographic,
  3595. this,
  3596. );
  3597. if (defined(maxPrimitiveHeight) && maxPrimitiveHeight > maxHeight) {
  3598. maxHeight = maxPrimitiveHeight;
  3599. }
  3600. }
  3601. const globe = this._globe;
  3602. if (!ignoreTerrain && defined(globe) && globe.show) {
  3603. const result = globe.getHeight(cartographic);
  3604. if (result > maxHeight) {
  3605. maxHeight = result;
  3606. }
  3607. }
  3608. if (maxHeight > Number.NEGATIVE_INFINITY) {
  3609. return maxHeight;
  3610. }
  3611. return undefined;
  3612. };
  3613. const updateHeightScratchCartographic = new Cartographic();
  3614. /**
  3615. * Calls the callback when a new tile is rendered that contains the given cartographic. The only parameter
  3616. * is the cartesian position on the tile.
  3617. *
  3618. * @private
  3619. *
  3620. * @param {Cartographic} cartographic The cartographic position.
  3621. * @param {Function} callback The function to be called when a new tile is loaded containing the updated cartographic.
  3622. * @param {HeightReference} [heightReference=CLAMP_TO_GROUND] Based on the height reference value, determines whether to ignore heights from 3D Tiles or terrain.
  3623. * @returns {Function} The function to remove this callback from the quadtree.
  3624. */
  3625. Scene.prototype.updateHeight = function (
  3626. cartographic,
  3627. callback,
  3628. heightReference,
  3629. ) {
  3630. //>>includeStart('debug', pragmas.debug);
  3631. Check.typeOf.func("callback", callback);
  3632. //>>includeEnd('debug');
  3633. const ellipsoid = this._ellipsoid;
  3634. const callbackWrapper = (clampedCartographic) => {
  3635. Cartographic.clone(cartographic, updateHeightScratchCartographic);
  3636. let height;
  3637. if (defined(clampedCartographic)) {
  3638. height = clampedCartographic.height;
  3639. }
  3640. if (!defined(height)) {
  3641. height = this.getHeight(cartographic, heightReference);
  3642. }
  3643. if (defined(height)) {
  3644. updateHeightScratchCartographic.height = height;
  3645. callback(updateHeightScratchCartographic);
  3646. }
  3647. };
  3648. const ignore3dTiles =
  3649. heightReference === HeightReference.CLAMP_TO_TERRAIN ||
  3650. heightReference === HeightReference.RELATIVE_TO_TERRAIN;
  3651. const ignoreTerrain =
  3652. heightReference === HeightReference.CLAMP_TO_3D_TILE ||
  3653. heightReference === HeightReference.RELATIVE_TO_3D_TILE;
  3654. let terrainRemoveCallback;
  3655. if (!ignoreTerrain && defined(this.globe)) {
  3656. terrainRemoveCallback = this.globe._surface.updateHeight(
  3657. cartographic,
  3658. callbackWrapper,
  3659. );
  3660. }
  3661. let tilesetRemoveCallbacks = {};
  3662. const createPrimitiveEventListener = (primitive) => {
  3663. if (
  3664. ignore3dTiles ||
  3665. primitive.isDestroyed() ||
  3666. !primitive.isCesium3DTileset
  3667. ) {
  3668. return;
  3669. }
  3670. const tilesetRemoveCallback = primitive.updateHeight(
  3671. cartographic,
  3672. callbackWrapper,
  3673. ellipsoid,
  3674. );
  3675. tilesetRemoveCallbacks[primitive.id] = tilesetRemoveCallback;
  3676. };
  3677. if (!ignore3dTiles) {
  3678. const length = this.primitives.length;
  3679. for (let i = 0; i < length; ++i) {
  3680. const primitive = this.primitives.get(i);
  3681. createPrimitiveEventListener(primitive);
  3682. }
  3683. }
  3684. const removeAddedListener = this.primitives.primitiveAdded.addEventListener(
  3685. createPrimitiveEventListener,
  3686. );
  3687. const removeRemovedListener =
  3688. this.primitives.primitiveRemoved.addEventListener((primitive) => {
  3689. if (primitive.isDestroyed() || !primitive.isCesium3DTileset) {
  3690. return;
  3691. }
  3692. if (defined(tilesetRemoveCallbacks[primitive.id])) {
  3693. tilesetRemoveCallbacks[primitive.id]();
  3694. }
  3695. delete tilesetRemoveCallbacks[primitive.id];
  3696. });
  3697. const removeCallback = () => {
  3698. terrainRemoveCallback = terrainRemoveCallback && terrainRemoveCallback();
  3699. Object.values(tilesetRemoveCallbacks).forEach((tilesetRemoveCallback) =>
  3700. tilesetRemoveCallback(),
  3701. );
  3702. tilesetRemoveCallbacks = {};
  3703. removeAddedListener();
  3704. removeRemovedListener();
  3705. };
  3706. return removeCallback;
  3707. };
  3708. function isCameraUnderground(scene) {
  3709. const camera = scene.camera;
  3710. const mode = scene._mode;
  3711. const cameraController = scene._screenSpaceCameraController;
  3712. const cartographic = camera.positionCartographic;
  3713. if (!defined(cartographic)) {
  3714. return false;
  3715. }
  3716. if (!cameraController.onMap() && cartographic.height < 0.0) {
  3717. // The camera can go off the map while in Columbus View.
  3718. // Make a best guess as to whether it's underground by checking if its height is less than zero.
  3719. return true;
  3720. }
  3721. if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
  3722. return false;
  3723. }
  3724. const globeHeight = scene._globeHeight;
  3725. return defined(globeHeight) && cartographic.height < globeHeight;
  3726. }
  3727. /**
  3728. * @private
  3729. */
  3730. Scene.prototype.initializeFrame = function () {
  3731. // Destroy released shaders and textures once every 120 frames to avoid thrashing the cache
  3732. if (this._shaderFrameCount++ === 120) {
  3733. this._shaderFrameCount = 0;
  3734. this._context.shaderCache.destroyReleasedShaderPrograms();
  3735. this._context.textureCache.destroyReleasedTextures();
  3736. }
  3737. this._tweens.update();
  3738. if (this._globeHeightDirty) {
  3739. if (defined(this._removeUpdateHeightCallback)) {
  3740. this._removeUpdateHeightCallback();
  3741. this._removeUpdateHeightCallback = undefined;
  3742. }
  3743. this._globeHeight = getGlobeHeight(this);
  3744. this._globeHeightDirty = false;
  3745. const cartographic = this.camera.positionCartographic;
  3746. this._removeUpdateHeightCallback = this.updateHeight(
  3747. cartographic,
  3748. (updatedCartographic) => {
  3749. if (this.isDestroyed()) {
  3750. return;
  3751. }
  3752. this._globeHeight = updatedCartographic.height;
  3753. },
  3754. );
  3755. }
  3756. this._cameraUnderground = isCameraUnderground(this);
  3757. this._globeTranslucencyState.update(this);
  3758. this._screenSpaceCameraController.update();
  3759. if (defined(this._deviceOrientationCameraController)) {
  3760. this._deviceOrientationCameraController.update();
  3761. }
  3762. this.camera.update(this._mode);
  3763. this.camera._updateCameraChanged();
  3764. };
  3765. function updateDebugShowFramesPerSecond(scene, renderedThisFrame) {
  3766. if (scene.debugShowFramesPerSecond) {
  3767. if (!defined(scene._performanceDisplay)) {
  3768. const performanceContainer = document.createElement("div");
  3769. performanceContainer.className =
  3770. "cesium-performanceDisplay-defaultContainer";
  3771. const container = scene._canvas.parentNode;
  3772. container.appendChild(performanceContainer);
  3773. const performanceDisplay = new PerformanceDisplay({
  3774. container: performanceContainer,
  3775. });
  3776. scene._performanceDisplay = performanceDisplay;
  3777. scene._performanceContainer = performanceContainer;
  3778. }
  3779. scene._performanceDisplay.throttled = scene.requestRenderMode;
  3780. scene._performanceDisplay.update(renderedThisFrame);
  3781. } else if (defined(scene._performanceDisplay)) {
  3782. scene._performanceDisplay =
  3783. scene._performanceDisplay && scene._performanceDisplay.destroy();
  3784. scene._performanceContainer.parentNode.removeChild(
  3785. scene._performanceContainer,
  3786. );
  3787. }
  3788. }
  3789. function prePassesUpdate(scene) {
  3790. scene._jobScheduler.resetBudgets();
  3791. const frameState = scene._frameState;
  3792. scene.primitives.prePassesUpdate(frameState);
  3793. if (defined(scene.globe)) {
  3794. scene.globe.update(frameState);
  3795. }
  3796. scene._picking.update();
  3797. frameState.creditDisplay.update();
  3798. }
  3799. function postPassesUpdate(scene) {
  3800. scene.primitives.postPassesUpdate(scene._frameState);
  3801. RequestScheduler.update();
  3802. }
  3803. const scratchBackgroundColor = new Color();
  3804. /**
  3805. * Render the scene
  3806. *
  3807. * @param {Scene} scene
  3808. * @private
  3809. */
  3810. function render(scene) {
  3811. const frameState = scene._frameState;
  3812. const context = scene.context;
  3813. const { uniformState } = context;
  3814. const view = scene._defaultView;
  3815. scene._view = view;
  3816. scene.updateFrameState();
  3817. frameState.passes.render = true;
  3818. frameState.passes.postProcess = scene.postProcessStages.hasSelected;
  3819. frameState.tilesetPassState = renderTilesetPassState;
  3820. let backgroundColor = scene.backgroundColor ?? Color.BLACK;
  3821. if (scene._hdr) {
  3822. backgroundColor = Color.clone(backgroundColor, scratchBackgroundColor);
  3823. backgroundColor.red = Math.pow(backgroundColor.red, scene.gamma);
  3824. backgroundColor.green = Math.pow(backgroundColor.green, scene.gamma);
  3825. backgroundColor.blue = Math.pow(backgroundColor.blue, scene.gamma);
  3826. }
  3827. frameState.backgroundColor = backgroundColor;
  3828. frameState.atmosphere = scene.atmosphere;
  3829. scene.fog.update(frameState);
  3830. uniformState.update(frameState);
  3831. const shadowMap = scene.shadowMap;
  3832. if (defined(shadowMap) && shadowMap.enabled) {
  3833. if (!defined(scene.light) || scene.light instanceof SunLight) {
  3834. // Negate the sun direction so that it is from the Sun, not to the Sun
  3835. Cartesian3.negate(
  3836. uniformState.sunDirectionWC,
  3837. scene._shadowMapCamera.direction,
  3838. );
  3839. } else {
  3840. Cartesian3.clone(scene.light.direction, scene._shadowMapCamera.direction);
  3841. }
  3842. frameState.shadowMaps.push(shadowMap);
  3843. }
  3844. scene._computeCommandList.length = 0;
  3845. scene._overlayCommandList.length = 0;
  3846. const viewport = view.viewport;
  3847. viewport.x = 0;
  3848. viewport.y = 0;
  3849. viewport.width = context.drawingBufferWidth;
  3850. viewport.height = context.drawingBufferHeight;
  3851. const passState = view.passState;
  3852. passState.framebuffer = undefined;
  3853. passState.blendingEnabled = undefined;
  3854. passState.scissorTest = undefined;
  3855. passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
  3856. context.beginFrame();
  3857. if (defined(scene.globe)) {
  3858. scene.globe.beginFrame(frameState);
  3859. }
  3860. scene.updateEnvironment();
  3861. scene.updateAndExecuteCommands(passState, backgroundColor);
  3862. scene.resolveFramebuffers(passState);
  3863. passState.framebuffer = undefined;
  3864. executeOverlayCommands(scene, passState);
  3865. if (defined(scene.globe)) {
  3866. scene.globe.endFrame(frameState);
  3867. if (!scene.globe.tilesLoaded) {
  3868. scene._renderRequested = true;
  3869. }
  3870. }
  3871. context.endFrame();
  3872. }
  3873. function tryAndCatchError(scene, functionToExecute) {
  3874. try {
  3875. functionToExecute(scene);
  3876. } catch (error) {
  3877. scene._renderError.raiseEvent(scene, error);
  3878. if (scene.rethrowRenderErrors) {
  3879. throw error;
  3880. }
  3881. }
  3882. }
  3883. function updateMostDetailedRayPicks(scene) {
  3884. return scene._picking.updateMostDetailedRayPicks(scene);
  3885. }
  3886. /**
  3887. * Update and render the scene. It is usually not necessary to call this function
  3888. * directly because {@link CesiumWidget} will do it automatically.
  3889. * @param {JulianDate} [time] The simulation time at which to render.
  3890. */
  3891. Scene.prototype.render = function (time) {
  3892. /**
  3893. *
  3894. * Pre passes update. Execute any pass invariant code that should run before the passes here.
  3895. *
  3896. */
  3897. this._preUpdate.raiseEvent(this, time);
  3898. const frameState = this._frameState;
  3899. frameState.newFrame = false;
  3900. if (!defined(time)) {
  3901. time = JulianDate.now();
  3902. }
  3903. const cameraChanged = this._view.checkForCameraUpdates(this);
  3904. if (cameraChanged) {
  3905. this._globeHeightDirty = true;
  3906. }
  3907. // Determine if should render a new frame in request render mode
  3908. let shouldRender =
  3909. !this.requestRenderMode ||
  3910. this._renderRequested ||
  3911. cameraChanged ||
  3912. this._logDepthBufferDirty ||
  3913. this._hdrDirty ||
  3914. this.mode === SceneMode.MORPHING;
  3915. if (
  3916. !shouldRender &&
  3917. defined(this.maximumRenderTimeChange) &&
  3918. defined(this._lastRenderTime)
  3919. ) {
  3920. const difference = Math.abs(
  3921. JulianDate.secondsDifference(this._lastRenderTime, time),
  3922. );
  3923. shouldRender = shouldRender || difference > this.maximumRenderTimeChange;
  3924. }
  3925. if (shouldRender) {
  3926. this._lastRenderTime = JulianDate.clone(time, this._lastRenderTime);
  3927. this._renderRequested = false;
  3928. this._logDepthBufferDirty = false;
  3929. this._hdrDirty = false;
  3930. const frameNumber = CesiumMath.incrementWrap(
  3931. frameState.frameNumber,
  3932. 15000000.0,
  3933. 1.0,
  3934. );
  3935. updateFrameNumber(this, frameNumber, time);
  3936. frameState.newFrame = true;
  3937. }
  3938. tryAndCatchError(this, prePassesUpdate);
  3939. /**
  3940. * Passes update. Add any passes here
  3941. */
  3942. if (this.primitives.show) {
  3943. tryAndCatchError(this, updateMostDetailedRayPicks);
  3944. tryAndCatchError(this, updatePreloadPass);
  3945. tryAndCatchError(this, updatePreloadFlightPass);
  3946. if (!shouldRender) {
  3947. tryAndCatchError(this, updateRequestRenderModeDeferCheckPass);
  3948. }
  3949. }
  3950. this._postUpdate.raiseEvent(this, time);
  3951. if (shouldRender) {
  3952. this._preRender.raiseEvent(this, time);
  3953. frameState.creditDisplay.beginFrame();
  3954. tryAndCatchError(this, render);
  3955. }
  3956. /**
  3957. * Post passes update. Execute any pass invariant code that should run after the passes here.
  3958. */
  3959. updateDebugShowFramesPerSecond(this, shouldRender);
  3960. tryAndCatchError(this, postPassesUpdate);
  3961. // Often used to trigger events (so don't want in trycatch) that the user
  3962. // might be subscribed to. Things like the tile load events, promises, etc.
  3963. // We don't want those events to resolve during the render loop because the events might add new primitives
  3964. callAfterRenderFunctions(this);
  3965. if (shouldRender) {
  3966. this._postRender.raiseEvent(this, time);
  3967. frameState.creditDisplay.endFrame();
  3968. }
  3969. };
  3970. /**
  3971. * Update and render the scene. Always forces a new render frame regardless of whether a render was
  3972. * previously requested.
  3973. * @param {JulianDate} [time] The simulation time at which to render.
  3974. *
  3975. * @private
  3976. */
  3977. Scene.prototype.forceRender = function (time) {
  3978. this._renderRequested = true;
  3979. this.render(time);
  3980. };
  3981. /**
  3982. * Requests a new rendered frame when {@link Scene#requestRenderMode} is set to <code>true</code>.
  3983. * The render rate will not exceed the {@link CesiumWidget#targetFrameRate}.
  3984. *
  3985. * @see Scene#requestRenderMode
  3986. */
  3987. Scene.prototype.requestRender = function () {
  3988. this._renderRequested = true;
  3989. };
  3990. /**
  3991. * @private
  3992. */
  3993. Scene.prototype.clampLineWidth = function (width) {
  3994. return Math.max(
  3995. ContextLimits.minimumAliasedLineWidth,
  3996. Math.min(width, ContextLimits.maximumAliasedLineWidth),
  3997. );
  3998. };
  3999. /**
  4000. * Returns an object with a <code>primitive</code> property that contains the first (top) primitive in the scene
  4001. * at a particular window coordinate or <code>undefined</code> if nothing is at the location. Other properties may
  4002. * potentially be set depending on the type of primitive and may be used to further identify the picked object.
  4003. * <p>
  4004. * When a feature of a 3D Tiles tileset is picked, <code>pick</code> returns a {@link Cesium3DTileFeature} object.
  4005. * </p>
  4006. *
  4007. * @example
  4008. * // On mouse over, color the feature yellow.
  4009. * handler.setInputAction(function(movement) {
  4010. * const feature = scene.pick(movement.endPosition);
  4011. * if (feature instanceof Cesium.Cesium3DTileFeature) {
  4012. * feature.color = Cesium.Color.YELLOW;
  4013. * }
  4014. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  4015. *
  4016. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4017. * @param {number} [width=3] Width of the pick rectangle.
  4018. * @param {number} [height=3] Height of the pick rectangle.
  4019. * @returns {object | undefined} Object containing the picked primitive or <code>undefined</code> if nothing is at the location.
  4020. */
  4021. Scene.prototype.pick = function (windowPosition, width, height) {
  4022. // Picking one object, result is either [object] or []
  4023. return this._picking.pick(this, windowPosition, width, height, 1)[0];
  4024. };
  4025. /**
  4026. * Performs the same operation as Scene.pick but asynchonosly without blocking the main render thread.
  4027. * Requires WebGL2 else using fallback.
  4028. *
  4029. * @example
  4030. * // On mouse over, color the feature yellow.
  4031. * handler.setInputAction(function(movement) {
  4032. * const feature = scene.pickAsync(movement.endPosition).then(function(feature) {
  4033. * if (feature instanceof Cesium.Cesium3DTileFeature) {
  4034. * feature.color = Cesium.Color.YELLOW;
  4035. * }
  4036. * });
  4037. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  4038. *
  4039. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4040. * @param {number} [width=3] Width of the pick rectangle.
  4041. * @param {number} [height=3] Height of the pick rectangle.
  4042. * @returns {Promise<Object | undefined>} Object containing the picked primitive or <code>undefined</code> if nothing is at the location.
  4043. *
  4044. * @see Scene#pick
  4045. */
  4046. Scene.prototype.pickAsync = async function (windowPosition, width, height) {
  4047. const result = await this._picking.pickAsync(
  4048. this,
  4049. windowPosition,
  4050. width,
  4051. height,
  4052. 1,
  4053. );
  4054. return result[0];
  4055. };
  4056. /**
  4057. * Returns a {@link VoxelCell} for the voxel sample rendered at a particular window coordinate,
  4058. * or <code>undefined</code> if no voxel is rendered at that position.
  4059. *
  4060. * @example
  4061. * On left click, report the value of the "color" property at that voxel sample.
  4062. * handler.setInputAction(function(movement) {
  4063. * const voxelCell = scene.pickVoxel(movement.position);
  4064. * if (defined(voxelCell)) {
  4065. * console.log(voxelCell.getProperty("color"));
  4066. * }
  4067. * }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  4068. *
  4069. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4070. * @param {number} [width=3] Width of the pick rectangle.
  4071. * @param {number} [height=3] Height of the pick rectangle.
  4072. * @returns {VoxelCell|undefined} Information about the voxel cell rendered at the picked position or <code>undefined</code> if no voxel is rendered at that position.
  4073. *
  4074. * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
  4075. */
  4076. Scene.prototype.pickVoxel = function (windowPosition, width, height) {
  4077. const pickedObject = this.pick(windowPosition, width, height);
  4078. if (!defined(pickedObject)) {
  4079. return;
  4080. }
  4081. const voxelPrimitive = pickedObject.primitive;
  4082. if (!(voxelPrimitive instanceof VoxelPrimitive)) {
  4083. return;
  4084. }
  4085. const voxelCoordinate = this._picking.pickVoxelCoordinate(
  4086. this,
  4087. windowPosition,
  4088. width,
  4089. height,
  4090. );
  4091. // Look up the keyframeNode containing this picked cell
  4092. const tileIndex = 255 * voxelCoordinate[0] + voxelCoordinate[1];
  4093. const keyframeNode = voxelPrimitive._traversal.findKeyframeNode(tileIndex);
  4094. if (!defined(keyframeNode)) {
  4095. // The tile rendered at the pick position has since been discarded by
  4096. // a traversal update
  4097. return;
  4098. }
  4099. // Look up the metadata for the picked cell
  4100. const sampleIndex = 255 * voxelCoordinate[2] + voxelCoordinate[3];
  4101. return VoxelCell.fromKeyframeNode(
  4102. voxelPrimitive,
  4103. tileIndex,
  4104. sampleIndex,
  4105. keyframeNode,
  4106. );
  4107. };
  4108. /**
  4109. * Pick a metadata value at the given window position.
  4110. *
  4111. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4112. * @param {string|undefined} schemaId The ID of the metadata schema to pick values
  4113. * from. If this is <code>undefined</code>, then it will pick the values from the object
  4114. * that match the given class- and property name, regardless of the schema ID.
  4115. * @param {string} className The name of the metadata class to pick
  4116. * values from
  4117. * @param {string} propertyName The name of the metadata property to pick
  4118. * values from
  4119. * @returns {MetadataValue|undefined} The metadata value, or <code>undefined</code> when
  4120. * no matching metadata was found at the given position
  4121. *
  4122. * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
  4123. */
  4124. Scene.prototype.pickMetadata = function (
  4125. windowPosition,
  4126. schemaId,
  4127. className,
  4128. propertyName,
  4129. ) {
  4130. //>>includeStart('debug', pragmas.debug);
  4131. Check.typeOf.object("windowPosition", windowPosition);
  4132. Check.typeOf.string("className", className);
  4133. Check.typeOf.string("propertyName", propertyName);
  4134. //>>includeEnd('debug');
  4135. const pickedObject = this.pick(windowPosition);
  4136. if (!defined(pickedObject)) {
  4137. return undefined;
  4138. }
  4139. // Check if the picked object is a model that has structural
  4140. // metadata, with a schema that contains the specified
  4141. // property.
  4142. const structuralMetadata = pickedObject.detail?.model?.structuralMetadata;
  4143. if (!defined(structuralMetadata)) {
  4144. return undefined;
  4145. }
  4146. const schema = structuralMetadata.schema;
  4147. const classProperty = getMetadataClassProperty(
  4148. schema,
  4149. schemaId,
  4150. className,
  4151. propertyName,
  4152. );
  4153. if (!defined(classProperty)) {
  4154. return undefined;
  4155. }
  4156. const metadataProperty = getMetadataProperty(
  4157. structuralMetadata,
  4158. className,
  4159. propertyName,
  4160. );
  4161. if (!defined(metadataProperty)) {
  4162. return undefined;
  4163. }
  4164. const pickedMetadataInfo = new PickedMetadataInfo(
  4165. schemaId,
  4166. className,
  4167. propertyName,
  4168. classProperty,
  4169. metadataProperty,
  4170. );
  4171. const pickedMetadataValues = this._picking.pickMetadata(
  4172. this,
  4173. windowPosition,
  4174. pickedMetadataInfo,
  4175. );
  4176. return pickedMetadataValues;
  4177. };
  4178. /**
  4179. * Pick the schema of the metadata of the object at the given position
  4180. *
  4181. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4182. * @returns {MetadataSchema | undefined} The metadata schema, or <code>undefined</code> if there is no object with
  4183. * associated metadata at the given position.
  4184. *
  4185. * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
  4186. */
  4187. Scene.prototype.pickMetadataSchema = function (windowPosition) {
  4188. //>>includeStart('debug', pragmas.debug);
  4189. Check.typeOf.object("windowPosition", windowPosition);
  4190. //>>includeEnd('debug');
  4191. const pickedObject = this.pick(windowPosition);
  4192. if (!defined(pickedObject)) {
  4193. return undefined;
  4194. }
  4195. const schema = pickedObject.detail?.model?.structuralMetadata?.schema;
  4196. return schema;
  4197. };
  4198. /**
  4199. * Returns the cartesian position reconstructed from the depth buffer and window position.
  4200. * The returned position is in world coordinates. Used internally by camera functions to
  4201. * prevent conversion to projected 2D coordinates and then back.
  4202. * <p>
  4203. * Set {@link Scene#pickTranslucentDepth} to <code>true</code> to include the depth of
  4204. * translucent primitives; otherwise, this essentially picks through translucent primitives.
  4205. * </p>
  4206. *
  4207. * @private
  4208. *
  4209. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4210. * @param {Cartesian3} [result] The object on which to restore the result.
  4211. * @returns {Cartesian3} The cartesian position in world coordinates.
  4212. *
  4213. * @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
  4214. */
  4215. Scene.prototype.pickPositionWorldCoordinates = function (
  4216. windowPosition,
  4217. result,
  4218. ) {
  4219. return this._picking.pickPositionWorldCoordinates(
  4220. this,
  4221. windowPosition,
  4222. result,
  4223. );
  4224. };
  4225. /**
  4226. * Returns the cartesian position reconstructed from the depth buffer and window position.
  4227. * <p>
  4228. * The position reconstructed from the depth buffer in 2D may be slightly different from those
  4229. * reconstructed in 3D and Columbus view. This is caused by the difference in the distribution
  4230. * of depth values of perspective and orthographic projection.
  4231. * </p>
  4232. * <p>
  4233. * Set {@link Scene#pickTranslucentDepth} to <code>true</code> to include the depth of
  4234. * translucent primitives; otherwise, this essentially picks through translucent primitives.
  4235. * </p>
  4236. *
  4237. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4238. * @param {Cartesian3} [result] The object on which to restore the result.
  4239. * @returns {Cartesian3} The cartesian position.
  4240. *
  4241. * @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
  4242. */
  4243. Scene.prototype.pickPosition = function (windowPosition, result) {
  4244. return this._picking.pickPosition(this, windowPosition, result);
  4245. };
  4246. /**
  4247. * Returns a list of objects, each containing a <code>primitive</code> property, for all primitives at
  4248. * a particular window coordinate position. Other properties may also be set depending on the
  4249. * type of primitive and may be used to further identify the picked object. The primitives in
  4250. * the list are ordered by their visual order in the scene (front to back).
  4251. *
  4252. * @param {Cartesian2} windowPosition Window coordinates to perform picking on.
  4253. * @param {number} [limit] If supplied, stop drilling after collecting this many picks.
  4254. * @param {number} [width=3] Width of the pick rectangle.
  4255. * @param {number} [height=3] Height of the pick rectangle.
  4256. * @returns {any[]} Array of objects, each containing 1 picked primitives.
  4257. *
  4258. * @exception {DeveloperError} windowPosition is undefined.
  4259. *
  4260. * @example
  4261. * const pickedObjects = scene.drillPick(new Cesium.Cartesian2(100.0, 200.0));
  4262. *
  4263. * @see Scene#pick
  4264. */
  4265. Scene.prototype.drillPick = function (windowPosition, limit, width, height) {
  4266. return this._picking.drillPick(this, windowPosition, limit, width, height);
  4267. };
  4268. function updatePreloadPass(scene) {
  4269. const frameState = scene._frameState;
  4270. preloadTilesetPassState.camera = frameState.camera;
  4271. preloadTilesetPassState.cullingVolume = frameState.cullingVolume;
  4272. const primitives = scene.primitives;
  4273. primitives.updateForPass(frameState, preloadTilesetPassState);
  4274. }
  4275. function updatePreloadFlightPass(scene) {
  4276. const frameState = scene._frameState;
  4277. const camera = frameState.camera;
  4278. if (!camera.canPreloadFlight()) {
  4279. return;
  4280. }
  4281. preloadFlightTilesetPassState.camera = scene.preloadFlightCamera;
  4282. preloadFlightTilesetPassState.cullingVolume =
  4283. scene.preloadFlightCullingVolume;
  4284. const primitives = scene.primitives;
  4285. primitives.updateForPass(frameState, preloadFlightTilesetPassState);
  4286. }
  4287. function updateRequestRenderModeDeferCheckPass(scene) {
  4288. // Check if any ignored requests are ready to go (to wake rendering up again)
  4289. scene.primitives.updateForPass(
  4290. scene._frameState,
  4291. requestRenderModeDeferCheckPassState,
  4292. );
  4293. }
  4294. /**
  4295. * Returns an object containing the first object intersected by the ray and the position of intersection,
  4296. * or <code>undefined</code> if there were no intersections. The intersected object has a <code>primitive</code>
  4297. * property that contains the intersected primitive. Other properties may be set depending on the type of primitive
  4298. * and may be used to further identify the picked object. The ray must be given in world coordinates.
  4299. * <p>
  4300. * This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
  4301. * primitives regardless of their visibility.
  4302. * </p>
  4303. *
  4304. * @private
  4305. *
  4306. * @param {Ray} ray The ray.
  4307. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  4308. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4309. * @returns {object | undefined} An object containing the object and position of the first intersection or <code>undefined</code> if there are no intersections.
  4310. *
  4311. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  4312. */
  4313. Scene.prototype.pickFromRay = function (ray, objectsToExclude, width) {
  4314. return this._picking.pickFromRay(this, ray, objectsToExclude, width);
  4315. };
  4316. /**
  4317. * Returns a list of objects, each containing the object intersected by the ray and the position of intersection.
  4318. * The intersected object has a <code>primitive</code> property that contains the intersected primitive. Other
  4319. * properties may also be set depending on the type of primitive and may be used to further identify the picked object.
  4320. * The primitives in the list are ordered by first intersection to last intersection. The ray must be given in
  4321. * world coordinates.
  4322. * <p>
  4323. * This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
  4324. * primitives regardless of their visibility.
  4325. * </p>
  4326. *
  4327. * @private
  4328. *
  4329. * @param {Ray} ray The ray.
  4330. * @param {number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
  4331. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  4332. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4333. * @returns {object[]} List of objects containing the object and position of each intersection.
  4334. *
  4335. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  4336. */
  4337. Scene.prototype.drillPickFromRay = function (
  4338. ray,
  4339. limit,
  4340. objectsToExclude,
  4341. width,
  4342. ) {
  4343. return this._picking.drillPickFromRay(
  4344. this,
  4345. ray,
  4346. limit,
  4347. objectsToExclude,
  4348. width,
  4349. );
  4350. };
  4351. /**
  4352. * Initiates an asynchronous {@link Scene#pickFromRay} request using the maximum level of detail for 3D Tilesets
  4353. * regardless of visibility.
  4354. *
  4355. * @private
  4356. *
  4357. * @param {Ray} ray The ray.
  4358. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  4359. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4360. * @returns {Promise<object>} A promise that resolves to an object containing the object and position of the first intersection.
  4361. *
  4362. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  4363. */
  4364. Scene.prototype.pickFromRayMostDetailed = function (
  4365. ray,
  4366. objectsToExclude,
  4367. width,
  4368. ) {
  4369. return this._picking.pickFromRayMostDetailed(
  4370. this,
  4371. ray,
  4372. objectsToExclude,
  4373. width,
  4374. );
  4375. };
  4376. /**
  4377. * Initiates an asynchronous {@link Scene#drillPickFromRay} request using the maximum level of detail for 3D Tilesets
  4378. * regardless of visibility.
  4379. *
  4380. * @private
  4381. *
  4382. * @param {Ray} ray The ray.
  4383. * @param {number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
  4384. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
  4385. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4386. * @returns {Promise<Object[]>} A promise that resolves to a list of objects containing the object and position of each intersection.
  4387. *
  4388. * @exception {DeveloperError} Ray intersections are only supported in 3D mode.
  4389. */
  4390. Scene.prototype.drillPickFromRayMostDetailed = function (
  4391. ray,
  4392. limit,
  4393. objectsToExclude,
  4394. width,
  4395. ) {
  4396. return this._picking.drillPickFromRayMostDetailed(
  4397. this,
  4398. ray,
  4399. limit,
  4400. objectsToExclude,
  4401. width,
  4402. );
  4403. };
  4404. /**
  4405. * Returns the height of scene geometry at the given cartographic position or <code>undefined</code> if there was no
  4406. * scene geometry to sample height from. The height of the input position is ignored. May be used to clamp objects to
  4407. * the globe, 3D Tiles, or primitives in the scene.
  4408. * <p>
  4409. * This function only samples height from globe tiles and 3D Tiles that are rendered in the current view. Samples height
  4410. * from all other primitives regardless of their visibility.
  4411. * </p>
  4412. *
  4413. * @param {Cartographic} position The cartographic position to sample height from.
  4414. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
  4415. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4416. * @returns {number | undefined} The height. This may be <code>undefined</code> if there was no scene geometry to sample height from.
  4417. *
  4418. * @example
  4419. * const position = new Cesium.Cartographic(-1.31968, 0.698874);
  4420. * const height = viewer.scene.sampleHeight(position);
  4421. * console.log(height);
  4422. *
  4423. * @see Scene#clampToHeight
  4424. * @see Scene#clampToHeightMostDetailed
  4425. * @see Scene#sampleHeightMostDetailed
  4426. *
  4427. * @exception {DeveloperError} sampleHeight is only supported in 3D mode.
  4428. * @exception {DeveloperError} sampleHeight requires depth texture support. Check sampleHeightSupported.
  4429. */
  4430. Scene.prototype.sampleHeight = function (position, objectsToExclude, width) {
  4431. return this._picking.sampleHeight(this, position, objectsToExclude, width);
  4432. };
  4433. /**
  4434. * Clamps the given cartesian position to the scene geometry along the geodetic surface normal. Returns the
  4435. * clamped position or <code>undefined</code> if there was no scene geometry to clamp to. May be used to clamp
  4436. * objects to the globe, 3D Tiles, or primitives in the scene.
  4437. * <p>
  4438. * This function only clamps to globe tiles and 3D Tiles that are rendered in the current view. Clamps to
  4439. * all other primitives regardless of their visibility.
  4440. * </p>
  4441. *
  4442. * @param {Cartesian3} cartesian The cartesian position.
  4443. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
  4444. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4445. * @param {Cartesian3} [result] An optional object to return the clamped position.
  4446. * @returns {Cartesian3 | undefined} 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.
  4447. *
  4448. * @example
  4449. * // Clamp an entity to the underlying scene geometry
  4450. * const position = entity.position.getValue(Cesium.JulianDate.now());
  4451. * entity.position = viewer.scene.clampToHeight(position);
  4452. *
  4453. * @see Scene#sampleHeight
  4454. * @see Scene#sampleHeightMostDetailed
  4455. * @see Scene#clampToHeightMostDetailed
  4456. *
  4457. * @exception {DeveloperError} clampToHeight is only supported in 3D mode.
  4458. * @exception {DeveloperError} clampToHeight requires depth texture support. Check clampToHeightSupported.
  4459. */
  4460. Scene.prototype.clampToHeight = function (
  4461. cartesian,
  4462. objectsToExclude,
  4463. width,
  4464. result,
  4465. ) {
  4466. return this._picking.clampToHeight(
  4467. this,
  4468. cartesian,
  4469. objectsToExclude,
  4470. width,
  4471. result,
  4472. );
  4473. };
  4474. /**
  4475. * Initiates an asynchronous {@link Scene#sampleHeight} query for an array of {@link Cartographic} positions
  4476. * using the maximum level of detail for 3D Tilesets in the scene. The height of the input positions is ignored.
  4477. * Returns a promise that is resolved when the query completes. Each point height is modified in place.
  4478. * If a height cannot be determined because no geometry can be sampled at that location, or another error occurs,
  4479. * the height is set to <code>undefined</code>.
  4480. *
  4481. * @param {Cartographic[]} positions The cartographic positions to update with sampled heights.
  4482. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
  4483. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4484. * @returns {Promise<Array<Cartographic | undefined>>} A promise that resolves to the provided list of positions when the query has completed. Positions may become <code>undefined</code> if the height cannot be determined.
  4485. *
  4486. * @example
  4487. * const positions = [
  4488. * new Cesium.Cartographic(-1.31968, 0.69887),
  4489. * new Cesium.Cartographic(-1.10489, 0.83923)
  4490. * ];
  4491. * const promise = viewer.scene.sampleHeightMostDetailed(positions);
  4492. * promise.then(function(updatedPosition) {
  4493. * // positions[0].height and positions[1].height have been updated.
  4494. * // updatedPositions is just a reference to positions.
  4495. * }
  4496. *
  4497. * @see Scene#sampleHeight
  4498. *
  4499. * @exception {DeveloperError} sampleHeightMostDetailed is only supported in 3D mode.
  4500. * @exception {DeveloperError} sampleHeightMostDetailed requires depth texture support. Check sampleHeightSupported.
  4501. */
  4502. Scene.prototype.sampleHeightMostDetailed = function (
  4503. positions,
  4504. objectsToExclude,
  4505. width,
  4506. ) {
  4507. return this._picking.sampleHeightMostDetailed(
  4508. this,
  4509. positions,
  4510. objectsToExclude,
  4511. width,
  4512. );
  4513. };
  4514. /**
  4515. * Initiates an asynchronous {@link Scene#clampToHeight} query for an array of {@link Cartesian3} positions
  4516. * using the maximum level of detail for 3D Tilesets in the scene. Returns a promise that is resolved when
  4517. * the query completes. Each position is modified in place. If a position cannot be clamped because no geometry
  4518. * can be sampled at that location, or another error occurs, the element in the array is set to undefined.
  4519. *
  4520. * @param {Cartesian3[]} cartesians The cartesian positions to update with clamped positions.
  4521. * @param {object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
  4522. * @param {number} [width=0.1] Width of the intersection volume in meters.
  4523. * @returns {Promise<Array<Cartesian3 | undefined>>} A promise that resolves to the provided list of positions when the query has completed. Positions may become <code>undefined</code> if they cannot be clamped.
  4524. *
  4525. * @example
  4526. * const cartesians = [
  4527. * entities[0].position.getValue(Cesium.JulianDate.now()),
  4528. * entities[1].position.getValue(Cesium.JulianDate.now())
  4529. * ];
  4530. * const promise = viewer.scene.clampToHeightMostDetailed(cartesians);
  4531. * promise.then(function(updatedCartesians) {
  4532. * entities[0].position = updatedCartesians[0];
  4533. * entities[1].position = updatedCartesians[1];
  4534. * }
  4535. *
  4536. * @see Scene#clampToHeight
  4537. *
  4538. * @exception {DeveloperError} clampToHeightMostDetailed is only supported in 3D mode.
  4539. * @exception {DeveloperError} clampToHeightMostDetailed requires depth texture support. Check clampToHeightSupported.
  4540. */
  4541. Scene.prototype.clampToHeightMostDetailed = function (
  4542. cartesians,
  4543. objectsToExclude,
  4544. width,
  4545. ) {
  4546. return this._picking.clampToHeightMostDetailed(
  4547. this,
  4548. cartesians,
  4549. objectsToExclude,
  4550. width,
  4551. );
  4552. };
  4553. /**
  4554. * Transforms a position in cartesian coordinates to canvas coordinates. This is commonly used to place an
  4555. * HTML element at the same screen position as an object in the scene.
  4556. *
  4557. * @param {Cartesian3} position The position in cartesian coordinates.
  4558. * @param {Cartesian2} [result] An optional object to return the input position transformed to canvas coordinates.
  4559. * @returns {Cartesian2 | undefined} 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.
  4560. *
  4561. * @example
  4562. * // Output the canvas position of longitude/latitude (0, 0) every time the mouse moves.
  4563. * const scene = widget.scene;
  4564. * const position = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
  4565. * const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
  4566. * handler.setInputAction(function(movement) {
  4567. * console.log(scene.cartesianToCanvasCoordinates(position));
  4568. * }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  4569. */
  4570. Scene.prototype.cartesianToCanvasCoordinates = function (position, result) {
  4571. return SceneTransforms.worldToWindowCoordinates(this, position, result);
  4572. };
  4573. /**
  4574. * Instantly completes an active transition.
  4575. */
  4576. Scene.prototype.completeMorph = function () {
  4577. this._transitioner.completeMorph();
  4578. };
  4579. /**
  4580. * Asynchronously transitions the scene to 2D.
  4581. * @param {number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  4582. */
  4583. Scene.prototype.morphTo2D = function (duration) {
  4584. duration = duration ?? 2.0;
  4585. this._transitioner.morphTo2D(duration, this._ellipsoid);
  4586. };
  4587. /**
  4588. * Asynchronously transitions the scene to Columbus View.
  4589. * @param {number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  4590. */
  4591. Scene.prototype.morphToColumbusView = function (duration) {
  4592. duration = duration ?? 2.0;
  4593. this._transitioner.morphToColumbusView(duration, this._ellipsoid);
  4594. };
  4595. /**
  4596. * Asynchronously transitions the scene to 3D.
  4597. * @param {number} [duration=2.0] The amount of time, in seconds, for transition animations to complete.
  4598. */
  4599. Scene.prototype.morphTo3D = function (duration) {
  4600. duration = duration ?? 2.0;
  4601. this._transitioner.morphTo3D(duration, this._ellipsoid);
  4602. };
  4603. function setTerrain(scene, terrain) {
  4604. // Cancel any in-progress terrain update
  4605. scene._removeTerrainProviderReadyListener =
  4606. scene._removeTerrainProviderReadyListener &&
  4607. scene._removeTerrainProviderReadyListener();
  4608. // If the terrain is already loaded, set it immediately
  4609. if (terrain.ready) {
  4610. if (defined(scene.globe)) {
  4611. scene.globe.terrainProvider = terrain.provider;
  4612. }
  4613. return;
  4614. }
  4615. // Otherwise, set a placeholder
  4616. scene.globe.terrainProvider = undefined;
  4617. scene._removeTerrainProviderReadyListener =
  4618. terrain.readyEvent.addEventListener((provider) => {
  4619. if (defined(scene) && defined(scene.globe)) {
  4620. scene.globe.terrainProvider = provider;
  4621. }
  4622. scene._removeTerrainProviderReadyListener();
  4623. });
  4624. }
  4625. /**
  4626. * Update the terrain providing surface geometry for the globe.
  4627. *
  4628. * @param {Terrain} terrain The terrain provider async helper
  4629. * @returns {Terrain} terrain The terrain provider async helper
  4630. *
  4631. * @example
  4632. * // Use Cesium World Terrain
  4633. * scene.setTerrain(Cesium.Terrain.fromWorldTerrain());
  4634. *
  4635. * @example
  4636. * // Use a custom terrain provider
  4637. * const terrain = new Cesium.Terrain(Cesium.CesiumTerrainProvider.fromUrl("https://myTestTerrain.com"));
  4638. * scene.setTerrain(terrain);
  4639. *
  4640. * terrain.errorEvent.addEventListener(error => {
  4641. * alert(`Encountered an error while creating terrain! ${error}`);
  4642. * });
  4643. */
  4644. Scene.prototype.setTerrain = function (terrain) {
  4645. //>>includeStart('debug', pragmas.debug);
  4646. Check.typeOf.object("terrain", terrain);
  4647. //>>includeEnd('debug');
  4648. setTerrain(this, terrain);
  4649. return terrain;
  4650. };
  4651. /**
  4652. * Returns true if this object was destroyed; otherwise, false.
  4653. * <br /><br />
  4654. * If this object was destroyed, it should not be used; calling any function other than
  4655. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  4656. *
  4657. * @returns {boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  4658. *
  4659. * @see Scene#destroy
  4660. */
  4661. Scene.prototype.isDestroyed = function () {
  4662. return false;
  4663. };
  4664. /**
  4665. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  4666. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  4667. * <br /><br />
  4668. * Once an object is destroyed, it should not be used; calling any function other than
  4669. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  4670. * assign the return value (<code>undefined</code>) to the object as done in the example.
  4671. *
  4672. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  4673. *
  4674. *
  4675. * @example
  4676. * scene = scene && scene.destroy();
  4677. *
  4678. * @see Scene#isDestroyed
  4679. */
  4680. Scene.prototype.destroy = function () {
  4681. this._tweens.removeAll();
  4682. this._computeEngine = this._computeEngine && this._computeEngine.destroy();
  4683. this._screenSpaceCameraController =
  4684. this._screenSpaceCameraController &&
  4685. this._screenSpaceCameraController.destroy();
  4686. this._deviceOrientationCameraController =
  4687. this._deviceOrientationCameraController &&
  4688. !this._deviceOrientationCameraController.isDestroyed() &&
  4689. this._deviceOrientationCameraController.destroy();
  4690. this._primitives = this._primitives && this._primitives.destroy();
  4691. this._groundPrimitives =
  4692. this._groundPrimitives && this._groundPrimitives.destroy();
  4693. this._globe = this._globe && this._globe.destroy();
  4694. this._removeTerrainProviderReadyListener =
  4695. this._removeTerrainProviderReadyListener &&
  4696. this._removeTerrainProviderReadyListener();
  4697. this.skyBox = this.skyBox && this.skyBox.destroy();
  4698. this.skyAtmosphere = this.skyAtmosphere && this.skyAtmosphere.destroy();
  4699. this._debugSphere = this._debugSphere && this._debugSphere.destroy();
  4700. this.sun = this.sun && this.sun.destroy();
  4701. this._sunPostProcess = this._sunPostProcess && this._sunPostProcess.destroy();
  4702. this._depthPlane = this._depthPlane && this._depthPlane.destroy();
  4703. this._transitioner = this._transitioner && this._transitioner.destroy();
  4704. this._debugFrustumPlanes =
  4705. this._debugFrustumPlanes && this._debugFrustumPlanes.destroy();
  4706. this._brdfLutGenerator =
  4707. this._brdfLutGenerator && this._brdfLutGenerator.destroy();
  4708. this._picking = this._picking && this._picking.destroy();
  4709. this._defaultView = this._defaultView && this._defaultView.destroy();
  4710. this._view = undefined;
  4711. if (this._removeCreditContainer) {
  4712. this._canvas.parentNode.removeChild(this._creditContainer);
  4713. }
  4714. this.postProcessStages =
  4715. this.postProcessStages && this.postProcessStages.destroy();
  4716. this._context = this._context && this._context.destroy();
  4717. this._frameState.creditDisplay =
  4718. this._frameState.creditDisplay && this._frameState.creditDisplay.destroy();
  4719. if (defined(this._performanceDisplay)) {
  4720. this._performanceDisplay =
  4721. this._performanceDisplay && this._performanceDisplay.destroy();
  4722. this._performanceContainer.parentNode.removeChild(
  4723. this._performanceContainer,
  4724. );
  4725. }
  4726. this._removeRequestListenerCallback();
  4727. this._removeTaskProcessorListenerCallback();
  4728. for (let i = 0; i < this._removeGlobeCallbacks.length; ++i) {
  4729. this._removeGlobeCallbacks[i]();
  4730. }
  4731. this._removeGlobeCallbacks.length = 0;
  4732. if (defined(this._removeUpdateHeightCallback)) {
  4733. this._removeUpdateHeightCallback();
  4734. this._removeUpdateHeightCallback = undefined;
  4735. }
  4736. return destroyObject(this);
  4737. };
  4738. export default Scene;