123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023 |
- class ObjectCollisionMatrix {
-
-
- constructor() {
- this.matrix = {};
- }
-
- get(bi, bj) {
- let {
- id: i
- } = bi;
- let {
- id: j
- } = bj;
- if (j > i) {
- const temp = j;
- j = i;
- i = temp;
- }
- return `${i}-${j}` in this.matrix;
- }
-
- set(bi, bj, value) {
- let {
- id: i
- } = bi;
- let {
- id: j
- } = bj;
- if (j > i) {
- const temp = j;
- j = i;
- i = temp;
- }
- if (value) {
- this.matrix[`${i}-${j}`] = true;
- } else {
- delete this.matrix[`${i}-${j}`];
- }
- }
-
- reset() {
- this.matrix = {};
- }
-
- setNumObjects(n) {}
- }
- class Mat3 {
-
-
- constructor(elements) {
- if (elements === void 0) {
- elements = [0, 0, 0, 0, 0, 0, 0, 0, 0];
- }
- this.elements = elements;
- }
-
- identity() {
- const e = this.elements;
- e[0] = 1;
- e[1] = 0;
- e[2] = 0;
- e[3] = 0;
- e[4] = 1;
- e[5] = 0;
- e[6] = 0;
- e[7] = 0;
- e[8] = 1;
- }
-
- setZero() {
- const e = this.elements;
- e[0] = 0;
- e[1] = 0;
- e[2] = 0;
- e[3] = 0;
- e[4] = 0;
- e[5] = 0;
- e[6] = 0;
- e[7] = 0;
- e[8] = 0;
- }
-
- setTrace(vector) {
- const e = this.elements;
- e[0] = vector.x;
- e[4] = vector.y;
- e[8] = vector.z;
- }
-
- getTrace(target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const e = this.elements;
- target.x = e[0];
- target.y = e[4];
- target.z = e[8];
- return target;
- }
-
- vmult(v, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const e = this.elements;
- const x = v.x;
- const y = v.y;
- const z = v.z;
- target.x = e[0] * x + e[1] * y + e[2] * z;
- target.y = e[3] * x + e[4] * y + e[5] * z;
- target.z = e[6] * x + e[7] * y + e[8] * z;
- return target;
- }
-
- smult(s) {
- for (let i = 0; i < this.elements.length; i++) {
- this.elements[i] *= s;
- }
- }
-
- mmult(matrix, target) {
- if (target === void 0) {
- target = new Mat3();
- }
- const A = this.elements;
- const B = matrix.elements;
- const T = target.elements;
- const a11 = A[0],
- a12 = A[1],
- a13 = A[2],
- a21 = A[3],
- a22 = A[4],
- a23 = A[5],
- a31 = A[6],
- a32 = A[7],
- a33 = A[8];
- const b11 = B[0],
- b12 = B[1],
- b13 = B[2],
- b21 = B[3],
- b22 = B[4],
- b23 = B[5],
- b31 = B[6],
- b32 = B[7],
- b33 = B[8];
- T[0] = a11 * b11 + a12 * b21 + a13 * b31;
- T[1] = a11 * b12 + a12 * b22 + a13 * b32;
- T[2] = a11 * b13 + a12 * b23 + a13 * b33;
- T[3] = a21 * b11 + a22 * b21 + a23 * b31;
- T[4] = a21 * b12 + a22 * b22 + a23 * b32;
- T[5] = a21 * b13 + a22 * b23 + a23 * b33;
- T[6] = a31 * b11 + a32 * b21 + a33 * b31;
- T[7] = a31 * b12 + a32 * b22 + a33 * b32;
- T[8] = a31 * b13 + a32 * b23 + a33 * b33;
- return target;
- }
-
- scale(vector, target) {
- if (target === void 0) {
- target = new Mat3();
- }
- const e = this.elements;
- const t = target.elements;
- for (let i = 0; i !== 3; i++) {
- t[3 * i + 0] = vector.x * e[3 * i + 0];
- t[3 * i + 1] = vector.y * e[3 * i + 1];
- t[3 * i + 2] = vector.z * e[3 * i + 2];
- }
- return target;
- }
-
- solve(b, target) {
- if (target === void 0) {
- target = new Vec3();
- }
-
- const nr = 3;
- const nc = 4;
- const eqns = [];
- let i;
- let j;
- for (i = 0; i < nr * nc; i++) {
- eqns.push(0);
- }
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++) {
- eqns[i + nc * j] = this.elements[i + 3 * j];
- }
- }
- eqns[3 + 4 * 0] = b.x;
- eqns[3 + 4 * 1] = b.y;
- eqns[3 + 4 * 2] = b.z;
- let n = 3;
- const k = n;
- let np;
- const kp = 4;
- let p;
- do {
- i = k - n;
- if (eqns[i + nc * i] === 0) {
-
- for (j = i + 1; j < k; j++) {
- if (eqns[i + nc * j] !== 0) {
- np = kp;
- do {
-
- p = kp - np;
- eqns[p + nc * i] += eqns[p + nc * j];
- } while (--np);
- break;
- }
- }
- }
- if (eqns[i + nc * i] !== 0) {
- for (j = i + 1; j < k; j++) {
- const multiplier = eqns[i + nc * j] / eqns[i + nc * i];
- np = kp;
- do {
-
- p = kp - np;
- eqns[p + nc * j] = p <= i ? 0 : eqns[p + nc * j] - eqns[p + nc * i] * multiplier;
- } while (--np);
- }
- }
- } while (--n);
- target.z = eqns[2 * nc + 3] / eqns[2 * nc + 2];
- target.y = (eqns[1 * nc + 3] - eqns[1 * nc + 2] * target.z) / eqns[1 * nc + 1];
- target.x = (eqns[0 * nc + 3] - eqns[0 * nc + 2] * target.z - eqns[0 * nc + 1] * target.y) / eqns[0 * nc + 0];
- if (isNaN(target.x) || isNaN(target.y) || isNaN(target.z) || target.x === Infinity || target.y === Infinity || target.z === Infinity) {
- throw `Could not solve equation! Got x=[${target.toString()}], b=[${b.toString()}], A=[${this.toString()}]`;
- }
- return target;
- }
-
- e(row, column, value) {
- if (value === undefined) {
- return this.elements[column + 3 * row];
- } else {
-
- this.elements[column + 3 * row] = value;
- }
- }
-
- copy(matrix) {
- for (let i = 0; i < matrix.elements.length; i++) {
- this.elements[i] = matrix.elements[i];
- }
- return this;
- }
-
- toString() {
- let r = '';
- const sep = ',';
- for (let i = 0; i < 9; i++) {
- r += this.elements[i] + sep;
- }
- return r;
- }
-
- reverse(target) {
- if (target === void 0) {
- target = new Mat3();
- }
-
- const nr = 3;
- const nc = 6;
- const eqns = reverse_eqns;
- let i;
- let j;
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++) {
- eqns[i + nc * j] = this.elements[i + 3 * j];
- }
- }
- eqns[3 + 6 * 0] = 1;
- eqns[3 + 6 * 1] = 0;
- eqns[3 + 6 * 2] = 0;
- eqns[4 + 6 * 0] = 0;
- eqns[4 + 6 * 1] = 1;
- eqns[4 + 6 * 2] = 0;
- eqns[5 + 6 * 0] = 0;
- eqns[5 + 6 * 1] = 0;
- eqns[5 + 6 * 2] = 1;
- let n = 3;
- const k = n;
- let np;
- const kp = nc;
- let p;
- do {
- i = k - n;
- if (eqns[i + nc * i] === 0) {
-
- for (j = i + 1; j < k; j++) {
- if (eqns[i + nc * j] !== 0) {
- np = kp;
- do {
-
- p = kp - np;
- eqns[p + nc * i] += eqns[p + nc * j];
- } while (--np);
- break;
- }
- }
- }
- if (eqns[i + nc * i] !== 0) {
- for (j = i + 1; j < k; j++) {
- const multiplier = eqns[i + nc * j] / eqns[i + nc * i];
- np = kp;
- do {
-
- p = kp - np;
- eqns[p + nc * j] = p <= i ? 0 : eqns[p + nc * j] - eqns[p + nc * i] * multiplier;
- } while (--np);
- }
- }
- } while (--n);
- i = 2;
- do {
- j = i - 1;
- do {
- const multiplier = eqns[i + nc * j] / eqns[i + nc * i];
- np = nc;
- do {
- p = nc - np;
- eqns[p + nc * j] = eqns[p + nc * j] - eqns[p + nc * i] * multiplier;
- } while (--np);
- } while (j--);
- } while (--i);
- i = 2;
- do {
- const multiplier = 1 / eqns[i + nc * i];
- np = nc;
- do {
- p = nc - np;
- eqns[p + nc * i] = eqns[p + nc * i] * multiplier;
- } while (--np);
- } while (i--);
- i = 2;
- do {
- j = 2;
- do {
- p = eqns[nr + j + nc * i];
- if (isNaN(p) || p === Infinity) {
- throw `Could not reverse! A=[${this.toString()}]`;
- }
- target.e(i, j, p);
- } while (j--);
- } while (i--);
- return target;
- }
-
- setRotationFromQuaternion(q) {
- const x = q.x;
- const y = q.y;
- const z = q.z;
- const w = q.w;
- const x2 = x + x;
- const y2 = y + y;
- const z2 = z + z;
- const xx = x * x2;
- const xy = x * y2;
- const xz = x * z2;
- const yy = y * y2;
- const yz = y * z2;
- const zz = z * z2;
- const wx = w * x2;
- const wy = w * y2;
- const wz = w * z2;
- const e = this.elements;
- e[3 * 0 + 0] = 1 - (yy + zz);
- e[3 * 0 + 1] = xy - wz;
- e[3 * 0 + 2] = xz + wy;
- e[3 * 1 + 0] = xy + wz;
- e[3 * 1 + 1] = 1 - (xx + zz);
- e[3 * 1 + 2] = yz - wx;
- e[3 * 2 + 0] = xz - wy;
- e[3 * 2 + 1] = yz + wx;
- e[3 * 2 + 2] = 1 - (xx + yy);
- return this;
- }
-
- transpose(target) {
- if (target === void 0) {
- target = new Mat3();
- }
- const M = this.elements;
- const T = target.elements;
- let tmp;
- T[0] = M[0];
- T[4] = M[4];
- T[8] = M[8];
- tmp = M[1];
- T[1] = M[3];
- T[3] = tmp;
- tmp = M[2];
- T[2] = M[6];
- T[6] = tmp;
- tmp = M[5];
- T[5] = M[7];
- T[7] = tmp;
- return target;
- }
- }
- const reverse_eqns = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
- class Vec3 {
- constructor(x, y, z) {
- if (x === void 0) {
- x = 0.0;
- }
- if (y === void 0) {
- y = 0.0;
- }
- if (z === void 0) {
- z = 0.0;
- }
- this.x = x;
- this.y = y;
- this.z = z;
- }
-
- cross(vector, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const vx = vector.x;
- const vy = vector.y;
- const vz = vector.z;
- const x = this.x;
- const y = this.y;
- const z = this.z;
- target.x = y * vz - z * vy;
- target.y = z * vx - x * vz;
- target.z = x * vy - y * vx;
- return target;
- }
-
- set(x, y, z) {
- this.x = x;
- this.y = y;
- this.z = z;
- return this;
- }
-
- setZero() {
- this.x = this.y = this.z = 0;
- }
-
- vadd(vector, target) {
- if (target) {
- target.x = vector.x + this.x;
- target.y = vector.y + this.y;
- target.z = vector.z + this.z;
- } else {
- return new Vec3(this.x + vector.x, this.y + vector.y, this.z + vector.z);
- }
- }
-
- vsub(vector, target) {
- if (target) {
- target.x = this.x - vector.x;
- target.y = this.y - vector.y;
- target.z = this.z - vector.z;
- } else {
- return new Vec3(this.x - vector.x, this.y - vector.y, this.z - vector.z);
- }
- }
-
- crossmat() {
- return new Mat3([0, -this.z, this.y, this.z, 0, -this.x, -this.y, this.x, 0]);
- }
-
- normalize() {
- const x = this.x;
- const y = this.y;
- const z = this.z;
- const n = Math.sqrt(x * x + y * y + z * z);
- if (n > 0.0) {
- const invN = 1 / n;
- this.x *= invN;
- this.y *= invN;
- this.z *= invN;
- } else {
-
- this.x = 0;
- this.y = 0;
- this.z = 0;
- }
- return n;
- }
-
- unit(target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const x = this.x;
- const y = this.y;
- const z = this.z;
- let ninv = Math.sqrt(x * x + y * y + z * z);
- if (ninv > 0.0) {
- ninv = 1.0 / ninv;
- target.x = x * ninv;
- target.y = y * ninv;
- target.z = z * ninv;
- } else {
- target.x = 1;
- target.y = 0;
- target.z = 0;
- }
- return target;
- }
-
- length() {
- const x = this.x;
- const y = this.y;
- const z = this.z;
- return Math.sqrt(x * x + y * y + z * z);
- }
-
- lengthSquared() {
- return this.dot(this);
- }
-
- distanceTo(p) {
- const x = this.x;
- const y = this.y;
- const z = this.z;
- const px = p.x;
- const py = p.y;
- const pz = p.z;
- return Math.sqrt((px - x) * (px - x) + (py - y) * (py - y) + (pz - z) * (pz - z));
- }
-
- distanceSquared(p) {
- const x = this.x;
- const y = this.y;
- const z = this.z;
- const px = p.x;
- const py = p.y;
- const pz = p.z;
- return (px - x) * (px - x) + (py - y) * (py - y) + (pz - z) * (pz - z);
- }
-
- scale(scalar, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const x = this.x;
- const y = this.y;
- const z = this.z;
- target.x = scalar * x;
- target.y = scalar * y;
- target.z = scalar * z;
- return target;
- }
-
- vmul(vector, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- target.x = vector.x * this.x;
- target.y = vector.y * this.y;
- target.z = vector.z * this.z;
- return target;
- }
-
- addScaledVector(scalar, vector, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- target.x = this.x + scalar * vector.x;
- target.y = this.y + scalar * vector.y;
- target.z = this.z + scalar * vector.z;
- return target;
- }
-
- dot(vector) {
- return this.x * vector.x + this.y * vector.y + this.z * vector.z;
- }
- isZero() {
- return this.x === 0 && this.y === 0 && this.z === 0;
- }
-
- negate(target) {
- if (target === void 0) {
- target = new Vec3();
- }
- target.x = -this.x;
- target.y = -this.y;
- target.z = -this.z;
- return target;
- }
-
- tangents(t1, t2) {
- const norm = this.length();
- if (norm > 0.0) {
- const n = Vec3_tangents_n;
- const inorm = 1 / norm;
- n.set(this.x * inorm, this.y * inorm, this.z * inorm);
- const randVec = Vec3_tangents_randVec;
- if (Math.abs(n.x) < 0.9) {
- randVec.set(1, 0, 0);
- n.cross(randVec, t1);
- } else {
- randVec.set(0, 1, 0);
- n.cross(randVec, t1);
- }
- n.cross(t1, t2);
- } else {
-
- t1.set(1, 0, 0);
- t2.set(0, 1, 0);
- }
- }
-
- toString() {
- return `${this.x},${this.y},${this.z}`;
- }
-
- toArray() {
- return [this.x, this.y, this.z];
- }
-
- copy(vector) {
- this.x = vector.x;
- this.y = vector.y;
- this.z = vector.z;
- return this;
- }
-
- lerp(vector, t, target) {
- const x = this.x;
- const y = this.y;
- const z = this.z;
- target.x = x + (vector.x - x) * t;
- target.y = y + (vector.y - y) * t;
- target.z = z + (vector.z - z) * t;
- }
-
- almostEquals(vector, precision) {
- if (precision === void 0) {
- precision = 1e-6;
- }
- if (Math.abs(this.x - vector.x) > precision || Math.abs(this.y - vector.y) > precision || Math.abs(this.z - vector.z) > precision) {
- return false;
- }
- return true;
- }
-
- almostZero(precision) {
- if (precision === void 0) {
- precision = 1e-6;
- }
- if (Math.abs(this.x) > precision || Math.abs(this.y) > precision || Math.abs(this.z) > precision) {
- return false;
- }
- return true;
- }
-
- isAntiparallelTo(vector, precision) {
- this.negate(antip_neg);
- return antip_neg.almostEquals(vector, precision);
- }
-
- clone() {
- return new Vec3(this.x, this.y, this.z);
- }
- }
- Vec3.ZERO = new Vec3(0, 0, 0);
- Vec3.UNIT_X = new Vec3(1, 0, 0);
- Vec3.UNIT_Y = new Vec3(0, 1, 0);
- Vec3.UNIT_Z = new Vec3(0, 0, 1);
- const Vec3_tangents_n = new Vec3();
- const Vec3_tangents_randVec = new Vec3();
- const antip_neg = new Vec3();
- class AABB {
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- this.lowerBound = new Vec3();
- this.upperBound = new Vec3();
- if (options.lowerBound) {
- this.lowerBound.copy(options.lowerBound);
- }
- if (options.upperBound) {
- this.upperBound.copy(options.upperBound);
- }
- }
-
- setFromPoints(points, position, quaternion, skinSize) {
- const l = this.lowerBound;
- const u = this.upperBound;
- const q = quaternion;
- l.copy(points[0]);
- if (q) {
- q.vmult(l, l);
- }
- u.copy(l);
- for (let i = 1; i < points.length; i++) {
- let p = points[i];
- if (q) {
- q.vmult(p, tmp$1);
- p = tmp$1;
- }
- if (p.x > u.x) {
- u.x = p.x;
- }
- if (p.x < l.x) {
- l.x = p.x;
- }
- if (p.y > u.y) {
- u.y = p.y;
- }
- if (p.y < l.y) {
- l.y = p.y;
- }
- if (p.z > u.z) {
- u.z = p.z;
- }
- if (p.z < l.z) {
- l.z = p.z;
- }
- }
- if (position) {
- position.vadd(l, l);
- position.vadd(u, u);
- }
- if (skinSize) {
- l.x -= skinSize;
- l.y -= skinSize;
- l.z -= skinSize;
- u.x += skinSize;
- u.y += skinSize;
- u.z += skinSize;
- }
- return this;
- }
-
- copy(aabb) {
- this.lowerBound.copy(aabb.lowerBound);
- this.upperBound.copy(aabb.upperBound);
- return this;
- }
-
- clone() {
- return new AABB().copy(this);
- }
-
- extend(aabb) {
- this.lowerBound.x = Math.min(this.lowerBound.x, aabb.lowerBound.x);
- this.upperBound.x = Math.max(this.upperBound.x, aabb.upperBound.x);
- this.lowerBound.y = Math.min(this.lowerBound.y, aabb.lowerBound.y);
- this.upperBound.y = Math.max(this.upperBound.y, aabb.upperBound.y);
- this.lowerBound.z = Math.min(this.lowerBound.z, aabb.lowerBound.z);
- this.upperBound.z = Math.max(this.upperBound.z, aabb.upperBound.z);
- }
-
- overlaps(aabb) {
- const l1 = this.lowerBound;
- const u1 = this.upperBound;
- const l2 = aabb.lowerBound;
- const u2 = aabb.upperBound;
-
-
-
- const overlapsX = l2.x <= u1.x && u1.x <= u2.x || l1.x <= u2.x && u2.x <= u1.x;
- const overlapsY = l2.y <= u1.y && u1.y <= u2.y || l1.y <= u2.y && u2.y <= u1.y;
- const overlapsZ = l2.z <= u1.z && u1.z <= u2.z || l1.z <= u2.z && u2.z <= u1.z;
- return overlapsX && overlapsY && overlapsZ;
- }
- volume() {
- const l = this.lowerBound;
- const u = this.upperBound;
- return (u.x - l.x) * (u.y - l.y) * (u.z - l.z);
- }
-
- contains(aabb) {
- const l1 = this.lowerBound;
- const u1 = this.upperBound;
- const l2 = aabb.lowerBound;
- const u2 = aabb.upperBound;
-
-
-
- return l1.x <= l2.x && u1.x >= u2.x && l1.y <= l2.y && u1.y >= u2.y && l1.z <= l2.z && u1.z >= u2.z;
- }
- getCorners(a, b, c, d, e, f, g, h) {
- const l = this.lowerBound;
- const u = this.upperBound;
- a.copy(l);
- b.set(u.x, l.y, l.z);
- c.set(u.x, u.y, l.z);
- d.set(l.x, u.y, u.z);
- e.set(u.x, l.y, u.z);
- f.set(l.x, u.y, l.z);
- g.set(l.x, l.y, u.z);
- h.copy(u);
- }
-
- toLocalFrame(frame, target) {
- const corners = transformIntoFrame_corners;
- const a = corners[0];
- const b = corners[1];
- const c = corners[2];
- const d = corners[3];
- const e = corners[4];
- const f = corners[5];
- const g = corners[6];
- const h = corners[7];
- this.getCorners(a, b, c, d, e, f, g, h);
- for (let i = 0; i !== 8; i++) {
- const corner = corners[i];
- frame.pointToLocal(corner, corner);
- }
- return target.setFromPoints(corners);
- }
-
- toWorldFrame(frame, target) {
- const corners = transformIntoFrame_corners;
- const a = corners[0];
- const b = corners[1];
- const c = corners[2];
- const d = corners[3];
- const e = corners[4];
- const f = corners[5];
- const g = corners[6];
- const h = corners[7];
- this.getCorners(a, b, c, d, e, f, g, h);
- for (let i = 0; i !== 8; i++) {
- const corner = corners[i];
- frame.pointToWorld(corner, corner);
- }
- return target.setFromPoints(corners);
- }
-
- overlapsRay(ray) {
- const {
- direction,
- from
- } = ray;
-
- const dirFracX = 1 / direction.x;
- const dirFracY = 1 / direction.y;
- const dirFracZ = 1 / direction.z;
- const t1 = (this.lowerBound.x - from.x) * dirFracX;
- const t2 = (this.upperBound.x - from.x) * dirFracX;
- const t3 = (this.lowerBound.y - from.y) * dirFracY;
- const t4 = (this.upperBound.y - from.y) * dirFracY;
- const t5 = (this.lowerBound.z - from.z) * dirFracZ;
- const t6 = (this.upperBound.z - from.z) * dirFracZ;
-
- const tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6));
- const tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6));
- if (tmax < 0) {
-
- return false;
- }
- if (tmin > tmax) {
-
- return false;
- }
- return true;
- }
- }
- const tmp$1 = new Vec3();
- const transformIntoFrame_corners = [new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3()];
- class ArrayCollisionMatrix {
-
- constructor() {
- this.matrix = [];
- }
-
- get(bi, bj) {
- let {
- index: i
- } = bi;
- let {
- index: j
- } = bj;
- if (j > i) {
- const temp = j;
- j = i;
- i = temp;
- }
- return this.matrix[(i * (i + 1) >> 1) + j - 1];
- }
-
- set(bi, bj, value) {
- let {
- index: i
- } = bi;
- let {
- index: j
- } = bj;
- if (j > i) {
- const temp = j;
- j = i;
- i = temp;
- }
- this.matrix[(i * (i + 1) >> 1) + j - 1] = value ? 1 : 0;
- }
-
- reset() {
- for (let i = 0, l = this.matrix.length; i !== l; i++) {
- this.matrix[i] = 0;
- }
- }
-
- setNumObjects(n) {
- this.matrix.length = n * (n - 1) >> 1;
- }
- }
- class EventTarget {
-
- addEventListener(type, listener) {
- if (this._listeners === undefined) {
- this._listeners = {};
- }
- const listeners = this._listeners;
- if (listeners[type] === undefined) {
- listeners[type] = [];
- }
- if (!listeners[type].includes(listener)) {
- listeners[type].push(listener);
- }
- return this;
- }
-
- hasEventListener(type, listener) {
- if (this._listeners === undefined) {
- return false;
- }
- const listeners = this._listeners;
- if (listeners[type] !== undefined && listeners[type].includes(listener)) {
- return true;
- }
- return false;
- }
-
- hasAnyEventListener(type) {
- if (this._listeners === undefined) {
- return false;
- }
- const listeners = this._listeners;
- return listeners[type] !== undefined;
- }
-
- removeEventListener(type, listener) {
- if (this._listeners === undefined) {
- return this;
- }
- const listeners = this._listeners;
- if (listeners[type] === undefined) {
- return this;
- }
- const index = listeners[type].indexOf(listener);
- if (index !== -1) {
- listeners[type].splice(index, 1);
- }
- return this;
- }
-
- dispatchEvent(event) {
- if (this._listeners === undefined) {
- return this;
- }
- const listeners = this._listeners;
- const listenerArray = listeners[event.type];
- if (listenerArray !== undefined) {
- event.target = this;
- for (let i = 0, l = listenerArray.length; i < l; i++) {
- listenerArray[i].call(this, event);
- }
- }
- return this;
- }
- }
- class Quaternion {
- constructor(x, y, z, w) {
- if (x === void 0) {
- x = 0;
- }
- if (y === void 0) {
- y = 0;
- }
- if (z === void 0) {
- z = 0;
- }
- if (w === void 0) {
- w = 1;
- }
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
- }
-
- set(x, y, z, w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
- return this;
- }
-
- toString() {
- return `${this.x},${this.y},${this.z},${this.w}`;
- }
-
- toArray() {
- return [this.x, this.y, this.z, this.w];
- }
-
- setFromAxisAngle(vector, angle) {
- const s = Math.sin(angle * 0.5);
- this.x = vector.x * s;
- this.y = vector.y * s;
- this.z = vector.z * s;
- this.w = Math.cos(angle * 0.5);
- return this;
- }
-
- toAxisAngle(targetAxis) {
- if (targetAxis === void 0) {
- targetAxis = new Vec3();
- }
- this.normalize();
- const angle = 2 * Math.acos(this.w);
- const s = Math.sqrt(1 - this.w * this.w);
- if (s < 0.001) {
-
-
- targetAxis.x = this.x;
- targetAxis.y = this.y;
- targetAxis.z = this.z;
- } else {
- targetAxis.x = this.x / s;
- targetAxis.y = this.y / s;
- targetAxis.z = this.z / s;
- }
- return [targetAxis, angle];
- }
-
- setFromVectors(u, v) {
- if (u.isAntiparallelTo(v)) {
- const t1 = sfv_t1;
- const t2 = sfv_t2;
- u.tangents(t1, t2);
- this.setFromAxisAngle(t1, Math.PI);
- } else {
- const a = u.cross(v);
- this.x = a.x;
- this.y = a.y;
- this.z = a.z;
- this.w = Math.sqrt(u.length() ** 2 * v.length() ** 2) + u.dot(v);
- this.normalize();
- }
- return this;
- }
-
- mult(quat, target) {
- if (target === void 0) {
- target = new Quaternion();
- }
- const ax = this.x;
- const ay = this.y;
- const az = this.z;
- const aw = this.w;
- const bx = quat.x;
- const by = quat.y;
- const bz = quat.z;
- const bw = quat.w;
- target.x = ax * bw + aw * bx + ay * bz - az * by;
- target.y = ay * bw + aw * by + az * bx - ax * bz;
- target.z = az * bw + aw * bz + ax * by - ay * bx;
- target.w = aw * bw - ax * bx - ay * by - az * bz;
- return target;
- }
-
- inverse(target) {
- if (target === void 0) {
- target = new Quaternion();
- }
- const x = this.x;
- const y = this.y;
- const z = this.z;
- const w = this.w;
- this.conjugate(target);
- const inorm2 = 1 / (x * x + y * y + z * z + w * w);
- target.x *= inorm2;
- target.y *= inorm2;
- target.z *= inorm2;
- target.w *= inorm2;
- return target;
- }
-
- conjugate(target) {
- if (target === void 0) {
- target = new Quaternion();
- }
- target.x = -this.x;
- target.y = -this.y;
- target.z = -this.z;
- target.w = this.w;
- return target;
- }
-
- normalize() {
- let l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
- if (l === 0) {
- this.x = 0;
- this.y = 0;
- this.z = 0;
- this.w = 0;
- } else {
- l = 1 / l;
- this.x *= l;
- this.y *= l;
- this.z *= l;
- this.w *= l;
- }
- return this;
- }
-
- normalizeFast() {
- const f = (3.0 - (this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w)) / 2.0;
- if (f === 0) {
- this.x = 0;
- this.y = 0;
- this.z = 0;
- this.w = 0;
- } else {
- this.x *= f;
- this.y *= f;
- this.z *= f;
- this.w *= f;
- }
- return this;
- }
-
- vmult(v, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const x = v.x;
- const y = v.y;
- const z = v.z;
- const qx = this.x;
- const qy = this.y;
- const qz = this.z;
- const qw = this.w;
- const ix = qw * x + qy * z - qz * y;
- const iy = qw * y + qz * x - qx * z;
- const iz = qw * z + qx * y - qy * x;
- const iw = -qx * x - qy * y - qz * z;
- target.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- target.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- target.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- return target;
- }
-
- copy(quat) {
- this.x = quat.x;
- this.y = quat.y;
- this.z = quat.z;
- this.w = quat.w;
- return this;
- }
-
- toEuler(target, order) {
- if (order === void 0) {
- order = 'YZX';
- }
- let heading;
- let attitude;
- let bank;
- const x = this.x;
- const y = this.y;
- const z = this.z;
- const w = this.w;
- switch (order) {
- case 'YZX':
- const test = x * y + z * w;
- if (test > 0.499) {
-
- heading = 2 * Math.atan2(x, w);
- attitude = Math.PI / 2;
- bank = 0;
- }
- if (test < -0.499) {
-
- heading = -2 * Math.atan2(x, w);
- attitude = -Math.PI / 2;
- bank = 0;
- }
- if (heading === undefined) {
- const sqx = x * x;
- const sqy = y * y;
- const sqz = z * z;
- heading = Math.atan2(2 * y * w - 2 * x * z, 1 - 2 * sqy - 2 * sqz);
- attitude = Math.asin(2 * test);
- bank = Math.atan2(2 * x * w - 2 * y * z, 1 - 2 * sqx - 2 * sqz);
- }
- break;
- default:
- throw new Error(`Euler order ${order} not supported yet.`);
- }
- target.y = heading;
- target.z = attitude;
- target.x = bank;
- }
-
- setFromEuler(x, y, z, order) {
- if (order === void 0) {
- order = 'XYZ';
- }
- const c1 = Math.cos(x / 2);
- const c2 = Math.cos(y / 2);
- const c3 = Math.cos(z / 2);
- const s1 = Math.sin(x / 2);
- const s2 = Math.sin(y / 2);
- const s3 = Math.sin(z / 2);
- if (order === 'XYZ') {
- this.x = s1 * c2 * c3 + c1 * s2 * s3;
- this.y = c1 * s2 * c3 - s1 * c2 * s3;
- this.z = c1 * c2 * s3 + s1 * s2 * c3;
- this.w = c1 * c2 * c3 - s1 * s2 * s3;
- } else if (order === 'YXZ') {
- this.x = s1 * c2 * c3 + c1 * s2 * s3;
- this.y = c1 * s2 * c3 - s1 * c2 * s3;
- this.z = c1 * c2 * s3 - s1 * s2 * c3;
- this.w = c1 * c2 * c3 + s1 * s2 * s3;
- } else if (order === 'ZXY') {
- this.x = s1 * c2 * c3 - c1 * s2 * s3;
- this.y = c1 * s2 * c3 + s1 * c2 * s3;
- this.z = c1 * c2 * s3 + s1 * s2 * c3;
- this.w = c1 * c2 * c3 - s1 * s2 * s3;
- } else if (order === 'ZYX') {
- this.x = s1 * c2 * c3 - c1 * s2 * s3;
- this.y = c1 * s2 * c3 + s1 * c2 * s3;
- this.z = c1 * c2 * s3 - s1 * s2 * c3;
- this.w = c1 * c2 * c3 + s1 * s2 * s3;
- } else if (order === 'YZX') {
- this.x = s1 * c2 * c3 + c1 * s2 * s3;
- this.y = c1 * s2 * c3 + s1 * c2 * s3;
- this.z = c1 * c2 * s3 - s1 * s2 * c3;
- this.w = c1 * c2 * c3 - s1 * s2 * s3;
- } else if (order === 'XZY') {
- this.x = s1 * c2 * c3 - c1 * s2 * s3;
- this.y = c1 * s2 * c3 - s1 * c2 * s3;
- this.z = c1 * c2 * s3 + s1 * s2 * c3;
- this.w = c1 * c2 * c3 + s1 * s2 * s3;
- }
- return this;
- }
- clone() {
- return new Quaternion(this.x, this.y, this.z, this.w);
- }
-
- slerp(toQuat, t, target) {
- if (target === void 0) {
- target = new Quaternion();
- }
- const ax = this.x;
- const ay = this.y;
- const az = this.z;
- const aw = this.w;
- let bx = toQuat.x;
- let by = toQuat.y;
- let bz = toQuat.z;
- let bw = toQuat.w;
- let omega;
- let cosom;
- let sinom;
- let scale0;
- let scale1;
- cosom = ax * bx + ay * by + az * bz + aw * bw;
- if (cosom < 0.0) {
- cosom = -cosom;
- bx = -bx;
- by = -by;
- bz = -bz;
- bw = -bw;
- }
- if (1.0 - cosom > 0.000001) {
-
- omega = Math.acos(cosom);
- sinom = Math.sin(omega);
- scale0 = Math.sin((1.0 - t) * omega) / sinom;
- scale1 = Math.sin(t * omega) / sinom;
- } else {
-
-
- scale0 = 1.0 - t;
- scale1 = t;
- }
- target.x = scale0 * ax + scale1 * bx;
- target.y = scale0 * ay + scale1 * by;
- target.z = scale0 * az + scale1 * bz;
- target.w = scale0 * aw + scale1 * bw;
- return target;
- }
-
- integrate(angularVelocity, dt, angularFactor, target) {
- if (target === void 0) {
- target = new Quaternion();
- }
- const ax = angularVelocity.x * angularFactor.x,
- ay = angularVelocity.y * angularFactor.y,
- az = angularVelocity.z * angularFactor.z,
- bx = this.x,
- by = this.y,
- bz = this.z,
- bw = this.w;
- const half_dt = dt * 0.5;
- target.x += half_dt * (ax * bw + ay * bz - az * by);
- target.y += half_dt * (ay * bw + az * bx - ax * bz);
- target.z += half_dt * (az * bw + ax * by - ay * bx);
- target.w += half_dt * (-ax * bx - ay * by - az * bz);
- return target;
- }
- }
- const sfv_t1 = new Vec3();
- const sfv_t2 = new Vec3();
- const SHAPE_TYPES = {
-
- SPHERE: 1,
-
- PLANE: 2,
-
- BOX: 4,
-
- COMPOUND: 8,
-
- CONVEXPOLYHEDRON: 16,
-
- HEIGHTFIELD: 32,
-
- PARTICLE: 64,
-
- CYLINDER: 128,
-
- TRIMESH: 256
- };
- class Shape {
-
-
-
-
-
-
-
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- this.id = Shape.idCounter++;
- this.type = options.type || 0;
- this.boundingSphereRadius = 0;
- this.collisionResponse = options.collisionResponse ? options.collisionResponse : true;
- this.collisionFilterGroup = options.collisionFilterGroup !== undefined ? options.collisionFilterGroup : 1;
- this.collisionFilterMask = options.collisionFilterMask !== undefined ? options.collisionFilterMask : -1;
- this.material = options.material ? options.material : null;
- this.body = null;
- }
-
- updateBoundingSphereRadius() {
- throw `computeBoundingSphereRadius() not implemented for shape type ${this.type}`;
- }
-
- volume() {
- throw `volume() not implemented for shape type ${this.type}`;
- }
-
- calculateLocalInertia(mass, target) {
- throw `calculateLocalInertia() not implemented for shape type ${this.type}`;
- }
-
- calculateWorldAABB(pos, quat, min, max) {
- throw `calculateWorldAABB() not implemented for shape type ${this.type}`;
- }
- }
- Shape.idCounter = 0;
- Shape.types = SHAPE_TYPES;
- class Transform {
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- this.position = new Vec3();
- this.quaternion = new Quaternion();
- if (options.position) {
- this.position.copy(options.position);
- }
- if (options.quaternion) {
- this.quaternion.copy(options.quaternion);
- }
- }
-
- pointToLocal(worldPoint, result) {
- return Transform.pointToLocalFrame(this.position, this.quaternion, worldPoint, result);
- }
-
- pointToWorld(localPoint, result) {
- return Transform.pointToWorldFrame(this.position, this.quaternion, localPoint, result);
- }
-
- vectorToWorldFrame(localVector, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- this.quaternion.vmult(localVector, result);
- return result;
- }
-
- static pointToLocalFrame(position, quaternion, worldPoint, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- worldPoint.vsub(position, result);
- quaternion.conjugate(tmpQuat$1);
- tmpQuat$1.vmult(result, result);
- return result;
- }
-
- static pointToWorldFrame(position, quaternion, localPoint, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- quaternion.vmult(localPoint, result);
- result.vadd(position, result);
- return result;
- }
-
- static vectorToWorldFrame(quaternion, localVector, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- quaternion.vmult(localVector, result);
- return result;
- }
-
- static vectorToLocalFrame(position, quaternion, worldVector, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- quaternion.w *= -1;
- quaternion.vmult(worldVector, result);
- quaternion.w *= -1;
- return result;
- }
- }
- const tmpQuat$1 = new Quaternion();
- class ConvexPolyhedron extends Shape {
-
-
-
-
-
-
-
-
-
-
- constructor(props) {
- if (props === void 0) {
- props = {};
- }
- const {
- vertices = [],
- faces = [],
- normals = [],
- axes,
- boundingSphereRadius
- } = props;
- super({
- type: Shape.types.CONVEXPOLYHEDRON
- });
- this.vertices = vertices;
- this.faces = faces;
- this.faceNormals = normals;
- if (this.faceNormals.length === 0) {
- this.computeNormals();
- }
- if (!boundingSphereRadius) {
- this.updateBoundingSphereRadius();
- } else {
- this.boundingSphereRadius = boundingSphereRadius;
- }
- this.worldVertices = [];
- this.worldVerticesNeedsUpdate = true;
- this.worldFaceNormals = [];
- this.worldFaceNormalsNeedsUpdate = true;
- this.uniqueAxes = axes ? axes.slice() : null;
- this.uniqueEdges = [];
- this.computeEdges();
- }
-
- computeEdges() {
- const faces = this.faces;
- const vertices = this.vertices;
- const edges = this.uniqueEdges;
- edges.length = 0;
- const edge = new Vec3();
- for (let i = 0; i !== faces.length; i++) {
- const face = faces[i];
- const numVertices = face.length;
- for (let j = 0; j !== numVertices; j++) {
- const k = (j + 1) % numVertices;
- vertices[face[j]].vsub(vertices[face[k]], edge);
- edge.normalize();
- let found = false;
- for (let p = 0; p !== edges.length; p++) {
- if (edges[p].almostEquals(edge) || edges[p].almostEquals(edge)) {
- found = true;
- break;
- }
- }
- if (!found) {
- edges.push(edge.clone());
- }
- }
- }
- }
-
- computeNormals() {
- this.faceNormals.length = this.faces.length;
- for (let i = 0; i < this.faces.length; i++) {
-
- for (let j = 0; j < this.faces[i].length; j++) {
- if (!this.vertices[this.faces[i][j]]) {
- throw new Error(`Vertex ${this.faces[i][j]} not found!`);
- }
- }
- const n = this.faceNormals[i] || new Vec3();
- this.getFaceNormal(i, n);
- n.negate(n);
- this.faceNormals[i] = n;
- const vertex = this.vertices[this.faces[i][0]];
- if (n.dot(vertex) < 0) {
- console.error(`.faceNormals[${i}] = Vec3(${n.toString()}) looks like it points into the shape? The vertices follow. Make sure they are ordered CCW around the normal, using the right hand rule.`);
- for (let j = 0; j < this.faces[i].length; j++) {
- console.warn(`.vertices[${this.faces[i][j]}] = Vec3(${this.vertices[this.faces[i][j]].toString()})`);
- }
- }
- }
- }
-
- getFaceNormal(i, target) {
- const f = this.faces[i];
- const va = this.vertices[f[0]];
- const vb = this.vertices[f[1]];
- const vc = this.vertices[f[2]];
- ConvexPolyhedron.computeNormal(va, vb, vc, target);
- }
-
- static computeNormal(va, vb, vc, target) {
- const cb = new Vec3();
- const ab = new Vec3();
- vb.vsub(va, ab);
- vc.vsub(vb, cb);
- cb.cross(ab, target);
- if (!target.isZero()) {
- target.normalize();
- }
- }
-
- clipAgainstHull(posA, quatA, hullB, posB, quatB, separatingNormal, minDist, maxDist, result) {
- const WorldNormal = new Vec3();
- let closestFaceB = -1;
- let dmax = -Number.MAX_VALUE;
- for (let face = 0; face < hullB.faces.length; face++) {
- WorldNormal.copy(hullB.faceNormals[face]);
- quatB.vmult(WorldNormal, WorldNormal);
- const d = WorldNormal.dot(separatingNormal);
- if (d > dmax) {
- dmax = d;
- closestFaceB = face;
- }
- }
- const worldVertsB1 = [];
- for (let i = 0; i < hullB.faces[closestFaceB].length; i++) {
- const b = hullB.vertices[hullB.faces[closestFaceB][i]];
- const worldb = new Vec3();
- worldb.copy(b);
- quatB.vmult(worldb, worldb);
- posB.vadd(worldb, worldb);
- worldVertsB1.push(worldb);
- }
- if (closestFaceB >= 0) {
- this.clipFaceAgainstHull(separatingNormal, posA, quatA, worldVertsB1, minDist, maxDist, result);
- }
- }
-
- findSeparatingAxis(hullB, posA, quatA, posB, quatB, target, faceListA, faceListB) {
- const faceANormalWS3 = new Vec3();
- const Worldnormal1 = new Vec3();
- const deltaC = new Vec3();
- const worldEdge0 = new Vec3();
- const worldEdge1 = new Vec3();
- const Cross = new Vec3();
- let dmin = Number.MAX_VALUE;
- const hullA = this;
- if (!hullA.uniqueAxes) {
- const numFacesA = faceListA ? faceListA.length : hullA.faces.length;
- for (let i = 0; i < numFacesA; i++) {
- const fi = faceListA ? faceListA[i] : i;
- faceANormalWS3.copy(hullA.faceNormals[fi]);
- quatA.vmult(faceANormalWS3, faceANormalWS3);
- const d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
- if (d === false) {
- return false;
- }
- if (d < dmin) {
- dmin = d;
- target.copy(faceANormalWS3);
- }
- }
- } else {
-
- for (let i = 0; i !== hullA.uniqueAxes.length; i++) {
-
- quatA.vmult(hullA.uniqueAxes[i], faceANormalWS3);
- const d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
- if (d === false) {
- return false;
- }
- if (d < dmin) {
- dmin = d;
- target.copy(faceANormalWS3);
- }
- }
- }
- if (!hullB.uniqueAxes) {
-
- const numFacesB = faceListB ? faceListB.length : hullB.faces.length;
- for (let i = 0; i < numFacesB; i++) {
- const fi = faceListB ? faceListB[i] : i;
- Worldnormal1.copy(hullB.faceNormals[fi]);
- quatB.vmult(Worldnormal1, Worldnormal1);
- const d = hullA.testSepAxis(Worldnormal1, hullB, posA, quatA, posB, quatB);
- if (d === false) {
- return false;
- }
- if (d < dmin) {
- dmin = d;
- target.copy(Worldnormal1);
- }
- }
- } else {
-
- for (let i = 0; i !== hullB.uniqueAxes.length; i++) {
- quatB.vmult(hullB.uniqueAxes[i], Worldnormal1);
- const d = hullA.testSepAxis(Worldnormal1, hullB, posA, quatA, posB, quatB);
- if (d === false) {
- return false;
- }
- if (d < dmin) {
- dmin = d;
- target.copy(Worldnormal1);
- }
- }
- }
- for (let e0 = 0; e0 !== hullA.uniqueEdges.length; e0++) {
-
- quatA.vmult(hullA.uniqueEdges[e0], worldEdge0);
- for (let e1 = 0; e1 !== hullB.uniqueEdges.length; e1++) {
-
- quatB.vmult(hullB.uniqueEdges[e1], worldEdge1);
- worldEdge0.cross(worldEdge1, Cross);
- if (!Cross.almostZero()) {
- Cross.normalize();
- const dist = hullA.testSepAxis(Cross, hullB, posA, quatA, posB, quatB);
- if (dist === false) {
- return false;
- }
- if (dist < dmin) {
- dmin = dist;
- target.copy(Cross);
- }
- }
- }
- }
- posB.vsub(posA, deltaC);
- if (deltaC.dot(target) > 0.0) {
- target.negate(target);
- }
- return true;
- }
-
- testSepAxis(axis, hullB, posA, quatA, posB, quatB) {
- const hullA = this;
- ConvexPolyhedron.project(hullA, axis, posA, quatA, maxminA);
- ConvexPolyhedron.project(hullB, axis, posB, quatB, maxminB);
- const maxA = maxminA[0];
- const minA = maxminA[1];
- const maxB = maxminB[0];
- const minB = maxminB[1];
- if (maxA < minB || maxB < minA) {
- return false;
- }
- const d0 = maxA - minB;
- const d1 = maxB - minA;
- const depth = d0 < d1 ? d0 : d1;
- return depth;
- }
-
- calculateLocalInertia(mass, target) {
-
-
- const aabbmax = new Vec3();
- const aabbmin = new Vec3();
- this.computeLocalAABB(aabbmin, aabbmax);
- const x = aabbmax.x - aabbmin.x;
- const y = aabbmax.y - aabbmin.y;
- const z = aabbmax.z - aabbmin.z;
- target.x = 1.0 / 12.0 * mass * (2 * y * 2 * y + 2 * z * 2 * z);
- target.y = 1.0 / 12.0 * mass * (2 * x * 2 * x + 2 * z * 2 * z);
- target.z = 1.0 / 12.0 * mass * (2 * y * 2 * y + 2 * x * 2 * x);
- }
-
- getPlaneConstantOfFace(face_i) {
- const f = this.faces[face_i];
- const n = this.faceNormals[face_i];
- const v = this.vertices[f[0]];
- const c = -n.dot(v);
- return c;
- }
-
- clipFaceAgainstHull(separatingNormal, posA, quatA, worldVertsB1, minDist, maxDist, result) {
- const faceANormalWS = new Vec3();
- const edge0 = new Vec3();
- const WorldEdge0 = new Vec3();
- const worldPlaneAnormal1 = new Vec3();
- const planeNormalWS1 = new Vec3();
- const worldA1 = new Vec3();
- const localPlaneNormal = new Vec3();
- const planeNormalWS = new Vec3();
- const hullA = this;
- const worldVertsB2 = [];
- const pVtxIn = worldVertsB1;
- const pVtxOut = worldVertsB2;
- let closestFaceA = -1;
- let dmin = Number.MAX_VALUE;
- for (let face = 0; face < hullA.faces.length; face++) {
- faceANormalWS.copy(hullA.faceNormals[face]);
- quatA.vmult(faceANormalWS, faceANormalWS);
- const d = faceANormalWS.dot(separatingNormal);
- if (d < dmin) {
- dmin = d;
- closestFaceA = face;
- }
- }
- if (closestFaceA < 0) {
- return;
- }
- const polyA = hullA.faces[closestFaceA];
- polyA.connectedFaces = [];
- for (let i = 0; i < hullA.faces.length; i++) {
- for (let j = 0; j < hullA.faces[i].length; j++) {
- if (
-
- polyA.indexOf(hullA.faces[i][j]) !== -1 &&
-
- i !== closestFaceA &&
-
- polyA.connectedFaces.indexOf(i) === -1) {
- polyA.connectedFaces.push(i);
- }
- }
- }
-
- const numVerticesA = polyA.length;
- for (let i = 0; i < numVerticesA; i++) {
- const a = hullA.vertices[polyA[i]];
- const b = hullA.vertices[polyA[(i + 1) % numVerticesA]];
- a.vsub(b, edge0);
- WorldEdge0.copy(edge0);
- quatA.vmult(WorldEdge0, WorldEdge0);
- posA.vadd(WorldEdge0, WorldEdge0);
- worldPlaneAnormal1.copy(this.faceNormals[closestFaceA]);
- quatA.vmult(worldPlaneAnormal1, worldPlaneAnormal1);
- posA.vadd(worldPlaneAnormal1, worldPlaneAnormal1);
- WorldEdge0.cross(worldPlaneAnormal1, planeNormalWS1);
- planeNormalWS1.negate(planeNormalWS1);
- worldA1.copy(a);
- quatA.vmult(worldA1, worldA1);
- posA.vadd(worldA1, worldA1);
- const otherFace = polyA.connectedFaces[i];
- localPlaneNormal.copy(this.faceNormals[otherFace]);
- const localPlaneEq = this.getPlaneConstantOfFace(otherFace);
- planeNormalWS.copy(localPlaneNormal);
- quatA.vmult(planeNormalWS, planeNormalWS);
- const planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
- this.clipFaceAgainstPlane(pVtxIn, pVtxOut, planeNormalWS, planeEqWS);
- while (pVtxIn.length) {
- pVtxIn.shift();
- }
- while (pVtxOut.length) {
- pVtxIn.push(pVtxOut.shift());
- }
- }
- localPlaneNormal.copy(this.faceNormals[closestFaceA]);
- const localPlaneEq = this.getPlaneConstantOfFace(closestFaceA);
- planeNormalWS.copy(localPlaneNormal);
- quatA.vmult(planeNormalWS, planeNormalWS);
- const planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
- for (let i = 0; i < pVtxIn.length; i++) {
- let depth = planeNormalWS.dot(pVtxIn[i]) + planeEqWS;
- if (depth <= minDist) {
- console.log(`clamped: depth=${depth} to minDist=${minDist}`);
- depth = minDist;
- }
- if (depth <= maxDist) {
- const point = pVtxIn[i];
- if (depth <= 1e-6) {
- const p = {
- point,
- normal: planeNormalWS,
- depth
- };
- result.push(p);
- }
- }
- }
- }
-
- clipFaceAgainstPlane(inVertices, outVertices, planeNormal, planeConstant) {
- let n_dot_first;
- let n_dot_last;
- const numVerts = inVertices.length;
- if (numVerts < 2) {
- return outVertices;
- }
- let firstVertex = inVertices[inVertices.length - 1];
- let lastVertex = inVertices[0];
- n_dot_first = planeNormal.dot(firstVertex) + planeConstant;
- for (let vi = 0; vi < numVerts; vi++) {
- lastVertex = inVertices[vi];
- n_dot_last = planeNormal.dot(lastVertex) + planeConstant;
- if (n_dot_first < 0) {
- if (n_dot_last < 0) {
-
- const newv = new Vec3();
- newv.copy(lastVertex);
- outVertices.push(newv);
- } else {
-
- const newv = new Vec3();
- firstVertex.lerp(lastVertex, n_dot_first / (n_dot_first - n_dot_last), newv);
- outVertices.push(newv);
- }
- } else {
- if (n_dot_last < 0) {
-
- const newv = new Vec3();
- firstVertex.lerp(lastVertex, n_dot_first / (n_dot_first - n_dot_last), newv);
- outVertices.push(newv);
- outVertices.push(lastVertex);
- }
- }
- firstVertex = lastVertex;
- n_dot_first = n_dot_last;
- }
- return outVertices;
- }
-
- computeWorldVertices(position, quat) {
- while (this.worldVertices.length < this.vertices.length) {
- this.worldVertices.push(new Vec3());
- }
- const verts = this.vertices;
- const worldVerts = this.worldVertices;
- for (let i = 0; i !== this.vertices.length; i++) {
- quat.vmult(verts[i], worldVerts[i]);
- position.vadd(worldVerts[i], worldVerts[i]);
- }
- this.worldVerticesNeedsUpdate = false;
- }
- computeLocalAABB(aabbmin, aabbmax) {
- const vertices = this.vertices;
- aabbmin.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
- aabbmax.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
- for (let i = 0; i < this.vertices.length; i++) {
- const v = vertices[i];
- if (v.x < aabbmin.x) {
- aabbmin.x = v.x;
- } else if (v.x > aabbmax.x) {
- aabbmax.x = v.x;
- }
- if (v.y < aabbmin.y) {
- aabbmin.y = v.y;
- } else if (v.y > aabbmax.y) {
- aabbmax.y = v.y;
- }
- if (v.z < aabbmin.z) {
- aabbmin.z = v.z;
- } else if (v.z > aabbmax.z) {
- aabbmax.z = v.z;
- }
- }
- }
-
- computeWorldFaceNormals(quat) {
- const N = this.faceNormals.length;
- while (this.worldFaceNormals.length < N) {
- this.worldFaceNormals.push(new Vec3());
- }
- const normals = this.faceNormals;
- const worldNormals = this.worldFaceNormals;
- for (let i = 0; i !== N; i++) {
- quat.vmult(normals[i], worldNormals[i]);
- }
- this.worldFaceNormalsNeedsUpdate = false;
- }
-
- updateBoundingSphereRadius() {
-
- let max2 = 0;
- const verts = this.vertices;
- for (let i = 0; i !== verts.length; i++) {
- const norm2 = verts[i].lengthSquared();
- if (norm2 > max2) {
- max2 = norm2;
- }
- }
- this.boundingSphereRadius = Math.sqrt(max2);
- }
-
- calculateWorldAABB(pos, quat, min, max) {
- const verts = this.vertices;
- let minx;
- let miny;
- let minz;
- let maxx;
- let maxy;
- let maxz;
- let tempWorldVertex = new Vec3();
- for (let i = 0; i < verts.length; i++) {
- tempWorldVertex.copy(verts[i]);
- quat.vmult(tempWorldVertex, tempWorldVertex);
- pos.vadd(tempWorldVertex, tempWorldVertex);
- const v = tempWorldVertex;
- if (minx === undefined || v.x < minx) {
- minx = v.x;
- }
- if (maxx === undefined || v.x > maxx) {
- maxx = v.x;
- }
- if (miny === undefined || v.y < miny) {
- miny = v.y;
- }
- if (maxy === undefined || v.y > maxy) {
- maxy = v.y;
- }
- if (minz === undefined || v.z < minz) {
- minz = v.z;
- }
- if (maxz === undefined || v.z > maxz) {
- maxz = v.z;
- }
- }
- min.set(minx, miny, minz);
- max.set(maxx, maxy, maxz);
- }
-
- volume() {
- return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
- }
-
- getAveragePointLocal(target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const verts = this.vertices;
- for (let i = 0; i < verts.length; i++) {
- target.vadd(verts[i], target);
- }
- target.scale(1 / verts.length, target);
- return target;
- }
-
- transformAllPoints(offset, quat) {
- const n = this.vertices.length;
- const verts = this.vertices;
- if (quat) {
-
- for (let i = 0; i < n; i++) {
- const v = verts[i];
- quat.vmult(v, v);
- }
- for (let i = 0; i < this.faceNormals.length; i++) {
- const v = this.faceNormals[i];
- quat.vmult(v, v);
- }
-
- }
- if (offset) {
- for (let i = 0; i < n; i++) {
- const v = verts[i];
- v.vadd(offset, v);
- }
- }
- }
-
- pointIsInside(p) {
- const verts = this.vertices;
- const faces = this.faces;
- const normals = this.faceNormals;
- const positiveResult = null;
- const pointInside = new Vec3();
- this.getAveragePointLocal(pointInside);
- for (let i = 0; i < this.faces.length; i++) {
- let n = normals[i];
- const v = verts[faces[i][0]];
-
- const vToP = new Vec3();
- p.vsub(v, vToP);
- const r1 = n.dot(vToP);
- const vToPointInside = new Vec3();
- pointInside.vsub(v, vToPointInside);
- const r2 = n.dot(vToPointInside);
- if (r1 < 0 && r2 > 0 || r1 > 0 && r2 < 0) {
- return false;
- }
- }
- return positiveResult ? 1 : -1;
- }
-
- static project(shape, axis, pos, quat, result) {
- const n = shape.vertices.length;
- project_worldVertex;
- const localAxis = project_localAxis;
- let max = 0;
- let min = 0;
- const localOrigin = project_localOrigin;
- const vs = shape.vertices;
- localOrigin.setZero();
- Transform.vectorToLocalFrame(pos, quat, axis, localAxis);
- Transform.pointToLocalFrame(pos, quat, localOrigin, localOrigin);
- const add = localOrigin.dot(localAxis);
- min = max = vs[0].dot(localAxis);
- for (let i = 1; i < n; i++) {
- const val = vs[i].dot(localAxis);
- if (val > max) {
- max = val;
- }
- if (val < min) {
- min = val;
- }
- }
- min -= add;
- max -= add;
- if (min > max) {
-
- const temp = min;
- min = max;
- max = temp;
- }
- result[0] = max;
- result[1] = min;
- }
- }
- const maxminA = [];
- const maxminB = [];
- const project_worldVertex = new Vec3();
- const project_localAxis = new Vec3();
- const project_localOrigin = new Vec3();
- class Box extends Shape {
-
-
- constructor(halfExtents) {
- super({
- type: Shape.types.BOX
- });
- this.halfExtents = halfExtents;
- this.convexPolyhedronRepresentation = null;
- this.updateConvexPolyhedronRepresentation();
- this.updateBoundingSphereRadius();
- }
-
- updateConvexPolyhedronRepresentation() {
- const sx = this.halfExtents.x;
- const sy = this.halfExtents.y;
- const sz = this.halfExtents.z;
- const V = Vec3;
- const vertices = [new V(-sx, -sy, -sz), new V(sx, -sy, -sz), new V(sx, sy, -sz), new V(-sx, sy, -sz), new V(-sx, -sy, sz), new V(sx, -sy, sz), new V(sx, sy, sz), new V(-sx, sy, sz)];
- const faces = [[3, 2, 1, 0],
- [4, 5, 6, 7],
- [5, 4, 0, 1],
- [2, 3, 7, 6],
- [0, 4, 7, 3],
- [1, 2, 6, 5]
- ];
- const axes = [new V(0, 0, 1), new V(0, 1, 0), new V(1, 0, 0)];
- const h = new ConvexPolyhedron({
- vertices,
- faces,
- axes
- });
- this.convexPolyhedronRepresentation = h;
- h.material = this.material;
- }
-
- calculateLocalInertia(mass, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- Box.calculateInertia(this.halfExtents, mass, target);
- return target;
- }
- static calculateInertia(halfExtents, mass, target) {
- const e = halfExtents;
- target.x = 1.0 / 12.0 * mass * (2 * e.y * 2 * e.y + 2 * e.z * 2 * e.z);
- target.y = 1.0 / 12.0 * mass * (2 * e.x * 2 * e.x + 2 * e.z * 2 * e.z);
- target.z = 1.0 / 12.0 * mass * (2 * e.y * 2 * e.y + 2 * e.x * 2 * e.x);
- }
-
- getSideNormals(sixTargetVectors, quat) {
- const sides = sixTargetVectors;
- const ex = this.halfExtents;
- sides[0].set(ex.x, 0, 0);
- sides[1].set(0, ex.y, 0);
- sides[2].set(0, 0, ex.z);
- sides[3].set(-ex.x, 0, 0);
- sides[4].set(0, -ex.y, 0);
- sides[5].set(0, 0, -ex.z);
- if (quat !== undefined) {
- for (let i = 0; i !== sides.length; i++) {
- quat.vmult(sides[i], sides[i]);
- }
- }
- return sides;
- }
-
- volume() {
- return 8.0 * this.halfExtents.x * this.halfExtents.y * this.halfExtents.z;
- }
-
- updateBoundingSphereRadius() {
- this.boundingSphereRadius = this.halfExtents.length();
- }
-
- forEachWorldCorner(pos, quat, callback) {
- const e = this.halfExtents;
- const corners = [[e.x, e.y, e.z], [-e.x, e.y, e.z], [-e.x, -e.y, e.z], [-e.x, -e.y, -e.z], [e.x, -e.y, -e.z], [e.x, e.y, -e.z], [-e.x, e.y, -e.z], [e.x, -e.y, e.z]];
- for (let i = 0; i < corners.length; i++) {
- worldCornerTempPos.set(corners[i][0], corners[i][1], corners[i][2]);
- quat.vmult(worldCornerTempPos, worldCornerTempPos);
- pos.vadd(worldCornerTempPos, worldCornerTempPos);
- callback(worldCornerTempPos.x, worldCornerTempPos.y, worldCornerTempPos.z);
- }
- }
-
- calculateWorldAABB(pos, quat, min, max) {
- const e = this.halfExtents;
- worldCornersTemp[0].set(e.x, e.y, e.z);
- worldCornersTemp[1].set(-e.x, e.y, e.z);
- worldCornersTemp[2].set(-e.x, -e.y, e.z);
- worldCornersTemp[3].set(-e.x, -e.y, -e.z);
- worldCornersTemp[4].set(e.x, -e.y, -e.z);
- worldCornersTemp[5].set(e.x, e.y, -e.z);
- worldCornersTemp[6].set(-e.x, e.y, -e.z);
- worldCornersTemp[7].set(e.x, -e.y, e.z);
- const wc = worldCornersTemp[0];
- quat.vmult(wc, wc);
- pos.vadd(wc, wc);
- max.copy(wc);
- min.copy(wc);
- for (let i = 1; i < 8; i++) {
- const wc = worldCornersTemp[i];
- quat.vmult(wc, wc);
- pos.vadd(wc, wc);
- const x = wc.x;
- const y = wc.y;
- const z = wc.z;
- if (x > max.x) {
- max.x = x;
- }
- if (y > max.y) {
- max.y = y;
- }
- if (z > max.z) {
- max.z = z;
- }
- if (x < min.x) {
- min.x = x;
- }
- if (y < min.y) {
- min.y = y;
- }
- if (z < min.z) {
- min.z = z;
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- }
- const worldCornerTempPos = new Vec3();
- const worldCornersTemp = [new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3()];
- const BODY_TYPES = {
-
- DYNAMIC: 1,
-
- STATIC: 2,
-
- KINEMATIC: 4
- };
- const BODY_SLEEP_STATES = {
-
- AWAKE: 0,
-
- SLEEPY: 1,
-
- SLEEPING: 2
- };
- class Body extends EventTarget {
-
-
-
-
-
-
-
-
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- super();
- this.id = Body.idCounter++;
- this.index = -1;
- this.world = null;
- this.vlambda = new Vec3();
- this.collisionFilterGroup = typeof options.collisionFilterGroup === 'number' ? options.collisionFilterGroup : 1;
- this.collisionFilterMask = typeof options.collisionFilterMask === 'number' ? options.collisionFilterMask : -1;
- this.collisionResponse = typeof options.collisionResponse === 'boolean' ? options.collisionResponse : true;
- this.position = new Vec3();
- this.previousPosition = new Vec3();
- this.interpolatedPosition = new Vec3();
- this.initPosition = new Vec3();
- if (options.position) {
- this.position.copy(options.position);
- this.previousPosition.copy(options.position);
- this.interpolatedPosition.copy(options.position);
- this.initPosition.copy(options.position);
- }
- this.velocity = new Vec3();
- if (options.velocity) {
- this.velocity.copy(options.velocity);
- }
- this.initVelocity = new Vec3();
- this.force = new Vec3();
- const mass = typeof options.mass === 'number' ? options.mass : 0;
- this.mass = mass;
- this.invMass = mass > 0 ? 1.0 / mass : 0;
- this.material = options.material || null;
- this.linearDamping = typeof options.linearDamping === 'number' ? options.linearDamping : 0.01;
- this.type = mass <= 0.0 ? Body.STATIC : Body.DYNAMIC;
- if (typeof options.type === typeof Body.STATIC) {
- this.type = options.type;
- }
- this.allowSleep = typeof options.allowSleep !== 'undefined' ? options.allowSleep : true;
- this.sleepState = Body.AWAKE;
- this.sleepSpeedLimit = typeof options.sleepSpeedLimit !== 'undefined' ? options.sleepSpeedLimit : 0.1;
- this.sleepTimeLimit = typeof options.sleepTimeLimit !== 'undefined' ? options.sleepTimeLimit : 1;
- this.timeLastSleepy = 0;
- this.wakeUpAfterNarrowphase = false;
- this.torque = new Vec3();
- this.quaternion = new Quaternion();
- this.initQuaternion = new Quaternion();
- this.previousQuaternion = new Quaternion();
- this.interpolatedQuaternion = new Quaternion();
- if (options.quaternion) {
- this.quaternion.copy(options.quaternion);
- this.initQuaternion.copy(options.quaternion);
- this.previousQuaternion.copy(options.quaternion);
- this.interpolatedQuaternion.copy(options.quaternion);
- }
- this.angularVelocity = new Vec3();
- if (options.angularVelocity) {
- this.angularVelocity.copy(options.angularVelocity);
- }
- this.initAngularVelocity = new Vec3();
- this.shapes = [];
- this.shapeOffsets = [];
- this.shapeOrientations = [];
- this.inertia = new Vec3();
- this.invInertia = new Vec3();
- this.invInertiaWorld = new Mat3();
- this.invMassSolve = 0;
- this.invInertiaSolve = new Vec3();
- this.invInertiaWorldSolve = new Mat3();
- this.fixedRotation = typeof options.fixedRotation !== 'undefined' ? options.fixedRotation : false;
- this.angularDamping = typeof options.angularDamping !== 'undefined' ? options.angularDamping : 0.01;
- this.linearFactor = new Vec3(1, 1, 1);
- if (options.linearFactor) {
- this.linearFactor.copy(options.linearFactor);
- }
- this.angularFactor = new Vec3(1, 1, 1);
- if (options.angularFactor) {
- this.angularFactor.copy(options.angularFactor);
- }
- this.aabb = new AABB();
- this.aabbNeedsUpdate = true;
- this.boundingRadius = 0;
- this.wlambda = new Vec3();
- this.isTrigger = Boolean(options.isTrigger);
- if (options.shape) {
- this.addShape(options.shape);
- }
- this.updateMassProperties();
- }
-
- wakeUp() {
- const prevState = this.sleepState;
- this.sleepState = Body.AWAKE;
- this.wakeUpAfterNarrowphase = false;
- if (prevState === Body.SLEEPING) {
- this.dispatchEvent(Body.wakeupEvent);
- }
- }
-
- sleep() {
- this.sleepState = Body.SLEEPING;
- this.velocity.set(0, 0, 0);
- this.angularVelocity.set(0, 0, 0);
- this.wakeUpAfterNarrowphase = false;
- }
-
- sleepTick(time) {
- if (this.allowSleep) {
- const sleepState = this.sleepState;
- const speedSquared = this.velocity.lengthSquared() + this.angularVelocity.lengthSquared();
- const speedLimitSquared = this.sleepSpeedLimit ** 2;
- if (sleepState === Body.AWAKE && speedSquared < speedLimitSquared) {
- this.sleepState = Body.SLEEPY;
- this.timeLastSleepy = time;
- this.dispatchEvent(Body.sleepyEvent);
- } else if (sleepState === Body.SLEEPY && speedSquared > speedLimitSquared) {
- this.wakeUp();
- } else if (sleepState === Body.SLEEPY && time - this.timeLastSleepy > this.sleepTimeLimit) {
- this.sleep();
- this.dispatchEvent(Body.sleepEvent);
- }
- }
- }
-
- updateSolveMassProperties() {
- if (this.sleepState === Body.SLEEPING || this.type === Body.KINEMATIC) {
- this.invMassSolve = 0;
- this.invInertiaSolve.setZero();
- this.invInertiaWorldSolve.setZero();
- } else {
- this.invMassSolve = this.invMass;
- this.invInertiaSolve.copy(this.invInertia);
- this.invInertiaWorldSolve.copy(this.invInertiaWorld);
- }
- }
-
- pointToLocalFrame(worldPoint, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- worldPoint.vsub(this.position, result);
- this.quaternion.conjugate().vmult(result, result);
- return result;
- }
-
- vectorToLocalFrame(worldVector, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- this.quaternion.conjugate().vmult(worldVector, result);
- return result;
- }
-
- pointToWorldFrame(localPoint, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- this.quaternion.vmult(localPoint, result);
- result.vadd(this.position, result);
- return result;
- }
-
- vectorToWorldFrame(localVector, result) {
- if (result === void 0) {
- result = new Vec3();
- }
- this.quaternion.vmult(localVector, result);
- return result;
- }
-
- addShape(shape, _offset, _orientation) {
- const offset = new Vec3();
- const orientation = new Quaternion();
- if (_offset) {
- offset.copy(_offset);
- }
- if (_orientation) {
- orientation.copy(_orientation);
- }
- this.shapes.push(shape);
- this.shapeOffsets.push(offset);
- this.shapeOrientations.push(orientation);
- this.updateMassProperties();
- this.updateBoundingRadius();
- this.aabbNeedsUpdate = true;
- shape.body = this;
- return this;
- }
-
- removeShape(shape) {
- const index = this.shapes.indexOf(shape);
- if (index === -1) {
- console.warn('Shape does not belong to the body');
- return this;
- }
- this.shapes.splice(index, 1);
- this.shapeOffsets.splice(index, 1);
- this.shapeOrientations.splice(index, 1);
- this.updateMassProperties();
- this.updateBoundingRadius();
- this.aabbNeedsUpdate = true;
- shape.body = null;
- return this;
- }
-
- updateBoundingRadius() {
- const shapes = this.shapes;
- const shapeOffsets = this.shapeOffsets;
- const N = shapes.length;
- let radius = 0;
- for (let i = 0; i !== N; i++) {
- const shape = shapes[i];
- shape.updateBoundingSphereRadius();
- const offset = shapeOffsets[i].length();
- const r = shape.boundingSphereRadius;
- if (offset + r > radius) {
- radius = offset + r;
- }
- }
- this.boundingRadius = radius;
- }
-
- updateAABB() {
- const shapes = this.shapes;
- const shapeOffsets = this.shapeOffsets;
- const shapeOrientations = this.shapeOrientations;
- const N = shapes.length;
- const offset = tmpVec;
- const orientation = tmpQuat;
- const bodyQuat = this.quaternion;
- const aabb = this.aabb;
- const shapeAABB = updateAABB_shapeAABB;
- for (let i = 0; i !== N; i++) {
- const shape = shapes[i];
- bodyQuat.vmult(shapeOffsets[i], offset);
- offset.vadd(this.position, offset);
- bodyQuat.mult(shapeOrientations[i], orientation);
- shape.calculateWorldAABB(offset, orientation, shapeAABB.lowerBound, shapeAABB.upperBound);
- if (i === 0) {
- aabb.copy(shapeAABB);
- } else {
- aabb.extend(shapeAABB);
- }
- }
- this.aabbNeedsUpdate = false;
- }
-
- updateInertiaWorld(force) {
- const I = this.invInertia;
- if (I.x === I.y && I.y === I.z && !force) ; else {
- const m1 = uiw_m1;
- const m2 = uiw_m2;
- uiw_m3;
- m1.setRotationFromQuaternion(this.quaternion);
- m1.transpose(m2);
- m1.scale(I, m1);
- m1.mmult(m2, this.invInertiaWorld);
- }
- }
-
- applyForce(force, relativePoint) {
- if (relativePoint === void 0) {
- relativePoint = new Vec3();
- }
-
- if (this.type !== Body.DYNAMIC) {
- return;
- }
- if (this.sleepState === Body.SLEEPING) {
- this.wakeUp();
- }
- const rotForce = Body_applyForce_rotForce;
- relativePoint.cross(force, rotForce);
- this.force.vadd(force, this.force);
- this.torque.vadd(rotForce, this.torque);
- }
-
- applyLocalForce(localForce, localPoint) {
- if (localPoint === void 0) {
- localPoint = new Vec3();
- }
- if (this.type !== Body.DYNAMIC) {
- return;
- }
- const worldForce = Body_applyLocalForce_worldForce;
- const relativePointWorld = Body_applyLocalForce_relativePointWorld;
- this.vectorToWorldFrame(localForce, worldForce);
- this.vectorToWorldFrame(localPoint, relativePointWorld);
- this.applyForce(worldForce, relativePointWorld);
- }
-
- applyTorque(torque) {
- if (this.type !== Body.DYNAMIC) {
- return;
- }
- if (this.sleepState === Body.SLEEPING) {
- this.wakeUp();
- }
- this.torque.vadd(torque, this.torque);
- }
-
- applyImpulse(impulse, relativePoint) {
- if (relativePoint === void 0) {
- relativePoint = new Vec3();
- }
- if (this.type !== Body.DYNAMIC) {
- return;
- }
- if (this.sleepState === Body.SLEEPING) {
- this.wakeUp();
- }
- const r = relativePoint;
- const velo = Body_applyImpulse_velo;
- velo.copy(impulse);
- velo.scale(this.invMass, velo);
- this.velocity.vadd(velo, this.velocity);
- const rotVelo = Body_applyImpulse_rotVelo;
- r.cross(impulse, rotVelo);
-
- this.invInertiaWorld.vmult(rotVelo, rotVelo);
- this.angularVelocity.vadd(rotVelo, this.angularVelocity);
- }
-
- applyLocalImpulse(localImpulse, localPoint) {
- if (localPoint === void 0) {
- localPoint = new Vec3();
- }
- if (this.type !== Body.DYNAMIC) {
- return;
- }
- const worldImpulse = Body_applyLocalImpulse_worldImpulse;
- const relativePointWorld = Body_applyLocalImpulse_relativePoint;
- this.vectorToWorldFrame(localImpulse, worldImpulse);
- this.vectorToWorldFrame(localPoint, relativePointWorld);
- this.applyImpulse(worldImpulse, relativePointWorld);
- }
-
- updateMassProperties() {
- const halfExtents = Body_updateMassProperties_halfExtents;
- this.invMass = this.mass > 0 ? 1.0 / this.mass : 0;
- const I = this.inertia;
- const fixed = this.fixedRotation;
- this.updateAABB();
- halfExtents.set((this.aabb.upperBound.x - this.aabb.lowerBound.x) / 2, (this.aabb.upperBound.y - this.aabb.lowerBound.y) / 2, (this.aabb.upperBound.z - this.aabb.lowerBound.z) / 2);
- Box.calculateInertia(halfExtents, this.mass, I);
- this.invInertia.set(I.x > 0 && !fixed ? 1.0 / I.x : 0, I.y > 0 && !fixed ? 1.0 / I.y : 0, I.z > 0 && !fixed ? 1.0 / I.z : 0);
- this.updateInertiaWorld(true);
- }
-
- getVelocityAtWorldPoint(worldPoint, result) {
- const r = new Vec3();
- worldPoint.vsub(this.position, r);
- this.angularVelocity.cross(r, result);
- this.velocity.vadd(result, result);
- return result;
- }
-
- integrate(dt, quatNormalize, quatNormalizeFast) {
-
- this.previousPosition.copy(this.position);
- this.previousQuaternion.copy(this.quaternion);
- if (!(this.type === Body.DYNAMIC || this.type === Body.KINEMATIC) || this.sleepState === Body.SLEEPING) {
-
- return;
- }
- const velo = this.velocity;
- const angularVelo = this.angularVelocity;
- const pos = this.position;
- const force = this.force;
- const torque = this.torque;
- const quat = this.quaternion;
- const invMass = this.invMass;
- const invInertia = this.invInertiaWorld;
- const linearFactor = this.linearFactor;
- const iMdt = invMass * dt;
- velo.x += force.x * iMdt * linearFactor.x;
- velo.y += force.y * iMdt * linearFactor.y;
- velo.z += force.z * iMdt * linearFactor.z;
- const e = invInertia.elements;
- const angularFactor = this.angularFactor;
- const tx = torque.x * angularFactor.x;
- const ty = torque.y * angularFactor.y;
- const tz = torque.z * angularFactor.z;
- angularVelo.x += dt * (e[0] * tx + e[1] * ty + e[2] * tz);
- angularVelo.y += dt * (e[3] * tx + e[4] * ty + e[5] * tz);
- angularVelo.z += dt * (e[6] * tx + e[7] * ty + e[8] * tz);
- pos.x += velo.x * dt;
- pos.y += velo.y * dt;
- pos.z += velo.z * dt;
- quat.integrate(this.angularVelocity, dt, this.angularFactor, quat);
- if (quatNormalize) {
- if (quatNormalizeFast) {
- quat.normalizeFast();
- } else {
- quat.normalize();
- }
- }
- this.aabbNeedsUpdate = true;
- this.updateInertiaWorld();
- }
- }
- Body.idCounter = 0;
- Body.COLLIDE_EVENT_NAME = 'collide';
- Body.DYNAMIC = BODY_TYPES.DYNAMIC;
- Body.STATIC = BODY_TYPES.STATIC;
- Body.KINEMATIC = BODY_TYPES.KINEMATIC;
- Body.AWAKE = BODY_SLEEP_STATES.AWAKE;
- Body.SLEEPY = BODY_SLEEP_STATES.SLEEPY;
- Body.SLEEPING = BODY_SLEEP_STATES.SLEEPING;
- Body.wakeupEvent = {
- type: 'wakeup'
- };
- Body.sleepyEvent = {
- type: 'sleepy'
- };
- Body.sleepEvent = {
- type: 'sleep'
- };
- const tmpVec = new Vec3();
- const tmpQuat = new Quaternion();
- const updateAABB_shapeAABB = new AABB();
- const uiw_m1 = new Mat3();
- const uiw_m2 = new Mat3();
- const uiw_m3 = new Mat3();
- const Body_applyForce_rotForce = new Vec3();
- const Body_applyLocalForce_worldForce = new Vec3();
- const Body_applyLocalForce_relativePointWorld = new Vec3();
- const Body_applyImpulse_velo = new Vec3();
- const Body_applyImpulse_rotVelo = new Vec3();
- const Body_applyLocalImpulse_worldImpulse = new Vec3();
- const Body_applyLocalImpulse_relativePoint = new Vec3();
- const Body_updateMassProperties_halfExtents = new Vec3();
- class Broadphase {
-
-
-
- constructor() {
- this.world = null;
- this.useBoundingBoxes = false;
- this.dirty = true;
- }
-
- collisionPairs(world, p1, p2) {
- throw new Error('collisionPairs not implemented for this BroadPhase class!');
- }
-
- needBroadphaseCollision(bodyA, bodyB) {
-
- if ((bodyA.collisionFilterGroup & bodyB.collisionFilterMask) === 0 || (bodyB.collisionFilterGroup & bodyA.collisionFilterMask) === 0) {
- return false;
- }
- if (((bodyA.type & Body.STATIC) !== 0 || bodyA.sleepState === Body.SLEEPING) && ((bodyB.type & Body.STATIC) !== 0 || bodyB.sleepState === Body.SLEEPING)) {
-
- return false;
- }
- return true;
- }
-
- intersectionTest(bodyA, bodyB, pairs1, pairs2) {
- if (this.useBoundingBoxes) {
- this.doBoundingBoxBroadphase(bodyA, bodyB, pairs1, pairs2);
- } else {
- this.doBoundingSphereBroadphase(bodyA, bodyB, pairs1, pairs2);
- }
- }
-
- doBoundingSphereBroadphase(bodyA, bodyB, pairs1, pairs2) {
- const r = Broadphase_collisionPairs_r;
- bodyB.position.vsub(bodyA.position, r);
- const boundingRadiusSum2 = (bodyA.boundingRadius + bodyB.boundingRadius) ** 2;
- const norm2 = r.lengthSquared();
- if (norm2 < boundingRadiusSum2) {
- pairs1.push(bodyA);
- pairs2.push(bodyB);
- }
- }
-
- doBoundingBoxBroadphase(bodyA, bodyB, pairs1, pairs2) {
- if (bodyA.aabbNeedsUpdate) {
- bodyA.updateAABB();
- }
- if (bodyB.aabbNeedsUpdate) {
- bodyB.updateAABB();
- }
- if (bodyA.aabb.overlaps(bodyB.aabb)) {
- pairs1.push(bodyA);
- pairs2.push(bodyB);
- }
- }
-
- makePairsUnique(pairs1, pairs2) {
- const t = Broadphase_makePairsUnique_temp;
- const p1 = Broadphase_makePairsUnique_p1;
- const p2 = Broadphase_makePairsUnique_p2;
- const N = pairs1.length;
- for (let i = 0; i !== N; i++) {
- p1[i] = pairs1[i];
- p2[i] = pairs2[i];
- }
- pairs1.length = 0;
- pairs2.length = 0;
- for (let i = 0; i !== N; i++) {
- const id1 = p1[i].id;
- const id2 = p2[i].id;
- const key = id1 < id2 ? `${id1},${id2}` : `${id2},${id1}`;
- t[key] = i;
- t.keys.push(key);
- }
- for (let i = 0; i !== t.keys.length; i++) {
- const key = t.keys.pop();
- const pairIndex = t[key];
- pairs1.push(p1[pairIndex]);
- pairs2.push(p2[pairIndex]);
- delete t[key];
- }
- }
-
- setWorld(world) {}
-
- static boundingSphereCheck(bodyA, bodyB) {
- const dist = new Vec3();
- bodyA.position.vsub(bodyB.position, dist);
- const sa = bodyA.shapes[0];
- const sb = bodyB.shapes[0];
- return Math.pow(sa.boundingSphereRadius + sb.boundingSphereRadius, 2) > dist.lengthSquared();
- }
-
- aabbQuery(world, aabb, result) {
- console.warn('.aabbQuery is not implemented in this Broadphase subclass.');
- return [];
- }
- }
- const Broadphase_collisionPairs_r = new Vec3();
- new Vec3();
- new Quaternion();
- new Vec3();
- const Broadphase_makePairsUnique_temp = {
- keys: []
- };
- const Broadphase_makePairsUnique_p1 = [];
- const Broadphase_makePairsUnique_p2 = [];
- new Vec3();
- class GridBroadphase extends Broadphase {
-
-
-
-
-
-
-
-
- constructor(aabbMin, aabbMax, nx, ny, nz) {
- if (aabbMin === void 0) {
- aabbMin = new Vec3(100, 100, 100);
- }
- if (aabbMax === void 0) {
- aabbMax = new Vec3(-100, -100, -100);
- }
- if (nx === void 0) {
- nx = 10;
- }
- if (ny === void 0) {
- ny = 10;
- }
- if (nz === void 0) {
- nz = 10;
- }
- super();
- this.nx = nx;
- this.ny = ny;
- this.nz = nz;
- this.aabbMin = aabbMin;
- this.aabbMax = aabbMax;
- const nbins = this.nx * this.ny * this.nz;
- if (nbins <= 0) {
- throw "GridBroadphase: Each dimension's n must be >0";
- }
- this.bins = [];
- this.binLengths = [];
- this.bins.length = nbins;
- this.binLengths.length = nbins;
- for (let i = 0; i < nbins; i++) {
- this.bins[i] = [];
- this.binLengths[i] = 0;
- }
- }
-
- collisionPairs(world, pairs1, pairs2) {
- const N = world.bodies.length;
- const bodies = world.bodies;
- const max = this.aabbMax;
- const min = this.aabbMin;
- const nx = this.nx;
- const ny = this.ny;
- const nz = this.nz;
- const xstep = ny * nz;
- const ystep = nz;
- const zstep = 1;
- const xmax = max.x;
- const ymax = max.y;
- const zmax = max.z;
- const xmin = min.x;
- const ymin = min.y;
- const zmin = min.z;
- const xmult = nx / (xmax - xmin);
- const ymult = ny / (ymax - ymin);
- const zmult = nz / (zmax - zmin);
- const binsizeX = (xmax - xmin) / nx;
- const binsizeY = (ymax - ymin) / ny;
- const binsizeZ = (zmax - zmin) / nz;
- const binRadius = Math.sqrt(binsizeX * binsizeX + binsizeY * binsizeY + binsizeZ * binsizeZ) * 0.5;
- const types = Shape.types;
- const SPHERE = types.SPHERE;
- const PLANE = types.PLANE;
- types.BOX;
- types.COMPOUND;
- types.CONVEXPOLYHEDRON;
- const bins = this.bins;
- const binLengths = this.binLengths;
- const Nbins = this.bins.length;
- for (let i = 0; i !== Nbins; i++) {
- binLengths[i] = 0;
- }
- const ceil = Math.ceil;
- function addBoxToBins(x0, y0, z0, x1, y1, z1, bi) {
- let xoff0 = (x0 - xmin) * xmult | 0;
- let yoff0 = (y0 - ymin) * ymult | 0;
- let zoff0 = (z0 - zmin) * zmult | 0;
- let xoff1 = ceil((x1 - xmin) * xmult);
- let yoff1 = ceil((y1 - ymin) * ymult);
- let zoff1 = ceil((z1 - zmin) * zmult);
- if (xoff0 < 0) {
- xoff0 = 0;
- } else if (xoff0 >= nx) {
- xoff0 = nx - 1;
- }
- if (yoff0 < 0) {
- yoff0 = 0;
- } else if (yoff0 >= ny) {
- yoff0 = ny - 1;
- }
- if (zoff0 < 0) {
- zoff0 = 0;
- } else if (zoff0 >= nz) {
- zoff0 = nz - 1;
- }
- if (xoff1 < 0) {
- xoff1 = 0;
- } else if (xoff1 >= nx) {
- xoff1 = nx - 1;
- }
- if (yoff1 < 0) {
- yoff1 = 0;
- } else if (yoff1 >= ny) {
- yoff1 = ny - 1;
- }
- if (zoff1 < 0) {
- zoff1 = 0;
- } else if (zoff1 >= nz) {
- zoff1 = nz - 1;
- }
- xoff0 *= xstep;
- yoff0 *= ystep;
- zoff0 *= zstep;
- xoff1 *= xstep;
- yoff1 *= ystep;
- zoff1 *= zstep;
- for (let xoff = xoff0; xoff <= xoff1; xoff += xstep) {
- for (let yoff = yoff0; yoff <= yoff1; yoff += ystep) {
- for (let zoff = zoff0; zoff <= zoff1; zoff += zstep) {
- const idx = xoff + yoff + zoff;
- bins[idx][binLengths[idx]++] = bi;
- }
- }
- }
- }
- for (let i = 0; i !== N; i++) {
- const bi = bodies[i];
- const si = bi.shapes[0];
- switch (si.type) {
- case SPHERE:
- {
- const shape = si;
-
- const x = bi.position.x;
- const y = bi.position.y;
- const z = bi.position.z;
- const r = shape.radius;
- addBoxToBins(x - r, y - r, z - r, x + r, y + r, z + r, bi);
- break;
- }
- case PLANE:
- {
- const shape = si;
- if (shape.worldNormalNeedsUpdate) {
- shape.computeWorldNormal(bi.quaternion);
- }
- const planeNormal = shape.worldNormal;
-
- const xreset = xmin + binsizeX * 0.5 - bi.position.x;
- const yreset = ymin + binsizeY * 0.5 - bi.position.y;
- const zreset = zmin + binsizeZ * 0.5 - bi.position.z;
- const d = GridBroadphase_collisionPairs_d;
- d.set(xreset, yreset, zreset);
- for (let xi = 0, xoff = 0; xi !== nx; xi++, xoff += xstep, d.y = yreset, d.x += binsizeX) {
- for (let yi = 0, yoff = 0; yi !== ny; yi++, yoff += ystep, d.z = zreset, d.y += binsizeY) {
- for (let zi = 0, zoff = 0; zi !== nz; zi++, zoff += zstep, d.z += binsizeZ) {
- if (d.dot(planeNormal) < binRadius) {
- const idx = xoff + yoff + zoff;
- bins[idx][binLengths[idx]++] = bi;
- }
- }
- }
- }
- break;
- }
- default:
- {
- if (bi.aabbNeedsUpdate) {
- bi.updateAABB();
- }
- addBoxToBins(bi.aabb.lowerBound.x, bi.aabb.lowerBound.y, bi.aabb.lowerBound.z, bi.aabb.upperBound.x, bi.aabb.upperBound.y, bi.aabb.upperBound.z, bi);
- break;
- }
- }
- }
- for (let i = 0; i !== Nbins; i++) {
- const binLength = binLengths[i];
- if (binLength > 1) {
- const bin = bins[i];
- for (let xi = 0; xi !== binLength; xi++) {
- const bi = bin[xi];
- for (let yi = 0; yi !== xi; yi++) {
- const bj = bin[yi];
- if (this.needBroadphaseCollision(bi, bj)) {
- this.intersectionTest(bi, bj, pairs1, pairs2);
- }
- }
- }
- }
- }
-
-
-
-
-
-
-
-
-
-
- this.makePairsUnique(pairs1, pairs2);
- }
- }
- const GridBroadphase_collisionPairs_d = new Vec3();
- new Vec3();
- class NaiveBroadphase extends Broadphase {
-
- constructor() {
- super();
- }
-
- collisionPairs(world, pairs1, pairs2) {
- const bodies = world.bodies;
- const n = bodies.length;
- let bi;
- let bj;
- for (let i = 0; i !== n; i++) {
- for (let j = 0; j !== i; j++) {
- bi = bodies[i];
- bj = bodies[j];
- if (!this.needBroadphaseCollision(bi, bj)) {
- continue;
- }
- this.intersectionTest(bi, bj, pairs1, pairs2);
- }
- }
- }
-
- aabbQuery(world, aabb, result) {
- if (result === void 0) {
- result = [];
- }
- for (let i = 0; i < world.bodies.length; i++) {
- const b = world.bodies[i];
- if (b.aabbNeedsUpdate) {
- b.updateAABB();
- }
- if (b.aabb.overlaps(aabb)) {
- result.push(b);
- }
- }
- return result;
- }
- }
- class RaycastResult {
-
-
-
-
-
-
-
-
-
-
- constructor() {
- this.rayFromWorld = new Vec3();
- this.rayToWorld = new Vec3();
- this.hitNormalWorld = new Vec3();
- this.hitPointWorld = new Vec3();
- this.hasHit = false;
- this.shape = null;
- this.body = null;
- this.hitFaceIndex = -1;
- this.distance = -1;
- this.shouldStop = false;
- }
-
- reset() {
- this.rayFromWorld.setZero();
- this.rayToWorld.setZero();
- this.hitNormalWorld.setZero();
- this.hitPointWorld.setZero();
- this.hasHit = false;
- this.shape = null;
- this.body = null;
- this.hitFaceIndex = -1;
- this.distance = -1;
- this.shouldStop = false;
- }
-
- abort() {
- this.shouldStop = true;
- }
-
- set(rayFromWorld, rayToWorld, hitNormalWorld, hitPointWorld, shape, body, distance) {
- this.rayFromWorld.copy(rayFromWorld);
- this.rayToWorld.copy(rayToWorld);
- this.hitNormalWorld.copy(hitNormalWorld);
- this.hitPointWorld.copy(hitPointWorld);
- this.shape = shape;
- this.body = body;
- this.distance = distance;
- }
- }
- let _Shape$types$SPHERE, _Shape$types$PLANE, _Shape$types$BOX, _Shape$types$CYLINDER, _Shape$types$CONVEXPO, _Shape$types$HEIGHTFI, _Shape$types$TRIMESH;
- const RAY_MODES = {
-
- CLOSEST: 1,
-
- ANY: 2,
-
- ALL: 4
- };
- _Shape$types$SPHERE = Shape.types.SPHERE;
- _Shape$types$PLANE = Shape.types.PLANE;
- _Shape$types$BOX = Shape.types.BOX;
- _Shape$types$CYLINDER = Shape.types.CYLINDER;
- _Shape$types$CONVEXPO = Shape.types.CONVEXPOLYHEDRON;
- _Shape$types$HEIGHTFI = Shape.types.HEIGHTFIELD;
- _Shape$types$TRIMESH = Shape.types.TRIMESH;
- class Ray {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- get [_Shape$types$SPHERE]() {
- return this._intersectSphere;
- }
- get [_Shape$types$PLANE]() {
- return this._intersectPlane;
- }
- get [_Shape$types$BOX]() {
- return this._intersectBox;
- }
- get [_Shape$types$CYLINDER]() {
- return this._intersectConvex;
- }
- get [_Shape$types$CONVEXPO]() {
- return this._intersectConvex;
- }
- get [_Shape$types$HEIGHTFI]() {
- return this._intersectHeightfield;
- }
- get [_Shape$types$TRIMESH]() {
- return this._intersectTrimesh;
- }
- constructor(from, to) {
- if (from === void 0) {
- from = new Vec3();
- }
- if (to === void 0) {
- to = new Vec3();
- }
- this.from = from.clone();
- this.to = to.clone();
- this.direction = new Vec3();
- this.precision = 0.0001;
- this.checkCollisionResponse = true;
- this.skipBackfaces = false;
- this.collisionFilterMask = -1;
- this.collisionFilterGroup = -1;
- this.mode = Ray.ANY;
- this.result = new RaycastResult();
- this.hasHit = false;
- this.callback = result => {};
- }
-
- intersectWorld(world, options) {
- this.mode = options.mode || Ray.ANY;
- this.result = options.result || new RaycastResult();
- this.skipBackfaces = !!options.skipBackfaces;
- this.collisionFilterMask = typeof options.collisionFilterMask !== 'undefined' ? options.collisionFilterMask : -1;
- this.collisionFilterGroup = typeof options.collisionFilterGroup !== 'undefined' ? options.collisionFilterGroup : -1;
- this.checkCollisionResponse = typeof options.checkCollisionResponse !== 'undefined' ? options.checkCollisionResponse : true;
- if (options.from) {
- this.from.copy(options.from);
- }
- if (options.to) {
- this.to.copy(options.to);
- }
- this.callback = options.callback || (() => {});
- this.hasHit = false;
- this.result.reset();
- this.updateDirection();
- this.getAABB(tmpAABB$1);
- tmpArray.length = 0;
- world.broadphase.aabbQuery(world, tmpAABB$1, tmpArray);
- this.intersectBodies(tmpArray);
- return this.hasHit;
- }
-
- intersectBody(body, result) {
- if (result) {
- this.result = result;
- this.updateDirection();
- }
- const checkCollisionResponse = this.checkCollisionResponse;
- if (checkCollisionResponse && !body.collisionResponse) {
- return;
- }
- if ((this.collisionFilterGroup & body.collisionFilterMask) === 0 || (body.collisionFilterGroup & this.collisionFilterMask) === 0) {
- return;
- }
- const xi = intersectBody_xi;
- const qi = intersectBody_qi;
- for (let i = 0, N = body.shapes.length; i < N; i++) {
- const shape = body.shapes[i];
- if (checkCollisionResponse && !shape.collisionResponse) {
- continue;
- }
- body.quaternion.mult(body.shapeOrientations[i], qi);
- body.quaternion.vmult(body.shapeOffsets[i], xi);
- xi.vadd(body.position, xi);
- this.intersectShape(shape, qi, xi, body);
- if (this.result.shouldStop) {
- break;
- }
- }
- }
-
- intersectBodies(bodies, result) {
- if (result) {
- this.result = result;
- this.updateDirection();
- }
- for (let i = 0, l = bodies.length; !this.result.shouldStop && i < l; i++) {
- this.intersectBody(bodies[i]);
- }
- }
-
- updateDirection() {
- this.to.vsub(this.from, this.direction);
- this.direction.normalize();
- }
- intersectShape(shape, quat, position, body) {
- const from = this.from;
- const distance = distanceFromIntersection(from, this.direction, position);
- if (distance > shape.boundingSphereRadius) {
- return;
- }
- const intersectMethod = this[shape.type];
- if (intersectMethod) {
- intersectMethod.call(this, shape, quat, position, body, shape);
- }
- }
- _intersectBox(box, quat, position, body, reportedShape) {
- return this._intersectConvex(box.convexPolyhedronRepresentation, quat, position, body, reportedShape);
- }
- _intersectPlane(shape, quat, position, body, reportedShape) {
- const from = this.from;
- const to = this.to;
- const direction = this.direction;
- const worldNormal = new Vec3(0, 0, 1);
- quat.vmult(worldNormal, worldNormal);
- const len = new Vec3();
- from.vsub(position, len);
- const planeToFrom = len.dot(worldNormal);
- to.vsub(position, len);
- const planeToTo = len.dot(worldNormal);
- if (planeToFrom * planeToTo > 0) {
-
- return;
- }
- if (from.distanceTo(to) < planeToFrom) {
- return;
- }
- const n_dot_dir = worldNormal.dot(direction);
- if (Math.abs(n_dot_dir) < this.precision) {
-
- return;
- }
- const planePointToFrom = new Vec3();
- const dir_scaled_with_t = new Vec3();
- const hitPointWorld = new Vec3();
- from.vsub(position, planePointToFrom);
- const t = -worldNormal.dot(planePointToFrom) / n_dot_dir;
- direction.scale(t, dir_scaled_with_t);
- from.vadd(dir_scaled_with_t, hitPointWorld);
- this.reportIntersection(worldNormal, hitPointWorld, reportedShape, body, -1);
- }
-
- getAABB(aabb) {
- const {
- lowerBound,
- upperBound
- } = aabb;
- const to = this.to;
- const from = this.from;
- lowerBound.x = Math.min(to.x, from.x);
- lowerBound.y = Math.min(to.y, from.y);
- lowerBound.z = Math.min(to.z, from.z);
- upperBound.x = Math.max(to.x, from.x);
- upperBound.y = Math.max(to.y, from.y);
- upperBound.z = Math.max(to.z, from.z);
- }
- _intersectHeightfield(shape, quat, position, body, reportedShape) {
- shape.data;
- shape.elementSize;
- const localRay = intersectHeightfield_localRay;
- localRay.from.copy(this.from);
- localRay.to.copy(this.to);
- Transform.pointToLocalFrame(position, quat, localRay.from, localRay.from);
- Transform.pointToLocalFrame(position, quat, localRay.to, localRay.to);
- localRay.updateDirection();
- const index = intersectHeightfield_index;
- let iMinX;
- let iMinY;
- let iMaxX;
- let iMaxY;
- iMinX = iMinY = 0;
- iMaxX = iMaxY = shape.data.length - 1;
- const aabb = new AABB();
- localRay.getAABB(aabb);
- shape.getIndexOfPosition(aabb.lowerBound.x, aabb.lowerBound.y, index, true);
- iMinX = Math.max(iMinX, index[0]);
- iMinY = Math.max(iMinY, index[1]);
- shape.getIndexOfPosition(aabb.upperBound.x, aabb.upperBound.y, index, true);
- iMaxX = Math.min(iMaxX, index[0] + 1);
- iMaxY = Math.min(iMaxY, index[1] + 1);
- for (let i = iMinX; i < iMaxX; i++) {
- for (let j = iMinY; j < iMaxY; j++) {
- if (this.result.shouldStop) {
- return;
- }
- shape.getAabbAtIndex(i, j, aabb);
- if (!aabb.overlapsRay(localRay)) {
- continue;
- }
- shape.getConvexTrianglePillar(i, j, false);
- Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
- this._intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
- if (this.result.shouldStop) {
- return;
- }
- shape.getConvexTrianglePillar(i, j, true);
- Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
- this._intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
- }
- }
- }
- _intersectSphere(sphere, quat, position, body, reportedShape) {
- const from = this.from;
- const to = this.to;
- const r = sphere.radius;
- const a = (to.x - from.x) ** 2 + (to.y - from.y) ** 2 + (to.z - from.z) ** 2;
- const b = 2 * ((to.x - from.x) * (from.x - position.x) + (to.y - from.y) * (from.y - position.y) + (to.z - from.z) * (from.z - position.z));
- const c = (from.x - position.x) ** 2 + (from.y - position.y) ** 2 + (from.z - position.z) ** 2 - r ** 2;
- const delta = b ** 2 - 4 * a * c;
- const intersectionPoint = Ray_intersectSphere_intersectionPoint;
- const normal = Ray_intersectSphere_normal;
- if (delta < 0) {
-
- return;
- } else if (delta === 0) {
-
- from.lerp(to, delta, intersectionPoint);
- intersectionPoint.vsub(position, normal);
- normal.normalize();
- this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
- } else {
- const d1 = (-b - Math.sqrt(delta)) / (2 * a);
- const d2 = (-b + Math.sqrt(delta)) / (2 * a);
- if (d1 >= 0 && d1 <= 1) {
- from.lerp(to, d1, intersectionPoint);
- intersectionPoint.vsub(position, normal);
- normal.normalize();
- this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
- }
- if (this.result.shouldStop) {
- return;
- }
- if (d2 >= 0 && d2 <= 1) {
- from.lerp(to, d2, intersectionPoint);
- intersectionPoint.vsub(position, normal);
- normal.normalize();
- this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
- }
- }
- }
- _intersectConvex(shape, quat, position, body, reportedShape, options) {
- intersectConvex_minDistNormal;
- const normal = intersectConvex_normal;
- const vector = intersectConvex_vector;
- intersectConvex_minDistIntersect;
- const faceList = options && options.faceList || null;
- const faces = shape.faces;
- const vertices = shape.vertices;
- const normals = shape.faceNormals;
- const direction = this.direction;
- const from = this.from;
- const to = this.to;
- const fromToDistance = from.distanceTo(to);
- const Nfaces = faceList ? faceList.length : faces.length;
- const result = this.result;
- for (let j = 0; !result.shouldStop && j < Nfaces; j++) {
- const fi = faceList ? faceList[j] : j;
- const face = faces[fi];
- const faceNormal = normals[fi];
- const q = quat;
- const x = position;
-
-
- vector.copy(vertices[face[0]]);
- q.vmult(vector, vector);
- vector.vadd(x, vector);
- vector.vsub(from, vector);
- q.vmult(faceNormal, normal);
- const dot = direction.dot(normal);
- if (Math.abs(dot) < this.precision) {
- continue;
- }
- const scalar = normal.dot(vector) / dot;
- if (scalar < 0) {
- continue;
- }
-
- direction.scale(scalar, intersectPoint);
- intersectPoint.vadd(from, intersectPoint);
- a.copy(vertices[face[0]]);
- q.vmult(a, a);
- x.vadd(a, a);
- for (let i = 1; !result.shouldStop && i < face.length - 1; i++) {
-
- b.copy(vertices[face[i]]);
- c.copy(vertices[face[i + 1]]);
- q.vmult(b, b);
- q.vmult(c, c);
- x.vadd(b, b);
- x.vadd(c, c);
- const distance = intersectPoint.distanceTo(from);
- if (!(Ray.pointInTriangle(intersectPoint, a, b, c) || Ray.pointInTriangle(intersectPoint, b, a, c)) || distance > fromToDistance) {
- continue;
- }
- this.reportIntersection(normal, intersectPoint, reportedShape, body, fi);
- }
- }
- }
-
- _intersectTrimesh(mesh, quat, position, body, reportedShape, options) {
- const normal = intersectTrimesh_normal;
- const triangles = intersectTrimesh_triangles;
- const treeTransform = intersectTrimesh_treeTransform;
- const vector = intersectConvex_vector;
- const localDirection = intersectTrimesh_localDirection;
- const localFrom = intersectTrimesh_localFrom;
- const localTo = intersectTrimesh_localTo;
- const worldIntersectPoint = intersectTrimesh_worldIntersectPoint;
- const worldNormal = intersectTrimesh_worldNormal;
- const indices = mesh.indices;
- mesh.vertices;
- const from = this.from;
- const to = this.to;
- const direction = this.direction;
- treeTransform.position.copy(position);
- treeTransform.quaternion.copy(quat);
- Transform.vectorToLocalFrame(position, quat, direction, localDirection);
- Transform.pointToLocalFrame(position, quat, from, localFrom);
- Transform.pointToLocalFrame(position, quat, to, localTo);
- localTo.x *= mesh.scale.x;
- localTo.y *= mesh.scale.y;
- localTo.z *= mesh.scale.z;
- localFrom.x *= mesh.scale.x;
- localFrom.y *= mesh.scale.y;
- localFrom.z *= mesh.scale.z;
- localTo.vsub(localFrom, localDirection);
- localDirection.normalize();
- const fromToDistanceSquared = localFrom.distanceSquared(localTo);
- mesh.tree.rayQuery(this, treeTransform, triangles);
- for (let i = 0, N = triangles.length; !this.result.shouldStop && i !== N; i++) {
- const trianglesIndex = triangles[i];
- mesh.getNormal(trianglesIndex, normal);
-
-
- mesh.getVertex(indices[trianglesIndex * 3], a);
- a.vsub(localFrom, vector);
- const dot = localDirection.dot(normal);
-
-
-
-
- const scalar = normal.dot(vector) / dot;
- if (scalar < 0) {
- continue;
- }
- localDirection.scale(scalar, intersectPoint);
- intersectPoint.vadd(localFrom, intersectPoint);
- mesh.getVertex(indices[trianglesIndex * 3 + 1], b);
- mesh.getVertex(indices[trianglesIndex * 3 + 2], c);
- const squaredDistance = intersectPoint.distanceSquared(localFrom);
- if (!(Ray.pointInTriangle(intersectPoint, b, a, c) || Ray.pointInTriangle(intersectPoint, a, b, c)) || squaredDistance > fromToDistanceSquared) {
- continue;
- }
- Transform.vectorToWorldFrame(quat, normal, worldNormal);
- Transform.pointToWorldFrame(position, quat, intersectPoint, worldIntersectPoint);
- this.reportIntersection(worldNormal, worldIntersectPoint, reportedShape, body, trianglesIndex);
- }
- triangles.length = 0;
- }
-
- reportIntersection(normal, hitPointWorld, shape, body, hitFaceIndex) {
- const from = this.from;
- const to = this.to;
- const distance = from.distanceTo(hitPointWorld);
- const result = this.result;
- if (this.skipBackfaces && normal.dot(this.direction) > 0) {
- return;
- }
- result.hitFaceIndex = typeof hitFaceIndex !== 'undefined' ? hitFaceIndex : -1;
- switch (this.mode) {
- case Ray.ALL:
- this.hasHit = true;
- result.set(from, to, normal, hitPointWorld, shape, body, distance);
- result.hasHit = true;
- this.callback(result);
- break;
- case Ray.CLOSEST:
-
- if (distance < result.distance || !result.hasHit) {
- this.hasHit = true;
- result.hasHit = true;
- result.set(from, to, normal, hitPointWorld, shape, body, distance);
- }
- break;
- case Ray.ANY:
-
- this.hasHit = true;
- result.hasHit = true;
- result.set(from, to, normal, hitPointWorld, shape, body, distance);
- result.shouldStop = true;
- break;
- }
- }
-
- static pointInTriangle(p, a, b, c) {
- c.vsub(a, v0);
- b.vsub(a, v1);
- p.vsub(a, v2);
- const dot00 = v0.dot(v0);
- const dot01 = v0.dot(v1);
- const dot02 = v0.dot(v2);
- const dot11 = v1.dot(v1);
- const dot12 = v1.dot(v2);
- let u;
- let v;
- return (u = dot11 * dot02 - dot01 * dot12) >= 0 && (v = dot00 * dot12 - dot01 * dot02) >= 0 && u + v < dot00 * dot11 - dot01 * dot01;
- }
- }
- Ray.CLOSEST = RAY_MODES.CLOSEST;
- Ray.ANY = RAY_MODES.ANY;
- Ray.ALL = RAY_MODES.ALL;
- const tmpAABB$1 = new AABB();
- const tmpArray = [];
- const v1 = new Vec3();
- const v2 = new Vec3();
- const intersectBody_xi = new Vec3();
- const intersectBody_qi = new Quaternion();
- const intersectPoint = new Vec3();
- const a = new Vec3();
- const b = new Vec3();
- const c = new Vec3();
- new Vec3();
- new RaycastResult();
- const intersectConvexOptions = {
- faceList: [0]
- };
- const worldPillarOffset = new Vec3();
- const intersectHeightfield_localRay = new Ray();
- const intersectHeightfield_index = [];
- const Ray_intersectSphere_intersectionPoint = new Vec3();
- const Ray_intersectSphere_normal = new Vec3();
- const intersectConvex_normal = new Vec3();
- const intersectConvex_minDistNormal = new Vec3();
- const intersectConvex_minDistIntersect = new Vec3();
- const intersectConvex_vector = new Vec3();
- const intersectTrimesh_normal = new Vec3();
- const intersectTrimesh_localDirection = new Vec3();
- const intersectTrimesh_localFrom = new Vec3();
- const intersectTrimesh_localTo = new Vec3();
- const intersectTrimesh_worldNormal = new Vec3();
- const intersectTrimesh_worldIntersectPoint = new Vec3();
- new AABB();
- const intersectTrimesh_triangles = [];
- const intersectTrimesh_treeTransform = new Transform();
- const v0 = new Vec3();
- const intersect = new Vec3();
- function distanceFromIntersection(from, direction, position) {
-
- position.vsub(from, v0);
- const dot = v0.dot(direction);
- direction.scale(dot, intersect);
- intersect.vadd(from, intersect);
- const distance = position.distanceTo(intersect);
- return distance;
- }
- class SAPBroadphase extends Broadphase {
-
-
-
-
- static checkBounds(bi, bj, axisIndex) {
- let biPos;
- let bjPos;
- if (axisIndex === 0) {
- biPos = bi.position.x;
- bjPos = bj.position.x;
- } else if (axisIndex === 1) {
- biPos = bi.position.y;
- bjPos = bj.position.y;
- } else if (axisIndex === 2) {
- biPos = bi.position.z;
- bjPos = bj.position.z;
- }
- const ri = bi.boundingRadius,
- rj = bj.boundingRadius,
- boundA2 = biPos + ri,
- boundB1 = bjPos - rj;
- return boundB1 < boundA2;
- }
-
- static insertionSortX(a) {
- for (let i = 1, l = a.length; i < l; i++) {
- const v = a[i];
- let j;
- for (j = i - 1; j >= 0; j--) {
- if (a[j].aabb.lowerBound.x <= v.aabb.lowerBound.x) {
- break;
- }
- a[j + 1] = a[j];
- }
- a[j + 1] = v;
- }
- return a;
- }
-
- static insertionSortY(a) {
- for (let i = 1, l = a.length; i < l; i++) {
- const v = a[i];
- let j;
- for (j = i - 1; j >= 0; j--) {
- if (a[j].aabb.lowerBound.y <= v.aabb.lowerBound.y) {
- break;
- }
- a[j + 1] = a[j];
- }
- a[j + 1] = v;
- }
- return a;
- }
-
- static insertionSortZ(a) {
- for (let i = 1, l = a.length; i < l; i++) {
- const v = a[i];
- let j;
- for (j = i - 1; j >= 0; j--) {
- if (a[j].aabb.lowerBound.z <= v.aabb.lowerBound.z) {
- break;
- }
- a[j + 1] = a[j];
- }
- a[j + 1] = v;
- }
- return a;
- }
- constructor(world) {
- super();
- this.axisList = [];
- this.world = null;
- this.axisIndex = 0;
- const axisList = this.axisList;
- this._addBodyHandler = event => {
- axisList.push(event.body);
- };
- this._removeBodyHandler = event => {
- const idx = axisList.indexOf(event.body);
- if (idx !== -1) {
- axisList.splice(idx, 1);
- }
- };
- if (world) {
- this.setWorld(world);
- }
- }
-
- setWorld(world) {
-
- this.axisList.length = 0;
- for (let i = 0; i < world.bodies.length; i++) {
- this.axisList.push(world.bodies[i]);
- }
- world.removeEventListener('addBody', this._addBodyHandler);
- world.removeEventListener('removeBody', this._removeBodyHandler);
- world.addEventListener('addBody', this._addBodyHandler);
- world.addEventListener('removeBody', this._removeBodyHandler);
- this.world = world;
- this.dirty = true;
- }
-
- collisionPairs(world, p1, p2) {
- const bodies = this.axisList;
- const N = bodies.length;
- const axisIndex = this.axisIndex;
- let i;
- let j;
- if (this.dirty) {
- this.sortList();
- this.dirty = false;
- }
- for (i = 0; i !== N; i++) {
- const bi = bodies[i];
- for (j = i + 1; j < N; j++) {
- const bj = bodies[j];
- if (!this.needBroadphaseCollision(bi, bj)) {
- continue;
- }
- if (!SAPBroadphase.checkBounds(bi, bj, axisIndex)) {
- break;
- }
- this.intersectionTest(bi, bj, p1, p2);
- }
- }
- }
- sortList() {
- const axisList = this.axisList;
- const axisIndex = this.axisIndex;
- const N = axisList.length;
- for (let i = 0; i !== N; i++) {
- const bi = axisList[i];
- if (bi.aabbNeedsUpdate) {
- bi.updateAABB();
- }
- }
- if (axisIndex === 0) {
- SAPBroadphase.insertionSortX(axisList);
- } else if (axisIndex === 1) {
- SAPBroadphase.insertionSortY(axisList);
- } else if (axisIndex === 2) {
- SAPBroadphase.insertionSortZ(axisList);
- }
- }
-
- autoDetectAxis() {
- let sumX = 0;
- let sumX2 = 0;
- let sumY = 0;
- let sumY2 = 0;
- let sumZ = 0;
- let sumZ2 = 0;
- const bodies = this.axisList;
- const N = bodies.length;
- const invN = 1 / N;
- for (let i = 0; i !== N; i++) {
- const b = bodies[i];
- const centerX = b.position.x;
- sumX += centerX;
- sumX2 += centerX * centerX;
- const centerY = b.position.y;
- sumY += centerY;
- sumY2 += centerY * centerY;
- const centerZ = b.position.z;
- sumZ += centerZ;
- sumZ2 += centerZ * centerZ;
- }
- const varianceX = sumX2 - sumX * sumX * invN;
- const varianceY = sumY2 - sumY * sumY * invN;
- const varianceZ = sumZ2 - sumZ * sumZ * invN;
- if (varianceX > varianceY) {
- if (varianceX > varianceZ) {
- this.axisIndex = 0;
- } else {
- this.axisIndex = 2;
- }
- } else if (varianceY > varianceZ) {
- this.axisIndex = 1;
- } else {
- this.axisIndex = 2;
- }
- }
-
- aabbQuery(world, aabb, result) {
- if (result === void 0) {
- result = [];
- }
- if (this.dirty) {
- this.sortList();
- this.dirty = false;
- }
- const axisIndex = this.axisIndex;
- let axis = 'x';
- if (axisIndex === 1) {
- axis = 'y';
- }
- if (axisIndex === 2) {
- axis = 'z';
- }
- const axisList = this.axisList;
- aabb.lowerBound[axis];
- aabb.upperBound[axis];
- for (let i = 0; i < axisList.length; i++) {
- const b = axisList[i];
- if (b.aabbNeedsUpdate) {
- b.updateAABB();
- }
- if (b.aabb.overlaps(aabb)) {
- result.push(b);
- }
- }
- return result;
- }
- }
- class Utils {
-
- static defaults(options, defaults) {
- if (options === void 0) {
- options = {};
- }
- for (let key in defaults) {
- if (!(key in options)) {
- options[key] = defaults[key];
- }
- }
- return options;
- }
- }
- class Constraint {
-
-
-
-
- constructor(bodyA, bodyB, options) {
- if (options === void 0) {
- options = {};
- }
- options = Utils.defaults(options, {
- collideConnected: true,
- wakeUpBodies: true
- });
- this.equations = [];
- this.bodyA = bodyA;
- this.bodyB = bodyB;
- this.id = Constraint.idCounter++;
- this.collideConnected = options.collideConnected;
- if (options.wakeUpBodies) {
- if (bodyA) {
- bodyA.wakeUp();
- }
- if (bodyB) {
- bodyB.wakeUp();
- }
- }
- }
-
- update() {
- throw new Error('method update() not implmemented in this Constraint subclass!');
- }
-
- enable() {
- const eqs = this.equations;
- for (let i = 0; i < eqs.length; i++) {
- eqs[i].enabled = true;
- }
- }
-
- disable() {
- const eqs = this.equations;
- for (let i = 0; i < eqs.length; i++) {
- eqs[i].enabled = false;
- }
- }
- }
- Constraint.idCounter = 0;
- class JacobianElement {
-
-
- constructor() {
- this.spatial = new Vec3();
- this.rotational = new Vec3();
- }
-
- multiplyElement(element) {
- return element.spatial.dot(this.spatial) + element.rotational.dot(this.rotational);
- }
-
- multiplyVectors(spatial, rotational) {
- return spatial.dot(this.spatial) + rotational.dot(this.rotational);
- }
- }
- class Equation {
-
-
-
-
-
-
- constructor(bi, bj, minForce, maxForce) {
- if (minForce === void 0) {
- minForce = -1e6;
- }
- if (maxForce === void 0) {
- maxForce = 1e6;
- }
- this.id = Equation.idCounter++;
- this.minForce = minForce;
- this.maxForce = maxForce;
- this.bi = bi;
- this.bj = bj;
- this.a = 0.0;
- this.b = 0.0;
- this.eps = 0.0;
- this.jacobianElementA = new JacobianElement();
- this.jacobianElementB = new JacobianElement();
- this.enabled = true;
- this.multiplier = 0;
- this.setSpookParams(1e7, 4, 1 / 60);
- }
-
- setSpookParams(stiffness, relaxation, timeStep) {
- const d = relaxation;
- const k = stiffness;
- const h = timeStep;
- this.a = 4.0 / (h * (1 + 4 * d));
- this.b = 4.0 * d / (1 + 4 * d);
- this.eps = 4.0 / (h * h * k * (1 + 4 * d));
- }
-
- computeB(a, b, h) {
- const GW = this.computeGW();
- const Gq = this.computeGq();
- const GiMf = this.computeGiMf();
- return -Gq * a - GW * b - GiMf * h;
- }
-
- computeGq() {
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- const bi = this.bi;
- const bj = this.bj;
- const xi = bi.position;
- const xj = bj.position;
- return GA.spatial.dot(xi) + GB.spatial.dot(xj);
- }
-
- computeGW() {
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- const bi = this.bi;
- const bj = this.bj;
- const vi = bi.velocity;
- const vj = bj.velocity;
- const wi = bi.angularVelocity;
- const wj = bj.angularVelocity;
- return GA.multiplyVectors(vi, wi) + GB.multiplyVectors(vj, wj);
- }
-
- computeGWlambda() {
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- const bi = this.bi;
- const bj = this.bj;
- const vi = bi.vlambda;
- const vj = bj.vlambda;
- const wi = bi.wlambda;
- const wj = bj.wlambda;
- return GA.multiplyVectors(vi, wi) + GB.multiplyVectors(vj, wj);
- }
-
- computeGiMf() {
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- const bi = this.bi;
- const bj = this.bj;
- const fi = bi.force;
- const ti = bi.torque;
- const fj = bj.force;
- const tj = bj.torque;
- const invMassi = bi.invMassSolve;
- const invMassj = bj.invMassSolve;
- fi.scale(invMassi, iMfi);
- fj.scale(invMassj, iMfj);
- bi.invInertiaWorldSolve.vmult(ti, invIi_vmult_taui);
- bj.invInertiaWorldSolve.vmult(tj, invIj_vmult_tauj);
- return GA.multiplyVectors(iMfi, invIi_vmult_taui) + GB.multiplyVectors(iMfj, invIj_vmult_tauj);
- }
-
- computeGiMGt() {
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- const bi = this.bi;
- const bj = this.bj;
- const invMassi = bi.invMassSolve;
- const invMassj = bj.invMassSolve;
- const invIi = bi.invInertiaWorldSolve;
- const invIj = bj.invInertiaWorldSolve;
- let result = invMassi + invMassj;
- invIi.vmult(GA.rotational, tmp);
- result += tmp.dot(GA.rotational);
- invIj.vmult(GB.rotational, tmp);
- result += tmp.dot(GB.rotational);
- return result;
- }
-
- addToWlambda(deltalambda) {
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- const bi = this.bi;
- const bj = this.bj;
- const temp = addToWlambda_temp;
-
- bi.vlambda.addScaledVector(bi.invMassSolve * deltalambda, GA.spatial, bi.vlambda);
- bj.vlambda.addScaledVector(bj.invMassSolve * deltalambda, GB.spatial, bj.vlambda);
- bi.invInertiaWorldSolve.vmult(GA.rotational, temp);
- bi.wlambda.addScaledVector(deltalambda, temp, bi.wlambda);
- bj.invInertiaWorldSolve.vmult(GB.rotational, temp);
- bj.wlambda.addScaledVector(deltalambda, temp, bj.wlambda);
- }
-
- computeC() {
- return this.computeGiMGt() + this.eps;
- }
- }
- Equation.idCounter = 0;
- const iMfi = new Vec3();
- const iMfj = new Vec3();
- const invIi_vmult_taui = new Vec3();
- const invIj_vmult_tauj = new Vec3();
- const tmp = new Vec3();
- const addToWlambda_temp = new Vec3();
- class ContactEquation extends Equation {
-
-
-
-
- constructor(bodyA, bodyB, maxForce) {
- if (maxForce === void 0) {
- maxForce = 1e6;
- }
- super(bodyA, bodyB, 0, maxForce);
- this.restitution = 0.0;
- this.ri = new Vec3();
- this.rj = new Vec3();
- this.ni = new Vec3();
- }
- computeB(h) {
- const a = this.a;
- const b = this.b;
- const bi = this.bi;
- const bj = this.bj;
- const ri = this.ri;
- const rj = this.rj;
- const rixn = ContactEquation_computeB_temp1;
- const rjxn = ContactEquation_computeB_temp2;
- const vi = bi.velocity;
- const wi = bi.angularVelocity;
- bi.force;
- bi.torque;
- const vj = bj.velocity;
- const wj = bj.angularVelocity;
- bj.force;
- bj.torque;
- const penetrationVec = ContactEquation_computeB_temp3;
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- const n = this.ni;
- ri.cross(n, rixn);
- rj.cross(n, rjxn);
-
- n.negate(GA.spatial);
- rixn.negate(GA.rotational);
- GB.spatial.copy(n);
- GB.rotational.copy(rjxn);
- penetrationVec.copy(bj.position);
- penetrationVec.vadd(rj, penetrationVec);
- penetrationVec.vsub(bi.position, penetrationVec);
- penetrationVec.vsub(ri, penetrationVec);
- const g = n.dot(penetrationVec);
- const ePlusOne = this.restitution + 1;
- const GW = ePlusOne * vj.dot(n) - ePlusOne * vi.dot(n) + wj.dot(rjxn) - wi.dot(rixn);
- const GiMf = this.computeGiMf();
- const B = -g * a - GW * b - h * GiMf;
- return B;
- }
-
- getImpactVelocityAlongNormal() {
- const vi = ContactEquation_getImpactVelocityAlongNormal_vi;
- const vj = ContactEquation_getImpactVelocityAlongNormal_vj;
- const xi = ContactEquation_getImpactVelocityAlongNormal_xi;
- const xj = ContactEquation_getImpactVelocityAlongNormal_xj;
- const relVel = ContactEquation_getImpactVelocityAlongNormal_relVel;
- this.bi.position.vadd(this.ri, xi);
- this.bj.position.vadd(this.rj, xj);
- this.bi.getVelocityAtWorldPoint(xi, vi);
- this.bj.getVelocityAtWorldPoint(xj, vj);
- vi.vsub(vj, relVel);
- return this.ni.dot(relVel);
- }
- }
- const ContactEquation_computeB_temp1 = new Vec3();
- const ContactEquation_computeB_temp2 = new Vec3();
- const ContactEquation_computeB_temp3 = new Vec3();
- const ContactEquation_getImpactVelocityAlongNormal_vi = new Vec3();
- const ContactEquation_getImpactVelocityAlongNormal_vj = new Vec3();
- const ContactEquation_getImpactVelocityAlongNormal_xi = new Vec3();
- const ContactEquation_getImpactVelocityAlongNormal_xj = new Vec3();
- const ContactEquation_getImpactVelocityAlongNormal_relVel = new Vec3();
- class PointToPointConstraint extends Constraint {
-
-
-
- constructor(bodyA, pivotA, bodyB, pivotB, maxForce) {
- if (pivotA === void 0) {
- pivotA = new Vec3();
- }
- if (pivotB === void 0) {
- pivotB = new Vec3();
- }
- if (maxForce === void 0) {
- maxForce = 1e6;
- }
- super(bodyA, bodyB);
- this.pivotA = pivotA.clone();
- this.pivotB = pivotB.clone();
- const x = this.equationX = new ContactEquation(bodyA, bodyB);
- const y = this.equationY = new ContactEquation(bodyA, bodyB);
- const z = this.equationZ = new ContactEquation(bodyA, bodyB);
- this.equations.push(x, y, z);
- x.minForce = y.minForce = z.minForce = -maxForce;
- x.maxForce = y.maxForce = z.maxForce = maxForce;
- x.ni.set(1, 0, 0);
- y.ni.set(0, 1, 0);
- z.ni.set(0, 0, 1);
- }
- update() {
- const bodyA = this.bodyA;
- const bodyB = this.bodyB;
- const x = this.equationX;
- const y = this.equationY;
- const z = this.equationZ;
- bodyA.quaternion.vmult(this.pivotA, x.ri);
- bodyB.quaternion.vmult(this.pivotB, x.rj);
- y.ri.copy(x.ri);
- y.rj.copy(x.rj);
- z.ri.copy(x.ri);
- z.rj.copy(x.rj);
- }
- }
- class ConeEquation extends Equation {
-
-
-
- constructor(bodyA, bodyB, options) {
- if (options === void 0) {
- options = {};
- }
- const maxForce = typeof options.maxForce !== 'undefined' ? options.maxForce : 1e6;
- super(bodyA, bodyB, -maxForce, maxForce);
- this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
- this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
- this.angle = typeof options.angle !== 'undefined' ? options.angle : 0;
- }
- computeB(h) {
- const a = this.a;
- const b = this.b;
- const ni = this.axisA;
- const nj = this.axisB;
- const nixnj = tmpVec1$2;
- const njxni = tmpVec2$2;
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- ni.cross(nj, nixnj);
- nj.cross(ni, njxni);
-
-
-
-
-
- GA.rotational.copy(njxni);
- GB.rotational.copy(nixnj);
- const g = Math.cos(this.angle) - ni.dot(nj);
- const GW = this.computeGW();
- const GiMf = this.computeGiMf();
- const B = -g * a - GW * b - h * GiMf;
- return B;
- }
- }
- const tmpVec1$2 = new Vec3();
- const tmpVec2$2 = new Vec3();
- class RotationalEquation extends Equation {
-
-
-
- constructor(bodyA, bodyB, options) {
- if (options === void 0) {
- options = {};
- }
- const maxForce = typeof options.maxForce !== 'undefined' ? options.maxForce : 1e6;
- super(bodyA, bodyB, -maxForce, maxForce);
- this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
- this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
- this.maxAngle = Math.PI / 2;
- }
- computeB(h) {
- const a = this.a;
- const b = this.b;
- const ni = this.axisA;
- const nj = this.axisB;
- const nixnj = tmpVec1$1;
- const njxni = tmpVec2$1;
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- ni.cross(nj, nixnj);
- nj.cross(ni, njxni);
-
-
-
- GA.rotational.copy(njxni);
- GB.rotational.copy(nixnj);
- const g = Math.cos(this.maxAngle) - ni.dot(nj);
- const GW = this.computeGW();
- const GiMf = this.computeGiMf();
- const B = -g * a - GW * b - h * GiMf;
- return B;
- }
- }
- const tmpVec1$1 = new Vec3();
- const tmpVec2$1 = new Vec3();
- class ConeTwistConstraint extends PointToPointConstraint {
-
-
-
-
- constructor(bodyA, bodyB, options) {
- if (options === void 0) {
- options = {};
- }
- const maxForce = typeof options.maxForce !== 'undefined' ? options.maxForce : 1e6;
- const pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
- const pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
- super(bodyA, pivotA, bodyB, pivotB, maxForce);
- this.axisA = options.axisA ? options.axisA.clone() : new Vec3();
- this.axisB = options.axisB ? options.axisB.clone() : new Vec3();
- this.collideConnected = !!options.collideConnected;
- this.angle = typeof options.angle !== 'undefined' ? options.angle : 0;
- const c = this.coneEquation = new ConeEquation(bodyA, bodyB, options);
- const t = this.twistEquation = new RotationalEquation(bodyA, bodyB, options);
- this.twistAngle = typeof options.twistAngle !== 'undefined' ? options.twistAngle : 0;
- c.maxForce = 0;
- c.minForce = -maxForce;
- t.maxForce = 0;
- t.minForce = -maxForce;
- this.equations.push(c, t);
- }
- update() {
- const bodyA = this.bodyA;
- const bodyB = this.bodyB;
- const cone = this.coneEquation;
- const twist = this.twistEquation;
- super.update();
- bodyA.vectorToWorldFrame(this.axisA, cone.axisA);
- bodyB.vectorToWorldFrame(this.axisB, cone.axisB);
- this.axisA.tangents(twist.axisA, twist.axisA);
- bodyA.vectorToWorldFrame(twist.axisA, twist.axisA);
- this.axisB.tangents(twist.axisB, twist.axisB);
- bodyB.vectorToWorldFrame(twist.axisB, twist.axisB);
- cone.angle = this.angle;
- twist.maxAngle = this.twistAngle;
- }
- }
- new Vec3();
- new Vec3();
- class DistanceConstraint extends Constraint {
-
-
- constructor(bodyA, bodyB, distance, maxForce) {
- if (maxForce === void 0) {
- maxForce = 1e6;
- }
- super(bodyA, bodyB);
- if (typeof distance === 'undefined') {
- distance = bodyA.position.distanceTo(bodyB.position);
- }
- this.distance = distance;
- const eq = this.distanceEquation = new ContactEquation(bodyA, bodyB);
- this.equations.push(eq);
- eq.minForce = -maxForce;
- eq.maxForce = maxForce;
- }
-
- update() {
- const bodyA = this.bodyA;
- const bodyB = this.bodyB;
- const eq = this.distanceEquation;
- const halfDist = this.distance * 0.5;
- const normal = eq.ni;
- bodyB.position.vsub(bodyA.position, normal);
- normal.normalize();
- normal.scale(halfDist, eq.ri);
- normal.scale(-halfDist, eq.rj);
- }
- }
- class LockConstraint extends PointToPointConstraint {
- constructor(bodyA, bodyB, options) {
- if (options === void 0) {
- options = {};
- }
- const maxForce = typeof options.maxForce !== 'undefined' ? options.maxForce : 1e6;
- const pivotA = new Vec3();
- const pivotB = new Vec3();
- const halfWay = new Vec3();
- bodyA.position.vadd(bodyB.position, halfWay);
- halfWay.scale(0.5, halfWay);
- bodyB.pointToLocalFrame(halfWay, pivotB);
- bodyA.pointToLocalFrame(halfWay, pivotA);
- super(bodyA, pivotA, bodyB, pivotB, maxForce);
- this.xA = bodyA.vectorToLocalFrame(Vec3.UNIT_X);
- this.xB = bodyB.vectorToLocalFrame(Vec3.UNIT_X);
- this.yA = bodyA.vectorToLocalFrame(Vec3.UNIT_Y);
- this.yB = bodyB.vectorToLocalFrame(Vec3.UNIT_Y);
- this.zA = bodyA.vectorToLocalFrame(Vec3.UNIT_Z);
- this.zB = bodyB.vectorToLocalFrame(Vec3.UNIT_Z);
- const r1 = this.rotationalEquation1 = new RotationalEquation(bodyA, bodyB, options);
- const r2 = this.rotationalEquation2 = new RotationalEquation(bodyA, bodyB, options);
- const r3 = this.rotationalEquation3 = new RotationalEquation(bodyA, bodyB, options);
- this.equations.push(r1, r2, r3);
- }
-
- update() {
- const bodyA = this.bodyA;
- const bodyB = this.bodyB;
- this.motorEquation;
- const r1 = this.rotationalEquation1;
- const r2 = this.rotationalEquation2;
- const r3 = this.rotationalEquation3;
- LockConstraint_update_tmpVec1;
- LockConstraint_update_tmpVec2;
- super.update();
- bodyA.vectorToWorldFrame(this.xA, r1.axisA);
- bodyB.vectorToWorldFrame(this.yB, r1.axisB);
- bodyA.vectorToWorldFrame(this.yA, r2.axisA);
- bodyB.vectorToWorldFrame(this.zB, r2.axisB);
- bodyA.vectorToWorldFrame(this.zA, r3.axisA);
- bodyB.vectorToWorldFrame(this.xB, r3.axisB);
- }
- }
- const LockConstraint_update_tmpVec1 = new Vec3();
- const LockConstraint_update_tmpVec2 = new Vec3();
- class RotationalMotorEquation extends Equation {
-
-
-
- constructor(bodyA, bodyB, maxForce) {
- if (maxForce === void 0) {
- maxForce = 1e6;
- }
- super(bodyA, bodyB, -maxForce, maxForce);
- this.axisA = new Vec3();
- this.axisB = new Vec3();
- this.targetVelocity = 0;
- }
- computeB(h) {
- this.a;
- const b = this.b;
- this.bi;
- this.bj;
- const axisA = this.axisA;
- const axisB = this.axisB;
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
-
-
-
-
- GA.rotational.copy(axisA);
- axisB.negate(GB.rotational);
- const GW = this.computeGW() - this.targetVelocity;
- const GiMf = this.computeGiMf();
- const B = -GW * b - h * GiMf;
- return B;
- }
- }
- class HingeConstraint extends PointToPointConstraint {
-
-
- constructor(bodyA, bodyB, options) {
- if (options === void 0) {
- options = {};
- }
- const maxForce = typeof options.maxForce !== 'undefined' ? options.maxForce : 1e6;
- const pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
- const pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
- super(bodyA, pivotA, bodyB, pivotB, maxForce);
- const axisA = this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
- axisA.normalize();
- const axisB = this.axisB = options.axisB ? options.axisB.clone() : new Vec3(1, 0, 0);
- axisB.normalize();
- this.collideConnected = !!options.collideConnected;
- const rotational1 = this.rotationalEquation1 = new RotationalEquation(bodyA, bodyB, options);
- const rotational2 = this.rotationalEquation2 = new RotationalEquation(bodyA, bodyB, options);
- const motor = this.motorEquation = new RotationalMotorEquation(bodyA, bodyB, maxForce);
- motor.enabled = false;
-
- this.equations.push(rotational1, rotational2, motor);
- }
-
- enableMotor() {
- this.motorEquation.enabled = true;
- }
-
- disableMotor() {
- this.motorEquation.enabled = false;
- }
-
- setMotorSpeed(speed) {
- this.motorEquation.targetVelocity = speed;
- }
-
- setMotorMaxForce(maxForce) {
- this.motorEquation.maxForce = maxForce;
- this.motorEquation.minForce = -maxForce;
- }
-
- update() {
- const bodyA = this.bodyA;
- const bodyB = this.bodyB;
- const motor = this.motorEquation;
- const r1 = this.rotationalEquation1;
- const r2 = this.rotationalEquation2;
- const worldAxisA = HingeConstraint_update_tmpVec1;
- const worldAxisB = HingeConstraint_update_tmpVec2;
- const axisA = this.axisA;
- const axisB = this.axisB;
- super.update();
- bodyA.quaternion.vmult(axisA, worldAxisA);
- bodyB.quaternion.vmult(axisB, worldAxisB);
- worldAxisA.tangents(r1.axisA, r2.axisA);
- r1.axisB.copy(worldAxisB);
- r2.axisB.copy(worldAxisB);
- if (this.motorEquation.enabled) {
- bodyA.quaternion.vmult(this.axisA, motor.axisA);
- bodyB.quaternion.vmult(this.axisB, motor.axisB);
- }
- }
- }
- const HingeConstraint_update_tmpVec1 = new Vec3();
- const HingeConstraint_update_tmpVec2 = new Vec3();
- class FrictionEquation extends Equation {
-
-
- constructor(bodyA, bodyB, slipForce) {
- super(bodyA, bodyB, -slipForce, slipForce);
- this.ri = new Vec3();
- this.rj = new Vec3();
- this.t = new Vec3();
- }
- computeB(h) {
- this.a;
- const b = this.b;
- this.bi;
- this.bj;
- const ri = this.ri;
- const rj = this.rj;
- const rixt = FrictionEquation_computeB_temp1;
- const rjxt = FrictionEquation_computeB_temp2;
- const t = this.t;
- ri.cross(t, rixt);
- rj.cross(t, rjxt);
-
- const GA = this.jacobianElementA;
- const GB = this.jacobianElementB;
- t.negate(GA.spatial);
- rixt.negate(GA.rotational);
- GB.spatial.copy(t);
- GB.rotational.copy(rjxt);
- const GW = this.computeGW();
- const GiMf = this.computeGiMf();
- const B = -GW * b - h * GiMf;
- return B;
- }
- }
- const FrictionEquation_computeB_temp1 = new Vec3();
- const FrictionEquation_computeB_temp2 = new Vec3();
- class ContactMaterial {
-
-
-
-
-
-
-
-
- constructor(m1, m2, options) {
- options = Utils.defaults(options, {
- friction: 0.3,
- restitution: 0.3,
- contactEquationStiffness: 1e7,
- contactEquationRelaxation: 3,
- frictionEquationStiffness: 1e7,
- frictionEquationRelaxation: 3
- });
- this.id = ContactMaterial.idCounter++;
- this.materials = [m1, m2];
- this.friction = options.friction;
- this.restitution = options.restitution;
- this.contactEquationStiffness = options.contactEquationStiffness;
- this.contactEquationRelaxation = options.contactEquationRelaxation;
- this.frictionEquationStiffness = options.frictionEquationStiffness;
- this.frictionEquationRelaxation = options.frictionEquationRelaxation;
- }
- }
- ContactMaterial.idCounter = 0;
- class Material {
-
-
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- let name = '';
- if (typeof options === 'string') {
-
- name = options;
- options = {};
- }
- this.name = name;
- this.id = Material.idCounter++;
- this.friction = typeof options.friction !== 'undefined' ? options.friction : -1;
- this.restitution = typeof options.restitution !== 'undefined' ? options.restitution : -1;
- }
- }
- Material.idCounter = 0;
- class Spring {
-
-
-
-
-
-
-
- constructor(bodyA, bodyB, options) {
- if (options === void 0) {
- options = {};
- }
- this.restLength = typeof options.restLength === 'number' ? options.restLength : 1;
- this.stiffness = options.stiffness || 100;
- this.damping = options.damping || 1;
- this.bodyA = bodyA;
- this.bodyB = bodyB;
- this.localAnchorA = new Vec3();
- this.localAnchorB = new Vec3();
- if (options.localAnchorA) {
- this.localAnchorA.copy(options.localAnchorA);
- }
- if (options.localAnchorB) {
- this.localAnchorB.copy(options.localAnchorB);
- }
- if (options.worldAnchorA) {
- this.setWorldAnchorA(options.worldAnchorA);
- }
- if (options.worldAnchorB) {
- this.setWorldAnchorB(options.worldAnchorB);
- }
- }
-
- setWorldAnchorA(worldAnchorA) {
- this.bodyA.pointToLocalFrame(worldAnchorA, this.localAnchorA);
- }
-
- setWorldAnchorB(worldAnchorB) {
- this.bodyB.pointToLocalFrame(worldAnchorB, this.localAnchorB);
- }
-
- getWorldAnchorA(result) {
- this.bodyA.pointToWorldFrame(this.localAnchorA, result);
- }
-
- getWorldAnchorB(result) {
- this.bodyB.pointToWorldFrame(this.localAnchorB, result);
- }
-
- applyForce() {
- const k = this.stiffness;
- const d = this.damping;
- const l = this.restLength;
- const bodyA = this.bodyA;
- const bodyB = this.bodyB;
- const r = applyForce_r;
- const r_unit = applyForce_r_unit;
- const u = applyForce_u;
- const f = applyForce_f;
- const tmp = applyForce_tmp;
- const worldAnchorA = applyForce_worldAnchorA;
- const worldAnchorB = applyForce_worldAnchorB;
- const ri = applyForce_ri;
- const rj = applyForce_rj;
- const ri_x_f = applyForce_ri_x_f;
- const rj_x_f = applyForce_rj_x_f;
- this.getWorldAnchorA(worldAnchorA);
- this.getWorldAnchorB(worldAnchorB);
- worldAnchorA.vsub(bodyA.position, ri);
- worldAnchorB.vsub(bodyB.position, rj);
- worldAnchorB.vsub(worldAnchorA, r);
- const rlen = r.length();
- r_unit.copy(r);
- r_unit.normalize();
- bodyB.velocity.vsub(bodyA.velocity, u);
- bodyB.angularVelocity.cross(rj, tmp);
- u.vadd(tmp, u);
- bodyA.angularVelocity.cross(ri, tmp);
- u.vsub(tmp, u);
- r_unit.scale(-k * (rlen - l) - d * u.dot(r_unit), f);
- bodyA.force.vsub(f, bodyA.force);
- bodyB.force.vadd(f, bodyB.force);
- ri.cross(f, ri_x_f);
- rj.cross(f, rj_x_f);
- bodyA.torque.vsub(ri_x_f, bodyA.torque);
- bodyB.torque.vadd(rj_x_f, bodyB.torque);
- }
- }
- const applyForce_r = new Vec3();
- const applyForce_r_unit = new Vec3();
- const applyForce_u = new Vec3();
- const applyForce_f = new Vec3();
- const applyForce_worldAnchorA = new Vec3();
- const applyForce_worldAnchorB = new Vec3();
- const applyForce_ri = new Vec3();
- const applyForce_rj = new Vec3();
- const applyForce_ri_x_f = new Vec3();
- const applyForce_rj_x_f = new Vec3();
- const applyForce_tmp = new Vec3();
- class WheelInfo {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- options = Utils.defaults(options, {
- chassisConnectionPointLocal: new Vec3(),
- chassisConnectionPointWorld: new Vec3(),
- directionLocal: new Vec3(),
- directionWorld: new Vec3(),
- axleLocal: new Vec3(),
- axleWorld: new Vec3(),
- suspensionRestLength: 1,
- suspensionMaxLength: 2,
- radius: 1,
- suspensionStiffness: 100,
- dampingCompression: 10,
- dampingRelaxation: 10,
- frictionSlip: 10.5,
- forwardAcceleration: 1,
- sideAcceleration: 1,
- steering: 0,
- rotation: 0,
- deltaRotation: 0,
- rollInfluence: 0.01,
- maxSuspensionForce: Number.MAX_VALUE,
- isFrontWheel: true,
- clippedInvContactDotSuspension: 1,
- suspensionRelativeVelocity: 0,
- suspensionForce: 0,
- slipInfo: 0,
- skidInfo: 0,
- suspensionLength: 0,
- maxSuspensionTravel: 1,
- useCustomSlidingRotationalSpeed: false,
- customSlidingRotationalSpeed: -0.1
- });
- this.maxSuspensionTravel = options.maxSuspensionTravel;
- this.customSlidingRotationalSpeed = options.customSlidingRotationalSpeed;
- this.useCustomSlidingRotationalSpeed = options.useCustomSlidingRotationalSpeed;
- this.sliding = false;
- this.chassisConnectionPointLocal = options.chassisConnectionPointLocal.clone();
- this.chassisConnectionPointWorld = options.chassisConnectionPointWorld.clone();
- this.directionLocal = options.directionLocal.clone();
- this.directionWorld = options.directionWorld.clone();
- this.axleLocal = options.axleLocal.clone();
- this.axleWorld = options.axleWorld.clone();
- this.suspensionRestLength = options.suspensionRestLength;
- this.suspensionMaxLength = options.suspensionMaxLength;
- this.radius = options.radius;
- this.suspensionStiffness = options.suspensionStiffness;
- this.dampingCompression = options.dampingCompression;
- this.dampingRelaxation = options.dampingRelaxation;
- this.frictionSlip = options.frictionSlip;
- this.forwardAcceleration = options.forwardAcceleration;
- this.sideAcceleration = options.sideAcceleration;
- this.steering = 0;
- this.rotation = 0;
- this.deltaRotation = 0;
- this.rollInfluence = options.rollInfluence;
- this.maxSuspensionForce = options.maxSuspensionForce;
- this.engineForce = 0;
- this.brake = 0;
- this.isFrontWheel = options.isFrontWheel;
- this.clippedInvContactDotSuspension = 1;
- this.suspensionRelativeVelocity = 0;
- this.suspensionForce = 0;
- this.slipInfo = 0;
- this.skidInfo = 0;
- this.suspensionLength = 0;
- this.sideImpulse = 0;
- this.forwardImpulse = 0;
- this.raycastResult = new RaycastResult();
- this.worldTransform = new Transform();
- this.isInContact = false;
- }
- updateWheel(chassis) {
- const raycastResult = this.raycastResult;
- if (this.isInContact) {
- const project = raycastResult.hitNormalWorld.dot(raycastResult.directionWorld);
- raycastResult.hitPointWorld.vsub(chassis.position, relpos);
- chassis.getVelocityAtWorldPoint(relpos, chassis_velocity_at_contactPoint);
- const projVel = raycastResult.hitNormalWorld.dot(chassis_velocity_at_contactPoint);
- if (project >= -0.1) {
- this.suspensionRelativeVelocity = 0.0;
- this.clippedInvContactDotSuspension = 1.0 / 0.1;
- } else {
- const inv = -1 / project;
- this.suspensionRelativeVelocity = projVel * inv;
- this.clippedInvContactDotSuspension = inv;
- }
- } else {
-
- raycastResult.suspensionLength = this.suspensionRestLength;
- this.suspensionRelativeVelocity = 0.0;
- raycastResult.directionWorld.scale(-1, raycastResult.hitNormalWorld);
- this.clippedInvContactDotSuspension = 1.0;
- }
- }
- }
- const chassis_velocity_at_contactPoint = new Vec3();
- const relpos = new Vec3();
- class RaycastVehicle {
-
-
-
-
-
-
-
-
-
- constructor(options) {
- this.chassisBody = options.chassisBody;
- this.wheelInfos = [];
- this.sliding = false;
- this.world = null;
- this.indexRightAxis = typeof options.indexRightAxis !== 'undefined' ? options.indexRightAxis : 2;
- this.indexForwardAxis = typeof options.indexForwardAxis !== 'undefined' ? options.indexForwardAxis : 0;
- this.indexUpAxis = typeof options.indexUpAxis !== 'undefined' ? options.indexUpAxis : 1;
- this.constraints = [];
- this.preStepCallback = () => {};
- this.currentVehicleSpeedKmHour = 0;
- this.numWheelsOnGround = 0;
- }
-
- addWheel(options) {
- if (options === void 0) {
- options = {};
- }
- const info = new WheelInfo(options);
- const index = this.wheelInfos.length;
- this.wheelInfos.push(info);
- return index;
- }
-
- setSteeringValue(value, wheelIndex) {
- const wheel = this.wheelInfos[wheelIndex];
- wheel.steering = value;
- }
-
- applyEngineForce(value, wheelIndex) {
- this.wheelInfos[wheelIndex].engineForce = value;
- }
-
- setBrake(brake, wheelIndex) {
- this.wheelInfos[wheelIndex].brake = brake;
- }
-
- addToWorld(world) {
- world.addBody(this.chassisBody);
- const that = this;
- this.preStepCallback = () => {
- that.updateVehicle(world.dt);
- };
- world.addEventListener('preStep', this.preStepCallback);
- this.world = world;
- }
-
- getVehicleAxisWorld(axisIndex, result) {
- result.set(axisIndex === 0 ? 1 : 0, axisIndex === 1 ? 1 : 0, axisIndex === 2 ? 1 : 0);
- this.chassisBody.vectorToWorldFrame(result, result);
- }
- updateVehicle(timeStep) {
- const wheelInfos = this.wheelInfos;
- const numWheels = wheelInfos.length;
- const chassisBody = this.chassisBody;
- for (let i = 0; i < numWheels; i++) {
- this.updateWheelTransform(i);
- }
- this.currentVehicleSpeedKmHour = 3.6 * chassisBody.velocity.length();
- const forwardWorld = new Vec3();
- this.getVehicleAxisWorld(this.indexForwardAxis, forwardWorld);
- if (forwardWorld.dot(chassisBody.velocity) < 0) {
- this.currentVehicleSpeedKmHour *= -1;
- }
- for (let i = 0; i < numWheels; i++) {
- this.castRay(wheelInfos[i]);
- }
- this.updateSuspension(timeStep);
- const impulse = new Vec3();
- const relpos = new Vec3();
- for (let i = 0; i < numWheels; i++) {
-
- const wheel = wheelInfos[i];
- let suspensionForce = wheel.suspensionForce;
- if (suspensionForce > wheel.maxSuspensionForce) {
- suspensionForce = wheel.maxSuspensionForce;
- }
- wheel.raycastResult.hitNormalWorld.scale(suspensionForce * timeStep, impulse);
- wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, relpos);
- chassisBody.applyImpulse(impulse, relpos);
- }
- this.updateFriction(timeStep);
- const hitNormalWorldScaledWithProj = new Vec3();
- const fwd = new Vec3();
- const vel = new Vec3();
- for (let i = 0; i < numWheels; i++) {
- const wheel = wheelInfos[i];
-
- chassisBody.getVelocityAtWorldPoint(wheel.chassisConnectionPointWorld, vel);
- let m = 1;
- switch (this.indexUpAxis) {
- case 1:
- m = -1;
- break;
- }
- if (wheel.isInContact) {
- this.getVehicleAxisWorld(this.indexForwardAxis, fwd);
- const proj = fwd.dot(wheel.raycastResult.hitNormalWorld);
- wheel.raycastResult.hitNormalWorld.scale(proj, hitNormalWorldScaledWithProj);
- fwd.vsub(hitNormalWorldScaledWithProj, fwd);
- const proj2 = fwd.dot(vel);
- wheel.deltaRotation = m * proj2 * timeStep / wheel.radius;
- }
- if ((wheel.sliding || !wheel.isInContact) && wheel.engineForce !== 0 && wheel.useCustomSlidingRotationalSpeed) {
-
- wheel.deltaRotation = (wheel.engineForce > 0 ? 1 : -1) * wheel.customSlidingRotationalSpeed * timeStep;
- }
- if (Math.abs(wheel.brake) > Math.abs(wheel.engineForce)) {
- wheel.deltaRotation = 0;
- }
- wheel.rotation += wheel.deltaRotation;
- wheel.deltaRotation *= 0.99;
- }
- }
- updateSuspension(deltaTime) {
- const chassisBody = this.chassisBody;
- const chassisMass = chassisBody.mass;
- const wheelInfos = this.wheelInfos;
- const numWheels = wheelInfos.length;
- for (let w_it = 0; w_it < numWheels; w_it++) {
- const wheel = wheelInfos[w_it];
- if (wheel.isInContact) {
- let force;
- const susp_length = wheel.suspensionRestLength;
- const current_length = wheel.suspensionLength;
- const length_diff = susp_length - current_length;
- force = wheel.suspensionStiffness * length_diff * wheel.clippedInvContactDotSuspension;
- const projected_rel_vel = wheel.suspensionRelativeVelocity;
- let susp_damping;
- if (projected_rel_vel < 0) {
- susp_damping = wheel.dampingCompression;
- } else {
- susp_damping = wheel.dampingRelaxation;
- }
- force -= susp_damping * projected_rel_vel;
- wheel.suspensionForce = force * chassisMass;
- if (wheel.suspensionForce < 0) {
- wheel.suspensionForce = 0;
- }
- } else {
- wheel.suspensionForce = 0;
- }
- }
- }
-
- removeFromWorld(world) {
- this.constraints;
- world.removeBody(this.chassisBody);
- world.removeEventListener('preStep', this.preStepCallback);
- this.world = null;
- }
- castRay(wheel) {
- const rayvector = castRay_rayvector;
- const target = castRay_target;
- this.updateWheelTransformWorld(wheel);
- const chassisBody = this.chassisBody;
- let depth = -1;
- const raylen = wheel.suspensionRestLength + wheel.radius;
- wheel.directionWorld.scale(raylen, rayvector);
- const source = wheel.chassisConnectionPointWorld;
- source.vadd(rayvector, target);
- const raycastResult = wheel.raycastResult;
- raycastResult.reset();
- const oldState = chassisBody.collisionResponse;
- chassisBody.collisionResponse = false;
- this.world.rayTest(source, target, raycastResult);
- chassisBody.collisionResponse = oldState;
- const object = raycastResult.body;
- wheel.raycastResult.groundObject = 0;
- if (object) {
- depth = raycastResult.distance;
- wheel.raycastResult.hitNormalWorld = raycastResult.hitNormalWorld;
- wheel.isInContact = true;
- const hitDistance = raycastResult.distance;
- wheel.suspensionLength = hitDistance - wheel.radius;
- const minSuspensionLength = wheel.suspensionRestLength - wheel.maxSuspensionTravel;
- const maxSuspensionLength = wheel.suspensionRestLength + wheel.maxSuspensionTravel;
- if (wheel.suspensionLength < minSuspensionLength) {
- wheel.suspensionLength = minSuspensionLength;
- }
- if (wheel.suspensionLength > maxSuspensionLength) {
- wheel.suspensionLength = maxSuspensionLength;
- wheel.raycastResult.reset();
- }
- const denominator = wheel.raycastResult.hitNormalWorld.dot(wheel.directionWorld);
- const chassis_velocity_at_contactPoint = new Vec3();
- chassisBody.getVelocityAtWorldPoint(wheel.raycastResult.hitPointWorld, chassis_velocity_at_contactPoint);
- const projVel = wheel.raycastResult.hitNormalWorld.dot(chassis_velocity_at_contactPoint);
- if (denominator >= -0.1) {
- wheel.suspensionRelativeVelocity = 0;
- wheel.clippedInvContactDotSuspension = 1 / 0.1;
- } else {
- const inv = -1 / denominator;
- wheel.suspensionRelativeVelocity = projVel * inv;
- wheel.clippedInvContactDotSuspension = inv;
- }
- } else {
-
- wheel.suspensionLength = wheel.suspensionRestLength + 0 * wheel.maxSuspensionTravel;
- wheel.suspensionRelativeVelocity = 0.0;
- wheel.directionWorld.scale(-1, wheel.raycastResult.hitNormalWorld);
- wheel.clippedInvContactDotSuspension = 1.0;
- }
- return depth;
- }
- updateWheelTransformWorld(wheel) {
- wheel.isInContact = false;
- const chassisBody = this.chassisBody;
- chassisBody.pointToWorldFrame(wheel.chassisConnectionPointLocal, wheel.chassisConnectionPointWorld);
- chassisBody.vectorToWorldFrame(wheel.directionLocal, wheel.directionWorld);
- chassisBody.vectorToWorldFrame(wheel.axleLocal, wheel.axleWorld);
- }
-
- updateWheelTransform(wheelIndex) {
- const up = tmpVec4;
- const right = tmpVec5;
- const fwd = tmpVec6;
- const wheel = this.wheelInfos[wheelIndex];
- this.updateWheelTransformWorld(wheel);
- wheel.directionLocal.scale(-1, up);
- right.copy(wheel.axleLocal);
- up.cross(right, fwd);
- fwd.normalize();
- right.normalize();
- const steering = wheel.steering;
- const steeringOrn = new Quaternion();
- steeringOrn.setFromAxisAngle(up, steering);
- const rotatingOrn = new Quaternion();
- rotatingOrn.setFromAxisAngle(right, wheel.rotation);
- const q = wheel.worldTransform.quaternion;
- this.chassisBody.quaternion.mult(steeringOrn, q);
- q.mult(rotatingOrn, q);
- q.normalize();
- const p = wheel.worldTransform.position;
- p.copy(wheel.directionWorld);
- p.scale(wheel.suspensionLength, p);
- p.vadd(wheel.chassisConnectionPointWorld, p);
- }
-
- getWheelTransformWorld(wheelIndex) {
- return this.wheelInfos[wheelIndex].worldTransform;
- }
- updateFriction(timeStep) {
- const surfNormalWS_scaled_proj = updateFriction_surfNormalWS_scaled_proj;
- const wheelInfos = this.wheelInfos;
- const numWheels = wheelInfos.length;
- const chassisBody = this.chassisBody;
- const forwardWS = updateFriction_forwardWS;
- const axle = updateFriction_axle;
- this.numWheelsOnGround = 0;
- for (let i = 0; i < numWheels; i++) {
- const wheel = wheelInfos[i];
- const groundObject = wheel.raycastResult.body;
- if (groundObject) {
- this.numWheelsOnGround++;
- }
- wheel.sideImpulse = 0;
- wheel.forwardImpulse = 0;
- if (!forwardWS[i]) {
- forwardWS[i] = new Vec3();
- }
- if (!axle[i]) {
- axle[i] = new Vec3();
- }
- }
- for (let i = 0; i < numWheels; i++) {
- const wheel = wheelInfos[i];
- const groundObject = wheel.raycastResult.body;
- if (groundObject) {
- const axlei = axle[i];
- const wheelTrans = this.getWheelTransformWorld(i);
- wheelTrans.vectorToWorldFrame(directions[this.indexRightAxis], axlei);
- const surfNormalWS = wheel.raycastResult.hitNormalWorld;
- const proj = axlei.dot(surfNormalWS);
- surfNormalWS.scale(proj, surfNormalWS_scaled_proj);
- axlei.vsub(surfNormalWS_scaled_proj, axlei);
- axlei.normalize();
- surfNormalWS.cross(axlei, forwardWS[i]);
- forwardWS[i].normalize();
- wheel.sideImpulse = resolveSingleBilateral(chassisBody, wheel.raycastResult.hitPointWorld, groundObject, wheel.raycastResult.hitPointWorld, axlei);
- wheel.sideImpulse *= sideFrictionStiffness2;
- }
- }
- const sideFactor = 1;
- const fwdFactor = 0.5;
- this.sliding = false;
- for (let i = 0; i < numWheels; i++) {
- const wheel = wheelInfos[i];
- const groundObject = wheel.raycastResult.body;
- let rollingFriction = 0;
- wheel.slipInfo = 1;
- if (groundObject) {
- const defaultRollingFrictionImpulse = 0;
- const maxImpulse = wheel.brake ? wheel.brake : defaultRollingFrictionImpulse;
-
- rollingFriction = calcRollingFriction(chassisBody, groundObject, wheel.raycastResult.hitPointWorld, forwardWS[i], maxImpulse);
- rollingFriction += wheel.engineForce * timeStep;
- const factor = maxImpulse / rollingFriction;
- wheel.slipInfo *= factor;
- }
- wheel.forwardImpulse = 0;
- wheel.skidInfo = 1;
- if (groundObject) {
- wheel.skidInfo = 1;
- const maximp = wheel.suspensionForce * timeStep * wheel.frictionSlip;
- const maximpSide = maximp;
- const maximpSquared = maximp * maximpSide;
- wheel.forwardImpulse = rollingFriction;
- const x = wheel.forwardImpulse * fwdFactor / wheel.forwardAcceleration;
- const y = wheel.sideImpulse * sideFactor / wheel.sideAcceleration;
- const impulseSquared = x * x + y * y;
- wheel.sliding = false;
- if (impulseSquared > maximpSquared) {
- this.sliding = true;
- wheel.sliding = true;
- const factor = maximp / Math.sqrt(impulseSquared);
- wheel.skidInfo *= factor;
- }
- }
- }
- if (this.sliding) {
- for (let i = 0; i < numWheels; i++) {
- const wheel = wheelInfos[i];
- if (wheel.sideImpulse !== 0) {
- if (wheel.skidInfo < 1) {
- wheel.forwardImpulse *= wheel.skidInfo;
- wheel.sideImpulse *= wheel.skidInfo;
- }
- }
- }
- }
- for (let i = 0; i < numWheels; i++) {
- const wheel = wheelInfos[i];
- const rel_pos = new Vec3();
- wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, rel_pos);
-
- if (wheel.forwardImpulse !== 0) {
- const impulse = new Vec3();
- forwardWS[i].scale(wheel.forwardImpulse, impulse);
- chassisBody.applyImpulse(impulse, rel_pos);
- }
- if (wheel.sideImpulse !== 0) {
- const groundObject = wheel.raycastResult.body;
- const rel_pos2 = new Vec3();
- wheel.raycastResult.hitPointWorld.vsub(groundObject.position, rel_pos2);
- const sideImp = new Vec3();
- axle[i].scale(wheel.sideImpulse, sideImp);
-
- chassisBody.vectorToLocalFrame(rel_pos, rel_pos);
- rel_pos['xyz'[this.indexUpAxis]] *= wheel.rollInfluence;
- chassisBody.vectorToWorldFrame(rel_pos, rel_pos);
- chassisBody.applyImpulse(sideImp, rel_pos);
- sideImp.scale(-1, sideImp);
- groundObject.applyImpulse(sideImp, rel_pos2);
- }
- }
- }
- }
- new Vec3();
- new Vec3();
- new Vec3();
- const tmpVec4 = new Vec3();
- const tmpVec5 = new Vec3();
- const tmpVec6 = new Vec3();
- new Ray();
- new Vec3();
- const castRay_rayvector = new Vec3();
- const castRay_target = new Vec3();
- const directions = [new Vec3(1, 0, 0), new Vec3(0, 1, 0), new Vec3(0, 0, 1)];
- const updateFriction_surfNormalWS_scaled_proj = new Vec3();
- const updateFriction_axle = [];
- const updateFriction_forwardWS = [];
- const sideFrictionStiffness2 = 1;
- const calcRollingFriction_vel1 = new Vec3();
- const calcRollingFriction_vel2 = new Vec3();
- const calcRollingFriction_vel = new Vec3();
- function calcRollingFriction(body0, body1, frictionPosWorld, frictionDirectionWorld, maxImpulse) {
- let j1 = 0;
- const contactPosWorld = frictionPosWorld;
-
- const vel1 = calcRollingFriction_vel1;
- const vel2 = calcRollingFriction_vel2;
- const vel = calcRollingFriction_vel;
-
- body0.getVelocityAtWorldPoint(contactPosWorld, vel1);
- body1.getVelocityAtWorldPoint(contactPosWorld, vel2);
- vel1.vsub(vel2, vel);
- const vrel = frictionDirectionWorld.dot(vel);
- const denom0 = computeImpulseDenominator(body0, frictionPosWorld, frictionDirectionWorld);
- const denom1 = computeImpulseDenominator(body1, frictionPosWorld, frictionDirectionWorld);
- const relaxation = 1;
- const jacDiagABInv = relaxation / (denom0 + denom1);
- j1 = -vrel * jacDiagABInv;
- if (maxImpulse < j1) {
- j1 = maxImpulse;
- }
- if (j1 < -maxImpulse) {
- j1 = -maxImpulse;
- }
- return j1;
- }
- const computeImpulseDenominator_r0 = new Vec3();
- const computeImpulseDenominator_c0 = new Vec3();
- const computeImpulseDenominator_vec = new Vec3();
- const computeImpulseDenominator_m = new Vec3();
- function computeImpulseDenominator(body, pos, normal) {
- const r0 = computeImpulseDenominator_r0;
- const c0 = computeImpulseDenominator_c0;
- const vec = computeImpulseDenominator_vec;
- const m = computeImpulseDenominator_m;
- pos.vsub(body.position, r0);
- r0.cross(normal, c0);
- body.invInertiaWorld.vmult(c0, m);
- m.cross(r0, vec);
- return body.invMass + normal.dot(vec);
- }
- const resolveSingleBilateral_vel1 = new Vec3();
- const resolveSingleBilateral_vel2 = new Vec3();
- const resolveSingleBilateral_vel = new Vec3();
- function resolveSingleBilateral(body1, pos1, body2, pos2, normal) {
- const normalLenSqr = normal.lengthSquared();
- if (normalLenSqr > 1.1) {
- return 0;
- }
-
-
-
- const vel1 = resolveSingleBilateral_vel1;
- const vel2 = resolveSingleBilateral_vel2;
- const vel = resolveSingleBilateral_vel;
- body1.getVelocityAtWorldPoint(pos1, vel1);
- body2.getVelocityAtWorldPoint(pos2, vel2);
- vel1.vsub(vel2, vel);
- const rel_vel = normal.dot(vel);
- const contactDamping = 0.2;
- const massTerm = 1 / (body1.invMass + body2.invMass);
- const impulse = -contactDamping * rel_vel * massTerm;
- return impulse;
- }
- class Sphere extends Shape {
-
-
- constructor(radius) {
- super({
- type: Shape.types.SPHERE
- });
- this.radius = radius !== undefined ? radius : 1.0;
- if (this.radius < 0) {
- throw new Error('The sphere radius cannot be negative.');
- }
- this.updateBoundingSphereRadius();
- }
-
- calculateLocalInertia(mass, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- const I = 2.0 * mass * this.radius * this.radius / 5.0;
- target.x = I;
- target.y = I;
- target.z = I;
- return target;
- }
-
- volume() {
- return 4.0 * Math.PI * Math.pow(this.radius, 3) / 3.0;
- }
- updateBoundingSphereRadius() {
- this.boundingSphereRadius = this.radius;
- }
- calculateWorldAABB(pos, quat, min, max) {
- const r = this.radius;
- const axes = ['x', 'y', 'z'];
- for (let i = 0; i < axes.length; i++) {
- const ax = axes[i];
- min[ax] = pos[ax] - r;
- max[ax] = pos[ax] + r;
- }
- }
- }
- class RigidVehicle {
-
-
-
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- this.wheelBodies = [];
- this.coordinateSystem = typeof options.coordinateSystem !== 'undefined' ? options.coordinateSystem.clone() : new Vec3(1, 2, 3);
- if (options.chassisBody) {
- this.chassisBody = options.chassisBody;
- } else {
-
- this.chassisBody = new Body({
- mass: 1,
- shape: new Box(new Vec3(5, 0.5, 2))
- });
- }
- this.constraints = [];
- this.wheelAxes = [];
- this.wheelForces = [];
- }
-
- addWheel(options) {
- if (options === void 0) {
- options = {};
- }
- let wheelBody;
- if (options.body) {
- wheelBody = options.body;
- } else {
-
- wheelBody = new Body({
- mass: 1,
- shape: new Sphere(1.2)
- });
- }
- this.wheelBodies.push(wheelBody);
- this.wheelForces.push(0);
- const position = typeof options.position !== 'undefined' ? options.position.clone() : new Vec3();
- const worldPosition = new Vec3();
- this.chassisBody.pointToWorldFrame(position, worldPosition);
- wheelBody.position.set(worldPosition.x, worldPosition.y, worldPosition.z);
- const axis = typeof options.axis !== 'undefined' ? options.axis.clone() : new Vec3(0, 0, 1);
- this.wheelAxes.push(axis);
- const hingeConstraint = new HingeConstraint(this.chassisBody, wheelBody, {
- pivotA: position,
- axisA: axis,
- pivotB: Vec3.ZERO,
- axisB: axis,
- collideConnected: false
- });
- this.constraints.push(hingeConstraint);
- return this.wheelBodies.length - 1;
- }
-
- setSteeringValue(value, wheelIndex) {
-
- const axis = this.wheelAxes[wheelIndex];
- const c = Math.cos(value);
- const s = Math.sin(value);
- const x = axis.x;
- const z = axis.z;
- this.constraints[wheelIndex].axisA.set(-c * x + s * z, 0, s * x + c * z);
- }
-
- setMotorSpeed(value, wheelIndex) {
- const hingeConstraint = this.constraints[wheelIndex];
- hingeConstraint.enableMotor();
- hingeConstraint.motorTargetVelocity = value;
- }
-
- disableMotor(wheelIndex) {
- const hingeConstraint = this.constraints[wheelIndex];
- hingeConstraint.disableMotor();
- }
-
- setWheelForce(value, wheelIndex) {
- this.wheelForces[wheelIndex] = value;
- }
-
- applyWheelForce(value, wheelIndex) {
- const axis = this.wheelAxes[wheelIndex];
- const wheelBody = this.wheelBodies[wheelIndex];
- const bodyTorque = wheelBody.torque;
- axis.scale(value, torque);
- wheelBody.vectorToWorldFrame(torque, torque);
- bodyTorque.vadd(torque, bodyTorque);
- }
-
- addToWorld(world) {
- const constraints = this.constraints;
- const bodies = this.wheelBodies.concat([this.chassisBody]);
- for (let i = 0; i < bodies.length; i++) {
- world.addBody(bodies[i]);
- }
- for (let i = 0; i < constraints.length; i++) {
- world.addConstraint(constraints[i]);
- }
- world.addEventListener('preStep', this._update.bind(this));
- }
- _update() {
- const wheelForces = this.wheelForces;
- for (let i = 0; i < wheelForces.length; i++) {
- this.applyWheelForce(wheelForces[i], i);
- }
- }
-
- removeFromWorld(world) {
- const constraints = this.constraints;
- const bodies = this.wheelBodies.concat([this.chassisBody]);
- for (let i = 0; i < bodies.length; i++) {
- world.removeBody(bodies[i]);
- }
- for (let i = 0; i < constraints.length; i++) {
- world.removeConstraint(constraints[i]);
- }
- }
-
- getWheelSpeed(wheelIndex) {
- const axis = this.wheelAxes[wheelIndex];
- const wheelBody = this.wheelBodies[wheelIndex];
- const w = wheelBody.angularVelocity;
- this.chassisBody.vectorToWorldFrame(axis, worldAxis);
- return w.dot(worldAxis);
- }
- }
- const torque = new Vec3();
- const worldAxis = new Vec3();
- class SPHSystem {
-
-
-
-
-
-
- constructor() {
- this.particles = [];
- this.density = 1;
- this.smoothingRadius = 1;
- this.speedOfSound = 1;
- this.viscosity = 0.01;
- this.eps = 0.000001;
- this.pressures = [];
- this.densities = [];
- this.neighbors = [];
- }
-
- add(particle) {
- this.particles.push(particle);
- if (this.neighbors.length < this.particles.length) {
- this.neighbors.push([]);
- }
- }
-
- remove(particle) {
- const idx = this.particles.indexOf(particle);
- if (idx !== -1) {
- this.particles.splice(idx, 1);
- if (this.neighbors.length > this.particles.length) {
- this.neighbors.pop();
- }
- }
- }
-
- getNeighbors(particle, neighbors) {
- const N = this.particles.length;
- const id = particle.id;
- const R2 = this.smoothingRadius * this.smoothingRadius;
- const dist = SPHSystem_getNeighbors_dist;
- for (let i = 0; i !== N; i++) {
- const p = this.particles[i];
- p.position.vsub(particle.position, dist);
- if (id !== p.id && dist.lengthSquared() < R2) {
- neighbors.push(p);
- }
- }
- }
- update() {
- const N = this.particles.length;
- const dist = SPHSystem_update_dist;
- const cs = this.speedOfSound;
- const eps = this.eps;
- for (let i = 0; i !== N; i++) {
- const p = this.particles[i];
- const neighbors = this.neighbors[i];
- neighbors.length = 0;
- this.getNeighbors(p, neighbors);
- neighbors.push(this.particles[i]);
- const numNeighbors = neighbors.length;
- let sum = 0.0;
- for (let j = 0; j !== numNeighbors; j++) {
-
- p.position.vsub(neighbors[j].position, dist);
- const len = dist.length();
- const weight = this.w(len);
- sum += neighbors[j].mass * weight;
- }
- this.densities[i] = sum;
- this.pressures[i] = cs * cs * (this.densities[i] - this.density);
- }
-
- const a_pressure = SPHSystem_update_a_pressure;
- const a_visc = SPHSystem_update_a_visc;
- const gradW = SPHSystem_update_gradW;
- const r_vec = SPHSystem_update_r_vec;
- const u = SPHSystem_update_u;
- for (let i = 0; i !== N; i++) {
- const particle = this.particles[i];
- a_pressure.set(0, 0, 0);
- a_visc.set(0, 0, 0);
- let Pij;
- let nabla;
- const neighbors = this.neighbors[i];
- const numNeighbors = neighbors.length;
- for (let j = 0; j !== numNeighbors; j++) {
- const neighbor = neighbors[j];
-
- particle.position.vsub(neighbor.position, r_vec);
- const r = r_vec.length();
- Pij = -neighbor.mass * (this.pressures[i] / (this.densities[i] * this.densities[i] + eps) + this.pressures[j] / (this.densities[j] * this.densities[j] + eps));
- this.gradw(r_vec, gradW);
- gradW.scale(Pij, gradW);
- a_pressure.vadd(gradW, a_pressure);
- neighbor.velocity.vsub(particle.velocity, u);
- u.scale(1.0 / (0.0001 + this.densities[i] * this.densities[j]) * this.viscosity * neighbor.mass, u);
- nabla = this.nablaw(r);
- u.scale(nabla, u);
- a_visc.vadd(u, a_visc);
- }
- a_visc.scale(particle.mass, a_visc);
- a_pressure.scale(particle.mass, a_pressure);
- particle.force.vadd(a_visc, particle.force);
- particle.force.vadd(a_pressure, particle.force);
- }
- }
- w(r) {
-
- const h = this.smoothingRadius;
- return 315.0 / (64.0 * Math.PI * h ** 9) * (h * h - r * r) ** 3;
- }
- gradw(rVec, resultVec) {
- const r = rVec.length();
- const h = this.smoothingRadius;
- rVec.scale(945.0 / (32.0 * Math.PI * h ** 9) * (h * h - r * r) ** 2, resultVec);
- }
- nablaw(r) {
- const h = this.smoothingRadius;
- const nabla = 945.0 / (32.0 * Math.PI * h ** 9) * (h * h - r * r) * (7 * r * r - 3 * h * h);
- return nabla;
- }
- }
- const SPHSystem_getNeighbors_dist = new Vec3();
- const SPHSystem_update_dist = new Vec3();
- const SPHSystem_update_a_pressure = new Vec3();
- const SPHSystem_update_a_visc = new Vec3();
- const SPHSystem_update_gradW = new Vec3();
- const SPHSystem_update_r_vec = new Vec3();
- const SPHSystem_update_u = new Vec3();
- class Cylinder extends ConvexPolyhedron {
-
-
-
-
-
- constructor(radiusTop, radiusBottom, height, numSegments) {
- if (radiusTop === void 0) {
- radiusTop = 1;
- }
- if (radiusBottom === void 0) {
- radiusBottom = 1;
- }
- if (height === void 0) {
- height = 1;
- }
- if (numSegments === void 0) {
- numSegments = 8;
- }
- if (radiusTop < 0) {
- throw new Error('The cylinder radiusTop cannot be negative.');
- }
- if (radiusBottom < 0) {
- throw new Error('The cylinder radiusBottom cannot be negative.');
- }
- const N = numSegments;
- const vertices = [];
- const axes = [];
- const faces = [];
- const bottomface = [];
- const topface = [];
- const cos = Math.cos;
- const sin = Math.sin;
- vertices.push(new Vec3(-radiusBottom * sin(0), -height * 0.5, radiusBottom * cos(0)));
- bottomface.push(0);
- vertices.push(new Vec3(-radiusTop * sin(0), height * 0.5, radiusTop * cos(0)));
- topface.push(1);
- for (let i = 0; i < N; i++) {
- const theta = 2 * Math.PI / N * (i + 1);
- const thetaN = 2 * Math.PI / N * (i + 0.5);
- if (i < N - 1) {
-
- vertices.push(new Vec3(-radiusBottom * sin(theta), -height * 0.5, radiusBottom * cos(theta)));
- bottomface.push(2 * i + 2);
- vertices.push(new Vec3(-radiusTop * sin(theta), height * 0.5, radiusTop * cos(theta)));
- topface.push(2 * i + 3);
- faces.push([2 * i, 2 * i + 1, 2 * i + 3, 2 * i + 2]);
- } else {
- faces.push([2 * i, 2 * i + 1, 1, 0]);
- }
- if (N % 2 === 1 || i < N / 2) {
- axes.push(new Vec3(-sin(thetaN), 0, cos(thetaN)));
- }
- }
- faces.push(bottomface);
- axes.push(new Vec3(0, 1, 0));
- const temp = [];
- for (let i = 0; i < topface.length; i++) {
- temp.push(topface[topface.length - i - 1]);
- }
- faces.push(temp);
- super({
- vertices,
- faces,
- axes
- });
- this.type = Shape.types.CYLINDER;
- this.radiusTop = radiusTop;
- this.radiusBottom = radiusBottom;
- this.height = height;
- this.numSegments = numSegments;
- }
- }
- class Particle extends Shape {
- constructor() {
- super({
- type: Shape.types.PARTICLE
- });
- }
-
- calculateLocalInertia(mass, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- target.set(0, 0, 0);
- return target;
- }
- volume() {
- return 0;
- }
- updateBoundingSphereRadius() {
- this.boundingSphereRadius = 0;
- }
- calculateWorldAABB(pos, quat, min, max) {
-
- min.copy(pos);
- max.copy(pos);
- }
- }
- class Plane extends Shape {
-
-
- constructor() {
- super({
- type: Shape.types.PLANE
- });
- this.worldNormal = new Vec3();
- this.worldNormalNeedsUpdate = true;
- this.boundingSphereRadius = Number.MAX_VALUE;
- }
-
- computeWorldNormal(quat) {
- const n = this.worldNormal;
- n.set(0, 0, 1);
- quat.vmult(n, n);
- this.worldNormalNeedsUpdate = false;
- }
- calculateLocalInertia(mass, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- return target;
- }
- volume() {
- return (
- Number.MAX_VALUE
- );
- }
- calculateWorldAABB(pos, quat, min, max) {
-
- tempNormal.set(0, 0, 1);
- quat.vmult(tempNormal, tempNormal);
- const maxVal = Number.MAX_VALUE;
- min.set(-maxVal, -maxVal, -maxVal);
- max.set(maxVal, maxVal, maxVal);
- if (tempNormal.x === 1) {
- max.x = pos.x;
- } else if (tempNormal.x === -1) {
- min.x = pos.x;
- }
- if (tempNormal.y === 1) {
- max.y = pos.y;
- } else if (tempNormal.y === -1) {
- min.y = pos.y;
- }
- if (tempNormal.z === 1) {
- max.z = pos.z;
- } else if (tempNormal.z === -1) {
- min.z = pos.z;
- }
- }
- updateBoundingSphereRadius() {
- this.boundingSphereRadius = Number.MAX_VALUE;
- }
- }
- const tempNormal = new Vec3();
- class Heightfield extends Shape {
-
-
-
-
-
-
- constructor(data, options) {
- if (options === void 0) {
- options = {};
- }
- options = Utils.defaults(options, {
- maxValue: null,
- minValue: null,
- elementSize: 1
- });
- super({
- type: Shape.types.HEIGHTFIELD
- });
- this.data = data;
- this.maxValue = options.maxValue;
- this.minValue = options.minValue;
- this.elementSize = options.elementSize;
- if (options.minValue === null) {
- this.updateMinValue();
- }
- if (options.maxValue === null) {
- this.updateMaxValue();
- }
- this.cacheEnabled = true;
- this.pillarConvex = new ConvexPolyhedron();
- this.pillarOffset = new Vec3();
- this.updateBoundingSphereRadius();
-
-
- this._cachedPillars = {};
- }
-
- update() {
- this._cachedPillars = {};
- }
-
- updateMinValue() {
- const data = this.data;
- let minValue = data[0][0];
- for (let i = 0; i !== data.length; i++) {
- for (let j = 0; j !== data[i].length; j++) {
- const v = data[i][j];
- if (v < minValue) {
- minValue = v;
- }
- }
- }
- this.minValue = minValue;
- }
-
- updateMaxValue() {
- const data = this.data;
- let maxValue = data[0][0];
- for (let i = 0; i !== data.length; i++) {
- for (let j = 0; j !== data[i].length; j++) {
- const v = data[i][j];
- if (v > maxValue) {
- maxValue = v;
- }
- }
- }
- this.maxValue = maxValue;
- }
-
- setHeightValueAtIndex(xi, yi, value) {
- const data = this.data;
- data[xi][yi] = value;
- this.clearCachedConvexTrianglePillar(xi, yi, false);
- if (xi > 0) {
- this.clearCachedConvexTrianglePillar(xi - 1, yi, true);
- this.clearCachedConvexTrianglePillar(xi - 1, yi, false);
- }
- if (yi > 0) {
- this.clearCachedConvexTrianglePillar(xi, yi - 1, true);
- this.clearCachedConvexTrianglePillar(xi, yi - 1, false);
- }
- if (yi > 0 && xi > 0) {
- this.clearCachedConvexTrianglePillar(xi - 1, yi - 1, true);
- }
- }
-
- getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, result) {
- if (result === void 0) {
- result = [];
- }
-
- const data = this.data;
- let max = this.minValue;
- for (let i = iMinX; i <= iMaxX; i++) {
- for (let j = iMinY; j <= iMaxY; j++) {
- const height = data[i][j];
- if (height > max) {
- max = height;
- }
- }
- }
- result[0] = this.minValue;
- result[1] = max;
- }
-
- getIndexOfPosition(x, y, result, clamp) {
-
- const w = this.elementSize;
- const data = this.data;
- let xi = Math.floor(x / w);
- let yi = Math.floor(y / w);
- result[0] = xi;
- result[1] = yi;
- if (clamp) {
-
- if (xi < 0) {
- xi = 0;
- }
- if (yi < 0) {
- yi = 0;
- }
- if (xi >= data.length - 1) {
- xi = data.length - 1;
- }
- if (yi >= data[0].length - 1) {
- yi = data[0].length - 1;
- }
- }
- if (xi < 0 || yi < 0 || xi >= data.length - 1 || yi >= data[0].length - 1) {
- return false;
- }
- return true;
- }
- getTriangleAt(x, y, edgeClamp, a, b, c) {
- const idx = getHeightAt_idx;
- this.getIndexOfPosition(x, y, idx, edgeClamp);
- let xi = idx[0];
- let yi = idx[1];
- const data = this.data;
- if (edgeClamp) {
- xi = Math.min(data.length - 2, Math.max(0, xi));
- yi = Math.min(data[0].length - 2, Math.max(0, yi));
- }
- const elementSize = this.elementSize;
- const lowerDist2 = (x / elementSize - xi) ** 2 + (y / elementSize - yi) ** 2;
- const upperDist2 = (x / elementSize - (xi + 1)) ** 2 + (y / elementSize - (yi + 1)) ** 2;
- const upper = lowerDist2 > upperDist2;
- this.getTriangle(xi, yi, upper, a, b, c);
- return upper;
- }
- getNormalAt(x, y, edgeClamp, result) {
- const a = getNormalAt_a;
- const b = getNormalAt_b;
- const c = getNormalAt_c;
- const e0 = getNormalAt_e0;
- const e1 = getNormalAt_e1;
- this.getTriangleAt(x, y, edgeClamp, a, b, c);
- b.vsub(a, e0);
- c.vsub(a, e1);
- e0.cross(e1, result);
- result.normalize();
- }
-
- getAabbAtIndex(xi, yi, _ref) {
- let {
- lowerBound,
- upperBound
- } = _ref;
- const data = this.data;
- const elementSize = this.elementSize;
- lowerBound.set(xi * elementSize, yi * elementSize, data[xi][yi]);
- upperBound.set((xi + 1) * elementSize, (yi + 1) * elementSize, data[xi + 1][yi + 1]);
- }
-
- getHeightAt(x, y, edgeClamp) {
- const data = this.data;
- const a = getHeightAt_a;
- const b = getHeightAt_b;
- const c = getHeightAt_c;
- const idx = getHeightAt_idx;
- this.getIndexOfPosition(x, y, idx, edgeClamp);
- let xi = idx[0];
- let yi = idx[1];
- if (edgeClamp) {
- xi = Math.min(data.length - 2, Math.max(0, xi));
- yi = Math.min(data[0].length - 2, Math.max(0, yi));
- }
- const upper = this.getTriangleAt(x, y, edgeClamp, a, b, c);
- barycentricWeights(x, y, a.x, a.y, b.x, b.y, c.x, c.y, getHeightAt_weights);
- const w = getHeightAt_weights;
- if (upper) {
-
- return data[xi + 1][yi + 1] * w.x + data[xi][yi + 1] * w.y + data[xi + 1][yi] * w.z;
- } else {
-
- return data[xi][yi] * w.x + data[xi + 1][yi] * w.y + data[xi][yi + 1] * w.z;
- }
- }
- getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle) {
- return `${xi}_${yi}_${getUpperTriangle ? 1 : 0}`;
- }
- getCachedConvexTrianglePillar(xi, yi, getUpperTriangle) {
- return this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
- }
- setCachedConvexTrianglePillar(xi, yi, getUpperTriangle, convex, offset) {
- this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)] = {
- convex,
- offset
- };
- }
- clearCachedConvexTrianglePillar(xi, yi, getUpperTriangle) {
- delete this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
- }
-
- getTriangle(xi, yi, upper, a, b, c) {
- const data = this.data;
- const elementSize = this.elementSize;
- if (upper) {
-
- a.set((xi + 1) * elementSize, (yi + 1) * elementSize, data[xi + 1][yi + 1]);
- b.set(xi * elementSize, (yi + 1) * elementSize, data[xi][yi + 1]);
- c.set((xi + 1) * elementSize, yi * elementSize, data[xi + 1][yi]);
- } else {
-
- a.set(xi * elementSize, yi * elementSize, data[xi][yi]);
- b.set((xi + 1) * elementSize, yi * elementSize, data[xi + 1][yi]);
- c.set(xi * elementSize, (yi + 1) * elementSize, data[xi][yi + 1]);
- }
- }
-
- getConvexTrianglePillar(xi, yi, getUpperTriangle) {
- let result = this.pillarConvex;
- let offsetResult = this.pillarOffset;
- if (this.cacheEnabled) {
- const data = this.getCachedConvexTrianglePillar(xi, yi, getUpperTriangle);
- if (data) {
- this.pillarConvex = data.convex;
- this.pillarOffset = data.offset;
- return;
- }
- result = new ConvexPolyhedron();
- offsetResult = new Vec3();
- this.pillarConvex = result;
- this.pillarOffset = offsetResult;
- }
- const data = this.data;
- const elementSize = this.elementSize;
- const faces = result.faces;
- result.vertices.length = 6;
- for (let i = 0; i < 6; i++) {
- if (!result.vertices[i]) {
- result.vertices[i] = new Vec3();
- }
- }
- faces.length = 5;
- for (let i = 0; i < 5; i++) {
- if (!faces[i]) {
- faces[i] = [];
- }
- }
- const verts = result.vertices;
- const h = (Math.min(data[xi][yi], data[xi + 1][yi], data[xi][yi + 1], data[xi + 1][yi + 1]) - this.minValue) / 2 + this.minValue;
- if (!getUpperTriangle) {
-
- offsetResult.set((xi + 0.25) * elementSize,
- (yi + 0.25) * elementSize, h
- );
- verts[0].set(-0.25 * elementSize, -0.25 * elementSize, data[xi][yi] - h);
- verts[1].set(0.75 * elementSize, -0.25 * elementSize, data[xi + 1][yi] - h);
- verts[2].set(-0.25 * elementSize, 0.75 * elementSize, data[xi][yi + 1] - h);
- verts[3].set(-0.25 * elementSize, -0.25 * elementSize, -Math.abs(h) - 1);
- verts[4].set(0.75 * elementSize, -0.25 * elementSize, -Math.abs(h) - 1);
- verts[5].set(-0.25 * elementSize, 0.75 * elementSize, -Math.abs(h) - 1);
- faces[0][0] = 0;
- faces[0][1] = 1;
- faces[0][2] = 2;
- faces[1][0] = 5;
- faces[1][1] = 4;
- faces[1][2] = 3;
- faces[2][0] = 0;
- faces[2][1] = 2;
- faces[2][2] = 5;
- faces[2][3] = 3;
- faces[3][0] = 1;
- faces[3][1] = 0;
- faces[3][2] = 3;
- faces[3][3] = 4;
- faces[4][0] = 4;
- faces[4][1] = 5;
- faces[4][2] = 2;
- faces[4][3] = 1;
- } else {
-
- offsetResult.set((xi + 0.75) * elementSize,
- (yi + 0.75) * elementSize, h
- );
- verts[0].set(0.25 * elementSize, 0.25 * elementSize, data[xi + 1][yi + 1] - h);
- verts[1].set(-0.75 * elementSize, 0.25 * elementSize, data[xi][yi + 1] - h);
- verts[2].set(0.25 * elementSize, -0.75 * elementSize, data[xi + 1][yi] - h);
- verts[3].set(0.25 * elementSize, 0.25 * elementSize, -Math.abs(h) - 1);
- verts[4].set(-0.75 * elementSize, 0.25 * elementSize, -Math.abs(h) - 1);
- verts[5].set(0.25 * elementSize, -0.75 * elementSize, -Math.abs(h) - 1);
- faces[0][0] = 0;
- faces[0][1] = 1;
- faces[0][2] = 2;
- faces[1][0] = 5;
- faces[1][1] = 4;
- faces[1][2] = 3;
- faces[2][0] = 2;
- faces[2][1] = 5;
- faces[2][2] = 3;
- faces[2][3] = 0;
- faces[3][0] = 3;
- faces[3][1] = 4;
- faces[3][2] = 1;
- faces[3][3] = 0;
- faces[4][0] = 1;
- faces[4][1] = 4;
- faces[4][2] = 5;
- faces[4][3] = 2;
- }
- result.computeNormals();
- result.computeEdges();
- result.updateBoundingSphereRadius();
- this.setCachedConvexTrianglePillar(xi, yi, getUpperTriangle, result, offsetResult);
- }
- calculateLocalInertia(mass, target) {
- if (target === void 0) {
- target = new Vec3();
- }
- target.set(0, 0, 0);
- return target;
- }
- volume() {
- return (
- Number.MAX_VALUE
- );
- }
- calculateWorldAABB(pos, quat, min, max) {
-
- min.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
- max.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
- }
- updateBoundingSphereRadius() {
-
- const data = this.data;
- const s = this.elementSize;
- this.boundingSphereRadius = new Vec3(data.length * s, data[0].length * s, Math.max(Math.abs(this.maxValue), Math.abs(this.minValue))).length();
- }
-
- setHeightsFromImage(image, scale) {
- const {
- x,
- z,
- y
- } = scale;
- const canvas = document.createElement('canvas');
- canvas.width = image.width;
- canvas.height = image.height;
- const context = canvas.getContext('2d');
- context.drawImage(image, 0, 0);
- const imageData = context.getImageData(0, 0, image.width, image.height);
- const matrix = this.data;
- matrix.length = 0;
- this.elementSize = Math.abs(x) / imageData.width;
- for (let i = 0; i < imageData.height; i++) {
- const row = [];
- for (let j = 0; j < imageData.width; j++) {
- const a = imageData.data[(i * imageData.height + j) * 4];
- const b = imageData.data[(i * imageData.height + j) * 4 + 1];
- const c = imageData.data[(i * imageData.height + j) * 4 + 2];
- const height = (a + b + c) / 4 / 255 * z;
- if (x < 0) {
- row.push(height);
- } else {
- row.unshift(height);
- }
- }
- if (y < 0) {
- matrix.unshift(row);
- } else {
- matrix.push(row);
- }
- }
- this.updateMaxValue();
- this.updateMinValue();
- this.update();
- }
- }
- const getHeightAt_idx = [];
- const getHeightAt_weights = new Vec3();
- const getHeightAt_a = new Vec3();
- const getHeightAt_b = new Vec3();
- const getHeightAt_c = new Vec3();
- const getNormalAt_a = new Vec3();
- const getNormalAt_b = new Vec3();
- const getNormalAt_c = new Vec3();
- const getNormalAt_e0 = new Vec3();
- const getNormalAt_e1 = new Vec3();
- function barycentricWeights(x, y, ax, ay, bx, by, cx, cy, result) {
- result.x = ((by - cy) * (x - cx) + (cx - bx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
- result.y = ((cy - ay) * (x - cx) + (ax - cx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
- result.z = 1 - result.x - result.y;
- }
- class OctreeNode {
-
-
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- this.root = options.root || null;
- this.aabb = options.aabb ? options.aabb.clone() : new AABB();
- this.data = [];
- this.children = [];
- }
-
- reset() {
- this.children.length = this.data.length = 0;
- }
-
- insert(aabb, elementData, level) {
- if (level === void 0) {
- level = 0;
- }
- const nodeData = this.data;
- if (!this.aabb.contains(aabb)) {
- return false;
- }
- const children = this.children;
- const maxDepth = this.maxDepth || this.root.maxDepth;
- if (level < maxDepth) {
-
- let subdivided = false;
- if (!children.length) {
- this.subdivide();
- subdivided = true;
- }
- for (let i = 0; i !== 8; i++) {
- if (children[i].insert(aabb, elementData, level + 1)) {
- return true;
- }
- }
- if (subdivided) {
-
- children.length = 0;
- }
- }
- nodeData.push(elementData);
- return true;
- }
-
- subdivide() {
- const aabb = this.aabb;
- const l = aabb.lowerBound;
- const u = aabb.upperBound;
- const children = this.children;
- children.push(new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(0, 0, 0)
- })
- }), new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(1, 0, 0)
- })
- }), new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(1, 1, 0)
- })
- }), new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(1, 1, 1)
- })
- }), new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(0, 1, 1)
- })
- }), new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(0, 0, 1)
- })
- }), new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(1, 0, 1)
- })
- }), new OctreeNode({
- aabb: new AABB({
- lowerBound: new Vec3(0, 1, 0)
- })
- }));
- u.vsub(l, halfDiagonal);
- halfDiagonal.scale(0.5, halfDiagonal);
- const root = this.root || this;
- for (let i = 0; i !== 8; i++) {
- const child = children[i];
- child.root = root;
- const lowerBound = child.aabb.lowerBound;
- lowerBound.x *= halfDiagonal.x;
- lowerBound.y *= halfDiagonal.y;
- lowerBound.z *= halfDiagonal.z;
- lowerBound.vadd(l, lowerBound);
- lowerBound.vadd(halfDiagonal, child.aabb.upperBound);
- }
- }
-
- aabbQuery(aabb, result) {
- this.data;
-
-
-
-
-
-
-
- this.children;
-
-
- const queue = [this];
- while (queue.length) {
- const node = queue.pop();
- if (node.aabb.overlaps(aabb)) {
- Array.prototype.push.apply(result, node.data);
- }
- Array.prototype.push.apply(queue, node.children);
- }
- return result;
- }
-
- rayQuery(ray, treeTransform, result) {
-
-
- ray.getAABB(tmpAABB);
- tmpAABB.toLocalFrame(treeTransform, tmpAABB);
- this.aabbQuery(tmpAABB, result);
- return result;
- }
-
- removeEmptyNodes() {
- for (let i = this.children.length - 1; i >= 0; i--) {
- this.children[i].removeEmptyNodes();
- if (!this.children[i].children.length && !this.children[i].data.length) {
- this.children.splice(i, 1);
- }
- }
- }
- }
- class Octree extends OctreeNode {
-
-
- constructor(aabb, options) {
- if (options === void 0) {
- options = {};
- }
- super({
- root: null,
- aabb
- });
- this.maxDepth = typeof options.maxDepth !== 'undefined' ? options.maxDepth : 8;
- }
- }
- const halfDiagonal = new Vec3();
- const tmpAABB = new AABB();
- class Trimesh extends Shape {
-
-
-
-
-
-
-
- constructor(vertices, indices) {
- super({
- type: Shape.types.TRIMESH
- });
- this.vertices = new Float32Array(vertices);
- this.indices = new Int16Array(indices);
- this.normals = new Float32Array(indices.length);
- this.aabb = new AABB();
- this.edges = null;
- this.scale = new Vec3(1, 1, 1);
- this.tree = new Octree();
- this.updateEdges();
- this.updateNormals();
- this.updateAABB();
- this.updateBoundingSphereRadius();
- this.updateTree();
- }
-
- updateTree() {
- const tree = this.tree;
- tree.reset();
- tree.aabb.copy(this.aabb);
- const scale = this.scale;
- tree.aabb.lowerBound.x *= 1 / scale.x;
- tree.aabb.lowerBound.y *= 1 / scale.y;
- tree.aabb.lowerBound.z *= 1 / scale.z;
- tree.aabb.upperBound.x *= 1 / scale.x;
- tree.aabb.upperBound.y *= 1 / scale.y;
- tree.aabb.upperBound.z *= 1 / scale.z;
- const triangleAABB = new AABB();
- const a = new Vec3();
- const b = new Vec3();
- const c = new Vec3();
- const points = [a, b, c];
- for (let i = 0; i < this.indices.length / 3; i++) {
-
-
- const i3 = i * 3;
- this._getUnscaledVertex(this.indices[i3], a);
- this._getUnscaledVertex(this.indices[i3 + 1], b);
- this._getUnscaledVertex(this.indices[i3 + 2], c);
- triangleAABB.setFromPoints(points);
- tree.insert(triangleAABB, i);
- }
- tree.removeEmptyNodes();
- }
-
- getTrianglesInAABB(aabb, result) {
- unscaledAABB.copy(aabb);
- const scale = this.scale;
- const isx = scale.x;
- const isy = scale.y;
- const isz = scale.z;
- const l = unscaledAABB.lowerBound;
- const u = unscaledAABB.upperBound;
- l.x /= isx;
- l.y /= isy;
- l.z /= isz;
- u.x /= isx;
- u.y /= isy;
- u.z /= isz;
- return this.tree.aabbQuery(unscaledAABB, result);
- }
-
- setScale(scale) {
- const wasUniform = this.scale.x === this.scale.y && this.scale.y === this.scale.z;
- const isUniform = scale.x === scale.y && scale.y === scale.z;
- if (!(wasUniform && isUniform)) {
-
- this.updateNormals();
- }
- this.scale.copy(scale);
- this.updateAABB();
- this.updateBoundingSphereRadius();
- }
-
- updateNormals() {
- const n = computeNormals_n;
- const normals = this.normals;
- for (let i = 0; i < this.indices.length / 3; i++) {
- const i3 = i * 3;
- const a = this.indices[i3];
- const b = this.indices[i3 + 1];
- const c = this.indices[i3 + 2];
- this.getVertex(a, va);
- this.getVertex(b, vb);
- this.getVertex(c, vc);
- Trimesh.computeNormal(vb, va, vc, n);
- normals[i3] = n.x;
- normals[i3 + 1] = n.y;
- normals[i3 + 2] = n.z;
- }
- }
-
- updateEdges() {
- const edges = {};
- const add = (a, b) => {
- const key = a < b ? `${a}_${b}` : `${b}_${a}`;
- edges[key] = true;
- };
- for (let i = 0; i < this.indices.length / 3; i++) {
- const i3 = i * 3;
- const a = this.indices[i3];
- const b = this.indices[i3 + 1];
- const c = this.indices[i3 + 2];
- add(a, b);
- add(b, c);
- add(c, a);
- }
- const keys = Object.keys(edges);
- this.edges = new Int16Array(keys.length * 2);
- for (let i = 0; i < keys.length; i++) {
- const indices = keys[i].split('_');
- this.edges[2 * i] = parseInt(indices[0], 10);
- this.edges[2 * i + 1] = parseInt(indices[1], 10);
- }
- }
-
- getEdgeVertex(edgeIndex, firstOrSecond, vertexStore) {
- const vertexIndex = this.edges[edgeIndex * 2 + (firstOrSecond ? 1 : 0)];
- this.getVertex(vertexIndex, vertexStore);
- }
-
- getEdgeVector(edgeIndex, vectorStore) {
- const va = getEdgeVector_va;
- const vb = getEdgeVector_vb;
- this.getEdgeVertex(edgeIndex, 0, va);
- this.getEdgeVertex(edgeIndex, 1, vb);
- vb.vsub(va, vectorStore);
- }
-
- static computeNormal(va, vb, vc, target) {
- vb.vsub(va, ab);
- vc.vsub(vb, cb);
- cb.cross(ab, target);
- if (!target.isZero()) {
- target.normalize();
- }
- }
-
- getVertex(i, out) {
- const scale = this.scale;
- this._getUnscaledVertex(i, out);
- out.x *= scale.x;
- out.y *= scale.y;
- out.z *= scale.z;
- return out;
- }
-
- _getUnscaledVertex(i, out) {
- const i3 = i * 3;
- const vertices = this.vertices;
- return out.set(vertices[i3], vertices[i3 + 1], vertices[i3 + 2]);
- }
-
- getWorldVertex(i, pos, quat, out) {
- this.getVertex(i, out);
- Transform.pointToWorldFrame(pos, quat, out, out);
- return out;
- }
-
- getTriangleVertices(i, a, b, c) {
- const i3 = i * 3;
- this.getVertex(this.indices[i3], a);
- this.getVertex(this.indices[i3 + 1], b);
- this.getVertex(this.indices[i3 + 2], c);
- }
-
- getNormal(i, target) {
- const i3 = i * 3;
- return target.set(this.normals[i3], this.normals[i3 + 1], this.normals[i3 + 2]);
- }
-
- calculateLocalInertia(mass, target) {
-
-
- this.computeLocalAABB(cli_aabb);
- const x = cli_aabb.upperBound.x - cli_aabb.lowerBound.x;
- const y = cli_aabb.upperBound.y - cli_aabb.lowerBound.y;
- const z = cli_aabb.upperBound.z - cli_aabb.lowerBound.z;
- return target.set(1.0 / 12.0 * mass * (2 * y * 2 * y + 2 * z * 2 * z), 1.0 / 12.0 * mass * (2 * x * 2 * x + 2 * z * 2 * z), 1.0 / 12.0 * mass * (2 * y * 2 * y + 2 * x * 2 * x));
- }
-
- computeLocalAABB(aabb) {
- const l = aabb.lowerBound;
- const u = aabb.upperBound;
- const n = this.vertices.length;
- this.vertices;
- const v = computeLocalAABB_worldVert;
- this.getVertex(0, v);
- l.copy(v);
- u.copy(v);
- for (let i = 0; i !== n; i++) {
- this.getVertex(i, v);
- if (v.x < l.x) {
- l.x = v.x;
- } else if (v.x > u.x) {
- u.x = v.x;
- }
- if (v.y < l.y) {
- l.y = v.y;
- } else if (v.y > u.y) {
- u.y = v.y;
- }
- if (v.z < l.z) {
- l.z = v.z;
- } else if (v.z > u.z) {
- u.z = v.z;
- }
- }
- }
-
- updateAABB() {
- this.computeLocalAABB(this.aabb);
- }
-
- updateBoundingSphereRadius() {
-
- let max2 = 0;
- const vertices = this.vertices;
- const v = new Vec3();
- for (let i = 0, N = vertices.length / 3; i !== N; i++) {
- this.getVertex(i, v);
- const norm2 = v.lengthSquared();
- if (norm2 > max2) {
- max2 = norm2;
- }
- }
- this.boundingSphereRadius = Math.sqrt(max2);
- }
-
- calculateWorldAABB(pos, quat, min, max) {
-
-
- const frame = calculateWorldAABB_frame;
- const result = calculateWorldAABB_aabb;
- frame.position = pos;
- frame.quaternion = quat;
- this.aabb.toWorldFrame(frame, result);
- min.copy(result.lowerBound);
- max.copy(result.upperBound);
- }
-
- volume() {
- return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
- }
-
- static createTorus(radius, tube, radialSegments, tubularSegments, arc) {
- if (radius === void 0) {
- radius = 1;
- }
- if (tube === void 0) {
- tube = 0.5;
- }
- if (radialSegments === void 0) {
- radialSegments = 8;
- }
- if (tubularSegments === void 0) {
- tubularSegments = 6;
- }
- if (arc === void 0) {
- arc = Math.PI * 2;
- }
- const vertices = [];
- const indices = [];
- for (let j = 0; j <= radialSegments; j++) {
- for (let i = 0; i <= tubularSegments; i++) {
- const u = i / tubularSegments * arc;
- const v = j / radialSegments * Math.PI * 2;
- const x = (radius + tube * Math.cos(v)) * Math.cos(u);
- const y = (radius + tube * Math.cos(v)) * Math.sin(u);
- const z = tube * Math.sin(v);
- vertices.push(x, y, z);
- }
- }
- for (let j = 1; j <= radialSegments; j++) {
- for (let i = 1; i <= tubularSegments; i++) {
- const a = (tubularSegments + 1) * j + i - 1;
- const b = (tubularSegments + 1) * (j - 1) + i - 1;
- const c = (tubularSegments + 1) * (j - 1) + i;
- const d = (tubularSegments + 1) * j + i;
- indices.push(a, b, d);
- indices.push(b, c, d);
- }
- }
- return new Trimesh(vertices, indices);
- }
- }
- const computeNormals_n = new Vec3();
- const unscaledAABB = new AABB();
- const getEdgeVector_va = new Vec3();
- const getEdgeVector_vb = new Vec3();
- const cb = new Vec3();
- const ab = new Vec3();
- const va = new Vec3();
- const vb = new Vec3();
- const vc = new Vec3();
- const cli_aabb = new AABB();
- const computeLocalAABB_worldVert = new Vec3();
- const calculateWorldAABB_frame = new Transform();
- const calculateWorldAABB_aabb = new AABB();
- class Solver {
-
-
- constructor() {
- this.equations = [];
- }
-
- solve(dt, world) {
- return (
- 0
- );
- }
-
- addEquation(eq) {
- if (eq.enabled && !eq.bi.isTrigger && !eq.bj.isTrigger) {
- this.equations.push(eq);
- }
- }
-
- removeEquation(eq) {
- const eqs = this.equations;
- const i = eqs.indexOf(eq);
- if (i !== -1) {
- eqs.splice(i, 1);
- }
- }
-
- removeAllEquations() {
- this.equations.length = 0;
- }
- }
- class GSSolver extends Solver {
-
-
-
- constructor() {
- super();
- this.iterations = 10;
- this.tolerance = 1e-7;
- }
-
- solve(dt, world) {
- let iter = 0;
- const maxIter = this.iterations;
- const tolSquared = this.tolerance * this.tolerance;
- const equations = this.equations;
- const Neq = equations.length;
- const bodies = world.bodies;
- const Nbodies = bodies.length;
- const h = dt;
- let B;
- let invC;
- let deltalambda;
- let deltalambdaTot;
- let GWlambda;
- let lambdaj;
- if (Neq !== 0) {
- for (let i = 0; i !== Nbodies; i++) {
- bodies[i].updateSolveMassProperties();
- }
- }
- const invCs = GSSolver_solve_invCs;
- const Bs = GSSolver_solve_Bs;
- const lambda = GSSolver_solve_lambda;
- invCs.length = Neq;
- Bs.length = Neq;
- lambda.length = Neq;
- for (let i = 0; i !== Neq; i++) {
- const c = equations[i];
- lambda[i] = 0.0;
- Bs[i] = c.computeB(h);
- invCs[i] = 1.0 / c.computeC();
- }
- if (Neq !== 0) {
-
- for (let i = 0; i !== Nbodies; i++) {
- const b = bodies[i];
- const vlambda = b.vlambda;
- const wlambda = b.wlambda;
- vlambda.set(0, 0, 0);
- wlambda.set(0, 0, 0);
- }
- for (iter = 0; iter !== maxIter; iter++) {
-
- deltalambdaTot = 0.0;
- for (let j = 0; j !== Neq; j++) {
- const c = equations[j];
- B = Bs[j];
- invC = invCs[j];
- lambdaj = lambda[j];
- GWlambda = c.computeGWlambda();
- deltalambda = invC * (B - GWlambda - c.eps * lambdaj);
- if (lambdaj + deltalambda < c.minForce) {
- deltalambda = c.minForce - lambdaj;
- } else if (lambdaj + deltalambda > c.maxForce) {
- deltalambda = c.maxForce - lambdaj;
- }
- lambda[j] += deltalambda;
- deltalambdaTot += deltalambda > 0.0 ? deltalambda : -deltalambda;
- c.addToWlambda(deltalambda);
- }
- if (deltalambdaTot * deltalambdaTot < tolSquared) {
- break;
- }
- }
- for (let i = 0; i !== Nbodies; i++) {
- const b = bodies[i];
- const v = b.velocity;
- const w = b.angularVelocity;
- b.vlambda.vmul(b.linearFactor, b.vlambda);
- v.vadd(b.vlambda, v);
- b.wlambda.vmul(b.angularFactor, b.wlambda);
- w.vadd(b.wlambda, w);
- }
- let l = equations.length;
- const invDt = 1 / h;
- while (l--) {
- equations[l].multiplier = lambda[l] * invDt;
- }
- }
- return iter;
- }
- }
- const GSSolver_solve_lambda = [];
- const GSSolver_solve_invCs = [];
- const GSSolver_solve_Bs = [];
- class SplitSolver extends Solver {
-
-
-
- constructor(subsolver) {
- super();
- this.iterations = 10;
- this.tolerance = 1e-7;
- this.subsolver = subsolver;
- this.nodes = [];
- this.nodePool = [];
- while (this.nodePool.length < 128) {
- this.nodePool.push(this.createNode());
- }
- }
-
- createNode() {
- return {
- body: null,
- children: [],
- eqs: [],
- visited: false
- };
- }
-
- solve(dt, world) {
- const nodes = SplitSolver_solve_nodes;
- const nodePool = this.nodePool;
- const bodies = world.bodies;
- const equations = this.equations;
- const Neq = equations.length;
- const Nbodies = bodies.length;
- const subsolver = this.subsolver;
- while (nodePool.length < Nbodies) {
- nodePool.push(this.createNode());
- }
- nodes.length = Nbodies;
- for (let i = 0; i < Nbodies; i++) {
- nodes[i] = nodePool[i];
- }
- for (let i = 0; i !== Nbodies; i++) {
- const node = nodes[i];
- node.body = bodies[i];
- node.children.length = 0;
- node.eqs.length = 0;
- node.visited = false;
- }
- for (let k = 0; k !== Neq; k++) {
- const eq = equations[k];
- const i = bodies.indexOf(eq.bi);
- const j = bodies.indexOf(eq.bj);
- const ni = nodes[i];
- const nj = nodes[j];
- ni.children.push(nj);
- ni.eqs.push(eq);
- nj.children.push(ni);
- nj.eqs.push(eq);
- }
- let child;
- let n = 0;
- let eqs = SplitSolver_solve_eqs;
- subsolver.tolerance = this.tolerance;
- subsolver.iterations = this.iterations;
- const dummyWorld = SplitSolver_solve_dummyWorld;
- while (child = getUnvisitedNode(nodes)) {
- eqs.length = 0;
- dummyWorld.bodies.length = 0;
- bfs(child, visitFunc, dummyWorld.bodies, eqs);
- const Neqs = eqs.length;
- eqs = eqs.sort(sortById);
- for (let i = 0; i !== Neqs; i++) {
- subsolver.addEquation(eqs[i]);
- }
- subsolver.solve(dt, dummyWorld);
- subsolver.removeAllEquations();
- n++;
- }
- return n;
- }
- }
- const SplitSolver_solve_nodes = [];
- const SplitSolver_solve_eqs = [];
- const SplitSolver_solve_dummyWorld = {
- bodies: []
- };
- const STATIC = Body.STATIC;
- function getUnvisitedNode(nodes) {
- const Nnodes = nodes.length;
- for (let i = 0; i !== Nnodes; i++) {
- const node = nodes[i];
- if (!node.visited && !(node.body.type & STATIC)) {
- return node;
- }
- }
- return false;
- }
- const queue = [];
- function bfs(root, visitFunc, bds, eqs) {
- queue.push(root);
- root.visited = true;
- visitFunc(root, bds, eqs);
- while (queue.length) {
- const node = queue.pop();
- let child;
- while (child = getUnvisitedNode(node.children)) {
- child.visited = true;
- visitFunc(child, bds, eqs);
- queue.push(child);
- }
- }
- }
- function visitFunc(node, bds, eqs) {
- bds.push(node.body);
- const Neqs = node.eqs.length;
- for (let i = 0; i !== Neqs; i++) {
- const eq = node.eqs[i];
- if (!eqs.includes(eq)) {
- eqs.push(eq);
- }
- }
- }
- function sortById(a, b) {
- return b.id - a.id;
- }
- class Pool {
- constructor() {
- this.objects = [];
- this.type = Object;
- }
-
- release() {
- const Nargs = arguments.length;
- for (let i = 0; i !== Nargs; i++) {
- this.objects.push(i < 0 || arguments.length <= i ? undefined : arguments[i]);
- }
- return this;
- }
-
- get() {
- if (this.objects.length === 0) {
- return this.constructObject();
- } else {
- return this.objects.pop();
- }
- }
-
- constructObject() {
- throw new Error('constructObject() not implemented in this Pool subclass yet!');
- }
-
- resize(size) {
- const objects = this.objects;
- while (objects.length > size) {
- objects.pop();
- }
- while (objects.length < size) {
- objects.push(this.constructObject());
- }
- return this;
- }
- }
- class Vec3Pool extends Pool {
- constructor() {
- super(...arguments);
- this.type = Vec3;
- }
-
- constructObject() {
- return new Vec3();
- }
- }
- const COLLISION_TYPES = {
- sphereSphere: Shape.types.SPHERE,
- spherePlane: Shape.types.SPHERE | Shape.types.PLANE,
- boxBox: Shape.types.BOX | Shape.types.BOX,
- sphereBox: Shape.types.SPHERE | Shape.types.BOX,
- planeBox: Shape.types.PLANE | Shape.types.BOX,
- convexConvex: Shape.types.CONVEXPOLYHEDRON,
- sphereConvex: Shape.types.SPHERE | Shape.types.CONVEXPOLYHEDRON,
- planeConvex: Shape.types.PLANE | Shape.types.CONVEXPOLYHEDRON,
- boxConvex: Shape.types.BOX | Shape.types.CONVEXPOLYHEDRON,
- sphereHeightfield: Shape.types.SPHERE | Shape.types.HEIGHTFIELD,
- boxHeightfield: Shape.types.BOX | Shape.types.HEIGHTFIELD,
- convexHeightfield: Shape.types.CONVEXPOLYHEDRON | Shape.types.HEIGHTFIELD,
- sphereParticle: Shape.types.PARTICLE | Shape.types.SPHERE,
- planeParticle: Shape.types.PLANE | Shape.types.PARTICLE,
- boxParticle: Shape.types.BOX | Shape.types.PARTICLE,
- convexParticle: Shape.types.PARTICLE | Shape.types.CONVEXPOLYHEDRON,
- cylinderCylinder: Shape.types.CYLINDER,
- sphereCylinder: Shape.types.SPHERE | Shape.types.CYLINDER,
- planeCylinder: Shape.types.PLANE | Shape.types.CYLINDER,
- boxCylinder: Shape.types.BOX | Shape.types.CYLINDER,
- convexCylinder: Shape.types.CONVEXPOLYHEDRON | Shape.types.CYLINDER,
- heightfieldCylinder: Shape.types.HEIGHTFIELD | Shape.types.CYLINDER,
- particleCylinder: Shape.types.PARTICLE | Shape.types.CYLINDER,
- sphereTrimesh: Shape.types.SPHERE | Shape.types.TRIMESH,
- planeTrimesh: Shape.types.PLANE | Shape.types.TRIMESH
- };
- class Narrowphase {
-
-
- get [COLLISION_TYPES.sphereSphere]() {
- return this.sphereSphere;
- }
- get [COLLISION_TYPES.spherePlane]() {
- return this.spherePlane;
- }
- get [COLLISION_TYPES.boxBox]() {
- return this.boxBox;
- }
- get [COLLISION_TYPES.sphereBox]() {
- return this.sphereBox;
- }
- get [COLLISION_TYPES.planeBox]() {
- return this.planeBox;
- }
- get [COLLISION_TYPES.convexConvex]() {
- return this.convexConvex;
- }
- get [COLLISION_TYPES.sphereConvex]() {
- return this.sphereConvex;
- }
- get [COLLISION_TYPES.planeConvex]() {
- return this.planeConvex;
- }
- get [COLLISION_TYPES.boxConvex]() {
- return this.boxConvex;
- }
- get [COLLISION_TYPES.sphereHeightfield]() {
- return this.sphereHeightfield;
- }
- get [COLLISION_TYPES.boxHeightfield]() {
- return this.boxHeightfield;
- }
- get [COLLISION_TYPES.convexHeightfield]() {
- return this.convexHeightfield;
- }
- get [COLLISION_TYPES.sphereParticle]() {
- return this.sphereParticle;
- }
- get [COLLISION_TYPES.planeParticle]() {
- return this.planeParticle;
- }
- get [COLLISION_TYPES.boxParticle]() {
- return this.boxParticle;
- }
- get [COLLISION_TYPES.convexParticle]() {
- return this.convexParticle;
- }
- get [COLLISION_TYPES.cylinderCylinder]() {
- return this.convexConvex;
- }
- get [COLLISION_TYPES.sphereCylinder]() {
- return this.sphereConvex;
- }
- get [COLLISION_TYPES.planeCylinder]() {
- return this.planeConvex;
- }
- get [COLLISION_TYPES.boxCylinder]() {
- return this.boxConvex;
- }
- get [COLLISION_TYPES.convexCylinder]() {
- return this.convexConvex;
- }
- get [COLLISION_TYPES.heightfieldCylinder]() {
- return this.heightfieldCylinder;
- }
- get [COLLISION_TYPES.particleCylinder]() {
- return this.particleCylinder;
- }
- get [COLLISION_TYPES.sphereTrimesh]() {
- return this.sphereTrimesh;
- }
- get [COLLISION_TYPES.planeTrimesh]() {
- return this.planeTrimesh;
- }
-
-
- constructor(world) {
- this.contactPointPool = [];
- this.frictionEquationPool = [];
- this.result = [];
- this.frictionResult = [];
- this.v3pool = new Vec3Pool();
- this.world = world;
- this.currentContactMaterial = world.defaultContactMaterial;
- this.enableFrictionReduction = false;
- }
-
- createContactEquation(bi, bj, si, sj, overrideShapeA, overrideShapeB) {
- let c;
- if (this.contactPointPool.length) {
- c = this.contactPointPool.pop();
- c.bi = bi;
- c.bj = bj;
- } else {
- c = new ContactEquation(bi, bj);
- }
- c.enabled = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
- const cm = this.currentContactMaterial;
- c.restitution = cm.restitution;
- c.setSpookParams(cm.contactEquationStiffness, cm.contactEquationRelaxation, this.world.dt);
- const matA = si.material || bi.material;
- const matB = sj.material || bj.material;
- if (matA && matB && matA.restitution >= 0 && matB.restitution >= 0) {
- c.restitution = matA.restitution * matB.restitution;
- }
- c.si = overrideShapeA || si;
- c.sj = overrideShapeB || sj;
- return c;
- }
- createFrictionEquationsFromContact(contactEquation, outArray) {
- const bodyA = contactEquation.bi;
- const bodyB = contactEquation.bj;
- const shapeA = contactEquation.si;
- const shapeB = contactEquation.sj;
- const world = this.world;
- const cm = this.currentContactMaterial;
- let friction = cm.friction;
- const matA = shapeA.material || bodyA.material;
- const matB = shapeB.material || bodyB.material;
- if (matA && matB && matA.friction >= 0 && matB.friction >= 0) {
- friction = matA.friction * matB.friction;
- }
- if (friction > 0) {
-
-
- const mug = friction * (world.frictionGravity || world.gravity).length();
- let reducedMass = bodyA.invMass + bodyB.invMass;
- if (reducedMass > 0) {
- reducedMass = 1 / reducedMass;
- }
- const pool = this.frictionEquationPool;
- const c1 = pool.length ? pool.pop() : new FrictionEquation(bodyA, bodyB, mug * reducedMass);
- const c2 = pool.length ? pool.pop() : new FrictionEquation(bodyA, bodyB, mug * reducedMass);
- c1.bi = c2.bi = bodyA;
- c1.bj = c2.bj = bodyB;
- c1.minForce = c2.minForce = -mug * reducedMass;
- c1.maxForce = c2.maxForce = mug * reducedMass;
- c1.ri.copy(contactEquation.ri);
- c1.rj.copy(contactEquation.rj);
- c2.ri.copy(contactEquation.ri);
- c2.rj.copy(contactEquation.rj);
- contactEquation.ni.tangents(c1.t, c2.t);
- c1.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
- c2.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
- c1.enabled = c2.enabled = contactEquation.enabled;
- outArray.push(c1, c2);
- return true;
- }
- return false;
- }
-
- createFrictionFromAverage(numContacts) {
-
- let c = this.result[this.result.length - 1];
- if (!this.createFrictionEquationsFromContact(c, this.frictionResult) || numContacts === 1) {
- return;
- }
- const f1 = this.frictionResult[this.frictionResult.length - 2];
- const f2 = this.frictionResult[this.frictionResult.length - 1];
- averageNormal.setZero();
- averageContactPointA.setZero();
- averageContactPointB.setZero();
- const bodyA = c.bi;
- c.bj;
- for (let i = 0; i !== numContacts; i++) {
- c = this.result[this.result.length - 1 - i];
- if (c.bi !== bodyA) {
- averageNormal.vadd(c.ni, averageNormal);
- averageContactPointA.vadd(c.ri, averageContactPointA);
- averageContactPointB.vadd(c.rj, averageContactPointB);
- } else {
- averageNormal.vsub(c.ni, averageNormal);
- averageContactPointA.vadd(c.rj, averageContactPointA);
- averageContactPointB.vadd(c.ri, averageContactPointB);
- }
- }
- const invNumContacts = 1 / numContacts;
- averageContactPointA.scale(invNumContacts, f1.ri);
- averageContactPointB.scale(invNumContacts, f1.rj);
- f2.ri.copy(f1.ri);
- f2.rj.copy(f1.rj);
- averageNormal.normalize();
- averageNormal.tangents(f1.t, f2.t);
- }
-
- getContacts(p1, p2, world, result, oldcontacts, frictionResult, frictionPool) {
-
- this.contactPointPool = oldcontacts;
- this.frictionEquationPool = frictionPool;
- this.result = result;
- this.frictionResult = frictionResult;
- const qi = tmpQuat1;
- const qj = tmpQuat2;
- const xi = tmpVec1;
- const xj = tmpVec2;
- for (let k = 0, N = p1.length; k !== N; k++) {
-
- const bi = p1[k];
- const bj = p2[k];
- let bodyContactMaterial = null;
- if (bi.material && bj.material) {
- bodyContactMaterial = world.getContactMaterial(bi.material, bj.material) || null;
- }
- const justTest = bi.type & Body.KINEMATIC && bj.type & Body.STATIC || bi.type & Body.STATIC && bj.type & Body.KINEMATIC || bi.type & Body.KINEMATIC && bj.type & Body.KINEMATIC;
- for (let i = 0; i < bi.shapes.length; i++) {
- bi.quaternion.mult(bi.shapeOrientations[i], qi);
- bi.quaternion.vmult(bi.shapeOffsets[i], xi);
- xi.vadd(bi.position, xi);
- const si = bi.shapes[i];
- for (let j = 0; j < bj.shapes.length; j++) {
-
- bj.quaternion.mult(bj.shapeOrientations[j], qj);
- bj.quaternion.vmult(bj.shapeOffsets[j], xj);
- xj.vadd(bj.position, xj);
- const sj = bj.shapes[j];
- if (!(si.collisionFilterMask & sj.collisionFilterGroup && sj.collisionFilterMask & si.collisionFilterGroup)) {
- continue;
- }
- if (xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius) {
- continue;
- }
- let shapeContactMaterial = null;
- if (si.material && sj.material) {
- shapeContactMaterial = world.getContactMaterial(si.material, sj.material) || null;
- }
- this.currentContactMaterial = shapeContactMaterial || bodyContactMaterial || world.defaultContactMaterial;
- const resolverIndex = si.type | sj.type;
- const resolver = this[resolverIndex];
- if (resolver) {
- let retval = false;
-
-
- if (si.type < sj.type) {
- retval = resolver.call(this, si, sj, xi, xj, qi, qj, bi, bj, si, sj, justTest);
- } else {
- retval = resolver.call(this, sj, si, xj, xi, qj, qi, bj, bi, si, sj, justTest);
- }
- if (retval && justTest) {
-
- world.shapeOverlapKeeper.set(si.id, sj.id);
- world.bodyOverlapKeeper.set(bi.id, bj.id);
- }
- }
- }
- }
- }
- }
- sphereSphere(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- if (justTest) {
- return xi.distanceSquared(xj) < (si.radius + sj.radius) ** 2;
- }
- const contactEq = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- xj.vsub(xi, contactEq.ni);
- contactEq.ni.normalize();
- contactEq.ri.copy(contactEq.ni);
- contactEq.rj.copy(contactEq.ni);
- contactEq.ri.scale(si.radius, contactEq.ri);
- contactEq.rj.scale(-sj.radius, contactEq.rj);
- contactEq.ri.vadd(xi, contactEq.ri);
- contactEq.ri.vsub(bi.position, contactEq.ri);
- contactEq.rj.vadd(xj, contactEq.rj);
- contactEq.rj.vsub(bj.position, contactEq.rj);
- this.result.push(contactEq);
- this.createFrictionEquationsFromContact(contactEq, this.frictionResult);
- }
- spherePlane(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
-
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- r.ni.set(0, 0, 1);
- qj.vmult(r.ni, r.ni);
- r.ni.negate(r.ni);
- r.ni.normalize();
-
- r.ni.scale(si.radius, r.ri);
- xi.vsub(xj, point_on_plane_to_sphere);
- r.ni.scale(r.ni.dot(point_on_plane_to_sphere), plane_to_sphere_ortho);
- point_on_plane_to_sphere.vsub(plane_to_sphere_ortho, r.rj);
- if (-point_on_plane_to_sphere.dot(r.ni) <= si.radius) {
- if (justTest) {
- return true;
- }
- const ri = r.ri;
- const rj = r.rj;
- ri.vadd(xi, ri);
- ri.vsub(bi.position, ri);
- rj.vadd(xj, rj);
- rj.vsub(bj.position, rj);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- boxBox(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- si.convexPolyhedronRepresentation.material = si.material;
- sj.convexPolyhedronRepresentation.material = sj.material;
- si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
- sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
- return this.convexConvex(si.convexPolyhedronRepresentation, sj.convexPolyhedronRepresentation, xi, xj, qi, qj, bi, bj, si, sj, justTest);
- }
- sphereBox(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- const v3pool = this.v3pool;
- const sides = sphereBox_sides;
- xi.vsub(xj, box_to_sphere);
- sj.getSideNormals(sides, qj);
- const R = si.radius;
- let found = false;
- const side_ns = sphereBox_side_ns;
- const side_ns1 = sphereBox_side_ns1;
- const side_ns2 = sphereBox_side_ns2;
- let side_h = null;
- let side_penetrations = 0;
- let side_dot1 = 0;
- let side_dot2 = 0;
- let side_distance = null;
- for (let idx = 0, nsides = sides.length; idx !== nsides && found === false; idx++) {
-
- const ns = sphereBox_ns;
- ns.copy(sides[idx]);
- const h = ns.length();
- ns.normalize();
- const dot = box_to_sphere.dot(ns);
- if (dot < h + R && dot > 0) {
-
- const ns1 = sphereBox_ns1;
- const ns2 = sphereBox_ns2;
- ns1.copy(sides[(idx + 1) % 3]);
- ns2.copy(sides[(idx + 2) % 3]);
- const h1 = ns1.length();
- const h2 = ns2.length();
- ns1.normalize();
- ns2.normalize();
- const dot1 = box_to_sphere.dot(ns1);
- const dot2 = box_to_sphere.dot(ns2);
- if (dot1 < h1 && dot1 > -h1 && dot2 < h2 && dot2 > -h2) {
- const dist = Math.abs(dot - h - R);
- if (side_distance === null || dist < side_distance) {
- side_distance = dist;
- side_dot1 = dot1;
- side_dot2 = dot2;
- side_h = h;
- side_ns.copy(ns);
- side_ns1.copy(ns1);
- side_ns2.copy(ns2);
- side_penetrations++;
- if (justTest) {
- return true;
- }
- }
- }
- }
- }
- if (side_penetrations) {
- found = true;
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- side_ns.scale(-R, r.ri);
- r.ni.copy(side_ns);
- r.ni.negate(r.ni);
- side_ns.scale(side_h, side_ns);
- side_ns1.scale(side_dot1, side_ns1);
- side_ns.vadd(side_ns1, side_ns);
- side_ns2.scale(side_dot2, side_ns2);
- side_ns.vadd(side_ns2, r.rj);
- r.ri.vadd(xi, r.ri);
- r.ri.vsub(bi.position, r.ri);
- r.rj.vadd(xj, r.rj);
- r.rj.vsub(bj.position, r.rj);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- let rj = v3pool.get();
- const sphere_to_corner = sphereBox_sphere_to_corner;
- for (let j = 0; j !== 2 && !found; j++) {
- for (let k = 0; k !== 2 && !found; k++) {
- for (let l = 0; l !== 2 && !found; l++) {
- rj.set(0, 0, 0);
- if (j) {
- rj.vadd(sides[0], rj);
- } else {
- rj.vsub(sides[0], rj);
- }
- if (k) {
- rj.vadd(sides[1], rj);
- } else {
- rj.vsub(sides[1], rj);
- }
- if (l) {
- rj.vadd(sides[2], rj);
- } else {
- rj.vsub(sides[2], rj);
- }
- xj.vadd(rj, sphere_to_corner);
- sphere_to_corner.vsub(xi, sphere_to_corner);
- if (sphere_to_corner.lengthSquared() < R * R) {
- if (justTest) {
- return true;
- }
- found = true;
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- r.ri.copy(sphere_to_corner);
- r.ri.normalize();
- r.ni.copy(r.ri);
- r.ri.scale(R, r.ri);
- r.rj.copy(rj);
- r.ri.vadd(xi, r.ri);
- r.ri.vsub(bi.position, r.ri);
- r.rj.vadd(xj, r.rj);
- r.rj.vsub(bj.position, r.rj);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- }
- }
- v3pool.release(rj);
- rj = null;
- const edgeTangent = v3pool.get();
- const edgeCenter = v3pool.get();
- const r = v3pool.get();
- const orthogonal = v3pool.get();
- const dist = v3pool.get();
- const Nsides = sides.length;
- for (let j = 0; j !== Nsides && !found; j++) {
- for (let k = 0; k !== Nsides && !found; k++) {
- if (j % 3 !== k % 3) {
-
- sides[k].cross(sides[j], edgeTangent);
- edgeTangent.normalize();
- sides[j].vadd(sides[k], edgeCenter);
- r.copy(xi);
- r.vsub(edgeCenter, r);
- r.vsub(xj, r);
- const orthonorm = r.dot(edgeTangent);
- edgeTangent.scale(orthonorm, orthogonal);
-
- let l = 0;
- while (l === j % 3 || l === k % 3) {
- l++;
- }
- dist.copy(xi);
- dist.vsub(orthogonal, dist);
- dist.vsub(edgeCenter, dist);
- dist.vsub(xj, dist);
- const tdist = Math.abs(orthonorm);
- const ndist = dist.length();
- if (tdist < sides[l].length() && ndist < R) {
- if (justTest) {
- return true;
- }
- found = true;
- const res = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- edgeCenter.vadd(orthogonal, res.rj);
- res.rj.copy(res.rj);
- dist.negate(res.ni);
- res.ni.normalize();
- res.ri.copy(res.rj);
- res.ri.vadd(xj, res.ri);
- res.ri.vsub(xi, res.ri);
- res.ri.normalize();
- res.ri.scale(R, res.ri);
- res.ri.vadd(xi, res.ri);
- res.ri.vsub(bi.position, res.ri);
- res.rj.vadd(xj, res.rj);
- res.rj.vsub(bj.position, res.rj);
- this.result.push(res);
- this.createFrictionEquationsFromContact(res, this.frictionResult);
- }
- }
- }
- }
- v3pool.release(edgeTangent, edgeCenter, r, orthogonal, dist);
- }
- planeBox(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- sj.convexPolyhedronRepresentation.material = sj.material;
- sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
- sj.convexPolyhedronRepresentation.id = sj.id;
- return this.planeConvex(si, sj.convexPolyhedronRepresentation, xi, xj, qi, qj, bi, bj, si, sj, justTest);
- }
- convexConvex(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest, faceListA, faceListB) {
- const sepAxis = convexConvex_sepAxis;
- if (xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius) {
- return;
- }
- if (si.findSeparatingAxis(sj, xi, qi, xj, qj, sepAxis, faceListA, faceListB)) {
- const res = [];
- const q = convexConvex_q;
- si.clipAgainstHull(xi, qi, sj, xj, qj, sepAxis, -100, 100, res);
- let numContacts = 0;
- for (let j = 0; j !== res.length; j++) {
- if (justTest) {
- return true;
- }
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- const ri = r.ri;
- const rj = r.rj;
- sepAxis.negate(r.ni);
- res[j].normal.negate(q);
- q.scale(res[j].depth, q);
- res[j].point.vadd(q, ri);
- rj.copy(res[j].point);
- ri.vsub(xi, ri);
- rj.vsub(xj, rj);
- ri.vadd(xi, ri);
- ri.vsub(bi.position, ri);
- rj.vadd(xj, rj);
- rj.vsub(bj.position, rj);
- this.result.push(r);
- numContacts++;
- if (!this.enableFrictionReduction) {
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- if (this.enableFrictionReduction && numContacts) {
- this.createFrictionFromAverage(numContacts);
- }
- }
- }
- sphereConvex(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- const v3pool = this.v3pool;
- xi.vsub(xj, convex_to_sphere);
- const normals = sj.faceNormals;
- const faces = sj.faces;
- const verts = sj.vertices;
- const R = si.radius;
-
-
- let found = false;
- for (let i = 0; i !== verts.length; i++) {
- const v = verts[i];
- const worldCorner = sphereConvex_worldCorner;
- qj.vmult(v, worldCorner);
- xj.vadd(worldCorner, worldCorner);
- const sphere_to_corner = sphereConvex_sphereToCorner;
- worldCorner.vsub(xi, sphere_to_corner);
- if (sphere_to_corner.lengthSquared() < R * R) {
- if (justTest) {
- return true;
- }
- found = true;
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- r.ri.copy(sphere_to_corner);
- r.ri.normalize();
- r.ni.copy(r.ri);
- r.ri.scale(R, r.ri);
- worldCorner.vsub(xj, r.rj);
- r.ri.vadd(xi, r.ri);
- r.ri.vsub(bi.position, r.ri);
- r.rj.vadd(xj, r.rj);
- r.rj.vsub(bj.position, r.rj);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- return;
- }
- }
- for (let i = 0, nfaces = faces.length; i !== nfaces && found === false; i++) {
- const normal = normals[i];
- const face = faces[i];
- const worldNormal = sphereConvex_worldNormal;
- qj.vmult(normal, worldNormal);
- const worldPoint = sphereConvex_worldPoint;
- qj.vmult(verts[face[0]], worldPoint);
- worldPoint.vadd(xj, worldPoint);
- const worldSpherePointClosestToPlane = sphereConvex_worldSpherePointClosestToPlane;
- worldNormal.scale(-R, worldSpherePointClosestToPlane);
- xi.vadd(worldSpherePointClosestToPlane, worldSpherePointClosestToPlane);
- const penetrationVec = sphereConvex_penetrationVec;
- worldSpherePointClosestToPlane.vsub(worldPoint, penetrationVec);
- const penetration = penetrationVec.dot(worldNormal);
- const worldPointToSphere = sphereConvex_sphereToWorldPoint;
- xi.vsub(worldPoint, worldPointToSphere);
- if (penetration < 0 && worldPointToSphere.dot(worldNormal) > 0) {
-
- const faceVerts = [];
- for (let j = 0, Nverts = face.length; j !== Nverts; j++) {
- const worldVertex = v3pool.get();
- qj.vmult(verts[face[j]], worldVertex);
- xj.vadd(worldVertex, worldVertex);
- faceVerts.push(worldVertex);
- }
- if (pointInPolygon(faceVerts, worldNormal, xi)) {
-
- if (justTest) {
- return true;
- }
- found = true;
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- worldNormal.scale(-R, r.ri);
- worldNormal.negate(r.ni);
- const penetrationVec2 = v3pool.get();
- worldNormal.scale(-penetration, penetrationVec2);
- const penetrationSpherePoint = v3pool.get();
- worldNormal.scale(-R, penetrationSpherePoint);
- xi.vsub(xj, r.rj);
- r.rj.vadd(penetrationSpherePoint, r.rj);
- r.rj.vadd(penetrationVec2, r.rj);
- r.rj.vadd(xj, r.rj);
- r.rj.vsub(bj.position, r.rj);
- r.ri.vadd(xi, r.ri);
- r.ri.vsub(bi.position, r.ri);
- v3pool.release(penetrationVec2);
- v3pool.release(penetrationSpherePoint);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- for (let j = 0, Nfaceverts = faceVerts.length; j !== Nfaceverts; j++) {
- v3pool.release(faceVerts[j]);
- }
- return;
- } else {
-
- for (let j = 0; j !== face.length; j++) {
-
- const v1 = v3pool.get();
- const v2 = v3pool.get();
- qj.vmult(verts[face[(j + 1) % face.length]], v1);
- qj.vmult(verts[face[(j + 2) % face.length]], v2);
- xj.vadd(v1, v1);
- xj.vadd(v2, v2);
- const edge = sphereConvex_edge;
- v2.vsub(v1, edge);
- const edgeUnit = sphereConvex_edgeUnit;
- edge.unit(edgeUnit);
- const p = v3pool.get();
- const v1_to_xi = v3pool.get();
- xi.vsub(v1, v1_to_xi);
- const dot = v1_to_xi.dot(edgeUnit);
- edgeUnit.scale(dot, p);
- p.vadd(v1, p);
- const xi_to_p = v3pool.get();
- p.vsub(xi, xi_to_p);
-
- if (dot > 0 && dot * dot < edge.lengthSquared() && xi_to_p.lengthSquared() < R * R) {
-
-
- if (justTest) {
- return true;
- }
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- p.vsub(xj, r.rj);
- p.vsub(xi, r.ni);
- r.ni.normalize();
- r.ni.scale(R, r.ri);
- r.rj.vadd(xj, r.rj);
- r.rj.vsub(bj.position, r.rj);
- r.ri.vadd(xi, r.ri);
- r.ri.vsub(bi.position, r.ri);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- for (let j = 0, Nfaceverts = faceVerts.length; j !== Nfaceverts; j++) {
- v3pool.release(faceVerts[j]);
- }
- v3pool.release(v1);
- v3pool.release(v2);
- v3pool.release(p);
- v3pool.release(xi_to_p);
- v3pool.release(v1_to_xi);
- return;
- }
- v3pool.release(v1);
- v3pool.release(v2);
- v3pool.release(p);
- v3pool.release(xi_to_p);
- v3pool.release(v1_to_xi);
- }
- }
- for (let j = 0, Nfaceverts = faceVerts.length; j !== Nfaceverts; j++) {
- v3pool.release(faceVerts[j]);
- }
- }
- }
- }
- planeConvex(planeShape, convexShape, planePosition, convexPosition, planeQuat, convexQuat, planeBody, convexBody, si, sj, justTest) {
-
- const worldVertex = planeConvex_v;
- const worldNormal = planeConvex_normal;
- worldNormal.set(0, 0, 1);
- planeQuat.vmult(worldNormal, worldNormal);
- let numContacts = 0;
- const relpos = planeConvex_relpos;
- for (let i = 0; i !== convexShape.vertices.length; i++) {
-
- worldVertex.copy(convexShape.vertices[i]);
- convexQuat.vmult(worldVertex, worldVertex);
- convexPosition.vadd(worldVertex, worldVertex);
- worldVertex.vsub(planePosition, relpos);
- const dot = worldNormal.dot(relpos);
- if (dot <= 0.0) {
- if (justTest) {
- return true;
- }
- const r = this.createContactEquation(planeBody, convexBody, planeShape, convexShape, si, sj);
- const projected = planeConvex_projected;
- worldNormal.scale(worldNormal.dot(relpos), projected);
- worldVertex.vsub(projected, projected);
- projected.vsub(planePosition, r.ri);
- r.ni.copy(worldNormal);
-
- worldVertex.vsub(convexPosition, r.rj);
- r.ri.vadd(planePosition, r.ri);
- r.ri.vsub(planeBody.position, r.ri);
- r.rj.vadd(convexPosition, r.rj);
- r.rj.vsub(convexBody.position, r.rj);
- this.result.push(r);
- numContacts++;
- if (!this.enableFrictionReduction) {
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- }
- if (this.enableFrictionReduction && numContacts) {
- this.createFrictionFromAverage(numContacts);
- }
- }
- boxConvex(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- si.convexPolyhedronRepresentation.material = si.material;
- si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
- return this.convexConvex(si.convexPolyhedronRepresentation, sj, xi, xj, qi, qj, bi, bj, si, sj, justTest);
- }
- sphereHeightfield(sphereShape, hfShape, spherePos, hfPos, sphereQuat, hfQuat, sphereBody, hfBody, rsi, rsj, justTest) {
- const data = hfShape.data;
- const radius = sphereShape.radius;
- const w = hfShape.elementSize;
- const worldPillarOffset = sphereHeightfield_tmp2;
- const localSpherePos = sphereHeightfield_tmp1;
- Transform.pointToLocalFrame(hfPos, hfQuat, spherePos, localSpherePos);
- let iMinX = Math.floor((localSpherePos.x - radius) / w) - 1;
- let iMaxX = Math.ceil((localSpherePos.x + radius) / w) + 1;
- let iMinY = Math.floor((localSpherePos.y - radius) / w) - 1;
- let iMaxY = Math.ceil((localSpherePos.y + radius) / w) + 1;
- if (iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMinY > data[0].length) {
- return;
- }
- if (iMinX < 0) {
- iMinX = 0;
- }
- if (iMaxX < 0) {
- iMaxX = 0;
- }
- if (iMinY < 0) {
- iMinY = 0;
- }
- if (iMaxY < 0) {
- iMaxY = 0;
- }
- if (iMinX >= data.length) {
- iMinX = data.length - 1;
- }
- if (iMaxX >= data.length) {
- iMaxX = data.length - 1;
- }
- if (iMaxY >= data[0].length) {
- iMaxY = data[0].length - 1;
- }
- if (iMinY >= data[0].length) {
- iMinY = data[0].length - 1;
- }
- const minMax = [];
- hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
- const min = minMax[0];
- const max = minMax[1];
- if (localSpherePos.z - radius > max || localSpherePos.z + radius < min) {
- return;
- }
- const result = this.result;
- for (let i = iMinX; i < iMaxX; i++) {
- for (let j = iMinY; j < iMaxY; j++) {
- const numContactsBefore = result.length;
- let intersecting = false;
- hfShape.getConvexTrianglePillar(i, j, false);
- Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
- if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
- intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
- }
- if (justTest && intersecting) {
- return true;
- }
- hfShape.getConvexTrianglePillar(i, j, true);
- Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
- if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
- intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
- }
- if (justTest && intersecting) {
- return true;
- }
- const numContacts = result.length - numContactsBefore;
- if (numContacts > 2) {
- return;
- }
-
- }
- }
- }
- boxHeightfield(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- si.convexPolyhedronRepresentation.material = si.material;
- si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
- return this.convexHeightfield(si.convexPolyhedronRepresentation, sj, xi, xj, qi, qj, bi, bj, si, sj, justTest);
- }
- convexHeightfield(convexShape, hfShape, convexPos, hfPos, convexQuat, hfQuat, convexBody, hfBody, rsi, rsj, justTest) {
- const data = hfShape.data;
- const w = hfShape.elementSize;
- const radius = convexShape.boundingSphereRadius;
- const worldPillarOffset = convexHeightfield_tmp2;
- const faceList = convexHeightfield_faceList;
- const localConvexPos = convexHeightfield_tmp1;
- Transform.pointToLocalFrame(hfPos, hfQuat, convexPos, localConvexPos);
- let iMinX = Math.floor((localConvexPos.x - radius) / w) - 1;
- let iMaxX = Math.ceil((localConvexPos.x + radius) / w) + 1;
- let iMinY = Math.floor((localConvexPos.y - radius) / w) - 1;
- let iMaxY = Math.ceil((localConvexPos.y + radius) / w) + 1;
- if (iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMinY > data[0].length) {
- return;
- }
- if (iMinX < 0) {
- iMinX = 0;
- }
- if (iMaxX < 0) {
- iMaxX = 0;
- }
- if (iMinY < 0) {
- iMinY = 0;
- }
- if (iMaxY < 0) {
- iMaxY = 0;
- }
- if (iMinX >= data.length) {
- iMinX = data.length - 1;
- }
- if (iMaxX >= data.length) {
- iMaxX = data.length - 1;
- }
- if (iMaxY >= data[0].length) {
- iMaxY = data[0].length - 1;
- }
- if (iMinY >= data[0].length) {
- iMinY = data[0].length - 1;
- }
- const minMax = [];
- hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
- const min = minMax[0];
- const max = minMax[1];
- if (localConvexPos.z - radius > max || localConvexPos.z + radius < min) {
- return;
- }
- for (let i = iMinX; i < iMaxX; i++) {
- for (let j = iMinY; j < iMaxY; j++) {
- let intersecting = false;
- hfShape.getConvexTrianglePillar(i, j, false);
- Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
- if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
- intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
- }
- if (justTest && intersecting) {
- return true;
- }
- hfShape.getConvexTrianglePillar(i, j, true);
- Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
- if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
- intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
- }
- if (justTest && intersecting) {
- return true;
- }
- }
- }
- }
- sphereParticle(sj, si, xj, xi, qj, qi, bj, bi, rsi, rsj, justTest) {
-
- const normal = particleSphere_normal;
- normal.set(0, 0, 1);
- xi.vsub(xj, normal);
- const lengthSquared = normal.lengthSquared();
- if (lengthSquared <= sj.radius * sj.radius) {
- if (justTest) {
- return true;
- }
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- normal.normalize();
- r.rj.copy(normal);
- r.rj.scale(sj.radius, r.rj);
- r.ni.copy(normal);
- r.ni.negate(r.ni);
- r.ri.set(0, 0, 0);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- planeParticle(sj, si, xj, xi, qj, qi, bj, bi, rsi, rsj, justTest) {
- const normal = particlePlane_normal;
- normal.set(0, 0, 1);
- bj.quaternion.vmult(normal, normal);
- const relpos = particlePlane_relpos;
- xi.vsub(bj.position, relpos);
- const dot = normal.dot(relpos);
- if (dot <= 0.0) {
- if (justTest) {
- return true;
- }
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- r.ni.copy(normal);
- r.ni.negate(r.ni);
- r.ri.set(0, 0, 0);
-
- const projected = particlePlane_projected;
- normal.scale(normal.dot(xi), projected);
- xi.vsub(projected, projected);
-
- r.rj.copy(projected);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- boxParticle(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- si.convexPolyhedronRepresentation.material = si.material;
- si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
- return this.convexParticle(si.convexPolyhedronRepresentation, sj, xi, xj, qi, qj, bi, bj, si, sj, justTest);
- }
- convexParticle(sj, si, xj, xi, qj, qi, bj, bi, rsi, rsj, justTest) {
- let penetratedFaceIndex = -1;
- const penetratedFaceNormal = convexParticle_penetratedFaceNormal;
- const worldPenetrationVec = convexParticle_worldPenetrationVec;
- let minPenetration = null;
- const local = convexParticle_local;
- local.copy(xi);
- local.vsub(xj, local);
- qj.conjugate(cqj);
- cqj.vmult(local, local);
- if (sj.pointIsInside(local)) {
- if (sj.worldVerticesNeedsUpdate) {
- sj.computeWorldVertices(xj, qj);
- }
- if (sj.worldFaceNormalsNeedsUpdate) {
- sj.computeWorldFaceNormals(qj);
- }
- for (let i = 0, nfaces = sj.faces.length; i !== nfaces; i++) {
-
- const verts = [sj.worldVertices[sj.faces[i][0]]];
- const normal = sj.worldFaceNormals[i];
- xi.vsub(verts[0], convexParticle_vertexToParticle);
- const penetration = -normal.dot(convexParticle_vertexToParticle);
- if (minPenetration === null || Math.abs(penetration) < Math.abs(minPenetration)) {
- if (justTest) {
- return true;
- }
- minPenetration = penetration;
- penetratedFaceIndex = i;
- penetratedFaceNormal.copy(normal);
- }
- }
- if (penetratedFaceIndex !== -1) {
-
- const r = this.createContactEquation(bi, bj, si, sj, rsi, rsj);
- penetratedFaceNormal.scale(minPenetration, worldPenetrationVec);
- worldPenetrationVec.vadd(xi, worldPenetrationVec);
- worldPenetrationVec.vsub(xj, worldPenetrationVec);
- r.rj.copy(worldPenetrationVec);
-
-
- penetratedFaceNormal.negate(r.ni);
- r.ri.set(0, 0, 0);
- const ri = r.ri;
- const rj = r.rj;
- ri.vadd(xi, ri);
- ri.vsub(bi.position, ri);
- rj.vadd(xj, rj);
- rj.vsub(bj.position, rj);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- } else {
- console.warn('Point found inside convex, but did not find penetrating face!');
- }
- }
- }
- heightfieldCylinder(hfShape, convexShape, hfPos, convexPos, hfQuat, convexQuat, hfBody, convexBody, rsi, rsj, justTest) {
- return this.convexHeightfield(convexShape, hfShape, convexPos, hfPos, convexQuat, hfQuat, convexBody, hfBody, rsi, rsj, justTest);
- }
- particleCylinder(si, sj, xi, xj, qi, qj, bi, bj, rsi, rsj, justTest) {
- return this.convexParticle(sj, si, xj, xi, qj, qi, bj, bi, rsi, rsj, justTest);
- }
- sphereTrimesh(sphereShape, trimeshShape, spherePos, trimeshPos, sphereQuat, trimeshQuat, sphereBody, trimeshBody, rsi, rsj, justTest) {
- const edgeVertexA = sphereTrimesh_edgeVertexA;
- const edgeVertexB = sphereTrimesh_edgeVertexB;
- const edgeVector = sphereTrimesh_edgeVector;
- const edgeVectorUnit = sphereTrimesh_edgeVectorUnit;
- const localSpherePos = sphereTrimesh_localSpherePos;
- const tmp = sphereTrimesh_tmp;
- const localSphereAABB = sphereTrimesh_localSphereAABB;
- const v2 = sphereTrimesh_v2;
- const relpos = sphereTrimesh_relpos;
- const triangles = sphereTrimesh_triangles;
- Transform.pointToLocalFrame(trimeshPos, trimeshQuat, spherePos, localSpherePos);
- const sphereRadius = sphereShape.radius;
- localSphereAABB.lowerBound.set(localSpherePos.x - sphereRadius, localSpherePos.y - sphereRadius, localSpherePos.z - sphereRadius);
- localSphereAABB.upperBound.set(localSpherePos.x + sphereRadius, localSpherePos.y + sphereRadius, localSpherePos.z + sphereRadius);
- trimeshShape.getTrianglesInAABB(localSphereAABB, triangles);
-
- const v = sphereTrimesh_v;
- const radiusSquared = sphereShape.radius * sphereShape.radius;
- for (let i = 0; i < triangles.length; i++) {
- for (let j = 0; j < 3; j++) {
- trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], v);
- v.vsub(localSpherePos, relpos);
- if (relpos.lengthSquared() <= radiusSquared) {
-
- v2.copy(v);
- Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
- v.vsub(spherePos, relpos);
- if (justTest) {
- return true;
- }
- let r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape, rsi, rsj);
- r.ni.copy(relpos);
- r.ni.normalize();
- r.ri.copy(r.ni);
- r.ri.scale(sphereShape.radius, r.ri);
- r.ri.vadd(spherePos, r.ri);
- r.ri.vsub(sphereBody.position, r.ri);
- r.rj.copy(v);
- r.rj.vsub(trimeshBody.position, r.rj);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- }
- for (let i = 0; i < triangles.length; i++) {
- for (let j = 0; j < 3; j++) {
- trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], edgeVertexA);
- trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + (j + 1) % 3], edgeVertexB);
- edgeVertexB.vsub(edgeVertexA, edgeVector);
- localSpherePos.vsub(edgeVertexB, tmp);
- const positionAlongEdgeB = tmp.dot(edgeVector);
- localSpherePos.vsub(edgeVertexA, tmp);
- let positionAlongEdgeA = tmp.dot(edgeVector);
- if (positionAlongEdgeA > 0 && positionAlongEdgeB < 0) {
-
- localSpherePos.vsub(edgeVertexA, tmp);
- edgeVectorUnit.copy(edgeVector);
- edgeVectorUnit.normalize();
- positionAlongEdgeA = tmp.dot(edgeVectorUnit);
- edgeVectorUnit.scale(positionAlongEdgeA, tmp);
- tmp.vadd(edgeVertexA, tmp);
- const dist = tmp.distanceTo(localSpherePos);
- if (dist < sphereShape.radius) {
- if (justTest) {
- return true;
- }
- const r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape, rsi, rsj);
- tmp.vsub(localSpherePos, r.ni);
- r.ni.normalize();
- r.ni.scale(sphereShape.radius, r.ri);
- r.ri.vadd(spherePos, r.ri);
- r.ri.vsub(sphereBody.position, r.ri);
- Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
- tmp.vsub(trimeshBody.position, r.rj);
- Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
- Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- }
- }
- const va = sphereTrimesh_va;
- const vb = sphereTrimesh_vb;
- const vc = sphereTrimesh_vc;
- const normal = sphereTrimesh_normal;
- for (let i = 0, N = triangles.length; i !== N; i++) {
- trimeshShape.getTriangleVertices(triangles[i], va, vb, vc);
- trimeshShape.getNormal(triangles[i], normal);
- localSpherePos.vsub(va, tmp);
- let dist = tmp.dot(normal);
- normal.scale(dist, tmp);
- localSpherePos.vsub(tmp, tmp);
- dist = tmp.distanceTo(localSpherePos);
- if (Ray.pointInTriangle(tmp, va, vb, vc) && dist < sphereShape.radius) {
- if (justTest) {
- return true;
- }
- let r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape, rsi, rsj);
- tmp.vsub(localSpherePos, r.ni);
- r.ni.normalize();
- r.ni.scale(sphereShape.radius, r.ri);
- r.ri.vadd(spherePos, r.ri);
- r.ri.vsub(sphereBody.position, r.ri);
- Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
- tmp.vsub(trimeshBody.position, r.rj);
- Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
- Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- triangles.length = 0;
- }
- planeTrimesh(planeShape, trimeshShape, planePos, trimeshPos, planeQuat, trimeshQuat, planeBody, trimeshBody, rsi, rsj, justTest) {
-
- const v = new Vec3();
- const normal = planeTrimesh_normal;
- normal.set(0, 0, 1);
- planeQuat.vmult(normal, normal);
- for (let i = 0; i < trimeshShape.vertices.length / 3; i++) {
-
- trimeshShape.getVertex(i, v);
- const v2 = new Vec3();
- v2.copy(v);
- Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
- const relpos = planeTrimesh_relpos;
- v.vsub(planePos, relpos);
- const dot = normal.dot(relpos);
- if (dot <= 0.0) {
- if (justTest) {
- return true;
- }
- const r = this.createContactEquation(planeBody, trimeshBody, planeShape, trimeshShape, rsi, rsj);
- r.ni.copy(normal);
-
- const projected = planeTrimesh_projected;
- normal.scale(relpos.dot(normal), projected);
- v.vsub(projected, projected);
- r.ri.copy(projected);
- r.ri.vsub(planeBody.position, r.ri);
- r.rj.copy(v);
- r.rj.vsub(trimeshBody.position, r.rj);
- this.result.push(r);
- this.createFrictionEquationsFromContact(r, this.frictionResult);
- }
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- const averageNormal = new Vec3();
- const averageContactPointA = new Vec3();
- const averageContactPointB = new Vec3();
- const tmpVec1 = new Vec3();
- const tmpVec2 = new Vec3();
- const tmpQuat1 = new Quaternion();
- const tmpQuat2 = new Quaternion();
- const planeTrimesh_normal = new Vec3();
- const planeTrimesh_relpos = new Vec3();
- const planeTrimesh_projected = new Vec3();
- const sphereTrimesh_normal = new Vec3();
- const sphereTrimesh_relpos = new Vec3();
- new Vec3();
- const sphereTrimesh_v = new Vec3();
- const sphereTrimesh_v2 = new Vec3();
- const sphereTrimesh_edgeVertexA = new Vec3();
- const sphereTrimesh_edgeVertexB = new Vec3();
- const sphereTrimesh_edgeVector = new Vec3();
- const sphereTrimesh_edgeVectorUnit = new Vec3();
- const sphereTrimesh_localSpherePos = new Vec3();
- const sphereTrimesh_tmp = new Vec3();
- const sphereTrimesh_va = new Vec3();
- const sphereTrimesh_vb = new Vec3();
- const sphereTrimesh_vc = new Vec3();
- const sphereTrimesh_localSphereAABB = new AABB();
- const sphereTrimesh_triangles = [];
- const point_on_plane_to_sphere = new Vec3();
- const plane_to_sphere_ortho = new Vec3();
- const pointInPolygon_edge = new Vec3();
- const pointInPolygon_edge_x_normal = new Vec3();
- const pointInPolygon_vtp = new Vec3();
- function pointInPolygon(verts, normal, p) {
- let positiveResult = null;
- const N = verts.length;
- for (let i = 0; i !== N; i++) {
- const v = verts[i];
- const edge = pointInPolygon_edge;
- verts[(i + 1) % N].vsub(v, edge);
- const edge_x_normal = pointInPolygon_edge_x_normal;
- edge.cross(normal, edge_x_normal);
- const vertex_to_p = pointInPolygon_vtp;
- p.vsub(v, vertex_to_p);
- const r = edge_x_normal.dot(vertex_to_p);
- if (positiveResult === null || r > 0 && positiveResult === true || r <= 0 && positiveResult === false) {
- if (positiveResult === null) {
- positiveResult = r > 0;
- }
- continue;
- } else {
- return false;
- }
- }
- return true;
- }
- const box_to_sphere = new Vec3();
- const sphereBox_ns = new Vec3();
- const sphereBox_ns1 = new Vec3();
- const sphereBox_ns2 = new Vec3();
- const sphereBox_sides = [new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3()];
- const sphereBox_sphere_to_corner = new Vec3();
- const sphereBox_side_ns = new Vec3();
- const sphereBox_side_ns1 = new Vec3();
- const sphereBox_side_ns2 = new Vec3();
- const convex_to_sphere = new Vec3();
- const sphereConvex_edge = new Vec3();
- const sphereConvex_edgeUnit = new Vec3();
- const sphereConvex_sphereToCorner = new Vec3();
- const sphereConvex_worldCorner = new Vec3();
- const sphereConvex_worldNormal = new Vec3();
- const sphereConvex_worldPoint = new Vec3();
- const sphereConvex_worldSpherePointClosestToPlane = new Vec3();
- const sphereConvex_penetrationVec = new Vec3();
- const sphereConvex_sphereToWorldPoint = new Vec3();
- new Vec3();
- new Vec3();
- const planeConvex_v = new Vec3();
- const planeConvex_normal = new Vec3();
- const planeConvex_relpos = new Vec3();
- const planeConvex_projected = new Vec3();
- const convexConvex_sepAxis = new Vec3();
- const convexConvex_q = new Vec3();
- const particlePlane_normal = new Vec3();
- const particlePlane_relpos = new Vec3();
- const particlePlane_projected = new Vec3();
- const particleSphere_normal = new Vec3();
- const cqj = new Quaternion();
- const convexParticle_local = new Vec3();
- new Vec3();
- const convexParticle_penetratedFaceNormal = new Vec3();
- const convexParticle_vertexToParticle = new Vec3();
- const convexParticle_worldPenetrationVec = new Vec3();
- const convexHeightfield_tmp1 = new Vec3();
- const convexHeightfield_tmp2 = new Vec3();
- const convexHeightfield_faceList = [0];
- const sphereHeightfield_tmp1 = new Vec3();
- const sphereHeightfield_tmp2 = new Vec3();
- class OverlapKeeper {
-
- constructor() {
- this.current = [];
- this.previous = [];
- }
-
- getKey(i, j) {
- if (j < i) {
- const temp = j;
- j = i;
- i = temp;
- }
- return i << 16 | j;
- }
-
- set(i, j) {
-
- const key = this.getKey(i, j);
- const current = this.current;
- let index = 0;
- while (key > current[index]) {
- index++;
- }
- if (key === current[index]) {
- return;
- }
- for (let j = current.length - 1; j >= index; j--) {
- current[j + 1] = current[j];
- }
- current[index] = key;
- }
-
- tick() {
- const tmp = this.current;
- this.current = this.previous;
- this.previous = tmp;
- this.current.length = 0;
- }
-
- getDiff(additions, removals) {
- const a = this.current;
- const b = this.previous;
- const al = a.length;
- const bl = b.length;
- let j = 0;
- for (let i = 0; i < al; i++) {
- let found = false;
- const keyA = a[i];
- while (keyA > b[j]) {
- j++;
- }
- found = keyA === b[j];
- if (!found) {
- unpackAndPush(additions, keyA);
- }
- }
- j = 0;
- for (let i = 0; i < bl; i++) {
- let found = false;
- const keyB = b[i];
- while (keyB > a[j]) {
- j++;
- }
- found = a[j] === keyB;
- if (!found) {
- unpackAndPush(removals, keyB);
- }
- }
- }
- }
- function unpackAndPush(array, key) {
- array.push((key & 0xffff0000) >> 16, key & 0x0000ffff);
- }
- const getKey = (i, j) => i < j ? `${i}-${j}` : `${j}-${i}`;
- class TupleDictionary {
- constructor() {
- this.data = {
- keys: []
- };
- }
-
- get(i, j) {
- const key = getKey(i, j);
- return this.data[key];
- }
-
- set(i, j, value) {
- const key = getKey(i, j);
- if (!this.get(i, j)) {
- this.data.keys.push(key);
- }
- this.data[key] = value;
- }
-
- delete(i, j) {
- const key = getKey(i, j);
- const index = this.data.keys.indexOf(key);
- if (index !== -1) {
- this.data.keys.splice(index, 1);
- }
- delete this.data[key];
- }
-
- reset() {
- const data = this.data;
- const keys = data.keys;
- while (keys.length > 0) {
- const key = keys.pop();
- delete data[key];
- }
- }
- }
- class World extends EventTarget {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- constructor(options) {
- if (options === void 0) {
- options = {};
- }
- super();
- this.dt = -1;
- this.allowSleep = !!options.allowSleep;
- this.contacts = [];
- this.frictionEquations = [];
- this.quatNormalizeSkip = options.quatNormalizeSkip !== undefined ? options.quatNormalizeSkip : 0;
- this.quatNormalizeFast = options.quatNormalizeFast !== undefined ? options.quatNormalizeFast : false;
- this.time = 0.0;
- this.stepnumber = 0;
- this.default_dt = 1 / 60;
- this.nextId = 0;
- this.gravity = new Vec3();
- if (options.gravity) {
- this.gravity.copy(options.gravity);
- }
- if (options.frictionGravity) {
- this.frictionGravity = new Vec3();
- this.frictionGravity.copy(options.frictionGravity);
- }
- this.broadphase = options.broadphase !== undefined ? options.broadphase : new NaiveBroadphase();
- this.bodies = [];
- this.hasActiveBodies = false;
- this.solver = options.solver !== undefined ? options.solver : new GSSolver();
- this.constraints = [];
- this.narrowphase = new Narrowphase(this);
- this.collisionMatrix = new ArrayCollisionMatrix();
- this.collisionMatrixPrevious = new ArrayCollisionMatrix();
- this.bodyOverlapKeeper = new OverlapKeeper();
- this.shapeOverlapKeeper = new OverlapKeeper();
- this.contactmaterials = [];
- this.contactMaterialTable = new TupleDictionary();
- this.defaultMaterial = new Material('default');
- this.defaultContactMaterial = new ContactMaterial(this.defaultMaterial, this.defaultMaterial, {
- friction: 0.3,
- restitution: 0.0
- });
- this.doProfiling = false;
- this.profile = {
- solve: 0,
- makeContactConstraints: 0,
- broadphase: 0,
- integrate: 0,
- narrowphase: 0
- };
- this.accumulator = 0;
- this.subsystems = [];
- this.addBodyEvent = {
- type: 'addBody',
- body: null
- };
- this.removeBodyEvent = {
- type: 'removeBody',
- body: null
- };
- this.idToBodyMap = {};
- this.broadphase.setWorld(this);
- }
-
- getContactMaterial(m1, m2) {
- return this.contactMaterialTable.get(m1.id, m2.id);
- }
-
- collisionMatrixTick() {
- const temp = this.collisionMatrixPrevious;
- this.collisionMatrixPrevious = this.collisionMatrix;
- this.collisionMatrix = temp;
- this.collisionMatrix.reset();
- this.bodyOverlapKeeper.tick();
- this.shapeOverlapKeeper.tick();
- }
-
- addConstraint(c) {
- this.constraints.push(c);
- }
-
- removeConstraint(c) {
- const idx = this.constraints.indexOf(c);
- if (idx !== -1) {
- this.constraints.splice(idx, 1);
- }
- }
-
- rayTest(from, to, result) {
- if (result instanceof RaycastResult) {
-
- this.raycastClosest(from, to, {
- skipBackfaces: true
- }, result);
- } else {
-
- this.raycastAll(from, to, {
- skipBackfaces: true
- }, result);
- }
- }
-
- raycastAll(from, to, options, callback) {
- if (options === void 0) {
- options = {};
- }
- options.mode = Ray.ALL;
- options.from = from;
- options.to = to;
- options.callback = callback;
- return tmpRay.intersectWorld(this, options);
- }
-
- raycastAny(from, to, options, result) {
- if (options === void 0) {
- options = {};
- }
- options.mode = Ray.ANY;
- options.from = from;
- options.to = to;
- options.result = result;
- return tmpRay.intersectWorld(this, options);
- }
-
- raycastClosest(from, to, options, result) {
- if (options === void 0) {
- options = {};
- }
- options.mode = Ray.CLOSEST;
- options.from = from;
- options.to = to;
- options.result = result;
- return tmpRay.intersectWorld(this, options);
- }
-
- addBody(body) {
- if (this.bodies.includes(body)) {
- return;
- }
- body.index = this.bodies.length;
- this.bodies.push(body);
- body.world = this;
- body.initPosition.copy(body.position);
- body.initVelocity.copy(body.velocity);
- body.timeLastSleepy = this.time;
- if (body instanceof Body) {
- body.initAngularVelocity.copy(body.angularVelocity);
- body.initQuaternion.copy(body.quaternion);
- }
- this.collisionMatrix.setNumObjects(this.bodies.length);
- this.addBodyEvent.body = body;
- this.idToBodyMap[body.id] = body;
- this.dispatchEvent(this.addBodyEvent);
- }
-
- removeBody(body) {
- body.world = null;
- const n = this.bodies.length - 1;
- const bodies = this.bodies;
- const idx = bodies.indexOf(body);
- if (idx !== -1) {
- bodies.splice(idx, 1);
-
- for (let i = 0; i !== bodies.length; i++) {
- bodies[i].index = i;
- }
- this.collisionMatrix.setNumObjects(n);
- this.removeBodyEvent.body = body;
- delete this.idToBodyMap[body.id];
- this.dispatchEvent(this.removeBodyEvent);
- }
- }
- getBodyById(id) {
- return this.idToBodyMap[id];
- }
-
- getShapeById(id) {
- const bodies = this.bodies;
- for (let i = 0; i < bodies.length; i++) {
- const shapes = bodies[i].shapes;
- for (let j = 0; j < shapes.length; j++) {
- const shape = shapes[j];
- if (shape.id === id) {
- return shape;
- }
- }
- }
- return null;
- }
-
- addContactMaterial(cmat) {
-
- this.contactmaterials.push(cmat);
- this.contactMaterialTable.set(cmat.materials[0].id, cmat.materials[1].id, cmat);
- }
-
- removeContactMaterial(cmat) {
- const idx = this.contactmaterials.indexOf(cmat);
- if (idx === -1) {
- return;
- }
- this.contactmaterials.splice(idx, 1);
- this.contactMaterialTable.delete(cmat.materials[0].id, cmat.materials[1].id);
- }
-
- fixedStep(dt, maxSubSteps) {
- if (dt === void 0) {
- dt = 1 / 60;
- }
- if (maxSubSteps === void 0) {
- maxSubSteps = 10;
- }
- const time = performance.now() / 1000;
- if (!this.lastCallTime) {
- this.step(dt, undefined, maxSubSteps);
- } else {
- const timeSinceLastCalled = time - this.lastCallTime;
- this.step(dt, timeSinceLastCalled, maxSubSteps);
- }
- this.lastCallTime = time;
- }
-
- step(dt, timeSinceLastCalled, maxSubSteps) {
- if (maxSubSteps === void 0) {
- maxSubSteps = 10;
- }
- if (timeSinceLastCalled === undefined) {
-
- this.internalStep(dt);
- this.time += dt;
- } else {
- this.accumulator += timeSinceLastCalled;
- const t0 = performance.now();
- let substeps = 0;
- while (this.accumulator >= dt && substeps < maxSubSteps) {
-
- this.internalStep(dt);
- this.accumulator -= dt;
- substeps++;
- if (performance.now() - t0 > dt * 1000) {
-
-
-
- break;
- }
- }
-
- this.accumulator = this.accumulator % dt;
- const t = this.accumulator / dt;
- for (let j = 0; j !== this.bodies.length; j++) {
- const b = this.bodies[j];
- b.previousPosition.lerp(b.position, t, b.interpolatedPosition);
- b.previousQuaternion.slerp(b.quaternion, t, b.interpolatedQuaternion);
- b.previousQuaternion.normalize();
- }
- this.time += timeSinceLastCalled;
- }
- }
- internalStep(dt) {
- this.dt = dt;
- const contacts = this.contacts;
- const p1 = World_step_p1;
- const p2 = World_step_p2;
- const N = this.bodies.length;
- const bodies = this.bodies;
- const solver = this.solver;
- const gravity = this.gravity;
- const doProfiling = this.doProfiling;
- const profile = this.profile;
- const DYNAMIC = Body.DYNAMIC;
- let profilingStart = -Infinity;
- const constraints = this.constraints;
- const frictionEquationPool = World_step_frictionEquationPool;
- gravity.length();
- const gx = gravity.x;
- const gy = gravity.y;
- const gz = gravity.z;
- let i = 0;
- if (doProfiling) {
- profilingStart = performance.now();
- }
- for (i = 0; i !== N; i++) {
- const bi = bodies[i];
- if (bi.type === DYNAMIC) {
-
- const f = bi.force;
- const m = bi.mass;
- f.x += m * gx;
- f.y += m * gy;
- f.z += m * gz;
- }
- }
- for (let i = 0, Nsubsystems = this.subsystems.length; i !== Nsubsystems; i++) {
- this.subsystems[i].update();
- }
- if (doProfiling) {
- profilingStart = performance.now();
- }
- p1.length = 0;
- p2.length = 0;
- this.broadphase.collisionPairs(this, p1, p2);
- if (doProfiling) {
- profile.broadphase = performance.now() - profilingStart;
- }
- let Nconstraints = constraints.length;
- for (i = 0; i !== Nconstraints; i++) {
- const c = constraints[i];
- if (!c.collideConnected) {
- for (let j = p1.length - 1; j >= 0; j -= 1) {
- if (c.bodyA === p1[j] && c.bodyB === p2[j] || c.bodyB === p1[j] && c.bodyA === p2[j]) {
- p1.splice(j, 1);
- p2.splice(j, 1);
- }
- }
- }
- }
- this.collisionMatrixTick();
- if (doProfiling) {
- profilingStart = performance.now();
- }
- const oldcontacts = World_step_oldContacts;
- const NoldContacts = contacts.length;
- for (i = 0; i !== NoldContacts; i++) {
- oldcontacts.push(contacts[i]);
- }
- contacts.length = 0;
- const NoldFrictionEquations = this.frictionEquations.length;
- for (i = 0; i !== NoldFrictionEquations; i++) {
- frictionEquationPool.push(this.frictionEquations[i]);
- }
- this.frictionEquations.length = 0;
- this.narrowphase.getContacts(p1, p2, this, contacts, oldcontacts,
- this.frictionEquations, frictionEquationPool);
- if (doProfiling) {
- profile.narrowphase = performance.now() - profilingStart;
- }
- if (doProfiling) {
- profilingStart = performance.now();
- }
- for (i = 0; i < this.frictionEquations.length; i++) {
- solver.addEquation(this.frictionEquations[i]);
- }
- const ncontacts = contacts.length;
- for (let k = 0; k !== ncontacts; k++) {
-
- const c = contacts[k];
- const bi = c.bi;
- const bj = c.bj;
- const si = c.si;
- const sj = c.sj;
- let cm;
- if (bi.material && bj.material) {
- cm = this.getContactMaterial(bi.material, bj.material) || this.defaultContactMaterial;
- } else {
- cm = this.defaultContactMaterial;
- }
- cm.friction;
-
- if (bi.material && bj.material) {
- if (bi.material.friction >= 0 && bj.material.friction >= 0) {
- bi.material.friction * bj.material.friction;
- }
- if (bi.material.restitution >= 0 && bj.material.restitution >= 0) {
- c.restitution = bi.material.restitution * bj.material.restitution;
- }
- }
-
-
-
-
- solver.addEquation(c);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (bi.allowSleep && bi.type === Body.DYNAMIC && bi.sleepState === Body.SLEEPING && bj.sleepState === Body.AWAKE && bj.type !== Body.STATIC) {
- const speedSquaredB = bj.velocity.lengthSquared() + bj.angularVelocity.lengthSquared();
- const speedLimitSquaredB = bj.sleepSpeedLimit ** 2;
- if (speedSquaredB >= speedLimitSquaredB * 2) {
- bi.wakeUpAfterNarrowphase = true;
- }
- }
- if (bj.allowSleep && bj.type === Body.DYNAMIC && bj.sleepState === Body.SLEEPING && bi.sleepState === Body.AWAKE && bi.type !== Body.STATIC) {
- const speedSquaredA = bi.velocity.lengthSquared() + bi.angularVelocity.lengthSquared();
- const speedLimitSquaredA = bi.sleepSpeedLimit ** 2;
- if (speedSquaredA >= speedLimitSquaredA * 2) {
- bj.wakeUpAfterNarrowphase = true;
- }
- }
- this.collisionMatrix.set(bi, bj, true);
- if (!this.collisionMatrixPrevious.get(bi, bj)) {
-
-
- World_step_collideEvent.body = bj;
- World_step_collideEvent.contact = c;
- bi.dispatchEvent(World_step_collideEvent);
- World_step_collideEvent.body = bi;
- bj.dispatchEvent(World_step_collideEvent);
- }
- this.bodyOverlapKeeper.set(bi.id, bj.id);
- this.shapeOverlapKeeper.set(si.id, sj.id);
- }
- this.emitContactEvents();
- if (doProfiling) {
- profile.makeContactConstraints = performance.now() - profilingStart;
- profilingStart = performance.now();
- }
- for (i = 0; i !== N; i++) {
- const bi = bodies[i];
- if (bi.wakeUpAfterNarrowphase) {
- bi.wakeUp();
- bi.wakeUpAfterNarrowphase = false;
- }
- }
- Nconstraints = constraints.length;
- for (i = 0; i !== Nconstraints; i++) {
- const c = constraints[i];
- c.update();
- for (let j = 0, Neq = c.equations.length; j !== Neq; j++) {
- const eq = c.equations[j];
- solver.addEquation(eq);
- }
- }
- solver.solve(dt, this);
- if (doProfiling) {
- profile.solve = performance.now() - profilingStart;
- }
- solver.removeAllEquations();
- const pow = Math.pow;
- for (i = 0; i !== N; i++) {
- const bi = bodies[i];
- if (bi.type & DYNAMIC) {
-
- const ld = pow(1.0 - bi.linearDamping, dt);
- const v = bi.velocity;
- v.scale(ld, v);
- const av = bi.angularVelocity;
- if (av) {
- const ad = pow(1.0 - bi.angularDamping, dt);
- av.scale(ad, av);
- }
- }
- }
- this.dispatchEvent(World_step_preStepEvent);
-
-
- if (doProfiling) {
- profilingStart = performance.now();
- }
- const stepnumber = this.stepnumber;
- const quatNormalize = stepnumber % (this.quatNormalizeSkip + 1) === 0;
- const quatNormalizeFast = this.quatNormalizeFast;
- for (i = 0; i !== N; i++) {
- bodies[i].integrate(dt, quatNormalize, quatNormalizeFast);
- }
- this.clearForces();
- this.broadphase.dirty = true;
- if (doProfiling) {
- profile.integrate = performance.now() - profilingStart;
- }
- this.stepnumber += 1;
- this.dispatchEvent(World_step_postStepEvent);
- let hasActiveBodies = true;
- if (this.allowSleep) {
- hasActiveBodies = false;
- for (i = 0; i !== N; i++) {
- const bi = bodies[i];
- bi.sleepTick(this.time);
- if (bi.sleepState !== Body.SLEEPING) {
- hasActiveBodies = true;
- }
- }
- }
- this.hasActiveBodies = hasActiveBodies;
- }
- emitContactEvents() {
- const hasBeginContact = this.hasAnyEventListener('beginContact');
- const hasEndContact = this.hasAnyEventListener('endContact');
- if (hasBeginContact || hasEndContact) {
- this.bodyOverlapKeeper.getDiff(additions, removals);
- }
- if (hasBeginContact) {
- for (let i = 0, l = additions.length; i < l; i += 2) {
- beginContactEvent.bodyA = this.getBodyById(additions[i]);
- beginContactEvent.bodyB = this.getBodyById(additions[i + 1]);
- this.dispatchEvent(beginContactEvent);
- }
- beginContactEvent.bodyA = beginContactEvent.bodyB = null;
- }
- if (hasEndContact) {
- for (let i = 0, l = removals.length; i < l; i += 2) {
- endContactEvent.bodyA = this.getBodyById(removals[i]);
- endContactEvent.bodyB = this.getBodyById(removals[i + 1]);
- this.dispatchEvent(endContactEvent);
- }
- endContactEvent.bodyA = endContactEvent.bodyB = null;
- }
- additions.length = removals.length = 0;
- const hasBeginShapeContact = this.hasAnyEventListener('beginShapeContact');
- const hasEndShapeContact = this.hasAnyEventListener('endShapeContact');
- if (hasBeginShapeContact || hasEndShapeContact) {
- this.shapeOverlapKeeper.getDiff(additions, removals);
- }
- if (hasBeginShapeContact) {
- for (let i = 0, l = additions.length; i < l; i += 2) {
- const shapeA = this.getShapeById(additions[i]);
- const shapeB = this.getShapeById(additions[i + 1]);
- beginShapeContactEvent.shapeA = shapeA;
- beginShapeContactEvent.shapeB = shapeB;
- if (shapeA) beginShapeContactEvent.bodyA = shapeA.body;
- if (shapeB) beginShapeContactEvent.bodyB = shapeB.body;
- this.dispatchEvent(beginShapeContactEvent);
- }
- beginShapeContactEvent.bodyA = beginShapeContactEvent.bodyB = beginShapeContactEvent.shapeA = beginShapeContactEvent.shapeB = null;
- }
- if (hasEndShapeContact) {
- for (let i = 0, l = removals.length; i < l; i += 2) {
- const shapeA = this.getShapeById(removals[i]);
- const shapeB = this.getShapeById(removals[i + 1]);
- endShapeContactEvent.shapeA = shapeA;
- endShapeContactEvent.shapeB = shapeB;
- if (shapeA) endShapeContactEvent.bodyA = shapeA.body;
- if (shapeB) endShapeContactEvent.bodyB = shapeB.body;
- this.dispatchEvent(endShapeContactEvent);
- }
- endShapeContactEvent.bodyA = endShapeContactEvent.bodyB = endShapeContactEvent.shapeA = endShapeContactEvent.shapeB = null;
- }
- }
-
- clearForces() {
- const bodies = this.bodies;
- const N = bodies.length;
- for (let i = 0; i !== N; i++) {
- const b = bodies[i];
- b.force;
- b.torque;
- b.force.set(0, 0, 0);
- b.torque.set(0, 0, 0);
- }
- }
- }
- new AABB();
- const tmpRay = new Ray();
- const performance = globalThis.performance || {};
- if (!performance.now) {
- let nowOffset = Date.now();
- if (performance.timing && performance.timing.navigationStart) {
- nowOffset = performance.timing.navigationStart;
- }
- performance.now = () => Date.now() - nowOffset;
- }
- new Vec3();
- const World_step_postStepEvent = {
- type: 'postStep'
- };
- const World_step_preStepEvent = {
- type: 'preStep'
- };
- const World_step_collideEvent = {
- type: Body.COLLIDE_EVENT_NAME,
- body: null,
- contact: null
- };
- const World_step_oldContacts = [];
- const World_step_frictionEquationPool = [];
- const World_step_p1 = [];
- const World_step_p2 = [];
- const additions = [];
- const removals = [];
- const beginContactEvent = {
- type: 'beginContact',
- bodyA: null,
- bodyB: null
- };
- const endContactEvent = {
- type: 'endContact',
- bodyA: null,
- bodyB: null
- };
- const beginShapeContactEvent = {
- type: 'beginShapeContact',
- bodyA: null,
- bodyB: null,
- shapeA: null,
- shapeB: null
- };
- const endShapeContactEvent = {
- type: 'endShapeContact',
- bodyA: null,
- bodyB: null,
- shapeA: null,
- shapeB: null
- };
- export { AABB, ArrayCollisionMatrix, BODY_SLEEP_STATES, BODY_TYPES, Body, Box, Broadphase, COLLISION_TYPES, ConeTwistConstraint, Constraint, ContactEquation, ContactMaterial, ConvexPolyhedron, Cylinder, DistanceConstraint, Equation, EventTarget, FrictionEquation, GSSolver, GridBroadphase, Heightfield, HingeConstraint, JacobianElement, LockConstraint, Mat3, Material, NaiveBroadphase, Narrowphase, ObjectCollisionMatrix, Particle, Plane, PointToPointConstraint, Pool, Quaternion, RAY_MODES, Ray, RaycastResult, RaycastVehicle, RigidVehicle, RotationalEquation, RotationalMotorEquation, SAPBroadphase, SHAPE_TYPES, SPHSystem, Shape, Solver, Sphere, SplitSolver, Spring, Transform, Trimesh, Vec3, Vec3Pool, WheelInfo, World };
|